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

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

Documentation (ajoutee ou completee) pour les classes du module SysTools - Reza 11 Aout 2004

File size: 17.8 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 -------------
70/*!
71 \internal
72 \ingroup SysTools
73 \brief Class for handling change sign expression (-x)
74 \sa CExpressionEvaluator
75*/
76class CE_ChsExp : public CExprBase {
77public:
78 explicit CE_ChsExp(CExprBase * e) { _e = e; }
79 virtual ~CE_ChsExp() { if (_e) delete _e; }
80 virtual double Evaluate() const { return -_e->Evaluate(); }
81 virtual bool CheckE(string& errmsg) const { if (_e) return true; else return false; }
82 virtual void Print(ostream& os) const { os << "-( "; _e->Print(os); os << " )"; }
83 protected:
84 CExprBase * _e;
85};
86
87//---------------------------------------------------------
88/*!
89 \internal
90 \ingroup SysTools
91 \brief Base class for binary operations on expressions
92 \sa CExpressionEvaluator
93*/
94class CE_BinExp : public CExprBase {
95public:
96 explicit CE_BinExp(char op, int prior);
97 virtual ~CE_BinExp() { if (_e1) delete _e1; if (_e2) delete _e2; }
98 inline void SetE1(CExprBase * e) { _e1 = e; }
99 inline void SetE2(CExprBase * e) { _e2 = e; }
100 virtual bool CheckE(string& errmsg) const;
101 virtual void Print(ostream& os) const;
102 inline char BOpC() const { return _bop; }
103 inline int Priority() const { return _priority; }
104 protected:
105 CExprBase * _e1;
106 CExprBase * _e2;
107 char _bop; // Caractere identificateur d'operation (+,-,*,/ ...)
108 int _priority; // Niveau de priorite: 1= +,- 2: *,/ 3: ^...
109};
110
111CE_BinExp::CE_BinExp(char op, int prior)
112{
113 _e1 = NULL; _e2 = NULL;
114 _bop = op;
115 _priority = prior;
116}
117
118bool CE_BinExp::CheckE(string& errmsg) const
119{
120 if ((_e1 == NULL) || (_e2 == NULL)) {
121 errmsg += "CE_BinExp::CheckE: Binary expression-missing argument ";
122 return false;
123 }
124 return true;
125}
126
127void CE_BinExp::Print(ostream& os) const
128{
129 os << "(" << (*_e1) << _bop << (*_e2) << ")" ;
130}
131
132//---------------------------------------------------------
133/*!
134 \internal
135 \ingroup SysTools
136 \brief Addition of two CExprBase (binary operation : x+y)
137 \sa CExpressionEvaluator
138*/
139class CE_AddExp : public CE_BinExp {
140public:
141 CE_AddExp() : CE_BinExp('+',1) {}
142 virtual double Evaluate() const { CheckThrow("CE_AddExp::Evaluate"); return _e1->Evaluate()+_e2->Evaluate();
143 }
144};
145/*!
146 \internal
147 \ingroup SysTools
148 \brief Multiplication of two CExprBase (binary operation : x*y)
149 \sa CExpressionEvaluator
150*/
151class CE_MulExp : public CE_BinExp {
152public:
153 CE_MulExp() : CE_BinExp('*',2) {}
154 virtual double Evaluate() const { CheckThrow("CE_MulExp::Evaluate"); return _e1->Evaluate()*_e2->Evaluate(); }
155};
156/*!
157 \internal
158 \ingroup SysTools
159 \brief Subtraction of two CExprBase (binary operation : x-y)
160 \sa CExpressionEvaluator
161*/
162class CE_SubExp : public CE_BinExp {
163public:
164 CE_SubExp() : CE_BinExp('-',1) {}
165 virtual double Evaluate() const { CheckThrow("CE_SubExp::Evaluate"); return _e1->Evaluate()-_e2->Evaluate(); }
166};
167/*!
168 \internal
169 \ingroup SysTools
170 \brief Division of two CExprBase (binary operation : x/y)
171 \sa CExpressionEvaluator
172*/
173class CE_DivExp : public CE_BinExp {
174public:
175 CE_DivExp() : CE_BinExp('/',2) {}
176 virtual double Evaluate() const { CheckThrow("CE_DivExp::Evaluate"); return _e1->Evaluate()/_e2->Evaluate(); }
177};
178
179//---------------------------------------------------------
180typedef double (* f0exp) ();
181typedef double (* f1exp) (double x);
182typedef double (* f2exp) (double x, double y);
183typedef double (* f3exp) (double x, double y, double z);
184
185//---------------------------------------------------------
186#define FMXARG 3
187/*!
188 \internal
189 \ingroup SysTools
190 \brief Function evaluation on other expression in the form f(), f(x), f(x,y), f(x,y,z)
191 \sa CExpressionEvaluator
192*/
193class CE_FuncExp : public CExprBase {
194public:
195 CE_FuncExp(string const & func);
196 virtual ~CE_FuncExp();
197 virtual double Evaluate() const ;
198 inline void AddArg(CExprBase * e);
199 inline int GetMaxNArg() const { return _maxne; }
200 virtual bool CheckE(string& errmsg) const;
201 virtual void Print(ostream& os) const;
202protected:
203 f0exp _f0;
204 f1exp _f1;
205 f2exp _f2;
206 f3exp _f3;
207 int _ne, _maxne;
208 CExprBase * _e[FMXARG];
209 string _fname;
210};
211
212// Les fonctions de generation de nombre aleatoire
213static double _CE_rand01() { return drand01(); }
214static double _CE_randpm1() { return drandpm1(); }
215static double _CE_gaurand() { return GauRnd(0., 1.); }
216//---------------------------------------------------------
217CE_FuncExp::CE_FuncExp(string const & func)
218{
219 _ne = 0; _maxne = -1;
220 for(int k=0; k<FMXARG; k++) _e[k] = NULL;
221 _f0 = NULL;
222 _f1 = NULL;
223 _f2 = NULL;
224 _f3 = NULL;
225 if (func == "sin") _f1 = sin;
226 else if (func == "cos") _f1 = cos;
227 else if (func == "tan") _f1 = tan;
228 else if (func == "asin") _f1 = asin;
229 else if (func == "acos") _f1 = acos;
230 else if (func == "atan") _f1 = atan;
231 else if (func == "atan2") _f2 = atan2;
232 else if (func == "sqrt") _f1 = sqrt;
233 else if (func == "fabs") _f1 = fabs;
234 else if (func == "floor") _f1 = floor;
235 else if (func == "exp") _f1 = exp;
236 else if (func == "log") _f1 = log;
237 else if (func == "log10") _f1 = log10;
238 else if (func == "pow") _f2 = pow;
239 else if (func == "hypot") _f2 = hypot;
240 else if (func == "sinh") _f1 = sinh;
241 else if (func == "cosh") _f1 = cosh;
242 else if (func == "tanh") _f1 = tanh;
243// Les fonctions aleatoires declaree plus haut
244 else if (func == "rand01") _f0 = _CE_rand01;
245 else if (func == "randpm1") _f0 = _CE_randpm1;
246 else if (func == "gaurand") _f0 = _CE_gaurand;
247 else {
248 string errmsg = "CE_FuncExp::CE_FuncExp() - Uknown function " ;
249 errmsg += func;
250 throw CExprException(errmsg);
251 }
252 if (_f0) _maxne = 0;
253 else if (_f1) _maxne = 1;
254 else if (_f2) _maxne = 2;
255 else if (_f3) _maxne = 3;
256 _fname = func;
257}
258
259
260CE_FuncExp::~CE_FuncExp()
261{
262for(int k=0; k<FMXARG; k++) if (_e[k]) delete _e[k];
263}
264
265void CE_FuncExp::AddArg(CExprBase * e)
266{
267 if ((e != NULL) && (_ne < _maxne)) { _e[_ne] = e; _ne++; }
268 else throw CExprException("CE_FuncExp::AddArg() e=NULL or too many arguments ");
269}
270
271double CE_FuncExp::Evaluate() const
272{
273 if ((_ne != _maxne) || (_maxne < 0) ) {
274 throw CExprException("CE_FuncExp::Evaluate() - Wrong argument number ");
275 }
276 if (_ne == 0) return _f0();
277 else if (_ne == 1) return _f1(_e[0]->Evaluate());
278 else if (_ne == 2) return _f2(_e[0]->Evaluate(), _e[1]->Evaluate());
279 else if (_ne == 3) return _f3(_e[0]->Evaluate(), _e[1]->Evaluate(),
280 _e[2]->Evaluate());
281 else return 0.;
282}
283
284bool CE_FuncExp::CheckE(string& errmsg) const
285{
286 if ((_ne != _maxne) || (_maxne < 0) ) {
287 char buff[128];
288 sprintf(buff, "CE_FuncExp::CheckE() %s - Wrong argument number - ne=%d maxne=%d ",
289 _fname.c_str(), _ne, _maxne);
290 errmsg += buff;
291 return false;
292 }
293 return true;
294}
295
296void CE_FuncExp::Print(ostream& os) const
297{
298 if ((_ne != _maxne) || (_maxne < 1) )
299 os << _fname << "(ArgError)" ;
300 else {
301 if (_ne == 1) os << _fname << "(" << *(_e[0]) << ")";
302 else if (_ne == 2) os << _fname << "(" << *(_e[0]) << "," << *(_e[1]) << ")";
303 else if (_ne == 3) os << _fname << "(" << *(_e[0])
304 << "," << *(_e[1]) << "," << *(_e[2]) << ")";
305 }
306}
307
308//---------------------------------------------------------
309/*!
310 \class CExpressionEvaluator
311 \ingroup SysTools
312 \brief Class for evaluation of arithmetic expressions with C-like syntax.
313
314 This classes can handle the parsing of c-like arithmetic
315 expressions containing numerical constants, the four
316 basic operations (addition +, subtraction -, multiplication *,
317 division /) and functions.
318 The numerical constants are also defined <tt> (Pi = M_PI E = M_E) </tt>.
319 The following functions from the standard math library and
320 random generators are available:
321
322 - sqrt fabs floor hypot
323 - exp log log10 pow
324 - sin cos tan asin acos atan atan2
325 - sinh cosh tanh
326 - rand01() : Flat random number generator in the range [0 1]
327 - randpm1() : Flat random number generator in the range [-1 1]
328 - gaurand() : Gaussian random number generator (m=0, sigma=1)
329
330 Usage example :
331 \code
332 #include "cexpre.h"
333 ...
334 string es = "4.+3*(cos(Pi/8.)+1.5)";
335 CExpressionEvaluator e(es);
336 cout << " Expression: " << e << " = " << e.Evaluate() << endl;
337 \endcode
338
339 Output : \n
340 <tt> Expression: (4+(3*(cos((3.14159/8))+1.5))) = 11.2716 </tt>
341*/
342
343/*!
344 Parse the string \c sex and builds an expression.
345 Can throw CExprException exception.
346*/
347CExpressionEvaluator::CExpressionEvaluator(string const & sex)
348{
349 _exp = NULL;
350 size_t off=0,stop=0;
351 string fname = "";
352 string errmsg;
353 _exp= ParseString(0,fname,sex,off,stop,errmsg);
354 if (_exp == NULL) throw CExprException(errmsg);
355}
356
357CExpressionEvaluator::~CExpressionEvaluator()
358{
359 if (_exp) delete _exp;
360}
361
362double CExpressionEvaluator::Evaluate() const
363{
364 if (_exp) return _exp->Evaluate();
365 else return 0.;
366}
367
368void CExpressionEvaluator::Print(ostream& os) const
369{
370 if (_exp) _exp->Print(os);
371 else os << "CExpressionEvaluator ???";
372}
373
374// cette fonction rearrange le stack des operations binaires en attente
375static CExprBase* Arrange_CE_BinExpStack(stack<CE_BinExp* >& sbx, CExprBase* cex, CE_BinExp* nbx)
376{
377 while ( !sbx.empty() && (nbx->Priority() <= sbx.top()->Priority()) ) {
378 sbx.top()->SetE2(cex);
379 cex = sbx.top(); sbx.pop();
380 }
381 nbx->SetE1(cex);
382 sbx.push(nbx);
383 return NULL;
384}
385
386// cette fonction rearrange le stack des operations binaires en attente
387static CExprBase* Arrange_CE_BinExpStack(stack<CE_BinExp* >& sbx, CExprBase* cex)
388{
389 if (sbx.empty()) return cex;
390 while ( !sbx.empty() ) {
391 sbx.top()->SetE2(cex);
392 cex = sbx.top(); sbx.pop();
393 }
394 return cex;
395}
396
397
398CExprBase* CExpressionEvaluator::ParseString(int extype, string fname, string const & sex,
399 size_t off, size_t& stop, string& errmsg)
400{
401 size_t len = sex.length();
402 if (len < 1) {
403 string errmsg = "CExpressionEvaluator::ParseString() Empty expression";
404 throw CExprException(errmsg);
405 }
406 errmsg = "";
407 CExprBase* rx = NULL; // Expression resultat
408 stack< CE_BinExp* > sbx; // Stack des expressions binaires
409 CE_FuncExp* fx = NULL; // Expression fonction
410 CExprBase* cx = NULL; // Element d'expression (courante)
411
412 if (extype == 2) fx = new CE_FuncExp(fname);
413
414 size_t p=0, q=0;
415 char lastopc=0, opc=0; // Last/current operation sign (+,-,*,/,...)
416 int osn = 0;
417 bool finok = false;
418 bool fgcont = true;
419 bool checkok = true;
420 bool apperrmsg = true;
421 // cout << " DBG-ParseString off= " << off << " sex[off]= " << sex[off]
422 // << " extype= " << extype << endl;
423 p = stop = off;
424 while ((p < len) && (fgcont) && (checkok) ) {
425 // cout << " DBG-2-ParseString p=" << p << " q=" << q << endl;
426
427 cx = NULL;
428 // ------------------------------- Bretelle ------
429 // Il faut sauter les signes +/- qui se trouverait dans les
430 // exposants des nombres xxxe-yy xxxe+y : 0.4e-2 ...
431 // Les qques lignes sont une bretelle qui saute ces signes +/- (Reza, Aout 2004)
432 // On verifie d'abord s'il y a un nombre valide au debut de la positions courante
433 char* lcc;
434 size_t pfn=0,psn;
435 bool numberok = false;
436 strtod(sex.c_str()+p, &lcc);
437 if (lcc != sex.c_str()+p) { // Expression valide de double au debut
438 numberok = true; // de la position courante
439 pfn = lcc-sex.c_str();
440 }
441 // On cherche le 1er signe d'operateur - apres le nombre de debut
442 q = sex.find_first_of("+-*/(),",p);
443
444 while ( numberok && (q < len) && (q < pfn) && (q > p) &&
445 ((sex[q] == '+') || (sex[q] == '-')) ) {
446 psn = q+1;
447 if (psn < len) q = sex.find_first_of("+-*/(),",psn);
448 else q = len+1;
449 }
450 //---- Fin de la Bretelle ---- pour sauter les signes +/- de l'exposant des nombres
451
452 if (q < len) { // operateur trouve
453 opc = sex[q]; // signe operateur courant
454 switch (opc) {
455 case '(' :
456 if (q == p) {
457 string fname = "";
458 cx = ParseString(1, fname, sex, q+1, stop, errmsg);
459 }
460 else cx = ParseString(2, sex.substr(p,q-p), sex, q+1, stop, errmsg);
461 if (!cx) { checkok = false; p = stop+1; apperrmsg = false; }
462 else {
463 if (osn == 1) {
464 if (sex[p-osn] == '-') cx = new CE_ChsExp(cx);
465 }
466 if (osn > 1) {
467 checkok = false; p = stop+1; fgcont = false;
468 delete cx;
469 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - multiple chs (+/-) (AA)";
470 }
471 else if (rx) {
472 checkok = false; p = stop+1; fgcont = false;
473 delete cx;
474 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - rx&&cx (A)";
475 }
476 else {
477 if (stop == len-1) {
478 rx = Arrange_CE_BinExpStack(sbx, cx);
479 finok = true;
480 }
481 else rx = cx;
482 p = stop+1; osn = 0; lastopc = opc;
483 }
484 }
485 break;
486
487 case ')' :
488 case ',' :
489 if (extype == 0) {
490 checkok = false; p = q; fgcont = false;
491 errmsg = "CExpressionEvaluator::ParseString() Unexpected ) or ,";
492 }
493 if ( (extype == 1) && (opc == ',')) {
494 checkok = false; p = q; fgcont = false;
495 errmsg = "CExpressionEvaluator::ParseString() Unexpected ,";
496 }
497 if ((q > p) && (rx)) {
498 checkok = false; p = q; fgcont = false;
499 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - rx&&cx (B)";
500 }
501 if (q > p) cx = new CE_NumberExp(sex.substr(p-osn,q-p+osn));
502 else cx = rx;
503
504 if (!cx && ( !fx || ( opc != ')' ) ||
505 ( (fx && (fx->GetMaxNArg() > 0) && (opc == ')' ) ) ) ) ) {
506 checkok = false; p = q; fgcont = false;
507 errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - farg=NULL (BB)";
508 }
509 else {
510 if (cx) { rx = Arrange_CE_BinExpStack(sbx, cx);
511 if (extype == 2) {
512 // cout << " DBG-ParseString-AddArg " << *(cx) << endl;
513 fx->AddArg(rx); rx = NULL;
514 }
515 }
516 if (opc == ')') { // Signe de fin de traitement d'une portion d'expression
517 if (extype == 2) { rx = fx; fx = NULL; }
518 stop = q; osn = 0; lastopc = opc;
519 fgcont = false;
520 finok = true;
521 }
522 else {
523 if (q == (len-1)) finok = true;
524 p = q+1; osn = 0; lastopc = opc;
525 }
526 }
527 break;
528
529 case '+' :
530 case '-' :
531 case '*' :
532 case '/' :
533 if (!( ((opc=='+')||(opc=='-')) && ( (q==off) || ( (q==p) && lastopc != '(') ) ) ) {
534 CE_BinExp* nbx;
535 if (opc == '+') nbx = new CE_AddExp;
536 else if (opc == '-') nbx = new CE_SubExp;
537 else if (opc == '*') nbx = new CE_MulExp;
538 else nbx = new CE_DivExp;
539 if ((p == q) && (rx == NULL)) {
540 checkok = false; p = q; osn = 0; fgcont = false;
541 delete nbx;
542 errmsg = "CExpressionEvaluator::ParseString() Syntax Error - rx==NULL (C)";
543 }
544 else {
545 if (p == q) cx = rx;
546 else cx = new CE_NumberExp(sex.substr(p-osn,q-p+osn));
547 rx = Arrange_CE_BinExpStack(sbx, cx, nbx);
548 p = q+1; osn = 0; lastopc = opc;
549 }
550 }
551 else {
552 // Traitement des signes +/- qui pourrait faire partie d'une constante numerique
553 p = q+1; osn++;
554 continue;
555 }
556 break;
557 default:
558 throw CExprException("CExpressionEvaluator::ParseString() BUG-BUG-BUG");
559 break;
560 } // Fin de switch
561 }
562 else { // dernier element
563 if ( (p<len) && (rx != NULL)) {
564 checkok = false; p = len-1; fgcont = false;
565 errmsg = "CExpressionEvaluator::ParseString() Syntax Error - rx!=NULL at end (D)";
566 }
567 else {
568 if (p<len) cx = new CE_NumberExp(sex.substr(p-osn));
569 else cx = rx;
570 rx = Arrange_CE_BinExpStack(sbx, cx);
571 stop = p = len; fgcont = false;
572 finok = true;
573 }
574 }
575 }
576 // cout << " DBG-ParseString-out stop= " << stop << " sex[stop]= " << sex[stop] << endl;
577 if (finok && checkok) {
578 if( !sbx.empty() ) {
579 checkok = false;
580 errmsg = "CExpressionEvaluator::ParseString() !sbx.empty() at the end (E)";
581 }
582 else {
583 checkok = rx->CheckE(errmsg);
584 }
585 }
586 if (!finok || !checkok || !rx) {
587 char buff[128];
588 if (errmsg.length() < 1) {
589 errmsg = "CExpressionEvaluator::ParseString() Error - " ;
590 if (!finok) errmsg += " !finok " ;
591 if (!checkok) errmsg += " !checkok " ;
592 if (!rx) errmsg += " !rx " ;
593 errmsg += " (F)";
594 }
595
596 if (apperrmsg) {
597 if (p<len)
598 sprintf(buff,"\n CExprError... %s <> %s ", sex.substr(0,p).c_str(),
599 sex.substr(p).c_str());
600 else sprintf(buff,"\n CExprError... %s <<", sex.c_str());
601 errmsg += buff;
602 }
603 if (rx) delete rx;
604 rx = NULL;
605 while (!sbx.empty()) {
606 delete sbx.top();
607 sbx.pop();
608 }
609 }
610 if (fx) delete fx;
611 return rx;
612}
613
614} // End of namespace SOPHYA
615
Note: See TracBrowser for help on using the repository browser.