/* * gen.c * * Generate C code (ANSI, K&R, C++) * * 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 #include #include #include "pcctscfg.h" #include "set.h" #include "syn.h" #include "hash.h" #include "generic.h" #include "dlgdef.h" #define NumExprPerLine 4 static int on1line=0; static set tokensRefdInBlock; /* T r a n s l a t i o n T a b l e s */ /* C_Trans[node type] == pointer to function that knows how to translate that node. */ #ifdef __cplusplus void (*C_Trans[NumNodeTypes+1])(...) = { NULL, NULL, /* See next table. Junctions have many types */ (void (*)(...)) genRuleRef, (void (*)(...)) genToken, (void (*)(...)) genAction }; #else void (*C_Trans[NumNodeTypes+1])() = { NULL, NULL, /* See next table. Junctions have many types */ genRuleRef, genToken, genAction }; #endif /* C_JTrans[Junction type] == pointer to function that knows how to translate that * kind of junction node. */ #ifdef __cplusplus void (*C_JTrans[NumJuncTypes+1])(...) = { NULL, (void (*)(...)) genSubBlk, (void (*)(...)) genOptBlk, (void (*)(...)) genLoopBlk, (void (*)(...)) genEndBlk, (void (*)(...)) genRule, (void (*)(...)) genJunction, (void (*)(...)) genEndRule, (void (*)(...)) genPlusBlk, (void (*)(...)) genLoopBegin }; #else void (*C_JTrans[NumJuncTypes+1])() = { NULL, genSubBlk, genOptBlk, genLoopBlk, genEndBlk, genRule, genJunction, genEndRule, genPlusBlk, genLoopBegin }; #endif #define PastWhiteSpace(s) while (*(s) == ' ' || *(s) == '\t') {s++;} static int tabs = 0; /* MR6 Got tired of text running off page when using standard tab stops */ #define TAB { int i; \ if (TabWidth==0) { \ for (i=0; irname);} else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q->rname); } } static void #ifdef __USE_PROTOS warn_about_using_gk_option(void) #else warn_about_using_gk_option() #endif { static int warned_already=0; if ( !DemandLookahead || warned_already ) return; warned_already = 1; warnNoFL("-gk option could cause trouble for <<...>>? predicates"); } void #ifdef __USE_PROTOS freeBlkFsets( Junction *q ) #else freeBlkFsets( q ) Junction *q; #endif { int i; Junction *alt; require(q!=NULL, "freeBlkFsets: invalid node"); for (alt=q; alt != NULL; alt= (Junction *) alt->p2 ) { for (i=1; i<=CLL_k; i++) set_free(alt->fset[i]); } } /* * Generate a local variable allocation for each token references * in this block. */ static void #ifdef __USE_PROTOS genTokenPointers( Junction *q ) #else genTokenPointers( q ) Junction *q; #endif { /* Rule refs are counted and can be referenced, but their * value is not set to anything useful ever. * * The ptrs are to be named _tij where i is the current level * and j is the element number within an alternative. */ int first=1, t=0; set a; tokensRefdInBlock = q->tokrefs; if ( set_deg(q->tokrefs) == 0 ) return; a = set_dup(q->tokrefs); gen("ANTLRTokenPtr "); for (; !set_nil(a); set_rm(t, a)) { t = set_int(a); if ( first ) first = 0; else _gen(","); if ( !DontCopyTokens ) _gen2("_tv%d%d,", BlkLevel, t); _gen2("_t%d%d", BlkLevel, t); if ( !DontCopyTokens ) {_gen2("= &_tv%d%d", BlkLevel, t);} else _gen("=NULL"); } _gen(";\n"); set_free(a); } static int #ifdef __USE_PROTOS hasDefaultException(ExceptionGroup *eg) #else hasDefaultException(eg) ExceptionGroup *eg; #endif { ListNode *q; for (q = eg->handlers->next; q!=NULL; q=q->next) { ExceptionHandler *eh = (ExceptionHandler *)q->elem; if ( strcmp("default", eh->signalname)==0 ) { return 1; } } return 0; } static void #ifdef __USE_PROTOS dumpException(ExceptionGroup *eg, int no_default_case) #else dumpException(eg, no_default_case) ExceptionGroup *eg; int no_default_case; #endif { char *outerLabel; /* MR7 */ int altHandler=0; /* MR7 */ int namedHandler=0; /* MR7 */ outerLabel=findOuterHandlerLabel(eg); /* MR7 */ if (eg->label != NULL) { /* MR7 */ namedHandler=1; /* MR7 */ } else if (eg->forRule) { /* MR7 */ /* nothing */ /* MR20 */ } else { /* MR7 */ altHandler=1; /* MR7 */ }; /* MR7 */ #if 0 ** if (! eg->used) { /* MR7 */ ** warnFL("exception group never used", /* MR7 */ ** FileStr[eg->altstart->file],eg->altstart->line); /* MR7 */ ** }; /* MR7 */ #endif if (namedHandler) { /* MR7 */ gen1("switch ( _signal ) { /* [%s] */\n",eg->label); /* MR7 */ } else { /* MR7 */ gen("switch ( _signal ) {\n"); /* MR7 */ gen("case NoSignal: break; /* MR7 */\n"); /* MR7 */ }; /* MR7 */ { ListNode *q; for (q = eg->handlers->next; q!=NULL; q=q->next) { ExceptionHandler *eh = (ExceptionHandler *)q->elem; if ( strcmp("default", eh->signalname)==0 ) { gen("default :\n"); tabs++; dumpAction(eh->action, output, tabs, -1, 1, 1); gen("_signal=NoSignal; /* MR7 */\n"); /* MR7 */ gen("break; /* MR7 */\n"); /* MR7 */ tabs--; gen("}\n"); /* copied from later code in dumpException */ /* MR7 */ if (namedHandler) { /* MR7 */ gen("if (_signal != NoSignal)"); /* MR7 */ _gen1(" goto %s_handler; /* MR7 */\n",outerLabel);/* MR7 */ } else if (altHandler) { /* MR7 */ gen1("goto %s_handler; /* MR7 */\n",outerLabel); /* MR7 */ }; return; } gen1("case %s :\n", eh->signalname); tabs++; if ( eh->action != NULL ) { dumpAction(eh->action, output, tabs, -1, 1, 1); gen("break; /* MR7 */\n"); /* MR7 */ } tabs--; } } if ( no_default_case ) return; gen("default :\n"); tabs++; /* MR7 */ gen("break; /* MR7 */\n"); /* MR7 */ tabs--; /* MR7 */ tabs++; /***** gen("*_retsignal = _signal;\n"); *****/ tabs--; gen("}\n"); if (namedHandler) { /* MR7 */ gen("if (_signal != NoSignal)"); /* MR7 */ _gen1(" goto %s_handler; /* MR7 */\n",outerLabel); /* MR7 */ } else if (altHandler) { /* MR7 */ gen1("goto %s_handler; /* MR7 */\n",outerLabel); /* MR7 */ }; } static void #ifdef __USE_PROTOS dumpExceptions(ListNode *list) #else dumpExceptions(list) ListNode *list; #endif { ListNode *p; for (p = list->next; p!=NULL; p=p->next) { ExceptionGroup *eg = (ExceptionGroup *) p->elem; _gen2("%s%s_handler:\n", eg->label==NULL?"":eg->label, eg->altID==NULL?"":eg->altID); if ( eg->altID!=NULL ) dumpException(eg, 0); else { /* This must be the rule exception handler */ dumpException(eg, 1); if ( !hasDefaultException(eg) ) { gen("default :\n"); tabs++; gen("zzdflthandlers(_signal,_retsignal);\n"); tabs--; gen("}\n"); } } } } /* For each element label that is found in a rule, generate a unique * Attribute (and AST pointer if GenAST) variable. */ void #ifdef __USE_PROTOS genElementLabels(ListNode *list) #else genElementLabels(list) ListNode *list; #endif { int first=1; ListNode *p; if ( GenCC ) {gen("ANTLRTokenPtr");} else {gen("Attrib");} for (p = list->next; p!=NULL; p=p->next) { char *ep = (char *)p->elem; if ( first ) first = 0; else _gen(","); if ( GenCC ) {_gen1(" %s=NULL",ep);} else {_gen1(" %s",ep);} } _gen(";\n"); if ( !GenAST ) return; first = 1; gen("AST"); for (p = list->next; p!=NULL; p=p->next) { char *ep = (char *)p->elem; if ( first ) first = 0; else _gen(","); _gen1(" *%s_ast=NULL",ep); } _gen(";\n"); } /* * Generate a local variable allocation for each token or rule reference * in this block. */ static void #ifdef __USE_PROTOS genASTPointers( Junction *q ) #else genASTPointers( q ) Junction *q; #endif { int first=1, t; set a; a = set_or(q->tokrefs, q->rulerefs); if ( set_deg(a) > 0 ) { gen("AST "); for (; !set_nil(a); set_rm(t, a)) { t = set_int(a); if ( first ) first = 0; else _gen(","); _gen2("*_ast%d%d=NULL", BlkLevel, t); } set_free(a); } _gen(";\n"); } static void #ifdef __USE_PROTOS BLOCK_Head( void ) #else BLOCK_Head( ) #endif { gen("{\n"); tabs++; if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel); } static void #ifdef __USE_PROTOS BLOCK_Tail( void ) #else BLOCK_Tail( ) #endif { if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel); if ( !GenCC ) gen("}\n"); tabs--; gen("}\n"); } static void #ifdef __USE_PROTOS BLOCK_Preamble( Junction *q ) #else BLOCK_Preamble( q ) Junction *q; #endif { ActionNode *a; Junction *begin; BLOCK_Head(); if ( GenCC ) genTokenPointers(q); if ( GenCC&&GenAST ) genASTPointers(q); if ( q->jtype == aPlusBlk ) gen("int zzcnt=1;\n"); if ( q->parm != NULL && !q->predparm ) gen1("zzaPush(%s);\n", q->parm) else if ( !GenCC ) gen("zzMake0;\n"); if ( !GenCC ) gen("{\n"); if ( q->jtype == aLoopBegin ) begin = (Junction *) ((Junction *)q->p1); else begin = q; if ( has_guess_block_as_first_item(begin) ) { gen("zzGUESS_BLOCK\n"); } if ( q->jtype == aLoopBegin ) a = findImmedAction( ((Junction *)q->p1)->p1 ); /* look at aLoopBlk */ else a = findImmedAction( q->p1 ); if ( a!=NULL && !a->is_predicate) { /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); a->done = 1; /* remove action. We have already handled it */ } } void #ifdef __USE_PROTOS genCombinedPredTreeContextOrig( Predicate *p ) #else genCombinedPredTreeContextOrig( p ) Predicate *p; #endif { static set *ctx=NULL; /* genExprSets() is destructive, make copy*/ require(p!=NULL, "can't make context tree for NULL pred tree"); #ifdef DBG_PRED fprintf(stderr, "enter genCombinedPredTreeContextOrig(%s,0x%x) with sets:\n", p->expr, p); s_fprT(stderr, p->scontext[1]); fprintf(stderr, "\n"); #endif if ( p->down == NULL ) { /*** if ( p->k>1 && p->tcontext!=NULL ) ***/ if ( p->tcontext!=NULL ) { _gen("("); genExprTree(p->tcontext, 1); _gen(")"); } /*** else if ( p->k==1 && set_deg(p->scontext[1])>0 ) ***/ else if ( set_deg(p->scontext[1])>0 ) { if ( ctx==NULL ) ctx = (set *)calloc(CLL_k+1, sizeof(set)); require(ctx!=NULL, "ctx cannot allocate"); ctx[0]=empty; ctx[1]=set_dup(p->scontext[1]); _gen("("); genExprSets(&(ctx[0]), p->k); _gen(")"); set_free(ctx[1]); } else if ( p->expr==PRED_AND_LIST || p->expr==PRED_OR_LIST ) { fatal_internal("pred tree is orphan OR or AND list"); } else { if (! HoistPredicateContext) { _gen(" 1 /* no context: prc is off */ "); } else { fatal_internal("pred tree context is empty"); }; } return; } /* MR10 - make AND just like OR */ if ( p->expr == PRED_AND_LIST ) { Predicate *list = p->down; for (; list!=NULL; list=list->right) { genCombinedPredTreeContextOrig(list); if ( list->right!=NULL ) _gen("|| /* MR10 was wrong */ "); }; return; } if ( p->expr == PRED_OR_LIST ) { Predicate *list = p->down; for (; list!=NULL; list=list->right) { genCombinedPredTreeContextOrig(list); if ( list->right!=NULL ) _gen("||"); }; return; }; fatal("pred tree is really wacked"); } /* [genCombinedPredTreeContext] */ void #ifdef __USE_PROTOS genCombinedPredTreeContext( Predicate *p ) #else genCombinedPredTreeContext( p ) Predicate *p; #endif { Tree *t; int predDepth=0; if (0 && ! MR_usingPredNames && ! MRhoisting) { genCombinedPredTreeContextOrig(p); } else { /* MR13 */ MR_pred_depth(p,&predDepth); /* MR13 */ if (predDepth == 1) { /* MR13 */ /* MR13 */ set scontext[2]; /* MR13 */ scontext[0]=empty; /* MR13 */ scontext[1]=MR_compute_pred_set(p); /* MR13 */ if (set_nil(scontext[1])) { /* MR13 */ _gen(" 1 /* MR12 no context (-prc off) */ "); /* MR13 */ } else { /* MR13 */ _gen("("); /* MR13 */ genExprSets(&scontext[0], 1); /* MR13 */ set_free(scontext[1]); /* MR13 */ _gen(")"); /* MR13 */ }; } else { t=MR_compute_pred_tree_context(p); if (t == NULL) { _gen(" 1 /* MR12 no context (-prc off) */ "); } else { _gen("("); genExprTree(t, 1); Tfree(t); /* MR10 */ _gen(")"); }; }; }; } /* [genPredTreeGate] */ void #ifdef __USE_PROTOS genPredTreeGate( Predicate *p, int in_and_expr ) #else genPredTreeGate( p, in_and_expr ) Predicate *p; int in_and_expr; #endif { if ( in_and_expr ) { _gen("!("); genCombinedPredTreeContext(p); _gen(")||"); if ( p->down!=NULL ) _gen("\n"); } else { _gen("("); genCombinedPredTreeContext(p); _gen(")&&"); if ( p->down!=NULL ) _gen("\n"); } } #ifdef __USE_PROTOS void genPredEntry(Predicate *p,int outer) #else void genPredEntry(p,outer) Predicate *p; int outer; #endif { int inverted=0; Predicate *q; int localOuter=outer; int needRP=0; if (p == NULL) return; if (p->predEntry != NULL && p->predEntry->predLiteral != NULL) { if (p->inverted != p->predEntry->pred->inverted) { _gen("! /* inverted pred */ ("); needRP=1; } else { if (!localOuter) _gen("("); needRP=1; }; dumpAction(p->predEntry->predLiteral,output,0,p->source->file,p->source->line,0); if (needRP) _gen(")"); return; }; inverted=p->inverted; if (inverted) { _gen(" ! /* inverted pred */ ("); localOuter=1; }; if (p->expr == PRED_OR_LIST) { if (!localOuter) _gen("("); for (q=p->down; q != NULL ; q=q->right) { genPredEntry(q,0); if (q->right != NULL) _gen(" || "); }; if (!localOuter) _gen(")"); } else if (p->expr == PRED_AND_LIST) { if (!localOuter) _gen("("); for (q=p->down; q != NULL ; q=q->right) { genPredEntry(q,0); if (q->right != NULL) _gen(" && "); }; if (!localOuter) _gen(")"); } else { if (!localOuter) _gen("("); require (p->source != NULL,"predEntry->source == NULL"); require (p->source->inverted == 0,"dumpPredEntry p->source->inverted != 0"); dumpAction(p->source->action,output,0,p->source->file,p->source->line,0); if (!localOuter) _gen(")"); }; if (inverted) { _gen(")"); } } void #ifdef __USE_PROTOS dumpPredAction(ActionNode *anode, char *s,FILE *output,int tabs,int file,int line,int final_newline) #else dumpPredAction(anode, s,output,tabs,file,line,final_newline) ActionNode *anode; char *s; FILE *output; int tabs; int file; int line; int final_newline; #endif { PredEntry *predEntry=anode->predEntry; int inverted=anode->inverted; Predicate *workPred; if (predEntry == NULL) { /* inline predicate literal */ require(inverted == 0,"dumpPredAction action->inverted"); dumpAction(s,output,tabs,file,line,final_newline); } else { /* a reference to a predicate - possibly with an inverted source */ if (predEntry->predLiteral != NULL) { if (inverted) _gen("! /* inverted pred */ ("); dumpAction(predEntry->predLiteral,output,0,anode->file,anode->line,0); if (inverted) _gen(")"); } else { workPred=predicate_dup(predEntry->pred); if (inverted) workPred->inverted=!workPred->inverted; genPredEntry(workPred,1); predicate_free(workPred); }; }; } /* [genPred] */ void #ifdef __USE_PROTOS genPred(Predicate *p, Node *j,int suppress_sva) #else genPred(p,j,suppress_sva) Predicate *p; Node *j; int suppress_sva; #endif { if ( FoundException && !suppress_sva) {_gen("(_sva=(");} /* MR11 suppress_sva */ else {_gen("(");} if ( GenLineInfo && j->file != -1 ) _gen("\n"); if (p->source != NULL && p->source->ampersandPred != NULL) { if (p->source->ampersandPred->k == 1) { set ctx[2]; ctx[0]=empty; ctx[1]=set_dup(p->source->ampersandPred->scontext[1]); _gen("("); genExprSets(&(ctx[0]), p->k); _gen(") && "); set_free(ctx[1]); } else { _gen("( "); genExprTree(p->source->ampersandPred->tcontext,1); _gen(" ) && "); }; }; dumpPredAction((ActionNode *)p->source, p->expr, output, 0, -1 /*indicates no line info*/, j->line, 0); if ( FoundException && !suppress_sva) /* MR11 suppress_sva */ {_gen("),_sva)");} /* MR10 - get red of "meant ==" messages */ else {_gen(")");} } void #ifdef __USE_PROTOS MR_distinctORcontextOpt(Predicate *p,Node *j,int in_and_expr) #else MR_distinctORcontextOpt(p,j,in_and_expr) Predicate *p; Node *j; int in_and_expr; #endif { Predicate *q; _gen(" /* MR10 Distinct OR context optimization */ \n"); if (in_and_expr) { gen("zzpf=0,\n"); for (q=p->down; q != NULL; q=q->right) { gen("( "); genCombinedPredTreeContext(q); _gen(" && (zzpf=1, "); genPred(q,j,0); _gen(" )) ||\n"); }; gen("!zzpf)"); } else { require (0, "MR_distinctORcontextOpt: can't get here when using MR_predSimplify"); #if 0 ** for (q=p->down; q != NULL; q=q->right) { ** gen("( "); ** genCombinedPredTreeContext(q); ** _gen(" && "); ** genPred(q,j); ** if (q->right != NULL) { ** _gen(" ) ||\n"); ** }; ** }; ** gen(")"); #endif }; } void #ifdef __USE_PROTOS genPredTreeOrig( Predicate *p, Node *j, int in_and_expr ) #else genPredTreeOrig( p, j, in_and_expr ) Predicate *p; Node *j; int in_and_expr; #endif { /* MR10 */ int allHaveContext=1; /* MR10 */ int noneHaveContext=1; /* MR10 */ MR_predContextPresent(p,&allHaveContext,&noneHaveContext); if ( ! noneHaveContext ) /* MR10 context guards ignored when -prc off */ { _gen("("); genPredTreeGate(p, in_and_expr); } /* if leaf node, just gen predicate */ if ( p->down==NULL ) { genPred(p,j,0); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } /* if AND list, do both preds (only two possible) */ if ( p->expr == PRED_AND_LIST ) { #if 0 ** _gen("("); ** genPredTreeOrig(p->down, j, 1); ** _gen("&&"); ** genPredTreeOrig(p->down->right, j, 1); ** _gen(")"); ** if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ ** return; #endif /* MR11 - make it work with AND with more than two children - like OR */ Predicate *list; _gen("("); list = p->down; for (; list!=NULL; list=list->right) { genPredTreeOrig(list, j, 1); if ( list->right!=NULL ) _gen("&&"); } _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; }; if ( p->expr == PRED_OR_LIST ) { Predicate *list; _gen("("); list = p->down; for (; list!=NULL; list=list->right) { genPredTreeOrig(list, j, 0); if ( list->right!=NULL ) _gen("||"); } _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } fatal_internal("genPredTreeOrig: predicate tree is wacked"); } #if 0 ** Predicate member dummyPredDepth is no longer used in MR10 ** but we might need it again in the future ** ** if (MRhoisting) { ** if ( !noneHaveContext && ** ! in_and_expr && ** p->source != NULL && ** p->source->dummyPredicateDepth > 0 && ** p->down == NULL) { ** _gen("("); ** genCombinedPredTreeContext(p); ** _gen(" )\n"); ** return; ** }; ** }; #endif /* [genPredTree] */ /* in_and_expr what to do if the context is wrong what to do if the context is correct but the predicate is false remember: if the context is wrong it's the same as if the predicate is true as far as enabling an alternative Consider (AND p q r) if in an ... && ... expression then you don't want the entire predicate chain to fail just because the context for one component is wrong: so return true Consider (OR p q r) if in an ... || ... expression then you don't want the entire predicate chain to succeed just because the context for one component is correct when the corresponding test is false: so return false when the context is correct but the test is false. */ void #ifdef __USE_PROTOS genPredTree( Predicate *p, Node *j, int in_and_expr, int suppress_sva ) #else genPredTree( p, j, in_and_expr, suppress_sva) Predicate *p; Node *j; int in_and_expr; int suppress_sva; #endif { int allHaveContext=1; int noneHaveContext=1; Tree *groupTree; Tree *oneTree; Predicate *q; int identicalORcontextOptimization=0; int identicalANDcontextOptimization=0; if (0 && !MR_usingPredNames && !MRhoisting) { genPredTreeOrig(p,j,in_and_expr); return; }; MR_predContextPresent(p,&allHaveContext,&noneHaveContext); if ( ! noneHaveContext ) { /* MR10 context guards ignored when -prc off */ _gen("("); /* MR10 optimize OR predicates which are all leaves */ if (p->expr == PRED_OR_LIST && MR_allPredLeaves(p->down)) { groupTree=MR_compute_pred_tree_context(p); for (q=p->down ; q != NULL ; q=q->right) { oneTree=MR_compute_pred_tree_context(q); if (! MR_tree_equ(groupTree,oneTree)) { Tfree(oneTree); break; }; Tfree(oneTree); }; Tfree(groupTree); if (q == NULL) { _gen("/* MR10 individual OR gates suppressed when all predicates are leaves"); _gen(" with identical context */\n"); genPredTreeGate(p,in_and_expr); /* use the parent's in_and_expr for this gate */ identicalORcontextOptimization=1; } else { MR_distinctORcontextOpt(p,j,in_and_expr); return; }; } else if (p->expr == PRED_AND_LIST && MR_allPredLeaves(p->down)) { /* MR12 optimize AND predicates which are all leaves */ groupTree=MR_compute_pred_tree_context(p); for (q=p->down ; q != NULL ; q=q->right) { oneTree=MR_compute_pred_tree_context(q); if (! MR_tree_equ(groupTree,oneTree)) { Tfree(oneTree); break; }; Tfree(oneTree); }; Tfree(groupTree); if (q == NULL) { _gen("/* MR12 individual AND gates suppressed when all predicates are leaves"); _gen(" with identical context */\n"); genPredTreeGate(p,in_and_expr); /* use the parent's in_and_expr for this gate */ identicalANDcontextOptimization=1; } else { genPredTreeGate(p, in_and_expr); }; } else { genPredTreeGate(p, in_and_expr); }; } /* if leaf node, just gen predicate */ if ( p->down==NULL ) { genPred(p,j,suppress_sva); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } /* if AND list, do both preds (only two possible) */ /* MR10 not any more ! */ if ( p->expr == PRED_AND_LIST ) { Predicate *list; _gen("("); list = p->down; for (; list != NULL; list=list->right) { if (identicalANDcontextOptimization) { genPred(list, j,suppress_sva); } else { genPredTree(list, j, 1, suppress_sva); /* in and context */ }; if ( list->right!=NULL ) _gen("&&"); }; _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } if ( p->expr == PRED_OR_LIST ) { Predicate *list; _gen("("); list = p->down; for (; list!=NULL; list=list->right) { if (identicalORcontextOptimization) { genPred(list, j,suppress_sva); } else { genPredTree(list, j, 0, suppress_sva); }; if ( list->right!=NULL ) _gen("||"); } _gen(")"); if ( ! noneHaveContext ) _gen(")"); /* MR10 context guards ignored when -prc off */ return; } fatal_internal("predicate tree is wacked"); } /* [genPredTreeMainXX] */ Predicate * /* MR10 */ #ifdef __USE_PROTOS genPredTreeMainXX( Predicate *p, Node *j ,int in_and_expr) #else genPredTreeMainXX( p, j ,in_and_expr) Predicate *p; Node *j; int in_and_expr; #endif { int allHaveContext=1; int noneHaveContext=1; #if 0 fprintf(stderr,"Pred before\n"); dumppred(p); fprintf(stderr,"\n"); fprintf(stderr,"Pred after\n"); dumppred(p); fprintf(stderr,"\n"); #endif p=MR_predSimplifyALL(p); /* MR10 */ require (MR_predicate_context_completed(p),"predicate context is not complete"); MR_cleanup_pred_trees(p); /* MR10 */ MR_predContextPresent(p,&allHaveContext,&noneHaveContext); if (!noneHaveContext & !allHaveContext) { warnFL("predicate contains elements both with and without context", FileStr[j->file],j->line); }; if (InfoP) { _gen("\n#if 0\n\n"); MR_dumpPred(p,1); _gen("#endif\n"); }; genPredTree(p,j,in_and_expr,0); return p; } Predicate * /* MR10 */ #ifdef __USE_PROTOS genPredTreeMain( Predicate *p, Node *j) #else genPredTreeMain( p, j) Predicate *p; Node *j; #endif { return genPredTreeMainXX(p,j,1); } static void #ifdef __USE_PROTOS genExprTreeOriginal( Tree *t, int k ) #else genExprTreeOriginal( t, k ) Tree *t; int k; #endif { require(t!=NULL, "genExprTreeOriginal: NULL tree"); if ( t->token == ALT ) { _gen("("); genExprTreeOriginal(t->down, k); _gen(")"); if ( t->right!=NULL ) { _gen("||"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTreeOriginal(t->right, k); _gen(")"); } return; } if ( t->down!=NULL ) _gen("("); _gen1("LA(%d)==",k); if ( TokenString(t->token) == NULL ) _gen1("%d", t->token) else _gen1("%s", TokenString(t->token)); if ( t->down!=NULL ) { _gen("&&"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTreeOriginal(t->down, k+1); _gen(")"); } if ( t->down!=NULL ) _gen(")"); if ( t->right!=NULL ) { _gen("||"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTreeOriginal(t->right, k); _gen(")"); } } #ifdef __USE_PROTOS static void MR_LAtokenString(int k,int token) #else static void MR_LAtokenString(k,token) int k; int token; #endif { char *ts; ts=TokenString(token); if (ts == NULL) { _gen2(" LA(%d)==%d",k,token); } else { _gen2(" LA(%d)==%s",k,ts); }; } #ifdef __USE_PROTOS static int MR_countLeaves(Tree *t) #else static int MR_countLeaves(t) Tree *t; #endif { if (t == NULL) return 0; if (t->token == ALT) { return MR_countLeaves(t->down)+MR_countLeaves(t->right); } else { return 1+MR_countLeaves(t->down)+MR_countLeaves(t->right); }; } #ifdef __USE_PROTOS static void MR_genOneLine(Tree *tree,int k) #else static void MR_genOneLine(tree,k) Tree *tree; int k; #endif { if (tree == NULL) return; if (tree->token == ALT) { MR_genOneLine(tree->down,k); } else { MR_LAtokenString(k,tree->token); if (tree->down != NULL && tree->down->right == NULL) { _gen(" &&"); MR_genOneLine(tree->down,k+1); } else if (tree->down != NULL) { _gen(" && ("); MR_genOneLine(tree->down,k+1); _gen(")"); }; }; if (tree->right != NULL) { _gen(" ||"); MR_genOneLine(tree->right,k); }; } static int across; static int depth; static int lastkonline; #ifdef __USE_PROTOS static void MR_genMultiLine(Tree *tree,int k) #else static void MR_genMultiLine(tree,k) Tree *tree; int k; #endif { int i; if (tree == NULL) return; if (tree->token == ALT) { MR_genMultiLine(tree,k); } else { MR_LAtokenString(k,tree->token); lastkonline=k; across++; if (tree->down != NULL && tree->down->right == NULL) { if (across > 3) { _gen("\n"); across=0; lastkonline=0; for (i=0 ; i < depth+k ; i++) _gen(" "); _gen("&&"); } else { _gen(" &&"); }; MR_genMultiLine(tree->down,k+1); } else if (tree->down != NULL) { _gen("\n"); lastkonline=0; across=0; for (i=0 ; i < depth+k ; i++) _gen(" "); _gen("&& ("); MR_genMultiLine(tree->down,k+1); _gen(")"); }; }; if (tree->right != NULL) { if (k < lastkonline) { _gen("\n"); across=0; lastkonline=0; for (i=0; i < depth+k-1 ; i++) _gen(" "); _gen("||"); } else if (across > 3 ) { _gen("\n"); across=0; lastkonline=0; for (i=0; i < depth+k ; i++) _gen(" "); _gen("||"); } else { _gen(" ||"); }; MR_genMultiLine(tree->right,k); }; } #ifdef __USE_PROTOS static void genExprTree(Tree *tree,int k) #else static void genExprTree(tree,k) Tree *tree; int k; #endif { int count; #if 0 /* MR20 THM This was probably an error. The routine should probably reference that static "across" and this declaration hides it. */ int across; #endif require (tree != NULL,"genExprTree: tree is NULL"); require (k > 0,"genExprTree: k <= 0"); if (0 && !MRhoisting) { /* MR11 make new version standard */ genExprTreeOriginal(tree,k); } else { count=MR_countLeaves(tree); if (count < 5) { MR_genOneLine(tree,k); } else { _gen("\n"); across=0; depth=0; lastkonline=0; MR_genMultiLine(tree,k); _gen("\n"); }; }; } /* * Generate LL(k) type expressions of the form: * * (LA(1) == T1 || LA(1) == T2 || ... || LA(1) == Tn) && * (LA(2) == T1 || LA(2) == T2 || ... || LA(2) == Tn) && * ..... * (LA(k) == T1 || LA(k) == T2 || ... || LA(k) == Tn) * * If GenExprSetsOpt generate: * * (setwdi[LA(1)]&(1<= 1. * * This routine is visible only to this file and cannot answer a TRANS message. * */ /* [genExpr] */ static int #ifdef __USE_PROTOS genExpr( Junction *j ) #else genExpr( j ) Junction *j; #endif { int max_k; /* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead * from CLL_k..LL_k */ { int limit; if ( j->ftree!=NULL ) limit = LL_k; else limit = CLL_k; max_k = genExprSets(j->fset, limit); } /* Do tests for real tuples from other productions that conflict with * artificial tuples generated by compression (using sets of tokens * rather than k-trees). */ if ( j->ftree != NULL ) { _gen(" && !("); genExprTree(j->ftree, 1); _gen(")"); } if ( ParseWithPredicates && j->predicate!=NULL ) { Predicate *p = j->predicate; warn_about_using_gk_option(); _gen("&&"); j->predicate=genPredTreeMain(p, (Node *)j); /* MR10 */ } return max_k; } static int #ifdef __USE_PROTOS genExprSets( set *fset, int limit ) #else genExprSets( fset, limit ) set *fset; int limit; #endif { int k = 1; int max_k = 0; unsigned *e, *g, firstTime=1; if (set_nil(fset[1])) { _gen(" 0 /* MR13 empty set expression - undefined rule ? infinite left recursion ? */ "); MR_BadExprSets++; }; if ( GenExprSetsOpt ) { while ( k <= limit && !set_nil(fset[k]) ) /* MR11 */ { if ( set_deg(fset[k])==1 ) /* too simple for a set? */ { int e; _gen1("(LA(%d)==",k); e = set_int(fset[k]); if ( TokenString(e) == NULL ) _gen1("%d)", e) else _gen1("%s)", TokenString(e)); } else { NewSet(); FillSet( fset[k] ); _gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<max_k ) max_k = k; if ( k == CLL_k ) break; k++; if ( k<=limit && !set_nil(fset[k]) ) _gen(" && "); /* MR11 */ on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } } return max_k; } while ( k<= limit && !set_nil(fset[k]) ) /* MR11 */ { if ( (e=g=set_pdq(fset[k])) == NULL ) fatal_internal("genExpr: cannot allocate IF expr pdq set"); for (; *e!=nil; e++) { if ( !firstTime ) _gen(" || ") else { _gen("("); firstTime = 0; } on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen1("LA(%d)==",k); if ( TokenString(*e) == NULL ) _gen1("%d", *e) else _gen1("%s", TokenString(*e)); } free( (char *)g ); _gen(")"); if ( k>max_k ) max_k = k; if ( k == CLL_k ) break; k++; if ( k <= limit && !set_nil(fset[k]) ) { firstTime=1; _gen(" && "); } /* MR11 */ on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } } return max_k; } /* * Generate code for any type of block. If the last alternative in the block is * empty (not even an action) don't bother doing it. This permits us to handle * optional and loop blocks as well. * * Only do this block, return after completing the block. * This routine is visible only to this file and cannot answer a TRANS message. */ static set #ifdef __USE_PROTOS genBlk( Junction *q, int jtype, int *max_k, int *need_right_curly, int * lastAltEmpty /* MR23 */) #else genBlk( q, jtype, max_k, need_right_curly, lastAltEmpty /* MR23 */) Junction *q; int jtype; int *max_k; int *need_right_curly; int *lastAltEmpty; /* MR23 */ #endif { set f; Junction *alt; int a_guess_in_block = 0; require(q!=NULL, "genBlk: invalid node"); require(q->ntype == nJunction, "genBlk: not junction"); *need_right_curly=0; *lastAltEmpty = 0; /* MR23 */ if ( q->p2 == NULL ) /* only one alternative? Then don't need if */ { if (first_item_is_guess_block((Junction *)q->p1)!=NULL ) { if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) { warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line); }; gen("zzGUESS\n"); /* guess anyway to make output code consistent */ /* MR10 disable */ /**** gen("if ( !zzrv )\n"); ****/ /* MR10 */ gen("if ( !zzrv ) {\n"); tabs++; (*need_right_curly)++; }; TRANS(q->p1); return empty; /* no decision to be made-->no error set */ } f = First(q, 1, jtype, max_k); for (alt=q; alt != NULL; alt= (Junction *) alt->p2 ) { if ( alt->p2 == NULL ) /* chk for empty alt */ { Node *p = alt->p1; if ( p->ntype == nJunction ) { /* we have empty alt */ /* MR23 There is a conflict between giving good error information for non-exceptions and making life easy for those using parser exception handling. Consider: r: { A } b; b: B; with input "C" Before MR21 the error message would be "expecting B - found C". After MR21 the error message would be "expect A, B - found C". This was good, but it caused problems for those using parser exceptions because the reference to B was generated inside the {...} where B really wasn't part of the block. In MR23 this has been changed for the case where exceptions are in use to not generate the extra check in the tail of the {A} block. */ /* MR23 */ if (isEmptyAlt( ((Junction *)p)->p1, (Node *)q->end)) { /* MR23 */ *lastAltEmpty = 1; /* MR23 */ if (FoundException) { /* MR23 */ /* code to restore state if a prev alt didn't follow guess */ /* MR23 */ if ( a_guess_in_block && jtype != aPlusBlk) { /* MR23 */ gen("if ( !zzrv ) zzGUESS_DONE; /* MR28 */\n"); /* MR23 */ } /* MR23 */ break; /* MR23 */ }; /* MR28 */ if (jtype == aPlusBlk) { /* MR28 */ break; /* MR28 */ } /* MR23 */ } } } /* end of for loop on alt */ /* MR10 */ if (alt->p2 == NULL && /* MR10 */ ( q->jtype == aSubBlk || q->jtype == RuleBlk) ) { /* MR10 */ if (first_item_is_guess_block(alt)) { /* MR10 */ warnFL("(...)? as last alternative of block is unnecessary", /* MR10 */ FileStr[alt->file],alt->line); /* MR10 */ }; /* MR10 */ }; if ( alt != q ) gen("else ") else { if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", *max_k);} else gen1("look(%d);\n", *max_k); } } if ( alt!=q ) { _gen("{\n"); tabs++; (*need_right_curly)++; /* code to restore state if a prev alt didn't follow guess */ if ( a_guess_in_block ) gen("if ( !zzrv ) zzGUESS_DONE;\n"); } if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) { a_guess_in_block = 1; gen("zzGUESS\n"); } gen("if ( "); if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) _gen("!zzrv && "); genExpr(alt); _gen(" ) "); _gen("{\n"); tabs++; TRANS(alt->p1); --tabs; gen("}\n"); /* MR10 */ if (alt->p2 == NULL) { /* MR10 */ if (first_item_is_guess_block(alt)) { /* MR10 */ gen("/* MR10 */ else {\n"); /* MR10 */ tabs++; /* MR10 */ (*need_right_curly)++; /* MR10 */ /* code to restore state if a prev alt didn't follow guess */ /* MR10 */ gen("/* MR10 */ if ( !zzrv ) zzGUESS_DONE;\n"); /* MR10 */ gen("/* MR10 */ if (0) {} /* last alternative of block is guess block */\n"); /* MR10 */ }; /* MR10 */ }; } return f; } static int #ifdef __USE_PROTOS has_guess_block_as_first_item( Junction *q ) #else has_guess_block_as_first_item( q ) Junction *q; #endif { Junction *alt; for (alt=q; alt != NULL; alt= (Junction *) alt->p2 ) { if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) return 1; } return 0; } static int #ifdef __USE_PROTOS has_guess_block_as_last_item( Junction *q ) #else has_guess_block_as_last_item( q ) Junction *q; #endif { Junction *alt; if (q == NULL) return 0; for (alt=q; alt->p2 != NULL && !( (Junction *) alt->p2)->ignore; alt= (Junction *) alt->p2 ) {}; return first_item_is_guess_block( (Junction *) alt->p1) != NULL; } /* MR30 See description of first_item_is_guess_block for background */ Junction * #ifdef __USE_PROTOS first_item_is_guess_block_extra(Junction *q ) #else first_item_is_guess_block_extra(q) Junction *q; #endif { while ( q!=NULL && ( ( q->ntype==nAction ) || ( q->ntype==nJunction && (q->jtype==Generic || q->jtype == aLoopBlk) ) ) ) { if ( q->ntype==nJunction ) q = (Junction *)q->p1; else q = (Junction *) ((ActionNode *)q)->next; } if ( q==NULL ) return NULL; if ( q->ntype!=nJunction ) return NULL; if ( q->jtype!=aSubBlk ) return NULL; if ( !q->guess ) return NULL; return q; } /* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node * of (...)?; This function ignores actions and predicates. */ Junction * #ifdef __USE_PROTOS first_item_is_guess_block( Junction *q ) #else first_item_is_guess_block( q ) Junction *q; #endif { Junction * qOriginal = q; /* DEBUG */ /* MR14 Couldn't find aSubBlock which was a guess block when it lay behind aLoopBlk. The aLoopBlk only appear in conjunction with aLoopBegin, but the routine didn't know that. I think. MR14a Added extra parentheses to clarify precedence MR30 This appears to have been a mistake. The First set was then computed incorrectly for: r : ( (A)? B | C )* The routine analysis_point was seeing the guess block when it was still analyzing the loopBegin block. As a consequence, when it looked for the analysis_point it was processing the B, but skipping over the C alternative altogether because it thought it was looking at a guess block, not realizing there was a loop block in front of the loopBegin. loopBegin loopBlk subBlk/guess A G EB G B EB EB EB ER | | | ^ ^ | | | | | +-> G C G ----------------------+ | | | +--- G G G -------------------------------------+ Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu). MR30 This is still more complicated. This fix caused ambiguity messages to be reported for "( (A B)? )* A B" but not for "( (A B)? )+". Why is there a difference when these are outwardly identical ? It is because the start of a (...)* block is represented by two nodes: a loopBegin block followed by a loopBlock whereas the start of a (...)+ block is represented as a single node: a plusBlock. So if first_item_is_guess_block is called when the current node is a loopBegin it starts with the loop block rather than the sub block which follows the loop block. However, we can't just skip past the loop block because some routines depend on the old implementation. So, we provide a new implementation which does skip the loopBlock. However, which should be called when ? I'm not sure, but my guess is that first_item_is_guess_block_extra (the new one) should only be called for the ambiguity routines. */ while ( q!=NULL && ( ( q->ntype==nAction ) || ( q->ntype==nJunction && (q->jtype==Generic /*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/ ) ) ) { if ( q->ntype==nJunction ) q = (Junction *)q->p1; else q = (Junction *) ((ActionNode *)q)->next; } if ( q==NULL ) return NULL; if ( q->ntype!=nJunction ) return NULL; if ( q->jtype!=aSubBlk ) return NULL; if ( !q->guess ) return NULL; return q; } /* MR1 */ /* MR1 10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs */ /* MR1 */ #define STRINGIZEBUFSIZE 1024 static char stringizeBuf[STRINGIZEBUFSIZE]; char * #ifdef __USE_PROTOS stringize(char * s) #else stringize(s) char *s; #endif { char *p; char *stop; p=stringizeBuf; stop=&stringizeBuf[1015]; if (s != 0) { while (*s != 0) { if (p >= stop) { goto stringizeStop; } else if (*s == '\n') { *p++='\\'; *p++='n'; *p++='\\'; *p++=*s++; } else if (*s == '\\') { *p++=*s; *p++=*s++; } else if (*s == '\"') { *p++='\\'; *p++=*s++; while (*s != 0) { if (p >= stop) { goto stringizeStop; } else if (*s == '\n') { *p++='\\'; *p++=*s++; } else if (*s == '\\') { *p++=*s++; *p++=*s++; } else if (*s == '\"') { *p++='\\'; *p++=*s++; break; } else { *p++=*s++; }; }; } else if (*s == '\'') { *p++=*s++; while (*s != 0) { if (p >= stop) { goto stringizeStop; } else if (*s == '\'') { *p++=*s++; break; } else if (*s == '\\') { *p++=*s++; *p++=*s++; } else if (*s == '\"') { *p++='\\'; *p++=*s++; break; } else { *p++=*s++; }; }; } else { *p++=*s++; }; }; }; goto stringizeExit; stringizeStop: *p++='.'; *p++='.'; *p++='.'; stringizeExit: *p=0; return stringizeBuf; } #ifdef __USE_PROTOS int isNullAction(char *s) #else int isNullAction(s) char *s; #endif { char *p; for (p=s; *p != '\0' ; p++) { if (*p != ';' && *p !=' ') return 0; }; return 1; } /* MR1 */ /* MR1 End of Routine to stringize code for failed predicates msgs */ /* MR1 */ /* Generate an action. Don't if action is NULL which means that it was already * handled as an init action. */ void #ifdef __USE_PROTOS genAction( ActionNode *p ) #else genAction( p ) ActionNode *p; #endif { require(p!=NULL, "genAction: invalid node and/or rule"); require(p->ntype==nAction, "genAction: not action"); if ( !p->done ) /* MR10 */ /* MR11 */ { if ( p->is_predicate) { if ( p->guardpred != NULL ) { Predicate *guardDup=predicate_dup(p->guardpred); /* MR10 */ gen("if (!"); guardDup=genPredTreeMain(guardDup, (Node *)p); predicate_free(guardDup); } /* MR10 */ else if (p->ampersandPred != NULL) { /* MR10 */ gen("if (!"); /* MR10 */ p->ampersandPred=genPredTreeMain(p->ampersandPred, (Node *)p); /* MR10 */ } else { gen("if (!("); /* make sure that '#line n' is on front of line */ if ( GenLineInfo && p->file != -1 ) _gen("\n"); dumpPredAction(p,p->action, output, 0, p->file, p->line, 0); _gen(")"); } /* MR23 Change failed predicate macro to have three arguments: macro arg 1: The stringized predicate itself macro arg 2: 0 => no user-defined error action 1 => user-defined error action macro arg 3: The user-defined error action This gives the user more control of the error action. */ tabs++; gen3(") {zzfailed_pred(\"%s\",%s, { %s } );}\n", /* MR23 */ stringize(p->action), /* MR23 */ (p->pred_fail == NULL ? /* MR23/MR27 */ "0 /* report */" : "1 /* user action */"), /* MR23/MR27 */ (p->pred_fail == NULL ? /* MR23 */ "; /* no user action */" : p->pred_fail)); /* MR23 */ tabs--; } else /* not a predicate */ { if (! isNullAction(p->action) && !p->noHoist) { if ( FoundGuessBlk ) { if ( GenCC ) { gen("if ( !guessing ) {\n"); } else { gen("zzNON_GUESS_MODE {\n"); }; }; dumpActionPlus(p, p->action, output, tabs, p->file, p->line, 1); /* MR21 */ if ( FoundGuessBlk ) gen("}\n"); }; } } TRANS(p->next) } /* * if invoking rule has !noAST pass zzSTR to rule ref and zzlink it in * else pass addr of temp root ptr (&_ast) (don't zzlink it in). * * if ! modifies rule-ref, then never link it in and never pass zzSTR. * Always pass address of temp root ptr. */ void #ifdef __USE_PROTOS genRuleRef( RuleRefNode *p ) #else genRuleRef( p ) RuleRefNode *p; #endif { Junction *q; char *handler_id = ""; RuleEntry *r, *r2; char *parm = "", *exsig = ""; int genRuleRef_emittedGuessGuard=0; /* MR10 */ require(p!=NULL, "genRuleRef: invalid node and/or rule"); require(p->ntype==nRuleRef, "genRuleRef: not rule reference"); if ( p->altstart!=NULL && p->altstart->exception_label!=NULL ) handler_id = p->altstart->exception_label; r = (RuleEntry *) hash_get(Rname, p->text); if ( r == NULL ) { warnFL( eMsg1("rule %s not defined", p->text), FileStr[p->file], p->line ); return; } /* MR8 5-Aug-97 Reported by S.Bochnak@microtool.com.pl */ /* Don't do assign when no return values declared */ /* Move definition of q up and use it to guard p->assign */ q = RulePtr[r->rulenum]; /* find definition of ref'd rule */ /* MR8 */ r2 = (RuleEntry *) hash_get(Rname, p->rname); if ( r2 == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;} OutLineInfo(output,p->line,FileStr[p->file]); if ( GenCC && GenAST ) { gen("_ast = NULL;\n"); } if ( FoundGuessBlk && p->assign!=NULL && q->ret != NULL ) { /* MR8 */ if ( GenCC ) { gen("if ( !guessing ) {\n"); } else { gen("zzNON_GUESS_MODE {\n"); }; tabs++; /* MR11 */ genRuleRef_emittedGuessGuard=1; /* MR11 */ }; if ( FoundException ) exsig = "&_signal"; tab(); if ( GenAST ) { if ( GenCC ) { /**** if ( r2->noAST || p->astnode==ASTexclude ) ****/ { /**** _gen("_ast = NULL;\n"); ****/ parm = "&_ast"; } /*** we always want to set just a pointer now, then set correct pointer after else { _gen("_astp = (_tail==NULL)?(&_sibling):(&(_tail->_right));\n"); parm = "_astp"; } ****/ } else { if ( r2->noAST || p->astnode==ASTexclude ) { _gen("_ast = NULL; "); parm = "&_ast"; } else parm = "zzSTR"; } if ( p->assign!=NULL && q->ret!=NULL ) /* MR8 */ { if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */ else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum); } if ( FoundException ) { _gen5("%s%s(%s,&_signal%s%s); ", RulePrefix, p->text, parm, (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); if ( p->ex_group!=NULL ) { _gen("\n"); gen("if (_signal) {\n"); tabs++; dumpException(p->ex_group, 0); tabs--; gen("}"); } else { _gen1("if (_signal) goto %s_handler;", handler_id); } } else { _gen5("%s%s(%s%s%s);", RulePrefix, p->text, parm, (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); } if ( GenCC && (r2->noAST || p->astnode==ASTexclude) ) { /* rule has a ! or element does */ /* still need to assign to #i so we can play with it */ _gen("\n"); gen2("_ast%d%d = (AST *)_ast;", BlkLevel-1, p->elnum); } else if ( !r2->noAST && p->astnode == ASTinclude ) { /* rule doesn't have a ! and neither does element */ /* MR10 */ if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) { /* MR10 */ _gen("\n"); /* MR10 */ if (GenCC) gen ("if (!guessing) { /* MR10 */") /* MR10 */ else gen ("if (!zzguessing) { /* MR10 */\n"); /* MR10 */ tabs++; /* MR10 */ }; if ( GenCC ) { _gen("\n"); gen("if ( _tail==NULL ) _sibling = _ast; else _tail->setRight(_ast);\n"); gen2("_ast%d%d = (AST *)_ast;\n", BlkLevel-1, p->elnum); tab(); } else _gen(" "); if ( GenCC ) { _gen("ASTBase::"); } else _gen("zz"); _gen("link(_root, &_sibling, &_tail);"); /* MR10 */ if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) { /* MR10 */ /* MR10 */ _gen("\n"); /* MR10 */ tabs--; /* MR10 */ if (GenCC) gen ("}; /* MR10 */") /* MR10 */ else gen ("}; /* MR10 */"); /* MR10 */ }; } } else { if ( p->assign!=NULL && q->ret!=NULL ) /* MR8 */ { if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */ else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum); } if ( FoundException ) { _gen4("%s%s(&_signal%s%s); ", RulePrefix, p->text, (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); if ( p->ex_group!=NULL ) { _gen("\n"); gen("if (_signal) {\n"); tabs++; dumpException(p->ex_group, 0); tabs--; gen("}"); } else { _gen1("if (_signal) goto %s_handler;", handler_id); } } else { _gen3("%s%s(%s);", RulePrefix, p->text, (p->parms!=NULL)?p->parms:""); } if ( p->assign!=NULL && q->ret!=NULL ) _gen("\n"); /* MR8 */ } if ( p->assign!=NULL && q->ret!=NULL) { /* MR8 */ if ( hasMultipleOperands(p->assign) ) /* MR23 */ { _gen("\n"); dumpRetValAssign(p->assign, q->ret, p); /* MR30 */ _gen("}"); } } _gen("\n"); /* Handle element labels now */ if ( p->el_label!=NULL ) { if ( GenAST ) { if ( GenCC ) { gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum); } else {gen1("%s_ast = zzastCur;\n", p->el_label);} } else if (!GenCC ) { gen1("%s = zzaCur;\n", p->el_label); } } if ( FoundGuessBlk && p->assign!=NULL && q->ret!=NULL ) { /* MR8 */ /* in guessing mode, don't branch to handler upon error */ tabs--; /* MR11 */ gen("} else {\n"); tabs++; /* MR11 */ if ( FoundException ) { gen6("%s%s(%s%s&_signal%s%s);\n", RulePrefix, p->text, parm, (*parm!='\0')?",":"", (p->parms!=NULL)?",":"", (p->parms!=NULL)?p->parms:""); } else { gen5("%s%s(%s%s%s);\n", RulePrefix, p->text, parm, (p->parms!=NULL && *parm!='\0')?",":"", (p->parms!=NULL)?p->parms:""); } tabs--; /* MR11 */ gen("}\n"); } TRANS(p->next) } /* * Generate code to match a token. * * Getting the next token is tricky. We want to ensure that any action * following a token is executed before the next GetToken(); */ void #ifdef __USE_PROTOS genToken( TokNode *p ) #else genToken( p ) TokNode *p; #endif { RuleEntry *r; char *handler_id = ""; ActionNode *a; char *set_name; char *set_nameErrSet; int complement; int ast_label_in_action = 0; /* MR27 */ int pushedCmodeAST = 0; /* MR27 */ require(p!=NULL, "genToken: invalid node and/or rule"); require(p->ntype==nToken, "genToken: not token"); if ( p->altstart!=NULL && p->altstart->exception_label!=NULL ) handler_id = p->altstart->exception_label; r = (RuleEntry *) hash_get(Rname, p->rname); if ( r == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;} /* * MR27 Has the element label been referenced as an AST (with the # operator) ? * If so, then we'll want to build the AST even though the user has used * the ! operator. */ /* MR27 */ if (GenAST && p->el_label != NULL) { /* MR27 */ ast_label_in_action = list_search_cstring(r->ast_labels_in_actions, /* MR27 */ p->el_label); /* MR27 */ } OutLineInfo(output,p->line,FileStr[p->file]); if ( !set_nil(p->tset) ) /* implies '.', ~Tok, or tokenclass */ { unsigned e; unsigned eErrSet = 0; set b; set bErrSet; /* MR23 */ b = set_dup(p->tset); bErrSet = set_dup(p->tset); /* MR23 */ complement = p->complement; /* MR23 */ if ( p->tclass!=NULL && complement == 0 /* MR23 */) { /* token class not complemented*/ static char buf[MaxRuleName+20]; /* MR23 */ static char bufErrSet[MaxRuleName+20]; /* MR23 */ if ( p->tclass->dumped ) { e = p->tclass->setnum; eErrSet = p->tclass->setnumErrSet; } else { e = DefErrSet(&b, 0, TokenString(p->token)); eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errset"); p->tclass->dumped = 1; /* indicate set has been created */ p->tclass->setnum = e; p->tclass->setnumErrSet = eErrSet; /* MR23 */ } sprintf(buf, "%s_set", TokenString(p->token)); sprintf(bufErrSet, "%s_errset", TokenString(p->token)); /* MR23 */ set_name = buf; set_nameErrSet = bufErrSet; /* MR23 */ } /* MR23 - Forgot about the case of ~TOKCLASS. */ else if ( p->tclass!=NULL && complement != 0 /* MR23 */) { static char buf[MaxRuleName+20]; /* MR23 */ static char bufErrSet[MaxRuleName+20]; /* MR23 */ if ( p->tclass->dumpedComplement ) { e = p->tclass->setnumComplement; eErrSet = p->tclass->setnumErrSetComplement; } else { e = DefErrSetWithSuffix(0, &b, 0, TokenString(p->token), "_setbar"); eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errsetbar"); p->tclass->dumpedComplement = 1; /* indicate set has been created */ p->tclass->setnumComplement = e; p->tclass->setnumErrSetComplement = eErrSet; /* MR23 */ } sprintf(buf, "%s_setbar", TokenString(p->token)); sprintf(bufErrSet, "%s_errsetbar", TokenString(p->token)); /* MR23 */ set_name = buf; set_nameErrSet = bufErrSet; /* MR23 */ } else { /* wild card */ static char buf[sizeof("zzerr")+11]; static char bufErrSet[sizeof("zzerr")+11]; int n = DefErrSet( &b, 0, NULL ); int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set"); if ( GenCC ) snprintf(buf, 11, "err%d", n); else snprintf(buf, 11, "zzerr%d", n); if ( GenCC ) sprintf(bufErrSet, "err%d", nErrSet); else snprintf(bufErrSet, 11, "zzerr%d", nErrSet); set_name = buf; set_nameErrSet = bufErrSet; } if ( !FoundException ) { /* MR23 */ gen2("zzsetmatch(%s, %s);", set_name, set_nameErrSet); } else if ( p->ex_group==NULL ) { if ( p->use_def_MT_handler ) gen3("zzsetmatch_wdfltsig(%s,(ANTLRTokenType)%d,%s);", set_name, p->token, tokenFollowSet(p)) else gen2("zzsetmatch_wsig(%s, %s_handler);", set_name, handler_id); } else { gen1("if ( !_setmatch_wsig(%s) ) {\n", set_name); tabs++; /* MR6 */ if (FoundGuessBlk) { /* MR6 */ if ( GenCC ) {gen("if ( guessing ) goto fail;\n");} /* MR6 */ else gen("if ( zzguessing ) goto fail;\n"); /* MR6 */ }; gen("_signal=MismatchedToken;\n"); dumpException(p->ex_group, 0); tabs--; gen("}\n"); } set_free(b); set_free(bErrSet); } else if ( TokenString(p->token)!=NULL ) { if ( FoundException ) { if ( p->use_def_MT_handler ) gen2("zzmatch_wdfltsig(%s,%s);",TokenString(p->token),tokenFollowSet(p)) else if ( p->ex_group==NULL ) { gen2("zzmatch_wsig(%s, %s_handler);", TokenString(p->token), handler_id); } else { /* MR6 */ if (GenCC) { /* MR6 */ gen1("if ( !_match_wsig(%s) ) {\n", TokenString(p->token)); /* MR6 */ } else { /* MR6 */ gen1("if ( !_zzmatch_wsig(%s) ) {\n", TokenString(p->token)); /* MR6 */ }; tabs++; /* MR6 */ if (FoundGuessBlk) { /* MR6 */ if ( GenCC ) {gen("if ( guessing ) goto fail;\n");} /* MR6 */ else gen("if ( zzguessing ) goto fail;\n"); /* MR6 */ }; gen("_signal=MismatchedToken;\n"); dumpException(p->ex_group, 0); tabs--; gen("}\n"); } } else gen1("zzmatch(%s);", TokenString(p->token)); } else { if ( FoundException ) { if ( p->use_def_MT_handler ) gen2("zzmatch_wdfltsig((ANTLRTokenType)%d,%s);", p->token,tokenFollowSet(p)) else gen2("zzmatch_wsig(%d,%s_handler);",p->token,handler_id); } else {gen1("zzmatch(%d);", p->token);} } a = findImmedAction( p->next ); /* generate the token labels */ if ( GenCC && p->elnum>0 ) { /* If building trees in C++, always gen the LT() assigns */ if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) { /* MR10 */ if ( FoundGuessBlk ) { /* MR10 */ gen("\n"); /* MR10 */ if (p->label_used_in_semantic_pred) { /* MR10 */ gen2(" _t%d%d = (ANTLRTokenPtr)LT(1); /* MR10 */\n", BlkLevel-1, p->elnum); /* MR10 */ } else { /* MR10 */ gen("if ( !guessing ) {\n"); tab(); /* MR10 */ _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);\n", BlkLevel-1, p->elnum); /* MR10 */ gen("}\n"); /* MR10 */ }; /* MR10 */ } else { /* MR10 */ _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);", BlkLevel-1, p->elnum); /* MR10 */ }; /* MR10 */ } /* * MR23 labase is never used in the C++ runtime library. * and this code is generated only in C++ mode */ /*** if ( LL_k>1 ) / * MR23 disabled */ /*** if ( !DemandLookahead ) _gen(" labase++;"); / * MR23 disabled */ /*** _gen("\n"); / * MR23 disabled */ /*** tab(); / * MR23 disabled */ } if ( GenAST ) { if ( FoundGuessBlk && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) ) { if ( GenCC ) {_gen("if ( !guessing ) {\n"); tab();} else {_gen("zzNON_GUESS_MODE {\n"); tab();} } /* MR27 addition when labels referenced when operator ! used */ pushedCmodeAST = 0; /* MR27 */ if (ast_label_in_action && (p->astnode == ASTexclude || r->noAST)) { _gen("\n"); if (GenCC) { /* MR13 */ if (NewAST) { /* MR13 */ gen4("_ast%d%d = newAST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } else { /* MR13 */ gen4("_ast%d%d = new AST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } } else { pushedCmodeAST = 1; gen("zzastPush(zzmk_ast(zzastnew(),zzaCur)); /* MR27 */"); } } /* end MR27 addition for labels referenced when operator ! used */ if (!r->noAST ) { if (GenCC && !(p->astnode == ASTexclude) ) { _gen("\n"); /* MR13 */ if (NewAST) { /* MR13 */ gen4("_ast%d%d = newAST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } else { /* MR13 */ gen4("_ast%d%d = new AST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); /* MR13 */ } tab(); } if ( GenCC && !(p->astnode == ASTexclude) ) {_gen2("_ast%d%d->", BlkLevel-1, p->elnum);} else _gen(" "); if ( p->astnode==ASTchild ) { if ( !GenCC ) _gen("zz"); _gen("subchild(_root, &_sibling, &_tail);"); } else if ( p->astnode==ASTroot ) { if ( !GenCC ) _gen("zz"); _gen("subroot(_root, &_sibling, &_tail);"); } if ( GenCC && !(p->astnode == ASTexclude) ) { _gen("\n"); tab(); } } else if ( !GenCC ) { if (! pushedCmodeAST) _gen(" zzastDPush;"); } if ( FoundGuessBlk && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) ) {gen("}\n"); tab();} } /* Handle element labels now */ if ( p->el_label!=NULL ) { int done_NON_GUESSMODE=0; _gen("\n"); /* MR10 */ /* do Attrib / Token ptr for token label used in semantic pred */ /* MR10 */ /* for these cases do assign even in guess mode */ /* MR10 */ /* MR10 */ if (p->label_used_in_semantic_pred) { /* MR10 */ if ( GenCC ) { /* MR10 */ if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) { /* MR10 */ gen3("%s = _t%d%d;", p->el_label, BlkLevel-1, p->elnum); /* MR10 */ } else { /* MR10 */ gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label); /* MR10 */ }; /* MR10 */ } else { /* MR10 */ gen1("%s = zzaCur;", p->el_label); /* MR10 */ }; /* MR10 */ if (FoundGuessBlk) _gen(" /* MR10 */"); /* MR10 */ _gen("\n"); /* MR10 */ }; /* Do Attrib / Token ptr */ /* MR10 */ if (! p->label_used_in_semantic_pred) { /* MR10 */ /* MR10 */ if ( FoundGuessBlk ) { /* MR10 */ if (! done_NON_GUESSMODE) { /* MR10 */ done_NON_GUESSMODE=1; /* MR10 */ if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();} /* MR10 */ else {gen("zzNON_GUESS_MODE {\n"); tab();} /* MR10 */ }; /* MR10 */ }; /* MR10 */ /* MR10 */ if ( GenCC ) { /* MR10 */ if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) { /* MR10 */ gen3("%s = _t%d%d;\n", p->el_label, BlkLevel-1, p->elnum); /* MR10 */ } else { /* MR10 */ gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label); /* MR10 */ }; /* MR10 */ } else { /* MR10 */ gen1("%s = zzaCur;\n", p->el_label); /* MR10 */ }; /* MR10 */ }; /* Do AST ptr */ if (GenAST && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST) )) /* MR27 */ { /* MR10 */ if ( FoundGuessBlk ) { /* MR10 */ if (! done_NON_GUESSMODE) { /* MR10 */ done_NON_GUESSMODE=1; /* MR10 */ if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();} /* MR10 */ else {gen("zzNON_GUESS_MODE {\n"); tab();} /* MR10 */ }; /* MR10 */ }; if ( GenCC ) { gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum); } else {gen1("%s_ast = zzastCur;\n", p->el_label);} } /* MR10 */ if (done_NON_GUESSMODE) { /* MR10 */ gen("}\n"); tab(); /* MR10 */ }; } /* Handle any actions immediately following action */ if ( a != NULL ) /* MR10 */ /* MR11 */ { /* delay next token fetch until after action */ _gen("\n"); if ( a->is_predicate) { #if 0 /* Disabled in MR30 ************************************************************ And moved into genAction ***************************************************************************** */ gen("if (!("); /* make sure that '#line n' is on front of line */ /* MR14 */ if ( GenLineInfo && p->file != -1 ) _gen("\n"); /* MR14 */ dumpPredAction(a,a->action, output, 0, a->file, a->line, 0); /* MR23 Change failed predicate macro to have three arguments: macro arg 1: The stringized predicate itself macro arg 2: 0 => no user-defined error action 1 => user-defined error action macro arg 3: The user-defined error action This gives the user more control of the error action. */ _gen(")) \n"); tabs++; gen3(" {zzfailed_pred(\"%s\",%s,{ %s } );}\n", /* MR23 */ stringize(a->action), /* MR23 */ (a->pred_fail == NULL ? /* MR23/MR27 */ "0 /* report */" : "1 /* user action */"), /* MR23/MR27 */ (a->pred_fail == NULL ? /* MR23 */ "; /* no user action */" : a->pred_fail)); /* MR23 */ tabs--; /* Disabled in MR30 ************************************************************ And moved into genAction ***************************************************************************** */ #endif } else /* MR9 a regular action - not a predicate action */ { /* MR23: Search an action which is not a predicate for LT(i), LA(i), or LATEXT(i) in order to warn novice users that it refers to the previous matched token, not the next one. This is different than the case for semantic predicates. */ /* MR23 */ if (GenCC) { /* MR23 */ if (strstr(a->action, "LT(") != NULL) LTinTokenAction = 1; /* MR23 */ } /* MR23 */ else { /* MR23 */ if (strstr(a->action, "LA(") != NULL) LTinTokenAction = 1; /* MR23 */ if (strstr(a->action, "LATEXT(") != NULL) LTinTokenAction = 1; /* MR23 */ } if ( FoundGuessBlk ) { if ( GenCC ) {gen("if ( !guessing ) {\n");} else gen("zzNON_GUESS_MODE {\n"); } dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); /* MR21 */ if ( FoundGuessBlk ) gen("}\n"); a->done = 1; /* MR30 */ } /*** a->done = 1; MR30 Moved up into then branch for true actions, but not predicates ***/ if ( !DemandLookahead ) { if ( GenCC ) { if ( FoundException && p->use_def_MT_handler ) gen("if (!_signal)"); _gen(" consume();") if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;"); _gen("\n"); } else { if ( FoundException && p->use_def_MT_handler ) _gen("if (!_signal)"); _gen(" zzCONSUME;\n"); if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;"); _gen("\n"); } } else gen("\n"); if (a->done) { /* MR30 */ TRANS( a->next ); /* MR30 */ } /* MR30 */ else { /* MR30 */ TRANS( p->next ); /* MR30 */ } /* MR30 */ } else { if ( !DemandLookahead ) { if ( GenCC ) { if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)"); _gen(" consume();") if (FoundException&&p->use_def_MT_handler) _gen(" _signal=NoSignal;"); _gen("\n"); } else { if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)"); _gen(" zzCONSUME;"); if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;"); _gen("\n"); } } else _gen("\n"); TRANS(p->next); } } /* MR21 * * There was a bug in the code generation for {...} which causes it * to omit the optional tokens from the error messages. The easiest * way to fix this was to make the opt block look like a sub block: * * { a | b | c } * * becomes (internally): * * ( a | b | c | ) * * The code for genOptBlk is now identical to genSubBlk except for * cosmetic changes. */ void #ifdef __USE_PROTOS genOptBlk( Junction *q ) #else genOptBlk( q ) Junction *q; #endif { int max_k; set f; int need_right_curly; set savetkref; int lastAltEmpty; /* MR23 */ savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genOptBlk: not junction"); require(q->jtype == aOptBlk, "genOptBlk: not opt block"); OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */ f = genBlk(q, aOptBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); /* MR23 Bypass error clause generation when exceptions are used in {...} block See multi-line note in genBlk near call to isEmptyAlt. */ if (! FoundException) { if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );} } else { gen("/* MR23 skip error clause for {...} when exceptions in use */\n"); } { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); if ( q->guess ) { gen("zzGUESS_DONE\n"); } /* must duplicate if (alpha)?; one guesses (validates), the * second pass matches */ if ( q->guess && analysis_point(q)==q ) { OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );} { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); } tokensRefdInBlock = savetkref; if (q->end->p1 != NULL) TRANS(q->end->p1); } /* * Generate code for a loop blk of form: * * |---| * v | * --o-G-o-->o-- */ void #ifdef __USE_PROTOS genLoopBlk( Junction *begin, Junction *q, Junction *start, int max_k ) #else genLoopBlk( begin, q, start, max_k ) Junction *begin; Junction *q; Junction *start; /* where to start generating code from */ int max_k; #endif { set f; int need_right_curly; set savetkref; Junction *guessBlock; /* MR10 */ int singleAlt; /* MR10 */ int lastAltEmpty; /* MR23 */ savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genLoopBlk: not junction"); require(q->jtype == aLoopBlk, "genLoopBlk: not loop block"); if ( q->visited ) return; q->visited = TRUE; /* first_item_is_guess_block doesn't care what kind of node it is */ guessBlock=first_item_is_guess_block( (Junction *) q->p1); /* MR10 */ singleAlt=q->p2==NULL; /* MR10 */ if (singleAlt && !guessBlock) /* MR10 */ /* only one alternative? */ { if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } gen("while ( "); if ( begin!=NULL ) genExpr(begin); else genExpr(q); /* if no predicates have been hoisted for this single alt (..)* * do so now */ require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); if ( ParseWithPredicates && begin->predicate==NULL ) { Predicate *a = MR_find_predicates_and_supp((Node *)q->p1); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); if ( a!=NULL ) { _gen("&&"); a=genPredTreeMain(a, (Node *)q); /* MR10 */ } /* MR10 */ if (MRhoisting) { /* MR10 */ predicate_free(a); /* MR10 */ }; } _gen(" ) {\n"); tabs++; TRANS(q->p1); if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1); if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } --tabs; gen("}\n"); freeBlkFsets(q); q->visited = FALSE; tokensRefdInBlock = savetkref; return; } gen("for (;;) {\n"); /* MR20 G. Hobbelt */ tabs++; /* MR6 */ /* MR6 "begin" can never be null when called from genLoopBegin */ /* MR6 because q==(Junction *)begin->p1 and we know q is valid */ /* MR6 */ /* MR6 from genLoopBegin: */ /* MR6 */ /* MR6 if ( LL_k>1 && !set_nil(q->fset[2]) ) */ /* MR6 genLoopBlk( q, (Junction *)q->p1, q, max_k ); */ /* MR6 else genLoopBlk( q, (Junction *)q->p1, NULL, max_k ); */ /* MR6 */ if ( begin!=NULL ) { if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } /* The bypass arc of the (...)* predicts what to do when you fail, but * ONLY after having tested the loop start expression. To avoid this, * we simply break out of the (...)* loop when we find something that * is not in the prediction of the loop (all alts thereof). */ gen("if ( !("); /*** TJP says: It used to use the prediction expression for the bypass arc of the (...)*. HOWEVER, if a non LL^1(k) decision was found, this thing would miss the ftree stored in the aLoopBegin node and generate an LL^1(k) decision anyway. *** genExpr((Junction *)begin->p2); ***/ genExpr((Junction *)begin); _gen(")) break;\n"); } /* generate code for terminating loop (this is optional branch) */ f = genBlk(q, aLoopBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); set_free(f); freeBlkFsets(q); /* generate code for terminating loop (this is optional branch) */ /* MR6 */ /* MR6 30-May-97 Bug reported by Manuel Ornato */ /* MR6 A definite bug involving the exit from a loop block */ /* MR6 In 1.23 and later versions (including 1.33) Instead */ /* MR6 exiting the block and reporting a syntax error the */ /* MR6 code loops forever. */ /* MR6 Looking at 1.20 which generates proper code it is not */ /* MR6 clear which of two changes should be undone. */ /* MR6 This is my best guess. */ /* MR6 From earlier MR6 note we know that begin can never be */ /* MR6 null when genLoopBlk called from genLoopBegin */ /* MR6 */ /* MR6 */ if ( begin==NULL) { /* MR6 */ /* code for exiting loop "for sure" */ /* MR6 */ gen("/* Suppressed by MR6 */ /*** else break; ***/\n"); /* MR6 */ }; /* MR10 */if (singleAlt && guessBlock) { /* MR10 */ tabs--; /* MR6 */ gen("} else break; /* MR6 code for exiting loop \"for sure\" */\n"); /* MR10 */ need_right_curly--; /* MR10 */ } else { /* MR6 */ gen("else break; /* MR6 code for exiting loop \"for sure\" */\n"); /* MR10 */ }; { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1); --tabs; gen("}\n"); q->visited = FALSE; tokensRefdInBlock = savetkref; } /* * Generate code for a loop blk of form: * * |---| * v | * --o-->o-->o-G-o-->o-- * | ^ * v | * o-----------o * * q->end points to the last node (far right) in the blk. * * Note that q->end->jtype must be 'EndBlk'. * * Generate code roughly of the following form: * * do { * ... code for alternatives ... * } while ( First Set of aLoopBlk ); * * OR if > 1 alternative * * do { * ... code for alternatives ... * else break; * } while ( 1 ); */ void #ifdef __USE_PROTOS genLoopBegin( Junction *q ) #else genLoopBegin( q ) Junction *q; #endif { set f; int i; int max_k; set savetkref; savetkref = tokensRefdInBlock; require(q!=NULL, "genLoopBegin: invalid node and/or rule"); require(q->ntype == nJunction, "genLoopBegin: not junction"); require(q->jtype == aLoopBegin, "genLoopBegin: not loop block"); require(q->p2!=NULL, "genLoopBegin: invalid Loop Graph"); OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */ f = First(q, 1, aLoopBegin, &max_k); /* If not simple LL(1), must specify to start at LoopBegin, not LoopBlk */ if ( LL_k>1 && !set_nil(q->fset[2]) ) genLoopBlk( q, (Junction *)q->p1, q, max_k ); else genLoopBlk( q, (Junction *)q->p1, NULL, max_k ); for (i=1; i<=CLL_k; i++) set_free(q->fset[i]); for (i=1; i<=CLL_k; i++) set_free(((Junction *)q->p2)->fset[i]); --BlkLevel; BLOCK_Tail(); set_free(f); tokensRefdInBlock = savetkref; /* MR21 */ if (MR_BlkErr) { /* MR21 */ set f, fArray[2]; /* MR21 */ f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ ); /* MR21 */ fArray[0]= empty; /* MR21 */ fArray[1]= set_dup(f); /* MR21 */ gen("if ("); /* MR21 */ genExprSets(fArray,1); /* note: destroys set arguments */ /* MR21 */ _gen(") { /* MR21 option -mrblksynerr */\n"); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ _gen("/* nothing */ }\n"); /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,0 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ }; if (q->end->p1 != NULL) TRANS(q->end->p1); } /* * Generate code for a loop blk of form: * * |---| * v | * --o-G-o-->o-- * * q->end points to the last node (far right) in the blk. * Note that q->end->jtype must be 'EndBlk'. * * Generate code roughly of the following form: * * do { * ... code for alternatives ... * } while ( First Set of aPlusBlk ); * * OR if > 1 alternative * * do { * ... code for alternatives ... * else if not 1st time through, break; * } while ( 1 ); */ void #ifdef __USE_PROTOS genPlusBlk( Junction *q ) #else genPlusBlk( q ) Junction *q; #endif { int max_k; set f; int need_right_curly; int lastAltEmpty; /* MR23 */ set savetkref; Junction *guessBlock; /* MR10 */ int singleAlt; /* MR10 */ savetkref = tokensRefdInBlock; require(q!=NULL, "genPlusBlk: invalid node and/or rule"); require(q->ntype == nJunction, "genPlusBlk: not junction"); require(q->jtype == aPlusBlk, "genPlusBlk: not Plus block"); require(q->p2 != NULL, "genPlusBlk: not a valid Plus block"); if ( q->visited ) return; q->visited = TRUE; OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption((Junction *)q, q->pFirstSetSymbol); /* MR21 */ /* first_item_is_guess_block doesn't care what kind of node it is */ guessBlock=first_item_is_guess_block( (Junction *)q->p1); /* MR10 */ /* if the ignore flag is set on the 2nd alt and that alt is empty, * then it is the implied optional alternative that we added for (...)+ * and, hence, only 1 alt. */ /* MR10 Reported by Pulkkinen Esa (esap@cs.tut.fi) * Outer code for guess blocks ignored when there is only one alt * for a (...)+ block. * Force use of regular code rather than "optimized" code for that case */ singleAlt=( ( (Junction *) q->p2)->p2 == NULL) && ( ( (Junction *) q->p2)->ignore ); /* only one alternative? */ if (singleAlt && !guessBlock) /* MR10 */ { Predicate *a=NULL; /* if the only alt has a semantic predicate, hoist it; must test before * entering loop. */ if ( ParseWithPredicates ) { require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); a = MR_find_predicates_and_supp((Node *)q); require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty"); if ( a!=NULL ) { gen("if ("); a=genPredTreeMain(a, (Node *)q); /* MR10 */ _gen(") {\n"); } } gen("do {\n"); tabs++; TRANS(q->p1); if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1); f = First(q, 1, aPlusBlk, &max_k); if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } --tabs; gen("} while ( "); if ( q->parm!=NULL && q->predparm ) _gen1("(%s) && ", q->parm); genExpr(q); if ( ParseWithPredicates && a!=NULL ) { if (! MR_comparePredicates(q->predicate,a)) { _gen("&&"); a=genPredTreeMain(a, (Node *)q); /* MR10 */ }; } _gen(" );\n"); if ( ParseWithPredicates && a!=NULL ) gen("}\n"); --BlkLevel; BLOCK_Tail(); q->visited = FALSE; freeBlkFsets(q); set_free(f); tokensRefdInBlock = savetkref; /* MR21 */ if (MR_BlkErr) { /* MR21 */ set f, fArray[2]; /* MR21 */ f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ ); /* MR21 */ fArray[0]= empty; /* MR21 */ fArray[1]= set_dup(f); /* MR21 */ gen("if ("); /* MR21 */ genExprSets(fArray,1); /* note: destroys set arguments */ /* MR21 */ _gen(") { /* MR21 option -mrblksynerr */\n"); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ _gen("/* nothing */ }\n"); /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,1 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ }; if (q->end->p1 != NULL) TRANS(q->end->p1); /* MR10 */ if (MRhoisting) { /* MR10 */ predicate_free(a); /* MR10 */ }; return; } gen("do {\n"); tabs++; f = genBlk(q, aPlusBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); /* MR6 */ /* MR6 Sinan Karasu (sinan@tardis.ds.boeing.com) */ /* MR6 Failed to turn off guess mode when leaving block */ /* MR6 */ /* MR6 */ if ( has_guess_block_as_last_item(q) ) { /* MR10 */ gen("/* MR10 ()+ */ else {\n"); /* MR10 */ tabs++; /* MR10 */ need_right_curly++; /* MR10 */ gen("/* MR10 ()+ */ if ( !zzrv ) zzGUESS_DONE;\n"); /* MR6 */ gen("/* MR10 ()+ */ if ( zzcnt > 1 ) break;\n"); /* MR10 */ } else { /* MR10 */ gen("/* MR10 ()+ */ else {\n"); /* MR10 */ tabs++; /* MR10 */ need_right_curly++; /* MR10 */ gen("if ( zzcnt > 1 ) break;\n"); /* MR10 */ }; /* MR21 */ if (MR_BlkErr && 1 >= max_k) { /* MR21 */ set f; /* MR21 */ f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ ); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,0 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ } /* MR21 */ else { tab(); makeErrorClause(q,f,max_k,1 /* use plus block bypass ? */); /* MR21 I think this generates the wrong set ? */ /* MR21 because it includes the plus block bypass ? */ /* MR21 but I'm afraid to change it without additional checking */ } { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); gen("zzcnt++;"); if ( !GenCC ) _gen1(" zzLOOP(zztasp%d);", BlkLevel-1); _gen("\n"); if ( DemandLookahead ) { if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);} else gen1("look(%d);\n", max_k); } --tabs; if ( q->parm!=NULL && q->predparm ) {gen1("} while (%s);\n", q->parm);} else gen("} while ( 1 );\n"); --BlkLevel; BLOCK_Tail(); q->visited = FALSE; tokensRefdInBlock = savetkref; /* MR21 */ if (MR_BlkErr) { /* MR21 */ set f, fArray[2]; /* MR21 */ f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ ); /* MR21 */ fArray[0]= empty; /* MR21 */ fArray[1]= set_dup(f); /* MR21 */ gen("if ("); /* MR21 */ genExprSets(fArray,1); /* note: destroys set arguments */ /* MR21 */ _gen(") { /* MR21 option -mrblksynerr */\n"); /* MR21 */ tabs++; /* MR21 */ tab(); /* MR21 */ _gen("/* nothing */ }\n"); /* MR21 */ tab(); /* MR21 */ makeErrorClause(q,f,1,1 /* use plus block bypass ? */ ); /* frees set */ /* MR21 */ tabs--; /* MR21 */ }; if (q->end->p1 != NULL) TRANS(q->end->p1); } /* * Generate code for a sub blk of alternatives of form: * * --o-G1--o-- * | ^ * v /| * o-G2-o| * | ^ * v | * .......... * | ^ * v / * o-Gn-o * * q points to the 1st junction of blk (upper-left). * q->end points to the last node (far right) in the blk. * Note that q->end->jtype must be 'EndBlk'. * The last node in every alt points to q->end. * * Generate code of the following form: * if ( First(G1) ) { * ...code for G1... * } * else if ( First(G2) ) { * ...code for G2... * } * ... * else { * ...code for Gn... * } */ void #ifdef __USE_PROTOS genSubBlk( Junction *q ) #else genSubBlk( q ) Junction *q; #endif { int max_k; set f; int need_right_curly; int lastAltEmpty; /* MR23 */ set savetkref; savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genSubBlk: not junction"); require(q->jtype == aSubBlk, "genSubBlk: not subblock"); OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */ f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); /* MR23 Bypass error clause generation when exceptions are used in a sub block in which the last alternative is epsilon. Example: "(A | B | )". See multi-line note in genBlk near call to isEmptyAlt. */ if (FoundException && lastAltEmpty) { gen("/* MR23 skip error clause for (...| epsilon) when exceptions in use */\n"); } else { if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );} } { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); if ( q->guess ) { gen("zzGUESS_DONE\n"); } /* must duplicate if (alpha)?; one guesses (validates), the * second pass matches */ if ( q->guess && analysis_point(q)==q ) { OutLineInfo(output,q->line,FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */);} { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets(q); --BlkLevel; BLOCK_Tail(); } tokensRefdInBlock = savetkref; if (q->end->p1 != NULL) TRANS(q->end->p1); } static int TnodesAllocatedPrevRule=0; /* * Generate code for a rule. * * rule--> o-->o-Alternatives-o-->o * Or, * rule--> o-->o-Alternative-o-->o * * The 1st junction is a RuleBlk. The second can be a SubBlk or just a junction * (one alternative--no block), the last is EndRule. * The second to last is EndBlk if more than one alternative exists in the rule. * * To get to the init-action for a rule, we must bypass the RuleBlk, * and possible SubBlk. * Mark any init-action as generated so genBlk() does not regenerate it. */ void #ifdef __USE_PROTOS genRule( Junction *q ) #else genRule( q ) Junction *q; #endif { const char * returnValueInitializer; do { /* MR10 Change recursion into iteration */ int max_k; set follow, rk, f; ActionNode *a; RuleEntry *r; int lastAltEmpty; /* MR23 */ static int file = -1; int need_right_curly; require(q->ntype == nJunction, "genRule: not junction"); require(q->jtype == RuleBlk, "genRule: not rule"); /* MR14 */ require (MR_BackTraceStack.count == 0,"-alpha MR_BackTraceStack.count != 0"); /* MR14 */ MR_pointerStackReset(&MR_BackTraceStack); /* MR14 */ if (AlphaBetaTrace) MR_MaintainBackTrace=1; CurRule=q->rname; /* MR11 */ r = (RuleEntry *) hash_get(Rname, q->rname); if ( r == NULL ) warnNoFL("Rule hash table is screwed up beyond belief"); if ( q->file != file ) /* open new output file if need to */ { /* MR6 */ /* MR6 Simpler to debug when output goes to stdout rather than a file */ /* MR6 */ /* MR6 */ if (UseStdout) { /* MR6 */ output = stdout; /* MR6 */ } else { /* MR6 */ if ( output != NULL) fclose( output ); /* MR6 */ output = fopen(OutMetaName(outname(FileStr[q->file])), "w"); /* MR6 */ }; require(output != NULL, "genRule: can't open output file"); #ifdef SPECIAL_FOPEN special_fopen_actions(OutMetaName(outname(FileStr[q->file]))); /* MR1 */ #endif if ( file == -1 ) genHdr1(q->file); else genHdr(q->file); file = q->file; } if (InfoM) { fprintf(stderr," rule %s\n",q->rname); fflush(output); }; #if 0 if (strcmp(q->rname,"***debug***") == 0) { fprintf(stderr,"***debug*** %s reached\n",q->rname); MR_break(); }; #endif DumpFuncHeader(q,r); tabs++; /* MR23 If there is a single return value then it can be initialized in the declaration using assignment syntax. If there are multiple return values then antlr creates a struct and initialization takes place element by element for each element of the struct. For multiple elements the initialization is by assignment so we have to wait until all declarations are done before emitting that code - because of restrictions in C which don't exist in C++. In the past (before MR23) the only kind of initialization was the PURIFY macro which was just a memset() of 0. Now we allow the user to specify an initial value. PURIFY is still used in C mode because C does not have constructors. However, PURIFY is not used in C++ mode because it might overwrite information created by elements which have their own ctor. */ if ( q->ret!=NULL ) { if ( hasMultipleOperands(q->ret) ) /* MR23 */ { /* Emit initialization code later. */ gen1("struct _rv%d _retv;\n",r->rulenum); } else { /* Emit initialization code now. */ tab(); DumpType(q->ret, output); returnValueInitializer = getInitializer(q->ret); if (returnValueInitializer == NULL) { /* MR23 */ gen(" _retv;\n"); /* MR1 MR3 */ } /* MR23 */ else { /* MR23 */ gen1(" _retv = %s;\n", returnValueInitializer); /* MR23 */ } /* MR23 */ } } OutLineInfo(output,q->line,FileStr[q->file]); if (InfoM) { fflush(output); }; gen("zzRULE;\n"); if ( FoundException ) { gen("int _sva=1;\n"); } if ( GenCC && GenAST ) gen("ASTBase *_ast = NULL, *_sibling = NULL, *_tail = NULL;\n"); if ( GenCC ) genTokenPointers(q); if ( GenCC&&GenAST ) genASTPointers(q); if ( q->el_labels!=NULL ) genElementLabels(q->el_labels); if ( FoundException ) gen("int _signal=NoSignal;\n"); if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel); /* MR10 */ /* move zzTRACEIN to before init action */ /* MR10 */ if ( TraceGen ) { /* MR10 */ if ( GenCC ) {gen1("zzTRACEIN(\"%s\");\n", q->rname);} /* MR10 */ else gen1("zzTRACEIN((ANTLRChar *)\"%s\");\n", q->rname); /* MR10 */ } /* MR7 Moved PURIFY() to after all local variables have been declared */ /* MR7 so that the generated code is valid C as well as C++ */ /* MR7 Jan Mikkelsen 10-June-1997 */ /* MR23 Do the PURIFY macro only for C mode. C++ users should use constructors or initialization expressions. */ if ( q->ret != NULL ) /* MR7 */ { /* MR7 */ if (hasMultipleOperands(q->ret)) { /* MR23 */ if (PURIFY == TRUE) { gen1("PCCTS_PURIFY(_retv,sizeof(struct _rv%d))\n",r->rulenum); /* MR23 */ } } /* MR7 */ else { /* MR7 */ /* MR23 If there were only one return value operand and it had an initializer then it would have been initialized in the declaration. */ returnValueInitializer = getInitializer(q->ret); /* MR23 */ if (returnValueInitializer == NULL) { /* MR23 */ if (PURIFY == TRUE) { gen("PCCTS_PURIFY(_retv,sizeof("); /* MR23 */ DumpType(q->ret, output); /* MR7 */ gen("))\n"); /* MR7 */ } } /* MR23 */ } /* MR7 */ if (hasMultipleOperands(q->ret)) { /* MR23 */ DumpInitializers(output, r, q->ret); /* MR23 */ } } if ( !GenCC ) gen("zzMake0;\n"); if ( FoundException ) gen("*_retsignal = NoSignal;\n"); if ( !GenCC ) gen("{\n"); if ( has_guess_block_as_first_item((Junction *)q->p1) ) { gen("zzGUESS_BLOCK\n"); } /* L o o k F o r I n i t A c t i o n */ if ( ((Junction *)q->p1)->jtype == aSubBlk ) a = findImmedAction( ((Junction *)q->p1)->p1 ); else a = findImmedAction( q->p1 ); /* only one alternative in rule */ if ( a!=NULL && !a->is_predicate) { /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); a->done = 1; /* ignore action. We have already handled it */ } BlkLevel++; q->visited = TRUE; /* mark RULE as visited for FIRST/FOLLOW */ BlockPreambleOption((Junction *)q->p1, NULL); /* MR21 */ f = genBlk((Junction *)q->p1, RuleBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */); if ( q->p1 != NULL ) if ( ((Junction *)q->p1)->p2 != NULL ) {tab(); makeErrorClause((Junction *)q->p1,f,max_k,0 /* use plus block bypass ? */);} { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } freeBlkFsets((Junction *)q->p1); q->visited = FALSE; --BlkLevel; if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel); genTraceOut(q); if ( q->ret!=NULL ) gen("return _retv;\n") else gen("return;\n"); /* E r r o r R e c o v e r y */ NewSet(); rk = empty; /* MR14 */ if (r->dontComputeErrorSet) { /* MR14 */ follow=empty; } else { MR_pointerStackReset(&MR_BackTraceStack); /* MR14 */ MR_ErrorSetComputationActive=1; REACH(q->end, 1, &rk, follow); MR_ErrorSetComputationActive=0; require (MR_BackTraceStack.count == 0,"K: MR_BackTraceStack.count != 0"); } FillSet( follow ); set_free( follow ); /* MR20 G. Hobbelt Isn't it so that "fail:" is ONLY referenced when: !FoundException || FoundGuessBlk ? Therefore add the "if" around this piece of code generation... Should guessing mode also use _handler label instead of "fail" when exception handling is active? gen can automatically put "if (guessing)" there so as to skip all kinds of user code. */ if ( !FoundException || FoundGuessBlk ) /* MR20 G. Hobbelt */ { /* MR20 G. Hobbelt */ _gen("fail:\n"); if ( !GenCC ) gen("zzEXIT(zztasp1);\n"); if ( FoundGuessBlk ) { if ( !GenCC ) {gen("if ( zzguessing ) zzGUESS_FAIL;\n");} else gen("if ( guessing ) zzGUESS_FAIL;\n"); } if ( q->erraction!=NULL ) dumpAction(q->erraction, output, tabs, q->file, q->line, 1); if ( GenCC ) { gen1("syn(zzBadTok, %s, zzMissSet, zzMissTok, zzErrk);\n", r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup); } else { gen1("zzsyn(zzMissText, zzBadTok, %s, zzMissSet, zzMissTok, zzErrk, zzBadText);\n", r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup); } gen3("%sresynch(setwd%d, 0x%x);\n", GenCC?"":"zz", wordnum, 1<ret!=NULL ) { genTraceOut(q); gen("return _retv;\n"); } else if ( q->exceptions!=NULL ) { genTraceOut(q); gen("return;\n"); } else if (!FoundException) { /* MR10 */ genTraceOut(q); /* MR10 */ }; } /* MR20 G. Hobbelt */ if ( !GenCC ) gen("}\n"); /* Gen code for exception handlers */ /* make sure each path out contains genTraceOut() */ if ( q->exceptions!=NULL ) { gen("/* exception handlers */\n"); dumpExceptions(q->exceptions); if ( !r->has_rule_exception ) { _gen("_handler:\n"); gen("zzdflthandlers(_signal,_retsignal);\n"); } /* MR20 G. Gobbelt The label "adios" is never referenced */ #if 0 _gen("_adios:\n"); #endif if ( q->ret!=NULL ) { genTraceOut(q); gen("return _retv;\n"); } else { genTraceOut(q); gen("return;\n"); } } else if ( FoundException ) { _gen("_handler:\n"); gen("zzdflthandlers(_signal,_retsignal);\n"); /* MR1 */ /* MR1 7-Apr-97 Fix suggested by: John Bair (jbair@iftime.com) */ /* MR1 */ if ( q->ret != NULL) { /* MR1 */ genTraceOut(q); /* MR10 */ gen("return _retv;\n"); /* MR1 */ } else { /* MR1 */ genTraceOut(q); /* MR10 */ gen("return;\n") ; /* MR1 */ }; /* MR1 */ } tabs--; gen("}\n"); /* MR10 Tired of looking at stacks that are as deep as the number of */ /* MR10 rules. Changes recursion to iteration. */ MR_releaseResourcesUsedInRule( (Node *) q ); /* MR10 */ if (InfoT) { fprintf(output,"\n/* tnodes created for rule %s: %d */\n", q->rname, (TnodesAllocated-TnodesAllocatedPrevRule) ); }; TnodesAllocatedPrevRule=TnodesAllocated; if (q->p2 == NULL) dumpAfterActions( output ); q=(Junction *)q->p2; require(q==NULL || q->jtype==RuleBlk,"RuleBlk p2 does not point to another RuleBlk"); } while (q != NULL); /**** The old code ****/ /**** if ( q->p2 != NULL ) {TRANS(q->p2);} ****/ /* generate code for next rule too */ /**** else dumpAfterActions( output ); ****/ } /* This is for the function definition, not the declaration. */ static void #ifdef __USE_PROTOS DumpFuncHeader( Junction *q, RuleEntry *r ) #else DumpFuncHeader( q, r ) Junction *q; RuleEntry *r; #endif { /* */ /* MR1 10-Apr-97 MR1 Simplify insertion of commas in function header */ /* */ int needComma; /* MR1 */ /* A N S I */ _gen("\n"); if ( q->ret!=NULL ) { if ( hasMultipleOperands(q->ret) ) /* MR23 */ { if (GenCC) gen2("%s::_rv%d\n", CurrentClassName, r->rulenum) else gen1("struct _rv%d\n",r->rulenum); } else { DumpType(q->ret, output); gen("\n"); } } else { _gen("void\n"); } /* MR1 */ /* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */ /* MR1 */ if ( !GenCC ) _gen("#ifdef __USE_PROTOS\n"); /* MR1 */ if ( !GenCC ) gen2("%s%s(", RulePrefix, q->rname) else gen3("%s::%s%s(", CurrentClassName, RulePrefix,q->rname); /* If we generate C++ method names, we must hide default arguments */ /* which can appear in the parameter declaration list. */ /* NOTICE: this is done only here, for the method definition, but */ /* not for the method declaration inside the class */ /* definition. This is exactly the behaviour defined in */ /* C++ standard for default parameters. */ DumpANSIFunctionArgDef(output,q, 0 /* emit initializers ? */); _gen("\n"); if ( GenCC ) { gen("{\n"); return; } /* K & R */ gen("#else\n"); gen2("%s%s(", RulePrefix, q->rname); needComma=0; /* MR1 */ if ( GenAST ) /* MR1 */ { /* MR1 */ _gen("_root"); /* MR1 */ needComma=1; /* MR1 */ } /* MR1 */ if ( FoundException ) /* MR1 */ { /* MR1 */ if (needComma) {_gen(",");needComma=0;}; /* MR1 */ _gen("_retsignal"); /* MR1 */ needComma=1; /* MR1 */ } /* MR1 */ /* MR5 Change below by Jan Mikkelsen (janm@zeta.org.au) 26-May-97 MR5 */ DumpListOfParmNames( q->pdecl, output, needComma ); /* MR5 */ gen(")\n"); if ( GenAST ) gen("AST **_root;\n"); if ( FoundException ) gen("int *_retsignal;\n"); DumpOldStyleParms( q->pdecl, output ); gen("#endif\n"); gen("{\n"); } void #ifdef __USE_PROTOS DumpANSIFunctionArgDef(FILE *f, Junction *q, int bInitializer) #else DumpANSIFunctionArgDef(f,q,bInitializer) FILE *f; Junction *q; int bInitializer; #endif { if ( GenAST ) { if ( GenCC ) {fprintf(f,"ASTBase **_root");} else fprintf(f,"AST**_root"); if ( !FoundException && q->pdecl!=NULL ) fprintf(f,","); } if ( FoundException ) { if ( GenAST ) fprintf(f,","); fprintf(f,"int *_retsignal"); if ( q->pdecl!=NULL ) { fprintf(f,","); } } if ( q->pdecl!=NULL ) { DumpFormals(f, q->pdecl, bInitializer); /* MR23 */ } else { if ( !GenAST && !FoundException ) { fprintf(f,"void"); } } fprintf(f,")"); } void #ifdef __USE_PROTOS genJunction( Junction *q ) #else genJunction( q ) Junction *q; #endif { require(q->ntype == nJunction, "genJunction: not junction"); require(q->jtype == Generic, "genJunction: not generic junction"); if ( q->p1 != NULL ) TRANS(q->p1); if ( q->p2 != NULL ) TRANS(q->p2); } void #ifdef __USE_PROTOS genEndBlk( Junction *q ) #else genEndBlk( q ) Junction *q; #endif { } void #ifdef __USE_PROTOS genEndRule( Junction *q ) #else genEndRule( q ) Junction *q; #endif { } void #ifdef __USE_PROTOS genHdr( int file ) #else genHdr( file ) int file; #endif { int i; _gen("/*\n"); _gen(" * A n t l r T r a n s l a t i o n H e a d e r\n"); _gen(" *\n"); _gen(" * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n"); _gen(" * Purdue University Electrical Engineering\n"); _gen(" * With AHPCRC, University of Minnesota\n"); _gen1(" * ANTLR Version %s\n", Version); _gen(" *\n"); /* MR10 */ _gen(" * "); /* MR10 */ for (i=0 ; i < Save_argc ; i++) { /* MR10 */ _gen(" "); /* MR10 */ _gen1("%s", Save_argv[i]); /* MR10 */ }; _gen("\n"); _gen(" *\n"); _gen(" */\n\n"); if (FirstAction != NULL ) dumpAction( FirstAction, output, 0, -1, 0, 1); /* MR11 MR15b */ _gen1("#define ANTLR_VERSION %s\n", VersionDef); _gen("#include \"pcctscfg.h\"\n"); _gen("#include \"pccts_stdio.h\"\n"); if ( strcmp(ParserName, DefaultParserName)!=0 ) _gen2("#define %s %s\n", DefaultParserName, ParserName); if ( strcmp(ParserName, DefaultParserName)!=0 ) {_gen1("#include \"%s\"\n", RemapFileName);} OutLineInfo(output,1,FileStr[file]); if ( GenCC ) { if ( UserTokenDefsFile != NULL ) fprintf(output, "#include %s\n", UserTokenDefsFile); else fprintf(output, "#include \"%s\"\n", DefFileName); } if ( HdrAction != NULL ) dumpAction( HdrAction, output, 0, -1, 0, 1); if ( !GenCC && FoundGuessBlk ) { _gen("#define ZZCAN_GUESS\n"); _gen("#include \"pccts_setjmp.h\"\n"); /* MR15 K.J. Cummings (cummings@peritus.com) */ } if ( FoundException ) { _gen("#define EXCEPTION_HANDLING\n"); _gen1("#define NUM_SIGNALS %d\n", NumSignals); } if ( !GenCC && OutputLL_k > 1 ) _gen1("#define LL_K %d\n", OutputLL_k); if ( GenAST&&!GenCC ) _gen("#define GENAST\n\n"); if ( GenAST ) { if ( GenCC ) {_gen1("#include \"%s\"\n\n", ASTBASE_H);} else _gen("#include \"ast.h\"\n\n"); } if ( !GenCC && DemandLookahead ) _gen("#define DEMAND_LOOK\n\n"); #ifdef DUM if ( !GenCC && LexGen ) { _gen1("#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken)); } #endif /* ###WARNING: This will have to change when SetWordSize changes */ if ( !GenCC ) _gen1("#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned)); if (TraceGen) { _gen("#ifndef zzTRACE_RULES\n"); /* MR20 */ _gen("#define zzTRACE_RULES\n"); /* MR20 */ _gen("#endif\n"); /* MR22 */ }; if ( !GenCC ) {_gen("#include \"antlr.h\"\n");} else { _gen1("#include \"%s\"\n", APARSER_H); _gen1("#include \"%s.h\"\n", CurrentClassName); } if ( !GenCC ) { if ( UserDefdTokens ) {_gen1("#include %s\n", UserTokenDefsFile);} /* still need this one as it has the func prototypes */ _gen1("#include \"%s\"\n", DefFileName); } /* still need this one as it defines the DLG interface */ if ( !GenCC ) _gen("#include \"dlgdef.h\"\n"); if ( LexGen && GenCC ) _gen1("#include \"%s\"\n", DLEXERBASE_H); if ( GenCC ) _gen1("#include \"%s\"\n", ATOKPTR_H); if ( !GenCC && LexGen ) _gen1("#include \"%s\"\n", ModeFileName); /* MR10 Ofer Ben-Ami (gremlin@cs.huji.ac.il) */ /* MR10 Finally, a definition of the Purify macro */ if (PURIFY == TRUE) { /* MR23 */ _gen("\n/* MR23 In order to remove calls to PURIFY use the antlr"); /* MR23 */ _gen(" -nopurify option */\n\n"); /* MR23 */ _gen("#ifndef PCCTS_PURIFY\n"); _gen("#define PCCTS_PURIFY(r,s) memset((char *) &(r),'\\0',(s));\n"); _gen("#endif\n\n"); } /* MR23 */ } void #ifdef __USE_PROTOS genHdr1( int file ) #else genHdr1( file ) int file; #endif { ListNode *p; genHdr(file); if ( GenAST ) { if ( !GenCC ) { _gen("#include \"ast.c\"\n"); _gen("zzASTgvars\n\n"); } } if ( !GenCC ) _gen("ANTLR_INFO\n"); if ( BeforeActions != NULL ) { for (p = BeforeActions->next; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, output, 0, ua->file, ua->line, 1); } } if ( !FoundException ) return; if ( GenCC ) { _gen1("\nvoid %s::\n", CurrentClassName); _gen("zzdflthandlers( int _signal, int *_retsignal )\n"); _gen("{\n"); } else { _gen("\nvoid\n"); /* MR1 */ /* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */ /* MR1 */ _gen("#ifdef __USE_PROTOS\n"); /* MR1 */ _gen("zzdflthandlers( int _signal, int *_retsignal )\n"); _gen("#else\n"); _gen("zzdflthandlers( _signal, _retsignal )\n"); _gen("int _signal;\n"); _gen("int *_retsignal;\n"); _gen("#endif\n"); _gen("{\n"); } tabs++; if ( DefaultExGroup!=NULL ) { dumpException(DefaultExGroup, 1); if ( !hasDefaultException(DefaultExGroup) ) { gen("default :\n"); tabs++; gen("*_retsignal = _signal;\n"); tabs--; gen("}\n"); } } else { gen("*_retsignal = _signal;\n"); } tabs--; _gen("}\n\n"); } void #ifdef __USE_PROTOS genStdPCCTSIncludeFile( FILE *f,char *gate ) /* MR10 */ #else genStdPCCTSIncludeFile( f , gate) /* MR10 */ FILE *f; char * gate; /* MR10 */ #endif { /* MR10 Ramanathan Santhanam (ps@kumaran.com) */ /* MR10 Same preprocessor symbol use to gate stdpccts.h */ /* MR10 even when two grammars are in use. */ /* MR10 Derive gate symbol from -fh filename */ if (gate == NULL) { fprintf(f,"#ifndef STDPCCTS_H\n"); /* MR10 */ fprintf(f,"#define STDPCCTS_H\n"); /* MR10 */ } else { fprintf(f,"#ifndef STDPCCTS_%s_H\n",gate); /* MR10 */ fprintf(f,"#define STDPCCTS_%s_H\n",gate); /* MR10 */ }; fprintf(f,"/*\n"); if (gate == NULL) { fprintf(f," * %s -- P C C T S I n c l u d e\n", stdpccts); } else { fprintf(f," * Standard PCCTS include file with -fh %s -- P C C T S I n c l u d e\n", stdpccts); } fprintf(f," *\n"); fprintf(f," * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n"); fprintf(f," * Purdue University Electrical Engineering\n"); fprintf(f," * With AHPCRC, University of Minnesota\n"); fprintf(f," * ANTLR Version %s\n", Version); fprintf(f," */\n\n"); fprintf(f,"#ifndef ANTLR_VERSION\n"); fprintf(f,"#define ANTLR_VERSION %s\n", VersionDef); fprintf(f,"#endif\n\n"); if (FirstAction != NULL ) dumpAction(FirstAction, f, 0, -1, 0, 1); /* MR11 */ fprintf(f,"#include \"pcctscfg.h\"\n"); fprintf(f,"#include \"pccts_stdio.h\"\n"); if ( GenCC ) { if ( UserDefdTokens ) fprintf(f, "#include %s\n", UserTokenDefsFile); else { fprintf(f, "#include \"%s\"\n", DefFileName); } fprintf(f, "#include \"%s\"\n", ATOKEN_H); if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1); fprintf(f, "#include \"%s\"\n", ATOKENBUFFER_H); if ( OutputLL_k > 1 ) fprintf(f,"static const unsigned LL_K=%d;\n", OutputLL_k); if ( GenAST ) { fprintf(f, "#include \"%s\"\n", ASTBASE_H); } if (TraceGen) { fprintf(f,"#ifndef zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#define zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#endif\n"); /* MR22 */ }; fprintf(f,"#include \"%s\"\n", APARSER_H); fprintf(f,"#include \"%s.h\"\n", CurrentClassName); if ( LexGen ) fprintf(f,"#include \"%s\"\n", DLEXERBASE_H); fprintf(f, "#endif\n"); return; } if ( strcmp(ParserName, DefaultParserName)!=0 ) fprintf(f, "#define %s %s\n", DefaultParserName, ParserName); if ( strcmp(ParserName, DefaultParserName)!=0 ) fprintf(f, "#include \"%s\"\n", RemapFileName); if ( UserTokenDefsFile != NULL ) fprintf(f, "#include %s\n", UserTokenDefsFile); if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1); if ( FoundGuessBlk ) { fprintf(f,"#define ZZCAN_GUESS\n"); fprintf(f,"#include \"pccts_setjmp.h\"\n"); } if (TraceGen) { fprintf(f,"#ifndef zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#define zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#endif\n"); /* MR22 */ }; if ( OutputLL_k > 1 ) fprintf(f,"#define LL_K %d\n", OutputLL_k); if ( GenAST ) fprintf(f,"#define GENAST\n"); if ( FoundException ) { /* MR1 7-Apr-97 1.33MR1 */ /* MR1 Fix suggested by: */ /* MR1 Francois-Xavier Fontaine (fontaine_f@istvax.ist.lu) */ fprintf(f,"#define EXCEPTION_HANDLING\n"); /* MR1 */ fprintf(f,"#define NUM_SIGNALS %d\n", NumSignals); /* MR1 */ } if ( DemandLookahead ) fprintf(f,"#define DEMAND_LOOK\n"); #ifdef DUM if ( LexGen ) fprintf(f, "#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken)); #endif /* ###WARNING: This will have to change when SetWordSize changes */ fprintf(f, "#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned)); if (TraceGen) { fprintf(f,"#ifndef zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#define zzTRACE_RULES\n"); /* MR20 */ fprintf(f,"#endif\n"); /* MR22 */ }; fprintf(f,"#include \"antlr.h\"\n"); if ( GenAST ) fprintf(f,"#include \"ast.h\"\n"); if ( UserDefdTokens ) fprintf(f, "#include %s\n", UserTokenDefsFile); /* still need this one as it has the func prototypes */ fprintf(f, "#include \"%s\"\n", DefFileName); /* still need this one as it defines the DLG interface */ fprintf(f,"#include \"dlgdef.h\"\n"); /* don't need this one unless DLG is used */ if ( LexGen ) fprintf(f,"#include \"%s\"\n", ModeFileName); fprintf(f,"#endif\n"); } /* dump action 's' to file 'output' starting at "local" tab 'tabs' Dump line information in front of action if GenLineInfo is set If file == -1 then GenLineInfo is ignored. The user may redefine the LineInfoFormatStr to his/her liking most compilers will like the default, however. June '93; changed so that empty lines are left alone so that line information is correct for the compiler/debuggers. */ void #ifdef __USE_PROTOS dumpAction( char *s, FILE *output, int tabs, int file, int line, int final_newline ) #else dumpAction( s, output, tabs, file, line, final_newline ) char *s; FILE *output; int tabs; int file; int line; int final_newline; #endif { int inDQuote, inSQuote; require(s!=NULL, "dumpAction: NULL action"); require(output!=NULL, eMsg1("dumpAction: output FILE is NULL for %s",s)); if ( GenLineInfo && file != -1 ) { OutLineInfo(output,line,FileStr[file]); } PastWhiteSpace( s ); /* don't print a tab if first non-white char is a # (preprocessor command) */ if ( *s!='#' ) {TAB;} inDQuote = inSQuote = FALSE; while ( *s != '\0' ) { if ( *s == '\\' ) { fputc( *s++, output ); /* Avoid '"' Case */ if ( *s == '\0' ) return; if ( *s == '\'' ) fputc( *s++, output ); if ( *s == '\"' ) fputc( *s++, output ); } if ( *s == '\'' ) { if ( !inDQuote ) inSQuote = !inSQuote; } if ( *s == '"' ) { if ( !inSQuote ) inDQuote = !inDQuote; } if ( *s == '\n' ) { fputc('\n', output); s++; PastWhiteSpace( s ); if ( *s == '}' ) { --tabs; TAB; fputc( *s++, output ); continue; } if ( *s == '\0' ) return; if ( *s != '#' ) /* #define, #endif etc.. start at col 1 */ { TAB; } } if ( *s == '}' && !(inSQuote || inDQuote) ) { --tabs; /* Indent one fewer */ } if ( *s == '{' && !(inSQuote || inDQuote) ) { tabs++; /* Indent one more */ } fputc( *s, output ); s++; } if ( final_newline ) fputc('\n', output); } static void #ifdef __USE_PROTOS dumpAfterActions( FILE *output ) #else dumpAfterActions( output ) FILE *output; #endif { ListNode *p; require(output!=NULL, "dumpAfterActions: output file was NULL for some reason"); if ( AfterActions != NULL ) { for (p = AfterActions->next; p!=NULL; p=p->next) { UserAction *ua = (UserAction *)p->elem; dumpAction( ua->action, output, 0, ua->file, ua->line, 1); } } fclose( output ); } /* * Find the next action in the stream of execution. Do not pass * junctions with more than one path leaving them. * Only pass generic junctions. * * Scan forward while (generic junction with p2==NULL) * If we stop on an action, return ptr to the action * else return NULL; */ static ActionNode * #ifdef __USE_PROTOS findImmedAction( Node *q ) #else findImmedAction( q ) Node *q; #endif { Junction *j; require(q!=NULL, "findImmedAction: NULL node"); require(q->ntype>=1 && q->ntype<=NumNodeTypes, "findImmedAction: invalid node"); while ( q->ntype == nJunction ) { j = (Junction *)q; if ( j->jtype != Generic || j->p2 != NULL ) return NULL; q = j->p1; if ( q == NULL ) return NULL; } if ( q->ntype == nAction ) return (ActionNode *)q; return NULL; } static void #ifdef __USE_PROTOS dumpRetValAssign( char *retval, char *ret_def, RuleRefNode * ruleRef /* MR30 */) #else dumpRetValAssign( retval, ret_def, ruleRef /* MR30 */) char *retval; char *ret_def; RuleRefNode *ruleRefNode; #endif { char *q = ret_def; tab(); while ( *retval != '\0' && *q != '\0') { while ( isspace((*retval)) ) retval++; while ( *retval!=',' && *retval!='\0' ) fputc(*retval++, output); fprintf(output, " = _trv."); DumpNextNameInDef(&q, output); while ( isspace(*q) ) q++; fputc(';', output); fputc(' ', output); if ( *retval == ',' ) retval++; } if (*retval == '\0' && *q != '\0') { /* MR30 */ errFL("Fewer output values than output formals for rule reference", /* MR30 */ FileStr[ruleRef->file],ruleRef->line); } if (*retval != '\0' && *q == '\0') { /* MR30 */ errFL("More output actuals than output formals for rule reference", /* MR30 */ FileStr[ruleRef->file],ruleRef->line); } } /* This function computes the set of tokens that can possibly be seen k * tokens in the future from point j */ static set #ifdef __USE_PROTOS ComputeErrorSet( Junction *j, int k, int usePlusBlockBypass) #else ComputeErrorSet( j, k, usePlusBlockBypass ) Junction *j; int k; int usePlusBlockBypass; #endif { Junction *alt1; set a, rk, f; require(j->ntype==nJunction, "ComputeErrorSet: non junction passed"); f = rk = empty; for (alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2) { if (alt1->ignore && ! usePlusBlockBypass) continue; /* MR21 - Ignore aPlusBlk forward p2 */ REACH(alt1->p1, k, &rk, a); require(set_nil(rk), "ComputeErrorSet: rk != nil"); set_free(rk); set_orin(&f, a); set_free(a); } return f; } static char * #ifdef __USE_PROTOS tokenFollowSet(TokNode *p) #else tokenFollowSet(p) TokNode *p; #endif { static char buf[100]; set rk, a; int n; rk = empty; REACH(p->next, 1, &rk, a); require(set_nil(rk), "rk != nil"); set_free(rk); n = DefErrSet( &a, 0, NULL ); set_free(a); if ( GenCC ) sprintf(buf, "err%d", n); else sprintf(buf, "zzerr%d", n); return buf; } static void #ifdef __USE_PROTOS makeErrorClause( Junction *q, set f, int max_k, int usePlusBlockBypass ) #else makeErrorClause( q, f, max_k, usePlusBlockBypass ) Junction *q; set f; int max_k; int usePlusBlockBypass; #endif { char * handler_id=""; /* MR7 */ int nilf=0; /* MR13 */ RuleEntry *ruleEntry; /* MR14 */ if ( FoundException ) { _gen("else {\n"); tabs++; if ( FoundGuessBlk ) { if ( GenCC ) {gen("if ( guessing ) goto fail;\n");} else gen("if ( zzguessing ) goto fail;\n"); } gen("if (_sva) _signal=NoViableAlt;\n"); gen("else _signal=NoSemViableAlt;\n"); if (q->outerEG != NULL) { handler_id=q->outerEG->altID; #if 0 } else { printf("q->curAltNum=%d q->exception_label=%s\n",q->curAltNum,q->exception_label); gen("*** DEBUG *** outerEG==NULL\n"); #endif }; gen1("goto %s_handler; /* MR7 */\n",handler_id); /* MR7 */ tabs--; gen("}\n"); return; } if ( max_k == 1 ) { /* MR13 */ nilf=set_nil(f); if ( GenCC ) { _gen1("else {FAIL(1,err%d", DefErrSet1(1,&f,1,NULL)); } else { _gen1("else {zzFAIL(1,zzerr%d", DefErrSet1(1,&f,1,NULL)); }; set_free(f); } else { int i; set_free(f); if ( GenCC ) {_gen1("else {FAIL(%d", max_k);} else _gen1("else {zzFAIL(%d", max_k); ruleEntry = (RuleEntry *) hash_get(Rname,q->rname); for (i=1; i<=max_k; i++) { /* MR14 */ if (ruleEntry->dontComputeErrorSet) { /* MR14 */ f=empty; } else { f = ComputeErrorSet(q, i, usePlusBlockBypass /* use plus block bypass ? */ ); } if ( GenCC ) {_gen1(",err%d", DefErrSet( &f, 1, NULL ));} else _gen1(",zzerr%d", DefErrSet( &f, 1, NULL )); set_free(f); } } _gen(",&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;}\n"); /* MR13 */ if (nilf) { /* MR13 */ errFL("empty error set for alt - probably because of undefined rule or infinite left recursion", /* MR13 */ FileStr[q->file],q->line); /* MR13 */ gen(" /* MR13 empty error set for this alt - undef rule ? infinite left recursion ? */"); /* MR13 */ }; } static /* MR7 */ #ifdef __USE_PROTOS char * findOuterHandlerLabel(ExceptionGroup *eg) /* MR7 */ #else char * findOuterHandlerLabel(eg) /* MR7 */ ExceptionGroup *eg; /* MR7 */ #endif { char *label=NULL; /* MR7 */ ExceptionGroup *outerEG; /* MR7 */ if (eg->forRule == 0) { /* MR7 */ if (eg->labelEntry != NULL) { /* MR7 */ outerEG=eg->labelEntry->outerEG; /* MR7 */ if (outerEG != NULL) { /* MR7 */ label=outerEG->altID; /* MR7 */ outerEG->used=1; /* MR7 */ }; /* MR7 */ } else if (eg->outerEG != NULL) { /* MR7 */ outerEG=eg->outerEG; /* MR7 */ label=outerEG->altID; /* MR7 */ outerEG->used=1; /* MR7 */ }; /* MR7 */ }; /* MR7 */ return (label==NULL ? "" : label); /* MR7 */ } /* MR7 */ /*** debug ***/ #if 0 ** static /* MR7 */ ** #ifdef __USE_PROTOS ** char * findOuterAltHandlerLabel(Junction *startJ) /* MR7 */ ** #else ** char * findOuterAltHandlerLabel(startJ) /* MR7 */ ** Junction *startJ; /* MR7 */ ** #endif ** { /* MR7 */ ** char *label=NULL; /* MR7 */ ** Junction *alt; /* MR7 */ ** /* MR7 */ ** for (alt=startJ; alt != NULL; alt=alt->outerAltstart) { /* MR7 */ ** label=alt->exception_label; /* MR7 */ ** if (label != NULL) break; /* MR7 */ ** }; /* MR7 */ ** return (label==NULL ? "" : label); /* MR7 */ ** } /* MR7 */ #endif #ifdef __USE_PROTOS static void OutLineInfo(FILE *file,int line,char *fileName) #else static void OutLineInfo(file,line,fileName) FILE * file; int line; char * fileName; #endif { static char * prevFileName=NULL; static char * prevFileNameMS=NULL; char * p; char * q; if (! GenLineInfo) return; if (!GenLineInfoMS) { fprintf(file, LineInfoFormatStr,line,fileName); } else { if (fileName == prevFileName) { fprintf(file, LineInfoFormatStr,line,prevFileNameMS); } else { if (prevFileNameMS != NULL) free (prevFileNameMS); prevFileNameMS=(char *)calloc(1,strlen(fileName)+1); require(prevFileNameMS != NULL,"why not do this in calloc wrapper"); q=prevFileNameMS; for (p=fileName; *p != 0; p++) { *q=*p; if (*q == '\\') *q='/'; q++; } } prevFileName=fileName; }; } #if 0 /* MR21 */ #ifdef __USE_PROTOS void OutFirstSetSymbol(Junction *q, char * pSymbol) #else void OutFirstSetSymbol(q, pSymbol) Junction* q; char * pSymbol #endif { set f; if (pSymbol == NULL) return; gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol); f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */); DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, ""); set_free(f); } #endif /* MR21 */ #ifdef __USE_PROTOS void BlockPreambleOption(Junction *q, char * pSymbol) #else void BlockPreambleOption(q, pSymbol) Junction* q; char * pSymbol; #endif { set f = empty; if (pSymbol != NULL) { f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */); gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol); DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, ""); } set_free(f); } /* MR21 */ void #ifdef __USE_PROTOS dumpActionPlus(ActionNode *a, char *s, FILE *output, int tabs, int file, int line, int final_newline ) #else dumpActionPlus(a, s, output, tabs, file, line, final_newline ) ActionNode *a; char *s; FILE *output; int tabs; int file; int line; int final_newline; #endif { dumpAction(s,output,tabs,file,line,final_newline); } #if 0 ** #ifdef __USE_PROTOS ** void MR_ErrorSets(Junction *q, int max_k, int usePlusBlockBypass) ** #else ** void MR_ErrorSets(q, max_k, usePlusBlockBypass) ** Junction *q; ** int max_k; ** int usePlusBlockBypass; ** #endif ** { ** int k; ** set setResult; ** Junction* alt1; ** Junction* p; ** set rk; ** ** require (max_k <= CLL_k, "k > CLL_k"); ** ** ** for (k = 1; k <= CLL_k; k++) {set_clr(q->fset[k]); } ** ** for (k = 1; k <= max_k; k++) { ** for (alt1=q; alt1 != NULL; alt1 = (Junction *)alt1->p2) ** { ** if (alt1->ignore && ! usePlusBlockBypass) continue; ** p = analysis_point((Junction *)alt1->p1); ** REACH(p, k, &rk, setResult); ** require(set_nil(rk), "rk != nil"); ** set_orin(&q->fset[k], setResult); ** } ** } ** } #endif #ifdef __USE_PROTOS void DumpInitializers(FILE* output, RuleEntry *r, char * pReturn) #else void DumpInitializers(output, r, pReturn) FILE* output; RuleEntry *r; char * pReturn; #endif { char *p = pReturn; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; char *q; require(pReturn!=NULL, "DumpInitializer: invalid string"); while (*p != 0) { p = endFormal(p, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); if (nest != 0) return; if (pValue != NULL) { tab(); q = strBetween(pSymbol, pEqualSign, pSeparator); fprintf(output, "_retv.%s", q); q = strBetween(pValue, NULL, pSeparator); fprintf(output, " = %s;\n", q); } } } #ifdef __USE_PROTOS void DumpFormals(FILE* output, char * pReturn, int bInitializer) #else void DumpFormals(output, pReturn, bInitializer) FILE* output; char * pReturn; int bInitializer; #endif { char *p = pReturn; char *pDataType; char *pSymbol; char *pEqualSign; char *pValue; char *pSeparator; int nest = 0; char *q; int count = 0; require(pReturn!=NULL, "DumpFormals: invalid string"); while (*p != 0) { p = endFormal(p, &pDataType, &pSymbol, &pEqualSign, &pValue, &pSeparator, &nest); if (nest != 0) return; if (count > 0) fprintf(output,","); if (pDataType != NULL && pSymbol != NULL) { q = strBetween(pDataType, pSymbol, pSeparator); fprintf(output, "%s", q); q = strBetween(pSymbol, pEqualSign, pSeparator); fprintf(output," %s",q); if (pValue != NULL) { q = strBetween(pValue, NULL, pSeparator); if (bInitializer != 0) { fprintf(output, " = %s", q); } } } count++; } } /* MR23 Check for empty alt in a more intelligent way. Previously, an empty alt for genBlk had to point directly to the endBlock. This did not work once I changed {...} blocks to look like (...|...| epsilon) since there were intervening generics. This fixes the problem for this particular case. Things like actions or empty blocks of various kinds will still cause problems, but I wasn't prepared to handle pathological cases like (A|()*). It does handle (A | ()), which is a recommended idiom for epsilon. Actually, this isn't quite correct since it doesn't handle the case of the ignore bit in the plus block bypass, but I'm too tired to figure out the correct fix, and will just work around it. */ #ifdef __USE_PROTOS int isEmptyAlt(Node * alt, Node * endBlock) #else int isEmptyAlt(alt, endBlock) Node * alt; Node * endBlock; #endif { Node * n = alt; Junction * j; while (n != endBlock) { switch (n->ntype) { case nRuleRef: return 0; case nToken: return 0; case nAction: return 0; case nJunction: goto JUNCTION; default: fatal_internal("Invalid node type"); return 0; } JUNCTION: j = (Junction *) n; switch (j->jtype) { case Generic: { n = j->p1; goto NEXT; } case aSubBlk: { n = j->p1; /* MR26 */ goto NEXT; /* MR26 */ } case EndBlk: return 0; case EndRule: return 1; default: return 0; } NEXT: continue; } return 1; }