# ExprEval Library

## Contents

###

Introduction
License
Expression Syntax
Using ExprEval in an Application
Fast Variable Access
Using the Internal Functions and Constants
Creating Custom Functions
Reference
Compiling the ExprEval Library
Drawbacks/Problems
Problems and Solutions
Example Use

## Introduction

> ExprEval Help document. This document is probably full of bugs and mispellings. I may get around to proofreading it later.

> ExprEval is a C based expression evaluation library. It is entirely C based, but can be used in C++ programs as well.. 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.

## License

> This library is licensed under the ExprEval License.

## Expression Syntax

> 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 pound sign '#' and end at the end of the line.
> Example:

>     #Set the x value
>     x = d * cos(r);

>     #Set the y value
>     y = d * sin(r);

> 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

> Using ExprEval in an application can be a little difficult. You generally follow these steps:

> - 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
> 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.

> Function, variable, and constant list example:

>     exprFuncList *flist;
>     exprValList *vlist;
>     exprValList *clist;
>     exprObj *obj;
>     EXPRTYPE result;
>     int err;

>     /* Create function list */
>     err = exprFuncListCreate(&flist);
>     if(err != EXPR_ERROR_NOERROR)
>         {
>         ...
>         }

>     /* Initialize internal functions */
>     err = exprFuncListInit(flist);
>     if(err != EXPR_ERROR_NOERROR)
>         {
>         ...
>         }

>     /* Create variable list */
>     err = exprValListCreate(&vlist);
>     if(err != EXPR_ERROR_NOERROR)
>         {
>         ...
>         }

>     /* Create the constant list */
>     err = exprValListCreate(&clist);
>     if(err != EXPR_ERROR_NOERROR)
>         {
>         ...
>         }

>     /* Initialize internal constants */
>     err = exprValListInit(clist);
>     if(err != EXPR_ERROR_NOERROR)
>         {
>         ...
>         }

>     /* Add any application defined functions, constants, or variables to the lists here or down below */

> Expression object example:

>     err = exprCreate(&obj, flist, vlist, clist, NULL, 0);
>     if(err != EXPR_ERROR_NOERROR)
>         {
>         ...
>         }

>     /* 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(obj, "2+sin(M_PI)+3*x;");
>     if(err != EXPR_ERROR_NOERROR)
>         {
>         ...
>         }

>     /* Changes to the function or constant lists do not change the expression now */

> Expression evaluation example:

>     /* Add or change any variables */

>     err = exprEval(obj, &result);
>     if(err != EXPR_ERROR_NOERRO)
>         {
>         ...
>         }
>     else
>         {
>         printf("Expression Result: %f\n", result);
>         }

> Free the expression object and lists example:

>     exprFree(obj);
>     exprValListFree(vlist);
>     exprValListFree(clist);
>     exprFuncListFree(flist);

## Fast Variable Access

> 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. Fast variable access is always used internally in 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 used, the variable memory location is directly accessed 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;

## Using the Internal Functions and Constants

> 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.

## Creating Custom Functions

> Custom functions can be created for use by the library. This is how a function should look

>     int custom_func(exprObj *obj, exprNode *nodes, int nodecount, EXPRTYPE **refs, int refcount, EXPRTYPE *val)
>         {
>         }

> obj is a pointer to the expression object that called the function, nodes is a pointer to an array of nodes that are the parameters of this function, nodecount is the number of items in the array (the number of parameters), refs 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.

> Solving a function typically goes as follows:

> - Verifiy the number of arguments, if needed
> - 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:

>     int custom_func(exprObj *obj, exprNode *nodes, int count, EXPRTYPE **refs, int refcount, EXPRTYPE *val)
>         {
>         int err;
>         EXPRTYPE d1, d2;

>         /* Need 2 arguments */
>         if(nodecount != 2)
>             return EXPR_ERROR_BADNUMBERARGUMENTS;

>         /* Eval arg 1 */
>         err = exprEvalNode(obj, nodes, 0, &d1);
>         if(err != EXPR_ERROR_NOERROR)
>             return err;

>         /* Eval arg 2 */
>         err = exprEvalNode(obj, nodes, 1, &d2);
>         if(err != EXPR_ERROR_NOERROR)
>             return err;

>         /* Make sure arg 2 is not 0.0 */
>         if(d2 == 0.0)
>             {
>             *val = 0.0;
>             return EXPR_ERROR_NOERROR;
>             }

>         /* Do math */
>         *val = atan(d1 / d2); /* No need to worry about divide by zero */

>         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

## Reference

> Headers:

> - expreval.h - Include file

> Defines:

> - 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 - An item already exists or created.
> - 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_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.
> - EXPR_ERROR_OUTOFRANGE - A bad value was passed to a function.
> - EXPR_ERROR_USER - Custom error values need to be larger than this.

> 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)
> - exprFuncType - Custom function type. Defined as:
>   typedef int (*exprFuncType)(exprObj *obj, exprNode *nodes, int nodecount, EXPRTYPE **refs, int refcount, EXPRTYPE *val);
> - exprBreakFuncType - Breaker function pointer to stop evaluation if the result is nonzero. Defined as:
>   typedef int (*exprBreakFuncType)(exprObj *o);

> Version information functions:

> - void exprGetVersion(int *major, int *mino);
>   Comments:
>   - Gets the version of the ExprEval library
>   Parameters:
>   - *major - Pointer to int to get major version number
>   - *minor - Pointer to int to get minor version number
>   Returns:
>   - Nothing

> Function list functions:

> - int exprFuncListCreate(exprFuncList **flist);
>   Comments:
>   - Creates a function lists and updates a pointer to point to it
>   Parameters:
>   - **flist - Pointer to a pointer to the function list
>   Returns
>   - Error code of the function. On success, the pointer passed by address will point to the new function list
> - int exprFuncListAdd(exprFuncList *flist, exprFuncType ptr, char *name, int min, int max, int refmin, int refmax);
>   Comments:
>   - Adds a function to the function list. Returns error if the function already exists.
>   Parameters:
>   - *flist - 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
>   Returns:
>   - Error code of the function
> - int exprFuncListFree(exprFuncList *flist);
>   Comments:
>   - Free the function list entirely
>   Parameters:
>   - *flist - Pointer to the function list to free
>   Returns:
>   - Error code of the function
> - int exprFuncListClear(exprFuncList *flist);
>   Comments:
>   - Clear the functions from the function list
>   Parameters:
>   - *flist - Pointer to the function list to clear
>   Returns:
>   - Error code of the function
> - int exprFuncListInit(exprFuncList *flist);
>   Comments:
>   - Initializes internal functions into the funtion list
>   Parameters:
>   - *flist - Function list to initialize
>   Returns:
>   - Error code of the function

> Value list functions:

> - int exprValListCreate(exprValList **vlist);
>   Comments:
>   - Creates a value list for variables or constants
>   Parameters:
>   - **vlist - Pointer to a pointer to the value list.
>   Returns:
>   - Error code of the function. On success, the pointer will be updated to point to the value list
> - int exprValListAdd(exprValList *vlist, char *name, EXPRTYPE val);
>   Comments:
>   - Add a value in a value list. Returns error if value already exists.
>   Parameters:
>   - *vlist - Value list to add a value to
>   - *name - Name of the value to add
>   - val - Value of the value to add
>   Returns:
>   - Error code of the function
> - int exprValListSet(exprValList *vlist, char *name, EXPRTYPE val);
>   Comments:
>   - Set a value in a value list.
>   Parameters:
>   - *vlist - Value list to set a value in
>   - *name - Name of the value to set
>   - val - Value of the value to set
>   Returns:
>   - Error code of the function
> - int exprValListGet(exprValList *vlist, char *name, EXPRTYPE *val)
>   Comment:
>   - Get the value of a variable or constant in a value list
>   Parameters:
>   - *vlist - Value list to use
>   - *name - Name of the value to get
>   - *val - Pointer to variable to get the value
>   Returns:
>   - Error code of the function
> - int exprValListAddAddress(exprValList *vlist, char *name, EXPRTYPE *addr)
>   Comment:
>   - This function is used to add a named value to the value list, but uses an outside variable such as a stack variable to store the value. This outside variable is used to set/get the value instead of the internal list value. You must ensure that this outside variable exists as long as the expression is using it's address.
>   Parameters:
>   - *vlist - Value list to use
>   - *name - Name of the value to add
>   - *addr - Address of the value being added
>   Returns:
>   - Error code of the function
> - int exprValListGetAddress(exprValList *vlist, char *name, EXPRTYPE **addr)
>   Comment:
>   - Get the memory address of a variable in a value list
>   Parameters:
>   - *vlist - Value list to use
>   - *name - Name of the value to get
>   - **addr - Pointer to a pointer to store the address of the value This will be NULL if the name is not in the list.
>   Returns:
>   - Error code of the function
> - void *exprValListGetNext(exprValList *vlist, char **name, EXPRTYPE *value, EXPRTYPE** addr, void *cookie);
>   Comment:
>   - This is used to enumerate the items in the value list. Do NOT change the list while enumerating the items. Any of the information items can be NULL if it is not needed.
>   Parameters:
>   - *vlist - Value list to use
>   - **name - Address of a pointer that will point to the name. Do not edit the name.
>   - *value - The current value of the item.
>   - **addr - Address of a pointer to store the address of the value.
>   - *cookie - NULL to find the first item, the return value to find subsequent items.
>   Returns:
>   - NULL if the item could not be found. Otherwise a cookie to be used to find additional items.
> - int exprValListFree(exprValList *vlist);
>   Comments:
>   - Completely free the value list
>   Parameters:
>   - *vlist - Value list to free
>   Returns:
>   - Error code of the function
> - int exprValListClear(exprValList *vlist);
>   Comments:
>   - Set the values in the list to 0.0
>   Parameters:
>   - *vlist - Value list to reset
>   Returns:
>   - Error code of the function
> - int exprValListInit(exprValList *vlist);
>   Comments:
>   - Initialize internal constants into a value list
>   Paramters:
>   - *vlist - Value list to initialize
>   Returns:
>   - Error code of the function

> Expression functions:

> - int exprCreate(exprObj **obj, exprFuncList *flist, exprValList *vlist, exprValList *clist, exprBreakFuncType breaker, void *userdata);
>   Comments:
>   - Create an expression object to use
>   Parameters:
>   - **obj - Pointer to a pointer to an expression object
>   - *flist - Function list to associate with the expression
>   - *vlist - Variable value list to associate with the expression
>   - *clist - Constant value list 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
>   Returns:
>   - Error code of the function
> - int exprFree(exprObj *obj);
>   Comments:
>   - Completely free the expression object
>   Paramters:
>   - *obj - Expression object to free
>   Returns:
>   - Error code of the function
> - int exprClear(exprObj *obj);
>   Comments:
>   - Clear an expression, but keep list and callback associations. You can then parse another expression without calling create
>   Parameters:
>   - *obj - Expression object to clear
>   Returns:
>   - Error code of the function
> - int exprParse(exprObj *obj, char *expr);
>   Comments:
>   - Parse an expression string into an expression object
>   Paramters:
>   - *obj - Expression object to use
>   - *expr - Expression string to parse
>   Returns:
>   - Error code of the function
> - int exprEval(exprObj *obj, EXPRTYPE *val);
>   Comments:
>   - Evaluate a parsed expression. This function does not reset the breaker count at each call, but instead accumulates the count until the breaker function is called. Then the count is reset to the value specified in exprSetBreakerCount.
>   Paramters:
>   - *obj - Expression object to evaluate
>   - *val = Pointer to variable to get result of evaluation. This can be NULL if the result is not needed.
>   Returns:
>   - Error code of the function
> - int exprEvalNode(exprObj *obj, exprNode *nodes, int curnode, EXPRTYPE *val);
>   Comments:
>   - Evaluate a node of an expression. Used by custom functions
>   Parameters:
>   - *obj - Expression object being used
>   - *nodes - Pointer to a node or list of nodes
>   - curnode - Index to the node to evaluate
>   - *val - Pointer to variable to get evaluation result
>   Returns:
>   - Error code of the function
> - exprFuncList *exprGetFuncList(exprObj *obj);
>   Comments:
>   - Gets the function list associated with an expression
>   Parameters:
>   - *obj - expression object
>   Returns:
>   - Pointer fo an exprFuncList object or NULL
> - exprValList *exprGetVarList(exprObj *obj);
>   Comments:
>   - Gets the variable list associated with an expression
>   Parameters:
>   - *obj - expression object
>   Returns:
>   - Pointer to an exprValList object or NULL
> - exprValList *exprGetConstList(exprObj *obj);
>   Comments:
>   - Gets the constant list associated with an expression
>   Parameters:
>   - *obj - expression object
>   Returns:
>   - Pointer to an exprValList object or NULL
> - exprBreakFuncType exprGetBreakFunc(exprObj *obj);
>   Comments:
>   - Gets the breaker callback of the expression
>   Parameters:
>   - *obj - expression object
>   Returns:
>   - Pointer to the callback function or NULL
> - int exprGetBreakResult(exprObj *obj);
>   Comments:
>   - Get the result of the breaker function
>   Parameters:
>   - *obj - expression object
>   Returns:
>   - zero to continue, nonzero to break
> - void* exprGetUserData(exprObj *obj);
>   Comments:
>   - Gets the user data associated with an expression
>   Parameters:
>   - *obj - expression object
>   Returns:
>   - User data
> - void exprSetUserData(exprObj *obj, void *userdata);
>   Comments:
>   - Sets the user data of an expression
>   Parameters:
>   - *obj - expresion object
>   - userdata - user data to set
>   Returns:
>   - Nothing
> - void exprSetBreakCount(exprObj *obj, int count);
>   Comments:
>   - Set how often the breaker function is tested. The default is 100000. This means the breaker function is tested once every 100000 times the exprEvalNode function is called for an expression. A smaller value tests the breaker function more often and a larger value tests the breaker function less. The breaker value is NOT reset during each call to exprEval, but is accumulated across calles to exprEval until the breaker function is finally called.
>   Parameters:
>   - *obj - expression object
>   - count - how many times exprEvalNode gets called before the breaker function is tested
>   Returns:
>   - Nothing
> - void exprGetErrorPosition(exprObj *obj, int *start, int *end);
>   Comments:
>   - Gets the start and ending positions in the expression string of the last parse error. The positions include any newline characters that may be in the string.
>   Parameters:
>   - *obj - expression object
>   - *start - pointer to an integer to get the start error position, -1 if unknown
>   - *end - pointer to an integer to get the end error position, -1 if unknown
>   Returns:
>   - Nothing

> Some useful functions

> - int exprValidIdent(char *name);
>   Comments:
>   - Determine if an identifier is valid
>   Parameters:
>   - *name - identifier to check
>   Returns:
>   - 0 on invalid. anything else on valid

## Compiling the ExprEval library

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" for the header file.

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. You should not have to change to much. I have tried to stick as close to ANSI/ISO C as I can.

## Drawbacks/Problems

The following is a list of some basic drawbacks of this library:

- This library is an expression evaluator, and nothing else. It does not simplify expressions and it does not do advanced math such as calculating the integrals and differentials of expression.
- This library has no way of detecting overflows except for those caused by the internal math routines. Adding two very very large numbers may cause an overflow to occur.
- This library is not super easy to use in an application. It has been designed to give much control to the developer. Because of this, the function/value lists are seperate from the expression objects, allowing the developer to use them however they need.
- There is no way to delete a single function, variable, or constant from a list. This is because I see no real need to do so because of the way the library works. There is no need to delete function from a function list or constants from a constant list. There are are also no decent reasons to delete variables from a variable list until you are completely done and delete all of them.

## Problems and Solutions

- Variables do not seem to change in a release/optimized build.
  I have noticed a small problem with this. Rarely, a variable may not appear to change in a release build. The reason is to do with compiler optimizations. For example, look at the following code:

  >     EXPRTYPE k;

  >     /* Add variable to the list */
  >     exprValListAddAddress(list, "k", &k);

  >     k = 0.0;

  >     /* Evaluate expression */
  >     for(int x = 0; x < 100; x++)
  >         {
  >         exprEval(expr, &result);

  >         doSomething(k);
  >         }

  Inside the loop, the variable 'k' does not appear to be changing, so the compiler may optimize it by loading it into a register before the loop and not accessing it from memory during the loop, even if the expression does change it. One way to avoid this is to use the 'volatile' keyword with the variable. Then the compiler must accesss it from memory each time it is accessed.

  >     volatile EXPRTYPE k;

  >     /* Add variable to the list */
  >     exprValListAddAddress(list, "k", (EXPRTYPE*)&k);

  >     k = 0.0;

  >     /* Evaluate expression */
  >     for(int x = 0; x < 100; x++)
  >         {
  >         exprEval(expr, &result);

  >         doSomething(k);
  >         }

## Example Use with Fast Variable Access

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.

Note that this codes has not actually been tested. See the test applications (test and imagegen) for other examples.

>     /* 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;
>         EXPRTYPE global_value;

>         /* 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);

>         /* A way to add global variables that can be used by two different lists. */
>         exprValListAddAddress(v, "global", &global_value);
>         /* exprValListAddAddress(v2, "global", &global_value); */

>         /* Also, exprValListAddAddress can be used to add variables directly.
>            Instead of:

>            EXPRTYPE *a;

>            exprValListAdd(v, "a", 0.0);
>            exprValListGetAddresss(v, "a", &a);

>            You can do:

>            EXPRTYPE a;

>            exprValListAddAddresss(v, "a", &a);

>            If you do this, you must ensure that the stack variable exists as long
>            as it is used by expression, otherwise it may cause a memory access
>            violation. */

>         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);
>         }