Geant4 Cross Reference |
1 // -*- C++ -*- 2 // --------------------------------------------------------------------------- 3 4 #include "CLHEP/Evaluator/Evaluator.h" 5 6 #include <iostream> 7 #include <sstream> 8 #include <string> 9 #include <cmath> // for std::pow() 10 #include <stack> 11 #include <unordered_map> 12 #include <string.h> 13 #include <ctype.h> 14 #include <errno.h> 15 #include <stdlib.h> // for strtod() 16 17 using std::string; 18 using std::stack; 19 20 //--------------------------------------------------------------------------- 21 // Fix non ISO C++ compliant cast from pointer to function 22 // to void*, which is a pointer to an object 23 typedef void (*voidfuncptr)(); 24 struct Item { 25 enum { UNKNOWN, VARIABLE, EXPRESSION, FUNCTION } what; 26 double variable; 27 string expression; 28 // Fix non ISO C++ compliant cast from pointer to function 29 // to void*, which is a pointer to an object 30 //void *function; 31 voidfuncptr function; 32 33 Item() : what(UNKNOWN), variable(0),expression(), function(0) {} 34 Item(double x) : what(VARIABLE), variable(x),expression(), function(0) {} 35 Item(string x) : what(EXPRESSION),variable(0),expression(x),function(0) {} 36 Item(voidfuncptr x) : what(FUNCTION), variable(0),expression(), function(x) {} 37 }; 38 39 using pchar = char *; 40 using dic_type = std::unordered_map<string, Item>; 41 42 struct Struct { 43 dic_type theDictionary; 44 pchar theExpression; 45 pchar thePosition; 46 int theStatus; 47 double theResult; 48 }; 49 50 //--------------------------------------------------------------------------- 51 #define EVAL HepTool::Evaluator 52 53 #define REMOVE_BLANKS \ 54 for(pointer=name;;pointer++) if (!isspace(*pointer)) break; \ 55 for(n=(int)strlen(pointer);n>0;n--) if (!isspace(*(pointer+n-1))) break 56 57 #define SKIP_BLANKS \ 58 for(;;pointer++) { \ 59 c = (pointer > end) ? '\0' : *pointer; \ 60 if (!isspace(c)) break; \ 61 } 62 63 #define EVAL_EXIT(STATUS,POSITION) endp = POSITION; return STATUS 64 #define MAX_N_PAR 5 65 66 static const char sss[MAX_N_PAR+2] = "012345"; 67 68 enum { ENDL, LBRA, OR, AND, EQ, NE, GE, GT, LE, LT, 69 PLUS, MINUS, UNARY_PLUS, UNARY_MINUS, MULT, DIV, POW, RBRA, VALUE }; 70 71 static int engine(pchar, pchar, double &, pchar &, const dic_type &); 72 73 static int variable(const string & name, double & result, 74 const dic_type & dictionary) 75 /*********************************************************************** 76 * * 77 * Name: variable Date: 03.10.00 * 78 * Author: Evgeni Chernyaev Revised: * 79 * * 80 * Function: Finds value of the variable. * 81 * This function is used by operand(). * 82 * * 83 * Parameters: * 84 * name - name of the variable. * 85 * result - value of the variable. * 86 * dictionary - dictionary of available variables and functions. * 87 * * 88 ***********************************************************************/ 89 { 90 dic_type::const_iterator iter = dictionary.find(name); 91 if (iter == dictionary.end()) 92 return EVAL::ERROR_UNKNOWN_VARIABLE; 93 Item item = iter->second; 94 switch (item.what) { 95 case Item::VARIABLE: 96 result = item.variable; 97 return EVAL::OK; 98 case Item::EXPRESSION: { 99 pchar exp_begin = (char *)(item.expression.c_str()); 100 pchar exp_end = exp_begin + strlen(exp_begin) - 1; 101 if (engine(exp_begin, exp_end, result, exp_end, dictionary) == EVAL::OK) 102 return EVAL::OK; 103 else 104 return EVAL::ERROR_CALCULATION_ERROR; 105 } 106 default: 107 return EVAL::ERROR_CALCULATION_ERROR; 108 } 109 } 110 111 static int function(const string & name, stack<double> & par, 112 double & result, const dic_type & dictionary) 113 /*********************************************************************** 114 * * 115 * Name: function Date: 03.10.00 * 116 * Author: Evgeni Chernyaev Revised: * 117 * * 118 * Function: Finds value of the function. * 119 * This function is used by operand(). * 120 * * 121 * Parameters: * 122 * name - name of the function. * 123 * par - stack of parameters. * 124 * result - value of the function. * 125 * dictionary - dictionary of available variables and functions. * 126 * * 127 ***********************************************************************/ 128 { 129 unsigned long npar = par.size(); 130 if (npar > MAX_N_PAR) return EVAL::ERROR_UNKNOWN_FUNCTION; 131 132 dic_type::const_iterator iter = dictionary.find(sss[npar]+name); 133 if (iter == dictionary.end()) return EVAL::ERROR_UNKNOWN_FUNCTION; 134 Item item = iter->second; 135 136 double pp[MAX_N_PAR] = {0.0}; 137 for(unsigned long i=0; i<npar; ++i) { pp[i] = par.top(); par.pop(); } 138 errno = 0; 139 if (item.function == 0) return EVAL::ERROR_CALCULATION_ERROR; 140 switch (npar) { 141 case 0: 142 result = ((double (*)())item.function)(); 143 break; 144 case 1: 145 result = ((double (*)(double))item.function)(pp[0]); 146 break; 147 case 2: 148 result = ((double (*)(double,double))item.function)(pp[1], pp[0]); 149 break; 150 case 3: 151 result = ((double (*)(double,double,double))item.function) 152 (pp[2],pp[1],pp[0]); 153 break; 154 case 4: 155 result = ((double (*)(double,double,double,double))item.function) 156 (pp[3],pp[2],pp[1],pp[0]); 157 break; 158 case 5: 159 result = ((double (*)(double,double,double,double,double))item.function) 160 (pp[4],pp[3],pp[2],pp[1],pp[0]); 161 break; 162 } 163 return (errno == 0) ? EVAL::OK : EVAL::ERROR_CALCULATION_ERROR; 164 } 165 166 static int operand(pchar begin, pchar end, double & result, 167 pchar & endp, const dic_type & dictionary) 168 /*********************************************************************** 169 * * 170 * Name: operand Date: 03.10.00 * 171 * Author: Evgeni Chernyaev Revised: * 172 * * 173 * Function: Finds value of the operand. The operand can be either * 174 * a number or a variable or a function. * 175 * This function is used by engine(). * 176 * * 177 * Parameters: * 178 * begin - pointer to the first character of the operand. * 179 * end - pointer to the last character of the character string. * 180 * result - value of the operand. * 181 * endp - pointer to the character where the evaluation stoped. * 182 * dictionary - dictionary of available variables and functions. * 183 * * 184 ***********************************************************************/ 185 { 186 pchar pointer = begin; 187 int EVAL_STATUS; 188 char c; 189 190 // G E T N U M B E R 191 192 if (!isalpha(*pointer)) { 193 errno = 0; 194 result = strtod(pointer, (char **)(&pointer)); 195 if (errno == 0) { 196 EVAL_EXIT( EVAL::OK, --pointer ); 197 }else{ 198 EVAL_EXIT( EVAL::ERROR_CALCULATION_ERROR, begin ); 199 } 200 } 201 202 // G E T N A M E 203 204 while(pointer <= end) { 205 c = *pointer; 206 if (c != '_' && !isalnum(c)) break; 207 pointer++; 208 } 209 c = *pointer; 210 *pointer = '\0'; 211 string name(begin); 212 *pointer = c; 213 214 // G E T V A R I A B L E 215 216 result = 0.0; 217 SKIP_BLANKS; 218 if (c != '(') { 219 EVAL_STATUS = variable(name, result, dictionary); 220 EVAL_EXIT( EVAL_STATUS, (EVAL_STATUS == EVAL::OK) ? --pointer : begin); 221 } 222 223 // G E T F U N C T I O N 224 225 stack<pchar> pos; // position stack 226 stack<double> par; // parameter stack 227 double value; 228 pchar par_begin = pointer+1, par_end; 229 230 for(;;pointer++) { 231 c = (pointer > end) ? '\0' : *pointer; 232 switch (c) { 233 case '\0': 234 EVAL_EXIT( EVAL::ERROR_UNPAIRED_PARENTHESIS, pos.top() ); 235 case '(': 236 pos.push(pointer); break; 237 case ',': 238 if (pos.size() == 1) { 239 par_end = pointer-1; 240 EVAL_STATUS = engine(par_begin, par_end, value, par_end, dictionary); 241 if (EVAL_STATUS == EVAL::WARNING_BLANK_STRING) 242 { EVAL_EXIT( EVAL::ERROR_EMPTY_PARAMETER, --par_end ); } 243 if (EVAL_STATUS != EVAL::OK) 244 { EVAL_EXIT( EVAL_STATUS, par_end ); } 245 par.push(value); 246 par_begin = pointer + 1; 247 } 248 break; 249 case ')': 250 if (pos.size() > 1) { 251 pos.pop(); 252 break; 253 }else{ 254 par_end = pointer-1; 255 EVAL_STATUS = engine(par_begin, par_end, value, par_end, dictionary); 256 switch (EVAL_STATUS) { 257 case EVAL::OK: 258 par.push(value); 259 break; 260 case EVAL::WARNING_BLANK_STRING: 261 if (par.size() != 0) 262 { EVAL_EXIT( EVAL::ERROR_EMPTY_PARAMETER, --par_end ); } 263 break; 264 default: 265 EVAL_EXIT( EVAL_STATUS, par_end ); 266 } 267 EVAL_STATUS = function(name, par, result, dictionary); 268 EVAL_EXIT( EVAL_STATUS, (EVAL_STATUS == EVAL::OK) ? pointer : begin); 269 } 270 } 271 } 272 } 273 274 /*********************************************************************** 275 * * 276 * Name: maker Date: 28.09.00 * 277 * Author: Evgeni Chernyaev Revised: * 278 * * 279 * Function: Executes basic arithmetic operations on values in the top * 280 * of the stack. Result is placed back into the stack. * 281 * This function is used by engine(). * 282 * * 283 * Parameters: * 284 * op - code of the operation. * 285 * val - stack of values. * 286 * * 287 ***********************************************************************/ 288 static int maker(int op, stack<double> & val) 289 { 290 if (val.size() < 2) return EVAL::ERROR_SYNTAX_ERROR; 291 double val2 = val.top(); val.pop(); 292 double val1 = val.top(); 293 switch (op) { 294 case OR: // operator || 295 val.top() = (val1 || val2) ? 1. : 0.; 296 return EVAL::OK; 297 case AND: // operator && 298 val.top() = (val1 && val2) ? 1. : 0.; 299 return EVAL::OK; 300 case EQ: // operator == 301 val.top() = (val1 == val2) ? 1. : 0.; 302 return EVAL::OK; 303 case NE: // operator != 304 val.top() = (val1 != val2) ? 1. : 0.; 305 return EVAL::OK; 306 case GE: // operator >= 307 val.top() = (val1 >= val2) ? 1. : 0.; 308 return EVAL::OK; 309 case GT: // operator > 310 val.top() = (val1 > val2) ? 1. : 0.; 311 return EVAL::OK; 312 case LE: // operator <= 313 val.top() = (val1 <= val2) ? 1. : 0.; 314 return EVAL::OK; 315 case LT: // operator < 316 val.top() = (val1 < val2) ? 1. : 0.; 317 return EVAL::OK; 318 case PLUS: // operator '+' 319 val.top() = val1 + val2; 320 return EVAL::OK; 321 case MINUS: // operator '-' 322 val.top() = val1 - val2; 323 return EVAL::OK; 324 case MULT: // operator '*' 325 val.top() = val1 * val2; 326 return EVAL::OK; 327 case DIV: // operator '/' 328 if (val2 == 0.0) return EVAL::ERROR_CALCULATION_ERROR; 329 val.top() = val1 / val2; 330 return EVAL::OK; 331 case POW: // operator '^' (or '**') 332 errno = 0; 333 val.top() = std::pow(val1,val2); 334 if (errno == 0) return EVAL::OK; 335 else return EVAL::ERROR_CALCULATION_ERROR; 336 case UNARY_PLUS: // unary operator '+' 337 val.top() = val1 + val2; // val1 is zero 338 return EVAL::OK; 339 case UNARY_MINUS: // unary operator '-' 340 val.top() = val1 - val2; // val1 is zero 341 return EVAL::OK; 342 default: 343 return EVAL::ERROR_CALCULATION_ERROR; 344 } 345 } 346 347 /*********************************************************************** 348 * * 349 * Name: engine Date: 28.09.00 * 350 * Author: Evgeni Chernyaev Revised: * 351 * * 352 * Function: Evaluates arithmetic expression. * 353 * * 354 * Parameters: * 355 * begin - pointer to the character string with expression. * 356 * end - pointer to the end of the character string (it is needed * 357 * for recursive call of engine(), when there is no '\0'). * 358 * result - result of the evaluation. * 359 * endp - pointer to the character where the evaluation stoped. * 360 * dictionary - dictionary of available variables and functions. * 361 * * 362 ***********************************************************************/ 363 static int engine(pchar begin, pchar end, double & result, 364 pchar & endp, const dic_type & dictionary) 365 { 366 enum SyntaxTableEntry { 367 SyntaxError = 0, 368 NumberVariableOrFunction = 1, 369 UnaryPlusOrMinus = 2, 370 AnyOperator = 3 371 }; 372 static const int SyntaxTable[19][19] = { 373 //E ( || && == != >= > <= < + - u+ u- * / ^ ) V - current token 374 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // E - previous 375 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // ( token 376 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // || 377 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // && 378 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // == 379 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // != 380 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // >= 381 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // > 382 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // <= 383 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // < 384 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // + 385 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // - 386 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // unary + 387 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // unary - 388 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // * 389 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // / 390 { 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 1 }, // ^ 391 { 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }, // ) 392 { 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 } // V = {.,N,C} 393 }; 394 enum ActionTableEntry { 395 UnbalancedParentheses = -1, 396 ExpressionCompleted = 0, 397 HigherPrecedenceOperator = 1, 398 SamePrecedenceOperator = 2, 399 CloseProcessedParenthesesOrExpression = 3, 400 LowerPrecedenceOperator = 4 401 }; 402 static const int ActionTable[17][18] = { 403 //E ( || && == != >= > <= < + - u+ u- * / ^ ) - current operator 404 { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1 }, // E - top operator 405 {-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3 }, // ( in stack 406 { 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // || 407 { 4, 1, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // && 408 { 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // == 409 { 4, 1, 4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4 }, // != 410 { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // >= 411 { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // > 412 { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // <= 413 { 4, 1, 4, 4, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4 }, // < 414 { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 1, 1, 4 }, // + 415 { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 1, 1, 1, 1, 1, 4 }, // - 416 { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 1, 4 }, // unary + 417 { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 1, 4 }, // unary - 418 { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 2, 2, 1, 4 }, // * 419 { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 2, 2, 1, 4 }, // / 420 { 4, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 4, 4, 4, 4 } // ^ 421 }; 422 423 stack<int> op; // operator stack 424 stack<pchar> pos; // position stack 425 stack<double> val; // value stack 426 double value; 427 pchar pointer = begin; 428 int iWhat, iCur, iPrev = 0, iTop, EVAL_STATUS; 429 char c; 430 431 op.push(0); pos.push(pointer); // push EOL to the stack 432 SKIP_BLANKS; 433 if (c == '\0') { EVAL_EXIT( EVAL::WARNING_BLANK_STRING, begin ); } 434 for(;;pointer++) { 435 436 // N E X T T O K E N 437 438 c = (pointer > end) ? '\0' : *pointer; 439 if (isspace(c)) continue; // skip space, tab etc. 440 switch (c) { 441 case '\0': iCur = ENDL; break; 442 case '(': iCur = LBRA; break; 443 case '|': 444 if (*(pointer+1) == '|') { 445 pointer++; iCur = OR; break; 446 }else{ 447 EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer ); 448 } 449 case '&': 450 if (*(pointer+1) == '&') { 451 pointer++; iCur = AND; break; 452 }else{ 453 EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer ); 454 } 455 case '=': 456 if (*(pointer+1) == '=') { 457 pointer++; iCur = EQ; break; 458 }else{ 459 EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer ); 460 } 461 case '!': 462 if (*(pointer+1) == '=') { 463 pointer++; iCur = NE; break; 464 }else{ 465 EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer ); 466 } 467 case '>': 468 if (*(pointer+1) == '=') { pointer++; iCur = GE; } else { iCur = GT; } 469 break; 470 case '<': 471 if (*(pointer+1) == '=') { pointer++; iCur = LE; } else { iCur = LT; } 472 break; 473 case '+': iCur = PLUS; break; 474 case '-': iCur = MINUS; break; 475 case '*': 476 if (*(pointer+1) == '*') { pointer++; iCur = POW; }else{ iCur = MULT; } 477 break; 478 case '/': iCur = DIV; break; 479 case '^': iCur = POW; break; 480 case ')': iCur = RBRA; break; 481 default: 482 if (c == '.' || isalnum(c)) { 483 iCur = VALUE; break; 484 }else{ 485 EVAL_EXIT( EVAL::ERROR_UNEXPECTED_SYMBOL, pointer ); 486 } 487 } 488 489 // S Y N T A X A N A L I S Y S 490 491 iWhat = SyntaxTable[iPrev][iCur]; 492 iPrev = iCur; 493 switch (iWhat) { 494 case 0: // syntax error 495 EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer ); 496 case 1: // operand: number, variable, function 497 EVAL_STATUS = operand(pointer, end, value, pointer, dictionary); 498 if (EVAL_STATUS != EVAL::OK) { EVAL_EXIT( EVAL_STATUS, pointer ); } 499 val.push(value); 500 continue; 501 case 2: // unary + or unary - 502 val.push(0.0); 503 if (iCur == PLUS) iCur = UNARY_PLUS; 504 if (iCur == MINUS) iCur = UNARY_MINUS; 505 // Note that for syntax purposes, ordinary + or - are fine. 506 // Thus iPrev need not change when we encounter a unary minus or plus. 507 case 3: default: // next operator 508 break; 509 } 510 511 // N E X T O P E R A T O R 512 513 for(;;) { 514 if (op.size() == 0) { EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer ); } 515 iTop = op.top(); 516 switch (ActionTable[iTop][iCur]) { 517 case -1: // syntax error 518 if (op.size() > 1) pointer = pos.top(); 519 EVAL_EXIT( EVAL::ERROR_UNPAIRED_PARENTHESIS, pointer ); 520 case 0: // last operation (assignment) 521 if (val.size() == 1) { 522 result = val.top(); 523 EVAL_EXIT( EVAL::OK, pointer ); 524 }else{ 525 EVAL_EXIT( EVAL::ERROR_SYNTAX_ERROR, pointer ); 526 } 527 case 1: // push current operator in stack 528 op.push(iCur); pos.push(pointer); 529 break; 530 case 2: // execute top operator 531 EVAL_STATUS = maker(iTop, val); // put current operator in stack 532 if (EVAL_STATUS != EVAL::OK) { 533 EVAL_EXIT( EVAL_STATUS, pos.top() ); 534 } 535 op.top() = iCur; pos.top() = pointer; 536 break; 537 case 3: // delete '(' from stack 538 op.pop(); pos.pop(); 539 break; 540 case 4: default: // execute top operator and 541 EVAL_STATUS = maker(iTop, val); // delete it from stack 542 if (EVAL_STATUS != EVAL::OK) { // repete with the same iCur 543 EVAL_EXIT( EVAL_STATUS, pos.top() ); 544 } 545 op.pop(); pos.pop(); 546 continue; 547 } 548 break; 549 } 550 } 551 } 552 553 //--------------------------------------------------------------------------- 554 static void setItem(const char * prefix, const char * name, 555 const Item & item, Struct * s) { 556 557 if (name == 0 || *name == '\0') { 558 s->theStatus = EVAL::ERROR_NOT_A_NAME; 559 return; 560 } 561 562 // 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 563 564 const char * pointer; int n; REMOVE_BLANKS; 565 566 // C H E C K N A M E 567 568 if (n == 0) { 569 s->theStatus = EVAL::ERROR_NOT_A_NAME; 570 return; 571 } 572 for(int i=0; i<n; i++) { 573 char c = *(pointer+i); 574 if (c != '_' && !isalnum(c)) { 575 s->theStatus = EVAL::ERROR_NOT_A_NAME; 576 return; 577 } 578 } 579 580 // A D D I T E M T O T H E D I C T I O N A R Y 581 582 string item_name = prefix + string(pointer,n); 583 dic_type::iterator iter = (s->theDictionary).find(item_name); 584 if (iter != (s->theDictionary).end()) { 585 iter->second = item; 586 if (item_name == name) { 587 s->theStatus = EVAL::WARNING_EXISTING_VARIABLE; 588 }else{ 589 s->theStatus = EVAL::WARNING_EXISTING_FUNCTION; 590 } 591 }else{ 592 (s->theDictionary)[item_name] = item; 593 s->theStatus = EVAL::OK; 594 } 595 } 596 597 //--------------------------------------------------------------------------- 598 namespace HepTool { 599 600 //--------------------------------------------------------------------------- 601 Evaluator::Evaluator() { 602 Struct * s = new Struct(); 603 p = (void *) s; 604 s->theExpression = 0; 605 s->thePosition = 0; 606 s->theStatus = OK; 607 s->theResult = 0.0; 608 } 609 610 //--------------------------------------------------------------------------- 611 Evaluator::~Evaluator() { 612 delete (Struct *)(p); 613 } 614 615 //--------------------------------------------------------------------------- 616 double Evaluator::evaluate(const char * expression) { 617 Struct * s = (Struct *)(p); 618 if (s->theExpression != 0) { delete[] s->theExpression; } 619 s->theExpression = 0; 620 s->thePosition = 0; 621 s->theStatus = WARNING_BLANK_STRING; 622 s->theResult = 0.0; 623 if (expression != 0) { 624 s->theExpression = new char[strlen(expression)+1]; 625 strcpy(s->theExpression, expression); 626 s->theStatus = engine(s->theExpression, 627 s->theExpression+strlen(expression)-1, 628 s->theResult, 629 s->thePosition, 630 s->theDictionary); 631 } 632 return s->theResult; 633 } 634 635 //--------------------------------------------------------------------------- 636 int Evaluator::status() const { 637 return ((Struct *)(p))->theStatus; 638 } 639 640 //--------------------------------------------------------------------------- 641 int Evaluator::error_position() const { 642 return int(((Struct *)(p))->thePosition - ((Struct *)(p))->theExpression); 643 } 644 645 //--------------------------------------------------------------------------- 646 void Evaluator::print_error() const { 647 Struct * s = (Struct *) p; 648 if(s->theStatus != OK) { 649 std::cerr << error_name() << std::endl; 650 } 651 return; 652 } 653 654 //--------------------------------------------------------------------------- 655 std::string Evaluator::error_name() const 656 { 657 char prefix[] = "Evaluator : "; 658 std::ostringstream errn; 659 Struct * s = (Struct *) p; 660 switch (s->theStatus) { 661 case ERROR_NOT_A_NAME: 662 errn << prefix << "invalid name"; 663 break; 664 case ERROR_SYNTAX_ERROR: 665 errn << prefix << "syntax error"; 666 break; 667 case ERROR_UNPAIRED_PARENTHESIS: 668 errn << prefix << "unpaired parenthesis"; 669 break; 670 case ERROR_UNEXPECTED_SYMBOL: 671 errn << prefix << "unexpected symbol"; 672 break; 673 case ERROR_UNKNOWN_VARIABLE: 674 errn << prefix << "unknown variable"; 675 break; 676 case ERROR_UNKNOWN_FUNCTION: 677 errn << prefix << "unknown function"; 678 break; 679 case ERROR_EMPTY_PARAMETER: 680 errn << prefix << "empty parameter in function call"; 681 break; 682 case ERROR_CALCULATION_ERROR: 683 errn << prefix << "calculation error"; 684 break; 685 default: 686 errn << " "; 687 } 688 return errn.str(); 689 } 690 691 //--------------------------------------------------------------------------- 692 void Evaluator::setVariable(const char * name, double value) 693 { setItem("", name, Item(value), (Struct *)p); } 694 695 void Evaluator::setVariable(const char * name, const char * expression) 696 { setItem("", name, Item(expression), (Struct *)p); } 697 698 //--------------------------------------------------------------------------- 699 // Fix non ISO C++ compliant cast from pointer to function 700 // to void*, which is a pointer to an object 701 void Evaluator::setFunction(const char * name, 702 double (*fun)()) 703 { setItem("0", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); } 704 705 void Evaluator::setFunction(const char * name, 706 double (*fun)(double)) 707 { setItem("1", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); } 708 709 void Evaluator::setFunction(const char * name, 710 double (*fun)(double,double)) 711 { setItem("2", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); } 712 713 void Evaluator::setFunction(const char * name, 714 double (*fun)(double,double,double)) 715 { setItem("3", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); } 716 717 void Evaluator::setFunction(const char * name, 718 double (*fun)(double,double,double,double)) 719 { setItem("4", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); } 720 721 void Evaluator::setFunction(const char * name, 722 double (*fun)(double,double,double,double,double)) 723 { setItem("5", name, Item(reinterpret_cast<voidfuncptr>(fun)), (Struct *)p); } 724 725 //--------------------------------------------------------------------------- 726 bool Evaluator::findVariable(const char * name) const { 727 if (name == 0 || *name == '\0') return false; 728 const char * pointer; int n; REMOVE_BLANKS; 729 if (n == 0) return false; 730 Struct * s = (Struct *)(p); 731 return 732 ((s->theDictionary).find(string(pointer,n)) == (s->theDictionary).end()) ? 733 false : true; 734 } 735 736 //--------------------------------------------------------------------------- 737 bool Evaluator::findFunction(const char * name, int npar) const { 738 if (name == 0 || *name == '\0') return false; 739 if (npar < 0 || npar > MAX_N_PAR) return false; 740 const char * pointer; int n; REMOVE_BLANKS; 741 if (n == 0) return false; 742 Struct * s = (Struct *)(p); 743 return ((s->theDictionary).find(sss[npar]+string(pointer,n)) == 744 (s->theDictionary).end()) ? false : true; 745 } 746 747 //--------------------------------------------------------------------------- 748 void Evaluator::removeVariable(const char * name) { 749 if (name == 0 || *name == '\0') return; 750 const char * pointer; int n; REMOVE_BLANKS; 751 if (n == 0) return; 752 Struct * s = (Struct *)(p); 753 (s->theDictionary).erase(string(pointer,n)); 754 } 755 756 //--------------------------------------------------------------------------- 757 void Evaluator::removeFunction(const char * name, int npar) { 758 if (name == 0 || *name == '\0') return; 759 if (npar < 0 || npar > MAX_N_PAR) return; 760 const char * pointer; int n; REMOVE_BLANKS; 761 if (n == 0) return; 762 Struct * s = (Struct *)(p); 763 (s->theDictionary).erase(sss[npar]+string(pointer,n)); 764 } 765 766 //--------------------------------------------------------------------------- 767 void Evaluator::clear() { 768 Struct * s = (Struct *) p; 769 s->theDictionary.clear(); 770 s->theExpression = 0; 771 s->thePosition = 0; 772 s->theStatus = OK; 773 s->theResult = 0.0; 774 } 775 776 //--------------------------------------------------------------------------- 777 } // namespace HepTool 778