#define __EXPR_CPP #include #include #include /////////////////////////////////////////////////////////// // TValue /////////////////////////////////////////////////////////// real& TValue::number() { if (_t == _strexpr) { if (TDate::isdate(_s)) _r = TDate(_s).date2ansi(); else _r = real(_s); _t = _numexpr; } return _r; } TString& TValue::string() { if (_t == _numexpr) { _s = _r.string(); _t = _strexpr; } return _s; } /////////////////////////////////////////////////////////// // TCodearray /////////////////////////////////////////////////////////// void TCodearray::clear() { destroy(); TArray::add(new TCode(_endsym)); } void TCodearray::add(TCodesym sym, const TValue& val) { TArray::insert(new TCode(sym, val), last()); } /////////////////////////////////////////////////////////// // TCode /////////////////////////////////////////////////////////// TObject* TCode::dup() const { return new TCode(*this); } TCode& TCode::operator =(const TCode& b) { _sym = b._sym; _val = b._val; return *this; } /////////////////////////////////////////////////////////// // TVar /////////////////////////////////////////////////////////// TObject* TVar::dup() const { return new TVar(*this); } int TVar::compare(const TSortable& s) const { const TVar& v = (const TVar&)s; return _name.compare(v._name); } /////////////////////////////////////////////////////////// // TVararray /////////////////////////////////////////////////////////// void TVararray::add(const char* name, const TValue& val) { _vars.add(new TVar(name, val)); _vars.sort(); // Brutto, ma per ora va bene qui; } TVar* TVararray::find(int i) const { TVar* v = (TVar*)_vars.objptr(i); CHECKD(v, "Variabile non trovata:", i); return v; } TVar* TVararray::find(const char* name) const { int mi = 0, ma = _vars.last(), i = 0; while(mi <= ma) { i = (mi+ma)/2; TVar* v = find(i); const int cmp = v->getname().compare(name); if (cmp == 0) return v; if (cmp < 0) mi = i+1; else ma = i-1; } for (i = _vars.last(); i >= 0; i--) { TVar* v = find(i); if (v->getname() == name) return v; // Se passa di qua ... m'incazzo } CHECKS(NULL, "Variabile non trovata:", name); return NULL; } void TVararray::set(const char* name, const real& val) { TVar* v = find(name); if (v != NULL) *v = val; } void TVararray::set(const char* name, const char* val) { TVar* v = find(name); if (v != NULL) *v = val; } const real& TVararray::getnum(const char* name) { TVar* v = find(name); if (v != NULL) return v->number(); return ZERO; } const TString& TVararray::getstring(const char* name) { TVar* v = find(name); if (v != NULL) return v->string(); return EMPTY_STRING; } /////////////////////////////////////////////////////////// // TEval_stack /////////////////////////////////////////////////////////// void TEval_stack::push(bool b) { if (_sp < _data.items()) { _sp++; peek_real() = b ? 1.0 : 0.0; } else TStack::push(new TValue(b ? real(1.0) : ZERO)); } void TEval_stack::push(int n) { if (_sp < _data.items()) { _sp++; peek_real() = n; } else TStack::push(new TValue(real(n))); } void TEval_stack::push(const real& r) { if (_sp < _data.items()) { _sp++; peek_real() = r; } else TStack::push(new TValue(r)); } void TEval_stack::push(const TString& s) { if (_sp < _data.items()) { _sp++; peek_string() = s; } else TStack::push(new TValue(s)); } void TEval_stack::push(const char* s) { if (_sp < _data.items()) { _sp++; peek_string() = s; } else TStack::push(new TValue(s)); } real& TEval_stack::pop_real() { TValue& o = (TValue&)pop(); return o.number(); } real& TEval_stack::peek_real() { TValue& o = (TValue&)peek(0); return o.number(); } TString& TEval_stack::pop_string() { TValue& o = (TValue&)pop(); return o.string(); } TString& TEval_stack::peek_string() { TValue& o = (TValue&)peek(0); return o.string(); } /////////////////////////////////////////////////////////// // TExpression /////////////////////////////////////////////////////////// TExpression::TExpression(const char* expression, TTypeexp type, bool ignore_err) : _original(expression) { _ignore_error=ignore_err; _error=0; _dirty = true; _type = type; compile(_original, type); } TExpression::TExpression(TTypeexp type, bool ignore_err) { _ignore_error=ignore_err; _error=0; _dirty = FALSE; _type = type; _code.clear(); } TExpression::TExpression(const TExpression & expr) : _code(expr._code), _var(expr._var), _val(expr._val), _ignore_error(expr._ignore_error), _error(expr._error), _dirty(expr._dirty), _user_func_defined(expr._user_func_defined), _type(expr._type), _original(expr._original) { } TObject* TExpression::dup() const { TExpression* o = new TExpression(*this); return o; } const real & TExpression::as_real() { if (user_func_dirty() || _dirty) eval(); _dirty = FALSE; return _val.number(); } const TString & TExpression::as_string() { if (user_func_dirty() || _dirty) eval(); _dirty = FALSE; return _val.string(); } bool TExpression::as_bool() { return !as_real().is_zero(); } void TExpression::print_on(ostream& out) const { out << _original; } void TExpression::evaluate_user_func(int index, int nparms, TEval_stack& stack, TTypeexp curtype) const { NFCHECK("Unknown function %d.", index); for (int i = nparms; i > 0; i--) stack.pop(); stack.push(ZERO); } void TExpression::setvar(const char* varname, const real& val) { if (_var.getnum(varname) != val) { _var.set(varname, val); _dirty = TRUE; } } void TExpression::setvar(int varnum, const real& val) { if (_var.getnum(varnum) != val) { _var.set(varnum, val); _dirty = TRUE; } } void TExpression::setvar(const char* varname, const char* val) { if (_var.getstring(varname) != val) { _var.set(varname, val); _dirty = true; } } void TExpression::setvar(int varnum, const char* val) { if (_var.getstring(varnum) != val) { _var.set(varnum, val); _dirty = true; } } bool TExpression::print_error(const char* msg) const { return yesnofatal_box("%s", msg); } static bool str2date(const TString& s, TDate& d) { if (s.blank() || s == "0") return true; if (TDate::isdate(s)) { d = s; return true; } return false; } static bool all_zeroes(const TString& str) { bool yes = str.not_empty(); for (const char* s = str; *s && yes; s++) yes = (*s == '0') || isspace(*s); return yes; } void TExpression::eval() { TEval_stack evalstack; TBit_array types; int type_pointer = 0; TCode instr; types.set(type_pointer, (_type == _numexpr)); TTypeexp type = _type; _code.begin(); while (!_code.end()) { instr = _code.step(); switch (instr.getsym()) { case _invalid: case _endsym: break; case _variable: if (type == _strexpr) { const TString & s1 = _var.getstring(instr.string()); evalstack.push(s1); } else { const real & r1 = _var.getnum(instr.string()); evalstack.push(r1); } break; case _number: { const real & r1 = instr.number(); evalstack.push(r1); } break; case _string: { const TString & s1 = instr.string(); evalstack.push(s1); } break; case _plus: if (type == _strexpr) { // Non unire le seguenti righe const TString& s = evalstack.pop_string(); evalstack.peek_string() << s; } else { // Non unire le seguenti righe const real& r = evalstack.pop_real(); evalstack.peek_real() += r; } break; case _minus: { const real& r = evalstack.pop_real(); evalstack.peek_real() -= r; } break; case _multiply: { const real& r = evalstack.pop_real(); evalstack.peek_real() *= r; } break; case _divide: { const real& r = evalstack.pop_real(); if (r.is_zero()) { if (!evalstack.peek_real().is_zero()) if (_ignore_error) _error=1; else print_error("Divisione per zero!"); } else evalstack.peek_real() /= r; } break; case _chgs: { real & r = evalstack.peek_real(); r = -r; } break; case _and: { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = (!r1.is_zero() && !r2.is_zero()) ? UNO : ZERO; } break; case _or: { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = (r1 != ZERO || r2 != ZERO) ? UNO : ZERO; } break; case _not: { real & r1 = evalstack.peek_real(); r1 = (r1 == ZERO) ? UNO : ZERO; } break; case _equal: if (type == _strexpr) { const TString & s2 = evalstack.pop_string(); const TString & s1 = evalstack.pop_string(); evalstack.push(s1 == s2); } else { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = (r1 == r2) ? 1.0 : 0.0; } break; case _match: { const TString & s2 = evalstack.pop_string(); const TString & s1 = evalstack.pop_string(); evalstack.push(s1.match(s2, true)); // Match ignoring case } break; case _noteq: if (type == _strexpr) { const TString & s2 = evalstack.pop_string(); TString & s1 = evalstack.pop_string(); evalstack.push(s1 != s2); } else { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = (r1 != r2) ? 1.0 : 0.0; } break; case _lt: if (type == _strexpr) { const TString & s2 = evalstack.pop_string(); const TString & s1 = evalstack.pop_string(); evalstack.push(s1 < s2); } else { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = (r1 < r2) ? 1.0 : 0.0; } break; case _gt: if (type == _strexpr) { const TString & s2 = evalstack.pop_string(); const TString & s1 = evalstack.pop_string(); evalstack.push(s1 > s2); } else { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = (r1 > r2) ? 1.0 : 0.0; } break; case _lteq: if (type == _strexpr) { const TString& s2 = evalstack.pop_string(); const TString& s1 = evalstack.pop_string(); evalstack.push(s1 <= s2); } else { const real& r2 = evalstack.pop_real(); real& r1 = evalstack.peek_real(); r1 = (r1 <= r2) ? 1.0 : 0.0; } break; case _gteq: if (type == _strexpr) { const TString& s2 = evalstack.pop_string(); const TString& s1 = evalstack.pop_string(); evalstack.push(s1 >= s2); } else { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = (r1 >= r2) ? 1.0 : 0.0; } break; case _userfunc: { const int nparms = (int) evalstack.pop_real().integer(); const int index = atoi(instr.string()); evaluate_user_func(index, nparms, evalstack, type); } break; case _sqrt: { real& r = evalstack.peek_real(); if (r < ZERO) { if (_ignore_error) _error=1; else print_error("Radice negativa!"); r = -r; } r = sqrt(r); } break; case _sqr: evalstack.peek_real() = sqr(evalstack.peek_real()); break; case _exp10: evalstack.peek_real() = exp10(evalstack.peek_real()); break; case _exp: evalstack.peek_real() = exp(evalstack.peek_real()); break; case _log10: evalstack.peek_real() = log10(evalstack.peek_real()); break; case _log: evalstack.peek_real() = log(evalstack.peek_real()); break; case _sin: evalstack.peek_real() = sin(evalstack.peek_real()); break; case _cos: evalstack.peek_real() = cos(evalstack.peek_real()); break; case _tan: evalstack.peek_real() = tan(evalstack.peek_real()); break; case _left: { const int len = (int)evalstack.pop_real().integer(); TString & s1 = evalstack.peek_string(); s1.cut(len); } break; case _right: { const int len = (int)evalstack.pop_real().integer(); TString & s1 = evalstack.peek_string(); s1 = s1.right(len); } break; case _mid: { int count = (int)evalstack.pop_real().integer(); if (count == 0) count--; int from = (int)evalstack.pop_real().integer() - 1; if (from < 0) from = 0; TString & s1 = evalstack.peek_string(); s1 = s1.mid(from, count); } break; case _substr: { const int to = (int)evalstack.pop_real().integer(); int from = (int)evalstack.pop_real().integer() - 1; if (from < 0) from = 0; TString & s1 = evalstack.peek_string(); s1 = s1.sub(from, to); } break; case _len: { const TString& s1 = evalstack.pop_string(); evalstack.push(s1.len()); } break; case _pow: { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = pow(r1, r2); } break; case _min: { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); if (r2 < r1) r1 = r2; } break; case _max: { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); if (r2 > r1) r1 = r2; } break; case _upper: evalstack.peek_string().upper(); break; case _trim: evalstack.peek_string().trim(); break; case _round: { const int ndec = (int)(evalstack.pop_real()).integer(); real & r = evalstack.peek_real(); r.round(ndec); } break; case _trunc: { const int ndec = (int)(evalstack.pop_real()).integer(); real & r = evalstack.peek_real(); r.trunc(ndec); } break; case _ceil: { const int ndec = (int)(evalstack.pop_real()).integer(); real & r = evalstack.peek_real(); r.ceil(ndec); } break; case _perc: { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 = real(r1 * r2 / 100.0); } break; case _scorp: { const real & r2 = evalstack.pop_real(); real & r1 = evalstack.peek_real(); r1 -= r1 * r2 / (r2 + 100.0); } break; case _if: { if (type == _strexpr) { const TString & s1 = evalstack.pop_string(); const TString & s2 = evalstack.pop_string(); const real & cond = evalstack.pop_real(); evalstack.push(cond.is_zero() ? s1 : s2); } else { const real & r1 = evalstack.pop_real(); const real & r2 = evalstack.pop_real(); real & cond = evalstack.peek_real(); cond = cond.is_zero() ? r1 : r2; } } break; case _ansi: { TString& s = evalstack.peek_string(); if (!s.empty()) { const TDate d(s); s = d.string(ANSI); } } break; case _num: type_pointer++; types.set(type_pointer, FALSE); type = _strexpr; break; case _endnum: type_pointer--; type = types[type_pointer] ? _numexpr : _strexpr; if (type == _numexpr) evalstack.peek_real(); break; case _str: type_pointer++; types.set(type_pointer, TRUE); type = _numexpr; break; case _endstr: type_pointer--; type = types[type_pointer] ? _numexpr : _strexpr; if (type == _strexpr) evalstack.peek_string(); break; case _between: { TString& s3 = evalstack.pop_string(); if (all_zeroes(s3)) s3.cut(0); // Svuota una stringa finale di soli zeri TString& s2 = evalstack.pop_string(); if (all_zeroes(s2)) s2.cut(0); // Svuota una stringa iniziale di soli zeri const TString& s1 = evalstack.pop_string(); bool good = true; if (s2.full() || s3.full()) { bool done = false; if (TDate::isdate(s1)) { TDate d2, d3; done = str2date(s2, d2) && str2date(s3, d3); if (done) { const TDate d1(s1); good = (d1 >= d2) && (!d3.ok() || d1 <= d3); } } if (!done) { if (type == _strexpr) good = s1 >= s2 && (s3.empty() || s1 <= s3); else { const real r1(s1), r2(s2), r3(s3); good = (s2.empty() || r1 >= r2) && (s3.empty() || r1 <= r3); } } } evalstack.push(good ? UNO : ZERO); } break; case _cfcheck: { const TString& s1 = evalstack.pop_string(); const TString& s2 = evalstack.pop_string(); const bool good = s1.len() < s2.len() ? cf_check(s1, s2) : cf_check(s2, s1); evalstack.push(good ? UNO : ZERO); } break; case _picheck: { const TString& s1 = evalstack.pop_string(); const TString& s2 = evalstack.pop_string(); const bool good = s1.len() < s2.len() ? pi_check(s1, s2) : pi_check(s2, s1); evalstack.push(good ? UNO : ZERO); } break; default: NFCHECK("operazione non valida %d", (int) instr.getsym()); break; } } // Lo stack non e' vuoto if (_code.items() > 1) _val = (const TValue&)evalstack.pop(); else _val = ZERO; } HIDDEN const char* _s; HIDDEN char _tok[81]; TCodesym TExpression::tok2fun(const char* tok) const { const int MAX_TOK = 31; HIDDEN const char* fnstr[MAX_TOK] = { "ANSI", "BETWEEN","CEIL", "CF_CHECK","COS", "EXP", "EXP10", "IF", "LEFT", "LEN", "LOG", "LOG10", "MAX", "MID", "MIN", "NUM", "PERC", "PI_CHECK","POW", "RIGHT", "ROUND", "SCORP", "SIN", "SQR", "SQRT", "STR", "SUBSTR", "TAN", "TRIM", "TRUNC", "UPPER" }; HIDDEN TCodesym fntok[MAX_TOK] = { _ansi, _between, _ceil, _cfcheck, _cos, _exp, _exp10, _if, _left, _len, _log, _log10, _max, _mid, _min, _num, _perc, _picheck, _pow, _right, _round, _scorp, _sin, _sqr, _sqrt, _str, _substr, _tan, _trim, _trunc, _upper }; int f = 0, l = MAX_TOK-1, i = MAX_TOK/2; for (;;) { // i = (f+l)>>1; i = f + (toupper(*tok) - *fnstr[f]) * (l - f + 1) / (*fnstr[l] - *fnstr[f] + 1); if (i < f || i > l) return _invalid; const int cmp = xvt_str_compare_ignoring_case(tok, fnstr[i]); if (cmp == 0) break; if (cmp > 0) f = i+1; else l = i-1; if (f > l) return _invalid; } CHECKD(i >= 0 && i < MAX_TOK, "Invalid function index ", i); return fntok[i]; } TCodesym TExpression::__gettoken() { TCodesym sym = _invalid; int i = 0; _tok[0] = '\0'; while (isspace(*_s)) _s++; if (!*_s) return _endsym; bool square_bracket = FALSE; if (isdigit(*_s) || (*_s == '.')) { sym = _number; while (isalnum(*_s) || (*_s == '_') || (*_s == '.') || (*_s == ':') || (*_s == '@') || (sym == _variable && *_s == '[') || (sym == _number && *_s == '-' ) || (square_bracket && (*_s == ',' || *_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 == ']') || (*_s == ',') */ ) sym = _variable; } else { if (sym == _variable && *_s == '[') square_bracket = TRUE; } _tok[i++] = *(_s++); } } _tok[i] = '\0'; return sym; } if (isalpha(*_s) || (*_s == '#') || (*_s == '_')) { if (*_s == '#') sym = _variable; _tok[i++] = *(_s++); if (sym == _variable && *_s == '-') { _tok[i++] = *(_s++); if (*_s == '>' || isdigit(*_s)) _tok[i++] = *(_s++); else return _invalid; // Non e' una -> (freccia) } while (isalnum(*_s) || (*_s == '[') || (*_s == ':') || (*_s == '_') || (*_s == '.') || (square_bracket && (*_s == ',' || *_s == ']')) ) { if (*_s == '[') { sym = _variable; square_bracket = TRUE; } else if (*_s == '.') sym = _variable; _tok[i++] = *(_s++); } _tok[i] = '\0'; if (sym != _variable) // So gia' tutto, inutile controllare oltre { sym = tok2fun(_tok); if (sym != _invalid) return sym; const char * p; for (p = _s; isspace(*p); p++); if (*p == '(') return _userfunc; } return _variable; } switch (*_s) { case '"' : case '\'' : { const char sep = *_s; _s++; while ((*_s) && (*_s != sep)) _tok[i++] = *(_s++); _tok[i] = '\0'; if (*_s == sep) _s++; return _string; } case ',' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _comma; case ';' : _tok[i++] = *(_s++); _tok[i] = '\0'; return _semicolon; 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; } HIDDEN int __parms_found = -1; TCodesym TExpression::__factor(TCodesym startsym) { TCodesym sym = _invalid; switch (startsym) { case _lpar: sym = __gettoken(); sym = __expression(sym); if (sym == _rpar) sym = __gettoken(); else sym = _invalid; break; case _variable: { int from = 1, to = 0; char* quadra = strchr(_tok, '['); if (quadra) { if (sscanf(quadra, "[%d,%d]", &from, &to) == 0) { sym = _invalid; break; } *quadra = '\0'; } _code.add(_variable, _tok); if (quadra) { _code.add(_number, real(from)); _code.add(_number, real(to >= from ? to-from+1 : 0)); _code.add(_mid); } int i; for (i = numvar()-1 ; i >= 0; i--) if (strcmp(_tok, varname(i)) == 0) break; if (i < 0) _var.add(_tok); sym = __gettoken(); } break; case _number: case _string: _code.add(startsym, _tok); sym = __gettoken(); break; case _userfunc: { TValue val (_tok); sym = __function(); if (sym != _invalid) { const int index = parse_user_func((const char *) val.string(), __parms_found); if (index < 0) { strcpy(_tok, (const char *) val.string()); sym = _invalid; } else { _code.add(_number, real(__parms_found)); val = real(index); _code.add(startsym, val); _user_func_defined = TRUE; } } } break; case _sqrt: case _sqr: case _exp10: case _exp: case _log10: case _log: case _sin: case _cos: case _tan: case _ansi: case _upper: case _trim: case _len: sym = __function(1); _code.add(startsym); break; case _left: case _right: case _pow: case _min: case _max: case _round: case _ceil: case _trunc: case _perc: case _scorp: case _cfcheck: case _picheck: sym = __function(2); _code.add(startsym); break; case _between: case _mid: case _substr: sym = __function(3); _code.add(startsym); break; case _if: sym = __function(3); _code.add(startsym); break; case _num: case _str: _code.add(startsym); sym = __function(1); _code.add(startsym == _num ? _endnum : _endstr); break; default: break; } return sym; } TCodesym TExpression::__term(TCodesym startsym) { TCodesym sym = __factor(startsym); while (sym == _multiply || sym == _divide) { const TCodesym savedsym = sym; sym = __gettoken(); sym = __factor(sym); _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); } TCodesym TExpression::__function(int nparms, bool fixed_num) { TCodesym sym = __gettoken(); if (sym != _lpar) return _invalid; __parms_found = 0; sym = __gettoken(); if (sym == _rpar) return nparms <= 0 || !fixed_num ? __gettoken() : _invalid; __parms_found++; sym = __expression(sym); while (sym == _comma || sym == _semicolon) { sym = __gettoken(); __parms_found++; sym = __expression(sym); } if (sym == _rpar) return nparms < 0 || __parms_found == nparms || (__parms_found < nparms && !fixed_num) ? __gettoken() : _invalid; return _invalid; } bool TExpression::set(const char* expression, TTypeexp type) { _original = expression; _type = type; _dirty = TRUE; return compile(_original, type); } bool TExpression::compile(const TString& expression, TTypeexp type) { _user_func_defined = FALSE; _s = expression; _type = type; _val = ZERO; _code.clear(); if (expression.blank()) return true; TCodesym currsym = __gettoken(); bool ok = currsym != _invalid; if (ok) ok = __expression(currsym) == _endsym; if (!ok) { _error = 2; if (!_ignore_error) { TString msg; msg << "Espressione errata : " << _original; print_error(msg); } } return ok; } const char* TExpression::last_token() const { return _tok; }