home *** CD-ROM | disk | FTP | other *** search
-
- #import <objc/Object.h>
- #import <objc/hashtable.h>
- #import <appkit/errors.h>
-
- /*
- * An Expression object parses and evaluates the text of a mathematical
- * expression. The expression text may contain numbers, variables,
- * arithmetic operations and program defined functions. For example,
- * an Expression object can parse the string "a+b*c", and if told
- * values for a, b and c, can calculate the value of the expression.
- *
- * This ability to parse and evaluate expressions at runtime makes it
- * easy for simple mathmatical programs to move beyond having canned example
- * functions compiled into their executables, and instead allow the user
- * to enter novel equations. New formulas can be tried without recompiling
- * the application.
- *
- * Typically an Expression is created and then told to parse some text
- * entered by the user. The result of the parse is a parse tree, which is
- * then used by the Expression to evaluate the expression, given a set
- * of values for the expression's variables. Variables can have either a
- * single value, or can be made to take on a series of values ("vector
- * variables"). For example, if you were graphing "A*x^2", you might
- * make A have a single value, but let x run over a range of
- * values that you would like to plot.
- *
- * The values of these vector variables can be set in two ways. In the
- * first way, a list of values is passed in using the setVar:vector:numVals:
- * method. In the second way, the variable is given a range for its
- * values with the setVar:min:max: method. The actual values are then
- * interpolated within that range. The resolution of the expression
- * determines how many values are calculated. If you mix these two styles
- * of vector variables, you must ensure that the number of explicitly
- * set values assigned to any variables matches the resolution of the
- * Expression.
- *
- * If there are more than one range-style vector variables in an Expression
- * they may be interpolated together or orthogonally, creating
- * multi-dimensional domains. You can set the total number of dimensions over
- * which the expression is evaluated, and then set the dimension of each
- * vector variable that is being interpolated.
- *
- * Expressions always operate lazily, meaning that results are never
- * calculated until they are needed (usually when result values are asked
- * for). This means just changing the values of variables is inexpensive.
- *
- * Expressions have methods which allow an application to enumerate the
- * names of all the variables found by the parse. This can be used to verify
- * that the expression is valid, beyond whether it was parsable. For
- * example, in a certain context there may be a fixed set of variable names
- * that may be used. After a successful parse, the application can run
- * through the names of all variables found, and ensure that they are all
- * appropriate.
- *
- * Expressions understand the arithmetic operators +, -, *, /. % is used
- * for modulus (as in C) and ^ means is used to raise a quantity to a power.
- * Parentheses can be used for grouping.
- *
- * Expressions have certain "built in" functions (e.g., sin()) that are
- * understood. It is also possible for applications to extend this default
- * set of functions. New functions are registered with the name of the
- * function, the allowable number of arguments (can be variable), and a C
- * procedure to call to perform the evaluation. The built in functions are:
- *
- * sin(x), cos(x), tan(x) - elementary trig
- * asin(x), acos(x), atan(x) - inverse elementary trig
- * exp(x), ln(x) - exponential and natural log
- * sqrt(x) - square root
- *
- * The constants "pi" and "e" are also built in.
- */
-
- /* function supplied by term implementor for evaluation */
- typedef float EXPTermEvalFunc(int numArgs, float *args);
-
- /* enumeration state used to loop through all the variable names */
- typedef void *EXPEnumState;
-
- /* private type for representing terms */
- typedef struct _EXPTerm *EXPTermPtr;
-
- @interface Expression : Object {
- char *text; /* text of the expression */
- NXHashTable *varTerms; /* terms of variables */
- EXPTermPtr parseTree; /* terms from the parse */
- NXHashTable *validFuncs; /* functions we know how to evaluate */
- int resolution; /* number of points to calc for range vars */
- BOOL resultsValid; /* are the results up to date? */
- short dimensions; /* #axes of evaluation, defaults to 1 */
- float *results; /* results of evaluation */
- float resultsMin; /* min of all results */
- float resultsMax; /* max of all results */
- }
-
- - init;
- /*
- * Initialize an Expression that was just created via "allocFromZone:". You
- * cannot use a "+new" method to create Expression objects. Below are some
- * examples of creating Expressions. The first expression goes in the
- * default malloc zone, the second is allocated in the same zone as
- * otherObject.
- *
- * id myExp1, myExp2;
- * myExp1 = [[Expression alloc] init];
- * myExp2 = [[Expression allocFromZone:[otherObject zone]] init];
- *
- */
-
- - free;
- /*
- * Frees the Expression, including any array of results returned by
- * the resultsVector:numVals: method.
- */
-
- - (BOOL)parse:(const char *)expressionString;
- /*
- * Parses the text of an expression. A parse tree of terms is built up as
- * a result of parsing expressionString. The method returns whether the
- * string was a legal expression. expressionString is copied and retained
- * within the Expression.
- */
-
- - (const char *)text;
- /*
- * Returns the last text parsed by the Expression.
- */
-
- - setResolution:(int)count;
- /*
- * Sets the resolution at which variables with a min and max range will
- * be subdivided. All vectors in the Expression must have the same
- * number of values, which must be equal to the resolution of the
- * Expression, at the time the Expression is evaluated. Note that setting
- * the list of values of a vector variable also changes the Expression's
- * resolution.
- */
-
- - (int)resolution;
- /*
- * Returns the resolution of the Expression.
- */
-
- - setVar:(const char *)varName value:(float)val;
- /*
- * Sets the value of the variable named varName to val. The variable
- * will have that value as a constant throughout subsequent evaluations.
- */
-
- - (float)varValue:(const char *)varName;
- /*
- * Returns the value of the variable varName. If the variable is being
- * used as a vector, then its first value is returned.
- */
-
- - setVar:(const char *)varName vector:(float *)vals numVals:(int)count;
- /*
- * Sets the values of the variable named varName to be the array
- * vals. Count is the number of values in the vector. This method
- * also sets the resolution of the Expression to be count.
- * All vectors in the Expression must have the same number of values,
- * which must be equal to the resolution of the Expression, at the
- * time the Expression is evaluated. The list of vals should be a block
- * of floats returned from malloc. It is NOT copied, but will be freed by
- * the Expression as part of its own free method.
- */
-
- - varVector:(const char *)varName vector:(float **)vals numVals:(int *)count;
- /*
- * Returns the vector of values of the variable varName by setting
- * vals to point to the vector. Count is set to the number of values.
- */
-
- - setVar:(const char *)varName min:(float)minVal max:(float)maxVal;
- /*
- * Sets the range of the variable varName to run from minVal to maxVal.
- * The variables values will be determined by interpolating points
- * within this range. The resolution of the Expression determines the
- * number of points that are taken within the range.
- */
-
- - setVar:(const char *)varName dimension:(short)dimensionNum;
- /*
- * Sets the dimension within which the variable will vary. The given value
- * must be between 0 and [expression dimensions]-1.
- */
-
- - var:(const char *)varName dimension:(short *)dimensionNum;
- /*
- * Returns the dimension within which the variable will vary.
- */
-
- - var:(const char *)varName min:(float *)minVal max:(float *)maxVal;
- /*
- * Returns the smallest and largest value of the variable varName by setting
- * minVal and maxVal.
- */
-
- - (float)resultValue;
- /*
- * Returns the value of the Expression when evaluated with its current
- * attributes. If there are vector variables in the Expression, it
- * returns the result using the first value of all vectors.
- */
-
- - resultsVector:(float **)vals numVals:(int *)count;
- /*
- * Returns the values of the Expression when evaluated with its current
- * attributes, by setting vals to point to the vector of results. count
- * is set to the number of results. The number of results returned will be
- * resolution^dimensions. If there are no vector variables in the
- * Expression, a single result is returned.
- */
-
- - resultsMin:(float *)minVal max:(float *)maxVal;
- /*
- * Returns the smallest and largest value of the results by setting
- * minVal and maxVal.
- */
-
- - setDimensions:(short)count;
- /*
- * Sets the number of evaluation dimensions. The number of values in the
- * results vector is resolution^dimensions. A given variable varies in one
- * dimension, as set by setVar:dimension:.
- */
-
- - (short)dimensions;
- /*
- * Returns the number of evaluation dimensions.
- */
-
- - (EXPEnumState)beginVariableEnumeration;
- - (const char *)nextVariable:(EXPEnumState)state;
- - (void)endVariableEnumeration:(EXPEnumState)state;
- /*
- * Used to walk through the names of all variables parsed. Example:
- * EXPEnumState state = [myExp beginVariableEnumeration];
- * const char *varName;
- * while (varName = [myExp nextVariable:state])
- * printf("A variable named %s was parsed.\n", varName);
- * [myExp endVariableEnumeration:state];
- */
-
- - addFuncTerm:(const char *)name minArgs:(int)min maxArgs:(int)max
- evalFunc:(EXPTermEvalFunc *)func;
- /*
- * Adds a function to the set of functions this Expression can parse.
- * Functions look like "name(arg1, arg2,...)" in the text that is
- * parsed. At evaluation time the C function func() will be called with
- * the values of the arguments. The arguments are passed in an array of
- * floats(see the EXPTermEvalFunc typedef above). Func must return the value
- * of the function with those arguments. min and max determine how many
- * arguments the function can accept. For example, min=1, max=1 means
- * the function takes one argument. A max value of -1 means an unbounded
- * number of arguments is allowed.
- */
-
- - removeFuncTerm:(const char *)name;
- /*
- * Removes a function from the set of functions this Expression can parse.
- * Be careful not to send this to an Expression that has already parsed
- * text which made use of this function, since a reference to this FuncTerm
- * will be left dangling in the parse tree.
- */
-
- @end
-
- /* Error codes we raise */
-
- typedef enum {
- expErrInvalidVarName = NX_APPBASE + 10000,
- /* An argument was passed referring to a variable whose name did not exist in the expression parsed. */
- expErrInvalidVarType,
- /* A variable was used in a way inconsistent with its type. */
- expErrMinMax,
- /* A min parameter was not less that its accompanying max parameter. */
- expErrNoText,
- /* A method could not complete because no expression had been parsed. */
- expErrResolutionMismatch,
- /* The number of points in the vector terms and the resolution of the Expression are inconsistent. */
- expFuncTypeInUse,
- /* A message was sent attempting to add a function which has already been declared. */
- expInvalidDimension
- /* A invalid value for a var's dimension was passed. */
- } EXPError;
-
-