mirror of
				https://github.com/eledio-devices/thirdparty-tinyexpr.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Added comparison and logical operators
This commit is contained in:
		
							
								
								
									
										64
									
								
								test.c
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								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[]) | int main(int argc, char *argv[]) | ||||||
| { | { | ||||||
|     lrun("Results", test_results); |     lrun("Results", test_results); | ||||||
| @@ -685,6 +748,7 @@ int main(int argc, char *argv[]) | |||||||
|     lrun("Optimize", test_optimize); |     lrun("Optimize", test_optimize); | ||||||
|     lrun("Pow", test_pow); |     lrun("Pow", test_pow); | ||||||
|     lrun("Combinatorics", test_combinatorics); |     lrun("Combinatorics", test_combinatorics); | ||||||
|  |     lrun("Logic", test_logic); | ||||||
|     lresults(); |     lresults(); | ||||||
|  |  | ||||||
|     return lfails != 0; |     return lfails != 0; | ||||||
|   | |||||||
							
								
								
									
										95
									
								
								tinyexpr.c
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								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 negate(double a) {return -a;} | ||||||
| static double comma(double a, double b) {(void)a; return b;} | 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) { | void next_token(state *s) { | ||||||
|     s->type = TOK_NULL; |     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 = divide; break; | ||||||
|                     case '^': s->type = TOK_INFIX; s->function = pow; 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 = 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_OPEN; break; | ||||||
|                     case ')': s->type = TOK_CLOSE; break; |                     case ')': s->type = TOK_CLOSE; break; | ||||||
|                     case ',': s->type = TOK_SEP; break; |                     case ',': s->type = TOK_SEP; break; | ||||||
| @@ -393,16 +432,21 @@ static te_expr *base(state *s) { | |||||||
|  |  | ||||||
|  |  | ||||||
| static te_expr *power(state *s) { | static te_expr *power(state *s) { | ||||||
|     /* <power>     =    {("-" | "+")} <base> */ |     /* <power>     =    {("-" | "+" | "!")} <base> */ | ||||||
|     int sign = 1; |     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 == sub) sign = -sign; | ||||||
|  |         if (s->function == logical_not) logical = 1; | ||||||
|         next_token(s); |         next_token(s); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     te_expr *ret; |     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); |         ret = base(s); | ||||||
|     } else { |     } else { | ||||||
|         ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); |         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); |     te_expr *ret = power(s); | ||||||
|  |  | ||||||
|     int neg = 0; |     int neg = 0; | ||||||
|  |     int lnot = 0; | ||||||
|     te_expr *insertion = 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]; |         te_expr *se = ret->parameters[0]; | ||||||
|         free(ret); |         free(ret); | ||||||
|         ret = se; |         ret = se; | ||||||
|  |  | ||||||
|  |         if (ret->function == negate) { | ||||||
|             neg = 1; |             neg = 1; | ||||||
|  |         } else if (ret->function == logical_not) { | ||||||
|  |             lnot = 1; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     while (s->type == TOK_INFIX && (s->function == pow)) { |     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 = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); | ||||||
|         ret->function = negate; |         ret->function = negate; | ||||||
|     } |     } | ||||||
|  |     if (lnot) { | ||||||
|  |         ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); | ||||||
|  |         ret->function = logical_not; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return ret; |     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) { | ||||||
|     /* <expr>      =    <term> {("+" | "-") <term>} */ |     /* <expr>      =    <term> {("+" | "-") <term>} */ | ||||||
|     te_expr *ret = term(s); |     te_expr *ret = term(s); | ||||||
|  |  | ||||||
| @@ -499,6 +553,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)) { | ||||||
|  |         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) { | static te_expr *list(state *s) { | ||||||
|     /* <list>      =    <expr> {"," <expr>} */ |     /* <list>      =    <expr> {"," <expr>} */ | ||||||
|     te_expr *ret = expr(s); |     te_expr *ret = expr(s); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user