| /* | |
| * 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 "expcect 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 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 */ | |
| "0; /* 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 */ | |
| "0; /* 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 | |
| initiailized 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 paramters. */ | |
| 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 wasnt'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; | |
| } |