65.9K
CodeProject 正在变化。 阅读更多。
Home

基于 C 的表达式求值库

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.03/5 (14投票s)

2004年8月10日

3分钟阅读

viewsIcon

58331

downloadIcon

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_PIM_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 库的更完整的文档和参考资料以及两个示例。 一个基本上是速度测试,另一个基于数学表达式生成图像。

© . All rights reserved.