+/*
+ * 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 <stdio.h>
+#include <ctype.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;
+
+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<tabs; i++) fputc('\t', 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 *);
+static void dumpAfterActions(FILE *output);
+static set ComputeErrorSet(Junction *, int);
+static void makeErrorClause(Junction *, set, 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 );
+#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();
+#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);}
+
+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
+{
+ 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<<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.
+ *
+ */
+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<<setnum);
+ }
+ if ( k>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<<setnum);
+
+ 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 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 <stdio.h>\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 <setjmp.h>\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 <stdio.h>\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 <setjmp.h>\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: <<pred>>? <<pred2>>?
+ *
+ * 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