Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:14:33

0001 
0002 // -*- C++ -*-
0003 // ---------------------------------------------------------------------------
0004 
0005 #include "Evaluator/Evaluator.h"
0006 #include "Evaluator/detail/Evaluator.h"
0007 
0008 #include <iostream>
0009 #include <cmath>        // for pow()
0010 #include <sstream>
0011 #include <mutex>
0012 #include <condition_variable>
0013 #include <cctype>
0014 #include <cerrno>
0015 #include <cstring>
0016 #include <cstdlib>     // for strtod()
0017 #include <stack>
0018 #include <string>
0019 #include <unordered_map>
0020 
0021 // Disable some diagnostics, which we know, but need to ignore
0022 #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__llvm__)
0023 /*  This is OK:
0024     ../DDCore/src/Evaluator/Evaluator.cpp: In execute_function 'int engine(pchar, pchar, double&, char*&, const dic_type&)':
0025     ../DDCore/src/Evaluator/Evaluator.cpp:164:23: warning: 'pp[3]' may be used uninitialized in this execute_function [-Wmaybe-uninitialized]
0026     result = (*fcn.f4)(pp[3],pp[2],pp[1],pp[0]);
0027     ....
0028 */
0029 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
0030 #endif
0031 
0032 // fallthrough only exists from c++17
0033 #if defined __has_cpp_attribute
0034     #if __has_cpp_attribute(fallthrough)
0035         #define ATTR_FALLTHROUGH [[fallthrough]]
0036     #else
0037         #define ATTR_FALLTHROUGH
0038     #endif
0039 #else
0040     #define ATTR_FALLTHROUGH
0041 #endif
0042 
0043 //---------------------------------------------------------------------------
0044 #define EVAL dd4hep::tools::Evaluator
0045 
0046 namespace  {
0047   
0048   /// Internal expression evaluator helper class
0049   struct Item {
0050     enum { UNKNOWN, VARIABLE, EXPRESSION, FUNCTION, STRING } what;
0051     double variable;
0052     std::string expression;
0053     void   *function;
0054 
0055     explicit Item()              : what(UNKNOWN),   variable(0),expression(), function(0) {}
0056     explicit Item(double x)      : what(VARIABLE),  variable(x),expression(), function(0) {}
0057     explicit Item(std::string x) : what(EXPRESSION),variable(0),expression(std::move(x)),function(0) {}
0058     explicit Item(void  *x)      : what(FUNCTION),  variable(0),expression(), function(x) {}
0059   };
0060 
0061   /// Internal expression evaluator helper union
0062   union FCN {
0063     void* ptr;
0064     double (*f0)();
0065     double (*f1)(double);
0066     double (*f2)(double,double);
0067     double (*f3)(double,double,double);
0068     double (*f4)(double,double,double,double);
0069     double (*f5)(double,double,double,double,double);
0070     FCN(void* p) { ptr = p; }
0071     FCN(double (*f)()) { f0 = f; }
0072     FCN(double (*f)(double)) { f1 = f; }
0073     FCN(double (*f)(double,double)) { f2 = f; }
0074     FCN(double (*f)(double,double,double)) { f3 = f; }
0075     FCN(double (*f)(double,double,double,double)) { f4 = f; }
0076     FCN(double (*f)(double,double,double,double,double)) { f5 = f; }
0077   };
0078 }
0079 
0080 //typedef char * pchar;
0081 typedef std::unordered_map<std::string,Item> dic_type;
0082 
0083 /// Internal expression evaluator helper class
0084 struct EVAL::Object::Struct {
0085   // based on https://stackoverflow.com/a/58018604
0086   struct ReadLock {
0087     ReadLock(Struct* s): theStruct(s), theLg(s->theLock) { 
0088       while(theStruct->theWriterWaiting)
0089         theStruct->theCond.wait(theLg);
0090       ++theStruct->theReadersWaiting;
0091     }
0092 
0093     ReadLock(const ReadLock&) = delete;
0094     ~ReadLock() {
0095       --theStruct->theReadersWaiting;
0096       while(theStruct->theReadersWaiting > 0)
0097         theStruct->theCond.wait(theLg);
0098       theStruct->theCond.notify_one();
0099     }
0100     Struct* theStruct;
0101     std::unique_lock<std::mutex> theLg;
0102 
0103   };
0104   struct WriteLock {
0105     WriteLock(Struct* s): theStruct(s), theLg(s->theLock) {
0106       while(theStruct->theWriterWaiting)
0107         theStruct->theCond.wait(theLg);
0108     }
0109     WriteLock(const WriteLock&) = delete;
0110     ~WriteLock() {
0111       theStruct->theWriterWaiting = true;
0112       while(theStruct->theReadersWaiting > 0)
0113         theStruct->theCond.wait(theLg);
0114       theStruct->theWriterWaiting = false;
0115       theStruct->theCond.notify_all();
0116     }
0117     Struct* theStruct;
0118     std::unique_lock<std::mutex> theLg;
0119   };
0120 
0121   dic_type    theDictionary;
0122   int theReadersWaiting = 0;
0123   bool theWriterWaiting = false;
0124   std::condition_variable theCond;
0125   std::mutex  theLock;
0126 };
0127 
0128 //---------------------------------------------------------------------------
0129 #define REMOVE_BLANKS                           \
0130   for(pointer=name;;pointer++) if (!isspace(*pointer)) break;       \
0131   for(n=strlen(pointer);n>0;n--) if (!isspace(*(pointer+n-1))) break
0132 
0133 #define SKIP_BLANKS                             \
0134   for(;;pointer++) {                            \
0135     c = (pointer > end) ? '\0' : *pointer;      \
0136     if (!isspace(c)) break;                     \
0137   }
0138 
0139 #define EVAL_EXIT(STATUS,POSITION) endp = POSITION; return STATUS
0140 #define MAX_N_PAR 5
0141 
0142 static constexpr char sss[MAX_N_PAR+2] = "012345";
0143 
0144 enum { ENDL, LBRA, OR, AND, EQ, NE, GE, GT, LE, LT,
0145        PLUS, MINUS, MULT, DIV, POW, RBRA, VALUE };
0146 
0147 static int engine(char const*, char const*, double &, char const* &, const dic_type &);
0148 
0149 static int variable(const std::string & name, double & result,
0150                     const dic_type & dictionary)
0151 /***********************************************************************
0152  *                                                                     *
0153  * Name: variable                                    Date:    03.10.00 *
0154  * Author: Evgeni Chernyaev                          Revised:          *
0155  *                                                                     *
0156  * Function: Finds value of the variable.                              *
0157  *           This function is used by operand().                       *
0158  *                                                                     *
0159  * Parameters:                                                         *
0160  *   name   - name of the variable.                                    *
0161  *   result - value of the variable.                                   *
0162  *   dictionary - dictionary of available variables and functions.     *
0163  *                                                                     *
0164  ***********************************************************************/
0165 {
0166   dic_type::const_iterator iter = dictionary.find(name);
0167   if (iter == dictionary.end())
0168     return EVAL::ERROR_UNKNOWN_VARIABLE;
0169   //NOTE: copying ::string not thread safe so must use ref
0170   Item const& item = iter->second;
0171   switch (item.what) {
0172   case Item::VARIABLE:
0173     result = item.variable;
0174     return EVAL::OK;
0175   case Item::EXPRESSION: {
0176     char const* exp_begin = (item.expression.c_str());
0177     char const* exp_end   = exp_begin + strlen(exp_begin) - 1;
0178     if (engine(exp_begin, exp_end, result, exp_end, dictionary) == EVAL::OK)
0179       return EVAL::OK;
0180     return EVAL::ERROR_CALCULATION_ERROR;
0181   }
0182   default:
0183     return EVAL::ERROR_CALCULATION_ERROR;
0184   }
0185 }
0186 
0187 static int execute_function(const std::string & name, std::stack<double> & par,
0188                     double & result, const dic_type & dictionary)
0189 /***********************************************************************
0190  *                                                                     *
0191  * Name: execute_function                            Date:    03.10.00 *
0192  * Author: Evgeni Chernyaev                          Revised:          *
0193  *                                                                     *
0194  * Function: Finds value of the function.                              *
0195  *           This function is used by operand().                       *
0196  *                                                                     *
0197  * Parameters:                                                         *
0198  *   name   - name of the function.                                    *
0199  *   par    - stack of parameters.                                     *
0200  *   result - value of the function.                                   *
0201  *   dictionary - dictionary of available variables and functions.     *
0202  *                                                                     *
0203  ***********************************************************************/
0204 {
0205   int npar = par.size();
0206   if (npar > MAX_N_PAR) return EVAL::ERROR_UNKNOWN_FUNCTION;
0207 
0208   dic_type::const_iterator iter = dictionary.find(sss[npar]+name);
0209   if (iter == dictionary.end()) return EVAL::ERROR_UNKNOWN_FUNCTION;
0210   //NOTE: copying ::string not thread safe so must use ref
0211   Item const& item = iter->second;
0212 
0213   double pp[MAX_N_PAR];
0214   for(int i=0; i<npar; i++) { pp[i] = par.top(); par.pop(); }
0215   errno = 0;
0216   if (item.function == 0)       return EVAL::ERROR_CALCULATION_ERROR;
0217   FCN fcn(item.function);
0218   switch (npar) {
0219   case 0:
0220     result = (*fcn.f0)();
0221     break;
0222   case 1:
0223     result = (*fcn.f1)(pp[0]);
0224     break;
0225   case 2:
0226     result = (*fcn.f2)(pp[1], pp[0]);
0227     break;
0228   case 3:
0229     result = (*fcn.f3)(pp[2],pp[1],pp[0]);
0230     break;
0231   case 4:
0232     result = (*fcn.f4)(pp[3],pp[2],pp[1],pp[0]);
0233     break;
0234   case 5:
0235     result = (*fcn.f5)(pp[4],pp[3],pp[2],pp[1],pp[0]);
0236     break;
0237   }
0238   return (errno == 0) ? EVAL::OK : EVAL::ERROR_CALCULATION_ERROR;
0239 }
0240 
0241 static int operand(char const* begin, char const* end, double & result,
0242                    char const* & endp, const dic_type & dictionary)
0243 /***********************************************************************
0244  *                                                                     *
0245  * Name: operand                                     Date:    03.10.00 *
0246  * Author: Evgeni Chernyaev                          Revised:          *
0247  *                                                                     *
0248  * Function: Finds value of the operand. The operand can be either     *
0249  *           a number or a variable or a function.                     *
0250  *           This function is used by engine().                        *
0251  *                                                                     *
0252  * Parameters:                                                         *
0253  *   begin  - pointer to the first character of the operand.           *
0254  *   end    - pointer to the last character of the character string.   *
0255  *   result - value of the operand.                                    *
0256  *   endp   - pointer to the character where the evaluation stoped.    *
0257  *   dictionary - dictionary of available variables and functions.     *
0258  *                                                                     *
0259  ***********************************************************************/
0260 {
0261   char const* pointer = begin;
0262   int   EVAL_STATUS;
0263   char  c;
0264 
0265   //   G E T   N U M B E R
0266 
0267   if (!isalpha(*pointer)) {
0268     errno = 0;
0269 #ifdef _WIN32
0270     if ( pointer[0] == '0' && pointer < end && (pointer[1] == 'x' || pointer[1] == 'X') )
0271       result = strtol(pointer, (char **)(&pointer), 0);
0272     else
0273 #endif
0274       result = strtod(pointer, (char **)(&pointer));
0275     if (errno == 0) {
0276       EVAL_EXIT( EVAL::OK, --pointer );
0277     }else{
0278       EVAL_EXIT( EVAL::ERROR_CALCULATION_ERROR, begin );
0279     }
0280   }
0281 
0282   //   G E T   N A M E
0283 
0284   while(pointer <= end) {
0285     c = *pointer;
0286     if ( !(c == '_' || c == ':') && !isalnum(c)) break;
0287     pointer++;
0288   }
0289   std::string name(begin, pointer-begin);
0290 
0291   //   G E T   V A R I A B L E
0292 
0293   result = 0.0;
0294   SKIP_BLANKS;
0295   if (c != '(') {
0296     EVAL_STATUS = variable(name, result, dictionary);
0297     EVAL_EXIT( EVAL_STATUS, (EVAL_STATUS == EVAL::OK) ? --pointer : begin);
0298   }
0299 
0300   //   G E T   F U N C T I O N
0301 
0302   std::stack<char const*>  pos;                // position stack
0303   std::stack<double> par;                // parameter stack
0304   double        value;
0305   char const*   par_begin = pointer+1;
0306   char const*   par_end;
0307 
0308   for(;;pointer++) {
0309     c = (pointer > end) ? '\0' : *pointer;
0310     switch (c) {
0311     case '\0':
0312       EVAL_EXIT( EVAL::ERROR_UNPAIRED_PARENTHESIS, pos.top() );
0313     case '(':
0314       pos.push(pointer); break;
0315     case ',':
0316       if (pos.size() == 1) {
0317         par_end = pointer-1;
0318         EVAL_STATUS = engine(par_begin, par_end, value, par_end, dictionary);
0319         if (EVAL_STATUS == EVAL::WARNING_BLANK_STRING)
0320       { EVAL_EXIT( EVAL::ERROR_EMPTY_PARAMETER, --par_end ); }
0321         if (EVAL_STATUS != EVAL::OK)
0322       { EVAL_EXIT( EVAL_STATUS, par_end ); }
0323         par.push(value);
0324         par_begin = pointer + 1;
0325       }
0326       break;
0327     case ')':
0328       if (pos.size() > 1) {
0329         pos.pop();
0330         break;
0331       }else{
0332         par_end = pointer-1;
0333         EVAL_STATUS = engine(par_begin, par_end, value, par_end, dictionary);
0334         switch (EVAL_STATUS) {
0335         case EVAL::OK:
0336           par.push(value);
0337           break;
0338         case EVAL::WARNING_BLANK_STRING:
0339           if (par.size() != 0)
0340         { EVAL_EXIT( EVAL::ERROR_EMPTY_PARAMETER, --par_end ); }
0341           break;
0342         default:
0343           EVAL_EXIT( EVAL_STATUS, par_end );
0344         }
0345         EVAL_STATUS = execute_function(name, par, result, dictionary);
0346         EVAL_EXIT( EVAL_STATUS, (EVAL_STATUS == EVAL::OK) ? pointer : begin);
0347       }
0348     }
0349   }
0350 }
0351 
0352 /***********************************************************************
0353  *                                                                     *
0354  * Name: maker                                       Date:    28.09.00 *
0355  * Author: Evgeni Chernyaev                          Revised:          *
0356  *                                                                     *
0357  * Function: Executes basic arithmetic operations on values in the top *
0358  *           of the stack. Result is placed back into the stack.       *
0359  *           This function is used by engine().                        *
0360  *                                                                     *
0361  * Parameters:                                                         *
0362  *   op  - code of the operation.                                      *
0363  *   val - stack of values.                                            *
0364  *                                                                     *
0365  ***********************************************************************/
0366 static int maker(int op, std::stack<double> & val)
0367 {
0368   if (val.size() < 2) return EVAL::ERROR_SYNTAX_ERROR;
0369   double val2 = val.top(); val.pop();
0370   double val1 = val.top();
0371   switch (op) {
0372   case OR:                                // operator ||
0373     val.top() = (val1 || val2) ? 1. : 0.;
0374     return EVAL::OK;
0375   case AND:                               // operator &&
0376     val.top() = (val1 && val2) ? 1. : 0.;
0377     return EVAL::OK;
0378   case EQ:                                // operator ==
0379     val.top() = (val1 == val2) ? 1. : 0.;
0380     return EVAL::OK;
0381   case NE:                                // operator !=
0382     val.top() = (val1 != val2) ? 1. : 0.;
0383     return EVAL::OK;
0384   case GE:                                // operator >=
0385     val.top() = (val1 >= val2) ? 1. : 0.;
0386     return EVAL::OK;
0387   case GT:                                // operator >
0388     val.top() = (val1 >  val2) ? 1. : 0.;
0389     return EVAL::OK;
0390   case LE:                                // operator <=
0391     val.top() = (val1 <= val2) ? 1. : 0.;
0392     return EVAL::OK;
0393   case LT:                                // operator <
0394     val.top() = (val1 <  val2) ? 1. : 0.;
0395     return EVAL::OK;
0396   case PLUS:                              // operator '+'
0397     val.top() = val1 + val2;
0398     return EVAL::OK;
0399   case MINUS:                             // operator '-'
0400     val.top() = val1 - val2;
0401     return EVAL::OK;
0402   case MULT:                              // operator '*'
0403     val.top() = val1 * val2;
0404     return EVAL::OK;
0405   case DIV:                               // operator '/'
0406     if (val2 == 0.0) return EVAL::ERROR_CALCULATION_ERROR;
0407     val.top() = val1 / val2;
0408     return EVAL::OK;
0409   case POW:                               // operator '^' (or '**')
0410     errno = 0;
0411     val.top() = pow(val1,val2);
0412     if (errno == 0) return EVAL::OK;
0413     ATTR_FALLTHROUGH;
0414   default:
0415     return EVAL::ERROR_CALCULATION_ERROR;
0416   }
0417 }
0418 
0419 /***********************************************************************
0420  *                                                                     *
0421  * Name: engine                                      Date:    28.09.00 *
0422  * Author: Evgeni Chernyaev                          Revised:          *
0423  *                                                                     *
0424  * Function: Evaluates arithmetic expression.                          *
0425  *                                                                     *
0426  * Parameters:                                                         *
0427  *   begin  - pointer to the character string with expression.         *
0428  *   end    - pointer to the end of the character string (it is needed *
0429  *            for recursive call of engine(), when there is no '\0').  *
0430  *   result - result of the evaluation.                                *
0431  *   endp   - pointer to the character where the evaluation stoped.    *
0432  *   dictionary - dictionary of available variables and functions.     *
0433  *                                                                     *
0434  ***********************************************************************/
0435 static int engine(char const* begin, char const* end, double & result,
0436                   char const*& endp, const dic_type & dictionary)
0437 {
0438   static constexpr int SyntaxTable[17][17] = {
0439     //E  (  || && == != >= >  <= <  +  -  *  /  ^  )  V - current token
0440     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1 },   // E - previous
0441     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1 },   // (   token
0442     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // ||
0443     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // &&
0444     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // ==
0445     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // !=
0446     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // >=
0447     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // >
0448     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // <=
0449     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // <
0450     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // +
0451     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // -
0452     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // *
0453     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // /
0454     { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },   // ^
0455     { 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 },   // )
0456     { 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }    // V = {.,N,C}
0457   };
0458   static constexpr int ActionTable[15][16] = {
0459     //E  (  || && == != >= >  <= <  +  -  *  /  ^  ) - current operator
0460     { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1 }, // E - top operator
0461     {-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 }, // (   in stack
0462     { 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ||
0463     { 4, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // &&
0464     { 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // ==
0465     { 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // !=
0466     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // >=
0467     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // >
0468     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // <=
0469     { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 4 }, // <
0470     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 4 }, // +
0471     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 4 }, // -
0472     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 4 }, // *
0473     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 4 }, // /
0474     { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }  // ^
0475   };
0476 
0477   std::stack<int>    op;                      // operator stack
0478   std::stack<char const*>  pos;                     // position stack
0479   std::stack<double> val;                     // value stack
0480   double        value;
0481   char const*   pointer = begin;
0482   int           iWhat, iCur, iPrev = 0, iTop, EVAL_STATUS;
0483   char          c;
0484 
0485   op.push(0); pos.push(pointer);         // push EOL to the stack
0486   SKIP_BLANKS;
0487   if (c == '\0') { EVAL_EXIT( EVAL::WARNING_BLANK_STRING, begin ); }
0488   for(;;pointer++) {
0489 
0490     //   N E X T   T O K E N
0491 
0492     c = (pointer > end) ? '\0' : *pointer;
0493     if (isspace(c)) continue;            // skip space, tab etc.
0494     switch (c) {
0495     case '\0': iCur = ENDL; break;
0496     case '(':  iCur = LBRA; break;
0497     case '|':
0498       if (*(pointer+1) == '|') {
0499         pointer++; iCur = OR; break;
0500       }else{
0501         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
0502       }
0503     case '&':
0504       if (*(pointer+1) == '&') {
0505         pointer++; iCur = AND; break;
0506       }else{
0507         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
0508       }
0509     case '=':
0510       if (*(pointer+1) == '=') {
0511         pointer++; iCur = EQ; break;
0512       }else{
0513         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
0514       }
0515     case '!':
0516       if (*(pointer+1) == '=') {
0517         pointer++; iCur = NE; break;
0518       }else{
0519         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
0520       }
0521     case '>':
0522       if (*(pointer+1) == '=') { pointer++; iCur = GE; } else { iCur = GT; }
0523       break;
0524     case '<':
0525       if (*(pointer+1) == '=') { pointer++; iCur = LE; } else { iCur = LT; }
0526       break;
0527     case '+':  iCur = PLUS;  break;
0528     case '-':  iCur = MINUS; break;
0529     case '*':
0530       if (*(pointer+1) == '*') { pointer++; iCur = POW; }else{ iCur = MULT; }
0531       break;
0532     case '/':  iCur = DIV;  break;
0533     case '^':  iCur = POW;  break;
0534     case ')':  iCur = RBRA; break;
0535     default:
0536       if (c == '.' || isalnum(c)) {
0537         iCur = VALUE; break;
0538       }else{
0539         EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer );
0540       }
0541     }
0542 
0543     //   S Y N T A X   A N A L I S Y S
0544 
0545     iWhat = SyntaxTable[iPrev][iCur];
0546     iPrev = iCur;
0547     switch (iWhat) {
0548     case 0:                             // syntax error
0549       EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer );
0550     case 1:                             // operand: number, variable, function
0551       EVAL_STATUS = operand(pointer, end, value, pointer, dictionary);
0552       if (EVAL_STATUS != EVAL::OK) { EVAL_EXIT( EVAL_STATUS, pointer ); }
0553       val.push(value);
0554       continue;
0555     case 2:                             // unary + or unary -
0556       val.push(0.0);
0557     case 3: default:                    // next operator
0558       break;
0559     }
0560 
0561     //   N E X T   O P E R A T O R
0562 
0563     for(;;) {
0564       if (op.size() == 0) { EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer ); }
0565       iTop = op.top();
0566       switch (ActionTable[iTop][iCur]) {
0567       case -1:                           // syntax error
0568         if (op.size() > 1) pointer = pos.top();
0569         EVAL_EXIT( EVAL::ERROR_UNPAIRED_PARENTHESIS, pointer );
0570       case 0:                            // last operation (assignment)
0571         if (val.size() == 1) {
0572           result = val.top();
0573           EVAL_EXIT( EVAL::OK, pointer );
0574         }else{
0575           EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer );
0576         }
0577       case 1:                           // push current operator in stack
0578         op.push(iCur); pos.push(pointer);
0579         break;
0580       case 2:                           // execute top operator
0581         EVAL_STATUS = maker(iTop, val); // put current operator in stack
0582         if (EVAL_STATUS != EVAL::OK) {
0583           EVAL_EXIT( EVAL_STATUS, pos.top() );
0584         }
0585         op.top() = iCur; pos.top() = pointer;
0586         break;
0587       case 3:                           // delete '(' from stack
0588         op.pop(); pos.pop();
0589         break;
0590       case 4: default:                  // execute top operator and
0591         EVAL_STATUS = maker(iTop, val); // delete it from stack
0592         if (EVAL_STATUS != EVAL::OK) {  // repete with the same iCur
0593           EVAL_EXIT( EVAL_STATUS, pos.top() );
0594         }
0595         op.pop(); pos.pop();
0596         continue;
0597       }
0598       break;
0599     }
0600   }
0601 }
0602 
0603 //---------------------------------------------------------------------------
0604 static int setItem(const char * prefix, const char * name,
0605                    const Item & item, EVAL::Object::Struct* imp) {
0606 
0607   if (name == 0 || *name == '\0') {
0608     return EVAL::ERROR_NOT_A_NAME;
0609   }
0610 
0611   //   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
0612 
0613   const char * pointer; int n; REMOVE_BLANKS;
0614 
0615   //   C H E C K   N A M E
0616 
0617   if (n == 0) {
0618     return EVAL::ERROR_NOT_A_NAME;
0619   }
0620   for(int i=0; i<n; i++) {
0621     char c = *(pointer+i);
0622     if ( !(c == '_' || c== ':') && !isalnum(c)) {
0623       return EVAL::ERROR_NOT_A_NAME;
0624     }
0625   }
0626 
0627   //   A D D   I T E M   T O   T H E   D I C T I O N A R Y
0628 
0629   std::string item_name = prefix + std::string(pointer,n);
0630   EVAL::Object::Struct::WriteLock guard(imp);
0631   dic_type::iterator iter = imp->theDictionary.find(item_name);
0632   if (iter != imp->theDictionary.end()) {
0633     iter->second = item;
0634     if (item_name == name) {
0635       return EVAL::WARNING_EXISTING_VARIABLE;
0636     }else{
0637       return EVAL::WARNING_EXISTING_FUNCTION;
0638     }
0639   }
0640   imp->theDictionary[item_name] = item;
0641   return EVAL::OK;
0642 }
0643 
0644 //---------------------------------------------------------------------------
0645   static void print_error_status(std::ostream& os, int status, char const* extra) {
0646   static char prefix[] = "Evaluator::Object : ";
0647   const char* opt = (extra ? extra : "");
0648   switch (status) {
0649   case EVAL::WARNING_EXISTING_VARIABLE:
0650     os << prefix << "existing variable";
0651     return;
0652   case EVAL::WARNING_EXISTING_FUNCTION:
0653     os << prefix << "existing function";
0654     return;
0655   case EVAL::WARNING_BLANK_STRING:
0656     os << prefix << "blank string detected";
0657     return;
0658   case EVAL::ERROR_NOT_A_NAME:
0659     os << prefix << "invalid name : " << opt;
0660     return;
0661   case EVAL::ERROR_SYNTAX_ERROR:
0662     os << prefix << "systax error"        ;
0663     return;
0664   case EVAL::ERROR_UNPAIRED_PARENTHESIS:
0665     os << prefix << "unpaired parenthesis";
0666     return;
0667   case EVAL::ERROR_UNEXPECTED_SYMBOL:
0668     os << prefix << "unexpected symbol : " << opt;
0669     return;
0670   case EVAL::ERROR_UNKNOWN_VARIABLE:
0671     os << prefix << "unknown variable : " << opt;
0672     return;
0673   case EVAL::ERROR_UNKNOWN_FUNCTION:
0674     os << prefix << "unknown function : " << opt;
0675     return;
0676   case EVAL::ERROR_EMPTY_PARAMETER:
0677     os << prefix << "empty parameter in function call: " << opt;
0678     return;
0679   case EVAL::ERROR_CALCULATION_ERROR:
0680     os << prefix << "calculation error";
0681     return;
0682   default:
0683     return;
0684   }
0685 }
0686 
0687 //---------------------------------------------------------------------------
0688 using namespace dd4hep::tools;
0689 
0690 //---------------------------------------------------------------------------
0691 Evaluator::Object::Object(double meter, double kilogram, double second, double ampere, double kelvin
0692                           , double mole, double candela, double radians) : imp( new Struct()) {
0693   setStdMath();
0694   setSystemOfUnits(meter, kilogram, second, ampere, kelvin
0695                    , mole, candela, radians );
0696 }
0697 
0698 //---------------------------------------------------------------------------
0699 Evaluator::Object::~Object() {
0700   delete imp;
0701 }
0702 
0703 //---------------------------------------------------------------------------
0704 Evaluator::Object::EvalStatus Evaluator::Object::evaluate(const char * expression) const {
0705   EvalStatus s;
0706   if (expression != 0) {
0707     Struct::ReadLock guard(imp);
0708     s.theStatus = engine(expression,
0709                          expression+strlen(expression)-1,
0710                          s.theResult,
0711                          s.thePosition,
0712                          imp->theDictionary);
0713   }
0714   return s;
0715 }
0716 
0717 //---------------------------------------------------------------------------
0718 int Evaluator::Object::EvalStatus::status() const {
0719   return theStatus;
0720 }
0721 
0722 //---------------------------------------------------------------------------
0723 double Evaluator::Object::EvalStatus::result() const {
0724   return theResult;
0725 }
0726 
0727 //---------------------------------------------------------------------------
0728 int Evaluator::Object::EvalStatus::error_position(const char* expression) const {
0729   return thePosition - expression;
0730 }
0731 
0732 //---------------------------------------------------------------------------
0733 void Evaluator::Object::EvalStatus::print_error() const {
0734   std::stringstream str;
0735   print_error(str);
0736   if ( str.str().empty() )  return;
0737   std::cerr << str.str() << std::endl;
0738 }
0739 
0740 //---------------------------------------------------------------------------
0741 void Evaluator::Object::EvalStatus::print_error(std::ostream& os) const {
0742   print_error_status(os, theStatus, thePosition);
0743 }
0744 
0745 //---------------------------------------------------------------------------
0746 int Evaluator::Object::setEnviron(const char* name, const char* value)  {
0747   std::string prefix = "${";
0748   std::string item_name = prefix + std::string(name) + std::string("}");
0749 
0750   //Need to take lock before creating Item since since Item to be destroyed
0751   // before the lock in order avoid ::string ref count thread problem
0752   Struct::WriteLock guard(imp);
0753   Item item;
0754   item.what = Item::STRING;
0755   item.expression = value;
0756   item.function = 0;
0757   item.variable = 0;
0758   dic_type::iterator iter = imp->theDictionary.find(item_name);
0759   if (iter != imp->theDictionary.end()) {
0760     iter->second = std::move(item);
0761     if (item_name == name) {
0762       return EVAL::WARNING_EXISTING_VARIABLE;
0763     }else{
0764       return EVAL::WARNING_EXISTING_FUNCTION;
0765     }
0766   }else{
0767     imp->theDictionary[item_name] = std::move(item);
0768     return EVAL::OK;
0769   }
0770 }
0771 
0772 //---------------------------------------------------------------------------
0773 std::pair<const char*,int> Evaluator::Object::getEnviron(const char* name)  const {
0774   Struct::ReadLock guard(imp);
0775   Struct const* cImp = imp;
0776   dic_type::const_iterator iter = cImp->theDictionary.find(name);
0777   if (iter != cImp->theDictionary.end()) {
0778     return std::make_pair(iter->second.expression.c_str(), EVAL::OK);
0779   }
0780   if ( ::strlen(name) > 3 )  {
0781     // Need to remove braces from ${xxxx} for call to getenv()
0782     std::string env_name(name+2,::strlen(name)-3);
0783     const char* env_str = ::getenv(env_name.c_str());
0784     if ( 0 != env_str )    {
0785       return std::make_pair(env_str, EVAL::OK);
0786     }
0787   }
0788   return std::make_pair(nullptr,EVAL::ERROR_UNKNOWN_VARIABLE);
0789 }
0790 
0791 //---------------------------------------------------------------------------
0792 int Evaluator::Object::setVariable(const char * name, double value)  {
0793   return setItem("", name, Item(value), imp);
0794 }
0795 
0796 int Evaluator::Object::setVariable(const char * name, const char * expression)  {
0797   Item item(expression);
0798   auto returnValue = setItem("", name, item, imp);
0799   {
0800     //We need to decrement the ref count on the item.expression while holding
0801     // the lock since the ::string was copied into the dictionary
0802     Struct::WriteLock guard(imp);
0803     item.expression = "";
0804   }
0805   return returnValue;
0806 }
0807 
0808 void Evaluator::Object::setVariableNoLock(const char * name, double value)  {
0809   std::string item_name = name;
0810   imp->theDictionary[item_name] = Item(value);
0811 }
0812 
0813 int Evaluator::Object::setFunction(const char * name,double (*fun)())   {
0814   return setItem("0", name, Item(FCN(fun).ptr), imp);
0815 }
0816 
0817 int Evaluator::Object::setFunction(const char * name,double (*fun)(double))   {
0818   return setItem("1", name, Item(FCN(fun).ptr), imp);
0819 }
0820 
0821 int Evaluator::Object::setFunction(const char * name, double (*fun)(double,double))  {
0822   return setItem("2", name, Item(FCN(fun).ptr), imp);
0823 }
0824 
0825 int Evaluator::Object::setFunction(const char * name, double (*fun)(double,double,double))  {
0826   return setItem("3", name, Item(FCN(fun).ptr), imp);
0827 }
0828 
0829 int Evaluator::Object::setFunction(const char * name, double (*fun)(double,double,double,double)) {
0830   return setItem("4", name, Item(FCN(fun).ptr), imp);
0831 }
0832 
0833 int Evaluator::Object::setFunction(const char * name, double (*fun)(double,double,double,double,double))  {
0834   return setItem("5", name, Item(FCN(fun).ptr), imp);
0835 }
0836 
0837 void Evaluator::Object::setFunctionNoLock(const char * name,double (*fun)(double))   {
0838   std::string item_name = "1"+std::string(name);
0839   imp->theDictionary[item_name] = Item(FCN(fun).ptr);
0840 }
0841 
0842 void Evaluator::Object::setFunctionNoLock(const char * name, double (*fun)(double,double))  {
0843   std::string item_name = "2"+std::string(name);
0844   imp->theDictionary[item_name] = Item(FCN(fun).ptr);
0845 }
0846 
0847 
0848 //---------------------------------------------------------------------------
0849 bool Evaluator::Object::findVariable(const char * name) const {
0850   if (name == 0 || *name == '\0') return false;
0851   const char * pointer; int n; REMOVE_BLANKS;
0852   if (n == 0) return false;
0853   Struct::ReadLock guard(imp);
0854   return
0855     (imp->theDictionary.find(std::string(pointer,n)) == imp->theDictionary.end()) ?
0856     false : true;
0857 }
0858 
0859 //---------------------------------------------------------------------------
0860 bool Evaluator::Object::findFunction(const char * name, int npar) const {
0861   if (name == 0 || *name == '\0')    return false;
0862   if (npar < 0  || npar > MAX_N_PAR) return false;
0863   const char * pointer; int n; REMOVE_BLANKS;
0864   if (n == 0) return false;
0865   Struct::ReadLock guard(imp);
0866   return (imp->theDictionary.find(sss[npar]+std::string(pointer,n)) ==
0867       imp->theDictionary.end()) ? false : true;
0868 }
0869 
0870 //---------------------------------------------------------------------------
0871 void Evaluator::Object::removeVariable(const char * name) {
0872   if (name == 0 || *name == '\0') return;
0873   const char * pointer; int n; REMOVE_BLANKS;
0874   if (n == 0) return;
0875   Struct::WriteLock guard(imp);
0876   imp->theDictionary.erase(std::string(pointer,n));
0877 }
0878 
0879 //---------------------------------------------------------------------------
0880 void Evaluator::Object::removeFunction(const char * name, int npar) {
0881   if (name == 0 || *name == '\0')    return;
0882   if (npar < 0  || npar > MAX_N_PAR) return;
0883   const char * pointer; int n; REMOVE_BLANKS;
0884   if (n == 0) return;
0885   Struct::WriteLock guard(imp);
0886   imp->theDictionary.erase(sss[npar]+std::string(pointer,n));
0887 }
0888 
0889 //---------------------------------------------------------------------------
0890 Evaluator::Evaluator(double meter, double kilogram, double second, double ampere, double kelvin
0891                           , double mole, double candela, double radians)   {
0892   object = new Object(meter, kilogram, second, ampere, kelvin, mole, candela, radians);
0893 }
0894 
0895 //---------------------------------------------------------------------------
0896 Evaluator::Evaluator(Evaluator&& other):object(other.object) {
0897   other.object=nullptr;
0898 }
0899 
0900 //---------------------------------------------------------------------------
0901 Evaluator::~Evaluator()   {
0902   delete object;
0903 }
0904 
0905 //---------------------------------------------------------------------------
0906 std::pair<int,double> Evaluator::evaluate(const std::string& expression)  const   {
0907   auto result = object->evaluate(expression.c_str());
0908   return std::make_pair(result.status(),result.result());
0909 }
0910 
0911 //---------------------------------------------------------------------------
0912 std::pair<int,double> Evaluator::evaluate(const std::string& expression, std::ostream& os)  const   {
0913   auto result = object->evaluate(expression.c_str());
0914   int    status = result.status();
0915   if ( status != OK )   {
0916     result.print_error(os);
0917   }
0918   return std::make_pair(result.status(),result.result());
0919 }
0920 
0921 //---------------------------------------------------------------------------
0922 int Evaluator::setEnviron(const std::string& name, const std::string& value)  const    {
0923   int result = object->setEnviron(name.c_str(), value.c_str());
0924   return result;
0925 }
0926 
0927 //---------------------------------------------------------------------------
0928 std::pair<int,std::string> Evaluator::getEnviron(const std::string& name)  const    {
0929   std::pair<int,std::string> result;
0930   auto env_status = object->getEnviron(name.c_str());
0931   result.first = env_status.second;
0932   if( env_status.first ) result.second = env_status.first;
0933   return result;
0934 }
0935 
0936 //---------------------------------------------------------------------------
0937 std::pair<int,std::string> Evaluator::getEnviron(const std::string& name, std::ostream& os)  const    {
0938   std::pair<int,std::string> result;
0939   auto env_status = object->getEnviron(name.c_str());
0940   result.first = env_status.second;
0941   if ( env_status.first )   {
0942     result.second = env_status.first;
0943   }
0944   if ( result.first != OK )   {
0945     print_error_status(os, result.first, name.c_str());
0946   }
0947   return result;
0948 }
0949 
0950 //---------------------------------------------------------------------------
0951 int Evaluator::setVariable(const std::string& name, double value)  const    {
0952   int result = object->setVariable(name.c_str(), value);
0953   return result;
0954 }
0955 
0956 //---------------------------------------------------------------------------
0957 int Evaluator::setVariable(const std::string& name, double value, std::ostream& os)  const    {
0958   int result = object->setVariable(name.c_str(), value);
0959   if ( result != OK )   {
0960     print_error_status(os, result, name.c_str());
0961   }
0962   return result;
0963 }
0964 
0965 //---------------------------------------------------------------------------
0966 int Evaluator::setVariable(const std::string& name, const std::string& value)  const    {
0967   int result = object->setVariable(name.c_str(), value.c_str());
0968   return result;
0969 }
0970 
0971 //---------------------------------------------------------------------------
0972 int Evaluator::setVariable(const std::string& name, const std::string& value, std::ostream& os)  const    {
0973   int result = object->setVariable(name.c_str(), value.c_str());
0974   if ( result != OK )   {
0975     print_error_status(os, result, name.c_str());
0976   }
0977   return result;
0978 }
0979 
0980 //---------------------------------------------------------------------------
0981 bool Evaluator::findVariable(const std::string& name)  const    {
0982   bool ret;
0983   ret = object->findVariable(name.c_str());
0984   return ret;
0985 }
0986 
0987 //---------------------------------------------------------------------------
0988 int Evaluator::setFunction(const std::string& name, double (*fun)())  const    {
0989   int result = object->setFunction(name.c_str(), fun);
0990   return result;
0991 }
0992 
0993 //---------------------------------------------------------------------------
0994 int Evaluator::setFunction(const std::string& name, double (*fun)(double))  const    {
0995   int result = object->setFunction(name.c_str(), fun);
0996   return result;
0997 }
0998 
0999 //---------------------------------------------------------------------------
1000 int Evaluator::setFunction(const std::string& name, double (*fun)(double, double))  const    {
1001   int result = object->setFunction(name.c_str(), fun);
1002   return result;
1003 }
1004 
1005 //---------------------------------------------------------------------------
1006 int Evaluator::setFunction(const std::string& name, double (*fun)(double, double, double))  const    {
1007   int result = object->setFunction(name.c_str(), fun);
1008   return result;
1009 }
1010 
1011 //---------------------------------------------------------------------------
1012 int Evaluator::setFunction(const std::string& name, double (*fun)(double, double, double, double))  const    {
1013   int result = object->setFunction(name.c_str(), fun);
1014   return result;
1015 }
1016 
1017 //---------------------------------------------------------------------------
1018 int Evaluator::setFunction(const std::string& name, double (*fun)(double, double, double, double, double))  const    {
1019   int result =object->setFunction(name.c_str(), fun);
1020   return result;
1021 }
1022 
1023 //---------------------------------------------------------------------------
1024 bool Evaluator::findFunction(const std::string& name, int npar) const    {
1025   bool ret;
1026   ret = object->findFunction(name.c_str(), npar);
1027   return ret;
1028 }