xref: /aosp_15_r20/external/angle/src/third_party/ceval/ceval.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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