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

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

Correction bug ds CExprEvaluator (gestion Chs - ) - Reza 8 Juin 2004

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