1157 lines
26 KiB
C++
Executable File
1157 lines
26 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, bool ignore_err)
|
|
: _original(expression)
|
|
|
|
{
|
|
_ignore_error=ignore_err;
|
|
_error=0;
|
|
_val = real(0.0);
|
|
_dirty = TRUE;
|
|
_type = type;
|
|
if (!compile(_original, type))
|
|
print_error(format("Wrong expression : %s", expression));
|
|
}
|
|
|
|
|
|
TExpression::TExpression(TTypeexp type, bool ignore_err)
|
|
: _original("")
|
|
{
|
|
_ignore_error=ignore_err;
|
|
_error=0;
|
|
_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),
|
|
_user_func_defined(expr._user_func_defined),
|
|
_ignore_error(expr._ignore_error),_error(expr._error)
|
|
{
|
|
}
|
|
|
|
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 yesnofatal_box("%s", msg);
|
|
}
|
|
|
|
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:
|
|
{
|
|
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()) ? 1.0 : 0.0;
|
|
}
|
|
break;
|
|
case _or:
|
|
{
|
|
const real & r2 = evalstack.pop_real();
|
|
real & r1 = evalstack.peek_real();
|
|
r1 = (r1 != ZERO || r2 != ZERO) ? 1.0 : 0.0;
|
|
}
|
|
break;
|
|
case _not:
|
|
{
|
|
real & r1 = evalstack.peek_real();
|
|
r1 = (r1 == ZERO) ? 1.0 : 0.0;
|
|
}
|
|
break;
|
|
case _equal:
|
|
if (type == _strexpr)
|
|
{
|
|
const TString & s2 = evalstack.pop_string();
|
|
const TString & s1 = evalstack.pop_string();
|
|
evalstack.push(real(s1 == s2 ? 1.0 : 0.0));
|
|
}
|
|
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(real((s1.match(s2)) ? 1.0 : 0.0));
|
|
}
|
|
break;
|
|
case _noteq:
|
|
if (type == _strexpr)
|
|
{
|
|
const TString & s2 = evalstack.pop_string();
|
|
TString & s1 = evalstack.pop_string();
|
|
evalstack.push(real(s1 != s2 ? 1.0 : 0.0));
|
|
}
|
|
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(real(s1 < s2 ? 1.0 : 0.0));
|
|
}
|
|
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(real(s1 > s2 ? 1.0 : 0.0));
|
|
}
|
|
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(real(s1 <= s2 ? 1.0 : 0.0));
|
|
}
|
|
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(real(s1 >= s2 ? 1.0 : 0.0));
|
|
}
|
|
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:
|
|
evalstack.peek_real() = sqrt(evalstack.peek_real());
|
|
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 = s1.left(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:
|
|
{
|
|
TString s1(evalstack.pop_string());
|
|
|
|
evalstack.push(real(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 _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();
|
|
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;
|
|
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 = 27;
|
|
HIDDEN const char* fnstr[MAX_TOK] = { "ANSI", "CEIL", "COS", "EXP", "EXP10",
|
|
"IF", "LEFT", "LEN", "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, _len, _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 == ':') || (*_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++);
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
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 = __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.set(format("%d", 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 _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:
|
|
sym = __function(2);
|
|
_code.add(startsym);
|
|
break;
|
|
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(TRUE);
|
|
if (sym != _lpar)
|
|
return _invalid;
|
|
__parms_found = 0;
|
|
sym = __gettoken(TRUE);
|
|
if (sym == _rpar)
|
|
return nparms <= 0 || !fixed_num ? __gettoken(TRUE) : _invalid;
|
|
__parms_found++;
|
|
while ((sym = __expression(sym)) == _comma)
|
|
{
|
|
sym = __gettoken(TRUE);
|
|
__parms_found++;
|
|
}
|
|
if (sym == _rpar)
|
|
return nparms < 0 || __parms_found == nparms || (__parms_found < nparms && !fixed_num) ?
|
|
__gettoken(TRUE) :
|
|
_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 char* expression, TTypeexp type)
|
|
|
|
{
|
|
TCodesym currsym;
|
|
|
|
_user_func_defined = FALSE;
|
|
_s = expression;
|
|
_type = type;
|
|
_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;
|
|
}
|