/* * gen.c * * $Id: gen.c,v 1.7 95/09/26 12:58:40 parrt Exp $ * $Revision: 1.7 $ * * 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-1995 */ #include #include #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; extern char *PRED_AND_LIST; extern char *PRED_OR_LIST; /* 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; #define TAB { int i; for (i=0; i>? 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 { gen1("switch ( _signal ) {\n", eg->label==NULL?"":eg->label); { 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;\n"); tabs--; gen("}\n"); return; } gen1("case %s :\n", eh->signalname); tabs++; if ( eh->action != NULL ) { dumpAction(eh->action, output, tabs, -1, 1, 1); gen("_signal = NoSignal;\n"); gen("break;\n"); } tabs--; } } if ( no_default_case ) return; gen("default :\n"); tabs++; /* gen("*_retsignal = _signal;\n");*/ gen("goto _handler;\n"); tabs--; gen("}\n"); } 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 ) { dumpAction(a->action, output, tabs, a->file, a->line, 1); a->done = 1; /* remove action. We have already handled it */ } } void #ifdef __USE_PROTOS genCombinedPredTreeContext( Predicate *p ) #else genCombinedPredTreeContext( 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 genCombinedPredTreeContext(%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 { fatal_internal("pred tree context is empty"); } return; } if ( p->expr == PRED_AND_LIST ) { require(p->down!=NULL && p->down->right!=NULL, "pred tree is wacked"); genCombinedPredTreeContext(p->down); _gen("||"); genCombinedPredTreeContext(p->down->right); return; } if ( p->expr == PRED_OR_LIST ) { Predicate *list = p->down; for (; list!=NULL; list=list->right) { genCombinedPredTreeContext(list); if ( list->right!=NULL ) _gen("||"); } return; } fatal("pred tree is really wacked"); } 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"); } } void #ifdef __USE_PROTOS genPred(Predicate *p, Node *j) #else genPred(p,j) Predicate *p; Node *j; #endif { if ( FoundException ) {_gen("(_sva=(");} else {_gen("(");} if ( GenLineInfo && j->file != -1 ) _gen("\n"); dumpAction(p->expr, output, 0, -1 /*indicates no line info*/, j->line, 0); if ( FoundException ) {_gen("))");} else {_gen(")");} } void #ifdef __USE_PROTOS genPredTree( Predicate *p, Node *j, int in_and_expr ) #else genPredTree( p, j, in_and_expr ) Predicate *p; Node *j; int in_and_expr; #endif { if ( HoistPredicateContext ) { _gen("("); genPredTreeGate(p, in_and_expr); } /* if leaf node, just gen predicate */ if ( p->down==NULL ) { genPred(p,j); if ( HoistPredicateContext ) _gen(")"); return; } /* if AND list, do both preds (only two possible) */ if ( p->expr == PRED_AND_LIST ) { _gen("("); genPredTree(p->down, j, 1); _gen("&&"); genPredTree(p->down->right, j, 1); _gen(")"); if ( HoistPredicateContext ) _gen(")"); return; } if ( p->expr == PRED_OR_LIST ) { Predicate *list; _gen("("); list = p->down; for (; list!=NULL; list=list->right) { genPredTree(list, j, 0); if ( list->right!=NULL ) _gen("||"); } _gen(")"); if ( HoistPredicateContext ) _gen(")"); return; } fatal_internal("predicate tree is wacked"); } void #ifdef __USE_PROTOS genPredTreeMain( Predicate *p, Node *j ) #else genPredTreeMain( p, j ) Predicate *p; Node *j; #endif { genPredTree(p,j,1); } static void #ifdef __USE_PROTOS genExprTree( Tree *t, int k ) #else genExprTree( t, k ) Tree *t; int k; #endif { require(t!=NULL, "genExprTree: NULL tree"); if ( t->token == ALT ) { _gen("("); genExprTree(t->down, k); _gen(")"); if ( t->right!=NULL ) { _gen("||"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTree(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("("); genExprTree(t->down, k+1); _gen(")"); } if ( t->down!=NULL ) _gen(")"); if ( t->right!=NULL ) { _gen("||"); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } _gen("("); genExprTree(t->right, k); _gen(")"); } } /* * 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 GenExprSets generate: * * (setwdi[LA(1)]&(1<= 1. * * This routine is visible only to this file and cannot answer a TRANS message. * */ 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("&&"); genPredTreeMain(p, (Node *)j); } 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 ( GenExprSets ) { while ( !set_nil(fset[k]) && k<=limit ) { if ( set_deg(fset[k])==1 ) /* too simple for a set? */ { int e; _gen1("(LA(%d)==",k); e = set_int(fset[k]); if ( TokenString(e) == NULL ) _gen1("%d)", e) else _gen1("%s)", TokenString(e)); } else { NewSet(); FillSet( fset[k] ); _gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<max_k ) max_k = k; if ( k == CLL_k ) break; k++; if ( !set_nil(fset[k]) && k<=limit ) _gen(" && "); on1line++; if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); } } return max_k; } while ( !set_nil(fset[k]) && k<=limit ) { 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 ( !set_nil(fset[k]) && k<=limit ) { firstTime=1; _gen(" && "); } 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 ) #else genBlk( q, jtype, max_k, need_right_curly ) Junction *q; int jtype; int *max_k; int *need_right_curly; #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; if ( q->p2 == NULL ) /* only one alternative? Then don't need if */ { if ( first_item_is_guess_block((Junction *)q->p1)!=NULL ) { warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line); gen("zzGUESS\n"); /* guess anyway to make output code consistent */ gen("if ( !zzrv )\n"); } 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 */ if ( ((Junction *)p)->p1 == (Node *)q->end ) { break; /* don't do this one, quit */ } } } 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 ) if ( !GenCC ) {gen("if ( zzguessing ) zzGUESS_DONE;\n");} else 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"); } 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; } /* return NULL if 1st item of alt is (...)? 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 { while ( q!=NULL && ((q->ntype==nJunction && q->jtype==Generic) || q->ntype==nAction) ) { 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; } /* 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 ) { if ( p->is_predicate ) { if ( p->guardpred!=NULL ) { gen("if (!"); genPredTreeMain(p->guardpred, (Node *)p); } else { gen("if (!("); /* make sure that '#line n' is on front of line */ if ( GenLineInfo && p->file != -1 ) _gen("\n"); dumpAction(p->action, output, 0, p->file, p->line, 0); _gen(")"); } if ( p->pred_fail != NULL ) { _gen(")\n"); tabs++; gen1("%s;\n", p->pred_fail); tabs--; } else _gen1(") {zzfailed_pred(\"%s\");}\n",p->action); } else { if ( FoundGuessBlk ) if ( GenCC ) {gen("if ( !guessing ) {\n");} else gen("zzNON_GUESS_MODE {\n"); dumpAction(p->action, output, tabs, p->file, p->line, 1); 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 = ""; 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; } r2 = (RuleEntry *) hash_get(Rname, p->rname); if ( r2 == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;} if ( GenLineInfo ) fprintf(output, LineInfoFormatStr, p->line, FileStr[p->file]); if ( GenCC && GenAST ) { gen("_ast = NULL;\n"); } if ( FoundGuessBlk && p->assign!=NULL ) if ( GenCC ) {gen("if ( !guessing ) {\n");} else gen("zzNON_GUESS_MODE {\n"); 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 ) { if ( !HasComma(p->assign) ) {_gen1("%s = ",p->assign);} 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 */ 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);"); } } else { if ( p->assign!=NULL ) { if ( !HasComma(p->assign) ) {_gen1("%s = ",p->assign);} 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 ) _gen("\n"); } q = RulePtr[r->rulenum]; /* find definition of ref'd rule */ if ( p->assign!=NULL ) { if ( HasComma(p->assign) ) { _gen("\n"); dumpRetValAssign(p->assign, q->ret); _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 ) { /* in guessing mode, don't branch to handler upon error */ gen("} else {\n"); 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:""); } 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; 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;} if ( GenLineInfo ) fprintf(output, LineInfoFormatStr, p->line, FileStr[p->file]); if ( !set_nil(p->tset) ) /* implies '.', ~Tok, or tokenclass */ { unsigned e; set b; b = set_dup(p->tset); if ( p->tclass!=NULL ) /* token class? */ { static char buf[MaxRuleName+1]; if ( p->tclass->dumped ) e = p->tclass->setnum; else { e = DefErrSet(&b, 0, TokenString(p->token)); p->tclass->dumped = 1; /* indicate set has been created */ p->tclass->setnum = e; } sprintf(buf, "%s_set", TokenString(p->token)); set_name = buf; } else { /* wild card to ~ operator */ static char buf[sizeof("zzerr")+10]; int n = DefErrSet( &b, 0, NULL ); if ( GenCC ) sprintf(buf, "err%d", n); else sprintf(buf, "zzerr%d", n); set_name = buf; } if ( !FoundException ) {gen1("zzsetmatch(%s);", set_name);} 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++; gen("if ( guessing ) goto fail;\n"); gen("_signal=MismatchedToken;\n"); dumpException(p->ex_group, 0); tabs--; gen("}\n"); } set_free(b); } 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 { gen1("if ( !_match_wsig(%s) ) {\n", TokenString(p->token)); tabs++; gen("if ( guessing ) goto fail;\n"); 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 ) { if ( FoundGuessBlk ) { gen("\n"); if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();} else {gen("zzNON_GUESS_MODE {\n"); tab();} } _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);\n", BlkLevel-1, p->elnum); if ( FoundGuessBlk ) {gen("}\n");} } if ( LL_k>1 ) if ( !DemandLookahead ) _gen(" labase++;"); _gen("\n"); tab(); } if ( GenAST ) { if ( FoundGuessBlk && !(p->astnode == ASTexclude || r->noAST) ) { if ( GenCC ) {_gen("if ( !guessing ) {\n"); tab();} else {_gen("zzNON_GUESS_MODE {\n"); tab();} } if ( !r->noAST ) { if ( GenCC && !(p->astnode == ASTexclude || r->noAST) ) { _gen("\n"); gen4("_ast%d%d = new AST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum); tab(); } if ( GenCC && !(p->astnode == ASTexclude || r->noAST) ) {_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 || r->noAST) ) { _gen("\n"); tab(); } } else if ( !GenCC ) _gen(" zzastDPush;"); if ( FoundGuessBlk && !(p->astnode == ASTexclude || r->noAST) ) {_gen("}\n"); tab();} } /* Handle element labels now */ if ( p->el_label!=NULL ) { _gen("\n"); if ( FoundGuessBlk ) { if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();} else {gen("zzNON_GUESS_MODE {\n"); tab();} } /* Do Attrib / Token ptr */ if ( GenCC ) { if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) {gen3("%s = _t%d%d;\n", p->el_label, BlkLevel-1, p->elnum);} else { gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label); } } else {gen1("%s = zzaCur;\n", p->el_label);} /* Do AST ptr */ if ( GenAST && !(p->astnode == ASTexclude || r->noAST) ) { 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);} } if ( FoundGuessBlk ) {_gen("}\n"); tab();} } /* Handle any actions immediately following action */ if ( a != NULL ) { /* delay next token fetch until after action */ _gen("\n"); if ( a->is_predicate ) { gen("if (!("); dumpAction(a->action, output, 0, a->file, a->line, 0); if ( a->pred_fail != NULL ) { _gen(")) {\n"); /* if ( FoundGuessBlk ) gen("zzNON_GUESS_MODE {\n");*/ tabs++; gen1("%s;\n", a->pred_fail); tabs--; gen("}\n"); /* if ( FoundGuessBlk ) gen("}\n");*/ } else _gen1(")) {zzfailed_pred(\"%s\");}\n",a->action); } else { if ( FoundGuessBlk ) if ( GenCC ) {gen("if ( !guessing ) {\n");} else gen("zzNON_GUESS_MODE {\n"); dumpAction(a->action, output, tabs, a->file, a->line, 1); if ( FoundGuessBlk ) gen("}\n"); } a->done = 1; 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"); TRANS( a->next ); } 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); } } void #ifdef __USE_PROTOS genOptBlk( Junction *q ) #else genOptBlk( q ) Junction *q; #endif { int max_k; set f; int need_right_curly; set savetkref; savetkref = tokensRefdInBlock; require(q!=NULL, "genOptBlk: invalid node and/or rule"); require(q->ntype == nJunction, "genOptBlk: not junction"); require(q->jtype == aOptBlk, "genOptBlk: not optional block"); if ( GenLineInfo ) fprintf(output, LineInfoFormatStr, q->line, FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; f = genBlk(q, aOptBlk, &max_k, &need_right_curly); set_free(f); freeBlkFsets(q); BlkLevel--; if ( first_item_is_guess_block((Junction *)q->p1)!=NULL ) { if ( !GenCC ) {gen("else if ( zzguessing ) zzGUESS_DONE;\n");} else gen("else if ( !zzrv ) zzGUESS_DONE;\n"); } { int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} } 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; savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genLoopBlk: not junction"); require(q->jtype == aLoopBlk, "genLoopBlk: not loop block"); if ( q->visited ) return; q->visited = TRUE; if ( q->p2 == NULL ) /* 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 */ if ( ParseWithPredicates && begin->predicate==NULL ) { Predicate *a = find_predicates((Node *)q->p1); if ( a!=NULL ) { _gen("&&"); genPredTreeMain(a, (Node *)q); } } _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("while ( 1 ) {\n"); tabs++; 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"); } f = genBlk(q, aLoopBlk, &max_k, &need_right_curly); set_free(f); freeBlkFsets(q); /* generate code for terminating loop (this is optional branch) */ if ( begin==NULL ) gen("else break;\n"); /* code for exiting loop "for sure" */ { 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"); if ( GenLineInfo ) fprintf(output, LineInfoFormatStr, q->line, FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; 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; 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; set savetkref; 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; if ( GenLineInfo ) fprintf(output, LineInfoFormatStr, q->line, FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; /* 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. */ if ( ((Junction *)q->p2)->p2 == NULL && ((Junction *)q->p2)->ignore ) /* only one alternative? */ { Predicate *a=NULL; /* if the only alt has a semantic predicate, hoist it; must test before * entering loop. */ if ( ParseWithPredicates ) { a = find_predicates((Node *)q); if ( a!=NULL ) { gen("if ("); genPredTreeMain(a, (Node *)q); _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 ) { _gen("&&"); genPredTreeMain(a, (Node *)q); } _gen(" );\n"); if ( ParseWithPredicates && a!=NULL ) gen("}\n"); --BlkLevel; BLOCK_Tail(); q->visited = FALSE; freeBlkFsets(q); set_free(f); tokensRefdInBlock = savetkref; if (q->end->p1 != NULL) TRANS(q->end->p1); return; } gen("do {\n"); tabs++; f = genBlk(q, aPlusBlk, &max_k, &need_right_curly); gen("else if ( zzcnt>1 ) break; /* implied exit branch */\n");/* code for exiting loop */ tab(); makeErrorClause(q,f,max_k); { 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; 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; set savetkref; savetkref = tokensRefdInBlock; require(q->ntype == nJunction, "genSubBlk: not junction"); require(q->jtype == aSubBlk, "genSubBlk: not subblock"); if ( GenLineInfo ) fprintf(output, LineInfoFormatStr, q->line, FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; f = genBlk(q, aSubBlk, &max_k, &need_right_curly); if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k);} { 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 ) { if ( GenLineInfo ) fprintf(output, LineInfoFormatStr, q->line, FileStr[q->file]); BLOCK_Preamble(q); BlkLevel++; f = genBlk(q, aSubBlk, &max_k, &need_right_curly); if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k);} { 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 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 { int max_k; set follow, rk, f; ActionNode *a; RuleEntry *r; static int file = -1; int need_right_curly; require(q->ntype == nJunction, "genRule: not junction"); require(q->jtype == RuleBlk, "genRule: not rule"); 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 */ { if ( output != NULL ) fclose( output ); output = fopen(OutMetaName(outname(FileStr[q->file])), "w"); require(output != NULL, "genRule: can't open output file"); special_fopen_actions(OutMetaName(outname(FileStr[q->file]))); if ( file == -1 ) genHdr1(q->file); else genHdr(q->file); file = q->file; } DumpFuncHeader(q,r); tabs++; if ( q->ret!=NULL ) { /* Declare the return value - and PURIFY it -ATG 6/5/95 */ if ( HasComma(q->ret) ) { gen1("struct _rv%d _retv;\n",r->rulenum); gen1("PURIFY(_retv,sizeof(struct _rv%d))\n",r->rulenum); } else { tab(); DumpType(q->ret, output); gen(" _retv;\n"); gen("PURIFY(_retv,sizeof("); DumpType(q->ret, output); gen("))\n"); } } if ( GenLineInfo ) { fprintf(output, LineInfoFormatStr, q->line, FileStr[q->file]); } gen("zzRULE;\n"); if ( FoundException ) { gen("int _sva=1;\n"); } if ( GenCC && GenAST ) gen("ASTBase **_astp, *_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); 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 ) { dumpAction(a->action, output, tabs, a->file, a->line, 1); a->done = 1; /* ignore action. We have already handled it */ } if ( TraceGen ) if ( GenCC ) {gen1("tracein(\"%s\");\n", q->rname);} else gen1("zzTRACEIN((ANTLRChar *)\"%s\");\n", q->rname); BlkLevel++; q->visited = TRUE; /* mark RULE as visited for FIRST/FOLLOW */ f = genBlk((Junction *)q->p1, RuleBlk, &max_k, &need_right_curly); if ( q->p1 != NULL ) if ( ((Junction *)q->p1)->p2 != NULL ) {tab(); makeErrorClause((Junction *)q->p1,f,max_k);} { 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); if ( TraceGen ) if ( GenCC ) {gen1("traceout(\"%s\");\n", q->rname);} else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q->rname); 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; REACH(q->end, 1, &rk, follow); FillSet( follow ); set_free( follow ); _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<rname);} else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q->rname); if ( q->ret!=NULL ) {gen("return _retv;\n");} else if ( q->exceptions!=NULL ) gen("return;\n"); if ( !GenCC ) gen("}\n"); /* Gen code for exception handlers */ if ( q->exceptions!=NULL ) { gen("/* exception handlers */\n"); dumpExceptions(q->exceptions); if ( !r->has_rule_exception ) { _gen("_handler:\n"); gen("zzdflthandlers(_signal,_retsignal);\n"); } _gen("_adios:\n"); if ( q->ret!=NULL ) {gen("return _retv;\n");} else {gen("return;\n");} } else if ( FoundException ) { _gen("_handler:\n"); gen("zzdflthandlers(_signal,_retsignal);\n"); } tabs--; gen("}\n"); if ( q->p2 != NULL ) {TRANS(q->p2);} /* generate code for next rule too */ else dumpAfterActions( output ); } static void #ifdef __USE_PROTOS DumpFuncHeader( Junction *q, RuleEntry *r ) #else DumpFuncHeader( q, r ) Junction *q; RuleEntry *r; #endif { /* A N S I */ _gen("\n"); if ( q->ret!=NULL ) { if ( HasComma(q->ret) ) { 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"); } if ( !GenCC ) _gen("#ifdef __STDC__\n"); if ( !GenCC ) gen2("%s%s(", RulePrefix, q->rname) else gen2("%s::%s(", CurrentClassName, q->rname); DumpANSIFunctionArgDef(output,q); _gen("\n"); if ( GenCC ) {gen("{\n"); return;} /* K & R */ gen("#else\n"); gen2("%s%s(", RulePrefix, q->rname); if ( GenAST ) { _gen("_root"); if ( q->pdecl!=NULL ) _gen(","); } if ( FoundException ) { if ( GenAST ) _gen(","); _gen("_retsignal"); if ( q->pdecl!=NULL ) _gen(","); } DumpListOfParmNames( q->pdecl, output ); 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) #else DumpANSIFunctionArgDef(f,q) FILE *f; Junction *q; #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 ) {fprintf(f,"%s", q->pdecl);} 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 { _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-1994\n"); _gen(" * Purdue University Electrical Engineering\n"); _gen(" * With AHPCRC, University of Minnesota\n"); _gen1(" * ANTLR Version %s\n", Version); _gen(" */\n"); _gen("#include \n"); _gen1("#define ANTLR_VERSION %s\n", VersionDef); if ( strcmp(ParserName, DefaultParserName)!=0 ) _gen2("#define %s %s\n", DefaultParserName, ParserName); if ( strcmp(ParserName, DefaultParserName)!=0 ) {_gen1("#include \"%s\"\n", RemapFileName);} if ( GenLineInfo ) _gen2(LineInfoFormatStr, 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 \n"); } 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 %d\n", NumWords(TokenNum-1)*sizeof(unsigned)); 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); _gen("#ifndef PURIFY\n#define PURIFY(r,s)\n#endif\n"); } 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"); _gen("#ifdef __STDC__\n"); _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 ) #else genStdPCCTSIncludeFile( f ) FILE *f; #endif { fprintf(f,"#ifndef STDPCCTS_H\n"); fprintf(f,"#define STDPCCTS_H\n"); fprintf(f,"/*\n"); fprintf(f," * %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-1994\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"); fprintf(f,"#include \n"); fprintf(f,"#define ANTLR_VERSION %s\n", VersionDef); 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); } 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 \n"); } if ( OutputLL_k > 1 ) fprintf(f,"#define LL_K %d\n", OutputLL_k); if ( GenAST ) fprintf(f,"#define GENAST\n"); if ( FoundException ) { _gen("#define EXCEPTION_HANDLING\n"); _gen1("#define NUM_SIGNALS %d\n", NumSignals); } 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 %d\n", NumWords(TokenNum-1)*sizeof(unsigned)); 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 ) { fprintf(output, LineInfoFormatStr, 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 ) #else dumpRetValAssign( retval, ret_def ) char *retval; char *ret_def; #endif { char *q = ret_def; tab(); while ( *retval != '\0' ) { while ( isspace((*retval)) ) retval++; while ( *retval!=',' && *retval!='\0' ) fputc(*retval++, output); fprintf(output, " = _trv."); DumpNextNameInDef(&q, output); fputc(';', output); fputc(' ', output); if ( *retval == ',' ) retval++; } } /* 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 ) #else ComputeErrorSet( j, k ) Junction *j; int k; #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) { 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 ) #else makeErrorClause( q, f, max_k ) Junction *q; set f; int max_k; #endif { 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"); gen("goto _handler;\n"); tabs--; gen("}\n"); return; } if ( max_k == 1 ) { if ( GenCC ) {_gen1("else {FAIL(1,err%d", DefErrSet(&f,1,NULL));} else _gen1("else {zzFAIL(1,zzerr%d", DefErrSet(&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); for (i=1; i<=max_k; i++) { f = ComputeErrorSet(q, i); 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"); } /* If predicates are allowed in parsing expressions: * * ( production 1 * | production 2 * ... * | production n * ) * * where production 1 yields visible predicates: <>? <>? * * generates (if -prc on): * * if ( (production 1 prediction) && * (((context_of_pred ? pred : 1) && * (context_of_pred2 ? pred2 : 1))||!(ctx_pred||ctx_pred2))) ) { * ... * } * else if ( production 2 prediction ) { * ... * } * ... * * A predicate tree of * * p1 * | * p2--p3 * * results in * * if ( (production 1 prediction) && * (((context_of_p1 ? p1 : 1) && * ((context_of_p2 ? p2 : 0)|| * (context_of_p3 ? p3 : 0))) || !(ctx_p1||ctx_p2||ctx_p3)) * ) { * ... * } * * If no context, then just test predicate expression. */ #ifdef DUM void #ifdef __USE_PROTOS genPredTree( Predicate *p, Junction *j ) #else genPredTree( p, j ) Predicate *p; Junction *j; #endif { int context_was_present = 0; Predicate *start_of_OR_list = NULL; _gen("("); start_of_OR_list = p; if ( HoistPredicateContext ) _gen("("); for (; p!=NULL; p=p->right) { if ( HoistPredicateContext ) { context_was_present = 0; if ( LL_k>1 && p->tcontext!=NULL ) { context_was_present = 1; _gen("(("); genExprTree(p->tcontext, 1); _gen(")"); } else if ( LL_k==1 && set_deg(p->scontext[1])>0 ) { context_was_present = 1; _gen("(("); genExprSets(&(p->scontext[0]), CLL_k); _gen(")"); } /* &&'s must use ?: still; only leaves with no parent can avoid ?: */ if ( p->down!=NULL || p->up!=NULL ) {_gen(" ? ");} else {_gen(" && ");} } if ( FoundException ) {_gen("(_sva=(");} else {_gen("(");} dumpAction(p->expr, output, 0, -1 /*indicates no line info*/, j->line, 0); if ( FoundException ) {_gen("))");} else {_gen(")");} if ( HoistPredicateContext && context_was_present ) { if ( p->down!=NULL || p->up!=NULL ) { /* &&'s must use ?: still */ _gen(" : "); genPredTermEliminator(p); } _gen(")"); } if ( p->down!=NULL ) { _gen("&&"); if ( HoistPredicateContext && context_was_present ) _gen("("); genPredTree(p->down, j); if ( HoistPredicateContext && context_was_present && ) { _gen(") || !("); genCombinedPredTreeContext(start_of_OR_list); _gen(")"); } } if ( p->right!=NULL ) _gen("||"); } if ( HoistPredicateContext ) { _gen(")) || !("); genCombinedPredTreeContext(start_of_OR_list); _gen(")"); } _gen(")"); } #endif