1 /*
2  * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
3  *
4  * Copyright (c) 2015, 2016 Lewis Van Winkle
5  *
6  * http://CodePlea.com
7  *
8  * This software is provided 'as-is', without any express or implied
9  * warranty. In no event will the authors be held liable for any damages
10  * arising from the use of this software.
11  *
12  * Permission is granted to anyone to use this software for any purpose,
13  * including commercial applications, and to alter it and redistribute it
14  * freely, subject to the following restrictions:
15  *
16  * 1. The origin of this software must not be misrepresented; you must not
17  * claim that you wrote the original software. If you use this software
18  * in a product, an acknowledgement in the product documentation would be
19  * appreciated but is not required.
20  * 2. Altered source versions must be plainly marked as such, and must not be
21  * misrepresented as being the original software.
22  * 3. This notice may not be removed or altered from any source distribution.
23  */
24 
25 #include "tinyexpr.h"
26 #include <stdio.h>
27 #include "minctest.h"
28 
29 
30 typedef struct {
31     const char *expr;
32     double answer;
33 } test_case;
34 
35 typedef struct {
36     const char *expr1;
37     const char *expr2;
38 } test_equ;
39 
40 
41 
test_results()42 void test_results() {
43     test_case cases[] = {
44         {"1", 1},
45         {"1 ", 1},
46         {"(1)", 1},
47 
48         {"pi", 3.14159},
49         {"atan(1)*4 - pi", 0},
50         {"e", 2.71828},
51 
52         {"2+1", 2+1},
53         {"(((2+(1))))", 2+1},
54         {"3+2", 3+2},
55 
56         {"3+2+4", 3+2+4},
57         {"(3+2)+4", 3+2+4},
58         {"3+(2+4)", 3+2+4},
59         {"(3+2+4)", 3+2+4},
60 
61         {"3*2*4", 3*2*4},
62         {"(3*2)*4", 3*2*4},
63         {"3*(2*4)", 3*2*4},
64         {"(3*2*4)", 3*2*4},
65 
66         {"3-2-4", 3-2-4},
67         {"(3-2)-4", (3-2)-4},
68         {"3-(2-4)", 3-(2-4)},
69         {"(3-2-4)", 3-2-4},
70 
71         {"3/2/4", 3.0/2.0/4.0},
72         {"(3/2)/4", (3.0/2.0)/4.0},
73         {"3/(2/4)", 3.0/(2.0/4.0)},
74         {"(3/2/4)", 3.0/2.0/4.0},
75 
76         {"(3*2/4)", 3.0*2.0/4.0},
77         {"(3/2*4)", 3.0/2.0*4.0},
78         {"3*(2/4)", 3.0*(2.0/4.0)},
79 
80         {"asin sin .5", 0.5},
81         {"sin asin .5", 0.5},
82         {"ln exp .5", 0.5},
83         {"exp ln .5", 0.5},
84 
85         {"asin sin-.5", -0.5},
86         {"asin sin-0.5", -0.5},
87         {"asin sin -0.5", -0.5},
88         {"asin (sin -0.5)", -0.5},
89         {"asin (sin (-0.5))", -0.5},
90         {"asin sin (-0.5)", -0.5},
91         {"(asin sin (-0.5))", -0.5},
92 
93         {"log10 1000", 3},
94         {"log10 1e3", 3},
95         {"log10 1000", 3},
96         {"log10 1e3", 3},
97         {"log10(1000)", 3},
98         {"log10(1e3)", 3},
99         {"log10 1.0e3", 3},
100         {"10^5*5e-5", 5},
101 
102 #ifdef TE_NAT_LOG
103         {"log 1000", 6.9078},
104         {"log e", 1},
105         {"log (e^10)", 10},
106 #else
107         {"log 1000", 3},
108 #endif
109 
110         {"ln (e^10)", 10},
111         {"100^.5+1", 11},
112         {"100 ^.5+1", 11},
113         {"100^+.5+1", 11},
114         {"100^--.5+1", 11},
115         {"100^---+-++---++-+-+-.5+1", 11},
116 
117         {"100^-.5+1", 1.1},
118         {"100^---.5+1", 1.1},
119         {"100^+---.5+1", 1.1},
120         {"1e2^+---.5e0+1e0", 1.1},
121         {"--(1e2^(+(-(-(-.5e0))))+1e0)", 1.1},
122 
123         {"sqrt 100 + 7", 17},
124         {"sqrt 100 * 7", 70},
125         {"sqrt (100 * 100)", 100},
126 
127         {"1,2", 2},
128         {"1,2+1", 3},
129         {"1+1,2+2,2+1", 3},
130         {"1,2,3", 3},
131         {"(1,2),3", 3},
132         {"1,(2,3)", 3},
133         {"-(1,(2,3))", -3},
134 
135         {"2^2", 4},
136         {"pow(2,2)", 4},
137 
138         {"atan2(1,1)", 0.7854},
139         {"atan2(1,2)", 0.4636},
140         {"atan2(2,1)", 1.1071},
141         {"atan2(3,4)", 0.6435},
142         {"atan2(3+3,4*2)", 0.6435},
143         {"atan2(3+3,(4*2))", 0.6435},
144         {"atan2((3+3),4*2)", 0.6435},
145         {"atan2((3+3),(4*2))", 0.6435},
146 
147     };
148 
149 
150     int i;
151     for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
152         const char *expr = cases[i].expr;
153         const double answer = cases[i].answer;
154 
155         int err;
156         const double ev = te_interp(expr, &err);
157         lok(!err);
158         lfequal(ev, answer);
159 
160         if (err) {
161             printf("FAILED: %s (%d)\n", expr, err);
162         }
163     }
164 }
165 
166 
test_syntax()167 void test_syntax() {
168     test_case errors[] = {
169         {"", 1},
170         {"1+", 2},
171         {"1)", 2},
172         {"(1", 2},
173         {"1**1", 3},
174         {"1*2(+4", 4},
175         {"1*2(1+4", 4},
176         {"a+5", 1},
177         {"A+5", 1},
178         {"Aa+5", 1},
179         {"1^^5", 3},
180         {"1**5", 3},
181         {"sin(cos5", 8},
182     };
183 
184 
185     int i;
186     for (i = 0; i < sizeof(errors) / sizeof(test_case); ++i) {
187         const char *expr = errors[i].expr;
188         const int e = errors[i].answer;
189 
190         int err;
191         const double r = te_interp(expr, &err);
192         lequal(err, e);
193         lok(r != r);
194 
195         te_expr *n = te_compile(expr, 0, 0, &err);
196         lequal(err, e);
197         lok(!n);
198 
199         if (err != e) {
200             printf("FAILED: %s\n", expr);
201         }
202 
203         const double k = te_interp(expr, 0);
204         lok(k != k);
205     }
206 }
207 
208 
test_nans()209 void test_nans() {
210 
211     const char *nans[] = {
212         "0/0",
213         "1%0",
214         "1%(1%0)",
215         "(1%0)%1",
216         "fac(-1)",
217         "ncr(2, 4)",
218         "ncr(-2, 4)",
219         "ncr(2, -4)",
220         "npr(2, 4)",
221         "npr(-2, 4)",
222         "npr(2, -4)",
223     };
224 
225     int i;
226     for (i = 0; i < sizeof(nans) / sizeof(const char *); ++i) {
227         const char *expr = nans[i];
228 
229         int err;
230         const double r = te_interp(expr, &err);
231         lequal(err, 0);
232         lok(r != r);
233 
234         te_expr *n = te_compile(expr, 0, 0, &err);
235         lok(n);
236         lequal(err, 0);
237         const double c = te_eval(n);
238         lok(c != c);
239         te_free(n);
240     }
241 }
242 
243 
test_infs()244 void test_infs() {
245 
246     const char *infs[] = {
247             "1/0",
248             "log(0)",
249             "pow(2,10000000)",
250             "fac(300)",
251             "ncr(300,100)",
252             "ncr(300000,100)",
253             "ncr(300000,100)*8",
254             "npr(3,2)*ncr(300000,100)",
255             "npr(100,90)",
256             "npr(30,25)",
257     };
258 
259     int i;
260     for (i = 0; i < sizeof(infs) / sizeof(const char *); ++i) {
261         const char *expr = infs[i];
262 
263         int err;
264         const double r = te_interp(expr, &err);
265         lequal(err, 0);
266         lok(r == r + 1);
267 
268         te_expr *n = te_compile(expr, 0, 0, &err);
269         lok(n);
270         lequal(err, 0);
271         const double c = te_eval(n);
272         lok(c == c + 1);
273         te_free(n);
274     }
275 }
276 
277 
test_variables()278 void test_variables() {
279 
280     double x, y, test;
281     te_variable lookup[] = {{"x", &x}, {"y", &y}, {"te_st", &test}};
282 
283     int err;
284 
285     te_expr *expr1 = te_compile("cos x + sin y", lookup, 2, &err);
286     lok(expr1);
287     lok(!err);
288 
289     te_expr *expr2 = te_compile("x+x+x-y", lookup, 2, &err);
290     lok(expr2);
291     lok(!err);
292 
293     te_expr *expr3 = te_compile("x*y^3", lookup, 2, &err);
294     lok(expr3);
295     lok(!err);
296 
297     te_expr *expr4 = te_compile("te_st+5", lookup, 3, &err);
298     lok(expr4);
299     lok(!err);
300 
301     for (y = 2; y < 3; ++y) {
302         for (x = 0; x < 5; ++x) {
303             double ev;
304 
305             ev = te_eval(expr1);
306             lfequal(ev, cos(x) + sin(y));
307 
308             ev = te_eval(expr2);
309             lfequal(ev, x+x+x-y);
310 
311             ev = te_eval(expr3);
312             lfequal(ev, x*y*y*y);
313 
314             test = x;
315             ev = te_eval(expr4);
316             lfequal(ev, x+5);
317         }
318     }
319 
320     te_free(expr1);
321     te_free(expr2);
322     te_free(expr3);
323     te_free(expr4);
324 
325 
326 
327     te_expr *expr5 = te_compile("xx*y^3", lookup, 2, &err);
328     lok(!expr5);
329     lok(err);
330 
331     te_expr *expr6 = te_compile("tes", lookup, 3, &err);
332     lok(!expr6);
333     lok(err);
334 
335     te_expr *expr7 = te_compile("sinn x", lookup, 2, &err);
336     lok(!expr7);
337     lok(err);
338 
339     te_expr *expr8 = te_compile("si x", lookup, 2, &err);
340     lok(!expr8);
341     lok(err);
342 }
343 
344 
345 
346 #define cross_check(a, b) do {\
347     if ((b)!=(b)) break;\
348     expr = te_compile((a), lookup, 2, &err);\
349     lfequal(te_eval(expr), (b));\
350     lok(!err);\
351     te_free(expr);\
352 }while(0)
353 
test_functions()354 void test_functions() {
355 
356     double x, y;
357     te_variable lookup[] = {{"x", &x}, {"y", &y}};
358 
359     int err;
360     te_expr *expr;
361 
362     for (x = -5; x < 5; x += .2) {
363         cross_check("abs x", fabs(x));
364         cross_check("acos x", acos(x));
365         cross_check("asin x", asin(x));
366         cross_check("atan x", atan(x));
367         cross_check("ceil x", ceil(x));
368         cross_check("cos x", cos(x));
369         cross_check("cosh x", cosh(x));
370         cross_check("exp x", exp(x));
371         cross_check("floor x", floor(x));
372         cross_check("ln x", log(x));
373         cross_check("log10 x", log10(x));
374         cross_check("sin x", sin(x));
375         cross_check("sinh x", sinh(x));
376         cross_check("sqrt x", sqrt(x));
377         cross_check("tan x", tan(x));
378         cross_check("tanh x", tanh(x));
379 
380         for (y = -2; y < 2; y += .2) {
381             if (fabs(x) < 0.01) break;
382             cross_check("atan2(x,y)", atan2(x, y));
383             cross_check("pow(x,y)", pow(x, y));
384         }
385     }
386 }
387 
388 
sum0()389 double sum0() {
390     return 6;
391 }
sum1(double a)392 double sum1(double a) {
393     return a * 2;
394 }
sum2(double a,double b)395 double sum2(double a, double b) {
396     return a + b;
397 }
sum3(double a,double b,double c)398 double sum3(double a, double b, double c) {
399     return a + b + c;
400 }
sum4(double a,double b,double c,double d)401 double sum4(double a, double b, double c, double d) {
402     return a + b + c + d;
403 }
sum5(double a,double b,double c,double d,double e)404 double sum5(double a, double b, double c, double d, double e) {
405     return a + b + c + d + e;
406 }
sum6(double a,double b,double c,double d,double e,double f)407 double sum6(double a, double b, double c, double d, double e, double f) {
408     return a + b + c + d + e + f;
409 }
sum7(double a,double b,double c,double d,double e,double f,double g)410 double sum7(double a, double b, double c, double d, double e, double f, double g) {
411     return a + b + c + d + e + f + g;
412 }
413 
414 
test_dynamic()415 void test_dynamic() {
416 
417     double x, f;
418     te_variable lookup[] = {
419         {"x", &x},
420         {"f", &f},
421         {"sum0", sum0, TE_FUNCTION0},
422         {"sum1", sum1, TE_FUNCTION1},
423         {"sum2", sum2, TE_FUNCTION2},
424         {"sum3", sum3, TE_FUNCTION3},
425         {"sum4", sum4, TE_FUNCTION4},
426         {"sum5", sum5, TE_FUNCTION5},
427         {"sum6", sum6, TE_FUNCTION6},
428         {"sum7", sum7, TE_FUNCTION7},
429     };
430 
431     test_case cases[] = {
432         {"x", 2},
433         {"f+x", 7},
434         {"x+x", 4},
435         {"x+f", 7},
436         {"f+f", 10},
437         {"f+sum0", 11},
438         {"sum0+sum0", 12},
439         {"sum0()+sum0", 12},
440         {"sum0+sum0()", 12},
441         {"sum0()+(0)+sum0()", 12},
442         {"sum1 sum0", 12},
443         {"sum1(sum0)", 12},
444         {"sum1 f", 10},
445         {"sum1 x", 4},
446         {"sum2 (sum0, x)", 8},
447         {"sum3 (sum0, x, 2)", 10},
448         {"sum2(2,3)", 5},
449         {"sum3(2,3,4)", 9},
450         {"sum4(2,3,4,5)", 14},
451         {"sum5(2,3,4,5,6)", 20},
452         {"sum6(2,3,4,5,6,7)", 27},
453         {"sum7(2,3,4,5,6,7,8)", 35},
454     };
455 
456     x = 2;
457     f = 5;
458 
459     int i;
460     for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
461         const char *expr = cases[i].expr;
462         const double answer = cases[i].answer;
463 
464         int err;
465         te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err);
466         lok(ex);
467         lfequal(te_eval(ex), answer);
468         te_free(ex);
469     }
470 }
471 
472 
clo0(void * context)473 double clo0(void *context) {
474     if (context) return *((double*)context) + 6;
475     return 6;
476 }
clo1(void * context,double a)477 double clo1(void *context, double a) {
478     if (context) return *((double*)context) + a * 2;
479     return a * 2;
480 }
clo2(void * context,double a,double b)481 double clo2(void *context, double a, double b) {
482     if (context) return *((double*)context) + a + b;
483     return a + b;
484 }
485 
cell(void * context,double a)486 double cell(void *context, double a) {
487     double *c = context;
488     return c[(int)a];
489 }
490 
test_closure()491 void test_closure() {
492 
493     double extra;
494     double c[] = {5,6,7,8,9};
495 
496     te_variable lookup[] = {
497         {"c0", clo0, TE_CLOSURE0, &extra},
498         {"c1", clo1, TE_CLOSURE1, &extra},
499         {"c2", clo2, TE_CLOSURE2, &extra},
500         {"cell", cell, TE_CLOSURE1, c},
501     };
502 
503     test_case cases[] = {
504         {"c0", 6},
505         {"c1 4", 8},
506         {"c2 (10, 20)", 30},
507     };
508 
509     int i;
510     for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
511         const char *expr = cases[i].expr;
512         const double answer = cases[i].answer;
513 
514         int err;
515         te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err);
516         lok(ex);
517 
518         extra = 0;
519         lfequal(te_eval(ex), answer + extra);
520 
521         extra = 10;
522         lfequal(te_eval(ex), answer + extra);
523 
524         te_free(ex);
525     }
526 
527 
528     test_case cases2[] = {
529         {"cell 0", 5},
530         {"cell 1", 6},
531         {"cell 0 + cell 1", 11},
532         {"cell 1 * cell 3 + cell 4", 57},
533     };
534 
535     for (i = 0; i < sizeof(cases2) / sizeof(test_case); ++i) {
536         const char *expr = cases2[i].expr;
537         const double answer = cases2[i].answer;
538 
539         int err;
540         te_expr *ex = te_compile(expr, lookup, sizeof(lookup)/sizeof(te_variable), &err);
541         lok(ex);
542         lfequal(te_eval(ex), answer);
543         te_free(ex);
544     }
545 }
546 
test_optimize()547 void test_optimize() {
548 
549     test_case cases[] = {
550         {"5+5", 10},
551         {"pow(2,2)", 4},
552         {"sqrt 100", 10},
553         {"pi * 2", 6.2832},
554     };
555 
556     int i;
557     for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
558         const char *expr = cases[i].expr;
559         const double answer = cases[i].answer;
560 
561         int err;
562         te_expr *ex = te_compile(expr, 0, 0, &err);
563         lok(ex);
564 
565         /* The answer should be know without
566          * even running eval. */
567         lfequal(ex->value, answer);
568         lfequal(te_eval(ex), answer);
569 
570         te_free(ex);
571     }
572 }
573 
test_pow()574 void test_pow() {
575 #ifdef TE_POW_FROM_RIGHT
576     test_equ cases[] = {
577         {"2^3^4", "2^(3^4)"},
578         {"-2^2", "-(2^2)"},
579         {"--2^2", "(2^2)"},
580         {"---2^2", "-(2^2)"},
581         {"-(2)^2", "-(2^2)"},
582         {"-(2*1)^2", "-(2^2)"},
583         {"-2^2", "-4"},
584         {"2^1.1^1.2^1.3", "2^(1.1^(1.2^1.3))"},
585         {"-a^b", "-(a^b)"},
586         {"-a^-b", "-(a^-b)"}
587     };
588 #else
589     test_equ cases[] = {
590         {"2^3^4", "(2^3)^4"},
591         {"-2^2", "(-2)^2"},
592         {"--2^2", "2^2"},
593         {"---2^2", "(-2)^2"},
594         {"-2^2", "4"},
595         {"2^1.1^1.2^1.3", "((2^1.1)^1.2)^1.3"},
596         {"-a^b", "(-a)^b"},
597         {"-a^-b", "(-a)^(-b)"}
598     };
599 #endif
600 
601     double a = 2, b = 3;
602 
603     te_variable lookup[] = {
604         {"a", &a},
605         {"b", &b}
606     };
607 
608     int i;
609     for (i = 0; i < sizeof(cases) / sizeof(test_equ); ++i) {
610         const char *expr1 = cases[i].expr1;
611         const char *expr2 = cases[i].expr2;
612 
613         te_expr *ex1 = te_compile(expr1, lookup, sizeof(lookup)/sizeof(te_variable), 0);
614         te_expr *ex2 = te_compile(expr2, lookup, sizeof(lookup)/sizeof(te_variable), 0);
615 
616         lok(ex1);
617         lok(ex2);
618 
619         double r1 = te_eval(ex1);
620         double r2 = te_eval(ex2);
621 
622         fflush(stdout);
623         lfequal(r1, r2);
624 
625         te_free(ex1);
626         te_free(ex2);
627     }
628 
629 }
630 
test_combinatorics()631 void test_combinatorics() {
632     test_case cases[] = {
633             {"fac(0)", 1},
634             {"fac(0.2)", 1},
635             {"fac(1)", 1},
636             {"fac(2)", 2},
637             {"fac(3)", 6},
638             {"fac(4.8)", 24},
639             {"fac(10)", 3628800},
640 
641             {"ncr(0,0)", 1},
642             {"ncr(10,1)", 10},
643             {"ncr(10,0)", 1},
644             {"ncr(10,10)", 1},
645             {"ncr(16,7)", 11440},
646             {"ncr(16,9)", 11440},
647             {"ncr(100,95)", 75287520},
648 
649             {"npr(0,0)", 1},
650             {"npr(10,1)", 10},
651             {"npr(10,0)", 1},
652             {"npr(10,10)", 3628800},
653             {"npr(20,5)", 1860480},
654             {"npr(100,4)", 94109400},
655     };
656 
657 
658     int i;
659     for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
660         const char *expr = cases[i].expr;
661         const double answer = cases[i].answer;
662 
663         int err;
664         const double ev = te_interp(expr, &err);
665         lok(!err);
666         lfequal(ev, answer);
667 
668         if (err) {
669             printf("FAILED: %s (%d)\n", expr, err);
670         }
671     }
672 }
673 
674 
main(int argc,char * argv[])675 int main(int argc, char *argv[])
676 {
677     lrun("Results", test_results);
678     lrun("Syntax", test_syntax);
679     lrun("NaNs", test_nans);
680     lrun("INFs", test_infs);
681     lrun("Variables", test_variables);
682     lrun("Functions", test_functions);
683     lrun("Dynamic", test_dynamic);
684     lrun("Closure", test_closure);
685     lrun("Optimize", test_optimize);
686     lrun("Pow", test_pow);
687     lrun("Combinatorics", test_combinatorics);
688     lresults();
689 
690     return lfails != 0;
691 }
692