Annotation of Examples/AppKit/Graph/expr.ym, revision 1.1.1.1

1.1       root        1: 
                      2: %{
                      3: /*
                      4:     expr.ym
                      5: 
                      6:     This file defines the grammar for parsing expressions.  To fully understand
                      7:     this code you will need to understand yacc.  The basic idea is that
                      8:     the parse tree is built from the bottom up as larger and larger
                      9:     sub-expressions are recognized by the grammar.  The nodes of the tree
                     10:     are created by the alloc* functions at the end of the file.  These
                     11:     functions are called by the rules of the grammar as various types of
                     12:     sub-expressions are recognized.  The one entry point to this file,
                     13:     _EXPParseExpression() encapsulates all the lex and yacc glue necessary
                     14:     to parse an expression.
                     15: */
                     16: 
                     17: #import <stdlib.h>
                     18: #import <string.h>
                     19: #import <stdio.h>
                     20: #import "exprDefs.h"
                     21: 
                     22: static Term *allocBinaryOpTerm(char op, Term *t1, Term *t2);
                     23: static Term *allocVarTerm(char *name);
                     24: static Term *allocConstantTerm(float value, BOOL isInt);
                     25: static Term *allocFuncTerm(char *name, TermList *args);
                     26: static void addAllocedTerm(Term *t);
                     27: static void yyerror(char *s);
                     28: extern yylex(), yyparse();
                     29: 
                     30: /* globals used to build up results of the parse */
                     31: static NXHashTable *ValidFuncTerms;    /* list of funcs we allow */
                     32: static NXHashTable *VarTerms;          /* vars found in expression */
                     33: static Term *CompleteExpr;             /* top of parse tree */
                     34: static BOOL ParseError;                        /* was there a parse error? */
                     35: static Term **TermsAlloced;            /* terms alloced during parse */
                     36: static int NumTermsAlloced;            /* #terms alloced during parse */
                     37: static NXZone *ParseZone;              /* zone to allocate parse results in */
                     38: 
                     39: /* initial size of TermsAlloced ptr array */
                     40: #define STACK_TERMS    200
                     41: 
                     42: %}
                     43: 
                     44: %token IDENTIFIER NUMBER INTEGER
                     45: 
                     46: %union {
                     47:     Term *node;
                     48:     TermList *list;
                     49:     float real;
                     50:     int integer;
                     51:     char *string;
                     52:     char character;
                     53: }
                     54: 
                     55: %token <real>          NUMBER
                     56: %token <integer>       INTEGER
                     57: %token <string>        IDENTIFIER
                     58: %token <character>     BADCHAR
                     59: %type  <node>          complete_expr expr function
                     60: %type  <list>          arglist
                     61: 
                     62: %start complete_expr
                     63: 
                     64: %left '+' '-'
                     65: %left '*' '/' '%'
                     66: %left UMINUS
                     67: %right '^'
                     68: 
                     69: %%
                     70: 
                     71: complete_expr: expr
                     72:                { CompleteExpr = $$; }
                     73:        ;
                     74: 
                     75: expr   : '(' expr ')'
                     76:                { $$ = $2; }
                     77:        | expr '+' expr
                     78:                { $$ = allocBinaryOpTerm('+', $1, $3); }
                     79:        | expr '-' expr
                     80:                { $$ = allocBinaryOpTerm('-', $1, $3); }
                     81:        | expr '*' expr
                     82:                { $$ = allocBinaryOpTerm('*', $1, $3); }
                     83:        | expr '/' expr
                     84:                { $$ = allocBinaryOpTerm('/', $1, $3); }
                     85:        | expr '%' expr
                     86:                { $$ = allocBinaryOpTerm('%', $1, $3); }
                     87:        | expr '^' expr
                     88:                { $$ = allocBinaryOpTerm('^', $1, $3); }
                     89:        | '-' expr      %prec UMINUS
                     90:                { $$ = _EXPAllocTerm(ParseZone, binOpTerm, 1, $2); 
                     91:                  $$->data.binOp.op = '-';
                     92:                }
                     93:        | function
                     94:        | IDENTIFIER
                     95:                { $$ = allocVarTerm($1); }
                     96:        | NUMBER
                     97:                { $$ = allocConstantTerm($1, NO); }
                     98:        | INTEGER
                     99:                { $$ = allocConstantTerm($1, YES); }
                    100:        ;
                    101: 
                    102: function : IDENTIFIER '(' ')'
                    103:                { $$ = allocFuncTerm($1, NULL); }
                    104:        | IDENTIFIER '(' arglist ')'
                    105:                { $$ = allocFuncTerm($1, $3); }
                    106:        ;
                    107: 
                    108: arglist : expr
                    109:                { $$ = NXZoneMalloc(NXDefaultMallocZone(), sizeof(TermList));
                    110:                  $$->terms[0] = $1;
                    111:                  $$->num = 1;
                    112:                }
                    113:        | arglist ',' expr
                    114:                { $$ = NXZoneRealloc(NXDefaultMallocZone(), $1,
                    115:                                sizeof(TermList) + $1->num*sizeof(Term *));
                    116:                  $$->terms[$$->num] = $3;
                    117:                  $$->num++;
                    118:                }
                    119:        ;
                    120: 
                    121: %%
                    122: 
                    123: /*
                    124:  * The main entry point into this file.  This routine sets up some globals
                    125:  * and calls yyparse(), a routine generated by yacc, to do the actual parse.
                    126:  * If the parse succeeds, the results are found in the globals, and are
                    127:  * returned to the caller.
                    128:  *
                    129:  * Note because of the globals this files uses to communicate between this
                    130:  * routine and the parsing guts, this is not thread safe (the yacc and lex
                    131:  * internals probably aren't thread safe either).  One easy solution to this
                    132:  * would be to put a mutex lock around the whole parse.
                    133:  *
                    134:  * If there is a parse error, since the tree is built bottom up it can be
                    135:  * difficult to free the data structures allocated before the error is
                    136:  * detected.  To solve this problem we keep a global buffer of pointers to
                    137:  * the parse tree nodes as they are allocated.  In the event of an error
                    138:  * we can then easily free them all regardless of the state of the parse tree.
                    139:  * Its also very important to empty the varTerms hash table in this case, so
                    140:  * it is not returned full of freed nodes.
                    141:  */
                    142: BOOL _EXPParseExpression(const char *text, NXHashTable *validTerms, Term **parseTree, NXHashTable *varTerms, NXZone *zone) {
                    143:     int parseRet;
                    144:     Term *termsAllocedStackSpace[STACK_TERMS];
                    145:     int i;
                    146: 
                    147:     CompleteExpr = NULL;       /* set globals to prepare for parsing */
                    148:     VarTerms = varTerms;
                    149:     ParseError = NO;
                    150:     ValidFuncTerms = validTerms;
                    151:     TermsAlloced = termsAllocedStackSpace;
                    152:     NumTermsAlloced = 0;
                    153:     ParseZone = zone;
                    154:     _EXPPrepareToScan(text);   /* sets up lex to scan the string */
                    155:     parseRet = yyparse();
                    156:     if (parseRet == 1 || ParseError) {
                    157:        for (i = 0; i < NumTermsAlloced; i++)
                    158:            _EXPFreeTerm(NULL, TermsAlloced[i]);
                    159:        *parseTree = NULL;
                    160:        NXEmptyHashTable(varTerms);
                    161:     } else
                    162:        *parseTree = CompleteExpr;
                    163:     if (NumTermsAlloced > STACK_TERMS)
                    164:        NXZoneFree(NXDefaultMallocZone(), TermsAlloced);
                    165:     return !(parseRet == 1 || ParseError);
                    166: }
                    167: 
                    168: /* allocates a new binary operator term */
                    169: static Term *allocBinaryOpTerm(char op, Term *t1, Term *t2) {
                    170:     Term *newTerm;
                    171: 
                    172:     newTerm = _EXPAllocTerm(ParseZone, binOpTerm, 2, t1, t2);
                    173:     newTerm->data.binOp.op = op;
                    174:     addAllocedTerm(newTerm);
                    175:     return newTerm;
                    176: }
                    177: 
                    178: /*
                    179:  * Allocates a new variable term.  We first check to see if the variable has
                    180:  * already been seen in this parse, and if so return the existing variable
                    181:  * term.  Otherwise we go ahead and allocate a new one.
                    182:  */
                    183: static Term *allocVarTerm(char *name) {
                    184:     Term *newTerm;
                    185:     Term key;
                    186: 
                    187:     key.tag = varTerm;
                    188:     key.data.var.name = name;
                    189:     newTerm = NXHashGet(VarTerms, &key);
                    190:     if (!newTerm) {
                    191:        newTerm = _EXPAllocTerm(ParseZone, varTerm, 0);
                    192:        newTerm->data.var.name = NXCopyStringBufferFromZone(name, ParseZone);
                    193:        NXHashInsert(VarTerms, newTerm);
                    194:        addAllocedTerm(newTerm);
                    195:     }
                    196:     free(name);
                    197:     return newTerm;
                    198: }
                    199: 
                    200: /* allocates a new constant term */
                    201: static Term *allocConstantTerm(float value, BOOL isInt) {
                    202:     Term *newTerm;
                    203: 
                    204:     newTerm = _EXPAllocTerm(ParseZone, constantTerm, 0);
                    205:     newTerm->data.constant.val = value;
                    206:     newTerm->data.constant.isInt = isInt;
                    207:     addAllocedTerm(newTerm);
                    208:     return newTerm;
                    209: }
                    210: 
                    211: /*
                    212:  * Allocates a new function term.  It looks up the function by name to see
                    213:  * if it is one we know how to parse.  If so, it makes sure the number of
                    214:  * arguments being passed is correct for the function.  If the function is
                    215:  * unknown or the number of arguments is wrong, we record the fact that
                    216:  * we've had a parse error in a global.
                    217:  */
                    218: static Term *allocFuncTerm(char *name, TermList *args) {
                    219:     Term *newTerm;
                    220:     Function *func;
                    221:     Function key;
                    222:     TermList noArgs;
                    223: 
                    224:     if (!args) {
                    225:        args = &noArgs;
                    226:        args->num = 0;
                    227:     }
                    228:     key.name = (char *)name;
                    229:     func = NXHashGet(ValidFuncTerms, &key);
                    230:     newTerm = _EXPAllocTerm(ParseZone, funcTerm, args->num);
                    231:     bcopy(args->terms, newTerm->subterms, args->num * sizeof(Term *));
                    232:     newTerm->data.func.type = func;
                    233:     if (!func || args->num < func->minArgs ||
                    234:                (args->num > func->maxArgs && func->maxArgs != -1))
                    235:        ParseError = YES;
                    236:     NXZoneFree(NXDefaultMallocZone(), args);
                    237:     free(name);
                    238:     addAllocedTerm(newTerm);
                    239:     return newTerm;
                    240: }
                    241: 
                    242: /*
                    243:  * Adds a term to the list of terms that we have allocated during this parse.
                    244:  * This routine allocates more space for Term pointers if necessary.  It knows
                    245:  * not to free the initial buffer of these pointers, since that buffer is
                    246:  * allocated on the stack by _EXPParseExpression().
                    247:  */
                    248: static void addAllocedTerm(Term *t) {
                    249:     Term **newSpace;
                    250: 
                    251:     if (!(NumTermsAlloced % STACK_TERMS) && NumTermsAlloced > 0) {
                    252:        newSpace = NXZoneMalloc(NXDefaultMallocZone(),
                    253:                        (NumTermsAlloced + STACK_TERMS) * sizeof(Term *));
                    254:        bcopy(TermsAlloced, newSpace, NumTermsAlloced * sizeof(Term *));
                    255:        if (NumTermsAlloced > STACK_TERMS)
                    256:            NXZoneFree(NXDefaultMallocZone(), TermsAlloced);
                    257:        TermsAlloced = newSpace;
                    258:     }
                    259:     TermsAlloced[NumTermsAlloced++] = t;
                    260: }
                    261: 
                    262: /* a piece of yacc glue called when there is a parse error */
                    263: static void yyerror(char *s) {}

unix.superglobalmegacorp.com

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