Line data Source code
1 : // SPDX-License-Identifier: Zlib
2 : /*
3 : * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
4 : *
5 : * Copyright (c) 2015-2020 Lewis Van Winkle
6 : *
7 : * http://CodePlea.com
8 : *
9 : * This software is provided 'as-is', without any express or implied
10 : * warranty. In no event will the authors be held liable for any damages
11 : * arising from the use of this software.
12 : *
13 : * Permission is granted to anyone to use this software for any purpose,
14 : * including commercial applications, and to alter it and redistribute it
15 : * freely, subject to the following restrictions:
16 : *
17 : * 1. The origin of this software must not be misrepresented; you must not
18 : * claim that you wrote the original software. If you use this software
19 : * in a product, an acknowledgement in the product documentation would be
20 : * appreciated but is not required.
21 : * 2. Altered source versions must be plainly marked as such, and must not be
22 : * misrepresented as being the original software.
23 : * 3. This notice may not be removed or altered from any source distribution.
24 : */
25 :
26 : /* COMPILE TIME OPTIONS */
27 :
28 : /* Exponentiation associativity:
29 : For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing.
30 : For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/
31 : /* #define TE_POW_FROM_RIGHT */
32 :
33 : /* Logarithms
34 : For log = base 10 log do nothing
35 : For log = natural log uncomment the next line. */
36 : /* #define TE_NAT_LOG */
37 :
38 : #include "tinyexpr.h"
39 : #include <ctype.h>
40 : #include <limits.h>
41 : #include <math.h>
42 : #include <stdio.h>
43 : #include <stdlib.h>
44 : #include <string.h>
45 :
46 : #ifndef NAN
47 : #define NAN (0.0 / 0.0)
48 : #endif
49 :
50 : #ifndef INFINITY
51 : #define INFINITY (1.0 / 0.0)
52 : #endif
53 :
54 : typedef double (*te_fun2)(double, double);
55 :
56 : enum {
57 : TOK_NULL = TE_CLOSURE7 + 1,
58 : TOK_ERROR,
59 : TOK_END,
60 : TOK_SEP,
61 : TOK_OPEN,
62 : TOK_CLOSE,
63 : TOK_NUMBER,
64 : TOK_VARIABLE,
65 : TOK_INFIX
66 : };
67 :
68 : enum { TE_CONSTANT = 1 };
69 :
70 : typedef struct state {
71 : const char *start;
72 : const char *next;
73 : int type;
74 : union {
75 : double value;
76 : const double *bound;
77 : const void *function;
78 : };
79 : void *context;
80 :
81 : const te_variable *lookup;
82 : int lookup_len;
83 : } state;
84 :
85 : #define TYPE_MASK(TYPE) ((TYPE) &0x0000001F)
86 :
87 : #define IS_PURE(TYPE) (((TYPE) &TE_FLAG_PURE) != 0)
88 : #define IS_FUNCTION(TYPE) (((TYPE) &TE_FUNCTION0) != 0)
89 : #define IS_CLOSURE(TYPE) (((TYPE) &TE_CLOSURE0) != 0)
90 : #define ARITY(TYPE) (((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) &0x00000007) : 0)
91 : #define NEW_EXPR(type, ...) new_expr((type), (const te_expr *[]){__VA_ARGS__})
92 :
93 0 : static te_expr *new_expr(const int type, const te_expr *parameters[]) {
94 0 : const int arity = ARITY(type);
95 0 : const int psize = sizeof(void *) * arity;
96 0 : const int size = (sizeof(te_expr) /* - sizeof(void *) */) + psize + (IS_CLOSURE(type) ? sizeof(void *) : 0);
97 0 : te_expr *ret = malloc(size);
98 0 : memset(ret, 0, size);
99 0 : if (arity && parameters) {
100 0 : memcpy(ret->parameters, parameters, psize);
101 : }
102 0 : ret->type = type;
103 0 : ret->bound = 0;
104 0 : return ret;
105 : }
106 :
107 0 : void te_free_parameters(te_expr *n) {
108 0 : if (!n)
109 0 : return;
110 0 : switch (TYPE_MASK(n->type)) {
111 0 : case TE_FUNCTION7:
112 0 : case TE_CLOSURE7: te_free(n->parameters[6]); /* Falls through. */
113 0 : case TE_FUNCTION6:
114 0 : case TE_CLOSURE6: te_free(n->parameters[5]); /* Falls through. */
115 0 : case TE_FUNCTION5:
116 0 : case TE_CLOSURE5: te_free(n->parameters[4]); /* Falls through. */
117 0 : case TE_FUNCTION4:
118 0 : case TE_CLOSURE4: te_free(n->parameters[3]); /* Falls through. */
119 0 : case TE_FUNCTION3:
120 0 : case TE_CLOSURE3: te_free(n->parameters[2]); /* Falls through. */
121 0 : case TE_FUNCTION2:
122 0 : case TE_CLOSURE2: te_free(n->parameters[1]); /* Falls through. */
123 0 : case TE_FUNCTION1:
124 0 : case TE_CLOSURE1: te_free(n->parameters[0]);
125 : }
126 : }
127 :
128 0 : void te_free(te_expr *n) {
129 0 : if (!n)
130 0 : return;
131 0 : te_free_parameters(n);
132 0 : free(n);
133 : }
134 :
135 0 : static double pi(void) { return 3.14159265358979323846; }
136 0 : static double e(void) { return 2.71828182845904523536; }
137 0 : static double fac(double a) { /* simplest version of fac */
138 0 : if (a < 0.0)
139 0 : return NAN;
140 0 : if (a > UINT_MAX)
141 0 : return INFINITY;
142 0 : unsigned int ua = (unsigned int) (a);
143 0 : unsigned long int result = 1, i;
144 0 : for (i = 1; i <= ua; i++) {
145 0 : if (i > ULONG_MAX / result)
146 0 : return INFINITY;
147 0 : result *= i;
148 : }
149 0 : return (double) result;
150 : }
151 0 : static double ncr(double n, double r) {
152 0 : if (n < 0.0 || r < 0.0 || n < r)
153 0 : return NAN;
154 0 : if (n > UINT_MAX || r > UINT_MAX)
155 0 : return INFINITY;
156 0 : unsigned long int un = (unsigned int) (n), ur = (unsigned int) (r), i;
157 0 : unsigned long int result = 1;
158 0 : if (ur > un / 2)
159 0 : ur = un - ur;
160 0 : for (i = 1; i <= ur; i++) {
161 0 : if (result > ULONG_MAX / (un - ur + i))
162 0 : return INFINITY;
163 0 : result *= un - ur + i;
164 0 : result /= i;
165 : }
166 0 : return result;
167 : }
168 0 : static double npr(double n, double r) { return ncr(n, r) * fac(r); }
169 :
170 : #ifdef _MSC_VER
171 : #pragma function(ceil)
172 : #pragma function(floor)
173 : #endif
174 :
175 : static const te_variable functions[] = {
176 : /* must be in alphabetical order */
177 : {"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE, 0},
178 : {"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
179 : {"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
180 : {"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
181 : {"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE, 0},
182 : {"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE, 0},
183 : {"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
184 : {"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
185 : {"e", e, TE_FUNCTION0 | TE_FLAG_PURE, 0},
186 : {"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE, 0},
187 : {"fac", fac, TE_FUNCTION1 | TE_FLAG_PURE, 0},
188 : {"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE, 0},
189 : {"ln", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
190 : #ifdef TE_NAT_LOG
191 : {"log", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
192 : #else
193 : {"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
194 : #endif
195 : {"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
196 : {"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
197 : {"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
198 : {"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0},
199 : {"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0},
200 : {"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
201 : {"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
202 : {"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE, 0},
203 : {"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
204 : {"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
205 : {0, 0, 0, 0}};
206 :
207 0 : static const te_variable *find_builtin(const char *name, int len) {
208 0 : int imin = 0;
209 0 : int imax = sizeof(functions) / sizeof(te_variable) - 2;
210 :
211 : /*Binary search.*/
212 0 : while (imax >= imin) {
213 0 : const int i = (imin + ((imax - imin) / 2));
214 0 : int c = strncmp(name, functions[i].name, len);
215 0 : if (!c)
216 0 : c = '\0' - functions[i].name[len];
217 0 : if (c == 0) {
218 0 : return functions + i;
219 0 : } else if (c > 0) {
220 0 : imin = i + 1;
221 : } else {
222 0 : imax = i - 1;
223 : }
224 : }
225 :
226 0 : return 0;
227 : }
228 :
229 0 : static const te_variable *find_lookup(const state *s, const char *name, int len) {
230 : int iters;
231 : const te_variable *var;
232 0 : if (!s->lookup)
233 0 : return 0;
234 :
235 0 : for (var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) {
236 0 : if (strncmp(name, var->name, len) == 0 && var->name[len] == '\0') {
237 0 : return var;
238 : }
239 : }
240 0 : return 0;
241 : }
242 :
243 0 : static double add(double a, double b) { return a + b; }
244 0 : static double sub(double a, double b) { return a - b; }
245 0 : static double mul(double a, double b) { return a * b; }
246 0 : static double divide(double a, double b) { return a / b; }
247 0 : static double negate(double a) { return -a; }
248 0 : static double comma(double a, double b) {
249 : (void) a;
250 0 : return b;
251 : }
252 :
253 0 : void next_token(state *s) {
254 0 : s->type = TOK_NULL;
255 :
256 : do {
257 :
258 0 : if (!*s->next) {
259 0 : s->type = TOK_END;
260 0 : return;
261 : }
262 :
263 : /* Try reading a number. */
264 0 : if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
265 0 : s->value = strtod(s->next, (char **) &s->next);
266 0 : s->type = TOK_NUMBER;
267 : } else {
268 : /* Look for a variable or builtin function call. */
269 0 : if (isalpha(s->next[0])) {
270 : const char *start;
271 0 : start = s->next;
272 0 : while (isalpha(s->next[0]) || isdigit(s->next[0]) || (s->next[0] == '_'))
273 0 : s->next++;
274 :
275 0 : const te_variable *var = find_lookup(s, start, s->next - start);
276 0 : if (!var)
277 0 : var = find_builtin(start, s->next - start);
278 :
279 0 : if (!var) {
280 0 : s->type = TOK_ERROR;
281 : } else {
282 0 : switch (TYPE_MASK(var->type)) {
283 0 : case TE_VARIABLE:
284 0 : s->type = TOK_VARIABLE;
285 0 : s->bound = var->address;
286 0 : break;
287 :
288 0 : case TE_CLOSURE0:
289 : case TE_CLOSURE1:
290 : case TE_CLOSURE2:
291 : case TE_CLOSURE3: /* Falls through. */
292 : case TE_CLOSURE4:
293 : case TE_CLOSURE5:
294 : case TE_CLOSURE6:
295 : case TE_CLOSURE7: /* Falls through. */
296 0 : s->context = var->context; /* Falls through. */
297 :
298 0 : case TE_FUNCTION0:
299 : case TE_FUNCTION1:
300 : case TE_FUNCTION2:
301 : case TE_FUNCTION3: /* Falls through. */
302 : case TE_FUNCTION4:
303 : case TE_FUNCTION5:
304 : case TE_FUNCTION6:
305 : case TE_FUNCTION7: /* Falls through. */
306 0 : s->type = var->type;
307 0 : s->function = var->address;
308 0 : break;
309 : }
310 : }
311 :
312 : } else {
313 : /* Look for an operator or special character. */
314 0 : switch (s->next++[0]) {
315 0 : case '+':
316 0 : s->type = TOK_INFIX;
317 0 : s->function = add;
318 0 : break;
319 0 : case '-':
320 0 : s->type = TOK_INFIX;
321 0 : s->function = sub;
322 0 : break;
323 0 : case '*':
324 0 : s->type = TOK_INFIX;
325 0 : s->function = mul;
326 0 : break;
327 0 : case '/':
328 0 : s->type = TOK_INFIX;
329 0 : s->function = divide;
330 0 : break;
331 0 : case '^':
332 0 : s->type = TOK_INFIX;
333 0 : s->function = pow;
334 0 : break;
335 0 : case '%':
336 0 : s->type = TOK_INFIX;
337 0 : s->function = fmod;
338 0 : break;
339 0 : case '(': s->type = TOK_OPEN; break;
340 0 : case ')': s->type = TOK_CLOSE; break;
341 0 : case ',': s->type = TOK_SEP; break;
342 0 : case ' ':
343 : case '\t':
344 : case '\n':
345 0 : case '\r': break;
346 0 : default: s->type = TOK_ERROR; break;
347 : }
348 : }
349 : }
350 0 : } while (s->type == TOK_NULL);
351 : }
352 :
353 : static te_expr *list(state *s);
354 : static te_expr *expr(state *s);
355 : static te_expr *power(state *s);
356 :
357 0 : static te_expr *base(state *s) {
358 : /* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
359 : te_expr *ret;
360 : int arity;
361 :
362 0 : switch (TYPE_MASK(s->type)) {
363 0 : case TOK_NUMBER:
364 0 : ret = new_expr(TE_CONSTANT, 0);
365 0 : ret->value = s->value;
366 0 : next_token(s);
367 0 : break;
368 :
369 0 : case TOK_VARIABLE:
370 0 : ret = new_expr(TE_VARIABLE, 0);
371 0 : ret->bound = s->bound;
372 0 : next_token(s);
373 0 : break;
374 :
375 0 : case TE_FUNCTION0:
376 : case TE_CLOSURE0:
377 0 : ret = new_expr(s->type, 0);
378 0 : ret->function = s->function;
379 0 : if (IS_CLOSURE(s->type))
380 0 : ret->parameters[0] = s->context;
381 0 : next_token(s);
382 0 : if (s->type == TOK_OPEN) {
383 0 : next_token(s);
384 0 : if (s->type != TOK_CLOSE) {
385 0 : s->type = TOK_ERROR;
386 : } else {
387 0 : next_token(s);
388 : }
389 : }
390 0 : break;
391 :
392 0 : case TE_FUNCTION1:
393 : case TE_CLOSURE1:
394 0 : ret = new_expr(s->type, 0);
395 0 : ret->function = s->function;
396 0 : if (IS_CLOSURE(s->type))
397 0 : ret->parameters[1] = s->context;
398 0 : next_token(s);
399 0 : ret->parameters[0] = power(s);
400 0 : break;
401 :
402 0 : case TE_FUNCTION2:
403 : case TE_FUNCTION3:
404 : case TE_FUNCTION4:
405 : case TE_FUNCTION5:
406 : case TE_FUNCTION6:
407 : case TE_FUNCTION7:
408 : case TE_CLOSURE2:
409 : case TE_CLOSURE3:
410 : case TE_CLOSURE4:
411 : case TE_CLOSURE5:
412 : case TE_CLOSURE6:
413 : case TE_CLOSURE7:
414 0 : arity = ARITY(s->type);
415 :
416 0 : ret = new_expr(s->type, 0);
417 0 : ret->function = s->function;
418 0 : if (IS_CLOSURE(s->type))
419 0 : ret->parameters[arity] = s->context;
420 0 : next_token(s);
421 :
422 0 : if (s->type != TOK_OPEN) {
423 0 : s->type = TOK_ERROR;
424 : } else {
425 : int i;
426 0 : for (i = 0; i < arity; i++) {
427 0 : next_token(s);
428 0 : ret->parameters[i] = expr(s);
429 0 : if (s->type != TOK_SEP) {
430 0 : break;
431 : }
432 : }
433 0 : if (s->type != TOK_CLOSE || i != arity - 1) {
434 0 : s->type = TOK_ERROR;
435 : } else {
436 0 : next_token(s);
437 : }
438 : }
439 :
440 0 : break;
441 :
442 0 : case TOK_OPEN:
443 0 : next_token(s);
444 0 : ret = list(s);
445 0 : if (s->type != TOK_CLOSE) {
446 0 : s->type = TOK_ERROR;
447 : } else {
448 0 : next_token(s);
449 : }
450 0 : break;
451 :
452 0 : default:
453 0 : ret = new_expr(0, 0);
454 0 : s->type = TOK_ERROR;
455 0 : ret->value = NAN;
456 0 : break;
457 : }
458 :
459 0 : return ret;
460 : }
461 :
462 0 : static te_expr *power(state *s) {
463 : /* <power> = {("-" | "+")} <base> */
464 0 : int sign = 1;
465 0 : while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
466 0 : if (s->function == sub)
467 0 : sign = -sign;
468 0 : next_token(s);
469 : }
470 :
471 : te_expr *ret;
472 :
473 0 : if (sign == 1) {
474 0 : ret = base(s);
475 : } else {
476 0 : ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
477 0 : ret->function = negate;
478 : }
479 :
480 0 : return ret;
481 : }
482 :
483 : #ifdef TE_POW_FROM_RIGHT
484 : static te_expr *factor(state *s) {
485 : /* <factor> = <power> {"^" <power>} */
486 : te_expr *ret = power(s);
487 :
488 : int neg = 0;
489 :
490 : if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) {
491 : te_expr *se = ret->parameters[0];
492 : free(ret);
493 : ret = se;
494 : neg = 1;
495 : }
496 :
497 : te_expr *insertion = 0;
498 :
499 : while (s->type == TOK_INFIX && (s->function == pow)) {
500 : te_fun2 t = s->function;
501 : next_token(s);
502 :
503 : if (insertion) {
504 : /* Make exponentiation go right-to-left. */
505 : te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s));
506 : insert->function = t;
507 : insertion->parameters[1] = insert;
508 : insertion = insert;
509 : } else {
510 : ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
511 : ret->function = t;
512 : insertion = ret;
513 : }
514 : }
515 :
516 : if (neg) {
517 : ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret);
518 : ret->function = negate;
519 : }
520 :
521 : return ret;
522 : }
523 : #else
524 0 : static te_expr *factor(state *s) {
525 : /* <factor> = <power> {"^" <power>} */
526 0 : te_expr *ret = power(s);
527 :
528 0 : while (s->type == TOK_INFIX && (s->function == pow)) {
529 0 : te_fun2 t = s->function;
530 0 : next_token(s);
531 0 : ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
532 0 : ret->function = t;
533 : }
534 :
535 0 : return ret;
536 : }
537 : #endif
538 :
539 0 : static te_expr *term(state *s) {
540 : /* <term> = <factor> {("*" | "/" | "%") <factor>} */
541 0 : te_expr *ret = factor(s);
542 :
543 0 : while (s->type == TOK_INFIX && (s->function == mul || s->function == divide || s->function == fmod)) {
544 0 : te_fun2 t = s->function;
545 0 : next_token(s);
546 0 : ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s));
547 0 : ret->function = t;
548 : }
549 :
550 0 : return ret;
551 : }
552 :
553 0 : static te_expr *expr(state *s) {
554 : /* <expr> = <term> {("+" | "-") <term>} */
555 0 : te_expr *ret = term(s);
556 :
557 0 : while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
558 0 : te_fun2 t = s->function;
559 0 : next_token(s);
560 0 : ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s));
561 0 : ret->function = t;
562 : }
563 :
564 0 : return ret;
565 : }
566 :
567 0 : static te_expr *list(state *s) {
568 : /* <list> = <expr> {"," <expr>} */
569 0 : te_expr *ret = expr(s);
570 :
571 0 : while (s->type == TOK_SEP) {
572 0 : next_token(s);
573 0 : ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s));
574 0 : ret->function = comma;
575 : }
576 :
577 0 : return ret;
578 : }
579 :
580 : #define TE_FUN(...) ((double (*)(__VA_ARGS__)) n->function)
581 : #define M(e) te_eval(n->parameters[e])
582 :
583 0 : double te_eval(const te_expr *n) {
584 0 : if (!n)
585 0 : return NAN;
586 :
587 0 : switch (TYPE_MASK(n->type)) {
588 0 : case TE_CONSTANT: return n->value;
589 0 : case TE_VARIABLE: return *n->bound;
590 :
591 0 : case TE_FUNCTION0:
592 : case TE_FUNCTION1:
593 : case TE_FUNCTION2:
594 : case TE_FUNCTION3:
595 : case TE_FUNCTION4:
596 : case TE_FUNCTION5:
597 : case TE_FUNCTION6:
598 : case TE_FUNCTION7:
599 0 : switch (ARITY(n->type)) {
600 0 : case 0: return TE_FUN(void)();
601 0 : case 1: return TE_FUN(double)(M(0));
602 0 : case 2: return TE_FUN(double, double)(M(0), M(1));
603 0 : case 3: return TE_FUN(double, double, double)(M(0), M(1), M(2));
604 0 : case 4: return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3));
605 0 : case 5: return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4));
606 0 : case 6: return TE_FUN(double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5));
607 0 : case 7: return TE_FUN(double, double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5), M(6));
608 0 : default: return NAN;
609 : }
610 :
611 0 : case TE_CLOSURE0:
612 : case TE_CLOSURE1:
613 : case TE_CLOSURE2:
614 : case TE_CLOSURE3:
615 : case TE_CLOSURE4:
616 : case TE_CLOSURE5:
617 : case TE_CLOSURE6:
618 : case TE_CLOSURE7:
619 0 : switch (ARITY(n->type)) {
620 0 : case 0: return TE_FUN(void *)(n->parameters[0]);
621 0 : case 1: return TE_FUN(void *, double)(n->parameters[1], M(0));
622 0 : case 2: return TE_FUN(void *, double, double)(n->parameters[2], M(0), M(1));
623 0 : case 3: return TE_FUN(void *, double, double, double)(n->parameters[3], M(0), M(1), M(2));
624 0 : case 4: return TE_FUN(void *, double, double, double, double)(n->parameters[4], M(0), M(1), M(2), M(3));
625 0 : case 5: return TE_FUN(void *, double, double, double, double, double)(n->parameters[5], M(0), M(1), M(2), M(3), M(4));
626 0 : case 6: return TE_FUN(void *, double, double, double, double, double, double)(n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5));
627 0 : case 7: return TE_FUN(void *, double, double, double, double, double, double, double)(n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6));
628 0 : default: return NAN;
629 : }
630 :
631 0 : default: return NAN;
632 : }
633 : }
634 :
635 : #undef TE_FUN
636 : #undef M
637 :
638 0 : static void optimize(te_expr *n) {
639 : /* Evaluates as much as possible. */
640 0 : if (n->type == TE_CONSTANT)
641 0 : return;
642 0 : if (n->type == TE_VARIABLE)
643 0 : return;
644 :
645 : /* Only optimize out functions flagged as pure. */
646 0 : if (IS_PURE(n->type)) {
647 0 : const int arity = ARITY(n->type);
648 0 : int known = 1;
649 : int i;
650 0 : for (i = 0; i < arity; ++i) {
651 0 : optimize(n->parameters[i]);
652 0 : if (((te_expr *) (n->parameters[i]))->type != TE_CONSTANT) {
653 0 : known = 0;
654 : }
655 : }
656 0 : if (known) {
657 0 : const double value = te_eval(n);
658 0 : te_free_parameters(n);
659 0 : n->type = TE_CONSTANT;
660 0 : n->value = value;
661 : }
662 : }
663 : }
664 :
665 0 : te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) {
666 : state s;
667 0 : s.start = s.next = expression;
668 0 : s.lookup = variables;
669 0 : s.lookup_len = var_count;
670 :
671 0 : next_token(&s);
672 0 : te_expr *root = list(&s);
673 :
674 0 : if (s.type != TOK_END) {
675 0 : te_free(root);
676 0 : if (error) {
677 0 : *error = (s.next - s.start);
678 0 : if (*error == 0)
679 0 : *error = 1;
680 : }
681 0 : return 0;
682 : } else {
683 0 : optimize(root);
684 0 : if (error)
685 0 : *error = 0;
686 0 : return root;
687 : }
688 : }
689 :
690 0 : double te_interp(const char *expression, int *error) {
691 0 : te_expr *n = te_compile(expression, 0, 0, error);
692 : double ret;
693 0 : if (n) {
694 0 : ret = te_eval(n);
695 0 : te_free(n);
696 : } else {
697 0 : ret = NAN;
698 : }
699 0 : return ret;
700 : }
701 :
702 0 : static void pn(const te_expr *n, int depth) {
703 : int i, arity;
704 0 : printf("%*s", depth, "");
705 :
706 0 : switch (TYPE_MASK(n->type)) {
707 0 : case TE_CONSTANT: printf("%f\n", n->value); break;
708 0 : case TE_VARIABLE: printf("bound %p\n", n->bound); break;
709 :
710 0 : case TE_FUNCTION0:
711 : case TE_FUNCTION1:
712 : case TE_FUNCTION2:
713 : case TE_FUNCTION3:
714 : case TE_FUNCTION4:
715 : case TE_FUNCTION5:
716 : case TE_FUNCTION6:
717 : case TE_FUNCTION7:
718 : case TE_CLOSURE0:
719 : case TE_CLOSURE1:
720 : case TE_CLOSURE2:
721 : case TE_CLOSURE3:
722 : case TE_CLOSURE4:
723 : case TE_CLOSURE5:
724 : case TE_CLOSURE6:
725 : case TE_CLOSURE7:
726 0 : arity = ARITY(n->type);
727 0 : printf("f%d", arity);
728 0 : for (i = 0; i < arity; i++) {
729 0 : printf(" %p", n->parameters[i]);
730 : }
731 0 : printf("\n");
732 0 : for (i = 0; i < arity; i++) {
733 0 : pn(n->parameters[i], depth + 1);
734 : }
735 0 : break;
736 : }
737 0 : }
738 :
739 0 : void te_print(const te_expr *n) {
740 0 : pn(n, 0);
741 0 : }
|