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

Last change on this file since 4033 was 3617, checked in by cmv, 16 years ago

chgt nom Gaussian -> GaussianRand etc.. pour ambiguite, cmv 02/05/2009

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