/**************************************************************************/ /* File: evalfunc.cc */ /* Author: Joachim Schoeberl */ /* Date: 01. Oct. 95 */ /**************************************************************************/ /* Function parser */ #include namespace ngstd { #include "bessel.hpp" using namespace ngstd; SymbolTable EvalFunction::functions; EvalFunction :: EvalFunction () { ; } EvalFunction :: EvalFunction (istream & aist) { ist = &aist; ReadNext(); ParseExpression (); } EvalFunction :: EvalFunction (const string & str) { stringstream strstr(str); ist = &strstr; ReadNext(); ParseExpression (); } EvalFunction :: EvalFunction (const EvalFunction & eval2) { program = eval2.program; constants = eval2.constants; globvariables = eval2.globvariables; } EvalFunction :: ~EvalFunction () { ; } void EvalFunction :: Parse (istream & aist) { ist = &aist; ReadNext(); ParseExpression (); } void EvalFunction :: AddConstant (double val) { step hstep; hstep.op = CONSTANT; hstep.operand.val = val; program.Append (hstep); } void EvalFunction :: AddVariable (int varnum) { step hstep; hstep.op = VARIABLE; hstep.operand.varnum = varnum; program.Append (hstep); } void EvalFunction :: AddGlobVariable (const double * aglobvar) { step hstep; hstep.op = GLOBVAR; hstep.operand.globvar = aglobvar; program.Append (hstep); } void EvalFunction :: AddFunction (double (*fun) (double)) { step hstep; hstep.op = FUNCTION; hstep.operand.fun = fun; program.Append (hstep); } void EvalFunction :: AddOperation (EVAL_TOKEN op) { step hstep; hstep.op = op; hstep.operand.val = 0; program.Append (hstep); } double EvalFunction :: Eval (const double * x) const { double y; Eval (x, &y, 1); return y; } void EvalFunction :: DefineConstant (const char * name, double val) { // cout << "evalfunc, def const " << name << " = " << val << endl; constants.Set (name, val); } void EvalFunction :: DefineGlobalVariable (const char * name, double * var) { // cout << "evalfunc, def const " << name << " = " << val << endl; globvariables.Set (name, var); } void EvalFunction :: Eval (const double * x, double * y, int ydim) const { int i, stacksize; /* enum { LOC_SIZE = 100 }; double locmem[LOC_SIZE]; double *pmem; if (program.Size() <= LOC_SIZE) pmem = locmem; else pmem = new double[program.Size()]; FlatArray stack(program.Size(), pmem); */ ArrayMem stack(program.Size()); stacksize = -1; for (i = 0; i < program.Size(); i++) { switch (program[i].op) { case ADD: stack[stacksize-1] += stack[stacksize]; stacksize--; break; case SUB: stack[stacksize-1] -= stack[stacksize]; stacksize--; break; case MULT: stack[stacksize-1] *= stack[stacksize]; stacksize--; break; case DIV: stack[stacksize-1] /= stack[stacksize]; stacksize--; break; case NEG: stack[stacksize] = -stack[stacksize]; break; case CONSTANT: stacksize++; stack[stacksize] = program[i].operand.val; break; case VARIABLE: stacksize++; stack[stacksize] = x[program[i].operand.varnum]; break; case GLOBVAR: stacksize++; stack[stacksize] = *program[i].operand.globvar; break; case FUNCTION: stack[stacksize] = (*program[i].operand.fun) (stack[stacksize]); break; case SIN: stack[stacksize] = sin (stack[stacksize]); break; case COS: stack[stacksize] = cos (stack[stacksize]); break; case TAN: stack[stacksize] = tan (stack[stacksize]); break; case ATAN: stack[stacksize] = atan (stack[stacksize]); break; case EXP: stack[stacksize] = exp (stack[stacksize]); break; case LOG: stack[stacksize] = log (stack[stacksize]); break; case ABS: stack[stacksize] = fabs (stack[stacksize]); break; case SQRT: stack[stacksize] = sqrt (stack[stacksize]); break; case STEP: stack[stacksize] = (stack[stacksize] >= 0) ? 1 : 0; break; /* case BESSELJ0: stack[stacksize] = bessj0 (stack[stacksize]); break; case BESSELJ1: stack[stacksize] = bessj1 (stack[stacksize]); break; case BESSELY0: stack[stacksize] = bessy0 (stack[stacksize]); break; case BESSELY1: stack[stacksize] = bessy1 (stack[stacksize]); break; */ default: cerr << "undefined operation for EvalFunction" << endl; } } if (stacksize != ydim-1) { cerr << "final stacksize not matching ydim" << endl; return; } for (i = 0; i < ydim; i++) y[i] = stack[i]; // if (program.Size() > LOC_SIZE) // delete pmem; } bool EvalFunction :: IsConstant () const { for (int i = 0; i < program.Size(); i++) { EVAL_TOKEN op = program[i].op; if (op == VARIABLE || op == GLOBVAR || op == COEFF_FUNC) return 0; } return 1; } void EvalFunction :: Print (ostream & ost) const { for (int i = 0; i < program.Size(); i++) { EVAL_TOKEN op = program[i].op; ost << "Step " << i << ": " << (int)op << " = " << (char) op << ", val = " << program[i].operand.val << endl; } } void EvalFunction :: ParseExpression () { ParseTerm (); while (1) { // cout << "parseexpr, goken = " << GetToken() << endl; switch (GetToken()) { case ADD: { ReadNext(); ParseTerm (); AddOperation (ADD); break; } case SUB: { ReadNext(); ParseTerm (); AddOperation (SUB); break; } default: return; } } } void EvalFunction :: ParseTerm () { ParsePrimary(); while (1) { // cout << "parseterm, goken = " << GetToken() << endl; switch (GetToken()) { case MULT: { ReadNext(); ParsePrimary(); AddOperation (MULT); break; } case DIV: { ReadNext(); ParsePrimary(); AddOperation (DIV); break; } default: return; } } } void EvalFunction :: ParsePrimary() { switch (GetToken()) { case CONSTANT: { ReadNext(); AddConstant (GetNumValue()); break; } case SUB: { ReadNext(); ParsePrimary(); AddConstant (-1); AddOperation (MULT); break; } case LP: { ReadNext(); ParseExpression(); ReadNext(); break; } case VARIABLE: { ReadNext(); AddVariable (GetVariableNumber()); break; } case GLOBVAR: { ReadNext(); AddGlobVariable (globvar); break; } case FUNCTION: { ReadNext(); double (*funp)(double) = functions[string_value]; ParsePrimary(); AddFunction (funp); break; } case SIN: case COS: case TAN: case ATAN: case EXP: case LOG: case ABS: case SQRT: case STEP: case BESSELJ0: case BESSELJ1: case BESSELY0: case BESSELY1: { EVAL_TOKEN op = GetToken(); ReadNext(); ParsePrimary(); AddOperation (op); break; } } } void EvalFunction :: ReadNext () { char ch; do { // whitespaces ueberspringen (*ist).get(ch); if ((*ist).eof()) { token = END; return; } } while (isspace(ch)); switch (ch) { case '*': case '/': case '+': case '-': case '(': case ')': { token = EVAL_TOKEN (ch); // cout << "found token " << ch << endl; break; } default: { if (isdigit (ch) || ch == '.') { (*ist).putback (ch); (*ist) >> num_value; // cout << "found constant " << num_value << endl; token = CONSTANT; } else { int cnt = 0; while (isalnum (ch)) { string_value[cnt] = ch; cnt++; (*ist).get(ch); } (*ist).putback (ch); string_value[cnt] = 0; // cout << "parse string " << string_value << endl; if (strcmp (string_value, "sin") == 0) { token = SIN; return; } if (strcmp (string_value, "cos") == 0) { token = COS; return; } if (strcmp (string_value, "tan") == 0) { token = TAN; return; } if (strcmp (string_value, "atan") == 0) { token = ATAN; return; } if (strcmp (string_value, "exp") == 0) { token = EXP; return; } if (strcmp (string_value, "log") == 0) { token = LOG; return; } if (strcmp (string_value, "abs") == 0) { token = ABS; return; } if (strcmp (string_value, "sqrt") == 0) { token = SQRT; return; } if (strcmp (string_value, "step") == 0) { token = STEP; return; } if (strcmp (string_value, "besselj0") == 0) { token = BESSELJ0; return; } if (strcmp (string_value, "besselj1") == 0) { token = BESSELJ1; return; } if (strcmp (string_value, "bessely0") == 0) { token = BESSELY0; return; } if (strcmp (string_value, "bessely1") == 0) { token = BESSELY1; return; } if (functions.Used (string_value)) { token = FUNCTION; return; } if (constants.Used (string_value)) { // cout << "scanner found constant" << endl; token = CONSTANT; num_value = constants[string_value]; return; } if (globvariables.Used (string_value)) { token = GLOBVAR; globvar = globvariables[string_value]; // cout << "scanner found glob. variable: " << *globvar << endl; return; } // cout << "found string " << string_value << endl; // (*ist) >> string_value; // cout << "string = " << string_value << endl; /* if (keywords.Used (string_value)) { token = keywords.Get (string_value); return; } */ if (strcmp (string_value, "x1") == 0 || strcmp (string_value, "x") == 0) { var_num = 0; token = VARIABLE; return; } if (strcmp (string_value, "x2") == 0 || strcmp (string_value, "y") == 0) { var_num = 1; token = VARIABLE; return; } if (strcmp (string_value, "x3") == 0 || strcmp (string_value, "z") == 0) { var_num = 2; token = VARIABLE; return; } /* if (cnt == 2 && string_value[0] == 'x' && isdigit (string_value[1])) { // cout << "found coordinate" << endl; var_num = atoi (string_value+1)-1; token = VARIABLE; } else */ token = STRING; } } } // cout << "token = " << token << " = " << char(token) << " numval = " << num_value << endl; } }