diff --git a/include/expr.cpp b/include/expr.cpp index d4ef420f2..90f76c5ca 100755 --- a/include/expr.cpp +++ b/include/expr.cpp @@ -11,7 +11,8 @@ TValue::TValue(const real& val) { _r = val; - _s = val.string( ); + _s = val.string(); + _t = _numexpr; } TCodearray::TCodearray(int size) : _rpn(size) @@ -45,14 +46,12 @@ TCode& TCode::operator =(const TCode& b) } 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++); @@ -190,7 +189,7 @@ TExpression::operator const char*() void TExpression::print_on(ostream& out) const { out << _original; } -void TExpression::evaluate_user_func(const char * name, int nparms, TStack & stack) +void TExpression::evaluate_user_func(const char * name, int nparms, TStack & stack) const { NFCHECK("Unknown function : %s ", name); @@ -246,7 +245,7 @@ void TExpression::eval() { TStack evalstack(50); TCode instr; - real o1, o2, zero(0.00); + real o1, o2; TString s1, s2; _code.begin(); @@ -315,15 +314,15 @@ void TExpression::eval() 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")); + 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)); + evalstack.push(real((o1 != ZERO && o2 != ZERO) ? 1.0 : 0.0)); } break; case _or: @@ -331,18 +330,18 @@ void TExpression::eval() { o2 = real((const char*) (TString&)evalstack.pop()); o1 = real((const char*) (TString&)evalstack.pop()); - evalstack.push(TString((o1 != zero || o2 != zero) ? "1" : "0")); + 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)); + 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)); + evalstack.push(real((o1 == ZERO) ? 1.0 : 0.0)); break; case _equal: if (_type == _strexpr) @@ -488,6 +487,14 @@ void TExpression::eval() evalstack.push(s); } break; + case _substr: + { + const int to = (int)((const real&)evalstack.pop()).integer(); + const int from = (int)((const real&)evalstack.pop()).integer() - 1; + const TString& s = ((const TString&)evalstack.pop()).sub(from, to); + evalstack.push(s); + } + break; case _pow: o2 = (real&) evalstack.pop(); o1 = (real&) evalstack.pop(); @@ -516,6 +523,46 @@ void TExpression::eval() evalstack.push(o1); } break; + case _trunc: + { + const int ndec = (int)((real&) evalstack.pop()).integer(); + o1 = (real&) evalstack.pop(); + o1.trunc(ndec); + evalstack.push(o1); + } + break; + case _ceil: + { + const int ndec = (int)((real&) evalstack.pop()).integer(); + o1 = (real&) evalstack.pop(); + o1.ceil(ndec); + evalstack.push(o1); + } + break; + case _perc: + { + o1 = (real&) evalstack.pop(); + o2 = (real&) evalstack.pop(); + evalstack.push(real(o1 * o2 / 100.0)); + } + break; + case _scorp: + { + const real percent = (real&)evalstack.pop(); + real imponibile = (real&)evalstack.pop(); + const real imposta = imponibile * percent / (percent + 100.0); + imponibile -= imposta; + evalstack.push(imponibile); + } + break; + case _if: + { + s1 = (TString&)evalstack.pop(); + s2 = (TString&)evalstack.pop(); + const real cond = (real&) evalstack.pop();; + evalstack.push(cond.is_zero() ? s1 : s2); + } + break; case _ansi: { const TDate d((const TString&)evalstack.pop()); @@ -526,29 +573,55 @@ void TExpression::eval() break; } } - if (_type == _strexpr) - _val = (const char*) (TString&) evalstack.pop(); - else - _val = (real&) evalstack.pop(); + if (_type == _strexpr) + _val = (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", - "round", "ansi", NULL }; -HIDDEN TCodesym _fntok[] = { _sqrt, _sqr, _exp10, _exp, _log10, _log, - _sin, _cos, _tan, _left, _right, _pow, - _min, _max, _mid, _upper, _round, _ansi}; +TCodesym TExpression::tok2fun(const char* tok) const +{ + const int MAX_TOK = 24; + HIDDEN const char* fnstr[MAX_TOK] = { "ANSI", "CEIL", "COS", "EXP", "EXP10", + "IF", "LEFT", "LOG", "LOG10", "MAX", + "MID", "MIN", "PERC", "POW", "RIGHT", + "ROUND", "SCORP", "SIN", "SQR", "SQRT", + "SUBSTR", "TAN", "TRUNC", "UPPER" }; + + HIDDEN TCodesym fntok[MAX_TOK] = { _ansi, _ceil, _cos, _exp, _exp10, + _if, _left, _log, _log10, _max, + _mid, _min, _perc, _pow, _right, + _round, _scorp, _sin, _sqr, _sqrt, + _substr, _tan, _trunc, _upper }; + + int f = 0, l = MAX_TOK-1, i; + while (TRUE) + { + i = (f+l)>>1; + const int cmp = stricmp(tok, fnstr[i]); + if (cmp == 0) + break; + if (cmp > 0) f = i+1; + else l = i-1; + if (f > l) + { + i = -1; + break; + } + } + return i >= 0 ? fntok[i] : _invalid; +} + + TCodesym TExpression::__gettoken(bool reduct) - { - TCodesym sym = _invalid; + TCodesym sym = _invalid; int i = 0; _tok[0] = '\0'; @@ -598,13 +671,14 @@ TCodesym TExpression::__gettoken(bool reduct) _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]; - for (const char * p = _s; *p && *p == ' '; p++); + + sym = tok2fun(_tok); // Guy was here! + if (sym != _invalid) + return sym; + + for (const char * p = _s; isspace(*p); p++); if (*p == '(') - return _userfunc; + return _userfunc; return _variable; } switch (*_s) @@ -703,9 +777,8 @@ TCodesym TExpression::__gettoken(bool reduct) TCodesym TExpression::__factor(TCodesym startsym) - { - TCodesym sym = _invalid; + TCodesym sym = _invalid; switch (startsym) { @@ -729,7 +802,6 @@ TCodesym TExpression::__factor(TCodesym startsym) case _userfunc: { TValue val (_tok); - sym = __gettoken(); if (sym == _lpar) { @@ -779,6 +851,10 @@ TCodesym TExpression::__factor(TCodesym startsym) case _min: case _max: case _round: + case _ceil: + case _trunc: + case _perc: + case _scorp: sym = __gettoken(); if (sym == _lpar) sym = __gettoken(TRUE); else break; @@ -791,6 +867,7 @@ TCodesym TExpression::__factor(TCodesym startsym) _code.add(startsym); break; case _mid: + case _substr: sym = __gettoken(); if (sym == _lpar) sym = __gettoken(TRUE); else break; @@ -805,7 +882,22 @@ TCodesym TExpression::__factor(TCodesym startsym) if (sym == _rpar) sym = __gettoken(); else break; _code.add(startsym); - break; + break; + case _if: + sym = __gettoken(); + if (sym == _lpar) sym = __gettoken(TRUE); + else break; + sym = __expression(sym); + if (sym == _comma) sym = __gettoken(TRUE); + else break; + sym = __expression(sym); + if (sym == _comma) sym = __gettoken(TRUE); + else break; + sym = __expression(sym); + if (sym == _rpar) sym = __gettoken(); + else break; + _code.add(startsym); + break; default: break; } @@ -814,7 +906,6 @@ TCodesym TExpression::__factor(TCodesym startsym) TCodesym TExpression::__term(TCodesym startsym) - { TCodesym sym; diff --git a/include/expr.h b/include/expr.h index d820e9054..873d0184f 100755 --- a/include/expr.h +++ b/include/expr.h @@ -54,8 +54,16 @@ enum TCodesym { _mid, // @emem Media degli elementi _upper, // @emem Trasformazione in maiuscolo _round, // @emem Arrotondamento - _ansi } ; // @emem Data in ansi - + _ansi, // @emem Data in ansi + _if, // @emem Se(expr, val TRUE, val FALSE) + _num, // @emem Converte una stringa in numero + _str, // @emem Converte un numero in stringa + _ceil, // @emem Arrotonda un numero all'intero successivo + _trunc, // @emem Tronca i decimali + _perc, // @emem Calcola la percentuale + _scorp, // @emem Scorpora una percentuale + _substr, // @emem Estrae una sottostringa +} ; // @doc INTERNAL // @enum TTypeexp | Tipi di espressioni definiti @@ -79,30 +87,39 @@ enum TCodesym { real _r; // @cmember:(INTERNAL) Valore in formato stringa TString _s; - + // @cmember:(INTERNAL) Tipo preferito + TTypeexp _t; + // @access Public Member public: // @cmember Assegnamento tra oggetti TValue TValue& operator =(const TValue& val) - { _s = val._s; _r = val._r; return *this;} + { _s = val._s; _r = val._r; _t = val._t; return *this; } + // @cmember Assegnamento di una stringa + TValue& operator =(const TString& s) + { _s = s; _r = real(s); _t = _strexpr; return *this; } + // @cmember Assegnamento di un numero + TValue& operator =(const real& r) + { _s = r.string(); _r = r; _t = _numexpr; return *this; } // @cmember Ritorna il valore numerico const real& number() const - { return _r;} + { return _r; } // @cmember Ritorna il valore come stringa const char* string() const { return (const char*) _s;} // @cmember Setta il valore passato come real void set(const real& val) - { _r = val; _s = val.string();} + { _r = val; _s = val.string(); _t = _numexpr; } // @cmember Setta il valore passato come stringa void set(const char* val) - { _s = val; _r = real(val);} - + { _s = val; _r = real(val); _t = _strexpr; } + // @cmember Setta il valore passato come stringa + TTypeexp type() const { return _t; } // @cmember Costruttore. Inizializza TValue con un reale TValue(const real& val); // @cmember Costruttore. Inizializza TValue con una stringa TValue(const char* val) - { _s = val; _r = real(val);} + { _s = val; _r = real(val); _t = _strexpr; } // @cmember Costruttore. Inizializza TValue con un altro TValue TValue(const TValue& val) { *this = val; } @@ -377,6 +394,8 @@ class TExpression : public TObject protected: // @cmember Valuta (calcola) l'espressione void eval(); + // @cmember Converte una stringa in un nome di funzione o _invalid se non esiste + TCodesym tok2fun(const char* tok) const; // @cmember Ritorna il prossimo token dell'espressione (se
e' TRUE interpreta // la virgola come un token) TCodesym __gettoken(bool reduct = FALSE); @@ -392,7 +411,7 @@ protected: protected: // TObject // @cmember Stampa l'espressione su
(serve per implementare l'insertore)
virtual void print_on(ostream& out) const ;
- virtual void evaluate_user_func(const char * name, int nparms, TStack & stack);
+ virtual void evaluate_user_func(const char* name, int nparms, TStack& stack) const;
// @access Public Member
public:
diff --git a/include/stack.cpp b/include/stack.cpp
index f6ec2b7e3..7836228ba 100755
--- a/include/stack.cpp
+++ b/include/stack.cpp
@@ -8,9 +8,19 @@ void TStack::push(const TObject& o)
add(o, _sp++);
}
+void TStack::push(TObject* o)
+{
+ add(o, _sp++);
+}
TObject& TStack::pop()
{
CHECK(count() > 0, "Stack underflow!");
return (*this)[--_sp];
}
+
+TObject& TStack::peek(int depth) const
+{
+ CHECK(depth > _sp, "Stack underflow!");
+ return (*this)[_sp-depth-1];
+}
diff --git a/include/stack.h b/include/stack.h
index f7f3e0b99..9e628e437 100755
--- a/include/stack.h
+++ b/include/stack.h
@@ -12,7 +12,7 @@
// @base public | TArray
class TStack : private TArray
-// @author:(INTERNAL) Sandro
+// @author:(INTERNAL) Alex
// @access:(INTERNAL) Private Member
{
@@ -21,16 +21,21 @@ class TStack : private TArray
// @access Public Member
public:
- // @cmember Costruttore. Chaima il costruttore di