ftp.nice.ch/pub/next/graphics/3d/NXplot3d.3.2.NIHS.bs.tar.gz#/NXplot3d.3.2/Source/Expression.h

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.