Introduction
ExprEval is a C based expression evaluation library designed to be fast and powerful. It is written in ANSI compliant C to be able to work with any C/C++ compiler.
How it works
ExprEval takes an expression entered as a string and parses it down into an expression tree. This tree, once parsed, can be evaluated over and over without the need to parse it again. Variables can still be changed by the application and/or the expression.
Fast variable access
Variable access is fast within the ExprEval library. At parse time, any variables found in the expression string are added to the variable list if they are not already there. Then the memory address of the variable is stored in the tree. This way, at evaluation time, the variable can be directly accessed without needing to lookup the variable using string comparisons. Functions are also provided to enable the application to do the same thing.
The expression string
The expression string consists of one or more expressions, each terminated with a semicolon. The expressions appear much like they would on paper. An expression can do assignments, basic math operators (+, -, *, /, negate), and even call functions.
Order of operators
The parser parses the expression in a way that the order of operators should work correctly. First, parenthesis are done, then multiplication and division, then addition and then subtraction.
Assignment
Assignments can occur about anywhere in an expression. If an assignment is inside a function parameter, the function solver must evaluate that parameter for the assignment to take place.
x = sin(y = 50);
Functions
The ExprEval library provides many default functions. Functions can take normal parameters and reference parameters, depending on the function solver. Normal parameters are not pre-evaluated by the library. Instead, the function solver needs to evaluate them. This means more work for the function solver, but also more power because the function solver can evaluate and execute the normal parameters in any order and any number of times. Reference parameters are passed to the function solver as addresses to the variable being referenced. Their main purpose is to enable the function solver to 'return' more than one value by changing the value of some other variables. Normal and reference parameters can be mixed together. The only thing that matters is that the normal parameters are in a certain order, and the reference parameters are in a certain order, defined by the function solver.
x = func1(a, b, c);
x = func2(&a, &b);
x = func3(1, 2, &a, 3, &b);
x = func3(1, &a, &b, 2, 3);
x = func3(2, &b, &a, 3, 1);
Custom functions
Custom functions can easily be added to the library. The functions are written in C, and then added to the function list.
Constants
The ExprEval library also provides many constants such as M_PI
, M_E
, etc.
Function, variable and constant lists
Function lists, variable lists, and constant lists are all stored separately from each other so that the developer can choose how to bind them to the expression objects. You can create multiple expressions objects which share the same variables or that have there own private variables or constants or functions or any mix and match.
Sample Usage
The following is a sample of how to use ExprEval:
#include "expreval.h"
...
...
int breaker(exprObj *o)
{
return need_to_stop;
}
EXPR_FUNCTIONSOLVER(my_func)
{
EXPRTYPE tmp;
int err;
EXPR_REQUIREREFCOUNT(1);
EXPR_REQUIRECOUNT(1);
EXPR_EVALNODE(0, tmp);
*refitems[0] = tmp;
*val = tmp;
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 dummy;
double pos;
err = exprFuncListCreate(&f);
if(err != EXPR_ERROR_NOERROR)
goto error;
err = exprFuncListInit(f);
if(err != EXPR_ERROR_NOERROR)
goto error;
err = exprFuncListAdd(f, my_func, "myfunc", 1, 1, 1, 1);
if(err != EXPR_ERROR_NOERROR)
goto error;
err = exprValListCreate(&c);
if(err != EXPR_ERROR_NOERROR)
goto error;
err = exprValListInit(c);
if(err != EXPR_ERROR_NOERROR)
goto error;
err = exprValListCreate(&v);
if(err != EXPR_ERROR_NOERROR)
goto error;
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;
err = exprCreate(&e, f, v, c, NULL, breaker, 0);
if(err != EXPR_ERROR_NOERROR)
goto error;
err = exprParse(e, expr);
if(err != EXPR_ERROR_NOERROR)
goto error;
exprSetSoftErrors(e, 1);
for(pos = 0.0; pos < 10.0; pos += 0.1)
{
*e_x = (EXPRTYPE)pos;
exprEval(e, &dummy);
do_something(*e_x, *e_y);
}
goto done;
error:
printf("An error occured\n");
done:
if(e)
exprFree(e);
if(f)
exprFuncListFree(f);
if(v)
exprValListFree(v);
if(c)
exprValListFree(c);
return;
}
Documentation and examples
The download contains a more complete documentation and reference for the ExprEval library as well as two examples. One is basically a speed test, and the other generates an image based on a math expression.