基于 C 的表达式求值库






3.03/5 (14投票s)
2004年8月10日
3分钟阅读

58331

1017
快速、强大、有用的表达式求值库。
引言
ExprEval 是一个基于 C 的表达式求值库,旨在快速且强大。 它用符合 ANSI 标准的 C 编写,可以与任何 C/C++ 编译器一起使用。
工作原理
ExprEval 接受作为字符串输入的表达式,并将其解析为表达式树。 一旦解析,这个树可以重复求值,而无需再次解析。 变量仍然可以由应用程序和/或表达式更改。
快速变量访问
在 ExprEval 库中,变量访问速度很快。 在解析时,如果在表达式字符串中找到任何变量,且该变量尚未存在于变量列表中,则会将其添加到变量列表中。 然后,该变量的内存地址存储在树中。 这样,在求值时,可以直接访问该变量,而无需使用字符串比较来查找该变量。 还提供了函数,使应用程序能够执行相同的操作。
表达式字符串
表达式字符串由一个或多个表达式组成,每个表达式以分号结尾。 这些表达式看起来很像它们在纸上的样子。 表达式可以进行赋值、基本数学运算符(+、-、*、/、取反),甚至可以调用函数。
运算符的优先级
解析器以一种运算符优先级应该正确的方式解析表达式。 首先计算括号,然后是乘法和除法,然后是加法,最后是减法。
赋值
赋值可以发生在表达式中的任何位置。 如果赋值位于函数参数中,则函数求解器必须计算该参数才能进行赋值。
x = sin(y = 50);
函数
ExprEval 库提供了许多默认函数。 函数可以采用普通参数和引用参数,具体取决于函数求解器。 普通参数不会被库预先计算。 相反,函数求解器需要计算它们。 这意味着函数求解器需要做更多的工作,但也意味着更大的能力,因为函数求解器可以按任何顺序和任何次数计算和执行普通参数。 引用参数作为变量地址传递给函数求解器。 它们的主要目的是使函数求解器能够通过更改某些其他变量的值来“返回”多个值。 普通参数和引用参数可以混合在一起。 唯一重要的是普通参数按特定顺序排列,引用参数按特定顺序排列,由函数求解器定义。
x = func1(a, b, c);
//Normal parameters
x = func2(&a, &b);
//Reference parameters referencing variables a and b
x = func3(1, 2, &a, 3, &b); //Normal and reference parameters can be mixed
x = func3(1, &a, &b, 2, 3); //This is the same as the above
x = func3(2, &b, &a, 3, 1); //This is not the same
自定义函数
可以很容易地将自定义函数添加到库中。 函数用 C 编写,然后添加到函数列表中。
常量
ExprEval 库还提供了许多常量,例如 M_PI
、M_E
等。
函数、变量和常量列表
函数列表、变量列表和常量列表彼此分开存储,以便开发人员可以选择如何将它们绑定到表达式对象。 您可以创建多个表达式对象,这些对象共享相同的变量,或者具有自己的私有变量、常量或函数,或者任意组合。
示例用法
以下是如何使用 ExprEval 的示例
#include "expreval.h" ... ... /* Breaker function to break out of long expression functions such as the 'for' function */ int breaker(exprObj *o) { /* Return nonzero to break out */ return need_to_stop; } /* Custom function using macros */ EXPR_FUNCTIONSOLVER(my_func) { EXPRTYPE tmp; int err; /* Need to declare this variable to use macros */ EXPR_REQUIREREFCOUNT(1); /* Need 1 reference parameter */ EXPR_REQUIRECOUNT(1); /* Need 1 normal parameter */ /* Evaluate the first normal parameter */ EXPR_EVALNODE(0, tmp); /* Set the ref parameter to the value of the normal parameter */ *refitems[0] = tmp; /* Set the return value */ *val = tmp; /* No error occured */ return EXPR_ERROR_NOERROR; } void DoExpression(char *expr) { exprObj *e = NULL; exprFuncList *f = NULL; exprValList *v = NULL; exprValList *c = NULL; EXPRTYPE *e_x, *e_y; /* EXPRTYPE is typedef for double */ EXPRTYPE dummy; double pos; /* Create function list */ err = exprFuncListCreate(&f); if(err != EXPR_ERROR_NOERROR) goto error; /* Init function list with internal functions */ err = exprFuncListInit(f); if(err != EXPR_ERROR_NOERROR) goto error; /* Add custom function */ err = exprFuncListAdd(f, my_func, "myfunc", 1, 1, 1, 1); if(err != EXPR_ERROR_NOERROR) goto error; /* Create constant list */ err = exprValListCreate(&c); if(err != EXPR_ERROR_NOERROR) goto error; /* Init constant list with internal constants */ err = exprValListInit(c); if(err != EXPR_ERROR_NOERROR) goto error; /* Create variable list */ err = exprValListCreate(&v); if(err != EXPR_ERROR_NOERROR) goto error; /* Add variables x and y */ exprValListAdd(v, "x", 0.0); exprValListAdd(v, "y", 0.0); exprValListGetAddress(v, "x", &e_x); exprValListGetAddress(v, "y", &e_y); if(e_x == NULL || e_y = NULL) goto error; /* Create expression object */ err = exprCreate(&e, f, v, c, NULL, breaker, 0); if(err != EXPR_ERROR_NOERROR) goto error; /* Parse expression */ err = exprParse(e, expr); if(err != EXPR_ERROR_NOERROR) goto error; /* Enable soft errors */ exprSetSoftErrors(e, 1); /* The expression should set the variable y based on x */ for(pos = 0.0; pos < 10.0; pos += 0.1) { /* Directly access and set variable x */ *e_x = (EXPRTYPE)pos; /* Evaluate the expression */ exprEval(e, &dummy); /* Do something with the results */ do_something(*e_x, *e_y); } goto done; error: /* Alert user of error */ printf("An error occured\n"); done: /* Do cleanup */ if(e) exprFree(e); if(f) exprFuncListFree(f); if(v) exprValListFree(v); if(c) exprValListFree(c); return; }
文档和示例
下载内容包含 ExprEval 库的更完整的文档和参考资料以及两个示例。 一个基本上是速度测试,另一个基于数学表达式生成图像。