Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-22 08:03:32

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