ExprEval Help document. This document is probably full of bugs and mispellings. I may get around to proofreading it later.
ExprEval is a C/C++ based expression evaluation library. It is entirely C based, but it comes with a C++ wrapper class that simplifies it's use. The source code is provided for the library so that it can be recompiled for the specific system or compiler.
ExprEval makes adding mathematical expression support to an application easy. It takes an expression string and parses it, and then it can evaluate it over and over. This library also has support for functions, constants, and variables. All of these items are stored in seperate lists so they can be shared among expressions or they can be private to a single expression or any mix and match. It is up to the developer how to link them together. You can also create your own custom functions. However, there is no C++ wrapper for custom functions, you must use the C routines for the function itself. You can still use the C++ routines to add the functions to the lists and work with the expression, just the function code must use the C routines.
This library is licensed under the ExprEval License.
Expressions have pretty much the same syntax as they would have on paper, with the following exceptions:
- Each expression must end with a semicolon. This is because the expression string can actually contain multiple expressions. The semicolon is used to mark the end of the expression.
Examples:
- 4*x+5;
- y=5+2;g=4+6;
- y=r*sin(a);x=r*cos(a);
- The asterisk '*' must be used to multiply.
Examples:
- y=5*6; Valid
- g=(x+1)*(x-1); Valid
- g=(x+1)(x-1); Invalid
More than one expression may be contained within an expression string. As shown above, each expression must end with a semicolon, even if only one expression is in the string. The value of an expression string is the value of the last expression in the string.
Examlples:
- g=7; Value: 7
- k=z+1; Value: z+1
- r=4;k=6;o=9+r-k; Value: 9+r-k
Some functions may take reference parameters. These parameters are references to other variables. You can mix reference parameters with normal parameters. The order of the normal parameters must remain the same and the order of the reference parameters must remain the same.
Examples:
- min(1,2,3,4,&mval); &mval is a reference to a variable mval
- min(1,2,&mval,3,4); You may mix them inside like this.
- min(1,2,(&mval),3,4); You may not nest reference parameters in any way
Expressions may also be nested with parenthesis.
Examples:
- y=sin(x-cos(5+max(4,5,6*x)));
- 6+(5-2*(x+y));
Expressions may also have whitespace characters and comments. Whitespace characters such as newlines, linefeeds, carriage returns, spaces, and tabs are ignored. Comments begin with the less than-sign '<' and end with the greater than-sign '>'. Comments may be nested as well.
Example:
<Set the x value> x = d * cos(r); <Set the y value> y = d * sin(r); <Comment out this for now <Flip the values> t = x; x = y; y = x; Stop commenting out>If a variable is used in an expression, but that variable does not exist, it is considered zero. If it does exist then its value is used instead.
Using ExprEval in an application can be a little difficult. You generally follow these steps:
You can manipulate the lists in any order after their creation. However, functions are translated during the parse, so after parsing an expression, manipulating the function list will make no change to an expression. Variables and constants can be manipulated after a parse to change the result of an expression. However, you must add any constants to be used by an expression to the constant list BEFORE parsing the expression, otherwise it will be seen as a variable. Applications can change both variables and constants, however the expression can only change variables. Expressions may NOT assign to a constant and expressions may NOT use constants as a reference parameter.
- Create function, variable, and constant lists
- Create the expression object
- Parse the expression
- Evaluate the expression as needed
- Free the expression object
- Free the function, variable, and constant lists
Function, variable, and constant list example:
exprFuncList *f; exprValList *v; exprValList *c; exprObj *o; EXPRTYPE result; int err; /* Create function list */ err = exprFuncListCreate(&f); if(err != EXPR_ERROR_NOERROR) { printf("Function List Creation Error %d\n", err); return; } /* Initialize internal functions */ err = exprFuncListInit(f); if(err != EXPR_ERROR_NOERROR) { printf("Function List Initialization Error %d\n", err); printf("Some internal functions may not be usable\n"); } /* Create variable list */ err = exprValListCreate(&v); if(err != EXPR_ERROR_NOERROR) { printf("Variable List Creation Error %d\n", err); exprFuncListFree(f); return; } /* Create the constant list */ err = exprValListCreate(&c); if(err != EXPR_ERROR_NOERROR) { printf("Constant List Creation Error %d\n", err); exprFuncListFree(f); exprValListFree(v); return; } /* Initialize internal constants */ err = exprValListInit(c); if(err != EXPR_ERROR_NOERROR) { printf("Constant List Initialization Error %d\n", err); printf("Some internal constants may not be usable\n"); } /* Add any application defined functions, constants, or variables to the lists here or down below */Expression object example:
err = exprCreate(&o, f, v, c, NULL, 0); if(err != EXPR_ERROR_NOERROR) { printf("Expression Object Creation Error %d\n", err); exprFuncListFree(f); exprValListFree(c); exprValListFree(v); return; } /* Add any application defined functions, constants, or variables to the lists here or down below. This is the last time you can for the functions or constants. */Expression parse example:
/* Functions and constants may be added or changed here */ err = exprParse(o, "2+sin(M_PI)+3*x;"); if(err != EXPR_ERROR_NOERROR) { printf("Expression Parse Error %d\n", err); /* Free objects and return */ exprFree(o); /* Free lists */ } /* Changes to the function or constant lists do not change the expression now */Expression evaluation example:
/* Add or change any variables */ err = exprEval(o, &result); if(err != EXPR_ERROR_NOERRO) { printf("Expression Evaluation Error %d\n", err); } else { printf("Expression Result: %f\n", result); }Free the expression object and lists example:
exprFree(o); exprFreeValList(v); exprFreeValList(c); exprFreeFuncList(f);
A new feature in ExprEval is fast variable access. This is simply a technique of quickly accessing variables by directly accessing their memory locations instead of using the value list functions. If you choose to enable fast variable access within ExprEval, you must NOT clear a variable list until after all expressions using it are completely finished evaluating. Then you must reparse the expressions before using them again. The reason is simple. When fast variable access is not used, the value list functions are used and they make sure to access the correct memory or add a variable if needed. However, when fast variable access is used, the variable memory location is directly accessed, and the value list functions are not used. If you clear a variable list and then evaluate an expression, it will access invalid memory.
You can also use fast variable access in you application to dramatically speed up loops. This is accomplished as follows:
- Add the desired variable to the variable list
- Get the address of the variable with exprValListGetAddress
- In the loop(s), directly set/get the variable any time needed: *var = 0.0;
To use the internal functions, they must first be initialized into a function list with exprFuncListInit. To use the internal constants, they must first be initialized into a value list with exprValListInit. For a list of the internal functions and constants, see the application help template file: ExprTmpl.html You may use this file in your own applications so you don't have to write a detail on the functions in ExprEval. All you have to do is add you own functions and constants to the file if there are any.
Custom functions must use the C routines, not the C++ wrapper classes. There are several macros that make creating custom functions easy. They require that the variables passed to these functions be the same though. This is how a custom function should normally look:
int custom_func(struct _exprObj *o, struct _exprNode *n, int count, EXPRTYPE **refitems, int refcount, EXPRTYPE *val) { }o is a pointer to the expression object that called the function, n is a pointer to an array of nodes that are the parameters of this function, count is the number of items in the array (the number of parameters), refitems is an array of pointers to referenced variables, refcount is the number of referenced variables, and val is a pointer to a variable to recieve the result of the function. The function should return an error value indicating the error status of the function.If the variables to the function are as above, the macros will make working with them easier. Solving a function typically goes as follows:
- Verifiy the number of arguments
- Evaluate the subnodes that you need. You do not have to evaluate every subnode if you do not need it
- Check for possible error conditions (division by zero)
- Clear math errors (If function uses any math routines)
- Calculate the result
- Check for math errors (If the function uses any math routines)
- return EXPR_ERROR_NOERROR
Example without the macros:
int custom_func(struct _exprObj *o, struct _exprNode *n, int count, EXPRTYPE **refitems, int refcount, EXPRTYPE *val) { int err; EXPRTYPE d1, d2; /* Need 2 arguments */ if(count != 2) return EXPR_ERROR_BADNUMBERARGUMENTS; /* Eval arg 1 */ err = exprEvalNode(o, &(n[0]), &d1); if(err != EXPR_ERROR_NOERROR) return err; /* Eval arg 2 */ err = exprEvalNode(o, &(n[1]), &d2); if(err != EXPR_ERROR_NOERROR) return err; /* Make sure arg 2 is not 0.0 */ if(d2 == 0.0) { /* Soft errors on */ if(exprGetSoftErrors(o)) { /* Yes */ *val = 0.0; return EXPR_ERROR_NOERROR; } else { /* No */ return EXPR_ERROR_OUTOFRANGE; /* Bad argument */ } } /* Clear any math routine errors */ errno = 0; /* Do math */ *val = atan(d1 / d2); /* No need to worry about divide by zero */ /* Check for math errors */ if(errno == EDOM || errno == ERANGE) { if(exprGetSoftErrors(o)) { *val = 0.0; return EXPR_ERROR_NOERROR; } else { return EXPR_ERROR_OUTOFRANGE; } } return EXPR_ERROR_NOERROR; }Same example with the macros:
EXPR_FUNCTIONSOLVER(custom_func) { int err; EXPRTYPE d1, d2; /* Require 2 arguments */ EXPR_REQUIRECOUNT(2); /* Evaluate the nodes */ EXPR_EVALNODE(0, d1); EXPR_EVALNODE(1, d2); /* Make sure d2 is not 0.0 */ if(d2 == 0.0) { EXPR_RETURNSOFTERR(EXPR_ERROR_OUTOFRANGE); } /* Clear math routine errors */ EXPR_CLEARMATHERR(); /* Do math */ *val = atan(d1 / d2) /* No need to worry about division by zero */ /* Check for math routine errors */ EXPR_CHECKMATHERR(); /* Return */ return EXPR_ERROR_NOERROR; }In order to use a custom function, it must be added to a function list before the expression is parsed by using exprFuncListAdd
The following is a list of the macros, their uses, and their definitions. They require the custom function arguments to have the same names as above (struct _exprObj *o, struct _exprNode *n, int count, EXPRTYPE *val).
Macro Usage Definition EXPR_EVALNODE(num, res) Evaluate a node. num is the zero based node number to evaluate. res is the variable to store the result in. err = exprEvalNode(o, &(n[num]), &res); if(err != EXPR_ERROR_NOERROR) return err;EXPR_REQUIRECOUNT(c) Require exactly c arguments. if(count != c) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_REQUIRECOUNTMIN(c) Require at least c arguments. if(count < c) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_REQUIRECOUNTMAX(c) Require at most c arguments. if(count > c) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_REQUIRECOUNTRANGE(c1, c2) Require at least c1 arguments and at most c2 arguments. if(count < c1 || count > c2) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_REQUIREREFCOUNT(c) Require exactly c ref arguments. if(refcount != c) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_REQUIREREFCOUNTMIN(c) Require at least c ref arguments. if(refcount < c) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_REQUIREREFCOUNTMAX(c) Require at most c ref arguments. if(refcount > c) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_REQUIREREFCOUNTRANGE(c1, c2) Require at least c1 ref arguments and at most c2 ref arguments. if(refcount < c1 || refcount > c2) return EXPR_ERROR_BADNUMBERARGUMENTS;EXPR_CHECKMATHERR() Check for EDOM or ERANGE math error. if(errno == ERANGE || errno == EDOM) { if(exprGetSoftErrors(o)) { *val = 0.0; return EXPR_ERROR_NOERROR; } else { return EXPR_ERROR_OUTOFRANGE; } }EXPR_CLEARMATHERR() Clear errno. errno = 0;EXPR_RETURNSOFTERR(s_err) If soft errors are on, set *val to 0.0 and return EXPR_ERROR_NOERROR. Else return e. if(exprGetSoftErrors(o)) { *val = 0.0; return EXPR_ERROR_NOERROR; } else { return s_err; }EXPR_CHECKBREAK() If breaker function returns nonzero, stop if(exprGetBreakResult(o)) { return EXPR_ERROR_BREAK; }EXPR_FUNCTIONSOLVER(name) Make creating function solvers easier int func_name##(struct _exprObj *o, struct _exprNode *n, int count, EXPRTYPE **refitems, int refcount, EXPRTYPE *val)If you use any of these macros inside any conditional or loop, make sure you put them in braces so it will work right.
Correct example:
if(d2 == 0.0) { EXPR_RETURNSOFTERR(EXPR_ERROR_OUTOFRANGE); }Incorrect example:
if(d2 == 0.0) EXPR_RETURNSOFTERR(EXPR_ERROR_OUTOFRANGE); /* This might not work correctly */
Headers:
- expreval.h - Include file for C usage
- expreval.hpp - Include file for C++ wrappers. No reference is provided for the C++ wrappers. Read this file to understand how they work. It is recommended that you make you own wrapper classes that are better suited to your purpose.
Defines:
- EXPR_VERSIONMAJOR - Major version number of the ExprEval interface (header)
- EXPR_VERSIONMINOR - Minor version number of the ExprEval interface (header)
- EXPR_MAXIDENTSIZE - Maximum identifier, constant, or function name size
- EXPR_ERROR_NOERROR - No error has occurred
- EXPR_ERROR_MEMORY - A memory allocation error occured. For function and value lists, the name may have been invalid
- EXPR_ERROR_NULLPOINTER - A null pointer was passed to a function that needed a valid pointer.
- EXPR_ERROR_NOTFOUND - An item was not found in the function or value list
- EXPR_ERROR_UNMATHEDCOMMENT - Comment is missing opening or closing mark.
- EXPR_ERROR_INVALIDCHAR - Invalid characters were found in the expression
- EXPR_ERROR_ALREADYEXISTS - For C++ wrapper class, already called Create member.
- EXPR_ERROR_DOESNOTEXIST - For C++ wrapper calss, expression object does not exist. Call Create member
- EXPR_ERROR_ALREADYPARSEDBAD - An expression was already parsed into this object, but unsuccessfully. Free the expression before creating and parsing again
- EXPR_ERROR_ALREADYPARSEDGOOD - An expression was already parsed into this object successfully. Free the expression before creating and parsing again
- EXPR_ERROR_EMPTYEXPR - An empty expression string was passed to be parsed
- EXPR_ERROR_UNMATHEDPAREN - Unmathed opening or closing parenthesis were found
- EXPR_ERROR_SYNTAX - A syntax error is in the expression
- EXPR_ERROR_MISSINGSEMICOLON - An expression is missing a semicolon
- EXPR_ERROR_BADIDENTIFIER - A bad identifier was used in the expression
- EXPR_ERROR_NOSUCHFUNCTION - Function used in the expression does not exist in the function list
- EXPR_ERROR_BADNUMBERARGUMENTS - A bad number of arguments was passed to the expression function
- EXPR_ERROR_BADEXPR - Can not evaluate an expression because it does not exist or has not been parsed successfully.
- EXPR_ERROR_UNABLETOASSIGN - Unable to do an assignment because a variable list has not been associated with the expression object
- EXPR_ERROR_OUTOFRANGE - A parameter to an expression function was invalid for that function, or the function caused an overflow to occur
- EXPR_ERROR_DIVBYZERO - An attemp to divide by zero has occured
- EXPR_ERROR_NOVARLIST - No variable list for the expression
- EXPR_ERROR_BREAK - The expression was broken by the break function
- EXPR_ERROR_CONSTANTASSIGN - The expresion attempted to assign to a constant.
- EXPR_ERROR_REFCONSTANT - The expression attempted to pass a constant as a reference parameter.
Objects:
- exprObj - The expression object
- exprFuncList - A function lists for the expresions
- exprValList - A value list for constants or variables
- exprNode - An individual node in a parsed expression tree
Types:
- EXPRTYPE - Type for the value of an expression (double)
- exprMsgFuncType - Message function pointer that can be used in custom functions to send messages to the application. Defined as:
typedef void (*exprMsgFuncType)(int type, int code, char *msg);- exprFuncType - Custom function type. Defined as:
typedef int (*exprFuncType)(struct _exprObj *o, struct _exprNode *n, int count, EXPRTYPE **refitems, int refcount, EXPRTYPE *val);- exprBreakFuncType - Breaker function pointer to stop evaluation if the result is nonzero. Defined as:
typedef int (*exprBreakFuncType)(struct _exprObj *o);Version information functions:
- void exprGetVersion(int *major, int *mino);
Comments:Parameters:
- Gets the version of the ExprEval library
Returns:
- *major - Pointer to int to get major version number
- *minor - Pointer to int to get minor version number
- Nothing
Function list functions:
- int exprFuncListCreate(exprFuncList **f);
Comments:Parameters:
- Creates a function lists and updates a pointer to point to it
Returns
- **f - Pointer to a pointer to the function list
- Error code of the function. On success, the pointer passed by address will point to the new function list
- int exprFuncListAdd(exprFuncList *f, exprFuncType ptr, char *name, int min, int max, int refmin, int refmax);
Comments:Parameters:
- Adds a function to the function list
Returns:
- *f - Pointer to an already created function list
- ptr - Pointer to a custom function
- *name - Name of the custom function
- min - Minimum number of arguments for the function, negative for no minimum
- max - Maximum number of arguments for the function, negative for no maximum
- refmin - Minimum number of ref arguments
- refmax - Maxmimum number of ref arguments
- Error code of the function
- int exprFuncListGet(exprFuncList *f, exprFuncType *ptr, char *name, int *min, int *max, int *refmin, int *refmax);
Comments:Parameters:
- Get function information from the function list
Returns:
- *f - Pointer to the function list
- *ptr - Pointer to a pointer to a custom function
- *name - Name of the function to get
- *min - Pointer to variable to get min data
- *max - Pointer to variable to get max data
- *refmin - Pointer to variable to get min ref data
- *refmax - Pointer to variable to get max ref data
- Error code of the function
- int exprFuncListFree(exprFuncList *f);
Comments:Parameters:
- Free the function list entirely
Returns:
- *f - Pointer to the function list to free
- Error code of the function
- int exprFuncListClear(exprFuncList *f);
Comments:Parameters:
- Clear the functions from the function list
Returns:
- *f - Pointer to the function list to clear
- Error code of the function
- int exprFuncListInit(exprFuncList *f);
Comments:Parameters:
- Initializes internal functions into the funtion list
Returns:
- *f - Function list to initialize
- Error code of the function
Value list functions:
- int exprValListCreate(exprValList **v);
Comments:Parameters:
- Creates a value list for variables or constants
Returns:
- **v - Pointer to a pointer to the value list.
- Error code of the function. On success, the pointer will be updated to point to the value list
- int exprValListAdd(exprValList *v, char *name, EXPRTYPE val);
Comments:Parameters:
- Add or update a value in a value list
Returns:
- *v - Value list to add a value to
- *name - Name of the value to add
- val - Value of the value to add
- Error code of the function
- int exprValListGet(exprValList *v, char *name, EXPRTYPE *val)
Comment:Parameters:
- Get the value of a variable or constant in a value list
Returns:
- *v - Value list to use
- *name - Name of the value to get
- *val - Pointer to variable to get the value
- Error code of the function
- int exprValListGetAddress(exprValList *v, char *name, EXPRTYPE **addr)
Comment:Parameters:
- Get the memory address of a variable in a value list
Returns:
- *v - Value list to use
- *name - Name of the value to get
- ** - Pointer to a pointer to store the address of the value This will be NULL if the name is not in the list.
- Error code of the function
- int exprValListFree(exprValList *v);
Comments:Parameters:
- Completely free the value list
Returns:
- *v - Value list to free
- Error code of the function
- int exprValListClear(exprValList *v);
Comments:Parameters:
- Set the values in the list to 0.0
Returns:
- *v - Value list to reset
- Error code of the function
- int exprValListInit(exprValList *v);
Comments:Paramters:
- Initialize internal constants into a value list
Returns:
- *v - Value list to initialize
- Error code of the function
Expression functions:
- int exprCreate(exprObj **o, exprFuncList *f, exprValList *v, exprValList *c, exprMsgFuncType msg, exprBreakFuncType breaker, void *userdata);
Comments:Parameters:
- Create an expression object to use
Returns:
- **o - Pointer to a pointer to an expression object
- *f - Function list to associate with the expression
- *v - Variable value list to associate with the expression
- *c - Constant value list to associate with the expression
- msg - Message function callback to associate with the expression
- breaker - Breaker function callback to associate with the expression. Used by functions that may be infinite loops (such as the for function)
- userdata - User data to associate with the expression
- Error code of the function
- int exprFree(exprObj *o);
Comments:Paramters:
- Completely free the expression object
Returns:
- *o - Expression object to free
- Error code of the function
- int exprClear(exprObj *o);
Comments:Parameters:
- Clear an expression, but keep list and callback associations. You can then parse another expression without calling create
Returns:
- *o - Expression object to clear
- Error code of the function
- int exprParse(exprObj *o, char *expr);
Comments:Paramters:
- Parse an expression string into an expression object
Returns:
- *o - Expression object to use
- *expr - Expression string to parse
- Error code of the function
- int exprEval(exprObj *o, EXPRTYPE *val);
Comments:Paramters:
- Evaluate a parsed expression
Returns:
- *o - Expression object to evaluate
- *val = Pointer to variable to get result of evaluation
- Error code of the function
- int exprEvalNode(exprObj *o, exprNode *n, EXPRTYPE *val);
Comments:Parameters:
- Evaluate a node of an expression. Used by custom functions
Returns:
- *o - Expression object being used
- *n - Pointer to node to evaluate
- *val - Pointer to variable to get evaluation result
- Error code of the function
- exprFuncList *exprGetFuncList(exprObj *o);
Comments:Parameters:
- Gets the function list associated with an expression
Returns:
- *o - expression object
- Pointer fo an exprFuncList object or NULL
- exprValList *exprGetVarList(exprObj *o);
Comments:Parameters:
- Gets the variable list associated with an expression
Returns:
- *o - expression object
- Pointer to an exprValList object or NULL
- exprValList *exprGetConstList(exprObj *o);
Comments:Parameters:
- Gets the constant list associated with an expression
Returns:
- *o - expression object
- Pointer to an exprValList object or NULL
- exprMsgFuncType exprGetMsgFunc(exprObj *o);
Comments:Parameters:
- Gets the message callback of the expression
Returns:
- *o - expression object
- Pointer to the callback function or NULL
- exprBreakFuncType exprGetBreakFunc(exprObj *o);
Comments:Parameters:
- Gets the breaker callback of the expression
Returns:
- *o - expression object
- Pointer to the callback function or NULL
- int exprGetBreakResult(exprObj *o);
Comments:Parameters:
- Get the result of the breaker function
Returns:
- *o - expression object
- zero to continue, nonzero to break
- void* exprGetUserData(exprObj *o);
Comments:Parameters:
- Gets the user data associated with an expression
Returns:
- *o - expression object
- User data
- int exprGetSoftErrors(exprObj *o);
Comments:Parameters:
- Gets the soft error status. 0 means off, anything else means on
Returns:
- *o - expression object
- Soft error status of the expression
- void exprSetUserData(exprObj *o, void *userdata);
Comments:Parameters:
- Sets the user data of an expression
Returns:
- *o - expresion object
- userdata - user data to set
- Nothing
- void exprSetSoftErrors(exprObj *o, int softerr);
Comments:Parameters:
- Set soft error on or off. 0 means off, anything else means on
Returns:
- *o - expresion object
- softerr - value to set the soft errors to
- Nothing
Some useful functions
- int exprValidIdent(char *name);
Comments:Parameters:
- Determine if an identifier is valid
Returns:
- *name - identifier to check
- 0 on invalid. anything else on valid
- int exprValidNumber(char *num);
Comments:Parameters:
- Determines if a number is valid. A valid number may contain digits and a decimal point. It must contain digits somewhere for it to be valid. A + or - sign is invalid because this is handled elsewhere by the libray.
Returns:
- *num - number to check
- 0 on invalid. anything else on valid
Compiling the ExprEval library is pretty simple. Just compile all of the source files (*.c) and link them into a library. You need to keep "expreval.h" and "expreval.hpp" for the header files.
The library used to have an option of fast variable access or slow variable access by using EXPR_FAST_VAR_ACCES. Now, fast variable access is used whether EXPR_FAST_VAR_ACCESS is defined or not.
You may have to make some changes to the library. I've tried to make doing so as simple as possible. If you need to change the include files or some macros or whatnot, edit the file "exprincl.h" This file includes any other files needed. For example, on Borland compilers you will need to change the include of "memory.h" to "mem.h". If some functions are not provided for your system, Edit the file "exprincl.c". You will need to add the functions as they are used by the library, and make them call the correct function for your system and return the value as the library expects. You should not have to change to much. I have tried to stick as close to ANSI/ISO C as I can.
Example:
/* This example assumes that your compiler does not have the malloc or free functions. */ void *malloc(int size) { /* Assume that you must request pages of memory instead */ int pages_needed; /* Figure out how many pages are needed */ pages_needed = (size + (PAGE_SIZE - 1)) / PAGE_SIZE; /* Assume alloc_pages allocates a number of pages and returns a pointer to them or NULL */ return alloc_pages(pages_needed); } void free(void *ptr) { dealloc_pages(ptr); }
The following is a list of some basic drawbacks of this library:
This is an example application of this library. It is a graphics program that calculates the color value of a pixel based on it's X,Y co-ordinate. It uses a made-up image library called graphic-lib
/* Include files */ #include <stdio.h> #include <stdlib.h> #include <setjmp.h> #include "graphiclib.h" #include "expreval.h" char *transerr(int err) { /* Translate error code into message */ } void gen_image(char *name, int w, int h, char *expr); { exprFuncList *f = NULL; exprValList *v = NULL; exprValList *c = NULL; exprObj *o = NULL; int x, y, err; jmp_buf jumper; int image; EXPRTYPE r, g, b; /* Error handling */ err = setjmp(jumper); if(err) { if(err != ID_IMAGENOERROR) printf("Error %d occurred: %s\n", err, transerr(err)); exprFree(o); exprFreeFuncList(f); exprFreeValList(v); exprFreeValList(c); image_free(image); return; } /* Set up lists */ /* Function list */ err = exprFuncListCreate(&f); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); err = exprFuncListInit(f); if(err != EXPR_ERROR_NOERROR) { printf("Function list init error. Functions may not be available.\n"); } /* Variable list */ err = exprValListCreate(&v); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); /* Constant list */ err = exprValListCreate(&c); if(err != EXPR_ERROR_NOERROR) { printf("Constants not available\n"); } else { err = exprValListInit(c); if(err != EXPR_ERROR_NOERROR) printf("Constant list init error. Constants may not be available.\n"); } /* Create and parse the expression */ /* Create */ err = exprCreate(&o, f, v, c, NULL, 0); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); /* Parse expression */ err = exprParse(o, expr); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); /* Create the image */ image = image_create(w, h); if(image == 0) { longjmp(jumper, ID_IMAGECREATEERROR); } /* Add width and height to variable list */ exprValListAdd(v, "w", (EXPRTYPE)w); exprValListAdd(v, "h", (EXPRTYPE)h); for(y = 0; y < h; y++) { for(x = 0; x < w; x++) { /* Add x and y */ exprValListAdd(v, "x", (EXPRTYPE)x); exprValListAdd(v, "y", (EXPRTYPE)y); /* Eval expression, ignoring errors */ exprEval(o); /* Get colors */ exprValListGet(v, "r", &r); exprValListGet(v, "g", &g); exprValListGet(v, "b", &b); /* Set pixel */ image_setpixel(image, x, y, (int)r, (int)g, (int)b); } } /* Save image */ image_save(image, name); /* Done */ longjmp(jumper, ID_IMAGENOERROR); } void main(void) { char name[MAXPATH] char tmp[10]; char expr[4096]; int sx, sy; printf("Image name to save: "); gets(name); printf("Image width: "); gets(tmp); sx = atoi(tmp); printf("Image height: "); gets(tmp); sy = atoi(tmp); printf("Color Expression (Use x, y, w, h Set r, g, b): "); gets(expr); gen_image(name, sx, sy, expr); }
This is an example application of this library. It is a graphics program that calculates the color value of a pixel based on it's X,Y co-ordinate. It uses a made-up image library called graphic-lib. It uses faster variable access by using the exprValListGetAddress function.
/* Include files */ #include <stdio.h> #include <stdlib.h> #include <setjmp.h> #include "graphiclib.h" #include "expreval.h" char *transerr(int err) { /* Translate error code into message */ } void gen_image(char *name, int w, int h, char *expr); { exprFuncList *f = NULL; exprValList *v = NULL; exprValList *c = NULL; exprObj *o = NULL; int x, y, err; jmp_buf jumper; int image; EXPRTYPE *v_x, *v_y; EXPRTYPE *v_r, *v_g, *v_b; /* Error handling */ err = setjmp(jumper); if(err) { if(err != ID_IMAGENOERROR) printf("Error %d occurred: %s\n", err, transerr(err)); exprFree(o); exprFreeFuncList(f); exprFreeValList(v); exprFreeValList(c); image_free(image); return; } /* Set up lists */ /* Function list */ err = exprFuncListCreate(&f); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); err = exprFuncListInit(f); if(err != EXPR_ERROR_NOERROR) { printf("Function list init error. Functions may not be available.\n"); } /* Variable list */ err = exprValListCreate(&v); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); /* Constant list */ err = exprValListCreate(&c); if(err != EXPR_ERROR_NOERROR) { printf("Constants not available\n"); } else { err = exprValListInit(c); if(err != EXPR_ERROR_NOERROR) printf("Constant list init error. Constants may not be available.\n"); } /* Create and parse the expression */ /* Create */ err = exprCreate(&o, f, v, c, NULL, 0); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); /* Parse expression */ err = exprParse(o, expr); if(err != EXPR_ERROR_NOERROR) longjmp(jumper, err); /* Create the image */ image = image_create(w, h); if(image == 0) { longjmp(jumper, ID_IMAGECREATEERROR); } /* Add width and height to variable list */ exprValListAdd(v, "w", (EXPRTYPE)w); exprValListAdd(v, "h", (EXPRTYPE)h); /* Add x and y to the list */ exprValListAdd(v, "x", 0.0); exprValListAdd(v, "y", 0.0); /* Add r, g, and b to the list */ exprValListAdd(v, "r", 0.0); exprValListAdd(v, "g", 0.0); exprValListAdd(b, "b", 0.0); /* Get addresses. Assume no error */ exprValListGetAddress(v, "x", &v_x); exprValListGetAddress(v, "y", &v_y); exprValListGetAddress(v, "r", &v_r); exprValListGetAddress(v, "g", &v_g); exprValListGetAddress(v, "g", &v_b); for(y = 0; y < h; y++) { for(x = 0; x < w; x++) { /* Directly set the x and y variables */ *v_x = (EXPRTYPE)x; *v_y = (EXPRTYPE)y; /* Eval expression, ignoring errors */ exprEval(o); /* Set pixel, using variables directly */ image_setpixel(image, x, y, (int)(*v_r), (int)(*v_g), (int)(*v_b)); } } /* Save image */ image_save(image, name); /* Done */ longjmp(jumper, ID_IMAGENOERROR); } void main(void) { char name[MAXPATH] char tmp[10]; char expr[4096]; int sx, sy; printf("Image name to save: "); gets(name); printf("Image width: "); gets(tmp); sx = atoi(tmp); printf("Image height: "); gets(tmp); sy = atoi(tmp); printf("Color Expression (Use x, y, w, h Set r, g, b): "); gets(expr); gen_image(name, sx, sy, expr); }