1 #ifndef CEVAL
2 #define CEVAL
3 //functions accessible from main()
4 // - double ceval_result(char * inp) returns the result of valid math expression stored as a char array `inp`
5 // - void ceval_tree(char * inp) prints the parse tree for the input expression `inp`
6
7 #include<stdio.h>
8 #include<string.h>
9 #include<math.h>
10 #include<ctype.h>
11 #include<stdarg.h>
12 /****************************************** TOKENS ***********************************************/
13 typedef enum ceval_node_id {
14 CEVAL_WHITESPACE, CEVAL_OPENPAR, CEVAL_CLOSEPAR, CEVAL_COMMA,
15 CEVAL_OR, CEVAL_AND, CEVAL_BIT_OR, CEVAL_BIT_XOR,
16 CEVAL_BIT_AND, CEVAL_EQUAL, CEVAL_NOTEQUAL,CEVAL_LESSER,
17 CEVAL_GREATER, CEVAL_LESSER_S, CEVAL_GREATER_S, CEVAL_BIT_LSHIFT,
18 CEVAL_BIT_RSHIFT, CEVAL_PLUS, CEVAL_MINUS, CEVAL_TIMES,
19 CEVAL_DIVIDE, CEVAL_MODULO, CEVAL_QUOTIENT, CEVAL_POW,
20 CEVAL_GCD, CEVAL_HCF, CEVAL_LCM, CEVAL_LOG,
21 CEVAL_ATAN2, CEVAL_SCI2DEC, CEVAL_POWFUN,
22
23 CEVAL_ABS, CEVAL_EXP, CEVAL_SQRT,CEVAL_CBRT,
24 CEVAL_LN, CEVAL_LOG10, CEVAL_CEIL, CEVAL_FLOOR,
25 CEVAL_SIGNUM, CEVAL_FACTORIAL, CEVAL_INT, CEVAL_FRAC,
26 CEVAL_DEG2RAD, CEVAL_RAD2DEG, CEVAL_SIN, CEVAL_COS,
27 CEVAL_TAN, CEVAL_ASIN, CEVAL_ACOS, CEVAL_ATAN,
28 CEVAL_SINH, CEVAL_COSH, CEVAL_TANH,CEVAL_NOT,
29 CEVAL_BIT_NOT,CEVAL_POSSIGN, CEVAL_NEGSIGN,
30
31 CEVAL_NUMBER, CEVAL_CONST_PI, CEVAL_CONST_E
32 } ceval_node_id;
33 typedef enum ceval_token_prec_specifiers {
34 // precedences :: <https://en.cppreference.com/w/cpp/language/operator_precedence>
35 // these precision specifiers are ordered in the ascending order of their precedences
36 // here, the higher precedence operators are evaluated first and end up at the bottom of the parse trees
37 CEVAL_PREC_IGNORE,
38 // {' ', '\t', '\n', '\b', '\r'}
39 CEVAL_PREC_PARANTHESES,
40 // {'(', ')'}
41 CEVAL_PREC_COMMA_OPR,
42 // {','}
43 CEVAL_PREC_LOGICAL_OR_OPR,
44 // {'||'}
45 CEVAL_PREC_LOGICAL_AND_OPR,
46 // {'&&'}
47 CEVAL_PREC_BIT_OR_OPR,
48 // {'|'}
49 CEVAL_PREC_BIT_XOR_OPR,
50 // {'^'}
51 CEVAL_PREC_BIT_AND_OPR,
52 // {'&'}
53 CEVAL_PREC_EQUALITY_OPRS,
54 // {'==', '!='}
55 CEVAL_PREC_RELATIONAL_OPRS,
56 // {'<', '>', '<=', '>='}
57 CEVAL_PREC_BIT_SHIFT_OPRS,
58 // {'<<', '>>'}
59 CEVAL_PREC_ADDITIVE_OPRS,
60 // {'+', '-'}
61 CEVAL_PREC_SIGN_OPRS,
62 // {'+', '-'}
63 CEVAL_PREC_MULTIPLICATIVE_OPRS,
64 // {'*', '/', '%', '//'}
65 CEVAL_PREC_EXPONENTIATION_OPR,
66 // {'**'}
67 CEVAL_PREC_FUNCTIONS,
68 // {
69 // 'exp()', 'sqrt()', 'cbrt()', 'sin()',
70 // 'cos()', 'tan()', 'asin()', 'acos()',
71 // 'atan()', 'sinh()', 'cosh()', 'tanh()',
72 // 'abs()', 'ceil()', 'floor()', 'log10()',
73 // 'ln()', 'deg2rad()', 'rad2deg()', 'signum()',
74 // 'int()', 'frac()', 'fact()', `pow()`,
75 // `atan2()`, `gcd()`, `hcf()`, `lcm()`,
76 // `log()`
77 // }
78 CEVAL_PREC_NOT_OPRS,
79 // {'!', '~'}}
80 CEVAL_PREC_SCI2DEC_OPR,
81 // {'e'},
82 CEVAL_PREC_NUMERIC
83 // {'_pi', '_e', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
84 } ceval_token_prec_specifiers;
85 typedef enum ceval_token_type {
86 CEVAL_UNARY_OPERATOR,
87 CEVAL_BINARY_OPERATOR,
88 CEVAL_UNARY_FUNCTION,
89 CEVAL_BINARY_FUNCTION,
90 CEVAL_OTHER
91 } ceval_token_type;
92 typedef struct ceval_token_info_ {
93 ceval_node_id id;
94 const char * symbol;
95 double prec;
96 ceval_token_type token_type;
97 } ceval_token_info_;
98 ceval_token_info_ ceval_token_info[] = {
99 { CEVAL_WHITESPACE, " ", CEVAL_PREC_IGNORE, CEVAL_OTHER },
100 { CEVAL_WHITESPACE, "\n", CEVAL_PREC_IGNORE, CEVAL_OTHER },
101 { CEVAL_WHITESPACE, "\t", CEVAL_PREC_IGNORE, CEVAL_OTHER },
102 { CEVAL_WHITESPACE, "\r", CEVAL_PREC_IGNORE, CEVAL_OTHER },
103 { CEVAL_WHITESPACE, "\b", CEVAL_PREC_IGNORE, CEVAL_OTHER },
104
105 { CEVAL_DEG2RAD, "deg2rad", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
106 { CEVAL_RAD2DEG, "rad2deg", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
107
108 { CEVAL_SIGNUM, "signum", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
109
110 { CEVAL_ATAN2, "atan2", CEVAL_PREC_FUNCTIONS, CEVAL_BINARY_FUNCTION },
111 { CEVAL_LOG10, "log10", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
112 { CEVAL_FLOOR, "floor", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
113
114 { CEVAL_SQRT, "sqrt", CEVAL_PREC_FUNCTIONS , CEVAL_UNARY_FUNCTION },
115 { CEVAL_CBRT, "cbrt", CEVAL_PREC_FUNCTIONS , CEVAL_UNARY_FUNCTION },
116 { CEVAL_CEIL, "ceil", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
117 { CEVAL_FRAC, "frac", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
118 { CEVAL_FACTORIAL, "fact", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
119 { CEVAL_SINH, "sinh", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
120 { CEVAL_COSH, "cosh", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
121 { CEVAL_TANH, "tanh", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
122 { CEVAL_ASIN, "asin", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
123 { CEVAL_ACOS, "acos", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
124 { CEVAL_ATAN, "atan", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
125
126 { CEVAL_POWFUN, "pow", CEVAL_PREC_FUNCTIONS, CEVAL_BINARY_FUNCTION },
127 { CEVAL_GCD, "gcd", CEVAL_PREC_FUNCTIONS, CEVAL_BINARY_FUNCTION },
128 { CEVAL_HCF, "hcf", CEVAL_PREC_FUNCTIONS, CEVAL_BINARY_FUNCTION },
129 { CEVAL_LCM, "lcm", CEVAL_PREC_FUNCTIONS, CEVAL_BINARY_FUNCTION },
130 { CEVAL_LOG, "log", CEVAL_PREC_FUNCTIONS, CEVAL_BINARY_FUNCTION },
131 { CEVAL_INT, "int", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
132 { CEVAL_SIN, "sin", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
133 { CEVAL_COS, "cos", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
134 { CEVAL_TAN, "tan", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
135 { CEVAL_ABS, "abs", CEVAL_PREC_FUNCTIONS , CEVAL_UNARY_FUNCTION },
136 { CEVAL_EXP, "exp", CEVAL_PREC_FUNCTIONS , CEVAL_UNARY_FUNCTION },
137 { CEVAL_CONST_PI, "_pi", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
138
139 { CEVAL_CONST_E, "_e", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
140 { CEVAL_LN, "ln", CEVAL_PREC_FUNCTIONS, CEVAL_UNARY_FUNCTION },
141 { CEVAL_OR, "||", CEVAL_PREC_LOGICAL_OR_OPR, CEVAL_BINARY_OPERATOR },
142 { CEVAL_AND, "&&", CEVAL_PREC_LOGICAL_AND_OPR, CEVAL_BINARY_OPERATOR },
143 { CEVAL_EQUAL, "==", CEVAL_PREC_EQUALITY_OPRS, CEVAL_BINARY_OPERATOR },
144 { CEVAL_NOTEQUAL, "!=", CEVAL_PREC_EQUALITY_OPRS, CEVAL_BINARY_OPERATOR },
145 { CEVAL_LESSER, "<=", CEVAL_PREC_RELATIONAL_OPRS , CEVAL_BINARY_OPERATOR },
146 { CEVAL_GREATER, ">=", CEVAL_PREC_RELATIONAL_OPRS , CEVAL_BINARY_OPERATOR },
147 { CEVAL_BIT_LSHIFT, "<<", CEVAL_PREC_BIT_SHIFT_OPRS, CEVAL_BINARY_OPERATOR},
148 { CEVAL_BIT_RSHIFT, ">>", CEVAL_PREC_BIT_SHIFT_OPRS, CEVAL_BINARY_OPERATOR},
149 { CEVAL_QUOTIENT, "//", CEVAL_PREC_MULTIPLICATIVE_OPRS , CEVAL_BINARY_OPERATOR },
150 { CEVAL_POW, "**", CEVAL_PREC_EXPONENTIATION_OPR , CEVAL_BINARY_OPERATOR },
151
152 { CEVAL_OPENPAR, "(", CEVAL_PREC_PARANTHESES, CEVAL_OTHER },
153 { CEVAL_CLOSEPAR, ")", CEVAL_PREC_PARANTHESES, CEVAL_OTHER },
154 { CEVAL_COMMA, ",", CEVAL_PREC_COMMA_OPR , CEVAL_BINARY_OPERATOR },
155 { CEVAL_BIT_OR, "|", CEVAL_PREC_BIT_OR_OPR, CEVAL_BINARY_OPERATOR},
156 { CEVAL_BIT_XOR, "^", CEVAL_PREC_BIT_XOR_OPR, CEVAL_BINARY_OPERATOR},
157 { CEVAL_BIT_AND, "&", CEVAL_PREC_BIT_AND_OPR, CEVAL_BINARY_OPERATOR},
158 { CEVAL_LESSER_S, "<", CEVAL_PREC_RELATIONAL_OPRS , CEVAL_BINARY_OPERATOR },
159 { CEVAL_GREATER_S, ">", CEVAL_PREC_RELATIONAL_OPRS , CEVAL_BINARY_OPERATOR },
160 { CEVAL_PLUS, "+", CEVAL_PREC_ADDITIVE_OPRS , CEVAL_BINARY_OPERATOR },
161 { CEVAL_MINUS, "-", CEVAL_PREC_ADDITIVE_OPRS , CEVAL_BINARY_OPERATOR },
162 { CEVAL_POSSIGN, "+", CEVAL_PREC_SIGN_OPRS, CEVAL_UNARY_OPERATOR },
163 { CEVAL_NEGSIGN, "-", CEVAL_PREC_SIGN_OPRS, CEVAL_UNARY_OPERATOR },
164 { CEVAL_TIMES, "*", CEVAL_PREC_MULTIPLICATIVE_OPRS , CEVAL_BINARY_OPERATOR },
165 { CEVAL_DIVIDE, "/", CEVAL_PREC_MULTIPLICATIVE_OPRS , CEVAL_BINARY_OPERATOR },
166 { CEVAL_MODULO, "%", CEVAL_PREC_MULTIPLICATIVE_OPRS , CEVAL_BINARY_OPERATOR },
167 { CEVAL_NOT, "!", CEVAL_PREC_NOT_OPRS, CEVAL_UNARY_FUNCTION},
168 { CEVAL_BIT_NOT, "~", CEVAL_PREC_NOT_OPRS, CEVAL_UNARY_OPERATOR},
169
170 { CEVAL_SCI2DEC, "e", CEVAL_PREC_SCI2DEC_OPR , CEVAL_BINARY_OPERATOR },
171 { CEVAL_NUMBER, "0", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
172 { CEVAL_NUMBER, "1", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
173 { CEVAL_NUMBER, "2", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
174 { CEVAL_NUMBER, "3", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
175 { CEVAL_NUMBER, "4", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
176 { CEVAL_NUMBER, "5", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
177 { CEVAL_NUMBER, "6", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
178 { CEVAL_NUMBER, "7", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
179 { CEVAL_NUMBER, "8", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
180 { CEVAL_NUMBER, "9", CEVAL_PREC_NUMERIC, CEVAL_OTHER },
181 };
182 #ifndef CEVAL_TOKEN_TABLE_SIZE
183 #define CEVAL_TOKEN_TABLE_SIZE sizeof(ceval_token_info) / sizeof(ceval_token_info[0])
184 #endif
ceval_is_binary_opr(ceval_node_id id)185 int ceval_is_binary_opr(ceval_node_id id) {
186 for(unsigned int i = 0; i < CEVAL_TOKEN_TABLE_SIZE; i++) {
187 if (ceval_token_info[i].id == id && ceval_token_info[i].token_type == CEVAL_BINARY_OPERATOR) {
188 return 1;
189 }
190 }
191 return 0;
192 }
ceval_is_binary_fun(ceval_node_id id)193 int ceval_is_binary_fun(ceval_node_id id) {
194 for(unsigned int i = 0; i < CEVAL_TOKEN_TABLE_SIZE; i++) {
195 if (ceval_token_info[i].id == id && ceval_token_info[i].token_type == CEVAL_BINARY_FUNCTION) {
196 return 1;
197 }
198 }
199 return 0;
200 }
ceval_token_symbol(ceval_node_id id)201 const char * ceval_token_symbol(ceval_node_id id) {
202 for(unsigned int i = 0; i < CEVAL_TOKEN_TABLE_SIZE; i++) {
203 if (id == ceval_token_info[i].id) {
204 return ceval_token_info[i].symbol;
205 }
206 }
207 return "";
208 }
ceval_token_id(char * symbol)209 ceval_node_id ceval_token_id(char * symbol) {
210 for(unsigned int i = 0; i < CEVAL_TOKEN_TABLE_SIZE; i++) {
211 if (!strcmp(ceval_token_info[i].symbol, symbol)) {
212 return ceval_token_info[i].id;
213 }
214 }
215 return CEVAL_WHITESPACE;
216 }
ceval_token_prec(ceval_node_id id)217 double ceval_token_prec(ceval_node_id id) {
218 for(unsigned int i = 0; i < CEVAL_TOKEN_TABLE_SIZE; i++) {
219 if (id == ceval_token_info[i].id) {
220 return ceval_token_info[i].prec;
221 }
222 }
223 return 0;
224 }
225 typedef struct ceval_node {
226 enum ceval_node_id id;
227 double pre;
228 double number;
229 struct ceval_node * left, * right, * parent;
230 }
231 ceval_node;
232 #ifdef __cplusplus
233 #define CEVAL_CXX
234 #include<iostream>
235 #include<string>
236 #endif
237 /***************************************** !TOKENS *******************************************/
238
239 /****************************************** FUNCTIONS ******************************************/
240 //constant definitions
241 #ifdef M_PI
242 #define CEVAL_PI M_PI
243 #else
244 #define CEVAL_PI 3.14159265358979323846
245 #endif
246 #ifdef M_E
247 #define CEVAL_E M_E
248 #else
249 #define CEVAL_E 2.71828182845904523536
250 #endif
251
252 #ifndef CEVAL_EPSILON
253 #define CEVAL_EPSILON 1e-2
254 #endif
255 #ifndef CEVAL_DELTA
256 #define CEVAL_DELTA 1e-6
257 #endif
258 #ifndef CEVAL_MAX_DIGITS
259 #define CEVAL_MAX_DIGITS 15
260 #endif
261 //these can be defined by the user before the include directive depending the desired level of precision
262
263 //helper function prototypes
264 void ceval_error(const char * , ...);
265 double ceval_gcd_binary(int, int);
266 char * ceval_shrink(char * );
267
268 //single argument funtion prototypes
269 double ceval_signum(double);
270 double ceval_asin(double);
271 double ceval_acos(double);
272 double ceval_atan(double);
273 double ceval_sin(double);
274 double ceval_cos(double);
275 double ceval_tan(double);
276 double ceval_sinh(double);
277 double ceval_cosh(double);
278 double ceval_tanh(double);
279 double ceval_rad2deg(double);
280 double ceval_deg2rad(double);
281 double ceval_int_part(double);
282 double ceval_frac_part(double);
283 double ceval_log10(double);
284 double ceval_ln(double);
285 double ceval_exp(double);
286 double ceval_factorial(double);
287 double ceval_positive_sign(double);
288 double ceval_negative_sign(double);
289 double ceval_abs(double);
290 double ceval_sqrt(double);
291 double ceval_sqrt(double);
292 double ceval_cbrt(double);
293 double ceval_ceil(double);
294 double ceval_floor(double);
295 double ceval_not(double);
296 double ceval_bit_not(double);
297
298 //double argument function prototypes
299 double ceval_sum(double, double, int);
300 double ceval_diff(double, double, int);
301 double ceval_prod(double, double, int);
302 double ceval_div(double, double, int);
303 double ceval_quotient(double, double, int);
304 double ceval_modulus(double, double, int);
305 double ceval_gcd(double, double, int);
306 double ceval_hcf(double, double, int);
307 double ceval_lcm(double, double, int);
308 double ceval_log(double, double, int);
309 double ceval_are_equal(double, double, int);
310 double ceval_not_equal(double, double, int);
311 double ceval_lesser(double, double, int);
312 double ceval_greater(double, double, int);
313 double ceval_lesser_s(double, double, int);
314 double ceval_greater_s(double, double, int);
315 double ceval_comma(double, double, int);
316 double ceval_power(double, double, int);
317 double ceval_atan2(double, double, int);
318 double ceval_sci2dec(double, double, int);
319 double ceval_and(double, double, int);
320 double ceval_or(double, double, int);
321 double ceval_bit_and(double, double, int);
322 double ceval_bit_xor(double, double, int);
323 double ceval_bit_or(double, double, int);
324 double ceval_bit_lshift(double, double, int);
325 double ceval_bit_rshift(double, double, int);
326
327 //helper function definitions
ceval_error(const char * error_format_string,...)328 void ceval_error(const char* error_format_string, ...) {
329 #ifndef CEVAL_STOICAL
330 // start whining
331 printf("\n[ceval]: ");
332 va_list args;
333 va_start(args, error_format_string);
334 vprintf(error_format_string, args);
335 va_end(args);
336 printf("\n");
337 #endif
338 }
ceval_gcd_binary(int a,int b)339 double ceval_gcd_binary(int a, int b) {
340 if (a == 0 && b == 0)
341 return 0;
342 while (b) {
343 a %= b;
344 b ^= a;
345 a ^= b;
346 b ^= a;
347 }
348 return a;
349 }
ceval_shrink(char * x)350 char * ceval_shrink(char * x) {
351 char * y = x;
352 unsigned int len = 0;
353 for (unsigned int i = 0; i < strlen(x); i++) {
354 if(x[i] == ' ' || x[i] == '\n' || x[i] == '\t' || x[i] == '\r') {
355 continue;
356 } else {
357 if(x[i]=='(' && x[i+1]==')') {
358 // empty pairs of parantheses are ignored
359 // simlar to c lang where {} are ignored as empty blocks of code
360 i++;
361 continue;
362 }
363 *(y + len) = (char)tolower(x[i]);
364 len++;
365 }
366 }
367 y[len] = '\0';
368 return y;
369 }
370 //single argument function definitions
371 double( * single_arg_fun[])(double) = {
372 // double_arg_fun (first three tokens are whitespace and parantheses)
373 NULL, NULL, NULL, NULL,
374 NULL, NULL, NULL, NULL,
375 NULL, NULL, NULL, NULL,
376 NULL, NULL, NULL, NULL,
377 NULL, NULL, NULL, NULL,
378 NULL, NULL, NULL, NULL,
379 NULL, NULL, NULL, NULL,
380 NULL, NULL, NULL,
381 // single_arg_fun
382 ceval_abs, ceval_exp, ceval_sqrt, ceval_cbrt,
383 ceval_ln, ceval_log10, ceval_ceil, ceval_floor,
384 ceval_signum, ceval_factorial, ceval_int_part, ceval_frac_part,
385 ceval_deg2rad, ceval_rad2deg, ceval_sin, ceval_cos,
386 ceval_tan, ceval_asin, ceval_acos, ceval_atan,
387 ceval_sinh, ceval_cosh, ceval_tanh, ceval_not,
388 ceval_bit_not, ceval_positive_sign, ceval_negative_sign,
389 // number and constant tokens
390 NULL, NULL, NULL
391 };
ceval_signum(double x)392 double ceval_signum(double x) {
393 return (x == 0) ? 0 :
394 (x > 0) ? 1 :
395 -1;
396 }
ceval_asin(double x)397 double ceval_asin(double x) {
398 if (x > 1 || x < -1) {
399 ceval_error("Numerical argument out of domain");
400 return NAN;
401 }
402 return asin(x);
403 }
ceval_acos(double x)404 double ceval_acos(double x) {
405 if (x > 1 || x < -1) {
406 ceval_error("Numerical argument out of domain");
407 return NAN;
408 }
409 return acos(x);
410 }
ceval_atan(double x)411 double ceval_atan(double x) {
412 return atan(x);
413 }
ceval_sin(double x)414 double ceval_sin(double x) {
415 double sin_val = sin(x);
416 //sin(pi) == 0.000000, but sin(pi-CEVAL_EPSILON) == -0.00000* and sin(pi+CEVAL_EPSILON) == +0.00000*
417 //since the precision of pi (approx) is limited, it often leads to -0.0000 printed out as a result
418 //thus, we assumse 0.0000 value for all |sin(x)|<=CEVAL_EPSILON
419 return (fabs(sin_val) <= CEVAL_EPSILON) ? 0 : sin_val;
420 }
ceval_cos(double x)421 double ceval_cos(double x) {
422 double cos_val = cos(x);
423 return (fabs(cos_val) <= CEVAL_EPSILON) ? 0 : cos_val;
424 }
ceval_tan(double x)425 double ceval_tan(double x) {
426 double tan_val = tan(x);
427 if (fabs(ceval_modulus(x - CEVAL_PI / 2, CEVAL_PI, 0)) <= CEVAL_DELTA) {
428 ceval_error("tan() is not defined for odd-integral multiples of pi/2");
429 return NAN;
430 }
431 return (fabs(tan_val) <= CEVAL_EPSILON) ? 0 : tan_val;
432 }
ceval_rad2deg(double x)433 double ceval_rad2deg(double x) {
434 return x / CEVAL_PI * 180;
435 }
ceval_deg2rad(double x)436 double ceval_deg2rad(double x) {
437 return x / 180 * CEVAL_PI;
438 }
ceval_int_part(double x)439 double ceval_int_part(double x) {
440 double x_i;
441 modf(x, & x_i);
442 return x_i;
443 }
ceval_frac_part(double x)444 double ceval_frac_part(double x) {
445 double x_i, x_f;
446 x_f = modf(x, & x_i);
447 return x_f;
448 }
ceval_log10(double x)449 double ceval_log10(double x) {
450 return ceval_log(10, x, 0);
451 }
ceval_ln(double x)452 double ceval_ln(double x) {
453 return ceval_log(CEVAL_E, x, 0);
454 }
ceval_exp(double x)455 double ceval_exp(double x) {
456 return ceval_power(CEVAL_E, x, 0);
457 }
ceval_factorial(double x)458 double ceval_factorial(double x) {
459 if (x < 0) {
460 ceval_error("Numerical argument out of domain");
461 return NAN;
462 }
463 return tgamma(x + 1);
464 }
ceval_positive_sign(double x)465 double ceval_positive_sign(double x) {
466 return x;
467 }
ceval_negative_sign(double x)468 double ceval_negative_sign(double x) {
469 return -x;
470 }
ceval_abs(double x)471 double ceval_abs(double x) {
472 return fabs(x);
473 }
ceval_sqrt(double x)474 double ceval_sqrt(double x) {
475 if (x >= 0) return sqrt(x);
476 ceval_error("sqrt(): can't operate on negative numbers");
477 return NAN;
478 }
ceval_cbrt(double x)479 double ceval_cbrt(double x) {
480 return cbrt(x);
481 }
ceval_ceil(double x)482 double ceval_ceil(double x) {
483 return ceil(x);
484 }
ceval_floor(double x)485 double ceval_floor(double x) {
486 return floor(x);
487 }
ceval_sinh(double x)488 double ceval_sinh(double x) {
489 return sinh(x);
490 }
ceval_cosh(double x)491 double ceval_cosh(double x) {
492 return cosh(x);
493 }
ceval_tanh(double x)494 double ceval_tanh(double x) {
495 return tanh(x);
496 }
ceval_not(double x)497 double ceval_not(double x) {
498 return (double) ! (int)x;
499 }
ceval_bit_not(double x)500 double ceval_bit_not(double x) {
501 if(ceval_frac_part(x) == 0) {
502 return ~(int)x;
503 } else {
504 ceval_error("bit_not(): operand must be of integral type");
505 return NAN;
506 }
507 }
508 //double argument function definitions
509 double( * double_arg_fun[])(double, double, int) = {
510 // double_arg_fun (first three tokens are whitespace and parantheses)
511 NULL, NULL, NULL, ceval_comma,
512 ceval_or, ceval_and, ceval_bit_or, ceval_bit_xor,
513 ceval_bit_and, ceval_are_equal, ceval_not_equal, ceval_lesser,
514 ceval_greater, ceval_lesser_s, ceval_greater_s, ceval_bit_lshift,
515 ceval_bit_rshift, ceval_sum, ceval_diff, ceval_prod,
516 ceval_div, ceval_modulus, ceval_quotient, ceval_power,
517 ceval_gcd, ceval_hcf, ceval_lcm, ceval_log,
518 ceval_atan2, ceval_sci2dec, ceval_power,
519 // single_arg_fun
520 NULL, NULL, NULL, NULL,
521 NULL, NULL, NULL, NULL,
522 NULL, NULL, NULL, NULL,
523 NULL, NULL, NULL, NULL,
524 NULL, NULL, NULL, NULL,
525 NULL, NULL, NULL, NULL,
526 NULL, NULL, NULL,
527 // number and constant tokens
528 NULL, NULL, NULL
529 };
ceval_sum(double a,double b,int arg_check)530 double ceval_sum(double a, double b, int arg_check) {
531 if (arg_check) {
532 ceval_error("sum(): function takes two arguments");
533 return NAN;
534 }
535 return a + b;
536 }
ceval_diff(double a,double b,int arg_check)537 double ceval_diff(double a, double b, int arg_check) {
538 if (arg_check) {
539 ceval_error("diff(): function takes two arguments");
540 return NAN;
541 }
542 return a - b;
543 }
ceval_prod(double a,double b,int arg_check)544 double ceval_prod(double a, double b, int arg_check) {
545 if (arg_check) {
546 ceval_error("prod(): function takes two arguments");
547 return NAN;
548 }
549 return a * b;
550 }
ceval_div(double a,double b,int arg_check)551 double ceval_div(double a, double b, int arg_check) {
552 if (arg_check) {
553 ceval_error("div(): function takes two arguments");
554 return NAN;
555 }
556 if (b == 0 && a == 0) {
557 ceval_error("0/0 is indeterminate...");
558 ceval_error("Continuing evaluation with the assumption 0/0 = 1");
559 return 1;
560 } else if (b == 0) {
561 ceval_error("Division by 0 is not defined...");
562 ceval_error("Continuing evaluation with the assumption 1/0 = inf");
563 return a * INFINITY;
564 }
565 return a / b;
566 }
ceval_modulus(double a,double b,int arg_check)567 double ceval_modulus(double a, double b, int arg_check) {
568 if (arg_check) {
569 ceval_error("modulo(): function takes two arguments");
570 return NAN;
571 }
572 if (b == 0) {
573 ceval_error("Division by 0 is not defined...");
574 ceval_error("Continuing evaluation with the assumption 1%0 = 0");
575 return 0;
576 }
577 return fmod(a, b);
578 }
ceval_quotient(double a,double b,int arg_check)579 double ceval_quotient(double a, double b, int arg_check) {
580 if (arg_check) {
581 ceval_error("quotient(): function takes two arguments");
582 return NAN;
583 }
584 //a = b*q + r
585 //q = (a - r)/b
586 if (b == 0 && a == 0) {
587 ceval_error("0/0 is indeterminate...");
588 ceval_error("Continuing evaluation with the assumption 0/0 = 1");
589 return 1;
590
591 } else if (b == 0) {
592 ceval_error("Division by 0 is not defined...");
593 ceval_error("Continuing evaluation with the assumption 1/0 = inf");
594 return a * INFINITY;
595 }
596 return (a - ceval_modulus(a, b, 0)) / b;
597 }
ceval_gcd(double a,double b,int arg_check)598 double ceval_gcd(double a, double b, int arg_check) {
599 if (arg_check) {
600 ceval_error("gcd(): function takes two arguments");
601 return NAN;
602 }
603 double a_f = ceval_frac_part(a),
604 b_f = ceval_frac_part(b);
605 int a_i = (int)ceval_int_part(a),
606 b_i = (int)ceval_int_part(b);
607 if (a_f == 0 && b_f == 0) {
608 return (double) ceval_gcd_binary(a_i, b_i);
609 } else {
610 ceval_error("gcd() takes only integral parameters");
611 return NAN;
612 }
613 }
ceval_hcf(double a,double b,int arg_check)614 double ceval_hcf(double a, double b, int arg_check) {
615 if (arg_check) {
616 ceval_error("hcf(): function takes two arguments");
617 return NAN;
618 }
619 return ceval_gcd(a, b, 0);
620 }
ceval_lcm(double a,double b,int arg_check)621 double ceval_lcm(double a, double b, int arg_check) {
622 if (arg_check) {
623 ceval_error("lcm(): function takes two arguments");
624 return NAN;
625 }
626 return a * b / ceval_gcd(a, b, 0);
627 }
ceval_log(double b,double x,int arg_check)628 double ceval_log(double b, double x, int arg_check) {
629 if (arg_check) {
630 ceval_error("log(): function takes two arguments");
631 return NAN;
632 }
633 if (b == 0) {
634 if (x == 0) {
635 ceval_error("log(0,0) is indeterminate");
636 return NAN;
637 } else {
638 return 0;
639 }
640 }
641 return log(x) / log(b);
642 }
ceval_are_equal(double a,double b,int arg_check)643 double ceval_are_equal(double a, double b, int arg_check) {
644 if (arg_check) {
645 ceval_error("==: function takes two arguments");
646 return NAN;
647 }
648 if (fabs(a - b) <= CEVAL_EPSILON) {
649 return 1;
650 } else {
651 return 0;
652 }
653 }
ceval_not_equal(double a,double b,int arg_check)654 double ceval_not_equal(double a, double b, int arg_check) {
655 if (arg_check) {
656 ceval_error("!=: function takes two arguments");
657 return NAN;
658 }
659 return (double)!(int)ceval_are_equal(a, b, 0);
660 }
ceval_lesser(double a,double b,int arg_check)661 double ceval_lesser(double a, double b, int arg_check) {
662 if (arg_check) {
663 ceval_error("<=: function takes two arguments");
664 return NAN;
665 }
666 return (double)!(int)ceval_greater_s(a, b, 0);
667 }
ceval_greater(double a,double b,int arg_check)668 double ceval_greater(double a, double b, int arg_check) {
669 if (arg_check) {
670 ceval_error(">=: function takes two arguments");
671 return NAN;
672 }
673 return (double)!(int)ceval_lesser_s(a, b, 0);
674 }
ceval_lesser_s(double a,double b,int arg_check)675 double ceval_lesser_s(double a, double b, int arg_check) {
676 if (arg_check) {
677 ceval_error("<: function takes two arguments");
678 return NAN;
679 }
680 return (b - a) >= CEVAL_EPSILON;
681 }
ceval_greater_s(double a,double b,int arg_check)682 double ceval_greater_s(double a, double b, int arg_check) {
683 if (arg_check) {
684 ceval_error(">: function takes two arguments");
685 return NAN;
686 }
687 return (a - b) >= CEVAL_EPSILON;
688 }
ceval_comma(double x,double y,int arg_check)689 double ceval_comma(double x, double y, int arg_check) {
690 if (arg_check) {
691 ceval_error(",: function takes two arguments");
692 return NAN;
693 }
694 return y;
695 }
ceval_power(double x,double y,int arg_check)696 double ceval_power(double x, double y, int arg_check) {
697 if (arg_check) {
698 ceval_error("pow(): function takes two arguments");
699 return NAN;
700 }
701 if(x<0 && ceval_frac_part(y)!=0) {
702 ceval_error("pow(): negative numbers can only be raised to integral powers");
703 return NAN;
704 }
705 return pow(x, y);
706 }
ceval_atan2(double x,double y,int arg_check)707 double ceval_atan2(double x, double y, int arg_check) {
708 if (arg_check) {
709 ceval_error("atan2(): function takes two arguments");
710 return NAN;
711 }
712 return atan2(x, y);
713 }
ceval_sci2dec(double m,double e,int arg_check)714 double ceval_sci2dec(double m, double e, int arg_check) {
715 if (arg_check) {
716 ceval_error("sci2dec(): function takes two arguments");
717 return NAN;
718 }
719 return (double) m * ceval_power(10, e, 0);
720 }
ceval_and(double x,double y,int arg_check)721 double ceval_and(double x, double y, int arg_check) {
722 if (arg_check) {
723 ceval_error("and(): function takes two arguments");
724 return NAN;
725 }
726 return (double) ((int)x && (int)y);
727 }
ceval_or(double x,double y,int arg_check)728 double ceval_or(double x, double y, int arg_check) {
729 if (arg_check) {
730 ceval_error("or(): function takes two arguments");
731 return NAN;
732 }
733 return (double) ((int)x || (int)y);
734 }
ceval_bit_and(double x,double y,int arg_check)735 double ceval_bit_and(double x, double y, int arg_check) {
736 if (arg_check) {
737 ceval_error("bit_and(): function takes two arguments");
738 return NAN;
739 }
740 if(ceval_frac_part(x) == 0 && ceval_frac_part(y) == 0) {
741 return (int)x & (int)y;
742 } else {
743 ceval_error("bit_and(): operands must be of integral type");
744 return NAN;
745 }
746 }
ceval_bit_xor(double x,double y,int arg_check)747 double ceval_bit_xor(double x, double y, int arg_check) {
748 if (arg_check) {
749 ceval_error("bit_xor(): function takes two arguments");
750 return NAN;
751 }
752 if(ceval_frac_part(x) == 0 && ceval_frac_part(y) == 0) {
753 return (int)x ^ (int)y;
754 } else {
755 ceval_error("bit_xor(): operands must be of integral type");
756 return NAN;
757 }
758 }
ceval_bit_or(double x,double y,int arg_check)759 double ceval_bit_or(double x, double y, int arg_check) {
760 if (arg_check) {
761 ceval_error("bit_or(): function takes two arguments");
762 return NAN;
763 }
764 if(ceval_frac_part(x) == 0 && ceval_frac_part(y) == 0) {
765 return (int)x | (int)y;
766 } else {
767 ceval_error("bit_or(): operands must be of integral type");
768 return NAN;
769 }
770 }
ceval_bit_lshift(double x,double y,int arg_check)771 double ceval_bit_lshift(double x, double y, int arg_check) {
772 if (arg_check) {
773 ceval_error("bit_lshift(): function takes two arguments");
774 return NAN;
775 }
776 if(ceval_frac_part(x) == 0 && ceval_frac_part(y) == 0) {
777 return (int)x << (int)y;
778 } else {
779 ceval_error("bit_lshift(): operands must be of integral type");
780 return NAN;
781 }
782
783 }
ceval_bit_rshift(double x,double y,int arg_check)784 double ceval_bit_rshift(double x, double y, int arg_check) {
785 if (arg_check) {
786 ceval_error("bit_rshift(): function takes two arguments");
787 return NAN;
788 }
789 if(ceval_frac_part(x) == 0 && ceval_frac_part(y) == 0) {
790 return (int)x >> (int)y;
791 } else {
792 ceval_error("bit_rshift(): operands must be of integral type");
793 return NAN;
794 }
795 }
796 /**************************************** !FUNCTIONS ********************************************/
797
798 /***************************************** PARSE_TREE_CONSTRUCTION *******************************************/
799 void * ceval_make_tree(char * );
800 ceval_node * ceval_insert_node(ceval_node * , ceval_node, int);
801 void ceval_print_tree(const void * );
802 void ceval_print_node(const ceval_node * , int);
803 void ceval_delete_node(ceval_node * );
804 void ceval_delete_tree(void * );
805
ceval_delete_node(ceval_node * node)806 void ceval_delete_node(ceval_node * node) {
807 if (!node) return;
808 ceval_delete_node(node -> left);
809 ceval_delete_node(node -> right);
810 free(node);
811 }
ceval_delete_tree(void * tree)812 void ceval_delete_tree(void * tree) {
813 ceval_delete_node((ceval_node * ) tree);
814 }
ceval_insert_node(ceval_node * current,ceval_node item,int isRightAssoc)815 ceval_node * ceval_insert_node(ceval_node * current, ceval_node item, int isRightAssoc) {
816 if (item.id != CEVAL_OPENPAR &&
817 item.id != CEVAL_NEGSIGN &&
818 item.id != CEVAL_POSSIGN) {
819 if (isRightAssoc) {
820 while (current -> pre > item.pre) {
821 current = current -> parent;
822 }
823 } else {
824 while (current -> pre >= item.pre) {
825 current = current -> parent;
826 }
827 }
828 }
829 if (item.id == CEVAL_CLOSEPAR) {
830 ceval_node * parent_of_openpar = current -> parent;
831 parent_of_openpar -> right = current -> right;
832 if (current -> right) current -> right -> parent = parent_of_openpar;
833 free(current);
834 current = parent_of_openpar;
835
836 if (current -> right -> id == CEVAL_COMMA &&
837 ceval_is_binary_fun(current -> id)) {
838 ceval_node * address_of_comma = current -> right;
839 parent_of_openpar -> left = address_of_comma -> left;
840 address_of_comma -> left -> parent = parent_of_openpar;
841 parent_of_openpar -> right = address_of_comma -> right;
842 address_of_comma -> right -> parent = parent_of_openpar;
843 free(address_of_comma);
844 }
845 return current;
846 }
847 ceval_node * newnode = (ceval_node * ) malloc(sizeof(ceval_node));
848 * newnode = item;
849 newnode -> right = NULL;
850
851 newnode -> left = current -> right;
852 if (current -> right) current -> right -> parent = newnode;
853 current -> right = newnode;
854 newnode -> parent = current;
855 current = newnode;
856 return current;
857 }
858
ceval_make_tree(char * expression)859 void * ceval_make_tree(char * expression) {
860 if (expression == NULL) return NULL;
861 strcpy(expression, ceval_shrink(expression));
862 ceval_node root = {
863 CEVAL_OPENPAR,
864 ceval_token_prec(CEVAL_OPENPAR),
865 0,
866 NULL,
867 NULL,
868 NULL
869 };
870 ceval_node_id previous_id = CEVAL_OPENPAR;
871 ceval_node * current = & root;
872 int isRightAssoc = 0;
873 while (1) {
874 ceval_node node;
875 char c = * expression++;
876 if (c == '\0') break;
877 int token_found = -1;
878 char token[50];
879 unsigned int len = 0;
880 for(unsigned int i = 0; i < CEVAL_TOKEN_TABLE_SIZE; i++) {
881 strcpy(token, ceval_token_info[i].symbol);
882 len = (unsigned int) strlen(token);
883 if (!memcmp(expression - 1, token, len)) {
884 token_found = ceval_token_info[i].id;
885 isRightAssoc = (token_found == CEVAL_POW || token_found == CEVAL_CLOSEPAR ) ? 1 : 0;
886 break;
887 }
888 }
889 // if token is found
890 if (token_found > -1) {
891 // check if the token is a binary operator
892 if (ceval_is_binary_opr((ceval_node_id)token_found)) {
893 // a binary operator must be preceded by a number, a numerical constant, a clospar, or a factorial
894 if (previous_id == CEVAL_NUMBER ||
895 previous_id == CEVAL_CONST_PI ||
896 previous_id == CEVAL_CONST_E ||
897 previous_id == CEVAL_CLOSEPAR) {
898 // other tokens (other than CEVAL_NUMBER, CEVAL_CLOSEPAR) are allowed only before '+'s or '-'s
899 expression = expression + (len - 1);
900 node.id = (ceval_node_id)token_found;
901 node.pre = ceval_token_prec(node.id);
902 } else {
903 // if the operator is not preceded by a number, a numerical constant, a closepar, or a factorial, then check if the
904 // character is a sign ('+' or '-')
905 if (c == '+') {
906 node.id = CEVAL_POSSIGN;
907 node.pre = ceval_token_prec(node.id);
908 } else if (c == '-') {
909 node.id = CEVAL_NEGSIGN;
910 node.pre = ceval_token_prec(node.id);
911 } else {
912 // if it is not a sign, then it must be a misplaced character
913 ceval_error("Misplaced '%c'.", c);
914 ceval_delete_tree(root.right);
915 root.right = NULL;
916 return NULL;
917 }
918 }
919 } else if (token_found == CEVAL_NUMBER){
920 // if the token is a number, then store it in an array
921 node.pre = ceval_token_prec(CEVAL_NUMBER);
922 unsigned int i;
923 char number[CEVAL_MAX_DIGITS];
924 for (i = 0; i + 1 < sizeof(number);) {
925 number[i++] = c;
926 c = * expression;
927 if (('0' <= c && c <= '9') ||
928 c == '.')
929 expression++;
930 else
931 break;
932 }
933 number[i] = '\0';
934 //copy the contents of the number array at &node.number
935 sscanf(number, "%lf", & node.number);
936 node.id = CEVAL_NUMBER;
937 goto END;
938 } else if (token_found == CEVAL_WHITESPACE) {
939 // skip whitespace
940 continue;
941 } else {
942 // for any other token
943 expression = expression + (len - 1);
944 node.id = (ceval_node_id)token_found;
945 node.pre = ceval_token_prec(node.id);
946 if (node.id == CEVAL_CONST_PI || node.id == CEVAL_CONST_E) {
947 node.number = (node.id == CEVAL_CONST_PI) ? CEVAL_PI : CEVAL_E;
948 }
949 }
950 } else {
951 // if the token is not found in the token table
952 ceval_error("Unknown token '%c'.", c);
953 ceval_delete_tree(root.right);
954 root.right = NULL;
955 return NULL;
956 }
957 END: ;
958 previous_id = node.id;
959 current = ceval_insert_node(current, node, isRightAssoc);
960 }
961 if (root.right) root.right -> parent = NULL;
962 return root.right;
963 }
ceval_print_node(const ceval_node * node,int indent)964 void ceval_print_node(const ceval_node * node, int indent) {
965 int i;
966 char number[CEVAL_MAX_DIGITS];
967 const char * str;
968 if (!node) return;
969 ceval_print_node(node -> right, indent + 4);
970 if (node -> id == CEVAL_NUMBER) {
971 if ((long) node -> number == node -> number) //for integers, skip the trailing zeroes
972 snprintf(number, sizeof(number), "%.0f", node -> number);
973 else snprintf(number, sizeof(number), "%.2f", node -> number);
974 str = number;
975 } else {
976 str = ceval_token_symbol(node -> id);
977 }
978 for (i = 0; i < indent; i++) {
979 putchar(' ');
980 putchar(' ');
981 }
982 printf("%s\n", str);
983 ceval_print_node(node -> left, indent + 4);
984 }
ceval_print_tree(const void * tree)985 void ceval_print_tree(const void * tree) {
986 ceval_print_node((const ceval_node * ) tree, 0);
987 }
988 /***************************************** !PARSE_TREE_CONSTRUCTION *******************************************/
989
990 /***************************************** EVALUATION *******************************************/
991 double ceval_evaluate_tree_(const ceval_node * );
992 double ceval_evaluate_tree(const void * );
993
ceval_evaluate_tree_(const ceval_node * node)994 double ceval_evaluate_tree_(const ceval_node * node) {
995 if (!node)
996 return 0;
997
998 double left, right;
999 left = ceval_evaluate_tree_(node -> left);
1000 right = ceval_evaluate_tree_(node -> right);
1001 switch (node -> id) {
1002
1003 //unary-right operators/functions (operate on the expression to their right)
1004 case CEVAL_ABS: case CEVAL_EXP: case CEVAL_SQRT: case CEVAL_CBRT:
1005 case CEVAL_LN: case CEVAL_LOG10: case CEVAL_CEIL: case CEVAL_FLOOR:
1006 case CEVAL_SIGNUM: case CEVAL_FACTORIAL: case CEVAL_INT: case CEVAL_FRAC:
1007 case CEVAL_DEG2RAD: case CEVAL_RAD2DEG: case CEVAL_SIN: case CEVAL_COS:
1008 case CEVAL_TAN: case CEVAL_ASIN: case CEVAL_ACOS: case CEVAL_ATAN:
1009 case CEVAL_SINH: case CEVAL_COSH: case CEVAL_TANH: case CEVAL_NOT:
1010 case CEVAL_BIT_NOT: case CEVAL_POSSIGN: case CEVAL_NEGSIGN:
1011 if (node -> right != NULL) {
1012 //operate on right operand
1013 return ( * single_arg_fun[node -> id])(right);
1014 } else {
1015 ceval_error("Missing operand(s)");
1016 return NAN;
1017 }
1018 //binary operators/functions
1019 case CEVAL_COMMA:
1020 case CEVAL_OR: case CEVAL_AND: case CEVAL_BIT_OR: case CEVAL_BIT_XOR:
1021 case CEVAL_BIT_AND: case CEVAL_EQUAL: case CEVAL_NOTEQUAL: case CEVAL_LESSER:
1022 case CEVAL_GREATER: case CEVAL_LESSER_S: case CEVAL_GREATER_S: case CEVAL_BIT_LSHIFT:
1023 case CEVAL_BIT_RSHIFT: case CEVAL_PLUS: case CEVAL_MINUS: case CEVAL_TIMES:
1024 case CEVAL_DIVIDE: case CEVAL_MODULO: case CEVAL_QUOTIENT: case CEVAL_POW:
1025 case CEVAL_GCD: case CEVAL_HCF: case CEVAL_LCM: case CEVAL_LOG:
1026 case CEVAL_ATAN2: case CEVAL_SCI2DEC: case CEVAL_POWFUN:
1027 if (node -> left == NULL) {
1028 return ( * double_arg_fun[node -> id])(left, right, -1);
1029 } else if (node -> right == NULL) {
1030 return ( * double_arg_fun[node -> id])(left, right, 1);
1031 } else {
1032 return ( * double_arg_fun[node -> id])(left, right, 0);
1033 }
1034 default:
1035 return node -> number;
1036 }
1037 }
ceval_evaluate_tree(const void * node)1038 double ceval_evaluate_tree(const void * node) {
1039 return (node == NULL)? NAN :
1040 ceval_evaluate_tree_((ceval_node * ) node);
1041 }
1042 /***************************************** !EVALUATION *******************************************/
1043
1044 /***************************************** MAIN FUNCTIONS *******************************************/
1045 // functions accessible from main()
1046 // - double ceval_result(char * inp) returns the result of valid math expression stored as a char array `inp`
1047 // - void ceval_tree(char * inp) prints the parse tree for the input expression `inp`
1048 // - define CEVAL_EPSILON (default value : 1e-2), CEVAL_DELTA (default value : 1e-6) and CEVAL_MAX_DIGITS (default value : 15) manually before the include directive
1049 // - define CEVAL_STOICAL before the #include directive to use the parser/evaluator in stoical (non-complaining) mode. It suppresses all the error messages from [ceval].
1050
ceval_result(char * expr)1051 double ceval_result(char * expr) {
1052 void * tree = ceval_make_tree(expr);
1053 double result = ceval_evaluate_tree(tree);
1054 ceval_delete_tree(tree);
1055 return result;
1056 }
ceval_tree(char * expr)1057 void ceval_tree(char * expr) {
1058 void * tree = ceval_make_tree(expr);
1059 ceval_print_tree(tree);
1060 ceval_delete_tree(tree);
1061 }
1062
1063 #ifdef CEVAL_CXX
ceval_result(std::string expr)1064 double ceval_result(std::string expr) {
1065 return ceval_result((char * ) expr.c_str());
1066 }
ceval_tree(std::string expr)1067 void ceval_tree(std::string expr) {
1068 ceval_tree((char * ) expr.c_str());
1069 }
1070 #endif
1071 /***************************************** !MAIN FUNCTIONS *******************************************/
1072 #endif
1073