campo-sirio/include/expr.cpp
guy 46922674c3 Potenziate espreesioni
git-svn-id: svn://10.65.10.50/trunk@3475 c028cbd2-c16b-5b4b-a496-9718f37d4682
1996-09-02 13:58:41 +00:00

1233 lines
28 KiB
C++
Executable File

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#define __EXPR_CPP
#include <expr.h>
#include <stack.h>
#include <utility.h>
#include <date.h>
TValue::TValue(const real& val)
{
_r = val;
_s = val.string();
_t = _numexpr;
}
void TCodearray::clear()
{
destroy();
TArray::add(new TCode(_endsym));
}
void TCodearray::add(TCodesym sym, const TValue& val)
{
TArray::insert(new TCode(sym, val), last());
}
TObject * TCode::dup() const
{
TCode * o = new TCode(*this);
return o;
}
TCode& TCode::operator =(const TCode& b)
{
_sym = b._sym;
_val = b._val;
return *this;
}
TObject * TVar::dup() const
{
TVar * o = new TVar(*this);
return o;
}
void TVararray::add(const char* name, const TValue& val)
{
TArray::add(new TVar(name, val));
}
void TVararray::set(const char* name, const real& val)
{
for (int i = items()-1; i >= 0; i--)
{
TVar* var = (TVar*)objptr(i);
CHECKS(var, "Variabile NULLA ", name);
if (strcmp(var->getname(), name) == 0)
{
*var = val;
break;
}
}
}
void TVararray::set(const char* name, const char* val)
{
for (int i = items()-1; i >= 0; i--)
{
TVar* var = (TVar*)objptr(i);
CHECKS(var, "Variabile NULLA ", name);
if (strcmp(var->getname(), name) == 0)
{
*var = val;
break;
}
}
}
const real& TVararray::getnum(const char* name)
{
for (int i = items()-1; i >= 0; i--)
{
const TVar* var = (const TVar*)objptr(i);
CHECKS(var, "Variabile NULLA ", name);
if (strcmp(var->getname(), name) == 0)
return var->number();
}
NFCHECK("Unknown variable: %s", name);
return ZERO;
}
const real& TVararray::getnum(int varnum)
{
if (varnum >= items())
fatal_box("invalid variable number : %d", varnum);
return ((TVar*)objptr(varnum))->number();
}
const char* TVararray::getstring(const char* name)
{
for (int i = items()-1; i >= 0; i--)
{
const TVar* var = (TVar*)objptr(i);
if (strcmp(var->getname(), name) == 0)
return var->string();
}
NFCHECK("Unknown variable : %s", name);
return "";
}
const char* TVararray::getstring(int varnum)
{
if (varnum < 0 || varnum >= items())
{
NFCHECK("Invalid variable number : %d", varnum);
return "";
}
const TVar* var = (const TVar*)objptr(varnum);
CHECKD(var, "Variabile nulla: ", varnum);
return var->string();
}
///////////////////////////////////////////////////////////
// TEval_stack
///////////////////////////////////////////////////////////
real& TEval_stack::pop_real()
{
TObject& o = pop();
if (o.class_id() == CLASS_STRING)
{
real* r = new real((TString&)o);
push(r);
return (real&)pop();
}
return (real&)o;
}
real& TEval_stack::peek_real()
{
TObject& o = peek(0);
if (o.class_id() == CLASS_STRING)
{
pop();
real* r = new real((TString&)o);
push(r);
return *r;
}
return (real&)o;
}
TString& TEval_stack::pop_string()
{
TObject& o = pop();
if (o.class_id() == CLASS_STRING)
return (TString&)o;
TString* s = new TString(((real&)o).string());
push(s);
return (TString&)pop();
}
TString& TEval_stack::peek_string()
{
TObject& o = peek();
if (o.class_id() == CLASS_STRING)
return (TString&)o;
pop();
TString* s = new TString(((real&)o).string());
push(s);
return *s;
}
///////////////////////////////////////////////////////////
// TExpression
///////////////////////////////////////////////////////////
TExpression::TExpression(const char* expression, TTypeexp type)
: _original(expression)
{
_val = real(0.0);
_dirty = TRUE;
_type = type;
if (!compile(_original, 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::TExpression(const TExpression & expr)
: _code(expr._code), _var(expr._var),
_val(expr._val), _dirty(expr._dirty),
_type(expr._type), _original(expr._original)
{
}
TObject* TExpression::dup() const
{
TExpression* o = new TExpression(*this);
return o;
}
TExpression::operator const real&()
{
if (user_func_dirty() || _dirty) eval();
_dirty = FALSE;
return _val.number();
}
TExpression::operator const char*()
{
if (user_func_dirty() || _dirty) eval();
_dirty = FALSE;
return _val.string();
}
TExpression::operator bool()
{
if (user_func_dirty() || _dirty) eval();
_dirty = FALSE;
return !_val.number().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();
if (curtype == _numexpr)
stack.push(ZERO);
else
stack.push(TString(""));
}
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 (strcmp(_var.getstring(varname), val) != 0)
{
_var.set(varname, val);
_dirty = TRUE;
}
}
void TExpression::setvar(int varnum, const char* val)
{
if (strcmp(_var.getstring(varnum), val) != 0)
{
_var.set(varnum, val);
_dirty = TRUE;
}
}
bool TExpression::print_error(const char* msg) const
{
return fatal_box("%s", msg);
}
void TExpression::eval()
{
TEval_stack evalstack;
TBit_array types;
int type_pointer = 0;
TCode instr;
real o1, o2;
TString s1, s2;
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)
{
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 = evalstack.pop_string();
s1 = evalstack.pop_string();
s1 << s2;
evalstack.push(s1);
*/
// Non unire le seguenti righe
const TString& s = evalstack.pop_string();
evalstack.peek_string() << s;
}
else
{
/*
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real(o1 + o2));
*/
// Non unire le seguenti righe
const real& r = evalstack.pop_real();
evalstack.peek_real() += r;
}
break;
case _minus:
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real(o1 - o2));
break;
case _multiply:
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real(o1 * o2));
break;
case _divide:
o2 = evalstack.pop_real();
if (o2.is_zero())
{
print_error("Divisione per zero!");
o2 = 1.0;
}
o1 = evalstack.pop_real();
evalstack.push(real(o1 / o2));
break;
case _chgs:
o1 = evalstack.pop_real();
evalstack.push(-o1);
break;
case _and:
if (type == _strexpr)
{
o2 = real((const char*)evalstack.pop_string());
o1 = real((const char*)evalstack.pop_string());
evalstack.push(TString((o1 != ZERO && o2 != ZERO) ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 != ZERO && o2 != ZERO) ? 1.0 : 0.0));
}
break;
case _or:
if (type == _strexpr)
{
o2 = real((const char*) evalstack.pop_string());
o1 = real((const char*) evalstack.pop_string());
evalstack.push(TString((o1 != ZERO || o2 != ZERO) ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 != ZERO || o2 != ZERO) ? 1.0 : 0.0));
}
break;
case _not:
o1 = evalstack.pop_real();
evalstack.push(real((o1 == ZERO) ? 1.0 : 0.0));
break;
case _equal:
if (type == _strexpr)
{
s2 = evalstack.pop_string();
s1 = evalstack.pop_string();
evalstack.push(TString((s1 == s2) ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 == o2) ? 1.0 : 0.0));
}
break;
case _match:
s2 = evalstack.pop_string();
s1 = evalstack.pop_string();
evalstack.push(TString((s1.match(s2)) ? "1" : "0"));
break;
case _noteq:
if (type == _strexpr)
{
s2 = evalstack.pop_string();
s1 = evalstack.pop_string();
evalstack.push(TString(s1 != s2 ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 != o2) ? 1.0 : 0.0));
}
break;
case _lt:
if (type == _strexpr)
{
s2 = evalstack.pop_string();
s1 = evalstack.pop_string();
evalstack.push(TString((s1 < (const char*)s2) ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 < o2) ? 1.0 : 0.0));
}
break;
case _gt:
if (type == _strexpr)
{
s2 = evalstack.pop_string();
s1 = evalstack.pop_string();
evalstack.push(TString((s1 > (const char*)s2) ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 > o2) ? 1.0 : 0.0));
}
break;
case _lteq:
if (type == _strexpr)
{
s2 = evalstack.pop_string();
s1 = evalstack.pop_string();
evalstack.push(TString((s1 <= (const char*)s2) ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 <= o2) ? 1.0 : 0.0));
}
break;
case _gteq:
if (type == _strexpr)
{
s2 = evalstack.pop_string();
s1 = evalstack.pop_string();
evalstack.push(TString((s1 >= (const char*)s2) ? "1" : "0"));
}
else
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real((o1 >= o2) ? 1.0 : 0.0));
}
break;
case _userfunc:
{
const int nparms = (int) ((real &) evalstack.pop()).integer();
const int index = atoi(instr.string());
evaluate_user_func(index, nparms, evalstack, type);
}
break;
case _sqrt:
evalstack.push(real(sqrt(evalstack.pop_real())));
break;
case _sqr:
evalstack.push(real(sqr(evalstack.pop_real())));
break;
case _exp10:
evalstack.push(real(exp10(evalstack.pop_real())));
break;
case _exp:
evalstack.push(real(exp(evalstack.pop_real())));
break;
case _log10:
evalstack.push(real(log10(evalstack.pop_real())));
break;
case _log:
evalstack.push(real(log(evalstack.pop_real())));
break;
case _sin:
evalstack.push(real(sin(evalstack.pop_real())));
break;
case _cos:
evalstack.push(real(cos(evalstack.pop_real())));
break;
case _tan:
evalstack.push(real(tan(evalstack.pop_real())));
break;
case _left:
o2 = evalstack.pop_real();
s2 = evalstack.pop_string();
s1 = s2.left((int)o2.integer());
evalstack.push(s1);
break;
case _right:
o2 = evalstack.pop_real();
s2 = evalstack.pop_string();
s1 = s2.right((int)o2.integer());
evalstack.push(s1);
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& s = evalstack.peek_string();
s = s.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& s = evalstack.peek_string();
s = s.sub(from, to);
}
break;
case _pow:
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(real(pow(o1, o2)));
break;
case _min:
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(o1 < o2 ? o1 : o2);
break;
case _max:
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
evalstack.push(o1 > o2 ? o1 : o2);
break;
case _upper:
evalstack.peek_string().upper();
break;
case _round:
{
const int ndec = (int)evalstack.pop_real().integer();
o1 = evalstack.pop_real();
o1.round(ndec);
evalstack.push(o1);
}
break;
case _trunc:
{
const int ndec = (int)evalstack.pop_real().integer();
o1 = evalstack.pop_real();
o1.trunc(ndec);
evalstack.push(o1);
}
break;
case _ceil:
{
const int ndec = (int)evalstack.pop_real().integer();
o1 = evalstack.pop_real();
o1.ceil(ndec);
evalstack.push(o1);
}
break;
case _perc:
{
o2 = evalstack.pop_real();
o1 = evalstack.pop_real();
const real val = real(o1 * o2 / 100.0);
evalstack.push(val);
}
break;
case _scorp:
{
const real percent = evalstack.pop_real();
real val = evalstack.pop_real();
val -= val * percent / (percent + 100.0);
evalstack.push(val);
}
break;
case _if:
{
if (type == _strexpr)
{
s1 = evalstack.pop_string();
s2 = evalstack.pop_string();
const real cond(evalstack.pop_string());
evalstack.push(cond.is_zero() ? s1 : s2);
}
else
{
o1 = evalstack.pop_real();
o2 = evalstack.pop_real();
const real cond = evalstack.pop_real();
evalstack.push(cond.is_zero() ? o1 : o2);
}
}
break;
case _ansi:
{
const TDate d(evalstack.pop_string());
const TString16 s(d.string(ANSI));
evalstack.push(s);
}
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.push(real(evalstack.pop_string()));
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.push(TString(evalstack.pop_real().string()));
break;
default:
NFCHECK("operazione non valida %d", (int) instr.getsym());
break;
}
}
// L'espressione non e' vuota
if (_code.items() > 1)
{
if (_type == _strexpr)
_val = evalstack.pop_string();
else
_val = evalstack.pop_real();
}
else
_val = ZERO;
}
HIDDEN const char* _s;
HIDDEN char _tok[81];
TCodesym TExpression::tok2fun(const char* tok) const
{
const int MAX_TOK = 26;
HIDDEN const char* fnstr[MAX_TOK] = { "ANSI", "CEIL", "COS", "EXP", "EXP10",
"IF", "LEFT", "LOG", "LOG10", "MAX",
"MID", "MIN", "NUM", "PERC", "POW",
"RIGHT", "ROUND", "SCORP", "SIN", "SQR",
"SQRT", "STR", "SUBSTR","TAN", "TRUNC",
"UPPER"};
HIDDEN TCodesym fntok[MAX_TOK] = { _ansi, _ceil, _cos, _exp, _exp10,
_if, _left, _log, _log10, _max,
_mid, _min, _num, _perc, _pow,
_right, _round, _scorp, _sin, _sqr,
_sqrt, _str, _substr, _tan, _trunc,
_upper};
int f = 0, l = MAX_TOK-1, i = MAX_TOK/2;
while (TRUE)
{
// 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 = stricmp(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(bool /* reduct */)
{
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 == ':') ||
(sym == _number && (*_s == '-' || *_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++);
while (isalnum(*_s) || (*_s == '-') || (*_s == '[') ||
(*_s == ':') || (*_s == '_') ||
(square_bracket && (*_s == ',' || *_s == ']'))
)
{
if (*_s == '-')
{
if (_s[1] != '>')
break; // Non e' una -> (freccia)
_tok[i++] = *(_s++);
sym = _variable;
}
else
{
if (*_s == '[')
{
sym = _variable;
square_bracket = TRUE;
}
}
_tok[i++] = *(_s++);
}
_tok[i] = '\0';
if (sym != _variable) // So gia' tutto, inutile controllare oltre
{
sym = tok2fun(_tok);
if (sym != _invalid)
return sym;
for (const char * 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 _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();
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);
}
for (int i = numvar()-1 ; i >= 0; i--)
if (strcmp(_tok, varname(i)) == 0) break;
if (i < 0) _var.add(_tok);
sym = __gettoken(TRUE);
}
break;
case _number:
case _string:
_code.add(startsym, _tok);
sym = __gettoken(TRUE);
break;
case _userfunc:
{
TValue val (_tok);
sym = __gettoken();
if (sym == _lpar)
{
sym = __gettoken();
int nparms = sym == _rpar ? 0 : 1;
if (sym != _rpar)
{
while ((sym = __expression(sym)) == _comma)
{
sym = __gettoken(TRUE);
nparms++;
}
}
if (sym == _rpar)
{
_code.add(_number, real(nparms));
const int index = parse_user_func((const char *) val.string(), nparms);
if (index < 0)
{
strcpy(_tok, (const char *) val.string());
sym = _invalid;
}
else
{
val.set(format("%d", index));
_code.add(startsym, val);
_user_func_defined = TRUE;
sym = __gettoken(TRUE);
}
}
else
sym = _invalid;
}
}
break;
case _sqrt:
case _sqr:
case _exp10:
case _exp:
case _log10:
case _log:
case _sin:
case _cos:
case _tan:
case _ansi:
sym = __gettoken();
if (sym == _lpar) sym = __gettoken();
else break;
sym = __expression(sym);
if (sym == _rpar) sym = __gettoken();
else break;
_code.add(startsym);
break;
case _upper:
sym = __gettoken();
if (sym == _lpar) sym = __gettoken();
else break;
sym = __expression(sym);
if (sym == _rpar) sym = __gettoken();
else break;
_code.add(startsym);
break;
case _left:
case _right:
case _pow:
case _min:
case _max:
case _round:
case _ceil:
case _trunc:
case _perc:
case _scorp:
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 == _rpar) sym = __gettoken(TRUE);
else break;
_code.add(startsym);
break;
case _mid:
case _substr:
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(TRUE);
else break;
_code.add(startsym);
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(TRUE);
else break;
_code.add(startsym);
break;
case _num:
case _str:
_code.add(startsym);
sym = __gettoken();
if (sym == _lpar) sym = __gettoken();
else break;
sym = __expression(sym);
if (sym == _rpar) sym = __gettoken();
else break;
_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);
}
bool TExpression::set(const char* expression, TTypeexp type)
{
_original = expression;
_type = type;
_dirty = TRUE;
return compile(_original, type);
}
bool TExpression::compile(const char* expression, TTypeexp type)
{
TCodesym currsym;
_user_func_defined = FALSE;
_s = expression;
_type = type;
/*
TString sc(256);
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)
{
const char sep (strchr(_tok, '\"') != NULL ? '\'' : '\"');
sc << sep << _tok << sep;
}
else sc << " " << _tok;
}
_s = sc;
*/
_val = real(0.0);
_code.clear();
if (*_s == '\0')
return TRUE;
if ((currsym = __gettoken()) == _invalid)
return FALSE;
return __expression(currsym) == _endsym;
}
const char* TExpression::last_token() const
{
return _tok;
}