mirror of
				https://github.com/eledio-devices/thirdparty-tinyexpr.git
				synced 2025-10-31 00:32:38 +01:00 
			
		
		
		
	
							
								
								
									
										63
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| 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) | ||||
| 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 -fPIC -O3") | ||||
|  | ||||
| set(SOURCE_FILES | ||||
|         tinyexpr.c | ||||
|         tinyexpr.h | ||||
|         ) | ||||
|  | ||||
| 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) | ||||
| install(FILES tinyexpr.h DESTINATION include COMPONENT Devel) | ||||
|  | ||||
| if (build_tinyexpr_test) | ||||
|     add_executable(tinyexpr_test test.c tinyexpr.c) | ||||
|     target_link_libraries(tinyexpr_test ${MATH_LIB}) | ||||
| endif() | ||||
|  | ||||
| if (build_tinyexpr_test_pr) | ||||
|     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 tinyexpr.c) | ||||
|     target_link_libraries(tinyexpr_benchmark ${MATH_LIB}) | ||||
| endif() | ||||
|  | ||||
| if (build_tinyexpr_example) | ||||
|     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 tinyexpr.c) | ||||
|     target_link_libraries(tinyexpr_example2 ${MATH_LIB}) | ||||
| endif() | ||||
|  | ||||
| if (build_tinyexpr_example3) | ||||
|     add_executable(tinyexpr_example3 example3.c tinyexpr.c) | ||||
|     target_link_libraries(tinyexpr_example3 ${MATH_LIB}) | ||||
| endif() | ||||
							
								
								
									
										95
									
								
								test.c
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								test.c
									
									
									
									
									
								
							| @@ -672,6 +672,100 @@ 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}, | ||||
|             {"!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}, | ||||
|             {"2 <= 2", 1}, | ||||
|             {"2 > 1", 1}, | ||||
|             {"2 > 2", 0}, | ||||
|             {"2 >= 2", 1}, | ||||
|             {"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}, | ||||
|             {"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}, | ||||
|  | ||||
| #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 | ||||
|  | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     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 +779,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; | ||||
|   | ||||
							
								
								
									
										133
									
								
								tinyexpr.c
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								tinyexpr.c
									
									
									
									
									
								
							| @@ -225,6 +225,19 @@ 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 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 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) { | ||||
|     s->type = TOK_NULL; | ||||
| @@ -281,6 +294,51 @@ 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 '!': | ||||
|                         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; | ||||
|                         } 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,20 +451,48 @@ static te_expr *base(state *s) { | ||||
|  | ||||
|  | ||||
| static te_expr *power(state *s) { | ||||
|     /* <power>     =    {("-" | "+")} <base> */ | ||||
|     /* <power>     =    {("-" | "+" | "!")} <base> */ | ||||
|     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 == logical_not) { | ||||
|             if (logical == 0) { | ||||
|                 logical = -1; | ||||
|             } else { | ||||
|                 logical = -logical; | ||||
|             } | ||||
|         } | ||||
|         next_token(s); | ||||
|     } | ||||
|  | ||||
|     te_expr *ret; | ||||
|  | ||||
|     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 { | ||||
|         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; | ||||
| @@ -417,14 +503,16 @@ static te_expr *factor(state *s) { | ||||
|     /* <factor>    =    <power> {"^" <power>} */ | ||||
|     te_expr *ret = power(s); | ||||
|  | ||||
|     int neg = 0; | ||||
|     const void *left_function = NULL; | ||||
|     te_expr *insertion = 0; | ||||
|  | ||||
|     if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) { | ||||
|     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; | ||||
|         neg = 1; | ||||
|     } | ||||
|  | ||||
|     while (s->type == TOK_INFIX && (s->function == pow)) { | ||||
| @@ -444,9 +532,9 @@ static te_expr *factor(state *s) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (neg) { | ||||
|     if (left_function) { | ||||
|         ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); | ||||
|         ret->function = negate; | ||||
|         ret->function = left_function; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| @@ -484,7 +572,7 @@ static te_expr *term(state *s) { | ||||
| } | ||||
|  | ||||
|  | ||||
| static te_expr *expr(state *s) { | ||||
| static te_expr *sum_expr(state *s) { | ||||
|     /* <expr>      =    <term> {("+" | "-") <term>} */ | ||||
|     te_expr *ret = term(s); | ||||
|  | ||||
| @@ -499,6 +587,37 @@ static te_expr *expr(state *s) { | ||||
| } | ||||
|  | ||||
|  | ||||
| static te_expr *test_expr(state *s) { | ||||
|     /* <expr>      =    <sum_expr> {(">" | ">=" | "<" | "<=" | "==" | "!=") <sum_expr>} */ | ||||
|     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 == 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)); | ||||
|         ret->function = t; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
|  | ||||
| static te_expr *expr(state *s) { | ||||
|     /* <expr>      =    <test_expr> {("&&" | "||") <test_expr>} */ | ||||
|     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) { | ||||
|     /* <list>      =    <expr> {"," <expr>} */ | ||||
|     te_expr *ret = expr(s); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user