CLHEP VERSION Reference Documentation
   
CLHEP Home Page     CLHEP Documentation     CLHEP Bug Reports

Evaluator.cc

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

Generated on 15 Nov 2012 for CLHEP by  doxygen 1.4.7