#include #include #define __EXPR_CPP #include #include #include TCodearray::TCodearray(int size) : _rpn(size) { clear(); } void TCodearray::clear() { _rpn.destroy(); _last = 0; TCode *c = new TCode(_endsym); _rpn.add(c, _last); } void TCodearray::add(TCodesym sym, const TValue& val) { TCode *c = new TCode(sym, val); _rpn.add(c, _last++); TCode *c1 = new TCode(_endsym); _rpn.add(c1, _last); } TCode& TCode::operator =(const TCode& b) { _sym = b._sym; _val = b._val; return *this; } TVararray::TVararray(int size) : _array(size) { clear(); } void TVararray::add(const char* name, const TValue& val) { TVar* v = new TVar(name, val); _array.add(v, _last++); } void TVararray::set(const char* name, const real& val) { for (int i = 0; i < _array.items(); i++) if (strcmp(((TVar&) _array[i]).getname(), name) == 0) { ((TVar&) _array[i]) = (TValue&) val; return; } } void TVararray::set(const char* name, const char* val) { for (int i = 0; i < _array.items(); i++) if (strcmp(((TVar&) _array[i]).getname(), name) == 0) { ((TVar&) _array[i]) = (TValue&) val; return; } } real __r; const real& TVararray::getnum(const char* name) { int i; for (i = 0; i < _array.items(); i++) { if (strcmp(((TVar*) _array.objptr(i))->getname(), name) == 0) { __r = ((TVar*) _array.objptr(i))->number(); return __r; } } fatal_box("Unknown variable : %s", name); return __r; } const real& TVararray::getnum(int varnum) { if (varnum >= _array.items()) fatal_box("invalid variable number : %d", varnum); __r = ((TVar*) _array.objptr(varnum))->number(); return __r; } const char* TVararray::getstring(const char* name) { const char* s = NULL; int i; for (i = 0; i < _array.items(); i++) { if (strcmp(((TVar*) _array.objptr(i))->getname(), name) == 0) return ((TVar*) _array.objptr(i))->string(); } fatal_box("Unknown variable : %s", name); return s; } const char* TVararray::getstring(int varnum) { if (varnum >= _array.items()) fatal_box("invalid variable number : %d", varnum); return ((TVar*) _array.objptr(varnum))->string(); } /////////////////////////////////////////////////////////// // TExpression /////////////////////////////////////////////////////////// TExpression::TExpression(const char* expression, TTypeexp type) : _original(expression) { _val = real(0.0); _dirty = TRUE; _type = type; if (!compile(expression, type)) { error_box("Wrong expression : %s", expression); _code.clear(); } } TExpression::TExpression(TTypeexp type) : _original("") { _val = real(0.0); _dirty = FALSE; _type = type; _code.clear(); } TExpression::operator const real&() { if (_dirty) eval(); _dirty = FALSE; return _val.number(); } TExpression::operator const char*() { if (_dirty) eval(); _dirty = FALSE; return _val.string(); } void TExpression::print_on(ostream& out) const { out << _original; } TExpression::operator bool() { if (_dirty) eval(); _dirty = FALSE; const real& r = _val.number(); return !r.is_zero(); } void TExpression::setvar(const char* varname, const real& val) { _dirty = TRUE; _var.set(varname, val); } void TExpression::setvar(int varnum, const real& val) { _dirty = TRUE; _var.set(varnum, val); } void TExpression::setvar(const char* varname, const char* val) { _dirty = TRUE; _var.set(varname, val); } void TExpression::setvar(int varnum, const char* val) { _dirty = TRUE; _var.set(varnum, val); } void TExpression::eval() { TStack evalstack(50); TCode instr; real o1, o2, zero(0.00); TString s1, s2; _code.begin(); while (!_code.end()) { instr = _code.step(); switch (instr.getsym()) { case _invalid: case _endsym: break; case _variable: if (_type == _strexpr) { s1 = _var.getstring(instr.string()); evalstack.push(s1); } else { o1 = _var.getnum(instr.string()); evalstack.push(o1); } break; case _number: o1 = instr.number(); evalstack.push(o1); break; case _string: s1 = instr.string(); evalstack.push(s1); break; case _plus: if (_type == _strexpr) { s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); s1 << s2; evalstack.push(s1); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(o1 + o2); } break; case _minus: o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(o1 - o2); break; case _multiply: o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(o1 * o2); break; case _divide: o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(o1 / o2); break; case _chgs: o1 = (real&) evalstack.pop(); evalstack.push(-o1); break; case _and: if (_type == _strexpr) { o2 = real((const char*) (TString&)evalstack.pop()); o1 = real((const char*) (TString&)evalstack.pop()); evalstack.push(TString((o1 != zero && o2 != zero) ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 != zero && o2 != zero) ? 1.0 : 0.0)); } break; case _or: if (_type == _strexpr) { o2 = real((const char*) (TString&)evalstack.pop()); o1 = real((const char*) (TString&)evalstack.pop()); evalstack.push(TString((o1 != zero || o2 != zero) ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 != zero || o2 != zero) ? 1.0 : 0.0)); } break; case _not: o1 = (real&) evalstack.pop(); evalstack.push(real((o1 == zero) ? 1.0 : 0.0)); break; case _equal: if (_type == _strexpr) { s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); evalstack.push(TString((s1 == s2) ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 == o2) ? 1.0 : 0.0)); } break; case _match: s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); evalstack.push(TString((s1.match(s2)) ? "1" : "0")); break; case _noteq: if (_type == _strexpr) { s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); evalstack.push(TString(s1 != s2 ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 != o2) ? 1.0 : 0.0)); } break; case _lt: if (_type == _strexpr) { s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); evalstack.push(TString((s1 < (const char*)s2) ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 < o2) ? 1.0 : 0.0)); } break; case _gt: if (_type == _strexpr) { s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); evalstack.push(TString((s1 > (const char*)s2) ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 > o2) ? 1.0 : 0.0)); } break; case _lteq: if (_type == _strexpr) { s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); evalstack.push(TString((s1 <= (const char*)s2) ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 <= o2) ? 1.0 : 0.0)); } break; case _gteq: if (_type == _strexpr) { s2 = (TString&) evalstack.pop(); s1 = (TString&) evalstack.pop(); evalstack.push(TString((s1 >= (const char*)s2) ? "1" : "0")); } else { o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(real((o1 >= o2) ? 1.0 : 0.0)); } break; case _sqrt: evalstack.push(sqrt((real&) evalstack.pop())); break; case _sqr: evalstack.push(sqr((real&) evalstack.pop())); break; case _exp10: evalstack.push(exp10((real&) evalstack.pop())); break; case _exp: evalstack.push(exp((real&) evalstack.pop())); break; case _log10: evalstack.push(log10((real&) evalstack.pop())); break; case _log: evalstack.push(log((real&) evalstack.pop())); break; case _sin: evalstack.push(sin((real&) evalstack.pop())); break; case _cos: evalstack.push(cos((real&) evalstack.pop())); break; case _tan: evalstack.push(tan((real&) evalstack.pop())); break; case _left: o2 = (real&) evalstack.pop(); s2 = (TString&) evalstack.pop(); s1 = s2.left((int)o2.integer()); evalstack.push(s1); break; case _right: o2 = (real&) evalstack.pop(); s2 = (TString&) evalstack.pop(); s1 = s2.right((int)o2.integer()); evalstack.push(s1); break; case _mid: { int count = (int)((const real&)evalstack.pop()).integer(); if (count == 0) count--; const int from = (int)((const real&)evalstack.pop()).integer() - 1; const TString& s = ((const TString&)evalstack.pop()).mid(from, count); evalstack.push(s); } break; case _pow: o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(pow(o1, o2)); break; case _min: o2 = (real&)evalstack.pop(); o1 = (real&)evalstack.pop(); evalstack.push(fnc_min(o1, o2)); break; case _max: o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); evalstack.push(fnc_min(o1, o2)); break; case _upper: s1 = (TString&) evalstack.pop(); s1.upper(); evalstack.push(s1); break; default: break; } } if (_type == _strexpr) _val = (const char*) (TString&) evalstack.pop(); else _val = (real&) evalstack.pop(); } HIDDEN const char* _s; HIDDEN char _tok[81]; HIDDEN const char* _fntable[] = { "sqrt", "sqr", "exp10", "exp", "log10", "log", "sin", "cos", "tan", "left", "right", "pow", "min", "max", "mid", "upper", NULL }; HIDDEN TCodesym _fntok[] = { _sqrt, _sqr, _exp10, _exp, _log10, _log, _sin, _cos, _tan, _left, _right, _pow, _min, _max, _mid, _upper}; TCodesym TExpression::__gettoken(bool reduct) { TCodesym sym = _invalid; int i = 0; _tok[0] = '\0'; while (isspace(*_s)) _s++; if (!*_s) return _endsym; if ((reduct) && (*_s == ',')) { _s++; return _comma; } if (isdigit(*_s) || (*_s == '.') || (*_s == ',')) { sym = _number; while (isalpha(*_s) || isdigit(*_s) || (*_s == '-') || (*_s == '[') || (*_s == ']') || (*_s == '.') || (*_s == ':') || (!reduct && (*_s == ','))) { if (*_s == '-') { if (_s[1] != '>') break; _tok[i++] = *(_s++); _tok[i++] = *(_s++); sym = _variable; } else { if (sym == _number) if ((isalpha(*_s)) ||(*_s == '[') || (*_s == ']') || (*_s == ',') || (*_s == ':')) sym = _variable; _tok[i++] = *(_s++); } } _tok[i] = '\0'; return sym; } if (isalpha(*_s) || (*_s == '#')) { _tok[i++] = *(_s++); while (isalpha(*_s) || isdigit(*_s) || (*_s == '-') || (*_s == '[') || (*_s == ']') || (*_s == ':') || (!reduct && (*_s == ','))) { if (*_s == '-') { if (_s[1] != '>') break; _tok[i++] = *(_s++); } _tok[i++] = *(_s++); } _tok[i] = '\0'; TString s(_tok); s.lower(); for ( int j = 0; _fntable[j] != NULL; j++) if (s == _fntable[j]) return _fntok[j]; return _variable; } switch (*_s) { case '"' : _s++; while ((*_s) && (*_s != '"')) _tok[i++] = *(_s++); _tok[i] = '\0'; if (*_s == '"') _s++; return _string; case ',' : _s++; return _comma; case '(' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _lpar; case ')' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _rpar; case '+' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _plus; case '-' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _minus; case '*' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _multiply; case '/' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _divide; case '&' : _tok[i++] = *(_s++); if (*_s != '&') break; _tok[i++] = *(_s++); _tok[i] = '\0'; return _and; case '|' : _tok[i++] = *(_s++); if (*_s != '|') break; _tok[i++] = *(_s++); _tok[i] = '\0'; return _or; case '!' : _tok[i++] = *(_s++); _tok[i] = '\0'; if (*_s == '=') { _tok[i++] = *(_s++); _tok[i] = '\0'; return _noteq; } return _not; case '=' : _tok[i++] = *(_s++); if (*_s == '=') _tok[i++] = *(_s++); _tok[i] = '\0'; return _equal; case '?' : _tok[i++] = *(_s++); if (*_s == '=') _tok[i++] = *(_s++); _tok[i] = '\0'; return _match; case '>' : _tok[i++] = *(_s++); _tok[i] = '\0'; if (*_s == '=') { _tok[i++] = *(_s++); _tok[i] = '\0'; return _gteq; } return _gt; case '<' : _tok[i++] = *(_s++); _tok[i] = '\0'; if (*_s == '=') { _tok[i++] = *(_s++); _tok[i] = '\0'; return _lteq; } return _lt; default: break; } return _invalid; } TCodesym TExpression::__factor(TCodesym startsym) { TCodesym sym = _invalid; switch (startsym) { case _lpar: sym = __gettoken(); sym = __expression(sym); if (sym == _rpar) sym = __gettoken(); break; case _variable: case _number: case _string: _code.add(startsym, _tok); if (startsym == _variable) { for (int i = 0 ; i < numvar(); i++) if (strcmp(_tok, varname(i)) == 0) break; if (i == numvar()) _var.add(_tok); } sym = __gettoken(TRUE); break; case _sqrt: case _sqr: case _exp10: case _exp: case _log10: case _log: case _sin: case _cos: case _tan: sym = __gettoken(); if (sym == _lpar) sym = __gettoken(); else break; if ((sym == _number) || (sym == _variable)) sym = __factor(sym); else break; if (sym == _rpar) sym = __gettoken(); else break; _code.add(startsym); break; case _upper: sym = __gettoken(); if (sym == _lpar) sym = __gettoken(); else break; if ((sym == _string) || (sym == _variable)) sym = __factor(sym); else break; if (sym == _rpar) sym = __gettoken(); else break; _code.add(startsym); break; case _left: case _right: case _pow: case _min: case _max: sym = __gettoken(); if (sym == _lpar) sym = __gettoken(TRUE); else break; if ((sym == _number) || (sym == _variable)) sym = __factor(sym); else break; if (sym == _comma) sym = __gettoken(TRUE); else break; if ((sym == _number) || (sym == _variable)) sym = __factor(sym); else break; if (sym == _rpar) sym = __gettoken(); else break; _code.add(startsym); break; case _mid: sym = __gettoken(); if (sym == _lpar) sym = __gettoken(TRUE); else break; if ((sym == _number) || (sym == _variable)) sym = __factor(sym); else break; if (sym == _comma) sym = __gettoken(TRUE); else break; if ((sym == _number) || (sym == _variable)) sym = __factor(sym); else break; if (sym == _comma) sym = __gettoken(TRUE); else break; if ((sym == _number) || (sym == _variable)) sym = __factor(sym); else break; if (sym == _rpar) sym = __gettoken(); else break; _code.add(startsym); break; default: break; } return sym; } TCodesym TExpression::__term(TCodesym startsym) { TCodesym sym; sym = __factor(startsym); while ((sym != _endsym) && ((sym == _multiply) || (sym == _divide))) { TCodesym savedsym = sym; sym = __gettoken(); sym = __factor(startsym); _code.add(savedsym); } return sym; } TCodesym TExpression::__expression(TCodesym startsym) { TCodesym sym; if ((startsym == _minus) || (startsym == _not) || (startsym == _plus)) sym =__gettoken(); else sym = startsym; sym = __term(sym); if ((startsym == _minus) || (startsym == _not)) _code.add(startsym == _not ? startsym : _chgs); while ((sym != _endsym) && ((sym == _minus) || (sym == _plus) || (sym == _equal) || (sym == _noteq) || (sym == _gt) || (sym == _lt) || (sym == _gteq) || (sym == _lteq) || (sym == _and) || (sym == _or) || (sym == _match))) { TCodesym savedsym = sym; sym = __gettoken(); sym = __term(sym); _code.add(savedsym); } return(sym); } bool TExpression::set(const char* expression, TTypeexp type) { _original = expression; _type = type; _dirty = TRUE; return compile(expression, type); } bool TExpression::compile(const char* expression, TTypeexp type) { TString sc(256); TCodesym currsym; _s = expression; _type = type; while (((currsym = __gettoken()) != _endsym) && (currsym != _invalid)) { if (currsym == _variable) { char *s1 = _tok; while ((*s1) && (*s1 != '[')) s1++; if (!*s1) sc << " " << _tok; else { *s1 = '\0'; s1++; char *s2 = s1; while ((*s1) && (*s1 != ',')) s1++; if (!*s1) sc << " " << _tok; else { *s1 = '\0'; s1++; int n1 = atoi(s2); s2 = s1; while ((*s1) && (*s1 != ']')) s1++; if (!*s1) sc << " " << _tok; else { const int n2 = atoi(s2); sc << format(" mid(%s,%d,%d)", _tok, n1, (n2 < n1) ? 0 : n2 - n1 + 1); } } } } else if (currsym == _string) sc << " \"" << _tok << "\""; else sc << " " << _tok; } _s = sc; _val = real(0.0); _code.clear(); if (!*_s) return TRUE; if ((currsym = __gettoken()) == _invalid) return FALSE; return __expression(currsym) == _endsym; }