diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/misc.c | 1864 |
1 files changed, 1864 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/misc.c b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/misc.c new file mode 100644 index 00000000..eef73e64 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/misc.c @@ -0,0 +1,1864 @@ +/* + * misc.c + * + * Manage tokens, regular expressions. + * Print methods for debugging + * Compute follow lists onto tail ends of rules. + * + * The following functions are visible: + * + * int addTname(char *); Add token name + * int addTexpr(char *); Add token expression + * int Tnum(char *); Get number of expr/token + * void Tklink(char *, char *); Link a name with an expression + * int hasAction(expr); Does expr already have action assigned? + * void setHasAction(expr); Indicate that expr now has an action + * Entry *newEntry(char *,int); Create new table entry with certain size + * void list_add(ListNode **list, char *e) + * void list_free(ListNode **list, int freeData); *** MR10 *** + * void list_apply(ListNode *list, void (*f)()) + * void lexclass(char *m); switch to new/old lexical class + * void lexmode(int i); switch to old lexical class i + * + * SOFTWARE RIGHTS + * + * We reserve no LEGAL rights to the Purdue Compiler Construction Tool + * Set (PCCTS) -- PCCTS is in the public domain. An individual or + * company may do whatever they wish with source code distributed with + * PCCTS or the code generated by PCCTS, including the incorporation of + * PCCTS, or its output, into commerical software. + * + * We encourage users to develop software with PCCTS. However, we do ask + * that credit is given to us for developing PCCTS. By "credit", + * we mean that if you incorporate our source code into one of your + * programs (commercial product, research project, or otherwise) that you + * acknowledge this fact somewhere in the documentation, research report, + * etc... If you like PCCTS and have developed a nice tool with the + * output, please mention that you developed it using PCCTS. In + * addition, we ask that this header remain intact in our source code. + * As long as these guidelines are kept, we expect to continue enhancing + * this system and expect to make other tools available as they are + * completed. + * + * ANTLR 1.33 + * Terence Parr + * Parr Research Corporation + * with Purdue University and AHPCRC, University of Minnesota + * 1989-2001 + */ + +#include <stdio.h> +#include "pcctscfg.h" +#include "set.h" +#include "syn.h" +#include "hash.h" +#include "generic.h" +#include "dlgdef.h" +#include <ctype.h> + +static int tsize=TSChunk; /* size of token str arrays */ + +static void +#ifdef __USE_PROTOS +RemapForcedTokensInSyntaxDiagram(Node *); +#else +RemapForcedTokensInSyntaxDiagram(); +#endif + + /* T o k e n M a n i p u l a t i o n */ + +/* + * add token 't' to the TokenStr/Expr array. Make more room if necessary. + * 't' is either an expression or a token name. + * + * There is only one TokenStr array, but multiple ExprStr's. Therefore, + * for each lex class (element of lclass) we must extend the ExprStr array. + * ExprStr's and TokenStr are always all the same size. + * + * Also, there is a Texpr hash table for each automaton. + */ +static void +#ifdef __USE_PROTOS +Ttrack( char *t ) +#else +Ttrack( t ) +char *t; +#endif +{ + if ( TokenNum >= tsize ) /* terminal table overflow? */ + { + char **p; + int i, more, j; + + more = TSChunk * (1 + ((TokenNum-tsize) / TSChunk)); + tsize += more; + TokenStr = (char **) realloc((char *)TokenStr, tsize*sizeof(char *)); + require(TokenStr != NULL, "Ttrack: can't extend TokenStr"); + for (i=0; i<NumLexClasses; i++) + { + lclass[i].exprs = (char **) + realloc((char *)lclass[i].exprs, tsize*sizeof(char *)); + require(lclass[i].exprs != NULL, "Ttrack: can't extend ExprStr"); + for (p= &lclass[i].exprs[tsize-more],j=1; j<=more; j++) *p++ = NULL; + } + for (p= &TokenStr[tsize-more],i=1; i<=more; i++) *p++ = NULL; + lexmode( CurrentLexClass ); /* reset ExprStr in case table moved */ + } + /* note: we use the actual ExprStr/TokenStr array + * here as TokenInd doesn't exist yet + */ + if ( *t == '"' ) ExprStr[TokenNum] = t; + else TokenStr[TokenNum] = t; +} + +static Expr * +#ifdef __USE_PROTOS +newExpr( char *e ) +#else +newExpr( e ) +char *e; +#endif +{ + Expr *p = (Expr *) calloc(1, sizeof(Expr)); + require(p!=NULL, "newExpr: cannot alloc Expr node"); + + p->expr = e; + p->lclass = CurrentLexClass; + return p; +} + +/* switch to lexical class/mode m. This amounts to creating a new + * lex mode if one does not already exist and making ExprStr point + * to the correct char string array. We must also switch Texpr tables. + * + * BTW, we need multiple ExprStr arrays because more than one automaton + * may have the same label for a token, but with different expressions. + * We need to track an expr for each automaton. If we disallowed this + * feature, only one ExprStr would be required. + */ +void +#ifdef __USE_PROTOS +lexclass( char *m ) +#else +lexclass( m ) +char *m; +#endif +{ + int i; + TermEntry *p; + static char EOFSTR[] = "\"@\""; + + if ( hash_get(Tname, m) != NULL ) + { + warn(eMsg1("lexclass name conflicts with token/errclass label '%s'",m)); + } + /* does m already exist? */ + i = LexClassIndex(m); + if ( i != -1 ) {lexmode(i); return;} + /* must make new one */ + NumLexClasses++; + CurrentLexClass = NumLexClasses-1; + require(NumLexClasses<=MaxLexClasses, "number of allowable lexclasses exceeded\nIncrease MaxLexClasses in generic.h and recompile all C files"); + lclass[CurrentLexClass].classnum = m; + lclass[CurrentLexClass].exprs = (char **) calloc(tsize, sizeof(char *)); + require(lclass[CurrentLexClass].exprs!=NULL, + "lexclass: cannot allocate ExprStr"); + lclass[CurrentLexClass].htable = newHashTable(); + ExprStr = lclass[CurrentLexClass].exprs; + Texpr = lclass[CurrentLexClass].htable; + /* define EOF for each automaton */ + p = newTermEntry( EOFSTR ); + p->token = EofToken; /* couldn't have remapped tokens yet, use EofToken */ + hash_add(Texpr, EOFSTR, (Entry *)p); + list_add(&ExprOrder, (void *)newExpr(EOFSTR)); + /* note: we use the actual ExprStr array + * here as TokenInd doesn't exist yet + */ + ExprStr[EofToken] = EOFSTR; +} + +void +#ifdef __USE_PROTOS +lexmode( int i ) +#else +lexmode( i ) +int i; +#endif +{ + require(i<NumLexClasses, "lexmode: invalid mode"); + ExprStr = lclass[i].exprs; + Texpr = lclass[i].htable; + CurrentLexClass = i; +} + +/* return index into lclass array of lexical class. return -1 if nonexistent */ +int +#ifdef __USE_PROTOS +LexClassIndex( char *cl ) +#else +LexClassIndex( cl ) +char *cl; +#endif +{ + int i; + + for (i=0; i<NumLexClasses; i++) + { + if ( strcmp(lclass[i].classnum, cl) == 0 ) return i; + } + return -1; +} + +int +#ifdef __USE_PROTOS +hasAction( char *expr ) +#else +hasAction( expr ) +char *expr; +#endif +{ + TermEntry *p; + require(expr!=NULL, "hasAction: invalid expr"); + + p = (TermEntry *) hash_get(Texpr, expr); + require(p!=NULL, eMsg1("hasAction: expr '%s' doesn't exist",expr)); + return (p->action!=NULL); +} + +void +#ifdef __USE_PROTOS +setHasAction( char *expr, char *action ) +#else +setHasAction( expr, action ) +char *expr; +char *action; +#endif +{ + TermEntry *p; + require(expr!=NULL, "setHasAction: invalid expr"); + + p = (TermEntry *) hash_get(Texpr, expr); + require(p!=NULL, eMsg1("setHasAction: expr '%s' doesn't exist",expr)); + p->action = action; +} + +ForcedToken * +#ifdef __USE_PROTOS +newForcedToken(char *token, int tnum) +#else +newForcedToken(token, tnum) +char *token; +int tnum; +#endif +{ + ForcedToken *ft = (ForcedToken *) calloc(1, sizeof(ForcedToken)); + require(ft!=NULL, "out of memory"); + ft->token = token; + ft->tnum = tnum; + return ft; +} + +/* + * Make a token indirection array that remaps token numbers and then walk + * the appropriate symbol tables and SynDiag to change token numbers + */ +void +#ifdef __USE_PROTOS +RemapForcedTokens(void) +#else +RemapForcedTokens() +#endif +{ + ListNode *p; + ForcedToken *q; + int max_token_number=0; /* MR9 23-Sep-97 Removed "unsigned" */ + int i; + + if ( ForcedTokens == NULL ) return; + + /* find max token num */ + for (p = ForcedTokens->next; p!=NULL; p=p->next) + { + q = (ForcedToken *) p->elem; + if ( q->tnum > max_token_number ) max_token_number = q->tnum; + } + fprintf(stderr, "max token number is %d\n", max_token_number); + + /* make token indirection array */ + TokenInd = (int *) calloc(max_token_number+1, sizeof(int)); + LastTokenCounted = TokenNum; + TokenNum = max_token_number+1; + require(TokenInd!=NULL, "RemapForcedTokens: cannot allocate TokenInd"); + + /* fill token indirection array and change token id htable ; swap token indices */ + for (i=1; i<TokenNum; i++) TokenInd[i] = i; + for (p = ForcedTokens->next; p!=NULL; p=p->next) + { + TermEntry *te; + int old_pos, t; + + q = (ForcedToken *) p->elem; + fprintf(stderr, "%s forced to %d\n", q->token, q->tnum); + te = (TermEntry *) hash_get(Tname, q->token); + require(te!=NULL, "RemapForcedTokens: token not in hash table"); + old_pos = te->token; + fprintf(stderr, "Before: TokenInd[old_pos==%d] is %d\n", old_pos, TokenInd[old_pos]); + fprintf(stderr, "Before: TokenInd[target==%d] is %d\n", q->tnum, TokenInd[q->tnum]); + q = (ForcedToken *) p->elem; + t = TokenInd[old_pos]; + TokenInd[old_pos] = q->tnum; + TokenInd[q->tnum] = t; + te->token = q->tnum; /* update token type id symbol table */ + fprintf(stderr, "After: TokenInd[old_pos==%d] is %d\n", old_pos, TokenInd[old_pos]); + fprintf(stderr, "After: TokenInd[target==%d] is %d\n", q->tnum, TokenInd[q->tnum]); + + /* Change the token number in the sym tab entry for the exprs + * at the old position of the token id and the target position + */ + /* update expr at target (if any) of forced token id */ + if ( q->tnum < TokenNum ) /* is it a valid position? */ + { + for (i=0; i<NumLexClasses; i++) + { + if ( lclass[i].exprs[q->tnum]!=NULL ) + { + /* update the symbol table for this expr */ + TermEntry *e = (TermEntry *) hash_get(lclass[i].htable, lclass[i].exprs[q->tnum]); + require(e!=NULL, "RemapForcedTokens: expr not in hash table"); + e->token = old_pos; + fprintf(stderr, "found expr '%s' at target %d in lclass[%d]; changed to %d\n", + lclass[i].exprs[q->tnum], q->tnum, i, old_pos); + } + } + } + /* update expr at old position (if any) of forced token id */ + for (i=0; i<NumLexClasses; i++) + { + if ( lclass[i].exprs[old_pos]!=NULL ) + { + /* update the symbol table for this expr */ + TermEntry *e = (TermEntry *) hash_get(lclass[i].htable, lclass[i].exprs[old_pos]); + require(e!=NULL, "RemapForcedTokens: expr not in hash table"); + e->token = q->tnum; + fprintf(stderr, "found expr '%s' for id %s in lclass[%d]; changed to %d\n", + lclass[i].exprs[old_pos], q->token, i, q->tnum); + } + } + } + + /* Update SynDiag */ + RemapForcedTokensInSyntaxDiagram((Node *)SynDiag); +} + +static void +#ifdef __USE_PROTOS +RemapForcedTokensInSyntaxDiagram(Node *p) +#else +RemapForcedTokensInSyntaxDiagram(p) +Node *p; +#endif +{ + Junction *j = (Junction *) p; + RuleRefNode *r = (RuleRefNode *) p; + TokNode *t = (TokNode *)p; + + if ( p==NULL ) return; + require(p->ntype>=1 && p->ntype<=NumNodeTypes, "Remap...: invalid diagram node"); + switch ( p->ntype ) + { + case nJunction : + if ( j->visited ) return; + if ( j->jtype == EndRule ) return; + j->visited = TRUE; + RemapForcedTokensInSyntaxDiagram( j->p1 ); + RemapForcedTokensInSyntaxDiagram( j->p2 ); + j->visited = FALSE; + return; + case nRuleRef : + RemapForcedTokensInSyntaxDiagram( r->next ); + return; + case nToken : + if ( t->remapped ) return; /* we've been here before */ + t->remapped = 1; + fprintf(stderr, "remapping %d to %d\n", t->token, TokenInd[t->token]); + t->token = TokenInd[t->token]; + RemapForcedTokensInSyntaxDiagram( t->next ); + return; + case nAction : + RemapForcedTokensInSyntaxDiagram( ((ActionNode *)p)->next ); + return; + default : + fatal_internal("invalid node type"); + } +} + +/* + * Add a token name. Return the token number associated with it. If it already + * exists, then return the token number assigned to it. + * + * Track the order in which tokens are found so that the DLG output maintains + * that order. It also lets us map token numbers to strings. + */ +int +#ifdef __USE_PROTOS +addTname( char *token ) +#else +addTname( token ) +char *token; +#endif +{ + TermEntry *p; + require(token!=NULL, "addTname: invalid token name"); + + if ( (p=(TermEntry *)hash_get(Tname, token)) != NULL ) return p->token; + p = newTermEntry( token ); + Ttrack( p->str ); + p->token = TokenNum++; + hash_add(Tname, token, (Entry *)p); + return p->token; +} + +/* This is the same as addTname except we force the TokenNum to be tnum. + * We don't have to use the Forced token stuff as no tokens will have + * been defined with #tokens when this is called. This is only called + * when a #tokdefs meta-op is used. + */ +int +#ifdef __USE_PROTOS +addForcedTname( char *token, int tnum ) +#else +addForcedTname( token, tnum ) +char *token; +int tnum; +#endif +{ + TermEntry *p; + require(token!=NULL, "addTname: invalid token name"); + + if ( (p=(TermEntry *)hash_get(Tname, token)) != NULL ) return p->token; + p = newTermEntry( token ); + Ttrack( p->str ); + p->token = tnum; + hash_add(Tname, token, (Entry *)p); + return p->token; +} + +/* + * Add a token expr. Return the token number associated with it. If it already + * exists, then return the token number assigned to it. + */ +int +#ifdef __USE_PROTOS +addTexpr( char *expr ) +#else +addTexpr( expr ) +char *expr; +#endif +{ + TermEntry *p; + require(expr!=NULL, "addTexpr: invalid regular expression"); + + if ( (p=(TermEntry *)hash_get(Texpr, expr)) != NULL ) return p->token; + p = newTermEntry( expr ); + Ttrack( p->str ); + /* track the order in which they occur */ + list_add(&ExprOrder, (void *)newExpr(p->str)); + p->token = TokenNum++; + hash_add(Texpr, expr, (Entry *)p); + return p->token; +} + +/* return the token number of 'term'. Return 0 if no 'term' exists */ +int +#ifdef __USE_PROTOS +Tnum( char *term ) +#else +Tnum( term ) +char *term; +#endif +{ + TermEntry *p; + require(term!=NULL, "Tnum: invalid terminal"); + + if ( *term=='"' ) p = (TermEntry *) hash_get(Texpr, term); + else p = (TermEntry *) hash_get(Tname, term); + if ( p == NULL ) return 0; + else return p->token; +} + +/* associate a Name with an expr. If both have been already assigned + * token numbers, then an error is reported. Add the token or expr + * that has not been added if no error. This 'represents' the #token + * ANTLR pseudo-op. If both have not been defined, define them both + * linked to same token number. + */ +void +#ifdef __USE_PROTOS +Tklink( char *token, char *expr ) +#else +Tklink( token, expr ) +char *token; +char *expr; +#endif +{ + TermEntry *p, *q; + require(token!=NULL && expr!=NULL, "Tklink: invalid token name and/or expr"); + + p = (TermEntry *) hash_get(Tname, token); + q = (TermEntry *) hash_get(Texpr, expr); + if ( p != NULL && q != NULL ) /* both defined */ + { + warn( eMsg2("token name %s and rexpr %s already defined; ignored", + token, expr) ); + return; + } + if ( p==NULL && q==NULL ) /* both not defined */ + { + int t = addTname( token ); + q = newTermEntry( expr ); + hash_add(Texpr, expr, (Entry *)q); + q->token = t; + /* note: we use the actual ExprStr array + * here as TokenInd doesn't exist yet + */ + ExprStr[t] = q->str; + /* track the order in which they occur */ + list_add(&ExprOrder, (void *)newExpr(q->str)); + return; + } + if ( p != NULL ) /* one is defined, one is not */ + { + q = newTermEntry( expr ); + hash_add(Texpr, expr, (Entry *)q); + q->token = p->token; + ExprStr[p->token] = q->str; /* both expr and token str defined now */ + list_add(&ExprOrder, (void *)newExpr(q->str)); + } + else /* trying to associate name with expr here*/ + { + p = newTermEntry( token ); + hash_add(Tname, token, (Entry *)p); + p->token = q->token; + TokenStr[p->token] = p->str;/* both expr and token str defined now */ + } +} + +/* + * Given a string, this function allocates and returns a pointer to a + * hash table record of size 'sz' whose "str" pointer is reset to a position + * in the string table. + */ +Entry * +#ifdef __USE_PROTOS +newEntry( char *text, int sz ) +#else +newEntry( text, sz ) +char *text; +int sz; +#endif +{ + Entry *p; + require(text!=NULL, "new: NULL terminal"); + + if ( (p = (Entry *) calloc(1,sz)) == 0 ) + { + fatal_internal("newEntry: out of memory for terminals\n"); + exit(PCCTS_EXIT_FAILURE); + } + p->str = mystrdup(text); + + return(p); +} + +/* + * add an element to a list. + * + * Any non-empty list has a sentinel node whose 'elem' pointer is really + * a pointer to the last element. (i.e. length(list) = #elemIn(list)+1). + * Elements are appended to the list. + */ +void +#ifdef __USE_PROTOS +list_add( ListNode **list, void *e ) +#else +list_add( list, e ) +ListNode **list; +void *e; +#endif +{ + ListNode *p, *tail; + require(e!=NULL, "list_add: attempting to add NULL list element"); + + p = newListNode; + require(p!=NULL, "list_add: cannot alloc new list node"); + p->elem = e; + if ( *list == NULL ) + { + ListNode *sentinel = newListNode; + require(sentinel!=NULL, "list_add: cannot alloc sentinel node"); + *list=sentinel; + sentinel->next = p; + sentinel->elem = (char *)p; /* set tail pointer */ + } + else /* find end of list */ + { + tail = (ListNode *) (*list)->elem; /* get tail pointer */ + tail->next = p; + (*list)->elem = (char *) p; /* reset tail */ + } +} + +/* MR10 list_free() frees the ListNode elements in the list */ +/* MR10 if freeData then free the data elements of the list too */ + +void +#ifdef __USE_PROTOS +list_free(ListNode **list,int freeData) +#else +list_free(list,freeData) + ListNode **list; + int freeData; +#endif +{ + ListNode *p; + ListNode *next; + + if (list == NULL) return; + if (*list == NULL) return; + for (p=*list; p != NULL; p=next) { + next=p->next; + if (freeData && p->elem != NULL) { + free( (char *) p->elem); + }; + free( (char *) p); + }; + *list=NULL; +} + +void +#ifdef __USE_PROTOS +list_apply( ListNode *list, void (*f)(void *) ) +#else +list_apply( list, f ) +ListNode *list; +void (*f)(); +#endif +{ + ListNode *p; + require(f!=NULL, "list_apply: NULL function to apply"); + + if ( list == NULL ) return; + for (p = list->next; p!=NULL; p=p->next) (*f)( p->elem ); +} + +/* MR27 */ + +#ifdef __USE_PROTOS +int list_search_cstring(ListNode *list, char * cstring) +#else +int list_search_cstring(list, cstring) + ListNode * list; + char * cstring; +#endif +{ + ListNode *p; + if (list == NULL ) return 0; + for (p = list->next; p!=NULL; p=p->next) { + if (p->elem == NULL) continue; + if (0 == strcmp((char *) p->elem , cstring)) return 1; + } + return 0; +} + + /* F O L L O W C y c l e S t u f f */ + +/* make a key based upon (rulename, computation, k value). + * Computation values are 'i'==FIRST, 'o'==FOLLOW. + */ + +/* MR10 Make the key all characters so it can be read easily */ +/* MR10 by a simple dump program. Also, separates */ +/* MR10 'o' and 'i' from rule name */ + +char * +#ifdef __USE_PROTOS +Fkey( char *rule, int computation, int k ) +#else +Fkey( rule, computation, k ) +char *rule; +int computation; +int k; +#endif +{ + static char key[MaxRuleName+2+2+1]; /* MR10 */ + int i; + + if ( k > 99 ) /* MR10 */ + fatal("k>99 is too big for this implementation of ANTLR!\n"); /* MR10 */ + if ( (i=strlen(rule)) > MaxRuleName ) /* MR10 */ + fatal( eMsgd("rule name > max of %d\n", MaxRuleName) ); /* MR10 */ + strcpy(key,rule); + +/* MR10 */ key[i]='*'; +/* MR10 */ key[i+1] = (char) computation; /* MR20 G. Hobbelt */ +/* MR10 */ if (k < 10) { +/* MR10 */ key[i+2] = (char) ( '0' + k); +/* MR10 */ key[i+3] = '\0'; +/* MR10 */ } else { +/* MR10 */ key[i+2] = (char) ( '0' + k/10); +/* MR10 */ key[i+3] = (char) ( '0' + k % 10); +/* MR10 */ key[i+4] = '\0'; +/* MR10 */ }; + + return key; +} + +/* Push a rule onto the kth FOLLOW stack */ +void +#ifdef __USE_PROTOS +FoPush( char *rule, int k ) +#else +FoPush( rule, k ) +char *rule; +int k; +#endif +{ + RuleEntry *r; + require(rule!=NULL, "FoPush: tried to push NULL rule"); + require(k<=CLL_k, "FoPush: tried to access non-existent stack"); + + /*fprintf(stderr, "FoPush(%s)\n", rule);*/ + r = (RuleEntry *) hash_get(Rname, rule); + if ( r == NULL ) {fatal_internal( eMsg1("rule %s must be defined but isn't", rule) );} + if ( FoStack[k] == NULL ) /* Does the kth stack exist yet? */ + { + /*fprintf(stderr, "allocating FoStack\n");*/ + FoStack[k] = (int *) calloc(FoStackSize, sizeof(int)); + require(FoStack[k]!=NULL, "FoPush: cannot allocate FOLLOW stack\n"); + } + if ( FoTOS[k] == NULL ) + { + FoTOS[k]=FoStack[k]; + *(FoTOS[k]) = r->rulenum; + } + else + { +#ifdef MEMCHK + require(valid(FoStack[k]), "FoPush: invalid FoStack"); +#endif + if ( FoTOS[k] >= &(FoStack[k][FoStackSize-1]) ) + fatal( eMsgd("exceeded max depth of FOLLOW recursion (%d)\n", + FoStackSize) ); + require(FoTOS[k]>=FoStack[k], + eMsg1("FoPush: FoStack stack-ptr is playing out of its sandbox", + rule)); + ++(FoTOS[k]); + *(FoTOS[k]) = r->rulenum; + } + { + /* +**** int *p; +**** fprintf(stderr, "FoStack[k=%d]:\n", k); +**** for (p=FoStack[k]; p<=FoTOS[k]; p++) +**** { +**** fprintf(stderr, "\t%s\n", RulePtr[*p]->rname); +**** } + */ + } +} + +/* Pop one rule off of the FOLLOW stack. TOS ptr is NULL if empty. */ +void +#ifdef __USE_PROTOS +FoPop( int k ) +#else +FoPop( k ) +int k; +#endif +{ + require(k<=CLL_k, "FoPop: tried to access non-existent stack"); + /*fprintf(stderr, "FoPop\n");*/ + require(FoTOS[k]>=FoStack[k]&&FoTOS[k]<=&(FoStack[k][FoStackSize-1]), + "FoPop: FoStack stack-ptr is playing out of its sandbox"); + if ( FoTOS[k] == FoStack[k] ) FoTOS[k] = NULL; + else (FoTOS[k])--; +} + +/* Compute FOLLOW cycle. + * Mark all FOLLOW sets for rules in cycle as incomplete. + * Then, save cycle on the cycle list (Cycles) for later resolution. + * The Cycle is stored in the form: + * (head of cycle==croot, rest of rules in cycle==cyclicDep) + * + * e.g. (Fo means "FOLLOW of", "-->" means requires or depends on) + * + * Fo(x)-->Fo(a)-->Fo(b)-->Fo(c)-->Fo(x) + * ^----Infinite recursion (cycle) + * + * the cycle would be: x -> {a,b,c} or stored as (x,{a,b,c}). Fo(x) depends + * on the FOLLOW of a,b, and c. The root of a cycle is always complete after + * Fo(x) finishes. Fo(a,b,c) however are not. It turns out that all rules + * in a FOLLOW cycle have the same FOLLOW set. + */ +void +#ifdef __USE_PROTOS +RegisterCycle( char *rule, int k ) +#else +RegisterCycle( rule, k ) +char *rule; +int k; +#endif +{ + CacheEntry *f; + Cycle *c; + int *p; + RuleEntry *r; + require(rule!=NULL, "RegisterCycle: tried to register NULL rule"); + require(k<=CLL_k, "RegisterCycle: tried to access non-existent stack"); + + /*fprintf(stderr, "RegisterCycle(%s)\n", rule);*/ + /* Find cycle start */ + r = (RuleEntry *) hash_get(Rname, rule); + require(r!=NULL,eMsg1("rule %s must be defined but isn't", rule)); + require(FoTOS[k]>=FoStack[k]&&FoTOS[k]<=&(FoStack[k][FoStackSize-1]), + eMsg1("RegisterCycle(%s): FoStack stack-ptr is playing out of its sandbox", + rule)); +/*** if ( FoTOS[k]<FoStack[k]||FoTOS[k]>&(FoStack[k][FoStackSize-1]) ) +**** { +**** fprintf(stderr, "RegisterCycle(%s): FoStack stack-ptr is playing out of its sandbox\n", +**** rule); +**** fprintf(stderr, "RegisterCycle: sp==0x%x out of bounds 0x%x...0x%x\n", +**** FoTOS[k], FoStack[k], &(FoStack[k][FoStackSize-1])); +**** exit(PCCTS_EXIT_FAILURE); +**** } +****/ + +#ifdef MEMCHK + require(valid(FoStack[k]), "RegisterCycle: invalid FoStack"); +#endif + for (p=FoTOS[k]; *p != r->rulenum && p >= FoStack[k]; --p) {;} + require(p>=FoStack[k], "RegisterCycle: FoStack is screwed up beyond belief"); + if ( p == FoTOS[k] ) return; /* don't worry about cycles to oneself */ + + /* compute cyclic dependents (rules in cycle except head) */ + c = newCycle; + require(c!=NULL, "RegisterCycle: couldn't alloc new cycle"); + c->cyclicDep = empty; + c->croot = *p++; /* record root of cycle */ + for (; p<=FoTOS[k]; p++) + { + /* Mark all dependent rules as incomplete */ + f = (CacheEntry *) hash_get(Fcache, Fkey(RulePtr[*p]->rname,'o',k)); + if ( f==NULL ) + { + f = newCacheEntry( Fkey(RulePtr[*p]->rname,'o',k) ); + hash_add(Fcache, Fkey(RulePtr[*p]->rname,'o',k), (Entry *)f); + } + f->incomplete = TRUE; + + set_orel(*p, &(c->cyclicDep)); /* mark rule as dependent of croot */ + } + list_add(&(Cycles[k]), (void *)c); +} + +/* make all rules in cycle complete + * + * while ( some set has changed ) do + * for each cycle do + * if degree of FOLLOW set for croot > old degree then + * update all FOLLOW sets for rules in cyclic dependency + * change = TRUE + * endif + * endfor + * endwhile + */ +void +#ifdef __USE_PROTOS +ResolveFoCycles( int k ) +#else +ResolveFoCycles( k ) +int k; +#endif +{ + ListNode *p, *q; + Cycle *c; + int changed = 1; + CacheEntry *f,*g; + int r; +/* int i; */ /* MR10 not useful */ + unsigned d; + + unsigned *cursor; /* MR10 */ + unsigned *origin; /* MR10 */ + + /*fprintf(stderr, "Resolving following cycles for %d\n", k);*/ + while ( changed ) + { + changed = 0; +/* MR10 i = 0; */ + for (p = Cycles[k]->next; p!=NULL; p=p->next) + { + c = (Cycle *) p->elem; + /*fprintf(stderr, "cycle %d: %s -->", i++, RulePtr[c->croot]->rname);*/ + /*s_fprT(stderr, c->cyclicDep);*/ + /*fprintf(stderr, "\n");*/ + f = (CacheEntry *) + hash_get(Fcache, Fkey(RulePtr[c->croot]->rname,'o',k)); + require(f!=NULL, eMsg1("FOLLOW(%s) must be in cache but isn't", RulePtr[c->croot]->rname) ); + if ( (d=set_deg(f->fset)) > c->deg ) + { + /*fprintf(stderr, "Fo(%s) has changed\n", RulePtr[c->croot]->rname);*/ + changed = 1; + c->deg = d; /* update cycle FOLLOW set degree */ + +/* MR10 */ origin=set_pdq(c->cyclicDep); +/* MR10 */ for (cursor=origin; *cursor != nil; cursor++) { +/* MR10 */ r=*cursor; + +/******** while ( !set_nil(c->cyclicDep) ) { *****/ +/******** r = set_int(c->cyclicDep); *****/ +/******** set_rm(r, c->cyclicDep); *****/ + + /*fprintf(stderr, "updating Fo(%s)\n", RulePtr[r]->rname);*/ + g = (CacheEntry *) + hash_get(Fcache, Fkey(RulePtr[r]->rname,'o',k)); + require(g!=NULL, eMsg1("FOLLOW(%s) must be in cache but isn't", RulePtr[r]->rname) ); + set_orin(&(g->fset), f->fset); + g->incomplete = FALSE; + } +/* MR10 */ free( (char *) origin); +/* MR10 */ origin=NULL; + } + } +/* MR10 - this if statement appears to be meaningless since i is always 0 */ +/* MR10 if ( i == 1 ) changed = 0; */ /* if only 1 cycle, no need to repeat */ + } + /* kill Cycle list */ + for (q = Cycles[k]->next; q != NULL; q=p) + { + p = q->next; + set_free( ((Cycle *)q->elem)->cyclicDep ); + free((char *)q); + } + free( (char *)Cycles[k] ); + Cycles[k] = NULL; +} + + + /* P r i n t i n g S y n t a x D i a g r a m s */ + +static void +#ifdef __USE_PROTOS +pBlk( Junction *q, int btype ) +#else +pBlk( q, btype ) +Junction *q; +int btype; +#endif +{ + int k,a; + Junction *alt, *p; + + q->end->pvisited = TRUE; + if ( btype == aLoopBegin ) + { + require(q->p2!=NULL, "pBlk: invalid ()* block"); + PRINT(q->p1); + alt = (Junction *)q->p2; + PRINT(alt->p1); + if ( PrintAnnotate ) + { + printf(" /* Opt "); + k = 1; + while ( !set_nil(alt->fset[k]) ) + { + s_fprT(stdout, alt->fset[k]); + if ( k++ == CLL_k ) break; + if ( !set_nil(alt->fset[k]) ) printf(", "); + } + printf(" */\n"); + } + return; + } + for (a=1,alt=q; alt != NULL; alt= (Junction *) alt->p2, a++) + { + if ( alt->p1 != NULL ) PRINT(alt->p1); + if ( PrintAnnotate ) + { + printf( " /* [%d] ", alt->altnum); + k = 1; + while ( !set_nil(alt->fset[k]) ) + { + s_fprT(stdout, alt->fset[k]); + if ( k++ == CLL_k ) break; + if ( !set_nil(alt->fset[k]) ) printf(", "); + } + if ( alt->p2 == NULL && btype == aOptBlk ) + printf( " (optional branch) */\n"); + else printf( " */\n"); + } + + /* ignore implied empty alt of Plus blocks */ + if ( alt->p2 != NULL && ((Junction *)alt->p2)->ignore ) break; + + if ( alt->p2 != NULL && !(((Junction *)alt->p2)->p2==NULL && btype == aOptBlk) ) + { + if ( pLevel == 1 ) + { + printf("\n"); + if ( a+1==pAlt1 || a+1==pAlt2 ) printf("=>"); + printf("\t"); + } + else printf(" "); + printf("|"); + if ( pLevel == 1 ) + { + p = (Junction *) ((Junction *)alt->p2)->p1; + while ( p!=NULL ) + { + if ( p->ntype==nAction ) + { + p=(Junction *)((ActionNode *)p)->next; + continue; + } + if ( p->ntype!=nJunction ) + { + break; + } + if ( p->jtype==EndBlk || p->jtype==EndRule ) + { + p = NULL; + break; + } + p = (Junction *)p->p1; + } + if ( p==NULL ) printf("\n\t"); /* Empty alt? */ + } + } + } + q->end->pvisited = FALSE; +} + +/* How to print out a junction */ +void +#ifdef __USE_PROTOS +pJunc( Junction *q ) +#else +pJunc( q ) +Junction *q; +#endif +{ + int dum_k; + int doing_rule; + require(q!=NULL, "pJunc: NULL node"); + require(q->ntype==nJunction, "pJunc: not junction"); + + if ( q->pvisited == TRUE ) return; + q->pvisited = TRUE; + switch ( q->jtype ) + { + case aSubBlk : + if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); + if ( q->end->p1 != NULL && ((Junction *)q->end->p1)->ntype==nJunction && + ((Junction *)q->end->p1)->jtype == EndRule ) doing_rule = 1; + else doing_rule = 0; + pLevel++; + if ( pLevel==1 ) + { + if ( pAlt1==1 ) printf("=>"); + printf("\t"); + } + else printf(" "); + if ( doing_rule ) + { + if ( pLevel==1 ) printf(" "); + pBlk(q,q->jtype); + } + else { + printf("("); + if ( pLevel==1 ) printf(" "); + pBlk(q,q->jtype); + if ( pLevel>1 ) printf(" "); + printf(")"); + } + if ( q->guess ) printf("?"); + pLevel--; + if ( PrintAnnotate ) freeBlkFsets(q); + if ( q->end->p1 != NULL ) PRINT(q->end->p1); + break; + case aOptBlk : + if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); + pLevel++; + if ( pLevel==1 ) + { + if ( pAlt1==1 ) printf("=>"); + printf("\t"); + } + else printf(" "); + printf("{"); + if ( pLevel==1 ) printf(" "); + pBlk(q,q->jtype); + if ( pLevel>1 ) printf(" "); + else printf("\n\t"); + printf("}"); + pLevel--; + if ( PrintAnnotate ) freeBlkFsets(q); + if ( q->end->p1 != NULL ) PRINT(q->end->p1); + break; + case aLoopBegin : + if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); + pLevel++; + if ( pLevel==1 ) + { + if ( pAlt1==1 ) printf("=>"); + printf("\t"); + } + else printf(" "); + printf("("); + if ( pLevel==1 ) printf(" "); + pBlk(q,q->jtype); + if ( pLevel>1 ) printf(" "); + else printf("\n\t"); + printf(")*"); + pLevel--; + if ( PrintAnnotate ) freeBlkFsets(q); + if ( q->end->p1 != NULL ) PRINT(q->end->p1); + break; + case aLoopBlk : + if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); + pBlk(q,q->jtype); + if ( PrintAnnotate ) freeBlkFsets(q); + break; + case aPlusBlk : + if ( PrintAnnotate ) First(q, 1, q->jtype, &dum_k); + pLevel++; + if ( pLevel==1 ) + { + if ( pAlt1==1 ) printf("=>"); + printf("\t"); + } + else printf(" "); + printf("("); + if ( pLevel==1 ) printf(" "); + pBlk(q,q->jtype); + if ( pLevel>1 ) printf(" "); + printf(")+"); + pLevel--; + if ( PrintAnnotate ) freeBlkFsets(q); + if ( q->end->p1 != NULL ) PRINT(q->end->p1); + break; + case EndBlk : + break; + case RuleBlk : + printf( "\n%s :\n", q->rname); + PRINT(q->p1); + if ( q->p2 != NULL ) PRINT(q->p2); + break; + case Generic : + if ( q->p1 != NULL ) PRINT(q->p1); + q->pvisited = FALSE; + if ( q->p2 != NULL ) PRINT(q->p2); + break; + case EndRule : + printf( "\n\t;\n"); + break; + } + q->pvisited = FALSE; +} + +/* How to print out a rule reference node */ +void +#ifdef __USE_PROTOS +pRuleRef( RuleRefNode *p ) +#else +pRuleRef( p ) +RuleRefNode *p; +#endif +{ + require(p!=NULL, "pRuleRef: NULL node"); + require(p->ntype==nRuleRef, "pRuleRef: not rule ref node"); + + printf( " %s", p->text); + PRINT(p->next); +} + +/* How to print out a terminal node */ +void +#ifdef __USE_PROTOS +pToken( TokNode *p ) +#else +pToken( p ) +TokNode *p; +#endif +{ + require(p!=NULL, "pToken: NULL node"); + require(p->ntype==nToken, "pToken: not token node"); + + if ( p->wild_card ) printf(" ."); + printf( " %s", TerminalString(p->token)); + PRINT(p->next); +} + +/* How to print out a terminal node */ +void +#ifdef __USE_PROTOS +pAction( ActionNode *p ) +#else +pAction( p ) +ActionNode *p; +#endif +{ + require(p!=NULL, "pAction: NULL node"); + require(p->ntype==nAction, "pAction: not action node"); + + PRINT(p->next); +} + + /* F i l l F o l l o w L i s t s */ + +/* + * Search all rules for all rule reference nodes, q to rule, r. + * Add q->next to follow list dangling off of rule r. + * i.e. + * + * r: -o-R-o-->o--> Ptr to node following rule r in another rule + * | + * o--> Ptr to node following another reference to r. + * + * This is the data structure employed to avoid FOLLOW set computation. We + * simply compute the FIRST (reach) of the EndRule Node which follows the + * list found at the end of all rules which are referenced elsewhere. Rules + * not invoked by other rules have no follow list (r->end->p1==NULL). + * Generally, only start symbols are not invoked by another rule. + * + * Note that this mechanism also gives a free cross-reference mechanism. + * + * The entire syntax diagram is layed out like this: + * + * SynDiag + * | + * v + * o-->R1--o + * | + * o-->R2--o + * | + * ... + * | + * o-->Rn--o + * + */ +void +#ifdef __USE_PROTOS +FoLink( Node *p ) +#else +FoLink( p ) +Node *p; +#endif +{ + RuleEntry *q; + Junction *j = (Junction *) p; + RuleRefNode *r = (RuleRefNode *) p; + + if ( p==NULL ) return; + require(p->ntype>=1 && p->ntype<=NumNodeTypes, + eMsgd("FoLink: invalid diagram node: ntype==%d",p->ntype)); + switch ( p->ntype ) + { + case nJunction : + if ( j->fvisited ) return; + if ( j->jtype == EndRule ) return; + j->fvisited = TRUE; + FoLink( j->p1 ); + FoLink( j->p2 ); +/* MR14 */ +/* MR14 */ /* Need to determine whether the guess block is an */ +/* MR14 */ /* of the form (alpha)? beta before follow sets are */ +/* MR14 */ /* computed. This is necessary to solve problem */ +/* MR14 */ /* of doing follow on the alpha of an (alpha)? beta block. */ +/* MR14 */ +/* MR14 */ /* This is performed by analysis_point as a side-effect. */ +/* MR14 */ +/* MR14 */ +/* MR14 */ if (j->jtype == aSubBlk && j->guess) { +/* MR14 */ Junction *ignore; +/* MR14 */ ignore=analysis_point(j); +/* MR14 */ } +/* MR14 */ + return; + case nRuleRef : + if ( r->linked ) return; + q = (RuleEntry *) hash_get(Rname, r->text); + if ( q == NULL ) + { + warnFL( eMsg1("rule %s not defined",r->text), FileStr[r->file], r->line ); + } + else + { + if ( r->parms!=NULL && RulePtr[q->rulenum]->pdecl==NULL ) + { + warnFL( eMsg1("rule %s accepts no parameter(s)", r->text), + FileStr[r->file], r->line ); + } + if ( r->parms==NULL && RulePtr[q->rulenum]->pdecl!=NULL ) + { + warnFL( eMsg1("rule %s requires parameter(s)", r->text), + FileStr[r->file], r->line ); + } + if ( r->assign!=NULL && RulePtr[q->rulenum]->ret==NULL ) + { + warnFL( eMsg1("rule %s yields no return value(s)", r->text), + FileStr[r->file], r->line ); + } + if ( r->assign==NULL && RulePtr[q->rulenum]->ret!=NULL ) + { + warnFL( eMsg1("rule %s returns a value(s)", r->text), + FileStr[r->file], r->line ); + } + if ( !r->linked ) + { + addFoLink( r->next, r->rname, RulePtr[q->rulenum] ); + r->linked = TRUE; + } + } + FoLink( r->next ); + return; + case nToken : + FoLink( ((TokNode *)p)->next ); + return; + case nAction : + FoLink( ((ActionNode *)p)->next ); + return; + default : + fatal_internal("invalid node type"); + } +} + +/* + * Add a reference to the end of a rule. + * + * 'r' points to the RuleBlk node in a rule. r->end points to the last node + * (EndRule jtype) in a rule. + * + * Initial: + * r->end --> o + * + * After: + * r->end --> o-->o--> Ptr to node following rule r in another rule + * | + * o--> Ptr to node following another reference to r. + * + * Note that the links are added to the head of the list so that r->end->p1 + * always points to the most recently added follow-link. At the end, it should + * point to the last reference found in the grammar (starting from the 1st rule). + */ +void +#ifdef __USE_PROTOS +addFoLink( Node *p, char *rname, Junction *r ) +#else +addFoLink( p, rname, r ) +Node *p; +char *rname; +Junction *r; +#endif +{ + Junction *j; + require(r!=NULL, "addFoLink: incorrect rule graph"); + require(r->end!=NULL, "addFoLink: incorrect rule graph"); + require(r->end->jtype==EndRule, "addFoLink: incorrect rule graph"); + require(p!=NULL, "addFoLink: NULL FOLLOW link"); + + j = newJunction(); + j->rname = rname; /* rname on follow links point to target rule */ + j->p1 = p; /* link to other rule */ + j->p2 = (Node *) r->end->p1;/* point to head of list */ + r->end->p1 = (Node *) j; /* reset head to point to new node */ +} + +void +#ifdef __USE_PROTOS +GenCrossRef( Junction *p ) +#else +GenCrossRef( p ) +Junction *p; +#endif +{ + set a; + Junction *j; + RuleEntry *q; + unsigned e; + require(p!=NULL, "GenCrossRef: why are you passing me a null grammar?"); + + printf("Cross Reference:\n\n"); + a = empty; + for (; p!=NULL; p = (Junction *)p->p2) + { + printf("Rule %20s referenced by {", p->rname); + /* make a set of rules for uniqueness */ + for (j = (Junction *)(p->end)->p1; j!=NULL; j = (Junction *)j->p2) + { + q = (RuleEntry *) hash_get(Rname, j->rname); + require(q!=NULL, "GenCrossRef: FoLinks are screwed up"); + set_orel(q->rulenum, &a); + } + for (; !set_nil(a); set_rm(e, a)) + { + e = set_int(a); + printf(" %s", RulePtr[e]->rname); + } + printf(" }\n"); + } + set_free( a ); +} + +/* + The single argument is a pointer to the start of an element of a + C++ style function prototypet list. Given a pointer to the start of + an formal we must locate the comma (or the end of the string) + and locate the datatype, formal name, and initial value expression. + + The function returns a pointer to the character following the comma + which terminates the formal declaration, or a pointer to the end of + the string if none was found. + + I thought we were parsing specialists, how come I'm doing this by + hand written code ? + + Examples of input: + + Foo f, + Foo f = Foo(1), + Foo f = Foo(1,2), + Foo f = &farray[1,2], + Foo f = ",", + Foo f = ',', + TFoo<int,char> f = TFoo<int,char>(1,2), + + A non-zero value for nesting indicates a problem matching '(' and ')', + '[' and ']', '<' and '>', '{' and '}', or improperly terminated string + or character literal. + +*/ + + +/* + * Don't care if it is a valid string literal or not, just find the end + * Start with pointer to leading "\"" + */ + +#ifdef __USE_PROTOS +char * skipStringLiteral(char *pCurrent) +#else +char * skipStringLiteral(pCurrent) +char *pCurrent; +#endif +{ + char *p = pCurrent; + if (*p == 0) return p; + require (*p == '\"', "skipStringLiteral") + p++; + for (p = p; *p != 0; p++) { + if (*p == '\\') { + p++; + if (*p == 0) break; + p++; + } + if (*p == '\"') { + p++; + break; + } + } + return p; +} + +/* + * Don't care if it is a valid character literal or not, just find the end + * Start with pointer to leading "'" + */ + +#ifdef __USE_PROTOS +char * skipCharLiteral(char *pStart) +#else +char * skipCharLiteral(pStart) + char *pStart; +#endif +{ + char *p = pStart; + if (*p == 0) return p; + require (*p == '\'', "skipCharLiteral") + p++; + for (p = p; *p != 0; p++) { + if (*p == '\\') { + p++; + if (*p == 0) break; + p++; + } + if (*p == '\'') { + p++; + break; + } + } + return p; +} + +#ifdef __USE_PROTOS +char * skipSpaces(char *pStart) +#else +char * skipSpaces(pStart) +char * pStart; +#endif +{ + char *p = pStart; + while (*p != 0 && isspace(*p)) p++; + return p; +} + +#ifdef __USE_PROTOS +char * skipToSeparatorOrEqualSign(char *pStart, int *pNest) +#else +char * skipToSeparatorOrEqualSign(pStart, pNest) +char *pStart; +int *pNest; +#endif +{ + char *p = pStart; + + int nest = 0; + + *pNest = (-1); + + while (*p != 0) { + switch (*p) { + + case '(' : + case '[' : + case '<' : + case '{' : + nest++; + p++; + break; + + case ')' : + case ']' : + case '>' : + case '}' : + nest--; + p++; + break; + + case '"' : + p = skipStringLiteral(p); + break; + + case '\'' : + p = skipCharLiteral(p); + break; + + case '\\': + p++; + if (*p == 0) goto EXIT; + p++; + break; + + case ',': + case '=': + if (nest == 0) goto EXIT; + p++; + break; + + default: + p++; + } + } +EXIT: + *pNest = nest; + return p; +} + +#ifdef __USE_PROTOS +char * skipToSeparator(char *pStart, int *pNest) +#else +char * skipToSeparator(pStart, pNest) +char *pStart; +int *pNest; +#endif +{ + char * p = pStart; + for ( ; ; ) { + p = skipToSeparatorOrEqualSign(p, pNest); + if (*pNest != 0) return p; + if (*p == ',') return p; + if (*p == 0) return p; + p++; + } +} + +/* skip to just past the "=" separating the declaration from the initialization value */ + +#ifdef __USE_PROTOS +char * getInitializer(char *pStart) +#else +char * getInitializer(pStart) +char * pStart; +#endif +{ + char *p; + char *pDataType; + char *pSymbol; + char *pEqualSign; + char *pValue; + char *pSeparator; + int nest = 0; + + require(pStart!=NULL, "getInitializer: invalid string"); + + p = endFormal(pStart, + &pDataType, + &pSymbol, + &pEqualSign, + &pValue, + &pSeparator, + &nest); + if (nest != 0) return NULL; + if (pEqualSign == NULL) return NULL; + if (pValue == NULL) return NULL; + return strBetween(pValue, NULL, pSeparator); +} + +/* + Examines the string from pStart to pEnd-1. + If the string has 0 length or is entirely white space + returns 1. Otherwise 0. +*/ + +#ifdef __USE_PROTOS +int isWhiteString(const char *pStart, const char *pEnd) +#else +int isWhiteString(pStart, pEnd) +const char *pStart; +const char *pEnd; +#endif +{ + const char *p; + for (p = pStart; p < pEnd; p++) { + if (! isspace(*p)) return 0; + } + return 1; +} + +/* + This replaces HasComma() which couldn't distinguish + + foo ["a,b"] + + from: + + foo[a,b] + +*/ + +#ifdef __USE_PROTOS +int hasMultipleOperands(char *pStart) +#else +int hasMultipleOperands(pStart) +char *pStart; +#endif +{ + char *p = pStart; + int nest = 0; + + p = skipSpaces(p); + if (*p == 0) return 0; + p = skipToSeparator(p, &nest); + if (nest == 0 && *p == ',') return 1; + return 0; +} + + +#define MAX_STR_BETWEEN_WORK_AREA 1000 + +static char strBetweenWorkArea[MAX_STR_BETWEEN_WORK_AREA]; + + +/* + strBetween(pStart, pNext, pStop) + + Creates a null terminated string by copying the text between two pointers + to a work area. The start of the string is pStart. The end of the string + is the character before pNext, or if pNext is null then the character before + pStop. Trailing spaces are not included in the copy operation. + + This is used when a string contains several parts. The pNext part may be + optional. The pStop will stop the scan when the optional part is not present + (is a null pointer). +*/ + +#ifdef __USE_PROTOS +char *strBetween(char *pStart, char *pNext, char *pStop) +#else +char *strBetween(pStart, pNext, pStop) +char *pStart; +char *pNext; +char *pStop; +#endif +{ + char *p; + char *q = strBetweenWorkArea; + const char *pEnd; + + pEnd = (pNext != NULL) ? pNext : pStop; + + require (pEnd != NULL, "pEnd == NULL"); + require (pEnd >= pStart, "pEnd < pStart"); + for (pEnd--; pEnd >= pStart; pEnd--) { /* MR31 */ + if (! isspace(*pEnd)) break; + } + for (p = pStart; + p <= pEnd && q < &strBetweenWorkArea[MAX_STR_BETWEEN_WORK_AREA-2]; + p++, q++) { + *q = *p; + } + *q = 0; + return strBetweenWorkArea; +} + +/* + function Returns pointer to character following separator at + value which to continue search for next formal. If at the + end of the string a pointer to the null byte at the + end of the string is returned. + + pStart Pointer to the starting position of the formal list + + This may be the middle of a longer string, for example + when looking for the end of formal #3 starting from + the middle of the complete formal list. + + ppDataType Returns a pointer to the start of the data type in the + formal. Example: pointer to "Foo". + + ppSymbol Returns a pointer to the start of the formal symbol. + Example: pointer to "f". + + ppEqualSign Returns a pointer to the equal sign separating the + formal symbol from the initial value. If there is + no "=" then this will be NULL. + + ppValue Returns a pointer to the initial value part of the + formal declaration. Example: pointer to "&farray[1,2]" + + ppSeparator Returns a pointer to the character which terminated the + scan. This should be a pointer to a comma or a null + byte which terminates the string. + + pNest Returns the nesting level when a separator was found. + This is non-zero for any kind of error. This is zero + for a successful parse of this portion of the formal + list. + +*/ + +#ifdef __USE_PROTOS +char * endFormal(char *pStart, + char **ppDataType, + char **ppSymbol, + char **ppEqualSign, + char **ppValue, + char **ppSeparator, + int *pNest) +#else +char * endFormal(pStart, + ppDataType, + ppSymbol, + ppEqualSign, + ppValue, + ppSeparator, + pNest) +char *pStart; +char **ppDataType; +char **ppSymbol; +char **ppEqualSign; +char **ppValue; +char **ppSeparator; +int *pNest; + +#endif +{ + char *p = pStart; + char *q; + + *ppDataType = NULL; + *ppSymbol = NULL; + *ppEqualSign = NULL; + *ppValue = NULL; + *ppSeparator = NULL; + + *pNest = 0; + + /* The first non-blank is the start of the datatype */ + + p = skipSpaces(p); + if (*p == 0) goto EXIT; + *ppDataType = p; + + /* We are not looking for the symbol, we are looking + for the separator that follows the symbol. Then + we'll back up. + + Search for the ',' or '=" or null terminator. + */ + + p = skipToSeparatorOrEqualSign(p, pNest); + + if (*pNest != 0) goto EXIT; + + /* + Work backwards to find start of symbol + Skip spaces between the end of symbol and separator + Assume that there are no spaces in the formal, but + there is a space preceding the formal + */ + + for (q = &p[-1]; q >= *ppDataType; q--) { + if (! isspace(*q)) break; + } + if (q < *ppDataType) goto EXIT; + + /* + MR26 Handle things like: IIR_Bool (IIR_Decl::*constraint)() + Backup until we hit the end of a symbol string, then find the + start of the symbol string. This wont' work for functions + with prototypes, but works for the most common cases. For + others, use typedef names. + */ + +/* MR26 */ for (q = q; q >= *ppDataType; q--) { +/* MR26 */ if (isalpha(*q) || isdigit(*q) || *q == '_' || *q == '$') break; +/* MR26 */ } +/* MR26 */ if (q < *ppDataType) goto EXIT; + + for (q = q; q >= *ppDataType; q--) { + if ( ! (isalpha(*q) || isdigit(*q) || *q == '_' || *q == '$')) break; + } + + *ppSymbol = &q[1]; + + if (*p == ',' || *p == 0) { + *ppSeparator = p; + goto EXIT; + } + + *ppEqualSign = p; + p = skipSpaces(++p); + *ppValue = p; + if (*p == 0) goto EXIT; + + + while (*p != 0 && *pNest == 0 && *p != ',') { + p = skipToSeparator(p, pNest); + } + if (*pNest == 0) *ppSeparator = p; + +EXIT: + if (*p == ',') p++; + return p; +} |