mirror of
				https://github.com/eledio-devices/thirdparty-tinyexpr.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Merge pull request #3 from EvilPudding/master
Added arity greater than 2.
This commit is contained in:
		
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,5 +1,6 @@ | |||||||
| CC = gcc | CC = gcc | ||||||
| CCFLAGS = -ansi -Wall -Wshadow -O2 | CCFLAGS = -ansi -Wall -Wshadow -O2 | ||||||
|  |  | ||||||
| LFLAGS = -lm | LFLAGS = -lm | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								test.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								test.c
									
									
									
									
									
								
							| @@ -340,6 +340,10 @@ double test2(double a, double b) { | |||||||
|     return a + b; |     return a + b; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | double test3(double a, double b, double c) { | ||||||
|  |     return (a + b) / c; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void test_dynamic() { | void test_dynamic() { | ||||||
|  |  | ||||||
| @@ -347,9 +351,10 @@ void test_dynamic() { | |||||||
|     te_variable lookup[] = { |     te_variable lookup[] = { | ||||||
|         {"x", &x}, |         {"x", &x}, | ||||||
|         {"f", &f}, |         {"f", &f}, | ||||||
|         {"test0", test0, TE_FUNCTION0}, |         {"test0", test0, TE_FUN | 0}, | ||||||
|         {"test1", test1, TE_FUNCTION1}, |         {"test1", test1, TE_FUN | 1}, | ||||||
|         {"test2", test2, TE_FUNCTION2}, |         {"test2", test2, TE_FUN | 2}, | ||||||
|  |         {"test3", test3, TE_FUN | 3}, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     test_case cases[] = { |     test_case cases[] = { | ||||||
| @@ -365,6 +370,7 @@ void test_dynamic() { | |||||||
|         {"test1 f", 10}, |         {"test1 f", 10}, | ||||||
|         {"test1 x", 4}, |         {"test1 x", 4}, | ||||||
|         {"test2 (test0, x)", 8}, |         {"test2 (test0, x)", 8}, | ||||||
|  |         {"test3 (test0, x, 2)", 4}, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     x = 2; |     x = 2; | ||||||
|   | |||||||
							
								
								
									
										244
									
								
								tinyexpr.c
									
									
									
									
									
								
							
							
						
						
									
										244
									
								
								tinyexpr.c
									
									
									
									
									
								
							| @@ -29,8 +29,11 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| enum {TOK_NULL, TOK_END, TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_INFIX, TOK_FUNCTION0, TOK_FUNCTION1, TOK_FUNCTION2, TOK_VARIABLE, TOK_SEP, TOK_ERROR}; | enum {TOK_NULL, TOK_END, TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_INFIX, | ||||||
| enum {TE_CONSTANT = -2}; |     TOK_VARIABLE, TOK_SEP, TOK_ERROR, TOK_FUNCTION0, TOK_FUNCTION1, | ||||||
|  |     TOK_FUNCTION2, TOK_FUNCTION3, TOK_FUNCTION4, TOK_FUNCTION5, TOK_FUNCTION6, | ||||||
|  |     TOK_FUNCTION7 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -38,29 +41,44 @@ typedef struct state { | |||||||
|     const char *start; |     const char *start; | ||||||
|     const char *next; |     const char *next; | ||||||
|     int type; |     int type; | ||||||
|     union {double value; te_fun0 f0; te_fun1 f1; te_fun2 f2; const double *bound;}; |     union {double value; te_fun fun; const double *bound;}; | ||||||
|  |  | ||||||
|     const te_variable *lookup; |     const te_variable *lookup; | ||||||
|     int lookup_len; |     int lookup_len; | ||||||
| } state; | } state; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static int te_get_type(const int type) { | ||||||
|  |     if(type == 0) return TE_VAR; | ||||||
|  |     return type & TE_FLAG_TYPE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static te_expr *new_expr(int type, te_expr *l, te_expr *r) { | static int te_get_arity(const int type) { | ||||||
|     te_expr *ret = malloc(sizeof(te_expr)); |     return type & TE_MASK_ARIT; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static te_expr *new_expr(const int type, const te_expr *members[]) { | ||||||
|  |     int member_count = te_get_arity(type); | ||||||
|  |     size_t member_size = sizeof(te_expr*) * member_count; | ||||||
|  |     te_expr *ret = malloc(sizeof(te_expr) + member_size); | ||||||
|  |     ret->member_count = member_count; | ||||||
|  |     if(!members) { | ||||||
|  |         memset(ret->members, 0, member_size); | ||||||
|  |     } else { | ||||||
|  |         memcpy(ret->members, members, member_size); | ||||||
|  |     } | ||||||
|     ret->type = type; |     ret->type = type; | ||||||
|     ret->left = l; |  | ||||||
|     ret->right = r; |  | ||||||
|     ret->bound = 0; |     ret->bound = 0; | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| void te_free(te_expr *n) { | void te_free(te_expr *n) { | ||||||
|  |     int i; | ||||||
|     if (!n) return; |     if (!n) return; | ||||||
|     if (n->left) te_free(n->left); |     for(i = n->member_count - 1; i >= 0; i--) te_free(n->members[i]); | ||||||
|     if (n->right) te_free(n->right); |  | ||||||
|     free(n); |     free(n); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -70,30 +88,29 @@ static const double e  = 2.71828182845904523536; | |||||||
|  |  | ||||||
| static const te_variable functions[] = { | static const te_variable functions[] = { | ||||||
|     /* must be in alphabetical order */ |     /* must be in alphabetical order */ | ||||||
|     {"abs", fabs, TE_FUNCTION1}, |     {"abs", fabs,     TE_FUN | 1}, | ||||||
|     {"acos", acos, TE_FUNCTION1}, |     {"acos", acos,    TE_FUN | 1}, | ||||||
|     {"asin", asin, TE_FUNCTION1}, |     {"asin", asin,    TE_FUN | 1}, | ||||||
|     {"atan", atan, TE_FUNCTION1}, |     {"atan", atan,    TE_FUN | 1}, | ||||||
|     {"atan2", atan2, TE_FUNCTION2}, |     {"atan2", atan2,  TE_FUN | 2}, | ||||||
|     {"ceil", ceil, TE_FUNCTION1}, |     {"ceil", ceil,    TE_FUN | 1}, | ||||||
|     {"cos", cos, TE_FUNCTION1}, |     {"cos", cos,      TE_FUN | 1}, | ||||||
|     {"cosh", cosh, TE_FUNCTION1}, |     {"cosh", cosh,    TE_FUN | 1}, | ||||||
|     {"e", &e, TE_VARIABLE}, |     {"e", &e,         TE_VAR}, | ||||||
|     {"exp", exp, TE_FUNCTION1}, |     {"exp", exp,      TE_FUN | 1}, | ||||||
|     {"floor", floor, TE_FUNCTION1}, |     {"floor", floor,  TE_FUN | 1}, | ||||||
|     {"ln", log, TE_FUNCTION1}, |     {"ln", log,       TE_FUN | 1}, | ||||||
|     {"log", log10, TE_FUNCTION1}, |     {"log", log10,    TE_FUN | 1}, | ||||||
|     {"pi", &pi, TE_VARIABLE}, |     {"pi", &pi,       TE_VAR}, | ||||||
|     {"pow", pow, TE_FUNCTION2}, |     {"pow", pow,      TE_FUN | 2}, | ||||||
|     {"sin", sin, TE_FUNCTION1}, |     {"sin", sin,      TE_FUN | 1}, | ||||||
|     {"sinh", sinh, TE_FUNCTION1}, |     {"sinh", sinh,    TE_FUN | 1}, | ||||||
|     {"sqrt", sqrt, TE_FUNCTION1}, |     {"sqrt", sqrt,    TE_FUN | 1}, | ||||||
|     {"tan", tan, TE_FUNCTION1}, |     {"tan", tan,      TE_FUN | 1}, | ||||||
|     {"tanh", tanh, TE_FUNCTION1}, |     {"tanh", tanh,    TE_FUN | 1}, | ||||||
|     {0} |     {0} | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| static const te_variable *find_builtin(const char *name, int len) { | static const te_variable *find_builtin(const char *name, int len) { | ||||||
|     int imin = 0; |     int imin = 0; | ||||||
|     int imax = sizeof(functions) / sizeof(te_variable) - 2; |     int imax = sizeof(functions) / sizeof(te_variable) - 2; | ||||||
| @@ -154,6 +171,7 @@ void next_token(state *s) { | |||||||
|         } else { |         } else { | ||||||
|             /* Look for a variable or builtin function call. */ |             /* Look for a variable or builtin function call. */ | ||||||
|             if (s->next[0] >= 'a' && s->next[0] <= 'z') { |             if (s->next[0] >= 'a' && s->next[0] <= 'z') { | ||||||
|  |                 int arity, type; | ||||||
|                 const char *start; |                 const char *start; | ||||||
|                 start = s->next; |                 start = s->next; | ||||||
|                 while ((s->next[0] >= 'a' && s->next[0] <= 'z') || (s->next[0] >= '0' && s->next[0] <= '9')) s->next++; |                 while ((s->next[0] >= 'a' && s->next[0] <= 'z') || (s->next[0] >= '0' && s->next[0] <= '9')) s->next++; | ||||||
| @@ -164,30 +182,28 @@ void next_token(state *s) { | |||||||
|                 if (!var) { |                 if (!var) { | ||||||
|                     s->type = TOK_ERROR; |                     s->type = TOK_ERROR; | ||||||
|                 } else { |                 } else { | ||||||
|                     if (var->type == TE_VARIABLE) { |                     type = te_get_type(var->type); | ||||||
|  |                     arity = te_get_arity(var->type); | ||||||
|  |                     switch(type) | ||||||
|  |                     { | ||||||
|  |                         case TE_VAR: | ||||||
|                             s->type = TOK_VARIABLE; |                             s->type = TOK_VARIABLE; | ||||||
|                         s->bound = var->value; |                             s->bound = var->value; break; | ||||||
|                     } else if (var->type == TE_FUNCTION0) { |                         case TE_FUN: | ||||||
|                         s->type = TOK_FUNCTION0; |                             s->type = TOK_FUNCTION0 + arity; | ||||||
|                         s->f0 = var->value; |                             s->fun.f0 = (void*)var->value; | ||||||
|                     } else if (var->type == TE_FUNCTION1) { |  | ||||||
|                         s->type = TOK_FUNCTION1; |  | ||||||
|                         s->f1 = var->value; |  | ||||||
|                     } else if (var->type == TE_FUNCTION2) { |  | ||||||
|                         s->type = TOK_FUNCTION2; |  | ||||||
|                         s->f2 = var->value; |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 /* Look for an operator or special character. */ |                 /* Look for an operator or special character. */ | ||||||
|                 switch (s->next++[0]) { |                 switch (s->next++[0]) { | ||||||
|                     case '+': s->type = TOK_INFIX; s->f2 = add; break; |                     case '+': s->type = TOK_INFIX; s->fun.f2 = add; break; | ||||||
|                     case '-': s->type = TOK_INFIX; s->f2 = sub; break; |                     case '-': s->type = TOK_INFIX; s->fun.f2 = sub; break; | ||||||
|                     case '*': s->type = TOK_INFIX; s->f2 = mul; break; |                     case '*': s->type = TOK_INFIX; s->fun.f2 = mul; break; | ||||||
|                     case '/': s->type = TOK_INFIX; s->f2 = divide; break; |                     case '/': s->type = TOK_INFIX; s->fun.f2 = divide; break; | ||||||
|                     case '^': s->type = TOK_INFIX; s->f2 = pow; break; |                     case '^': s->type = TOK_INFIX; s->fun.f2 = pow; break; | ||||||
|                     case '%': s->type = TOK_INFIX; s->f2 = fmod; break; |                     case '%': s->type = TOK_INFIX; s->fun.f2 = fmod; 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; | ||||||
| @@ -207,23 +223,24 @@ static te_expr *power(state *s); | |||||||
| static te_expr *base(state *s) { | static te_expr *base(state *s) { | ||||||
|     /* <base>      =    <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-2> "(" <expr> "," <expr> ")" | "(" <list> ")" */ |     /* <base>      =    <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-2> "(" <expr> "," <expr> ")" | "(" <list> ")" */ | ||||||
|     te_expr *ret; |     te_expr *ret; | ||||||
|  |     int arity; | ||||||
|  |  | ||||||
|     switch (s->type) { |     switch (s->type) { | ||||||
|         case TOK_NUMBER: |         case TOK_NUMBER: | ||||||
|             ret = new_expr(TE_CONSTANT, 0, 0); |             ret = new_expr(TE_CONST, 0); | ||||||
|             ret->value = s->value; |             ret->value = s->value; | ||||||
|             next_token(s); |             next_token(s); | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case TOK_VARIABLE: |         case TOK_VARIABLE: | ||||||
|             ret = new_expr(TE_VARIABLE, 0, 0); |             ret = new_expr(TE_VAR, 0); | ||||||
|             ret->bound = s->bound; |             ret->bound = s->bound; | ||||||
|             next_token(s); |             next_token(s); | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case TOK_FUNCTION0: |         case TOK_FUNCTION0: | ||||||
|             ret = new_expr(TE_FUNCTION0, 0, 0); |             ret = new_expr(TE_FUN, 0); | ||||||
|             ret->f0 = s->f0; |             ret->fun.f0 = s->fun.f0; | ||||||
|             next_token(s); |             next_token(s); | ||||||
|             if (s->type == TOK_OPEN) { |             if (s->type == TOK_OPEN) { | ||||||
|                 next_token(s); |                 next_token(s); | ||||||
| @@ -236,34 +253,37 @@ static te_expr *base(state *s) { | |||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case TOK_FUNCTION1: |         case TOK_FUNCTION1: | ||||||
|             ret = new_expr(TE_FUNCTION1, 0, 0); |             ret = new_expr(TE_FUN | 1, 0); | ||||||
|             ret->f1 = s->f1; |             ret->fun.f0 = s->fun.f0; | ||||||
|  |  | ||||||
|             next_token(s); |             next_token(s); | ||||||
|             ret->left = power(s); |             ret->members[0] = power(s); | ||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         case TOK_FUNCTION2: |         case TOK_FUNCTION2: case TOK_FUNCTION3: case TOK_FUNCTION4: | ||||||
|             ret = new_expr(TE_FUNCTION2, 0, 0); |         case TOK_FUNCTION5: case TOK_FUNCTION6: case TOK_FUNCTION7: | ||||||
|             ret->f2 = s->f2; |             arity = s->type - TOK_FUNCTION0; | ||||||
|  |  | ||||||
|  |             ret = new_expr(TE_FUN | arity, 0); | ||||||
|  |             ret->fun.f0 = s->fun.f0; | ||||||
|             next_token(s); |             next_token(s); | ||||||
|  |  | ||||||
|             if (s->type != TOK_OPEN) { |             if (s->type != TOK_OPEN) { | ||||||
|                 s->type = TOK_ERROR; |                 s->type = TOK_ERROR; | ||||||
|             } else { |             } else { | ||||||
|  |                 int i; | ||||||
|  |                 for(i = 0; i < arity; i++) { | ||||||
|                     next_token(s); |                     next_token(s); | ||||||
|                 ret->left = expr(s); |                     ret->members[i] = expr(s); | ||||||
|  |                     if(s->type != TOK_SEP) { | ||||||
|                 if (s->type != TOK_SEP) { |                         break; | ||||||
|                     s->type = TOK_ERROR; |  | ||||||
|                 } else { |  | ||||||
|                     next_token(s); |  | ||||||
|                     ret->right = expr(s); |  | ||||||
|                     if (s->type != TOK_CLOSE) { |  | ||||||
|                         s->type = TOK_ERROR; |  | ||||||
|                     } else { |  | ||||||
|                         next_token(s); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |                 if(s->type != TOK_CLOSE || i < arity - 1) { | ||||||
|  |                     s->type = TOK_ERROR; | ||||||
|  |                 } else { | ||||||
|  |                     next_token(s); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             break; |             break; | ||||||
| @@ -279,7 +299,7 @@ static te_expr *base(state *s) { | |||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         default: |         default: | ||||||
|             ret = new_expr(0, 0, 0); |             ret = new_expr(0, 0); | ||||||
|             s->type = TOK_ERROR; |             s->type = TOK_ERROR; | ||||||
|             ret->value = 0.0/0.0; |             ret->value = 0.0/0.0; | ||||||
|             break; |             break; | ||||||
| @@ -292,8 +312,8 @@ 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->f2 == add || s->f2 == sub)) { |     while (s->type == TOK_INFIX && (s->fun.f2 == add || s->fun.f2 == sub)) { | ||||||
|         if (s->f2 == sub) sign = -sign; |         if (s->fun.f2 == sub) sign = -sign; | ||||||
|         next_token(s); |         next_token(s); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -302,8 +322,8 @@ static te_expr *power(state *s) { | |||||||
|     if (sign == 1) { |     if (sign == 1) { | ||||||
|         ret = base(s); |         ret = base(s); | ||||||
|     } else { |     } else { | ||||||
|         ret = new_expr(TE_FUNCTION1, base(s), 0); |         ret = new_expr(TE_FUN | 1, (const te_expr*[]){base(s)}); | ||||||
|         ret->f1 = negate; |         ret->fun.f1 = negate; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return ret; |     return ret; | ||||||
| @@ -314,11 +334,11 @@ static te_expr *factor(state *s) { | |||||||
|     /* <factor>    =    <power> {"^" <power>} */ |     /* <factor>    =    <power> {"^" <power>} */ | ||||||
|     te_expr *ret = power(s); |     te_expr *ret = power(s); | ||||||
|  |  | ||||||
|     while (s->type == TOK_INFIX && (s->f2 == pow)) { |     while (s->type == TOK_INFIX && (s->fun.f2 == pow)) { | ||||||
|         te_fun2 t = s->f2; |         te_fun2 t = s->fun.f2; | ||||||
|         next_token(s); |         next_token(s); | ||||||
|         ret = new_expr(TE_FUNCTION2, ret, power(s)); |         ret = new_expr(TE_FUN | 2, (const te_expr*[]){ret, power(s)}); | ||||||
|         ret->f2 = t; |         ret->fun.f2 = t; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return ret; |     return ret; | ||||||
| @@ -329,11 +349,11 @@ static te_expr *term(state *s) { | |||||||
|     /* <term>      =    <factor> {("*" | "/" | "%") <factor>} */ |     /* <term>      =    <factor> {("*" | "/" | "%") <factor>} */ | ||||||
|     te_expr *ret = factor(s); |     te_expr *ret = factor(s); | ||||||
|  |  | ||||||
|     while (s->type == TOK_INFIX && (s->f2 == mul || s->f2 == divide || s->f2 == fmod)) { |     while (s->type == TOK_INFIX && (s->fun.f2 == mul || s->fun.f2 == divide || s->fun.f2 == fmod)) { | ||||||
|         te_fun2 t = s->f2; |         te_fun2 t = s->fun.f2; | ||||||
|         next_token(s); |         next_token(s); | ||||||
|         ret = new_expr(TE_FUNCTION2, ret, factor(s)); |         ret = new_expr(TE_FUN | 2, (const te_expr*[]){ret, factor(s)}); | ||||||
|         ret->f2 = t; |         ret->fun.f2 = t; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return ret; |     return ret; | ||||||
| @@ -344,11 +364,11 @@ static te_expr *expr(state *s) { | |||||||
|     /* <expr>      =    <term> {("+" | "-") <term>} */ |     /* <expr>      =    <term> {("+" | "-") <term>} */ | ||||||
|     te_expr *ret = term(s); |     te_expr *ret = term(s); | ||||||
|  |  | ||||||
|     while (s->type == TOK_INFIX && (s->f2 == add || s->f2 == sub)) { |     while (s->type == TOK_INFIX && (s->fun.f2 == add || s->fun.f2 == sub)) { | ||||||
|         te_fun2 t = s->f2; |         te_fun2 t = s->fun.f2; | ||||||
|         next_token(s); |         next_token(s); | ||||||
|         ret = new_expr(TE_FUNCTION2, ret, term(s)); |         ret = new_expr(TE_FUN | 2, (const te_expr*[]){ret, term(s)}); | ||||||
|         ret->f2 = t; |         ret->fun.f2 = t; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return ret; |     return ret; | ||||||
| @@ -361,8 +381,8 @@ static te_expr *list(state *s) { | |||||||
|  |  | ||||||
|     while (s->type == TOK_SEP) { |     while (s->type == TOK_SEP) { | ||||||
|         next_token(s); |         next_token(s); | ||||||
|         ret = new_expr(TE_FUNCTION2, ret, expr(s)); |         ret = new_expr(TE_FUN | 2, (const te_expr*[]){ret, expr(s)}); | ||||||
|         ret->f2 = comma; |         ret->fun.f2 = comma; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return ret; |     return ret; | ||||||
| @@ -370,12 +390,23 @@ static te_expr *list(state *s) { | |||||||
|  |  | ||||||
|  |  | ||||||
| double te_eval(const te_expr *n) { | double te_eval(const te_expr *n) { | ||||||
|     switch (n->type) { |     switch(te_get_type(n->type)) { | ||||||
|         case TE_CONSTANT: return n->value; |         case TE_CONST: return n->value; | ||||||
|         case TE_VARIABLE: return *n->bound; |         case TE_VAR: return *n->bound; | ||||||
|         case TE_FUNCTION0: return n->f0(); |         case TE_FUN: | ||||||
|         case TE_FUNCTION1: return n->f1(te_eval(n->left)); |         switch(te_get_arity(n->type)) { | ||||||
|         case TE_FUNCTION2: return n->f2(te_eval(n->left), te_eval(n->right)); |             #define m(e) te_eval(n->members[e]) | ||||||
|  |             case 0: return n->fun.f0(); | ||||||
|  |             case 1: return n->fun.f1(m(0)); | ||||||
|  |             case 2: return n->fun.f2(m(0), m(1)); | ||||||
|  |             case 3: return n->fun.f3(m(0), m(1), m(2)); | ||||||
|  |             case 4: return n->fun.f4(m(0), m(1), m(2), m(3)); | ||||||
|  |             case 5: return n->fun.f5(m(0), m(1), m(2), m(3), m(4)); | ||||||
|  |             case 6: return n->fun.f6(m(0), m(1), m(2), m(3), m(4), m(5)); | ||||||
|  |             case 7: return n->fun.f7(m(0), m(1), m(2), m(3), m(4), m(5), m(6)); | ||||||
|  |             default: return 0.0/0.0; | ||||||
|  |             #undef m | ||||||
|  |         } | ||||||
|         default: return 0.0/0.0; |         default: return 0.0/0.0; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -447,21 +478,24 @@ double te_interp(const char *expression, int *error) { | |||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void pn (const te_expr *n, int depth) { | static void pn (const te_expr *n, int depth) { | ||||||
|  |     int i, arity; | ||||||
|     printf("%*s", depth, ""); |     printf("%*s", depth, ""); | ||||||
|  |  | ||||||
|     if (n->bound) { |     switch(te_get_type(n->type)) { | ||||||
|         printf("bound %p\n", n->bound); |     case TE_CONST: printf("%f\n", n->value); break; | ||||||
|     } else if (n->left == 0 && n->right == 0) { |     case TE_VAR: printf("bound %p\n", n->bound); break; | ||||||
|         printf("%f\n", n->value); |     case TE_FUN: | ||||||
|     } else if (n->left && n->right == 0) { |          arity = te_get_arity(n->type); | ||||||
|         printf("f1 %p\n", n->left); |          printf("f%d", arity); | ||||||
|         pn(n->left, depth+1); |          for(i = 0; i < arity; i++) { | ||||||
|     } else { |              printf(" %p", n->members[i]); | ||||||
|         printf("f2 %p %p\n", n->left, n->right); |          } | ||||||
|         pn(n->left, depth+1); |          printf("\n"); | ||||||
|         pn(n->right, depth+1); |          for(i = 0; i < arity; i++) { | ||||||
|  |              pn(n->members[i], depth + 1); | ||||||
|  |          } | ||||||
|  |          break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								tinyexpr.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								tinyexpr.h
									
									
									
									
									
								
							| @@ -34,18 +34,29 @@ extern "C" { | |||||||
| typedef double (*te_fun0)(void); | typedef double (*te_fun0)(void); | ||||||
| typedef double (*te_fun1)(double); | typedef double (*te_fun1)(double); | ||||||
| typedef double (*te_fun2)(double, double); | typedef double (*te_fun2)(double, double); | ||||||
|  | typedef double (*te_fun3)(double, double, double); | ||||||
|  | typedef double (*te_fun4)(double, double, double, double); | ||||||
|  | typedef double (*te_fun5)(double, double, double, double, double); | ||||||
|  | typedef double (*te_fun6)(double, double, double, double, double, double); | ||||||
|  | typedef double (*te_fun7)(double, double, double, double, double, double, double); | ||||||
|  |  | ||||||
|  | typedef union | ||||||
|  | { | ||||||
|  |     te_fun0 f0; te_fun1 f1; te_fun2 f2; te_fun3 f3; te_fun4 f4; te_fun5 f5; te_fun6 f6; te_fun7 f7; | ||||||
|  | } te_fun; | ||||||
|  |  | ||||||
| typedef struct te_expr { | typedef struct te_expr { | ||||||
|     struct te_expr *left, *right; |  | ||||||
|     int type; |     int type; | ||||||
|     union {double value; const double *bound; te_fun0 f0; te_fun1 f1; te_fun2 f2;}; |     union {double value; const double *bound; te_fun fun; }; | ||||||
|  |     int member_count; | ||||||
|  |     struct te_expr *members[]; | ||||||
| } te_expr; | } te_expr; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define TE_MASK_ARIT 0x00000007 /* Three bits, Arity, max is 8 */ | ||||||
|  | #define TE_FLAG_TYPE 0x00000018 /* Two bits, 1 = constant, 2 = variable, 3 = function */ | ||||||
|  |  | ||||||
|  | enum { TE_CONST = 1 << 3, TE_VAR = 2 << 3, TE_FUN = 3 << 3}; | ||||||
| enum {TE_FUNCTION0 = -1, TE_VARIABLE = 0, TE_FUNCTION1 = 1, TE_FUNCTION2 = 2}; |  | ||||||
|  |  | ||||||
| typedef struct te_variable { | typedef struct te_variable { | ||||||
|     const char *name; |     const char *name; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user