#include #include #include #include #include "cexpre.h" #include #include namespace SOPHYA { long CExprBase::totnexp_create = 0; long CExprBase::totnexp_delete = 0; CExprBase::CExprBase() { totnexp_create++; // cout << "CExprBase::CExprBase()-Creation " << hex << this << dec << endl; } CExprBase::~CExprBase() { totnexp_delete++; // cout << "CExprBase::~CExprBase() " << hex << this << dec << endl; } void CExprBase::CheckThrow(const char * msg) const { string errmsg; bool ok = CheckE(errmsg); if (ok) return; else { errmsg += msg; throw CExprException(errmsg); } } //--------------------------------------------------------- class CE_NumberExp : public CExprBase { public: CE_NumberExp(double v) { _val = v; } CE_NumberExp(string const & s); virtual ~CE_NumberExp() {} virtual double Evaluate() const { return _val; } virtual void Print(ostream& os) const { os << _val; } protected: double _val; }; CE_NumberExp::CE_NumberExp(string const & s) { size_t l = s.length(); if (l < 1) { string errmsg = "CE_NumberExp::CE_NumberExp() Empty expression"; throw CExprException(errmsg); } if (s == "Pi") _val = M_PI; else if (s == "E") _val = M_E; else { string errmsg = "CE_NumberExp::CE_NumberExp() Bad numerical constant: "; errmsg += s; if ((s == "+") || (s == "-")) throw CExprException(errmsg); for(int k=0; kEvaluate()+_e2->Evaluate(); } }; class CE_MulExp : public CE_BinExp { public: CE_MulExp() : CE_BinExp('*',2) {} virtual double Evaluate() const { CheckThrow("CE_MulExp::Evaluate"); return _e1->Evaluate()*_e2->Evaluate(); } }; class CE_SubExp : public CE_BinExp { public: CE_SubExp() : CE_BinExp('-',1) {} virtual double Evaluate() const { CheckThrow("CE_SubExp::Evaluate"); return _e1->Evaluate()-_e2->Evaluate(); } }; class CE_DivExp : public CE_BinExp { public: CE_DivExp() : CE_BinExp('/',2) {} virtual double Evaluate() const { CheckThrow("CE_DivExp::Evaluate"); return _e1->Evaluate()/_e2->Evaluate(); } }; //--------------------------------------------------------- typedef double (* f0exp) (); typedef double (* f1exp) (double x); typedef double (* f2exp) (double x, double y); typedef double (* f3exp) (double x, double y, double z); //--------------------------------------------------------- #define FMXARG 3 class CE_FuncExp : public CExprBase { public: CE_FuncExp(string const & func); virtual ~CE_FuncExp(); virtual double Evaluate() const ; inline void AddArg(CExprBase * e); virtual bool CheckE(string& errmsg) const; virtual void Print(ostream& os) const; protected: f0exp _f0; f1exp _f1; f2exp _f2; f3exp _f3; int _ne, _maxne; CExprBase * _e[FMXARG]; string _fname; }; //--------------------------------------------------------- CE_FuncExp::CE_FuncExp(string const & func) { _ne = 0; _maxne = -1; for(int k=0; kEvaluate()); else if (_ne == 2) return _f2(_e[0]->Evaluate(), _e[1]->Evaluate()); else if (_ne == 3) return _f3(_e[0]->Evaluate(), _e[1]->Evaluate(), _e[2]->Evaluate()); else return 0.; } bool CE_FuncExp::CheckE(string& errmsg) const { if ((_ne != _maxne) || (_maxne < 0) ) { char buff[128]; sprintf(buff, "CE_FuncExp::CheckE() %s - Wrong argument number - ne=%d maxne=%d ", _fname.c_str(), _ne, _maxne); errmsg += buff; return false; } return true; } void CE_FuncExp::Print(ostream& os) const { if ((_ne != _maxne) || (_maxne < 1) ) os << _fname << "(ArgError)" ; else { if (_ne == 1) os << _fname << "(" << *(_e[0]) << ")"; else if (_ne == 2) os << _fname << "(" << *(_e[0]) << "," << *(_e[1]) << ")"; else if (_ne == 3) os << _fname << "(" << *(_e[0]) << "," << *(_e[1]) << "," << *(_e[2]) << ")"; } } //--------------------------------------------------------- CExpressionEvaluator::CExpressionEvaluator(string const & sex) { _exp = NULL; size_t off=0,stop=0; string fname = ""; string errmsg; _exp= ParseString(0,fname,sex,off,stop,errmsg); if (_exp == NULL) throw CExprException(errmsg); } CExpressionEvaluator::~CExpressionEvaluator() { if (_exp) delete _exp; } double CExpressionEvaluator::Evaluate() const { if (_exp) return _exp->Evaluate(); else return 0.; } void CExpressionEvaluator::Print(ostream& os) const { if (_exp) _exp->Print(os); else os << "CExpressionEvaluator ???"; } // cette fonction rearrange le stack des operations binaires en attente CExprBase* Arrange_CE_BinExpStack(stack& sbx, CExprBase* cex, CE_BinExp* nbx) { while ( !sbx.empty() && (nbx->Priority() <= sbx.top()->Priority()) ) { sbx.top()->SetE2(cex); cex = sbx.top(); sbx.pop(); } nbx->SetE1(cex); sbx.push(nbx); return NULL; } // cette fonction rearrange le stack des operations binaires en attente CExprBase* Arrange_CE_BinExpStack(stack& sbx, CExprBase* cex) { if (sbx.empty()) return cex; while ( !sbx.empty() ) { sbx.top()->SetE2(cex); cex = sbx.top(); sbx.pop(); } return cex; } CExprBase* CExpressionEvaluator::ParseString(int extype, string fname, string const & sex, size_t off, size_t& stop, string& errmsg) { size_t len = sex.length(); if (len < 1) { string errmsg = "CExpressionEvaluator::ParseString() Empty expression"; throw CExprException(errmsg); } errmsg = ""; CExprBase* rx = NULL; // Expression resultat stack< CE_BinExp* > sbx; // Stack des expressions binaires CE_FuncExp* fx = NULL; // Expression fonction CExprBase* cx = NULL; // Element d'expression (courante) if (extype == 2) fx = new CE_FuncExp(fname); size_t p=0, q=0; char lastopc=0, opc=0; // Last/current operation sign (+,-,*,/,...) bool finok = false; bool fgcont = true; bool checkok = true; // cout << " DBG-ParseString off= " << off << " sex[off]= " << sex[off] // << " extype= " << extype << endl; p = stop = off; while ((p < len) && (fgcont) && (checkok) ) { // cout << " DBG-2-ParseString p=" << p << " q=" << q << endl; cx = NULL; q = sex.find_first_of("+-*/(),",p); if (q < len) { // operateur trouve opc = sex[q]; // signe operateur courant switch (opc) { case '(' : if (q == p) { string fname = ""; cx = ParseString(1, fname, sex, q+1, stop, errmsg); } else cx = ParseString(2, sex.substr(p,q-p), sex, q+1, stop, errmsg); if (!cx) { checkok = false; p = stop+1; } else { if (rx) { checkok = false; p = stop+1; fgcont = false; delete cx; errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - rx&&cx (A)"; } else { if (stop == len-1) { rx = Arrange_CE_BinExpStack(sbx, cx); finok = true; } else rx = cx; p = stop+1; lastopc = opc; } } break; case ')' : case ',' : if (extype == 0) { checkok = false; p = q; fgcont = false; errmsg = "CExpressionEvaluator::ParseString() Unexpected ) or ,"; } if ( (extype == 1) && (opc == ',')) { checkok = false; p = q; fgcont = false; errmsg = "CExpressionEvaluator::ParseString() Unexpected ,"; } if ((q > p) && (rx)) { checkok = false; p = q; fgcont = false; errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - rx&&cx (B)"; } if (q > p) cx = new CE_NumberExp(sex.substr(p,q-p)); else cx = rx; if (!cx) { checkok = false; p = q; fgcont = false; errmsg = "CExpressionEvaluator::ParseString()/ Syntax Error - farg=NULL (BB)"; } else { rx = Arrange_CE_BinExpStack(sbx, cx); if (extype == 2) { // cout << " DBG-ParseString-AddArg " << *(cx) << endl; fx->AddArg(rx); rx = NULL; } if (opc == ')') { // Signe de fin de traitement d'une portion d'expression if (extype == 2) { rx = fx; fx = NULL; } stop = q; lastopc = opc; fgcont = false; finok = true; } else { if (q == (len-1)) finok = true; p = q+1; lastopc = opc; } } break; case '+' : case '-' : case '*' : case '/' : // Traitement des signes +/- qui pourrait faire partie d'une constante numerique if (!( ((opc=='+')||(opc=='-')) && ( (q==off) || ( (q==p) && (rx == NULL) ) ) ) ) { // ((lastopc=='+')||(lastopc=='-')||(lastopc=='*')||(lastopc=='/')) ) ) ) ) { CE_BinExp* nbx; if (opc == '+') nbx = new CE_AddExp; else if (opc == '-') nbx = new CE_SubExp; else if (opc == '*') nbx = new CE_MulExp; else nbx = new CE_DivExp; if ((p == q) && (rx == NULL)) { checkok = false; p = q; fgcont = false; delete nbx; errmsg = "CExpressionEvaluator::ParseString() Syntax Error - rx==NULL (C)"; } else { if (p == q) cx = rx; else cx = new CE_NumberExp(sex.substr(p,q-p)); rx = Arrange_CE_BinExpStack(sbx, cx, nbx); p = q+1; lastopc = opc; } } break; default: throw CExprException("CExpressionEvaluator::ParseString() BUG-BUG-BUG"); break; } // Fin de switch } else { // dernier element if ( (pCheckE(errmsg); } } if (!finok || !checkok || !rx) { char buff[128]; if (errmsg.length() < 1) { errmsg = "CExpressionEvaluator::ParseString() Error - " ; if (!finok) errmsg += " !finok " ; if (!checkok) errmsg += " !checkok " ; if (!rx) errmsg += " !rx " ; errmsg += " (F)"; } sprintf(buff,"\n CExprError... S=[%s] (p=%ld , len=%ld)", sex.c_str(), (long)p,(long)len); errmsg += buff; if (rx) delete rx; rx = NULL; while (!sbx.empty()) { delete sbx.top(); sbx.pop(); } } if (fx) delete fx; return rx; } } // End of namespace SOPHYA