source: Sophya/trunk/SophyaLib/SysTools/cexpre.cc@ 2593

Last change on this file since 2593 was 2593, checked in by ansari, 21 years ago

Correction bug decodage cst xxx.e-yy , ajout fonctions 0 argument rand01(), randpm1() gaurand() - Reza 9 Aout 2004

File size: 15.7 KB
Line 
1#include <stdlib.h>
2#include <stdio.h>
3#include <ctype.h>
4#include <string.h>
5#include "cexpre.h"
6#include <stack>
7#include <math.h>
8#include "srandgen.h"
9
10namespace SOPHYA {
11
12long CExprBase::totnexp_create = 0;
13long CExprBase::totnexp_delete = 0;
14CExprBase::CExprBase()
15{
16 totnexp_create++;
17 // cout << "CExprBase::CExprBase()-Creation " << hex << this << dec << endl;
18}
19
20CExprBase::~CExprBase()
21{
22 totnexp_delete++;
23 // cout << "CExprBase::~CExprBase() " << hex << this << dec << endl;
24}
25
26void CExprBase::CheckThrow(const char * msg) const
27{
28 string errmsg;
29 bool ok = CheckE(errmsg);
30 if (ok) return;
31 else {
32 errmsg += msg;
33 throw CExprException(errmsg);
34 }
35}
36
37//---------------------------------------------------------
38class CE_NumberExp : public CExprBase {
39public:
40 CE_NumberExp(double v) { _val = v; }
41 CE_NumberExp(string const & s);
42 virtual ~CE_NumberExp() {}
43 virtual double Evaluate() const { return _val; }
44 virtual void Print(ostream& os) const { os << _val; }
45protected:
46 double _val;
47};
48
49CE_NumberExp::CE_NumberExp(string const & s)
50{
51 size_t l = s.length();
52 if (l < 1) {
53 string errmsg = "CE_NumberExp::CE_NumberExp() Empty expression";
54 throw CExprException(errmsg);
55 }
56 if (s == "Pi") _val = M_PI;
57 else if (s == "E") _val = M_E;
58 else {
59 string errmsg = "CE_NumberExp::CE_NumberExp() Bad numerical constant: ";
60 errmsg += s;
61
62 char* lcc;
63 _val = strtod(s.c_str(), &lcc);
64 if (*lcc != '\0') throw CExprException(errmsg);
65 }
66}
67
68//---------------------------------------------------------
69//----------- Expression changement de signe -------------
70class CE_ChsExp : public CExprBase {
71public:
72 explicit CE_ChsExp(CExprBase * e) { _e = e; }
73 virtual ~CE_ChsExp() { if (_e) delete _e; }
74 virtual double Evaluate() const { return -_e->Evaluate(); }
75 virtual bool CheckE(string& errmsg) const { if (_e) return true; else return false; }
76 virtual void Print(ostream& os) const { os << "-( "; _e->Print(os); os << " )"; }
77 protected:
78 CExprBase * _e;
79};
80
81//---------------------------------------------------------
82class CE_BinExp : public CExprBase {
83public:
84 explicit CE_BinExp(char op, int prior);
85 virtual ~CE_BinExp() { if (_e1) delete _e1; if (_e2) delete _e2; }
86 inline void SetE1(CExprBase * e) { _e1 = e; }
87 inline void SetE2(CExprBase * e) { _e2 = e; }
88 virtual bool CheckE(string& errmsg) const;
89 virtual void Print(ostream& os) const;
90 inline char BOpC() const { return _bop; }
91 inline int Priority() const { return _priority; }
92 protected:
93 CExprBase * _e1;
94 CExprBase * _e2;
95 char _bop; // Caractere identificateur d'operation (+,-,*,/ ...)
96 int _priority; // Niveau de priorite: 1= +,- 2: *,/ 3: ^...
97};
98
99CE_BinExp::CE_BinExp(char op, int prior)
100{
101 _e1 = NULL; _e2 = NULL;
102 _bop = op;
103 _priority = prior;
104}
105
106bool CE_BinExp::CheckE(string& errmsg) const
107{
108 if ((_e1 == NULL) || (_e2 == NULL)) {
109 errmsg += "CE_BinExp::CheckE: Binary expression-missing argument ";
110 return false;
111 }
112 return true;
113}
114
115void CE_BinExp::Print(ostream& os) const
116{
117 os << "(" << (*_e1) << _bop << (*_e2) << ")" ;
118}
119
120//---------------------------------------------------------
121class CE_AddExp : public CE_BinExp {
122public:
123 CE_AddExp() : CE_BinExp('+',1) {}
124 virtual double Evaluate() const { CheckThrow("CE_AddExp::Evaluate"); return _e1->Evaluate()+_e2->Evaluate();
125 }
126};
127class CE_MulExp : public CE_BinExp {
128public:
129 CE_MulExp() : CE_BinExp('*',2) {}
130 virtual double Evaluate() const { CheckThrow("CE_MulExp::Evaluate"); return _e1->Evaluate()*_e2->Evaluate(); }
131};
132class CE_SubExp : public CE_BinExp {
133public:
134 CE_SubExp() : CE_BinExp('-',1) {}
135 virtual double Evaluate() const { CheckThrow("CE_SubExp::Evaluate"); return _e1->Evaluate()-_e2->Evaluate(); }
136};
137class CE_DivExp : public CE_BinExp {
138public:
139 CE_DivExp() : CE_BinExp('/',2) {}
140 virtual double Evaluate() const { CheckThrow("CE_DivExp::Evaluate"); return _e1->Evaluate()/_e2->Evaluate(); }
141};
142
143//---------------------------------------------------------
144typedef double (* f0exp) ();
145typedef double (* f1exp) (double x);
146typedef double (* f2exp) (double x, double y);
147typedef double (* f3exp) (double x, double y, double z);
148
149//---------------------------------------------------------
150#define FMXARG 3
151class CE_FuncExp : public CExprBase {
152public:
153 CE_FuncExp(string const & func);
154 virtual ~CE_FuncExp();
155 virtual double Evaluate() const ;
156 inline void AddArg(CExprBase * e);
157 inline int GetMaxNArg() const { return _maxne; }
158 virtual bool CheckE(string& errmsg) const;
159 virtual void Print(ostream& os) const;
160protected:
161 f0exp _f0;
162 f1exp _f1;
163 f2exp _f2;
164 f3exp _f3;
165 int _ne, _maxne;
166 CExprBase * _e[FMXARG];
167 string _fname;
168};
169
170// Les fonctions de generation de nombre aleatoire
171double _CE_rand01() { return drand01(); }
172double _CE_randpm1() { return drandpm1(); }
173double _CE_gaurand() { return GauRnd(0., 1.); }
174//---------------------------------------------------------
175CE_FuncExp::CE_FuncExp(string const & func)
176{
177 _ne = 0; _maxne = -1;
178 for(int k=0; k<FMXARG; k++) _e[k] = NULL;
179 _f0 = NULL;
180 _f1 = NULL;
181 _f2 = NULL;
182 _f3 = NULL;
183 if (func == "sin") _f1 = sin;
184 else if (func == "cos") _f1 = cos;
185 else if (func == "tan") _f1 = tan;
186 else if (func == "asin") _f1 = asin;
187 else if (func == "acos") _f1 = acos;
188 else if (func == "atan") _f1 = atan;
189 else if (func == "atan2") _f2 = atan2;
190 else if (func == "sqrt") _f1 = sqrt;
191 else if (func == "fabs") _f1 = fabs;
192 else if (func == "floor") _f1 = floor;
193 else if (func == "exp") _f1 = exp;
194 else if (func == "log") _f1 = log;
195 else if (func == "log10") _f1 = log10;
196 else if (func == "pow") _f2 = pow;
197 else if (func == "hypot") _f2 = hypot;
198 else if (func == "sinh") _f1 = sinh;
199 else if (func == "cosh") _f1 = cosh;
200 else if (func == "tanh") _f1 = tanh;
201// Les fonctions aleatoires declaree plus haut
202 else if (func == "rand01") _f0 = _CE_rand01;
203 else if (func == "randpm1") _f0 = _CE_randpm1;
204 else if (func == "gaurand") _f0 = _CE_gaurand;
205 else {
206 string errmsg = "CE_FuncExp::CE_FuncExp() - Uknown function " ;
207 errmsg += func;
208 throw CExprException(errmsg);
209 }
210 if (_f0) _maxne = 0;
211 else if (_f1) _maxne = 1;
212 else if (_f2) _maxne = 2;
213 else if (_f3) _maxne = 3;
214 _fname = func;
215}
216
217
218CE_FuncExp::~CE_FuncExp()
219{
220for(int k=0; k<FMXARG; k++) if (_e[k]) delete _e[k];
221}
222
223void CE_FuncExp::AddArg(CExprBase * e)
224{
225 if ((e != NULL) && (_ne < _maxne)) { _e[_ne] = e; _ne++; }
226 else throw CExprException("CE_FuncExp::AddArg() e=NULL or too many arguments ");
227}
228
229double CE_FuncExp::Evaluate() const
230{
231 if ((_ne != _maxne) || (_maxne < 0) ) {
232 throw CExprException("CE_FuncExp::Evaluate() - Wrong argument number ");
233 }
234 if (_ne == 0) return _f0();
235 else if (_ne == 1) return _f1(_e[0]->Evaluate());
236 else if (_ne == 2) return _f2(_e[0]->Evaluate(), _e[1]->Evaluate());
237 else if (_ne == 3) return _f3(_e[0]->Evaluate(), _e[1]->Evaluate(),
238 _e[2]->Evaluate());
239 else return 0.;
240}
241
242bool CE_FuncExp::CheckE(string& errmsg) const
243{
244 if ((_ne != _maxne) || (_maxne < 0) ) {
245 char buff[128];
246 sprintf(buff, "CE_FuncExp::CheckE() %s - Wrong argument number - ne=%d maxne=%d ",
247 _fname.c_str(), _ne, _maxne);
248 errmsg += buff;
249 return false;
250 }
251 return true;
252}
253
254void CE_FuncExp::Print(ostream& os) const
255{
256 if ((_ne != _maxne) || (_maxne < 1) )
257 os << _fname << "(ArgError)" ;
258 else {
259 if (_ne == 1) os << _fname << "(" << *(_e[0]) << ")";
260 else if (_ne == 2) os << _fname << "(" << *(_e[0]) << "," << *(_e[1]) << ")";
261 else if (_ne == 3) os << _fname << "(" << *(_e[0])
262 << "," << *(_e[1]) << "," << *(_e[2]) << ")";
263 }
264}
265
266//---------------------------------------------------------
267CExpressionEvaluator::CExpressionEvaluator(string const & sex)
268{
269 _exp = NULL;
270 size_t off=0,stop=0;
271 string fname = "";
272 string errmsg;
273 _exp= ParseString(0,fname,sex,off,stop,errmsg);
274 if (_exp == NULL) throw CExprException(errmsg);
275}
276
277CExpressionEvaluator::~CExpressionEvaluator()
278{
279 if (_exp) delete _exp;
280}
281
282double CExpressionEvaluator::Evaluate() const
283{
284 if (_exp) return _exp->Evaluate();
285 else return 0.;
286}
287
288void CExpressionEvaluator::Print(ostream& os) const
289{
290 if (_exp) _exp->Print(os);
291 else os << "CExpressionEvaluator ???";
292}
293
294// cette fonction rearrange le stack des operations binaires en attente
295CExprBase* Arrange_CE_BinExpStack(stack<CE_BinExp* >& sbx, CExprBase* cex, CE_BinExp* nbx)
296{
297 while ( !sbx.empty() && (nbx->Priority() <= sbx.top()->Priority()) ) {
298 sbx.top()->SetE2(cex);
299 cex = sbx.top(); sbx.pop();
300 }
301 nbx->SetE1(cex);
302 sbx.push(nbx);
303 return NULL;
304}
305
306// cette fonction rearrange le stack des operations binaires en attente
307CExprBase* Arrange_CE_BinExpStack(stack<CE_BinExp* >& sbx, CExprBase* cex)
308{
309 if (sbx.empty()) return cex;
310 while ( !sbx.empty() ) {
311 sbx.top()->SetE2(cex);
312 cex = sbx.top(); sbx.pop();
313 }
314 return cex;
315}
316
317
318CExprBase* CExpressionEvaluator::ParseString(int extype, string fname, string const & sex,
319 size_t off, size_t& stop, string& errmsg)
320{
321 size_t len = sex.length();
322 if (len < 1) {
323 string errmsg = "CExpressionEvaluator::ParseString() Empty expression";
324 throw CExprException(errmsg);
325 }
326 errmsg = "";
327 CExprBase* rx = NULL; // Expression resultat
328 stack< CE_BinExp* > sbx; // Stack des expressions binaires
329 CE_FuncExp* fx = NULL; // Expression fonction
330 CExprBase* cx = NULL; // Element d'expression (courante)
331
332 if (extype == 2) fx = new CE_FuncExp(fname);
333
334 size_t p=0, q=0;
335 char lastopc=0, opc=0; // Last/current operation sign (+,-,*,/,...)
336 int osn = 0;
337 bool finok = false;
338 bool fgcont = true;
339 bool checkok = true;
340 bool apperrmsg = true;
341 // cout << " DBG-ParseString off= " << off << " sex[off]= " << sex[off]
342 // << " extype= " << extype << endl;
343 p = stop = off;
344 while ((p < len) && (fgcont) && (checkok) ) {
345 // cout << " DBG-2-ParseString p=" << p << " q=" << q << endl;
346
347 cx = NULL;
348 // ------------------------------- Bretelle ------
349 // Il faut sauter les signes +/- qui se trouverait dans les
350 // exposants des nombres xxxe-yy xxxe+y : 0.4e-2 ...
351 // Les qques lignes sont une bretelle qui saute ces signes +/- (Reza, Aout 2004)
352 // On verifie d'abord s'il y a un nombre valide au debut de la positions courante
353 char* lcc;
354 size_t pfn=0,psn;
355 bool numberok = false;
356 strtod(sex.c_str()+p, &lcc);
357 if (lcc != sex.c_str()+p) { // Expression valide de double au debut
358 numberok = true; // de la position courante
359 pfn = lcc-sex.c_str();
360 }
361 // On cherche le 1er signe d'operateur - apres le nombre de debut
362 q = sex.find_first_of("+-*/(),",p);
363
364 while ( numberok && (q < len) && (q < pfn) && (q > p) &&
365 ((sex[q] == '+') || (sex[q] == '-')) ) {
366 psn = q+1;
367 if (psn < len) q = sex.find_first_of("+-*/(),",psn);
368 else q = len+1;
369 }
370 //---- Fin de la Bretelle ---- pour sauter les signes +/- de l'exposant des nombres
371
372 if (q < len) { // operateur trouve
373 opc = sex[q]; // signe operateur courant
374 switch (opc) {
375 case '(' :
376 if (q == p) {
377 string fname = "";
378 cx = ParseString(1, fname, sex, q+1, stop, errmsg);
379 }
380 else cx = ParseString(2, sex.substr(p,q-p), sex, q+1, stop, errmsg);
381 if (!cx) { checkok = false; p = stop+1; apperrmsg = false; }
382 else {
383 if (osn == 1) {
384 if (sex[p-osn] == '-') cx = new CE_ChsExp(cx);
385 }
386 if (osn > 1) {
387 checkok = false; p = stop+1; fgcont = false;
388 delete cx;
389 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - multiple chs (+/-) (AA)";
390 }
391 else if (rx) {
392 checkok = false; p = stop+1; fgcont = false;
393 delete cx;
394 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - rx&&cx (A)";
395 }
396 else {
397 if (stop == len-1) {
398 rx = Arrange_CE_BinExpStack(sbx, cx);
399 finok = true;
400 }
401 else rx = cx;
402 p = stop+1; osn = 0; lastopc = opc;
403 }
404 }
405 break;
406
407 case ')' :
408 case ',' :
409 if (extype == 0) {
410 checkok = false; p = q; fgcont = false;
411 errmsg = "CExpressionEvaluator::ParseString() Unexpected ) or ,";
412 }
413 if ( (extype == 1) && (opc == ',')) {
414 checkok = false; p = q; fgcont = false;
415 errmsg = "CExpressionEvaluator::ParseString() Unexpected ,";
416 }
417 if ((q > p) && (rx)) {
418 checkok = false; p = q; fgcont = false;
419 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - rx&&cx (B)";
420 }
421 if (q > p) cx = new CE_NumberExp(sex.substr(p-osn,q-p+osn));
422 else cx = rx;
423
424 if (!cx && ( !fx || ( opc != ')' ) ||
425 ( (fx && (fx->GetMaxNArg() > 0) && (opc == ')' ) ) ) ) ) {
426 checkok = false; p = q; fgcont = false;
427 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - farg=NULL (BB)";
428 }
429 else {
430 if (cx) { rx = Arrange_CE_BinExpStack(sbx, cx);
431 if (extype == 2) {
432 // cout << " DBG-ParseString-AddArg " << *(cx) << endl;
433 fx->AddArg(rx); rx = NULL;
434 }
435 }
436 if (opc == ')') { // Signe de fin de traitement d'une portion d'expression
437 if (extype == 2) { rx = fx; fx = NULL; }
438 stop = q; osn = 0; lastopc = opc;
439 fgcont = false;
440 finok = true;
441 }
442 else {
443 if (q == (len-1)) finok = true;
444 p = q+1; osn = 0; lastopc = opc;
445 }
446 }
447 break;
448
449 case '+' :
450 case '-' :
451 case '*' :
452 case '/' :
453 if (!( ((opc=='+')||(opc=='-')) && ( (q==off) || ( (q==p) && lastopc != '(') ) ) ) {
454 CE_BinExp* nbx;
455 if (opc == '+') nbx = new CE_AddExp;
456 else if (opc == '-') nbx = new CE_SubExp;
457 else if (opc == '*') nbx = new CE_MulExp;
458 else nbx = new CE_DivExp;
459 if ((p == q) && (rx == NULL)) {
460 checkok = false; p = q; osn = 0; fgcont = false;
461 delete nbx;
462 errmsg = "CExpressionEvaluator::ParseString() Syntax Error - rx==NULL (C)";
463 }
464 else {
465 if (p == q) cx = rx;
466 else cx = new CE_NumberExp(sex.substr(p-osn,q-p+osn));
467 rx = Arrange_CE_BinExpStack(sbx, cx, nbx);
468 p = q+1; osn = 0; lastopc = opc;
469 }
470 }
471 else {
472 // Traitement des signes +/- qui pourrait faire partie d'une constante numerique
473 p = q+1; osn++;
474 continue;
475 }
476 break;
477 default:
478 throw CExprException("CExpressionEvaluator::ParseString() BUG-BUG-BUG");
479 break;
480 } // Fin de switch
481 }
482 else { // dernier element
483 if ( (p<len) && (rx != NULL)) {
484 checkok = false; p = len-1; fgcont = false;
485 errmsg = "CExpressionEvaluator::ParseString() Syntax Error - rx!=NULL at end (D)";
486 }
487 else {
488 if (p<len) cx = new CE_NumberExp(sex.substr(p-osn));
489 else cx = rx;
490 rx = Arrange_CE_BinExpStack(sbx, cx);
491 stop = p = len; fgcont = false;
492 finok = true;
493 }
494 }
495 }
496 // cout << " DBG-ParseString-out stop= " << stop << " sex[stop]= " << sex[stop] << endl;
497 if (finok && checkok) {
498 if( !sbx.empty() ) {
499 checkok = false;
500 errmsg = "CExpressionEvaluator::ParseString() !sbx.empty() at the end (E)";
501 }
502 else {
503 checkok = rx->CheckE(errmsg);
504 }
505 }
506 if (!finok || !checkok || !rx) {
507 char buff[128];
508 if (errmsg.length() < 1) {
509 errmsg = "CExpressionEvaluator::ParseString() Error - " ;
510 if (!finok) errmsg += " !finok " ;
511 if (!checkok) errmsg += " !checkok " ;
512 if (!rx) errmsg += " !rx " ;
513 errmsg += " (F)";
514 }
515
516 if (apperrmsg) {
517 if (p<len)
518 sprintf(buff,"\n CExprError... %s <> %s ", sex.substr(0,p).c_str(),
519 sex.substr(p).c_str());
520 else sprintf(buff,"\n CExprError... %s <<", sex.c_str());
521 errmsg += buff;
522 }
523 if (rx) delete rx;
524 rx = NULL;
525 while (!sbx.empty()) {
526 delete sbx.top();
527 sbx.pop();
528 }
529 }
530 if (fx) delete fx;
531 return rx;
532}
533
534} // End of namespace SOPHYA
535
Note: See TracBrowser for help on using the repository browser.