misc.c revision 4fd606d1f5abe38e1f42c38de1d2e895166bd0f4
/*
* 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
* 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 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 void
#ifdef __USE_PROTOS
#else
#endif
/* T o k e n M a n i p u l a t i o n */
/*
* '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
{
{
char **p;
int i, more, j;
for (i=0; i<NumLexClasses; i++)
{
}
}
* here as TokenInd doesn't exist yet
*/
}
static Expr *
#ifdef __USE_PROTOS
newExpr( char *e )
#else
newExpr( e )
char *e;
#endif
{
p->expr = e;
p->lclass = CurrentLexClass;
return p;
}
* 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[] = "\"@\"";
{
}
/* does m already exist? */
i = LexClassIndex(m);
if ( i != -1 ) {lexmode(i); return;}
/* must make new one */
require(NumLexClasses<=MaxLexClasses, "number of allowable lexclasses exceeded\nIncrease MaxLexClasses in generic.h and recompile all C files");
"lexclass: cannot allocate ExprStr");
/* define EOF for each automaton */
p = newTermEntry( EOFSTR );
/* note: we use the actual ExprStr array
* here as TokenInd doesn't exist yet
*/
}
void
#ifdef __USE_PROTOS
lexmode( int i )
#else
lexmode( i )
int i;
#endif
{
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++)
{
}
return -1;
}
int
#ifdef __USE_PROTOS
#else
char *expr;
#endif
{
TermEntry *p;
}
void
#ifdef __USE_PROTOS
#else
char *expr;
char *action;
#endif
{
TermEntry *p;
}
#ifdef __USE_PROTOS
#else
char *token;
int tnum;
#endif
{
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
#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 */
{
q = (ForcedToken *) p->elem;
}
/* make token indirection array */
/* fill token indirection array and change token id htable ; swap token indices */
{
int old_pos, t;
q = (ForcedToken *) p->elem;
q = (ForcedToken *) p->elem;
/* 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 */
{
for (i=0; i<NumLexClasses; i++)
{
{
/* update the symbol table for this expr */
}
}
}
/* update expr at old position (if any) of forced token id */
for (i=0; i<NumLexClasses; i++)
{
{
/* update the symbol table for this expr */
}
}
}
/* Update SynDiag */
}
static void
#ifdef __USE_PROTOS
#else
Node *p;
#endif
{
RuleRefNode *r = (RuleRefNode *) p;
if ( p==NULL ) return;
switch ( p->ntype )
{
case nJunction :
if ( j->visited ) return;
return;
case nRuleRef :
return;
case nToken :
if ( t->remapped ) return; /* we've been here before */
t->remapped = 1;
return;
case nAction :
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
#else
char *token;
#endif
{
TermEntry *p;
p = newTermEntry( token );
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
#else
char *token;
int tnum;
#endif
{
TermEntry *p;
p = newTermEntry( token );
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
#else
char *expr;
#endif
{
TermEntry *p;
p = newTermEntry( expr );
/* track the order in which they occur */
return p->token;
}
/* return the token number of 'term'. Return 0 if no 'term' exists */
int
#ifdef __USE_PROTOS
#else
char *term;
#endif
{
TermEntry *p;
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
#else
char *token;
char *expr;
#endif
{
TermEntry *p, *q;
{
return;
}
{
q = newTermEntry( expr );
q->token = t;
/* note: we use the actual ExprStr array
* here as TokenInd doesn't exist yet
*/
/* track the order in which they occur */
return;
}
if ( p != NULL ) /* one is defined, one is not */
{
q = newTermEntry( expr );
}
else /* trying to associate name with expr here*/
{
p = newTermEntry( token );
}
}
/*
* 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
#else
char *text;
int sz;
#endif
{
Entry *p;
{
fatal_internal("newEntry: out of memory for terminals\n");
}
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
#else
void *e;
#endif
{
p = newListNode;
p->elem = e;
{
}
else /* find end of list */
{
}
}
/* 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
#else
int freeData;
#endif
{
ListNode *p;
};
free( (char *) p);
};
}
void
#ifdef __USE_PROTOS
#else
list_apply( list, f )
void (*f)();
#endif
{
ListNode *p;
}
/* MR27 */
#ifdef __USE_PROTOS
#else
char * cstring;
#endif
{
ListNode *p;
}
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
#else
char *rule;
int computation;
int k;
#endif
{
int i;
if ( k > 99 ) /* MR10 */
/* MR10 */ if (k < 10) {
/* MR10 */ } else {
/* MR10 */ };
return key;
}
/* Push a rule onto the kth FOLLOW stack */
void
#ifdef __USE_PROTOS
#else
char *rule;
int k;
#endif
{
RuleEntry *r;
/*fprintf(stderr, "FoPush(%s)\n", rule);*/
{
/*fprintf(stderr, "allocating FoStack\n");*/
}
{
}
else
{
#ifdef MEMCHK
#endif
FoStackSize) );
eMsg1("FoPush: FoStack stack-ptr is playing out of its sandbox",
rule));
++(FoTOS[k]);
}
{
/*
**** 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
{
/*fprintf(stderr, "FoPop\n");*/
"FoPop: FoStack stack-ptr is playing out of its sandbox");
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;
/*fprintf(stderr, "RegisterCycle(%s)\n", rule);*/
/* Find cycle start */
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
#endif
if ( p == FoTOS[k] ) return; /* don't worry about cycles to oneself */
/* compute cyclic dependents (rules in cycle except head) */
c = newCycle;
c->croot = *p++; /* record root of cycle */
for (; p<=FoTOS[k]; p++)
{
/* Mark all dependent rules as incomplete */
if ( f==NULL )
{
}
f->incomplete = TRUE;
}
}
/* 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; */
{
/*fprintf(stderr, "cycle %d: %s -->", i++, RulePtr[c->croot]->rname);*/
/*s_fprT(stderr, c->cyclicDep);*/
/*fprintf(stderr, "\n");*/
f = (CacheEntry *)
{
/*fprintf(stderr, "Fo(%s) has changed\n", RulePtr[c->croot]->rname);*/
changed = 1;
c->deg = d; /* update cycle FOLLOW set degree */
/* 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 *)
g->incomplete = FALSE;
}
}
}
/* 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 */
{
p = q->next;
free((char *)q);
}
}
/* 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
#else
Junction *q;
int btype;
#endif
{
int k,a;
if ( btype == aLoopBegin )
{
if ( PrintAnnotate )
{
printf(" /* Opt ");
k = 1;
{
if ( k++ == CLL_k ) break;
}
printf(" */\n");
}
return;
}
{
if ( PrintAnnotate )
{
k = 1;
{
if ( k++ == CLL_k ) break;
}
printf( " (optional branch) */\n");
else printf( " */\n");
}
/* ignore implied empty alt of Plus blocks */
{
if ( pLevel == 1 )
{
printf("\n");
printf("\t");
}
else printf(" ");
printf("|");
if ( pLevel == 1 )
{
while ( p!=NULL )
{
{
continue;
}
{
break;
}
{
p = NULL;
break;
}
}
}
}
}
}
/* How to print out a junction */
void
#ifdef __USE_PROTOS
#else
pJunc( q )
Junction *q;
#endif
{
int dum_k;
int doing_rule;
switch ( q->jtype )
{
case aSubBlk :
else doing_rule = 0;
pLevel++;
if ( pLevel==1 )
{
printf("\t");
}
else printf(" ");
if ( doing_rule )
{
}
else {
printf("(");
printf(")");
}
pLevel--;
if ( PrintAnnotate ) freeBlkFsets(q);
break;
case aOptBlk :
pLevel++;
if ( pLevel==1 )
{
printf("\t");
}
else printf(" ");
printf("{");
else printf("\n\t");
printf("}");
pLevel--;
if ( PrintAnnotate ) freeBlkFsets(q);
break;
case aLoopBegin :
pLevel++;
if ( pLevel==1 )
{
printf("\t");
}
else printf(" ");
printf("(");
else printf("\n\t");
printf(")*");
pLevel--;
if ( PrintAnnotate ) freeBlkFsets(q);
break;
case aLoopBlk :
if ( PrintAnnotate ) freeBlkFsets(q);
break;
case aPlusBlk :
pLevel++;
if ( pLevel==1 )
{
printf("\t");
}
else printf(" ");
printf("(");
printf(")+");
pLevel--;
if ( PrintAnnotate ) freeBlkFsets(q);
break;
case EndBlk :
break;
case RuleBlk :
break;
case Generic :
break;
case EndRule :
printf( "\n\t;\n");
break;
}
}
/* How to print out a rule reference node */
void
#ifdef __USE_PROTOS
pRuleRef( RuleRefNode *p )
#else
pRuleRef( p )
RuleRefNode *p;
#endif
{
}
/* How to print out a terminal node */
void
#ifdef __USE_PROTOS
#else
pToken( p )
TokNode *p;
#endif
{
}
/* How to print out a terminal node */
void
#ifdef __USE_PROTOS
pAction( ActionNode *p )
#else
pAction( p )
ActionNode *p;
#endif
{
}
/* 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
#else
FoLink( p )
Node *p;
#endif
{
RuleEntry *q;
RuleRefNode *r = (RuleRefNode *) p;
if ( p==NULL ) return;
switch ( p->ntype )
{
case nJunction :
if ( j->fvisited ) return;
/* 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 */ }
/* MR14 */
return;
case nRuleRef :
if ( r->linked ) return;
if ( q == NULL )
{
}
else
{
{
}
{
}
{
}
{
}
if ( !r->linked )
{
}
}
return;
case nToken :
return;
case nAction :
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
#else
Node *p;
char *rname;
Junction *r;
#endif
{
Junction *j;
j = newJunction();
j->p1 = p; /* link to other rule */
}
void
#ifdef __USE_PROTOS
GenCrossRef( Junction *p )
#else
GenCrossRef( p )
Junction *p;
#endif
{
set a;
Junction *j;
RuleEntry *q;
unsigned e;
printf("Cross Reference:\n\n");
a = empty;
{
/* make a set of rules for uniqueness */
{
}
{
e = set_int(a);
}
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;
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;
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
#else
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 '=':
p++;
break;
default:
p++;
}
}
EXIT:
return p;
}
#ifdef __USE_PROTOS
#else
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;
&pSymbol,
&pValue,
&nest);
}
/*
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
#else
const char *pStart;
const char *pEnd;
#endif
{
const char *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
char *pStart;
#endif
{
char *p = pStart;
int nest = 0;
p = skipSpaces(p);
if (*p == 0) return 0;
p = skipToSeparator(p, &nest);
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
#else
char *pStart;
char *pNext;
char *pStop;
#endif
{
char *p;
char *q = strBetweenWorkArea;
const char *pEnd;
}
for (p = pStart;
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 **ppDataType,
char **ppSymbol,
char **ppEqualSign,
char **ppValue,
char **ppSeparator,
int *pNest)
#else
char *pStart;
char **ppDataType;
char **ppSymbol;
char **ppEqualSign;
char **ppValue;
char **ppSeparator;
int *pNest;
#endif
{
char *p = pStart;
char *q;
*ppDataType = NULL;
*ppEqualSign = 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);
/*
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 */ }
for (q = q; q >= *ppDataType; q--) {
}
*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;
}