From af6c47ef2835e6e258a000a4cbe40e6a1dbc5bd6 Mon Sep 17 00:00:00 2001 From: Lewis Van Winkle Date: Mon, 22 Aug 2016 21:20:28 -0500 Subject: [PATCH] Added option TE_POW_FROM_RIGHT --- test.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ tinyexpr.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/test.c b/test.c index 59941f0..21d270f 100644 --- a/test.c +++ b/test.c @@ -32,6 +32,10 @@ typedef struct { double answer; } test_case; +typedef struct { + const char *expr1; + const char *expr2; +} test_equ; @@ -517,6 +521,52 @@ void test_optimize() { } } +void test_pow() { +#ifdef TE_POW_FROM_RIGHT + test_equ cases[] = { + {"2^3^4", "2^(3^4)"}, + {"2^1.1^1.2^1.3", "2^(1.1^(1.2^1.3))"}, + {"-a^b", "-(a^b)"}, + {"-a^-b", "-(a^-b)"} + }; +#else + test_equ cases[] = { + {"2^3^4", "(2^3)^4"}, + {"2^1.1^1.2^1.3", "((2^1.1)^1.2)^1.3"}, + {"-a^b", "(-a)^b"}, + {"-a^-b", "(-a)^(-b)"} + }; +#endif + + double a = 2, b = 3; + + te_variable lookup[] = { + {"a", &a}, + {"b", &b} + }; + + int i; + for (i = 0; i < sizeof(cases) / sizeof(test_equ); ++i) { + const char *expr1 = cases[i].expr1; + const char *expr2 = cases[i].expr2; + + te_expr *ex1 = te_compile(expr1, lookup, sizeof(lookup)/sizeof(te_variable), 0); + te_expr *ex2 = te_compile(expr2, lookup, sizeof(lookup)/sizeof(te_variable), 0); + + lok(ex1); + lok(ex2); + + double r1 = te_eval(ex1); + double r2 = te_eval(ex2); + + fflush(stdout); + lfequal(r1, r2); + + te_free(ex1); + te_free(ex2); + } + +} int main(int argc, char *argv[]) { @@ -528,6 +578,7 @@ int main(int argc, char *argv[]) lrun("Dynamic", test_dynamic); lrun("Closure", test_closure); lrun("Optimize", test_optimize); + lrun("Pow", test_pow); lresults(); return lfails != 0; diff --git a/tinyexpr.c b/tinyexpr.c index 0246580..9021cab 100644 --- a/tinyexpr.c +++ b/tinyexpr.c @@ -22,6 +22,14 @@ * 3. This notice may not be removed or altered from any source distribution. */ +/* COMPILE TIME OPTIONS */ + +/* Exponentiation associativity: +For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing. +For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/ +/* #define TE_POW_FROM_RIGHT */ + + #include "tinyexpr.h" #include #include @@ -357,7 +365,48 @@ static te_expr *power(state *s) { return ret; } +#ifdef TE_POW_FROM_RIGHT +static te_expr *factor(state *s) { + /* = {"^" } */ + te_expr *ret = power(s); + int neg = 0; + te_expr *insertion = 0; + + if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) { + te_expr *se = ret->parameters[0]; + if (se->type != TE_CONSTANT) { + free(ret); + ret = se; + neg = 1; + } + } + + while (s->type == TOK_INFIX && (s->function == pow)) { + te_fun2 t = s->function; + next_token(s); + + if (insertion) { + /* Make exponentiation go right-to-left. */ + te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s)); + insert->function = t; + insertion->parameters[1] = insert; + insertion = insert; + } else { + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); + ret->function = t; + insertion = ret; + } + } + + if (neg) { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); + ret->function = negate; + } + + return ret; +} +#else static te_expr *factor(state *s) { /* = {"^" } */ te_expr *ret = power(s); @@ -371,6 +420,8 @@ static te_expr *factor(state *s) { return ret; } +#endif + static te_expr *term(state *s) {