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

Last change on this file since 2680 was 2615, checked in by cmv, 21 years ago

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