File indexing completed on 2026-09-22 08:03:32
0001
0002
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
0022 #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__llvm__)
0023
0024
0025
0026
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
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
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
0071 typedef std::unordered_map<std::string,Item> dic_type;
0072
0073
0074 struct EVAL::Object::Struct {
0075
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
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155 {
0156 dic_type::const_iterator iter = dictionary.find(name);
0157 if (iter == dictionary.end())
0158 return EVAL::ERROR_UNKNOWN_VARIABLE;
0159
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
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
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
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
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 {
0251 char const* pointer = begin;
0252 int EVAL_STATUS;
0253 char c;
0254
0255
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
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
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
0291
0292 std::stack<char const*> pos;
0293 std::stack<double> par;
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
0345
0346
0347
0348
0349
0350
0351
0352
0353
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:
0363 val.top() = (val1 || val2) ? 1. : 0.;
0364 return EVAL::OK;
0365 case AND:
0366 val.top() = (val1 && val2) ? 1. : 0.;
0367 return EVAL::OK;
0368 case EQ:
0369 val.top() = (val1 == val2) ? 1. : 0.;
0370 return EVAL::OK;
0371 case NE:
0372 val.top() = (val1 != val2) ? 1. : 0.;
0373 return EVAL::OK;
0374 case GE:
0375 val.top() = (val1 >= val2) ? 1. : 0.;
0376 return EVAL::OK;
0377 case GT:
0378 val.top() = (val1 > val2) ? 1. : 0.;
0379 return EVAL::OK;
0380 case LE:
0381 val.top() = (val1 <= val2) ? 1. : 0.;
0382 return EVAL::OK;
0383 case LT:
0384 val.top() = (val1 < val2) ? 1. : 0.;
0385 return EVAL::OK;
0386 case PLUS:
0387 val.top() = val1 + val2;
0388 return EVAL::OK;
0389 case MINUS:
0390 val.top() = val1 - val2;
0391 return EVAL::OK;
0392 case MULT:
0393 val.top() = val1 * val2;
0394 return EVAL::OK;
0395 case DIV:
0396 if (val2 == 0.0) return EVAL::ERROR_CALCULATION_ERROR;
0397 val.top() = val1 / val2;
0398 return EVAL::OK;
0399 case POW:
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
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
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
0430 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1 },
0431 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 1 },
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 }
0447 };
0448 static constexpr int ActionTable[15][16] = {
0449
0450 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1 },
0451 {-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 },
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;
0468 std::stack<char const*> pos;
0469 std::stack<double> val;
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);
0476 SKIP_BLANKS;
0477 if (c == '\0') { EVAL_EXIT( EVAL::WARNING_BLANK_STRING, begin ); }
0478 for(;;pointer++) {
0479
0480
0481
0482 c = (pointer > end) ? '\0' : *pointer;
0483 if (isspace(c)) continue;
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
0534
0535 iWhat = SyntaxTable[iPrev][iCur];
0536 iPrev = iCur;
0537 switch (iWhat) {
0538 case 0:
0539 EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer );
0540 case 1:
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:
0546 val.push(0.0);
0547 case 3: default:
0548 break;
0549 }
0550
0551
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:
0558 if (op.size() > 1) pointer = pos.top();
0559 EVAL_EXIT( EVAL::ERROR_UNPAIRED_PARENTHESIS, pointer );
0560 case 0:
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:
0568 op.push(iCur); pos.push(pointer);
0569 break;
0570 case 2:
0571 EVAL_STATUS = maker(iTop, val);
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:
0578 op.pop(); pos.pop();
0579 break;
0580 case 4: default:
0581 EVAL_STATUS = maker(iTop, val);
0582 if (EVAL_STATUS != EVAL::OK) {
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
0602
0603 const char * pointer; int n; REMOVE_BLANKS;
0604
0605
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
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
0741
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
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
0791
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 }