Annotation of Examples/AppKit/Graph/Expression.h, revision 1.1.1.1

1.1       root        1: 
                      2: #import <objc/Object.h>
                      3: #import <objc/hashtable.h>
                      4: #import <appkit/errors.h>
                      5: 
                      6:  /*
                      7:   * An Expression object parses and evaluates the text of a mathematical
                      8:   * expression.  The expression text may contain numbers, variables,
                      9:   * arithmetic operations and program defined functions.  For example,
                     10:   * an Expression object can parse the string "a+b*c", and if told
                     11:   * values for a, b and c, can calculate the value of the expression.
                     12:   *
                     13:   * This ability to parse and evaluate expressions at runtime makes it
                     14:   * easy for simple mathmatical programs to move beyond having canned example
                     15:   * functions compiled into their executables, and instead allow the user
                     16:   * to enter novel equations.  New formulas can be tried without recompiling
                     17:   * the application.
                     18:   * 
                     19:   * Typically an Expression is created and then told to parse some text
                     20:   * entered by the user.  The result of the parse is a parse tree, which is
                     21:   * then used by the Expression to evaluate the expression, given a set
                     22:   * of values for the expression's variables.  Variables can have either a
                     23:   * single value, or can be made to take on a series of values ("vector
                     24:   * variables").  For example, if you were graphing "A*x^2", you might
                     25:   * make A have a single value, but let x run over a range of
                     26:   * values that you would like to plot.
                     27:   *
                     28:   * The values of these vector variables can be set in two ways.  In the
                     29:   * first way, a list of values is passed in using the setVar:vector:numVals: 
                     30:   * method.  In the second way, the variable is given a range for its
                     31:   * values with the setVar:min:max: method.  The actual values are then
                     32:   * interpolated within that range.  The resolution of the expression
                     33:   * determines how many values are calculated.  If you mix these two styles
                     34:   * of vector variables, you must ensure that the number of explicitly
                     35:   * set values assigned to any variables matches the resolution of the
                     36:   * Expression.
                     37:   *
                     38:   * If there are more than one range-style vector variables in an Expression
                     39:   * they may be interpolated together or orthogonally, creating
                     40:   * multi-dimensional domains.  You can set the total number of dimensions over
                     41:   * which the expression is evaluated, and then set the dimension of each
                     42:   * vector variable that is being interpolated.
                     43:   *
                     44:   * Expressions always operate lazily, meaning that results are never
                     45:   * calculated until they are needed (usually when result values are asked
                     46:   * for). This means just changing the values of variables is inexpensive.
                     47:   *
                     48:   * Expressions have methods which allow an application to enumerate the
                     49:   * names of all the variables found by the parse.  This can be used to verify
                     50:   * that the expression is valid, beyond whether it was parsable.  For
                     51:   * example, in a certain context there may be a fixed set of variable names
                     52:   * that may be used.  After a successful parse, the application can run
                     53:   * through the names of all variables found, and ensure that they are all
                     54:   * appropriate.
                     55:   *
                     56:   * Expressions understand the arithmetic operators +, -, *, /.  % is used
                     57:   * for modulus (as in C) and ^ means is used to raise a quantity to a power.
                     58:   * Parentheses can be used for grouping.
                     59:   *
                     60:   * Expressions have certain "built in" functions (e.g., sin()) that are
                     61:   * understood.  It is also possible for applications to extend this default
                     62:   * set of functions.  New functions are registered with the name of the
                     63:   * function, the allowable number of arguments (can be variable), and a C
                     64:   * procedure to call to perform the evaluation.  The built in functions are:
                     65:   *
                     66:   *    sin(x), cos(x), tan(x)          - elementary trig
                     67:   *    asin(x), acos(x), atan(x)       - inverse elementary trig
                     68:   *    exp(x), ln(x)                   - exponential and natural log
                     69:   *    sqrt(x)                         - square root
                     70:   *
                     71:   * The constants "pi" and "e" are also built in.
                     72:   */
                     73: 
                     74: /* function supplied by term implementor for evaluation */
                     75: typedef float EXPTermEvalFunc(int numArgs, float *args);
                     76: 
                     77: /* enumeration state used to loop through all the variable names */
                     78: typedef void *EXPEnumState;
                     79: 
                     80: /* private type for representing terms */
                     81: typedef struct _EXPTerm *EXPTermPtr;
                     82: 
                     83: @interface Expression : Object {
                     84:     char *text;                        /* text of the expression */
                     85:     NXHashTable *varTerms;     /* terms of variables */
                     86:     EXPTermPtr parseTree;      /* terms from the parse */
                     87:     NXHashTable *validFuncs;   /* functions we know how to evaluate */
                     88:     int resolution;            /* number of points to calc for range vars */
                     89:     BOOL resultsValid;         /* are the results up to date? */
                     90:     short dimensions;          /* #axes of evaluation, defaults to 1 */
                     91:     float *results;            /* results of evaluation */
                     92:     float resultsMin;          /* min of all results */
                     93:     float resultsMax;          /* max of all results */
                     94: }
                     95: 
                     96: - init;
                     97:  /*
                     98:   * Initialize an Expression that was just created via "allocFromZone:".  You
                     99:   * cannot use a "+new" method to create Expression objects.  Below are some
                    100:   * examples of creating Expressions.  The first expression goes in the 
                    101:   * default malloc zone, the second is allocated in the same zone as
                    102:   * otherObject.
                    103:   *
                    104:   *    id myExp1, myExp2;
                    105:   *    myExp1 = [[Expression alloc] init];
                    106:   *    myExp2 = [[Expression allocFromZone:[otherObject zone]] init];
                    107:   *
                    108:   */
                    109: 
                    110: - free;
                    111:  /*
                    112:   * Frees the Expression, including any array of results returned by
                    113:   * the resultsVector:numVals: method.
                    114:   */
                    115: 
                    116: - (BOOL)parse:(const char *)expressionString;
                    117:  /*
                    118:   * Parses the text of an expression.  A parse tree of terms is built up as
                    119:   * a result of parsing expressionString.  The method returns whether the
                    120:   * string was a legal expression.  expressionString is copied and retained
                    121:   * within the Expression.
                    122:   */
                    123: 
                    124: - (const char *)text;
                    125:  /*
                    126:   * Returns the last text parsed by the Expression.
                    127:   */
                    128: 
                    129: - setResolution:(int)count;
                    130:  /*
                    131:   * Sets the resolution at which variables with a min and max range will
                    132:   * be subdivided.  All vectors in the Expression must have the same
                    133:   * number of values, which must be equal to the resolution of the
                    134:   * Expression, at the time the Expression is evaluated.  Note that setting
                    135:   * the list of values of a vector variable also changes the Expression's
                    136:   * resolution.
                    137:   */
                    138: 
                    139: - (int)resolution;
                    140:  /*
                    141:   * Returns the resolution of the Expression.
                    142:   */
                    143: 
                    144: - setVar:(const char *)varName value:(float)val;
                    145:  /*
                    146:   * Sets the value of the variable named varName to val.  The variable
                    147:   * will have that value as a constant throughout subsequent evaluations.
                    148:   */
                    149: 
                    150: - (float)varValue:(const char *)varName;
                    151:  /*
                    152:   * Returns the value of the variable varName.  If the variable is being
                    153:   * used as a vector, then its first value is returned.
                    154:   */
                    155: 
                    156: - setVar:(const char *)varName vector:(float *)vals numVals:(int)count;
                    157:  /*
                    158:   * Sets the values of the variable named varName to be the array
                    159:   * vals.  Count is the number of values in the vector.  This method
                    160:   * also sets the resolution of the Expression to be count.
                    161:   * All vectors in the Expression must have the same number of values,
                    162:   * which must be equal to the resolution of the Expression, at the
                    163:   * time the Expression is evaluated.  The list of vals should be a block
                    164:   * of floats returned from malloc.  It is NOT copied, but will be freed by
                    165:   * the Expression as part of its own free method.
                    166:   */
                    167: 
                    168: - varVector:(const char *)varName vector:(float **)vals numVals:(int *)count;
                    169:  /*
                    170:   * Returns the vector of values of the variable varName by setting
                    171:   * vals to point to the vector.  Count is set to the number of values.
                    172:   */
                    173: 
                    174: - setVar:(const char *)varName min:(float)minVal max:(float)maxVal;
                    175:  /*
                    176:   * Sets the range of the variable varName to run from minVal to maxVal.
                    177:   * The variables values will be determined by interpolating points
                    178:   * within this range.  The resolution of the Expression determines the
                    179:   * number of points that are taken within the range.
                    180:   */
                    181: 
                    182: - setVar:(const char *)varName dimension:(short)dimensionNum;
                    183:  /*
                    184:   * Sets the dimension within which the variable will vary.  The given value
                    185:   * must be between 0 and [expression dimensions]-1.
                    186:   */
                    187: 
                    188: - var:(const char *)varName dimension:(short *)dimensionNum;
                    189:  /*
                    190:   * Returns the dimension within which the variable will vary.
                    191:   */
                    192: 
                    193: - var:(const char *)varName min:(float *)minVal max:(float *)maxVal;
                    194:  /*
                    195:   * Returns the smallest and largest value of the variable varName by setting
                    196:   * minVal and maxVal.
                    197:   */
                    198: 
                    199: - (float)resultValue;
                    200:  /*
                    201:   * Returns the value of the Expression when evaluated with its current
                    202:   * attributes.  If there are vector variables in the Expression, it
                    203:   * returns the result using the first value of all vectors.
                    204:   */
                    205: 
                    206: - resultsVector:(float **)vals numVals:(int *)count;
                    207:  /*
                    208:   * Returns the values of the Expression when evaluated with its current
                    209:   * attributes, by setting vals to point to the vector of results.  count
                    210:   * is set to the number of results.  The number of results returned will be
                    211:   * resolution^dimensions.  If there are no vector variables in the
                    212:   * Expression, a single result is returned.
                    213:   */
                    214: 
                    215: - resultsMin:(float *)minVal max:(float *)maxVal;
                    216:  /*
                    217:   * Returns the smallest and largest value of the results by setting
                    218:   * minVal and maxVal.
                    219:   */
                    220: 
                    221: - setDimensions:(short)count;
                    222:  /*
                    223:   * Sets the number of evaluation dimensions.  The number of values in the
                    224:   * results vector is resolution^dimensions.  A given variable varies in one
                    225:   * dimension, as set by setVar:dimension:.
                    226:   */
                    227: 
                    228: - (short)dimensions;
                    229:  /*
                    230:   * Returns the number of evaluation dimensions.
                    231:   */
                    232: 
                    233: - (EXPEnumState)beginVariableEnumeration;
                    234: - (const char *)nextVariable:(EXPEnumState)state;
                    235: - (void)endVariableEnumeration:(EXPEnumState)state;
                    236:  /*
                    237:   * Used to walk through the names of all variables parsed.  Example:
                    238:   *    EXPEnumState state = [myExp beginVariableEnumeration];
                    239:   *    const char *varName;
                    240:   *    while (varName = [myExp nextVariable:state])
                    241:   *        printf("A variable named %s was parsed.\n", varName);
                    242:   *    [myExp endVariableEnumeration:state];
                    243:   */
                    244: 
                    245: - addFuncTerm:(const char *)name minArgs:(int)min maxArgs:(int)max
                    246:                                        evalFunc:(EXPTermEvalFunc *)func;
                    247:  /*
                    248:   * Adds a function to the set of functions this Expression can parse.
                    249:   * Functions look like "name(arg1, arg2,...)" in the text that is
                    250:   * parsed.  At evaluation time the C function func() will be called with
                    251:   * the values of the arguments.  The arguments are passed in an array of
                    252:   * floats(see the EXPTermEvalFunc typedef above).  Func must return the value
                    253:   * of the function with those arguments. min and max determine how many
                    254:   * arguments the function can accept.  For example, min=1, max=1 means
                    255:   * the function takes one argument.  A max value of -1 means an unbounded
                    256:   * number of arguments is allowed.
                    257:   */
                    258: 
                    259: - removeFuncTerm:(const char *)name;
                    260:  /*
                    261:   * Removes a function from the set of functions this Expression can parse.
                    262:   * Be careful not to send this to an Expression that has already parsed
                    263:   * text which made use of this function, since a reference to this FuncTerm
                    264:   * will be left dangling in the parse tree.
                    265:   */
                    266: 
                    267: @end
                    268: 
                    269: /* Error codes we raise */
                    270: 
                    271: typedef enum {
                    272:     expErrInvalidVarName = NX_APPBASE + 10000,
                    273:       /* An argument was passed referring to a variable whose name did not exist in the expression parsed. */
                    274:     expErrInvalidVarType,
                    275:       /* A variable was used in a way inconsistent with its type. */
                    276:     expErrMinMax,
                    277:       /* A min parameter was not less that its accompanying max parameter. */
                    278:     expErrNoText,
                    279:       /* A method could not complete because no expression had been parsed. */
                    280:     expErrResolutionMismatch,
                    281:       /* The number of points in the vector terms and the resolution of the Expression are inconsistent. */
                    282:     expFuncTypeInUse,
                    283:       /* A message was sent attempting to add a function which has already been declared. */
                    284:     expInvalidDimension
                    285:       /* A invalid value for a var's dimension was passed. */
                    286: } EXPError;
                    287: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.