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