This is Expression.h in view mode; [Download] [Up]
#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;
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.