diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/gen.c | 4797 |
1 files changed, 4797 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/gen.c b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/gen.c new file mode 100644 index 00000000..851b5651 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/C/VfrCompile/Pccts/antlr/gen.c @@ -0,0 +1,4797 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#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; i<tabs; i++) fputc('\t', output); \ + } else { \ + for (i=0; i<tabs*TabWidth; i++) fputc(' ',output); \ + }; \ + } + +static void +#ifdef __USE_PROTOS +tab( void ) +#else +tab( ) +#endif +TAB + +#ifdef __USE_PROTOS +static char *tokenFollowSet(TokNode *); +static ActionNode *findImmedAction( Node * ); +static void dumpRetValAssign(char *, char *, RuleRefNode *); /* MR30 */ +static void dumpAfterActions(FILE *output); +static set ComputeErrorSet(Junction *, int, int); +static void makeErrorClause(Junction *, set, int, int); +static void DumpFuncHeader( Junction *, RuleEntry * ); +static int has_guess_block_as_first_item(Junction *); +static int genExprSets(set *, int); +static void genExprTree( Tree *t, int k ); +static void genExprTreeOriginal( Tree *t, int k ); /* MR10 */ +static char * findOuterHandlerLabel(ExceptionGroup *eg); /* MR7 */ +static void OutLineInfo(FILE *file,int line,char *fileName); /* MR14 */ +#else +static char *tokenFollowSet(); +static ActionNode *findImmedAction(); +static void dumpRetValAssign(); +static void dumpAfterActions(); +static set ComputeErrorSet(); +static void makeErrorClause(); +static void DumpFuncHeader(); +static int has_guess_block_as_first_item(); +static int genExprSets(); +static void genExprTree(); +static void genExprTreeOriginal(); /* MR10 */ +static char * findOuterHandlerLabel(); /* MR7 */ +static void OutLineInfo(); /* MR14 */ +#endif + +#define gen(s) {tab(); fprintf(output, s);} +#define gen1(s,a) {tab(); fprintf(output, s,a);} +#define gen2(s,a,b) {tab(); fprintf(output, s,a,b);} +#define gen3(s,a,b,c) {tab(); fprintf(output, s,a,b,c);} +#define gen4(s,a,b,c,d) {tab(); fprintf(output, s,a,b,c,d);} +#define gen5(s,a,b,c,d,e) {tab(); fprintf(output, s,a,b,c,d,e);} +#define gen6(s,a,b,c,d,e,f) {tab(); fprintf(output, s,a,b,c,d,e,f);} +#define gen7(s,a,b,c,d,e,f,g) {tab(); fprintf(output, s,a,b,c,d,e,f,g);} + +#define _gen(s) {fprintf(output, s);} +#define _gen1(s,a) {fprintf(output, s,a);} +#define _gen2(s,a,b) {fprintf(output, s,a,b);} +#define _gen3(s,a,b,c) {fprintf(output, s,a,b,c);} +#define _gen4(s,a,b,c,d){fprintf(output, s,a,b,c,d);} +#define _gen5(s,a,b,c,d,e){fprintf(output, s,a,b,c,d,e);} +#define _gen6(s,a,b,c,d,e,f){fprintf(output, s,a,b,c,d,e,f);} +#define _gen7(s,a,b,c,d,e,f,g){fprintf(output, s,a,b,c,d,e,f,g);} + + +/* MR11 a convenient place to set a break point */ + +#ifdef __USE_PROTOS +void MR_break(void) +#else +void MR_break() +#endif +{ + return; +} + +/* MR10 genTraceOut(Junction *) */ + +#ifdef __USE_PROTOS +static void genTraceOut(Junction *q) +#else +static void genTraceOut(q) + Junction *q; +#endif +{ + if ( TraceGen ) { + if ( GenCC ) {gen1("zzTRACEOUT(\"%s\");\n", q->rname);} + 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<<j)) && (setwdi[LA(2)]&(1<<j)) ... + * + * where n is set_deg(expr) and Ti is some random token and k is the last nonempty + * set in fset <=CLL_k. + * k=1..CLL_k where CLL_k >= 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<<setnum); + } + if ( k>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")+10]; + static char bufErrSet[sizeof("zzerr")+10]; + int n = DefErrSet( &b, 0, NULL ); + int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set"); + if ( GenCC ) sprintf(buf, "err%d", n); + else sprintf(buf, "zzerr%d", n); + if ( GenCC ) sprintf(bufErrSet, "err%d", nErrSet); + else sprintf(bufErrSet, "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<<setnum); + + if ( q->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; +} |