Evaluator.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 // $Id:$
00003 // ---------------------------------------------------------------------------
00004 
00005 #include "CLHEP/Evaluator/Evaluator.h"
00006 
00007 #include <iostream>
00008 #include <sstream>
00009 #include <cmath>        // for std::pow()
00010 #include "CLHEP/Evaluator/stack.icc"
00011 #include "CLHEP/Evaluator/string.icc"
00012 #include "CLHEP/Evaluator/hash_map.icc"
00013 #include <string.h>
00014 #include <ctype.h>
00015 #include <errno.h>
00016 #include <stdlib.h>     // for strtod()
00017 
00018 //---------------------------------------------------------------------------
00019 // Fix non ISO C++ compliant cast from pointer to function
00020 // to void*, which is a pointer to an object
00021 typedef void (*voidfuncptr)();
00022 struct Item {
00023   enum { UNKNOWN, VARIABLE, EXPRESSION, FUNCTION } what;
00024   double variable;
00025   string expression;
00026   // Fix non ISO C++ compliant cast from pointer to function
00027   // to void*, which is a pointer to an object
00028   //void   *function;
00029   voidfuncptr function;
00030 
00031   Item()         : what(UNKNOWN),   variable(0),expression(), function(0) {}
00032   Item(double x) : what(VARIABLE),  variable(x),expression(), function(0) {}
00033   Item(string x) : what(EXPRESSION),variable(0),expression(x),function(0) {}
00034   Item(voidfuncptr x) : what(FUNCTION),  variable(0),expression(), function(x) {}
00035 };
00036 
00037 typedef char * pchar;
00038 typedef hash_map<string,Item> dic_type;
00039 
00040 struct Struct {
00041   dic_type theDictionary;
00042   pchar    theExpression;
00043   pchar    thePosition;
00044   int      theStatus;
00045   double   theResult;
00046 };
00047 
00048 //---------------------------------------------------------------------------
00049 #define EVAL HepTool::Evaluator
00050 
00051 #define REMOVE_BLANKS \
00052 for(pointer=name;;pointer++) if (!isspace(*pointer)) break; \
00053 for(n=strlen(pointer);n>0;n--) if (!isspace(*(pointer+n-1))) break
00054 
00055 #define SKIP_BLANKS                      \
00056 for(;;pointer++) {                       \
00057   c = (pointer > end) ? '\0' : *pointer; \
00058   if (!isspace(c)) break;                \
00059 }
00060 
00061 #define EVAL_EXIT(STATUS,POSITION) endp = POSITION; return STATUS
00062 #define MAX_N_PAR 5
00063 
00064 static const char sss[MAX_N_PAR+2] = "012345";
00065 
00066 enum { ENDL, LBRA, OR, AND, EQ, NE, GE, GT, LE, LT,
00067        PLUS, MINUS, UNARY_PLUS, UNARY_MINUS, MULT, DIV, POW, RBRA, VALUE };
00068 
00069 static int engine(pchar, pchar, double &, pchar &, const dic_type &);
00070 
00071 static int variable(const string & name, double & result,
00072                     const dic_type & dictionary)
00073 /***********************************************************************
00074  *                                                                     *
00075  * Name: variable                                    Date:    03.10.00 *
00076  * Author: Evgeni Chernyaev                          Revised:          *
00077  *                                                                     *
00078  * Function: Finds value of the variable.                              * 
00079  *           This function is used by operand().                       *
00080  *                                                                     *
00081  * Parameters:                                                         *
00082  *   name   - name of the variable.                                    *
00083  *   result - value of the variable.                                   *
00084  *   dictionary - dictionary of available variables and functions.     *
00085  *                                                                     *
00086  ***********************************************************************/
00087 {
00088   dic_type::const_iterator iter = dictionary.find(name);
00089   if (iter == dictionary.end())
00090     return EVAL::ERROR_UNKNOWN_VARIABLE;
00091   Item item = iter->second;
00092   switch (item.what) {
00093   case Item::VARIABLE:
00094     result = item.variable;
00095     return EVAL::OK;
00096   case Item::EXPRESSION: {
00097     pchar exp_begin = (char *)(item.expression.c_str());
00098     pchar exp_end   = exp_begin + strlen(exp_begin) - 1;
00099     if (engine(exp_begin, exp_end, result, exp_end, dictionary) == EVAL::OK)
00100       return EVAL::OK;
00101   }
00102   default:
00103     return EVAL::ERROR_CALCULATION_ERROR;
00104   }
00105 }
00106 
00107 static int function(const string & name, stack<double> & par,
00108                     double & result, const dic_type & dictionary) 
00109 /***********************************************************************
00110  *                                                                     *
00111  * Name: function                                    Date:    03.10.00 *
00112  * Author: Evgeni Chernyaev                          Revised:          *
00113  *                                                                     *
00114  * Function: Finds value of the function.                              * 
00115  *           This function is used by operand().                       *
00116  *                                                                     *
00117  * Parameters:                                                         *
00118  *   name   - name of the function.                                    *
00119  *   par    - stack of parameters.                                     *
00120  *   result - value of the function.                                   *
00121  *   dictionary - dictionary of available variables and functions.     *
00122  *                                                                     *
00123  ***********************************************************************/
00124 {
00125   int npar = par.size();
00126   if (npar > MAX_N_PAR) return EVAL::ERROR_UNKNOWN_FUNCTION;
00127 
00128   dic_type::const_iterator iter = dictionary.find(sss[npar]+name);
00129   if (iter == dictionary.end()) return EVAL::ERROR_UNKNOWN_FUNCTION;
00130   Item item = iter->second;
00131 
00132   double pp[MAX_N_PAR];
00133   for(int i=0; i<npar; i++) { pp[i] = par.top(); par.pop(); }
00134   errno = 0;
00135   if (item.function == 0)       return EVAL::ERROR_CALCULATION_ERROR;
00136   switch (npar) {
00137   case 0:
00138     result = ((double (*)())item.function)();
00139     break;  
00140   case 1:
00141     result = ((double (*)(double))item.function)(pp[0]);
00142     break;  
00143   case 2:
00144     result = ((double (*)(double,double))item.function)(pp[1], pp[0]);
00145     break;  
00146   case 3:
00147     result = ((double (*)(double,double,double))item.function)
00148       (pp[2],pp[1],pp[0]);
00149     break;  
00150   case 4:
00151     result = ((double (*)(double,double,double,double))item.function)
00152       (pp[3],pp[2],pp[1],pp[0]);
00153     break;  
00154   case 5:
00155     result = ((double (*)(double,double,double,double,double))item.function)
00156       (pp[4],pp[3],pp[2],pp[1],pp[0]);
00157     break;  
00158   }
00159   return (errno == 0) ? EVAL::OK : EVAL::ERROR_CALCULATION_ERROR;
00160 }
00161 
00162 static int operand(pchar begin, pchar end, double & result,
00163                    pchar & endp, const dic_type & dictionary) 
00164 /***********************************************************************
00165  *                                                                     *
00166  * Name: operand                                     Date:    03.10.00 *
00167  * Author: Evgeni Chernyaev                          Revised:          *
00168  *                                                                     *
00169  * Function: Finds value of the operand. The operand can be either     * 
00170  *           a number or a variable or a function.                     *  
00171  *           This function is used by engine().                        * 
00172  *                                                                     *
00173  * Parameters:                                                         *
00174  *   begin  - pointer to the first character of the operand.           *
00175  *   end    - pointer to the last character of the character string.   *
00176  *   result - value of the operand.                                    *
00177  *   endp   - pointer to the character where the evaluation stoped.    *
00178  *   dictionary - dictionary of available variables and functions.     *
00179  *                                                                     *
00180  ***********************************************************************/
00181 {
00182   pchar pointer = begin;
00183   int   EVAL_STATUS;
00184   char  c;
00185 
00186   //   G E T   N U M B E R
00187 
00188   if (!isalpha(*pointer)) {
00189     errno = 0;
00190     result = strtod(pointer, (char **)(&pointer));
00191     if (errno == 0) {
00192       EVAL_EXIT( EVAL::OK, --pointer );
00193     }else{
00194       EVAL_EXIT( EVAL::ERROR_CALCULATION_ERROR, begin );
00195     }
00196   }
00197 
00198   //   G E T   N A M E
00199 
00200   while(pointer <= end) {
00201     c = *pointer;
00202     if (c != '_' && !isalnum(c)) break;
00203     pointer++;
00204   }
00205   c = *pointer;
00206   *pointer = '\0';
00207   string name(begin);
00208   *pointer = c;
00209 
00210   //   G E T   V A R I A B L E
00211 
00212   result = 0.0;
00213   SKIP_BLANKS;
00214   if (c != '(') {
00215     EVAL_STATUS = variable(name, result, dictionary);
00216     EVAL_EXIT( EVAL_STATUS, (EVAL_STATUS == EVAL::OK) ? --pointer : begin);
00217   }
00218 
00219   //   G E T   F U N C T I O N
00220 
00221   stack<pchar>  pos;                // position stack 
00222   stack<double> par;                // parameter stack
00223   double        value;
00224   pchar         par_begin = pointer+1, par_end;
00225 
00226   for(;;pointer++) {
00227     c = (pointer > end) ? '\0' : *pointer;
00228     switch (c) {
00229     case '\0':  
00230       EVAL_EXIT( EVAL::ERROR_UNPAIRED_PARENTHESIS, pos.top() ); 
00231     case '(':
00232       pos.push(pointer); break;
00233     case ',':
00234       if (pos.size() == 1) {
00235         par_end = pointer-1;
00236         EVAL_STATUS = engine(par_begin, par_end, value, par_end, dictionary);
00237         if (EVAL_STATUS == EVAL::WARNING_BLANK_STRING)
00238           { EVAL_EXIT( EVAL::ERROR_EMPTY_PARAMETER, --par_end ); }
00239         if (EVAL_STATUS != EVAL::OK)
00240           { EVAL_EXIT( EVAL_STATUS, par_end ); }
00241         par.push(value);
00242         par_begin = pointer + 1;
00243       }
00244       break;
00245     case ')':
00246       if (pos.size() > 1) {
00247         pos.pop();
00248         break;
00249       }else{
00250         par_end = pointer-1;
00251         EVAL_STATUS = engine(par_begin, par_end, value, par_end, dictionary);
00252         switch (EVAL_STATUS) {
00253         case EVAL::OK:
00254           par.push(value);
00255           break;
00256         case EVAL::WARNING_BLANK_STRING:
00257           if (par.size() != 0)
00258             { EVAL_EXIT( EVAL::ERROR_EMPTY_PARAMETER, --par_end ); }
00259           break;
00260         default:
00261           EVAL_EXIT( EVAL_STATUS, par_end );
00262         }
00263         EVAL_STATUS = function(name, par, result, dictionary);
00264         EVAL_EXIT( EVAL_STATUS, (EVAL_STATUS == EVAL::OK) ? pointer : begin);
00265       }
00266     }
00267   }
00268 }
00269 
00270 /***********************************************************************
00271  *                                                                     *
00272  * Name: maker                                       Date:    28.09.00 *
00273  * Author: Evgeni Chernyaev                          Revised:          *
00274  *                                                                     *
00275  * Function: Executes basic arithmetic operations on values in the top *
00276  *           of the stack. Result is placed back into the stack.       *
00277  *           This function is used by engine().                        * 
00278  *                                                                     *
00279  * Parameters:                                                         *
00280  *   op  - code of the operation.                                      *
00281  *   val - stack of values.                                            *
00282  *                                                                     *
00283  ***********************************************************************/
00284 static int maker(int op, stack<double> & val)
00285 {
00286   if (val.size() < 2) return EVAL::ERROR_SYNTAX_ERROR;
00287   double val2 = val.top(); val.pop();
00288   double val1 = val.top();
00289   switch (op) {
00290   case OR:                                // operator ||
00291     val.top() = (val1 || val2) ? 1. : 0.;
00292     return EVAL::OK;
00293   case AND:                               // operator &&
00294     val.top() = (val1 && val2) ? 1. : 0.;
00295     return EVAL::OK;
00296   case EQ:                                // operator ==
00297     val.top() = (val1 == val2) ? 1. : 0.;
00298     return EVAL::OK;
00299   case NE:                                // operator !=
00300     val.top() = (val1 != val2) ? 1. : 0.;
00301     return EVAL::OK;
00302   case GE:                                // operator >=
00303     val.top() = (val1 >= val2) ? 1. : 0.;
00304     return EVAL::OK;
00305   case GT:                                // operator >
00306     val.top() = (val1 >  val2) ? 1. : 0.;
00307     return EVAL::OK;
00308   case LE:                                // operator <=
00309     val.top() = (val1 <= val2) ? 1. : 0.;
00310     return EVAL::OK;
00311   case LT:                                // operator <
00312     val.top() = (val1 <  val2) ? 1. : 0.;
00313     return EVAL::OK;
00314   case PLUS:                              // operator '+'
00315     val.top() = val1 + val2;
00316     return EVAL::OK;
00317   case MINUS:                             // operator '-'
00318     val.top() = val1 - val2;
00319     return EVAL::OK;
00320   case MULT:                              // operator '*'
00321     val.top() = val1 * val2;
00322     return EVAL::OK;
00323   case DIV:                               // operator '/'
00324     if (val2 == 0.0) return EVAL::ERROR_CALCULATION_ERROR;
00325     val.top() = val1 / val2;
00326     return EVAL::OK;
00327   case POW:                               // operator '^' (or '**')
00328     errno = 0;
00329     val.top() = std::pow(val1,val2);
00330     if (errno == 0) return EVAL::OK;
00331   case UNARY_PLUS:                              // unary operator '+'
00332     val.top() = val1 + val2;                    // val1 is zero
00333     return EVAL::OK;
00334   case UNARY_MINUS:                             // unary operator '-'
00335     val.top() = val1 - val2;                    // val1 is zero
00336     return EVAL::OK;
00337   default:
00338     return EVAL::ERROR_CALCULATION_ERROR;
00339   }
00340 }
00341 
00342 /***********************************************************************
00343  *                                                                     *
00344  * Name: engine                                      Date:    28.09.00 *
00345  * Author: Evgeni Chernyaev                          Revised:          *
00346  *                                                                     *
00347  * Function: Evaluates arithmetic expression.                          *
00348  *                                                                     *
00349  * Parameters:                                                         *
00350  *   begin  - pointer to the character string with expression.         *
00351  *   end    - pointer to the end of the character string (it is needed *
00352  *            for recursive call of engine(), when there is no '\0').  *
00353  *   result - result of the evaluation.                                *
00354  *   endp   - pointer to the character where the evaluation stoped.    *
00355  *   dictionary - dictionary of available variables and functions.     *
00356  *                                                                     *
00357  ***********************************************************************/
00358 static int engine(pchar begin, pchar end, double & result,
00359                   pchar & endp, const dic_type & dictionary)
00360 {
00361   enum SyntaxTableEntry {
00362     SyntaxError = 0,
00363     NumberVariableOrFunction = 1,
00364     UnaryPlusOrMinus = 2,
00365     AnyOperator = 3
00366   };
00367   static const int SyntaxTable[19][19] = {
00368     //E  (  || && == != >= >  <= <  +  -  u+ u- *  /  ^  )  V - current token
00369     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // E - previous
00370     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // (   token
00371     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // ||
00372     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // &&
00373     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // ==
00374     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // !=
00375     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // >=
00376     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // >
00377     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // <=
00378     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // <
00379     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // +
00380     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // -
00381     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // unary +
00382     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // unary -
00383     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // *
00384     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // /
00385     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 },   // ^
00386     { 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 },   // )
00387     { 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }    // V = {.,N,C}
00388   };
00389   enum ActionTableEntry {
00390     UnbalancedParentheses = -1,
00391     ExpressionCompleted = 0,
00392     HigherPrecedenceOperator = 1,
00393     SamePrecedenceOperator = 2,
00394     CloseProcessedParenthesesOrExpression = 3,
00395     LowerPrecedenceOperator = 4
00396   };
00397   static const int ActionTable[17][18] = {
00398     //E  (  || && == != >= >  <= <  +  -  u+ u- *  /  ^  ) - current operator
00399     { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1 }, // E - top operator
00400     {-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 }, // (   in stack
00401     { 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ||
00402     { 4, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // &&
00403     { 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ==
00404     { 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // !=
00405     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // >=
00406     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // >
00407     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // <=
00408     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // <
00409     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 1, 1, 4 }, // +
00410     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 1, 1, 4 }, // -
00411     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 1, 4 }, // unary +
00412     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 1, 4 }, // unary -
00413     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 2, 2, 1, 4 }, // *
00414     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 2, 2, 1, 4 }, // /
00415     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 4, 4 }  // ^
00416   };
00417 
00418   stack<int>    op;                      // operator stack
00419   stack<pchar>  pos;                     // position stack
00420   stack<double> val;                     // value stack
00421   double        value;
00422   pchar         pointer = begin;
00423   int           iWhat, iCur, iPrev = 0, iTop, EVAL_STATUS;
00424   char          c;
00425 
00426   op.push(0); pos.push(pointer);         // push EOL to the stack
00427   SKIP_BLANKS;
00428   if (c == '\0') { EVAL_EXIT( EVAL::WARNING_BLANK_STRING, begin ); }
00429   for(;;pointer++) {
00430 
00431     //   N E X T   T O K E N
00432 
00433     c = (pointer > end) ? '\0' : *pointer;
00434     if (isspace(c)) continue;            // skip space, tab etc.
00435     switch (c) {
00436     case '\0': iCur = ENDL; break;
00437     case '(':  iCur = LBRA; break;
00438     case '|':
00439       if (*(pointer+1) == '|') {
00440         pointer++; iCur = OR; break;
00441       }else{
00442         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
00443       }
00444     case '&':
00445       if (*(pointer+1) == '&') {
00446         pointer++; iCur = AND; break;
00447       }else{
00448         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
00449       }
00450     case '=':
00451       if (*(pointer+1) == '=') {
00452         pointer++; iCur = EQ; break;
00453       }else{
00454         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
00455       }
00456     case '!':
00457       if (*(pointer+1) == '=') {
00458         pointer++; iCur = NE; break;
00459       }else{
00460         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
00461       }
00462     case '>':
00463       if (*(pointer+1) == '=') { pointer++; iCur = GE; } else { iCur = GT; }
00464       break;
00465     case '<':
00466       if (*(pointer+1) == '=') { pointer++; iCur = LE; } else { iCur = LT; }
00467       break;
00468     case '+':  iCur = PLUS;  break;
00469     case '-':  iCur = MINUS; break;
00470     case '*':
00471       if (*(pointer+1) == '*') { pointer++; iCur = POW; }else{ iCur = MULT; }
00472       break;
00473     case '/':  iCur = DIV;  break;
00474     case '^':  iCur = POW;  break;
00475     case ')':  iCur = RBRA; break;
00476     default:
00477       if (c == '.' || isalnum(c)) {
00478         iCur = VALUE; break;
00479       }else{
00480         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
00481       }
00482     }
00483 
00484     //   S Y N T A X   A N A L I S Y S
00485 
00486     iWhat = SyntaxTable[iPrev][iCur];
00487     iPrev = iCur;
00488     switch (iWhat) {
00489     case 0:                             // syntax error
00490       EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer );
00491     case 1:                             // operand: number, variable, function
00492       EVAL_STATUS = operand(pointer, end, value, pointer, dictionary);
00493       if (EVAL_STATUS != EVAL::OK) { EVAL_EXIT( EVAL_STATUS, pointer ); }
00494       val.push(value);
00495       continue;
00496     case 2:                             // unary + or unary -
00497       val.push(0.0);
00498       if (iCur == PLUS)  iCur = UNARY_PLUS;
00499       if (iCur == MINUS) iCur = UNARY_MINUS;
00500       // Note that for syntax purposes, ordinary + or - are fine.
00501       // Thus iPrev need not change when we encounter a unary minus or plus.
00502     case 3: default:                    // next operator
00503       break;
00504     }
00505 
00506     //   N E X T   O P E R A T O R
00507 
00508     for(;;) {
00509       if (op.size() == 0) { EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer ); }
00510       iTop = op.top();
00511       switch (ActionTable[iTop][iCur]) {
00512       case -1:                           // syntax error 
00513         if (op.size() > 1) pointer = pos.top();
00514         EVAL_EXIT( EVAL::ERROR_UNPAIRED_PARENTHESIS, pointer );
00515       case 0:                            // last operation (assignment)
00516         if (val.size() == 1) {
00517           result = val.top();
00518           EVAL_EXIT( EVAL::OK, pointer );
00519         }else{
00520           EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer );
00521         }
00522       case 1:                           // push current operator in stack
00523         op.push(iCur); pos.push(pointer);
00524         break;
00525       case 2:                           // execute top operator
00526         EVAL_STATUS = maker(iTop, val); // put current operator in stack
00527         if (EVAL_STATUS != EVAL::OK) {
00528           EVAL_EXIT( EVAL_STATUS, pos.top() );
00529         }
00530         op.top() = iCur; pos.top() = pointer;
00531         break;
00532       case 3:                           // delete '(' from stack
00533         op.pop(); pos.pop();
00534         break;
00535       case 4: default:                  // execute top operator and 
00536         EVAL_STATUS = maker(iTop, val); // delete it from stack
00537         if (EVAL_STATUS != EVAL::OK) {  // repete with the same iCur 
00538           EVAL_EXIT( EVAL_STATUS, pos.top() );
00539         }
00540         op.pop(); pos.pop();
00541         continue;
00542       }
00543       break;
00544     }
00545   }
00546 }
00547 
00548 //---------------------------------------------------------------------------
00549 static void setItem(const char * prefix, const char * name,
00550                     const Item & item, Struct * s) {
00551 
00552   if (name == 0 || *name == '\0') {
00553     s->theStatus = EVAL::ERROR_NOT_A_NAME;
00554     return;
00555   }
00556 
00557   //   R E M O V E   L E A D I N G   A N D   T R A I L I N G   S P A C E S
00558 
00559   const char * pointer; int n; REMOVE_BLANKS;
00560 
00561   //   C H E C K   N A M E 
00562  
00563   if (n == 0) {
00564     s->theStatus = EVAL::ERROR_NOT_A_NAME;
00565     return;
00566   }
00567   for(int i=0; i<n; i++) {
00568     char c = *(pointer+i);
00569     if (c != '_' && !isalnum(c)) {
00570       s->theStatus = EVAL::ERROR_NOT_A_NAME;
00571       return;
00572     }
00573   }
00574 
00575   //   A D D   I T E M   T O   T H E   D I C T I O N A R Y
00576 
00577   string item_name = prefix + string(pointer,n);
00578   dic_type::iterator iter = (s->theDictionary).find(item_name);
00579   if (iter != (s->theDictionary).end()) {
00580     iter->second = item;
00581     if (item_name == name) {
00582       s->theStatus = EVAL::WARNING_EXISTING_VARIABLE;
00583     }else{
00584       s->theStatus = EVAL::WARNING_EXISTING_FUNCTION;
00585     }
00586   }else{
00587     (s->theDictionary)[item_name] = item;
00588     s->theStatus = EVAL::OK;
00589   }
00590 } 
00591                     
00592 //---------------------------------------------------------------------------
00593 namespace HepTool {
00594 
00595 //---------------------------------------------------------------------------
00596 Evaluator::Evaluator() {
00597   Struct * s = new Struct();
00598   p = (void *) s;
00599   s->theExpression = 0;
00600   s->thePosition   = 0;
00601   s->theStatus     = OK;
00602   s->theResult     = 0.0;
00603 }
00604 
00605 //---------------------------------------------------------------------------
00606 Evaluator::~Evaluator() {
00607   delete (Struct *)(p);
00608 }
00609 
00610 //---------------------------------------------------------------------------
00611 double Evaluator::evaluate(const char * expression) {
00612   Struct * s = (Struct *)(p);
00613   if (s->theExpression != 0) { delete[] s->theExpression; }
00614   s->theExpression = 0;
00615   s->thePosition   = 0;
00616   s->theStatus     = WARNING_BLANK_STRING;
00617   s->theResult     = 0.0;
00618   if (expression != 0) {
00619     s->theExpression = new char[strlen(expression)+1];
00620     strcpy(s->theExpression, expression);
00621     s->theStatus = engine(s->theExpression,
00622                           s->theExpression+strlen(expression)-1,
00623                           s->theResult,
00624                           s->thePosition,
00625                           s->theDictionary);
00626   }
00627   return s->theResult;
00628 }
00629 
00630 //---------------------------------------------------------------------------
00631 int Evaluator::status() const {
00632   return ((Struct *)(p))->theStatus;
00633 }
00634 
00635 //---------------------------------------------------------------------------
00636 int Evaluator::error_position() const {
00637   return ((Struct *)(p))->thePosition - ((Struct *)(p))->theExpression;
00638 }
00639 
00640 //---------------------------------------------------------------------------
00641 void Evaluator::print_error() const {
00642   Struct * s = (Struct *) p;
00643   if(s->theStatus != OK) {
00644       std::cerr << error_name() << std::endl;
00645   }
00646   return;
00647 }
00648 
00649 //---------------------------------------------------------------------------
00650 std::string Evaluator::error_name() const
00651 {
00652   char prefix[] = "Evaluator : ";
00653   std::ostringstream errn;
00654   Struct * s = (Struct *) p;
00655   switch (s->theStatus) {
00656   case ERROR_NOT_A_NAME:
00657     errn << prefix << "invalid name";
00658     break;
00659   case ERROR_SYNTAX_ERROR:
00660     errn << prefix << "syntax error";
00661     break;
00662   case ERROR_UNPAIRED_PARENTHESIS:
00663     errn << prefix << "unpaired parenthesis";
00664     break;
00665   case ERROR_UNEXPECTED_SYMBOL:
00666     errn << prefix << "unexpected symbol";
00667     break;
00668   case ERROR_UNKNOWN_VARIABLE:
00669     errn << prefix << "unknown variable";
00670     break;
00671   case ERROR_UNKNOWN_FUNCTION:
00672     errn << prefix << "unknown function";
00673     break;
00674   case ERROR_EMPTY_PARAMETER: 
00675     errn << prefix << "empty parameter in function call";
00676     break;
00677   case ERROR_CALCULATION_ERROR:
00678     errn << prefix << "calculation error";
00679     break;
00680   default:
00681     errn << " ";
00682   }
00683   return errn.str();
00684 }
00685 
00686 //---------------------------------------------------------------------------
00687 void Evaluator::setVariable(const char * name, double value)
00688 { setItem("", name, Item(value), (Struct *)p); }
00689 
00690 void Evaluator::setVariable(const char * name, const char * expression)
00691 { setItem("", name, Item(expression), (Struct *)p); }
00692 
00693 //---------------------------------------------------------------------------
00694 // Fix non ISO C++ compliant cast from pointer to function
00695 // to void*, which is a pointer to an object
00696 void Evaluator::setFunction(const char * name,
00697                             double (*fun)())
00698 { setItem("0", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); }
00699 
00700 void Evaluator::setFunction(const char * name,
00701                             double (*fun)(double))
00702 { setItem("1", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); }
00703 
00704 void Evaluator::setFunction(const char * name,
00705                             double (*fun)(double,double))
00706 { setItem("2", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); }
00707 
00708 void Evaluator::setFunction(const char * name,
00709                             double (*fun)(double,double,double))
00710 { setItem("3", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); }
00711 
00712 void Evaluator::setFunction(const char * name,
00713                             double (*fun)(double,double,double,double))
00714 { setItem("4", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); }
00715 
00716 void Evaluator::setFunction(const char * name,
00717                             double (*fun)(double,double,double,double,double))
00718 { setItem("5", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); }
00719 
00720 //---------------------------------------------------------------------------
00721 bool Evaluator::findVariable(const char * name) const {
00722   if (name == 0 || *name == '\0') return false;
00723   const char * pointer; int n; REMOVE_BLANKS;
00724   if (n == 0) return false;
00725   Struct * s = (Struct *)(p);
00726   return
00727     ((s->theDictionary).find(string(pointer,n)) == (s->theDictionary).end()) ?
00728     false : true;
00729 }
00730 
00731 //---------------------------------------------------------------------------
00732 bool Evaluator::findFunction(const char * name, int npar) const {
00733   if (name == 0 || *name == '\0')    return false;
00734   if (npar < 0  || npar > MAX_N_PAR) return false;
00735   const char * pointer; int n; REMOVE_BLANKS;
00736   if (n == 0) return false;
00737   Struct * s = (Struct *)(p);
00738   return ((s->theDictionary).find(sss[npar]+string(pointer,n)) ==
00739           (s->theDictionary).end()) ? false : true;
00740 }
00741 
00742 //---------------------------------------------------------------------------
00743 void Evaluator::removeVariable(const char * name) {
00744   if (name == 0 || *name == '\0') return;
00745   const char * pointer; int n; REMOVE_BLANKS;
00746   if (n == 0) return;
00747   Struct * s = (Struct *)(p);
00748   (s->theDictionary).erase(string(pointer,n));
00749 }
00750 
00751 //---------------------------------------------------------------------------
00752 void Evaluator::removeFunction(const char * name, int npar) {
00753   if (name == 0 || *name == '\0')    return;
00754   if (npar < 0  || npar > MAX_N_PAR) return;
00755   const char * pointer; int n; REMOVE_BLANKS;
00756   if (n == 0) return;
00757   Struct * s = (Struct *)(p);
00758   (s->theDictionary).erase(sss[npar]+string(pointer,n));
00759 }
00760 
00761 //---------------------------------------------------------------------------
00762 void Evaluator::clear() {
00763   Struct * s = (Struct *) p;
00764   s->theDictionary.clear();
00765   s->theExpression = 0;
00766   s->thePosition   = 0;
00767   s->theStatus     = OK;
00768   s->theResult     = 0.0;
00769 }
00770 
00771 //---------------------------------------------------------------------------
00772 } // namespace HepTool

Generated on Mon May 27 17:47:35 2013 for Geant4 by  doxygen 1.4.7