From c62727052fa4adf6814943fb7472c5527dbed450 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Sun, 16 Apr 2017 23:53:24 +0200 Subject: [PATCH 01/10] Add CMake build system support --- CMakeLists.txt | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5294ff5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,53 @@ +cmake_minimum_required(VERSION 2.8.4) + +project(tinyexpr) + +option(build_tinyexpr_test "Build TinyExpr tests." OFF) +option(build_tinyexpr_test_pr "Build TinyExpr tests PR." OFF) +option(build_tinyexpr_bench "Build TinyExpr benchmark." OFF) +option(build_tinyexpr_example "Build TinyExpr example." OFF) +option(build_tinyexpr_example2 "Build TinyExpr example 2." OFF) +option(build_tinyexpr_example3 "Build TinyExpr example 3." OFF) + +find_library(MATH_LIB m) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi -Wall -Wshadow -O2") + +set(SOURCE_FILES + tinyexpr.c + tinyexpr.h + ) + +add_library(tinyexpr STATIC ${SOURCE_FILES}) +target_link_libraries(tinyexpr ${MATH_LIB}) + +if (build_tinyexpr_test) + add_executable(tinyexpr_test test.c) + target_link_libraries(tinyexpr_test tinyexpr) +endif() + +if (build_tinyexpr_test_pr) + add_definitions(-DTE_POW_FROM_RIGHT -DTE_NAT_LOG) + add_executable(tinyexpr_test_pr test.c) + target_link_libraries(tinyexpr_test_pr tinyexpr) +endif() + +if (build_tinyexpr_bench) + add_executable(tinyexpr_benchmark benchmark.c) + target_link_libraries(tinyexpr_benchmark tinyexpr) +endif() + +if (build_tinyexpr_example) + add_executable(tinyexpr_example example.c) + target_link_libraries(tinyexpr_example tinyexpr) +endif() + +if (build_tinyexpr_example2) + add_executable(tinyexpr_example2 example2.c) + target_link_libraries(tinyexpr_example2 tinyexpr) +endif() + +if (build_tinyexpr_example3) + add_executable(tinyexpr_example3 example3.c) + target_link_libraries(tinyexpr_example3 tinyexpr) +endif() From c95c36b83c8d746f57c3f88a18fe54b1b67a5fa7 Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Wed, 19 Apr 2017 18:22:49 +0200 Subject: [PATCH 02/10] Tweak build --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5294ff5..47cbbd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ option(build_tinyexpr_example3 "Build TinyExpr example 3." OFF) find_library(MATH_LIB m) -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi -Wall -Wshadow -O2") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ansi -Wall -Wshadow -fPIC -O3") set(SOURCE_FILES tinyexpr.c From da52ce22b4b265752f37f6e95d85908a90327187 Mon Sep 17 00:00:00 2001 From: cschreib Date: Wed, 14 Jun 2017 16:33:31 +0200 Subject: [PATCH 03/10] Fixed tests not built with the right preprocessos options --- CMakeLists.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47cbbd4..dc651a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,32 +22,32 @@ add_library(tinyexpr STATIC ${SOURCE_FILES}) target_link_libraries(tinyexpr ${MATH_LIB}) if (build_tinyexpr_test) - add_executable(tinyexpr_test test.c) - target_link_libraries(tinyexpr_test tinyexpr) + add_executable(tinyexpr_test test.c tinyexpr.c) + target_link_libraries(tinyexpr_test ${MATH_LIB}) endif() if (build_tinyexpr_test_pr) - add_definitions(-DTE_POW_FROM_RIGHT -DTE_NAT_LOG) - add_executable(tinyexpr_test_pr test.c) - target_link_libraries(tinyexpr_test_pr tinyexpr) + add_executable(tinyexpr_test_pr test.c tinyexpr.c) + target_compile_definitions(tinyexpr_test_pr PRIVATE TE_POW_FROM_RIGHT TE_NAT_LOG) + target_link_libraries(tinyexpr_test_pr ${MATH_LIB}) endif() if (build_tinyexpr_bench) - add_executable(tinyexpr_benchmark benchmark.c) - target_link_libraries(tinyexpr_benchmark tinyexpr) + add_executable(tinyexpr_benchmark benchmark.c tinyexpr.c) + target_link_libraries(tinyexpr_benchmark ${MATH_LIB}) endif() if (build_tinyexpr_example) - add_executable(tinyexpr_example example.c) - target_link_libraries(tinyexpr_example tinyexpr) + add_executable(tinyexpr_example example.c tinyexpr.c) + target_link_libraries(tinyexpr_example ${MATH_LIB}) endif() if (build_tinyexpr_example2) - add_executable(tinyexpr_example2 example2.c) - target_link_libraries(tinyexpr_example2 tinyexpr) + add_executable(tinyexpr_example2 example2.c tinyexpr.c) + target_link_libraries(tinyexpr_example2 ${MATH_LIB}) endif() if (build_tinyexpr_example3) - add_executable(tinyexpr_example3 example3.c) - target_link_libraries(tinyexpr_example3 tinyexpr) + add_executable(tinyexpr_example3 example3.c tinyexpr.c) + target_link_libraries(tinyexpr_example3 ${MATH_LIB}) endif() From 57cd1fd4ac522805f54da4a059d3faebde9f5141 Mon Sep 17 00:00:00 2001 From: cschreib Date: Wed, 14 Jun 2017 16:34:01 +0200 Subject: [PATCH 04/10] Added missing install target --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dc651a3..8f270af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ set(SOURCE_FILES add_library(tinyexpr STATIC ${SOURCE_FILES}) target_link_libraries(tinyexpr ${MATH_LIB}) +install(TARGETS tinyexpr ARCHIVE DESTINATION lib) if (build_tinyexpr_test) add_executable(tinyexpr_test test.c tinyexpr.c) From a0fe4fa915653f1c89c5a0e4d0ac5a698944ea17 Mon Sep 17 00:00:00 2001 From: cschreib Date: Wed, 14 Jun 2017 16:34:34 +0200 Subject: [PATCH 05/10] Allow customizing library options TE_NAT_LOG and TE_POW_FROM_RIGHT --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f270af..fbce6c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,12 @@ set(SOURCE_FILES ) add_library(tinyexpr STATIC ${SOURCE_FILES}) +if (TE_POW_FROM_RIGHT) + target_compile_definitions(tinyexpr PRIVATE TE_POW_FROM_RIGHT) +endif() +if (TE_NAT_LOG) + target_compile_definitions(tinyexpr PRIVATE TE_NAT_LOG) +endif() target_link_libraries(tinyexpr ${MATH_LIB}) install(TARGETS tinyexpr ARCHIVE DESTINATION lib) From 2f664da4de10622b7fcbe24502464ada636d4888 Mon Sep 17 00:00:00 2001 From: cschreib Date: Wed, 14 Jun 2017 16:37:51 +0200 Subject: [PATCH 06/10] Added GUI options for library compilation options --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fbce6c8..902f126 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.8.4) project(tinyexpr) +option(TE_POW_FROM_RIGHT "Evaluate exponents from right to left." OFF) +option(TE_NAT_LOG "Define the log function as natural logarithm." OFF) option(build_tinyexpr_test "Build TinyExpr tests." OFF) option(build_tinyexpr_test_pr "Build TinyExpr tests PR." OFF) option(build_tinyexpr_bench "Build TinyExpr benchmark." OFF) From aecac82263fe87678f7d8bde7efa7e6832cb1639 Mon Sep 17 00:00:00 2001 From: cschreib Date: Wed, 14 Jun 2017 16:52:52 +0200 Subject: [PATCH 07/10] Added missing install target for include file --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 902f126..3d37e57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ if (TE_NAT_LOG) endif() target_link_libraries(tinyexpr ${MATH_LIB}) install(TARGETS tinyexpr ARCHIVE DESTINATION lib) +install(FILES tinyexpr.h DESTINATION include COMPONENT Devel) if (build_tinyexpr_test) add_executable(tinyexpr_test test.c tinyexpr.c) From c1b01d879ea5bb7d14a6529988327bb407641a9b Mon Sep 17 00:00:00 2001 From: cschreib Date: Fri, 30 Jun 2017 12:06:47 +0200 Subject: [PATCH 08/10] Added comparison and logical operators --- test.c | 64 +++++++++++++++++++++++++++++++++++ tinyexpr.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 155 insertions(+), 6 deletions(-) diff --git a/test.c b/test.c index c772950..a7f07f4 100644 --- a/test.c +++ b/test.c @@ -672,6 +672,69 @@ void test_combinatorics() { } +void test_logic() { + test_case cases[] = { + {"1 && 1", 1}, + {"1 && 0", 0}, + {"0 && 1", 0}, + {"0 && 0", 0}, + {"1 || 1", 1}, + {"1 || 0", 1}, + {"0 || 1", 1}, + {"0 || 0", 0}, + {"!0", 1}, + {"!1", 0}, + + {"1 < 2", 1}, + {"2 < 2", 0}, + {"2 <= 2", 1}, + {"2 > 1", 1}, + {"2 > 2", 0}, + {"2 >= 2", 1}, + {"2 > -2", 1}, + {"-2 < 2", 1}, + + {"1 < 2 && 2 < 3", 1}, + {"1 < 2 && 3 < 2", 0}, + {"2 < 1 && 2 < 3", 0}, + {"2 < 1 && 3 < 2", 0}, + {"1 < 2 || 2 < 3", 1}, + {"1 < 2 || 3 < 2", 1}, + {"2 < 1 || 2 < 3", 1}, + {"2 < 1 || 3 < 2", 0}, + + {"1 < 1+1", 1}, + {"1 < 1*2", 1}, + {"1 < 2/2", 0}, + {"1 < 2^2", 1}, + + {"5+5 < 4+10", 1}, + {"5+(5 < 4)+10", 15}, + {"5+(5 < 4+10)", 6}, + {"(5+5 < 4)+10", 10}, + {"5+!(5 < 4)+10", 16}, + {"5+!(5 < 4+10)", 5}, + {"!(5+5 < 4)+10", 11}, + }; + + + int i; + for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) { + const char *expr = cases[i].expr; + const double answer = cases[i].answer; + + int err; + const double ev = te_interp(expr, &err); + lok(!err); + lfequal(ev, answer); + + if (err) { + printf("FAILED: %s (%d)\n", expr, err); + } + } +} + + int main(int argc, char *argv[]) { lrun("Results", test_results); @@ -685,6 +748,7 @@ int main(int argc, char *argv[]) lrun("Optimize", test_optimize); lrun("Pow", test_pow); lrun("Combinatorics", test_combinatorics); + lrun("Logic", test_logic); lresults(); return lfails != 0; diff --git a/tinyexpr.c b/tinyexpr.c index 91a1848..44def87 100755 --- a/tinyexpr.c +++ b/tinyexpr.c @@ -225,6 +225,14 @@ static double divide(double a, double b) {return a / b;} static double negate(double a) {return -a;} static double comma(double a, double b) {(void)a; return b;} +static double greater(double a, double b) {return a > b;} +static double greater_eq(double a, double b) {return a >= b;} +static double lower(double a, double b) {return a < b;} +static double lower_eq(double a, double b) {return a <= b;} +static double logical_and(double a, double b) {return (int)(a + 0.5) == 1 && (int)(b + 0.5) == 1;} +static double logical_or(double a, double b) {return (int)(a + 0.5) == 1 || (int)(b + 0.5) == 1;} +static double logical_not(double a) {return (int)(a + 0.5) == 0;} + void next_token(state *s) { s->type = TOK_NULL; @@ -281,6 +289,37 @@ void next_token(state *s) { case '/': s->type = TOK_INFIX; s->function = divide; break; case '^': s->type = TOK_INFIX; s->function = pow; break; case '%': s->type = TOK_INFIX; s->function = fmod; break; + case '!': s->type = TOK_INFIX; s->function = logical_not; break; + case '<': + if (s->next++[0] == '=') { + s->type = TOK_INFIX; s->function = lower_eq; + } else { + s->next--; + s->type = TOK_INFIX; s->function = lower; + } + break; + case '>': + if (s->next++[0] == '=') { + s->type = TOK_INFIX; s->function = greater_eq; + } else { + s->next--; + s->type = TOK_INFIX; s->function = greater; + } + break; + case '&': + if (s->next++[0] == '&') { + s->type = TOK_INFIX; s->function = logical_and; + } else { + s->type = TOK_ERROR; + } + break; + case '|': + if (s->next++[0] == '|') { + s->type = TOK_INFIX; s->function = logical_or; + } else { + s->type = TOK_ERROR; + } + break; case '(': s->type = TOK_OPEN; break; case ')': s->type = TOK_CLOSE; break; case ',': s->type = TOK_SEP; break; @@ -393,16 +432,21 @@ static te_expr *base(state *s) { static te_expr *power(state *s) { - /* = {("-" | "+")} */ + /* = {("-" | "+" | "!")} */ int sign = 1; - while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) { + int logical = 0; + while (s->type == TOK_INFIX && (s->function == add || s->function == sub || s->function == logical_not)) { if (s->function == sub) sign = -sign; + if (s->function == logical_not) logical = 1; next_token(s); } te_expr *ret; - if (sign == 1) { + if (logical) { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); + ret->function = logical_not; + } else if (sign == 1) { ret = base(s); } else { ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); @@ -418,13 +462,19 @@ static te_expr *factor(state *s) { te_expr *ret = power(s); int neg = 0; + int lnot = 0; te_expr *insertion = 0; - if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) { + if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE)) { te_expr *se = ret->parameters[0]; free(ret); ret = se; - neg = 1; + + if (ret->function == negate) { + neg = 1; + } else if (ret->function == logical_not) { + lnot = 1; + } } while (s->type == TOK_INFIX && (s->function == pow)) { @@ -448,6 +498,10 @@ static te_expr *factor(state *s) { ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); ret->function = negate; } + if (lnot) { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); + ret->function = logical_not; + } return ret; } @@ -484,7 +538,7 @@ static te_expr *term(state *s) { } -static te_expr *expr(state *s) { +static te_expr *sum_expr(state *s) { /* = {("+" | "-") } */ te_expr *ret = term(s); @@ -499,6 +553,37 @@ static te_expr *expr(state *s) { } +static te_expr *test_expr(state *s) { + /* = {(">" | ">=" | "<" | "<=") } */ + te_expr *ret = sum_expr(s); + + while (s->type == TOK_INFIX && (s->function == greater || s->function == greater_eq || + s->function == lower || s->function == lower_eq)) { + te_fun2 t = s->function; + next_token(s); + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, sum_expr(s)); + ret->function = t; + } + + return ret; +} + + +static te_expr *expr(state *s) { + /* = {("&&" | "||") } */ + te_expr *ret = test_expr(s); + + while (s->type == TOK_INFIX && (s->function == logical_and || s->function == logical_or)) { + te_fun2 t = s->function; + next_token(s); + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, test_expr(s)); + ret->function = t; + } + + return ret; +} + + static te_expr *list(state *s) { /* = {"," } */ te_expr *ret = expr(s); From 4cdeb9150e3579349d4513795dfadd41a7dcb45a Mon Sep 17 00:00:00 2001 From: cschreib Date: Fri, 30 Jun 2017 13:35:49 +0200 Subject: [PATCH 09/10] Added equality tests --- test.c | 9 +++++++++ tinyexpr.c | 28 ++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/test.c b/test.c index a7f07f4..5535645 100644 --- a/test.c +++ b/test.c @@ -694,6 +694,15 @@ void test_logic() { {"2 > -2", 1}, {"-2 < 2", 1}, + {"0 == 0", 1}, + {"0 != 0", 0}, + {"2 == 2", 1}, + {"2 != 2", 0}, + {"2 == 3", 0}, + {"2 != 3", 1}, + {"2 == 2.0001", 0}, + {"2 != 2.0001", 1}, + {"1 < 2 && 2 < 3", 1}, {"1 < 2 && 3 < 2", 0}, {"2 < 1 && 2 < 3", 0}, diff --git a/tinyexpr.c b/tinyexpr.c index 44def87..21215a6 100755 --- a/tinyexpr.c +++ b/tinyexpr.c @@ -229,9 +229,11 @@ static double greater(double a, double b) {return a > b;} static double greater_eq(double a, double b) {return a >= b;} static double lower(double a, double b) {return a < b;} static double lower_eq(double a, double b) {return a <= b;} -static double logical_and(double a, double b) {return (int)(a + 0.5) == 1 && (int)(b + 0.5) == 1;} -static double logical_or(double a, double b) {return (int)(a + 0.5) == 1 || (int)(b + 0.5) == 1;} -static double logical_not(double a) {return (int)(a + 0.5) == 0;} +static double equal(double a, double b) {return a == b;} +static double not_equal(double a, double b) {return a != b;} +static double logical_and(double a, double b) {return (int)a != 0 && (int)b != 0;} +static double logical_or(double a, double b) {return (int)a != 0 || (int)b != 0;} +static double logical_not(double a) {return (int)a == 0;} void next_token(state *s) { @@ -289,7 +291,21 @@ void next_token(state *s) { case '/': s->type = TOK_INFIX; s->function = divide; break; case '^': s->type = TOK_INFIX; s->function = pow; break; case '%': s->type = TOK_INFIX; s->function = fmod; break; - case '!': s->type = TOK_INFIX; s->function = logical_not; break; + case '!': + if (s->next++[0] == '=') { + s->type = TOK_INFIX; s->function = not_equal; + } else { + s->next--; + s->type = TOK_INFIX; s->function = logical_not; + } + break; + case '=': + if (s->next++[0] == '=') { + s->type = TOK_INFIX; s->function = equal; + } else { + s->type = TOK_ERROR; + } + break; case '<': if (s->next++[0] == '=') { s->type = TOK_INFIX; s->function = lower_eq; @@ -554,11 +570,11 @@ static te_expr *sum_expr(state *s) { static te_expr *test_expr(state *s) { - /* = {(">" | ">=" | "<" | "<=") } */ + /* = {(">" | ">=" | "<" | "<=" | "==" | "!=") } */ te_expr *ret = sum_expr(s); while (s->type == TOK_INFIX && (s->function == greater || s->function == greater_eq || - s->function == lower || s->function == lower_eq)) { + s->function == lower || s->function == lower_eq || s->function == equal || s->function == not_equal)) { te_fun2 t = s->function; next_token(s); ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, sum_expr(s)); From 9de3ed238a2a2d4e669b50b1f6dc159b15e0e951 Mon Sep 17 00:00:00 2001 From: cschreib Date: Sat, 1 Jul 2017 18:36:19 +0200 Subject: [PATCH 10/10] Fixed right-to-left interpreter and repeated unary operators --- test.c | 22 +++++++++++++++++ tinyexpr.c | 72 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 67 insertions(+), 27 deletions(-) diff --git a/test.c b/test.c index 5535645..a44628d 100644 --- a/test.c +++ b/test.c @@ -684,6 +684,17 @@ void test_logic() { {"0 || 0", 0}, {"!0", 1}, {"!1", 0}, + {"!2", 0}, + + {"!-2", 0}, + {"-!2", 0}, + {"!!0", 0}, + {"!!1", 1}, + {"!!2", 1}, + {"!!-2", 1}, + {"!-!2", 1}, + {"-!!2", -1}, + {"--!!2", 1}, {"1 < 2", 1}, {"2 < 2", 0}, @@ -724,6 +735,17 @@ void test_logic() { {"5+!(5 < 4)+10", 16}, {"5+!(5 < 4+10)", 5}, {"!(5+5 < 4)+10", 11}, + +#ifdef TE_POW_FROM_RIGHT + {"!0^2", 1}, + {"!0^-1", 0}, + {"-!0^2", -1}, +#else + {"!0^2", 1}, + {"!0^-1", 1}, + {"-!0^2", 1}, +#endif + }; diff --git a/tinyexpr.c b/tinyexpr.c index 21215a6..f61869c 100755 --- a/tinyexpr.c +++ b/tinyexpr.c @@ -231,9 +231,12 @@ static double lower(double a, double b) {return a < b;} static double lower_eq(double a, double b) {return a <= b;} static double equal(double a, double b) {return a == b;} static double not_equal(double a, double b) {return a != b;} -static double logical_and(double a, double b) {return (int)a != 0 && (int)b != 0;} -static double logical_or(double a, double b) {return (int)a != 0 || (int)b != 0;} -static double logical_not(double a) {return (int)a == 0;} +static double logical_and(double a, double b) {return a != 0.0 && b != 0.0;} +static double logical_or(double a, double b) {return a != 0.0 || b != 0.0;} +static double logical_not(double a) {return a == 0.0;} +static double logical_notnot(double a) {return a != 0.0;} +static double negate_logical_not(double a) {return -(a == 0.0);} +static double negate_logical_notnot(double a) {return -(a != 0.0);} void next_token(state *s) { @@ -450,23 +453,46 @@ static te_expr *base(state *s) { static te_expr *power(state *s) { /* = {("-" | "+" | "!")} */ int sign = 1; + while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) { + if (s->function == sub) sign = -sign; + next_token(s); + } + int logical = 0; while (s->type == TOK_INFIX && (s->function == add || s->function == sub || s->function == logical_not)) { - if (s->function == sub) sign = -sign; - if (s->function == logical_not) logical = 1; + if (s->function == logical_not) { + if (logical == 0) { + logical = -1; + } else { + logical = -logical; + } + } next_token(s); } te_expr *ret; - if (logical) { - ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); - ret->function = logical_not; - } else if (sign == 1) { - ret = base(s); + if (sign == 1) { + if (logical == 0) { + ret = base(s); + } else if (logical == -1) { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); + ret->function = logical_not; + } else { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); + ret->function = logical_notnot; + } } else { - ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); - ret->function = negate; + if (logical == 0) { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); + ret->function = negate; + } else if (logical == -1) { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); + ret->function = negate_logical_not; + } else { + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); + ret->function = negate_logical_notnot; + } } return ret; @@ -477,20 +503,16 @@ static te_expr *factor(state *s) { /* = {"^" } */ te_expr *ret = power(s); - int neg = 0; - int lnot = 0; + const void *left_function = NULL; te_expr *insertion = 0; - if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE)) { + if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && + (ret->function == negate || ret->function == logical_not || ret->function == logical_notnot || + ret->function == negate_logical_not || ret->function == negate_logical_notnot)) { + left_function = ret->function; te_expr *se = ret->parameters[0]; free(ret); ret = se; - - if (ret->function == negate) { - neg = 1; - } else if (ret->function == logical_not) { - lnot = 1; - } } while (s->type == TOK_INFIX && (s->function == pow)) { @@ -510,13 +532,9 @@ static te_expr *factor(state *s) { } } - if (neg) { - ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); - ret->function = negate; - } - if (lnot) { + if (left_function) { ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); - ret->function = logical_not; + ret->function = left_function; } return ret;