/*
 * gen.c
 *
 * Generate C code (ANSI, K&R, C++)
 *
 * SOFTWARE RIGHTS
 *
 * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
 * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
 * company may do whatever they wish with source code distributed with
 * PCCTS or the code generated by PCCTS, including the incorporation of
 * PCCTS, or its output, into commerical software.
 *
 * We encourage users to develop software with PCCTS.  However, we do ask
 * that credit is given to us for developing PCCTS.  By "credit",
 * we mean that if you incorporate our source code into one of your
 * programs (commercial product, research project, or otherwise) that you
 * acknowledge this fact somewhere in the documentation, research report,
 * etc...  If you like PCCTS and have developed a nice tool with the
 * output, please mention that you developed it using PCCTS.  In
 * addition, we ask that this header remain intact in our source code.
 * As long as these guidelines are kept, we expect to continue enhancing
 * this system and expect to make other tools available as they are
 * completed.
 *
 * ANTLR 1.33
 * Terence Parr
 * Parr Research Corporation
 * with Purdue University and AHPCRC, University of Minnesota
 * 1989-2001
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "pcctscfg.h"
#include "set.h"
#include "syn.h"
#include "hash.h"
#include "generic.h"
#include "dlgdef.h"

#define NumExprPerLine	4
static int on1line=0;
static set tokensRefdInBlock;

					/* T r a n s l a t i o n  T a b l e s */

/* C_Trans[node type] == pointer to function that knows how to translate that node. */
#ifdef __cplusplus
void (*C_Trans[NumNodeTypes+1])(...) = {
	NULL,
	NULL,					/* See next table.
Junctions have many types */
	(void (*)(...)) genRuleRef,
	(void (*)(...)) genToken,
	(void (*)(...)) genAction
 };
#else
void (*C_Trans[NumNodeTypes+1])() = {
	NULL,
	NULL,					/* See next table.
Junctions have many types */
	genRuleRef,
	genToken,
	genAction
 };
#endif

/* C_JTrans[Junction type] == pointer to function that knows how to translate that
 * kind of junction node.
 */
#ifdef __cplusplus
void (*C_JTrans[NumJuncTypes+1])(...) = {
	NULL,
	(void (*)(...)) genSubBlk,
	(void (*)(...)) genOptBlk,
	(void (*)(...)) genLoopBlk,
	(void (*)(...)) genEndBlk,
	(void (*)(...)) genRule,
	(void (*)(...)) genJunction,
	(void (*)(...)) genEndRule,
	(void (*)(...)) genPlusBlk,
	(void (*)(...)) genLoopBegin
 };
#else
void (*C_JTrans[NumJuncTypes+1])() = {
	NULL,
	genSubBlk,
	genOptBlk,
	genLoopBlk,
	genEndBlk,
	genRule,
	genJunction,
	genEndRule,
	genPlusBlk,
	genLoopBegin
 };
#endif

#define PastWhiteSpace(s)	while (*(s) == ' ' || *(s) == '\t') {s++;}

static int tabs = 0;

/* MR6	Got tired of text running off page when using standard tab stops */

#define TAB { int i; 					                		\
	      if (TabWidth==0) { 					                \
	         for (i=0; i<tabs; i++) fputc('\t', output);		                \
	      } else {           							\
		 for (i=0; i<tabs*TabWidth; i++) fputc(' ',output);     	        \
	      };	                						\
	    }

static void
#ifdef __USE_PROTOS
tab( void )
#else
tab( )
#endif
TAB

#ifdef __USE_PROTOS
static char *tokenFollowSet(TokNode *);
static ActionNode *findImmedAction( Node * );
static void dumpRetValAssign(char *, char *, RuleRefNode *);		/* MR30 */
static void dumpAfterActions(FILE *output);
static set ComputeErrorSet(Junction *, int, int);
static void makeErrorClause(Junction *, set, int, int);
static void DumpFuncHeader( Junction *, RuleEntry * );
static int has_guess_block_as_first_item(Junction *);
static int genExprSets(set *, int);
static void genExprTree( Tree *t, int k );
static void genExprTreeOriginal( Tree *t, int k );                  /* MR10 */
static char * findOuterHandlerLabel(ExceptionGroup *eg);            /* MR7 */
static void OutLineInfo(FILE *file,int line,char *fileName);        /* MR14 */
#else
static char *tokenFollowSet();
static ActionNode *findImmedAction();
static void dumpRetValAssign();
static void dumpAfterActions();
static set ComputeErrorSet();
static void makeErrorClause();
static void DumpFuncHeader();
static int has_guess_block_as_first_item();
static int genExprSets();
static void genExprTree();
static void genExprTreeOriginal();                                  /* MR10 */
static char * findOuterHandlerLabel();                              /* MR7 */
static void OutLineInfo();                                          /* MR14 */
#endif

#define gen(s)			{tab(); fprintf(output, s);}
#define gen1(s,a)		{tab(); fprintf(output, s,a);}
#define gen2(s,a,b)		{tab(); fprintf(output, s,a,b);}
#define gen3(s,a,b,c)	{tab(); fprintf(output, s,a,b,c);}
#define gen4(s,a,b,c,d)	{tab(); fprintf(output, s,a,b,c,d);}
#define gen5(s,a,b,c,d,e)	{tab(); fprintf(output, s,a,b,c,d,e);}
#define gen6(s,a,b,c,d,e,f)	{tab(); fprintf(output, s,a,b,c,d,e,f);}
#define gen7(s,a,b,c,d,e,f,g)	{tab(); fprintf(output, s,a,b,c,d,e,f,g);}

#define _gen(s)			{fprintf(output, s);}
#define _gen1(s,a)		{fprintf(output, s,a);}
#define _gen2(s,a,b)	{fprintf(output, s,a,b);}
#define _gen3(s,a,b,c)	{fprintf(output, s,a,b,c);}
#define _gen4(s,a,b,c,d){fprintf(output, s,a,b,c,d);}
#define _gen5(s,a,b,c,d,e){fprintf(output, s,a,b,c,d,e);}
#define _gen6(s,a,b,c,d,e,f){fprintf(output, s,a,b,c,d,e,f);}
#define _gen7(s,a,b,c,d,e,f,g){fprintf(output, s,a,b,c,d,e,f,g);}


/* MR11 a convenient place to set a break point */

#ifdef __USE_PROTOS
void MR_break(void) 
#else
void MR_break() 
#endif
{
  return;
}

/* MR10 genTraceOut(Junction *)      */

#ifdef __USE_PROTOS
static void genTraceOut(Junction *q)
#else
static void genTraceOut(q)
  Junction  *q;
#endif
{
  if ( TraceGen ) {
		if ( GenCC ) {gen1("zzTRACEOUT(\"%s\");\n", q->rname);}
    		else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q->rname);
  }
}

static void
#ifdef __USE_PROTOS
warn_about_using_gk_option(void)
#else
warn_about_using_gk_option()
#endif
{
	static int warned_already=0;

	if ( !DemandLookahead || warned_already ) return;
	warned_already = 1;
	warnNoFL("-gk option could cause trouble for <<...>>? predicates");
}

void
#ifdef __USE_PROTOS
freeBlkFsets( Junction *q )
#else
freeBlkFsets( q )
Junction *q;
#endif
{
	int i;
	Junction *alt;
	require(q!=NULL, "freeBlkFsets: invalid node");

	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
	{
		for (i=1; i<=CLL_k; i++) set_free(alt->fset[i]);
	}
}

/*
 * Generate a local variable allocation for each token references
 * in this block.
 */
static void
#ifdef __USE_PROTOS
genTokenPointers( Junction *q )
#else
genTokenPointers( q )
Junction *q;
#endif
{
	/* Rule refs are counted and can be referenced, but their
	 * value is not set to anything useful ever.
	 *
     * The ptrs are to be named _tij where i is the current level
	 * and j is the element number within an alternative.
	 */
	int first=1, t=0;
	set a;
	tokensRefdInBlock = q->tokrefs;

	if ( set_deg(q->tokrefs) == 0 ) return;
	a = set_dup(q->tokrefs);
	gen("ANTLRTokenPtr ");
	for (; !set_nil(a); set_rm(t, a))
	{
		t = set_int(a);
		if ( first ) first = 0;
		else _gen(",");
		if ( !DontCopyTokens ) _gen2("_tv%d%d,", BlkLevel, t);
		_gen2("_t%d%d", BlkLevel, t);
		if ( !DontCopyTokens ) {_gen2("= &_tv%d%d", BlkLevel, t);}
		else _gen("=NULL");
	}
	_gen(";\n");
	set_free(a);
}

static int
#ifdef __USE_PROTOS
hasDefaultException(ExceptionGroup *eg)
#else
hasDefaultException(eg)
ExceptionGroup *eg;
#endif
{
    ListNode *q;

    for (q = eg->handlers->next; q!=NULL; q=q->next)
    {
        ExceptionHandler *eh = (ExceptionHandler *)q->elem;
        if ( strcmp("default", eh->signalname)==0 ) {
            return 1;
        }
    }
    return 0;
}
static void
#ifdef __USE_PROTOS
dumpException(ExceptionGroup *eg, int no_default_case)
#else
dumpException(eg, no_default_case)
ExceptionGroup *eg;
int no_default_case;
#endif
{
    char    *outerLabel;                                             /* MR7 */
    int     altHandler=0;                                            /* MR7 */
    int     namedHandler=0;                                          /* MR7 */

    outerLabel=findOuterHandlerLabel(eg);                            /* MR7 */

    if (eg->label != NULL) {                                         /* MR7 */
      namedHandler=1;                                                /* MR7 */
    } else if (eg->forRule) {                                        /* MR7 */
      /* nothing */                                                  /* MR20 */
    } else {                                                         /* MR7 */
      altHandler=1;                                                  /* MR7 */
    };                                                               /* MR7 */

#if 0
**     if (! eg->used) {                                             /* MR7 */
**     	warnFL("exception group never used",                         /* MR7 */
**             FileStr[eg->altstart->file],eg->altstart->line);      /* MR7 */
**     };                                                            /* MR7 */
#endif

    if (namedHandler) {                                              /* MR7 */
	  gen1("switch ( _signal ) {  /* [%s] */\n",eg->label);          /* MR7 */
    } else {                                                         /* MR7 */
	  gen("switch ( _signal ) {\n");                                 /* MR7 */
      gen("case NoSignal: break;  /* MR7 */\n");                     /* MR7 */
    };                                                               /* MR7 */
	{
		ListNode *q;
		for (q = eg->handlers->next; q!=NULL; q=q->next)
		{
			ExceptionHandler *eh = (ExceptionHandler *)q->elem;
			if ( strcmp("default", eh->signalname)==0 ) {
				gen("default :\n");
				tabs++;
				dumpAction(eh->action, output, tabs, -1, 1, 1);
                gen("_signal=NoSignal;  /* MR7 */\n");                  /* MR7 */
                gen("break;  /* MR7 */\n");                             /* MR7 */
				tabs--;
				gen("}\n");

                /* copied from later code in dumpException */        /* MR7 */

                if (namedHandler) {                                  /* MR7 */
                  gen("if (_signal != NoSignal)");                   /* MR7 */
                  _gen1(" goto %s_handler;  /* MR7 */\n",outerLabel);/* MR7 */
                } else if (altHandler) {                             /* MR7 */
                  gen1("goto %s_handler;  /* MR7 */\n",outerLabel);  /* MR7 */
                };
				return;
			}
			gen1("case %s :\n", eh->signalname);
			tabs++;
			if ( eh->action != NULL )
			{
				dumpAction(eh->action, output, tabs, -1, 1, 1);
                gen("break;  /* MR7 */\n");                          /* MR7 */
			}
			tabs--;
		}
	}
	if ( no_default_case ) return;

	gen("default :\n");
    tabs++;                                                         /* MR7 */
    gen("break;  /* MR7 */\n");                                     /* MR7 */
    tabs--;                                                         /* MR7 */

	tabs++;
/*****	gen("*_retsignal = _signal;\n"); *****/

	tabs--;
	gen("}\n");

    if (namedHandler) {                                             /* MR7 */
      gen("if (_signal != NoSignal)");                              /* MR7 */
      _gen1(" goto %s_handler;  /* MR7 */\n",outerLabel);           /* MR7 */
    } else if (altHandler) {                                        /* MR7 */
      gen1("goto %s_handler;  /* MR7 */\n",outerLabel);             /* MR7 */
    };

}

static void
#ifdef __USE_PROTOS
dumpExceptions(ListNode *list)
#else
dumpExceptions(list)
ListNode *list;
#endif
{
	ListNode *p;

	for (p = list->next; p!=NULL; p=p->next)
	{
		ExceptionGroup *eg = (ExceptionGroup *) p->elem;
		_gen2("%s%s_handler:\n",
			  eg->label==NULL?"":eg->label,
			  eg->altID==NULL?"":eg->altID);
		if ( eg->altID!=NULL ) dumpException(eg, 0);
		else {
			/* This must be the rule exception handler */
			dumpException(eg, 1);
			if ( !hasDefaultException(eg) )
            {
                gen("default :\n");
                tabs++;
                gen("zzdflthandlers(_signal,_retsignal);\n");
                tabs--;
                gen("}\n");
            }
		}
	}
}

/* For each element label that is found in a rule, generate a unique
 * Attribute (and AST pointer if GenAST) variable.
 */
void
#ifdef __USE_PROTOS
genElementLabels(ListNode *list)
#else
genElementLabels(list)
ListNode *list;
#endif
{
	int first=1;
	ListNode *p;

	if ( GenCC ) {gen("ANTLRTokenPtr");}
	else {gen("Attrib");}
	for (p = list->next; p!=NULL; p=p->next)
	{
		char *ep = (char *)p->elem;
		if ( first ) first = 0;
		else _gen(",");
		if ( GenCC ) {_gen1(" %s=NULL",ep);}
		else {_gen1(" %s",ep);}
	}
	_gen(";\n");

	if ( !GenAST ) return;

	first = 1;
	gen("AST");
	for (p = list->next; p!=NULL; p=p->next)
	{
		char *ep = (char *)p->elem;
		if ( first ) first = 0;
		else _gen(",");
		_gen1(" *%s_ast=NULL",ep);
	}
	_gen(";\n");
}

/*
 * Generate a local variable allocation for each token or rule reference
 * in this block.
 */
static void
#ifdef __USE_PROTOS
genASTPointers( Junction *q )
#else
genASTPointers( q )
Junction *q;
#endif
{
	int first=1, t;
	set a;

	a = set_or(q->tokrefs, q->rulerefs);
	if ( set_deg(a) > 0 )
	{
		gen("AST ");
		for (; !set_nil(a); set_rm(t, a))
		{
			t = set_int(a);
			if ( first ) first = 0;
			else _gen(",");
			_gen2("*_ast%d%d=NULL", BlkLevel, t);
		}
		set_free(a);
	}
	_gen(";\n");
}

static void
#ifdef __USE_PROTOS
BLOCK_Head( void )
#else
BLOCK_Head( )
#endif
{
	gen("{\n");
	tabs++;
	if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel);
}

static void
#ifdef __USE_PROTOS
BLOCK_Tail( void )
#else
BLOCK_Tail( )
#endif
{
	if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel);
	if ( !GenCC ) gen("}\n");
	tabs--;
	gen("}\n");
}

static void
#ifdef __USE_PROTOS
BLOCK_Preamble( Junction *q )
#else
BLOCK_Preamble( q )
Junction *q;
#endif
{
	ActionNode *a;
	Junction *begin;

	BLOCK_Head();
	if ( GenCC ) genTokenPointers(q);
	if ( GenCC&&GenAST ) genASTPointers(q);
	if ( q->jtype == aPlusBlk ) gen("int zzcnt=1;\n");
	if ( q->parm != NULL && !q->predparm ) gen1("zzaPush(%s);\n", q->parm)
	else if ( !GenCC ) gen("zzMake0;\n");
	if ( !GenCC ) gen("{\n");
	if ( q->jtype == aLoopBegin ) begin = (Junction *) ((Junction *)q->p1);
	else begin = q;
	if ( has_guess_block_as_first_item(begin) )
	{
		gen("zzGUESS_BLOCK\n");
	}
	if ( q->jtype == aLoopBegin )
		a = findImmedAction( ((Junction *)q->p1)->p1 );	/* look at aLoopBlk */
	else
		a = findImmedAction( q->p1 );
	if ( a!=NULL && !a->is_predicate) {
/* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1);
		   a->done = 1;	/* remove action. We have already handled it */
	}
}

void
#ifdef __USE_PROTOS
genCombinedPredTreeContextOrig( Predicate *p )
#else
genCombinedPredTreeContextOrig( p )
Predicate *p;
#endif
{
	static set *ctx=NULL;		/* genExprSets() is destructive, make copy*/
	require(p!=NULL, "can't make context tree for NULL pred tree");

#ifdef DBG_PRED
	fprintf(stderr, "enter genCombinedPredTreeContextOrig(%s,0x%x) with sets:\n", p->expr, p);
	s_fprT(stderr, p->scontext[1]);
	fprintf(stderr, "\n");
#endif
	if ( p->down == NULL )
	{
/***	if ( p->k>1 && p->tcontext!=NULL ) ***/
		if ( p->tcontext!=NULL )
		{
			_gen("(");
			genExprTree(p->tcontext, 1);
			_gen(")");
		}
/***	else if ( p->k==1 && set_deg(p->scontext[1])>0 ) ***/
		else if ( set_deg(p->scontext[1])>0 )
		{
			if ( ctx==NULL ) ctx = (set *)calloc(CLL_k+1, sizeof(set));
			require(ctx!=NULL, "ctx cannot allocate");
			ctx[0]=empty;
			ctx[1]=set_dup(p->scontext[1]);
			_gen("(");
			genExprSets(&(ctx[0]), p->k);
			_gen(")");
			set_free(ctx[1]);
		}
		else if ( p->expr==PRED_AND_LIST || p->expr==PRED_OR_LIST ) {
			fatal_internal("pred tree is orphan OR or AND list");
		}
		else {
            if (! HoistPredicateContext) {
              _gen(" 1 /* no context: prc is off */ ");
            } else {
              fatal_internal("pred tree context is empty");
            };
		}
		return;
	}

/* MR10 - make AND just like OR */

	if ( p->expr == PRED_AND_LIST )
	{
        Predicate *list = p->down;
        for (; list!=NULL; list=list->right)
        {
     	     genCombinedPredTreeContextOrig(list);
       		 if ( list->right!=NULL ) _gen("|| /* MR10 was wrong */ ");
        };
		return;
	}

	if ( p->expr == PRED_OR_LIST )
	{
        Predicate *list = p->down;
        for (; list!=NULL; list=list->right)
        {
           genCombinedPredTreeContextOrig(list);
           if ( list->right!=NULL ) _gen("||");
        };
        return;
     };

	fatal("pred tree is really wacked");
}

/* [genCombinedPredTreeContext] */

void
#ifdef __USE_PROTOS
genCombinedPredTreeContext( Predicate *p )
#else
genCombinedPredTreeContext( p )
Predicate *p;
#endif
{
  Tree  *t;
  int   predDepth=0;

  if (0 && ! MR_usingPredNames && ! MRhoisting) {
    genCombinedPredTreeContextOrig(p);
  } else {
/* MR13 */    MR_pred_depth(p,&predDepth);
/* MR13 */    if (predDepth == 1) {
/* MR13 */
/* MR13 */      set   scontext[2];
/* MR13 */      scontext[0]=empty;
/* MR13 */      scontext[1]=MR_compute_pred_set(p);
/* MR13 */      if (set_nil(scontext[1])) {
/* MR13 */        _gen(" 1 /* MR12 no context (-prc off) */ ");
/* MR13 */      } else {
/* MR13 */        _gen("(");
/* MR13 */        genExprSets(&scontext[0], 1);
/* MR13 */        set_free(scontext[1]);
/* MR13 */        _gen(")");
/* MR13 */      };

    } else {
      t=MR_compute_pred_tree_context(p);
      if (t == NULL) {
        _gen(" 1 /* MR12 no context (-prc off) */ ");
      } else {
        _gen("(");
        genExprTree(t, 1);
        Tfree(t);   /* MR10 */
        _gen(")");
      };
    };
  };
}

/* [genPredTreeGate] */

void
#ifdef __USE_PROTOS
genPredTreeGate( Predicate *p, int in_and_expr )
#else
genPredTreeGate( p, in_and_expr )
Predicate *p;
int in_and_expr;
#endif
{
	if ( in_and_expr )
	{
		_gen("!(");
		genCombinedPredTreeContext(p);
		_gen(")||");
		if ( p->down!=NULL ) _gen("\n");
	}
	else
	{
		_gen("(");
		genCombinedPredTreeContext(p);
		_gen(")&&");
		if ( p->down!=NULL ) _gen("\n");
	}
}

#ifdef __USE_PROTOS
void genPredEntry(Predicate *p,int outer)
#else
void genPredEntry(p,outer)
  Predicate     *p;
  int           outer;
#endif
{
    int         inverted=0;
    Predicate   *q;
    int         localOuter=outer;
    int         needRP=0;

    if (p == NULL) return;

    if (p->predEntry != NULL && p->predEntry->predLiteral != NULL) {
      if (p->inverted != p->predEntry->pred->inverted) {
        _gen("! /* inverted pred */ (");
        needRP=1;
      } else {
        if (!localOuter) _gen("(");
        needRP=1;
      };
      dumpAction(p->predEntry->predLiteral,output,0,p->source->file,p->source->line,0);
      if (needRP) _gen(")");
      return;
    };

    inverted=p->inverted;

    if (inverted) {
      _gen(" ! /* inverted pred */ (");
      localOuter=1;
    };

    if (p->expr == PRED_OR_LIST) {
      if (!localOuter) _gen("(");
      for (q=p->down; q != NULL ; q=q->right) {
        genPredEntry(q,0);
        if (q->right != NULL) _gen(" || ");
      };
      if (!localOuter) _gen(")");
    } else if (p->expr == PRED_AND_LIST) {
      if (!localOuter) _gen("(");
      for (q=p->down; q != NULL ; q=q->right) {
        genPredEntry(q,0);
        if (q->right != NULL) _gen(" && ");
      };
      if (!localOuter) _gen(")");
    } else {
      if (!localOuter) _gen("(");
      require (p->source != NULL,"predEntry->source == NULL");
      require (p->source->inverted == 0,"dumpPredEntry p->source->inverted != 0");
      dumpAction(p->source->action,output,0,p->source->file,p->source->line,0);
      if (!localOuter) _gen(")");
    };

    if (inverted) {
        _gen(")");
    }
}

void
#ifdef __USE_PROTOS
dumpPredAction(ActionNode *anode,
                    char *s,FILE *output,int tabs,int file,int line,int final_newline)
#else
dumpPredAction(anode,
                    s,output,tabs,file,line,final_newline)

    ActionNode  *anode;
    char        *s;
    FILE        *output;
    int         tabs;
    int         file;
    int         line;
    int         final_newline;
#endif
{
    PredEntry   *predEntry=anode->predEntry;
    int         inverted=anode->inverted;
    Predicate   *workPred;

    if (predEntry == NULL) {

      /* inline predicate literal */

      require(inverted == 0,"dumpPredAction action->inverted");
  	  dumpAction(s,output,tabs,file,line,final_newline);

    } else {

      /* a reference to a predicate - possibly with an inverted source */

      if (predEntry->predLiteral != NULL) {
        if (inverted) _gen("! /* inverted pred */ (");
        dumpAction(predEntry->predLiteral,output,0,anode->file,anode->line,0);
        if (inverted) _gen(")");
      } else {
        workPred=predicate_dup(predEntry->pred);
        if (inverted) workPred->inverted=!workPred->inverted;
        genPredEntry(workPred,1);
        predicate_free(workPred);
      };
    };
}

/* [genPred] */

void
#ifdef __USE_PROTOS
genPred(Predicate *p, Node *j,int suppress_sva)
#else
genPred(p,j,suppress_sva)
    Predicate   *p;
    Node        *j;
    int         suppress_sva;
#endif
{
	if ( FoundException && !suppress_sva) {_gen("(_sva=(");}    /* MR11 suppress_sva */
	else {_gen("(");}
	if ( GenLineInfo && j->file != -1 ) _gen("\n");
    if (p->source != NULL && p->source->ampersandPred != NULL) {
      if (p->source->ampersandPred->k == 1) {

            set     ctx[2];

			ctx[0]=empty;
			ctx[1]=set_dup(p->source->ampersandPred->scontext[1]);

			_gen("(");
			genExprSets(&(ctx[0]), p->k);
			_gen(") && ");
			set_free(ctx[1]);
      } else {
        _gen("( ");
        genExprTree(p->source->ampersandPred->tcontext,1);
		_gen(" ) && ");
      };
    };

    dumpPredAction((ActionNode *)p->source,
                p->expr, output, 0, -1 /*indicates no line info*/, j->line, 0);

	if ( FoundException && !suppress_sva)   /* MR11 suppress_sva */
         {_gen("),_sva)");}    /* MR10 - get red of "meant ==" messages */
	else {_gen(")");}
}

void
#ifdef __USE_PROTOS
MR_distinctORcontextOpt(Predicate *p,Node *j,int in_and_expr)
#else
MR_distinctORcontextOpt(p,j,in_and_expr)
    Predicate   *p;
    Node        *j;
    int         in_and_expr;
#endif
{
    Predicate   *q;

    _gen(" /* MR10 Distinct OR context optimization */ \n");

    if (in_and_expr) {
      gen("zzpf=0,\n");
      for (q=p->down; q != NULL; q=q->right) {
        gen("(  ");
        genCombinedPredTreeContext(q);
        _gen(" && (zzpf=1, ");
        genPred(q,j,0);
        _gen("  )) ||\n");
      };
      gen("!zzpf)");
    } else {
      require (0,
            "MR_distinctORcontextOpt: can't get here when using MR_predSimplify");
#if 0
**      for (q=p->down; q != NULL; q=q->right) {
**        gen("(  ");
**        genCombinedPredTreeContext(q);
**        _gen(" && ");
**        genPred(q,j);
**        if (q->right != NULL) {
**          _gen("  ) ||\n");
**        };
**      };
**      gen(")");
#endif
   };
}

void
#ifdef __USE_PROTOS
genPredTreeOrig( Predicate *p, Node *j, int in_and_expr )
#else
genPredTreeOrig( p, j, in_and_expr )
Predicate *p;
Node *j;
int in_and_expr;
#endif
{

/* MR10 */  int     allHaveContext=1;
/* MR10 */  int     noneHaveContext=1;

/* MR10 */  MR_predContextPresent(p,&allHaveContext,&noneHaveContext);

	if ( ! noneHaveContext )                  /* MR10 context guards ignored when -prc off */
	{
		_gen("(");
		genPredTreeGate(p, in_and_expr);
	}

	/* if leaf node, just gen predicate */

	if ( p->down==NULL )
	{
		genPred(p,j,0);
		if ( ! noneHaveContext ) _gen(")");   /* MR10 context guards ignored when -prc off */
		return;
	}

	/* if AND list, do both preds (only two possible) */
	if ( p->expr == PRED_AND_LIST )
	{
#if 0
**		_gen("(");
**		genPredTreeOrig(p->down, j, 1);
**		_gen("&&");
**		genPredTreeOrig(p->down->right, j, 1);
**		_gen(")");
**		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
**		return;
#endif
        /* MR11 - make it work with AND with more than two children - like OR */

		Predicate *list;
		_gen("(");
		list = p->down;
		for (; list!=NULL; list=list->right)
		{
			genPredTreeOrig(list, j, 1);
			if ( list->right!=NULL ) _gen("&&");
		}
		_gen(")");
		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
		return;
    };

	if ( p->expr == PRED_OR_LIST )
	{
		Predicate *list;
		_gen("(");
		list = p->down;
		for (; list!=NULL; list=list->right)
		{
			genPredTreeOrig(list, j, 0);
			if ( list->right!=NULL ) _gen("||");
		}
		_gen(")");
		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
		return;
	}

	fatal_internal("genPredTreeOrig: predicate tree is wacked");
}

#if 0
**   Predicate member dummyPredDepth is no longer used in MR10
**     but we might need it again in the future
**
**   if (MRhoisting) {
**     if ( !noneHaveContext &&
**          ! in_and_expr &&
**          p->source != NULL &&
**          p->source->dummyPredicateDepth > 0 &&
**          p->down == NULL) {
** 		_gen("(");
** 		genCombinedPredTreeContext(p);
** 		_gen("  )\n");
** 		return;
**     };
**   };
#endif

/* [genPredTree] */

/* in_and_expr

   what to do if the context is wrong
   what to do if the context is correct but the predicate is false

   remember: if the context is wrong it's the same as if the
             predicate is true as far as enabling an alternative

        Consider (AND p q r)

        if in an ... && ... expression then you don't want
        the entire predicate chain to fail just because the
        context for one component is wrong: so return true

        Consider (OR p q r)

        if in an ... || ... expression then you don't want
        the entire predicate chain to succeed just because
        the context for one component is correct when the
        corresponding test is false: so return false when
        the context is correct but the test is false.
*/

void
#ifdef __USE_PROTOS
genPredTree( Predicate *p, Node *j, int in_and_expr, int suppress_sva )
#else
genPredTree( p, j, in_and_expr, suppress_sva)
  Predicate     *p;
  Node          *j;
  int           in_and_expr;
  int           suppress_sva;
#endif
{

    int         allHaveContext=1;
    int         noneHaveContext=1;
    Tree        *groupTree;
    Tree        *oneTree;
    Predicate   *q;
    int         identicalORcontextOptimization=0;
    int         identicalANDcontextOptimization=0;

    if (0 && !MR_usingPredNames && !MRhoisting) {
      genPredTreeOrig(p,j,in_and_expr);
      return;
    };

    MR_predContextPresent(p,&allHaveContext,&noneHaveContext);

	if ( ! noneHaveContext ) {                 /* MR10 context guards ignored when -prc off */

      _gen("(");

            /* MR10 optimize OR predicates which are all leaves */

      if (p->expr == PRED_OR_LIST && MR_allPredLeaves(p->down)) {
        groupTree=MR_compute_pred_tree_context(p);
        for (q=p->down ; q != NULL ; q=q->right) {
          oneTree=MR_compute_pred_tree_context(q);
          if (! MR_tree_equ(groupTree,oneTree)) {
            Tfree(oneTree);
            break;
          };
          Tfree(oneTree);
        };
        Tfree(groupTree);
        if (q == NULL) {
          _gen("/* MR10 individual OR gates suppressed when all predicates are leaves");
          _gen(" with identical context */\n");
          genPredTreeGate(p,in_and_expr);   /* use the parent's in_and_expr for this gate */
          identicalORcontextOptimization=1;
        } else {
          MR_distinctORcontextOpt(p,j,in_and_expr);
          return;
        };
      } else if (p->expr == PRED_AND_LIST && MR_allPredLeaves(p->down)) {

            /* MR12 optimize AND predicates which are all leaves */

        groupTree=MR_compute_pred_tree_context(p);
        for (q=p->down ; q != NULL ; q=q->right) {
          oneTree=MR_compute_pred_tree_context(q);
          if (! MR_tree_equ(groupTree,oneTree)) {
            Tfree(oneTree);
            break;
          };
          Tfree(oneTree);
        };
        Tfree(groupTree);
        if (q == NULL) {
          _gen("/* MR12 individual AND gates suppressed when all predicates are leaves");
          _gen(" with identical context */\n");
          genPredTreeGate(p,in_and_expr);   /* use the parent's in_and_expr for this gate */
          identicalANDcontextOptimization=1;
        } else {
          genPredTreeGate(p, in_and_expr);
        };
      } else {
  	    genPredTreeGate(p, in_and_expr);
      };
	}

	/* if leaf node, just gen predicate */

	if ( p->down==NULL )
	{
		genPred(p,j,suppress_sva);
		if ( ! noneHaveContext ) _gen(")");   /* MR10 context guards ignored when -prc off */
		return;
	}

	/* if AND list, do both preds (only two possible) */
    /* MR10    not any more ! */

	if ( p->expr == PRED_AND_LIST )
	{
		Predicate *list;
		_gen("(");
		list = p->down;
        for (; list != NULL; list=list->right) {
          if (identicalANDcontextOptimization) {
            genPred(list, j,suppress_sva);
          } else {
	   	    genPredTree(list, j, 1, suppress_sva);  /* in and context */
          };
          if ( list->right!=NULL ) _gen("&&");
        };
		_gen(")");
		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
		return;
	}

	if ( p->expr == PRED_OR_LIST )
	{
		Predicate *list;
		_gen("(");
		list = p->down;
		for (; list!=NULL; list=list->right)
		{
            if (identicalORcontextOptimization) {
	          genPred(list, j,suppress_sva);
            } else {
	   	      genPredTree(list, j, 0, suppress_sva);
            };
			if ( list->right!=NULL ) _gen("||");
		}
		_gen(")");
		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
		return;
	}

	fatal_internal("predicate tree is wacked");
}

/* [genPredTreeMainXX] */

Predicate *     /* MR10 */
#ifdef __USE_PROTOS
genPredTreeMainXX( Predicate *p, Node *j ,int in_and_expr)
#else
genPredTreeMainXX( p, j ,in_and_expr)
    Predicate   *p;
    Node        *j;
    int         in_and_expr;
#endif
{

    int     allHaveContext=1;
    int     noneHaveContext=1;

#if 0
    fprintf(stderr,"Pred before\n");
    dumppred(p);
    fprintf(stderr,"\n");
    fprintf(stderr,"Pred after\n");
    dumppred(p);
    fprintf(stderr,"\n");
#endif

    p=MR_predSimplifyALL(p);    /* MR10 */

    require (MR_predicate_context_completed(p),"predicate context is not complete");

    MR_cleanup_pred_trees(p);   /* MR10 */

    MR_predContextPresent(p,&allHaveContext,&noneHaveContext);
    if (!noneHaveContext & !allHaveContext) {
      warnFL("predicate contains elements both with and without context",
                FileStr[j->file],j->line);
    };

    if (InfoP) {
       _gen("\n#if 0\n\n");
       MR_dumpPred(p,1);
       _gen("#endif\n");
    };
	genPredTree(p,j,in_and_expr,0);
    return p;
}

Predicate *     /* MR10 */
#ifdef __USE_PROTOS
genPredTreeMain( Predicate *p, Node *j)
#else
genPredTreeMain( p, j)
    Predicate   *p;
    Node        *j;
#endif
{
  return genPredTreeMainXX(p,j,1);
}

static void
#ifdef __USE_PROTOS
genExprTreeOriginal( Tree *t, int k )
#else
genExprTreeOriginal( t, k )
Tree *t;
int k;
#endif
{
	require(t!=NULL, "genExprTreeOriginal: NULL tree");
	
	if ( t->token == ALT )
	{
		_gen("("); genExprTreeOriginal(t->down, k); _gen(")");
		if ( t->right!=NULL )
		{
			_gen("||");
			on1line++;
			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
			_gen("("); genExprTreeOriginal(t->right, k); _gen(")");
		}
		return;
	}
	if ( t->down!=NULL ) _gen("(");
	_gen1("LA(%d)==",k);
	if ( TokenString(t->token) == NULL ) _gen1("%d", t->token)
	else _gen1("%s", TokenString(t->token));
	if ( t->down!=NULL )
	{
		_gen("&&");
		on1line++;
		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
		_gen("("); genExprTreeOriginal(t->down, k+1); _gen(")");
	}
	if ( t->down!=NULL ) _gen(")");
	if ( t->right!=NULL )
	{
		_gen("||");
		on1line++;
		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
		_gen("("); genExprTreeOriginal(t->right, k); _gen(")");
	}
}

#ifdef __USE_PROTOS
static void MR_LAtokenString(int k,int token)
#else
static void MR_LAtokenString(k,token)
  int   k;
  int   token;
#endif
{
    char    *ts;

    ts=TokenString(token);
    if (ts == NULL) {
      _gen2(" LA(%d)==%d",k,token);
    } else {
      _gen2(" LA(%d)==%s",k,ts);
    };
}


#ifdef __USE_PROTOS
static int MR_countLeaves(Tree *t)
#else
static int MR_countLeaves(t)
  Tree  *t;
#endif
{
  if (t == NULL) return 0;
  if (t->token == ALT) {
    return MR_countLeaves(t->down)+MR_countLeaves(t->right);
  } else {
    return 1+MR_countLeaves(t->down)+MR_countLeaves(t->right);
  };
}

#ifdef __USE_PROTOS
static void MR_genOneLine(Tree *tree,int k)
#else
static void MR_genOneLine(tree,k)
  Tree      *tree;
  int       k;
#endif
{
    if (tree == NULL) return;
    if (tree->token == ALT) {
       MR_genOneLine(tree->down,k);
    } else {
       MR_LAtokenString(k,tree->token);
       if (tree->down != NULL &&
           tree->down->right == NULL) {
          _gen(" &&");
          MR_genOneLine(tree->down,k+1);
       } else if (tree->down != NULL) {
         _gen(" && (");
         MR_genOneLine(tree->down,k+1);
         _gen(")");
       };
    };
    if (tree->right != NULL) {
      _gen(" ||");
      MR_genOneLine(tree->right,k);
    };
}

static int across;
static int depth;
static int lastkonline;

#ifdef __USE_PROTOS
static void MR_genMultiLine(Tree *tree,int k)
#else
static void MR_genMultiLine(tree,k)
  Tree  *tree;
  int   k;
#endif
{
    int     i;

    if (tree == NULL) return;
    if (tree->token == ALT) {
      MR_genMultiLine(tree,k);
    } else {
      MR_LAtokenString(k,tree->token);
      lastkonline=k;
      across++;
      if (tree->down != NULL && tree->down->right == NULL) {
        if (across > 3) {
          _gen("\n");
          across=0;
          lastkonline=0;
          for (i=0 ; i < depth+k ; i++) _gen("   ");
          _gen("&&");
        } else {
          _gen(" &&");
        };
        MR_genMultiLine(tree->down,k+1);
      } else if (tree->down != NULL) {
        _gen("\n");
        lastkonline=0;
        across=0;
        for (i=0 ; i < depth+k ; i++) _gen("   ");
        _gen("&& (");
        MR_genMultiLine(tree->down,k+1);
        _gen(")");
      };
    };
    if (tree->right != NULL) {
      if (k < lastkonline) {
        _gen("\n");
        across=0;
        lastkonline=0;
        for (i=0; i < depth+k-1 ; i++) _gen("   ");
        _gen("||");
      } else if (across > 3 ) {
        _gen("\n");
        across=0;
        lastkonline=0;
        for (i=0; i < depth+k ; i++) _gen("   ");
        _gen("||");
      } else {
        _gen(" ||");
      };
      MR_genMultiLine(tree->right,k);
    };
}

#ifdef __USE_PROTOS
static void genExprTree(Tree *tree,int k)
#else
static void genExprTree(tree,k)
  Tree  *tree;
  int   k;
#endif
{
    int     count;

#if 0
    /* MR20 THM This was probably an error.
            The routine should probably reference that static 
            "across" and this declaration hides it.
    */

    int     across;
#endif
  
    require (tree != NULL,"genExprTree: tree is NULL");
    require (k > 0,"genExprTree: k <= 0");

    if (0 && !MRhoisting) {   /* MR11 make new version standard */
      genExprTreeOriginal(tree,k);
    } else {
      count=MR_countLeaves(tree);
      if (count < 5) {
        MR_genOneLine(tree,k);
      } else {
        _gen("\n");
        across=0;
        depth=0;
        lastkonline=0;
        MR_genMultiLine(tree,k);
        _gen("\n");
      };
    };
}


/*
 * Generate LL(k) type expressions of the form:
 *
 *		 (LA(1) == T1 || LA(1) == T2 || ... || LA(1) == Tn) &&
 *		 (LA(2) == T1 || LA(2) == T2 || ... || LA(2) == Tn) &&
 *			.....
 *		 (LA(k) == T1 || LA(k) == T2 || ... || LA(k) == Tn)
 *
 * If GenExprSetsOpt generate:
 *
 *		(setwdi[LA(1)]&(1<<j)) && (setwdi[LA(2)]&(1<<j)) ...
 *
 * where n is set_deg(expr) and Ti is some random token and k is the last nonempty
 * set in fset <=CLL_k.
 * k=1..CLL_k where CLL_k >= 1.
 *
 * This routine is visible only to this file and cannot answer a TRANS message.
 *
 */

/*  [genExpr] */

static int
#ifdef __USE_PROTOS
genExpr( Junction *j )
#else
genExpr( j )
Junction *j;
#endif
{
	int max_k;

	/* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead
	 * from CLL_k..LL_k
	 */
	{
		int limit;
		if ( j->ftree!=NULL ) limit = LL_k;
		else limit = CLL_k;
		max_k = genExprSets(j->fset, limit);
	}

	/* Do tests for real tuples from other productions that conflict with
	 * artificial tuples generated by compression (using sets of tokens
	 * rather than k-trees).
	 */
	if ( j->ftree != NULL )
	{
		_gen(" && !("); genExprTree(j->ftree, 1); _gen(")");
	}

	if ( ParseWithPredicates && j->predicate!=NULL )
	{
		Predicate *p = j->predicate;
		warn_about_using_gk_option();
		_gen("&&");
		j->predicate=genPredTreeMain(p, (Node *)j);     /* MR10 */
	}

	return max_k;
}

static int
#ifdef __USE_PROTOS
genExprSets( set *fset, int limit )
#else
genExprSets( fset, limit )
set *fset;
int limit;
#endif
{
	int k = 1;
	int max_k = 0;
	unsigned *e, *g, firstTime=1;

    if (set_nil(fset[1])) {
      _gen(" 0 /* MR13 empty set expression  - undefined rule ? infinite left recursion ? */ ");
      MR_BadExprSets++;
    };

	if ( GenExprSetsOpt )
	{
		while ( k <= limit && !set_nil(fset[k]) )   /* MR11 */
		{
			if ( set_deg(fset[k])==1 )	/* too simple for a set? */
			{
				int e;
				_gen1("(LA(%d)==",k);
				e = set_int(fset[k]);
				if ( TokenString(e) == NULL ) _gen1("%d)", e)
				else _gen1("%s)", TokenString(e));
			}
			else
			{
				NewSet();
				FillSet( fset[k] );
				_gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<<setnum);
			}
			if ( k>max_k ) max_k = k;
			if ( k == CLL_k ) break;
			k++;
			if ( k<=limit && !set_nil(fset[k]) ) _gen(" && ");  /* MR11 */
			on1line++;
			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
		}
		return max_k;
	}

	while ( k<= limit &&  !set_nil(fset[k]) )       /* MR11 */
	{
		if ( (e=g=set_pdq(fset[k])) == NULL ) fatal_internal("genExpr: cannot allocate IF expr pdq set");
		for (; *e!=nil; e++)
		{
			if ( !firstTime ) _gen(" || ") else { _gen("("); firstTime = 0; }
			on1line++;
			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
			_gen1("LA(%d)==",k);
			if ( TokenString(*e) == NULL ) _gen1("%d", *e)
			else _gen1("%s", TokenString(*e));
		}
		free( (char *)g );
		_gen(")");
		if ( k>max_k ) max_k = k;
		if ( k == CLL_k ) break;
		k++;
		if ( k <= limit && !set_nil(fset[k]) ) { firstTime=1; _gen(" && "); }   /* MR11 */
		on1line++;
		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
	}
	return max_k;
}

/*
 * Generate code for any type of block.  If the last alternative in the block is
 * empty (not even an action) don't bother doing it.  This permits us to handle
 * optional and loop blocks as well.
 *
 * Only do this block, return after completing the block.
 * This routine is visible only to this file and cannot answer a TRANS message.
 */
static set
#ifdef __USE_PROTOS
genBlk( Junction *q, int jtype, int *max_k, int *need_right_curly, int * lastAltEmpty /* MR23 */)
#else
genBlk( q, jtype, max_k, need_right_curly, lastAltEmpty /* MR23 */)
Junction *q;
int jtype;
int *max_k;
int *need_right_curly;
int *lastAltEmpty; /* MR23 */
#endif
{
	set f;
	Junction *alt;
	int a_guess_in_block = 0;
	require(q!=NULL,				"genBlk: invalid node");
	require(q->ntype == nJunction,	"genBlk: not junction");
	*need_right_curly=0;
	*lastAltEmpty = 0;		/* MR23 */
	if ( q->p2 == NULL )	/* only one alternative?  Then don't need if */
	{	
		if (first_item_is_guess_block((Junction *)q->p1)!=NULL )
		{
            if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) {
  			  warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line);
            };
   	   	    gen("zzGUESS\n");	/* guess anyway to make output code consistent */
/* MR10 disable */  /**** gen("if ( !zzrv )\n"); ****/
/* MR10 */          gen("if ( !zzrv ) {\n"); tabs++; (*need_right_curly)++;
        };
		TRANS(q->p1);
		return empty;		/* no decision to be made-->no error set */
	}

	f = First(q, 1, jtype, max_k);
	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
	{
		if ( alt->p2 == NULL )					/* chk for empty alt */
		{	
			Node *p = alt->p1;
			if ( p->ntype == nJunction )
			{
				/* we have empty alt */
/* MR23
   There is a conflict between giving good error information for non-exceptions
   and making life easy for those using parser exception handling.  Consider:

         r: { A } b;
		 b: B;
		 
		   with input "C"

   Before MR21 the error message would be "expecting B - found C".  After MR21
   the error message would be "expect A, B - found C".  This was good, but it
   caused problems for those using parser exceptions because the reference to
   B was generated inside the {...} where B really wasn't part of the block.

   In MR23 this has been changed for the case where exceptions are in use to
   not generate the extra check in the tail of the {A} block.
*/


/* MR23 */	if (isEmptyAlt( ((Junction *)p)->p1, (Node *)q->end)) {
/* MR23 */      *lastAltEmpty = 1;
/* MR23 */		if (FoundException) {
/* MR23 */			/* code to restore state if a prev alt didn't follow guess */
/* MR23 */			if ( a_guess_in_block && jtype != aPlusBlk) {
/* MR23 */				gen("if ( !zzrv ) zzGUESS_DONE; /* MR28 */\n");
/* MR23 */			}
/* MR23 */			break;
/* MR23 */		};
/* MR28 */      if (jtype == aPlusBlk) {
/* MR28 */          break;
/* MR28 */      }
/* MR23 */	}
		}
	} /* end of for loop on alt */

/* MR10 */        if (alt->p2 == NULL &&
/* MR10 */               ( q->jtype == aSubBlk || q->jtype == RuleBlk) ) {
/* MR10 */          if (first_item_is_guess_block(alt)) {
/* MR10 */               warnFL("(...)? as last alternative of block is unnecessary",
/* MR10 */                                FileStr[alt->file],alt->line);
/* MR10 */          };
/* MR10 */        };

		if ( alt != q ) gen("else ")
		else
		{
			if ( DemandLookahead ) {
				if ( !GenCC ) {gen1("LOOK(%d);\n", *max_k);}
				else gen1("look(%d);\n", *max_k);
			}
		}

		if ( alt!=q )
		{
			_gen("{\n");
			tabs++;
			(*need_right_curly)++;
			/* code to restore state if a prev alt didn't follow guess */
			if ( a_guess_in_block )
				gen("if ( !zzrv ) zzGUESS_DONE;\n");
		}
		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL )
		{
			a_guess_in_block = 1;
			gen("zzGUESS\n");
		}
		gen("if ( ");
		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) _gen("!zzrv && ");
		genExpr(alt);
		_gen(" ) ");
		_gen("{\n");
		tabs++;
		TRANS(alt->p1);
		--tabs;
		gen("}\n");
/* MR10 */        if (alt->p2 == NULL) {
/* MR10 */          if (first_item_is_guess_block(alt)) {
/* MR10 */            gen("/* MR10 */ else {\n");
/* MR10 */            tabs++;
/* MR10 */  		  (*need_right_curly)++;
/* MR10 */  		  /* code to restore state if a prev alt didn't follow guess */
/* MR10 */            gen("/* MR10 */ if ( !zzrv ) zzGUESS_DONE;\n");
/* MR10 */            gen("/* MR10 */ if (0) {}     /* last alternative of block is guess block */\n");
/* MR10 */          };
/* MR10 */        };
	}
	return f;
}

static int
#ifdef __USE_PROTOS
has_guess_block_as_first_item( Junction *q )
#else
has_guess_block_as_first_item( q )
Junction *q;
#endif
{
	Junction *alt;

	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
	{
		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) return 1;
	}
	return 0;
}

static int
#ifdef __USE_PROTOS
has_guess_block_as_last_item( Junction *q )
#else
has_guess_block_as_last_item( q )
Junction *q;
#endif
{
	Junction *alt;

    if (q == NULL) return 0;
	for (alt=q; alt->p2 != NULL && !( (Junction *) alt->p2)->ignore; alt= (Junction *) alt->p2 ) {};
    return first_item_is_guess_block( (Junction *) alt->p1) != NULL;
}

/* MR30 See description of first_item_is_guess_block for background */

Junction *
#ifdef __USE_PROTOS
first_item_is_guess_block_extra(Junction *q )
#else
first_item_is_guess_block_extra(q)
Junction *q;
#endif
{
	while ( q!=NULL &&
            (  ( q->ntype==nAction ) ||
               ( q->ntype==nJunction &&
                    (q->jtype==Generic || q->jtype == aLoopBlk) 
               )
            )
          )
	{
		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
		else q = (Junction *) ((ActionNode *)q)->next;
	}

	if ( q==NULL ) return NULL;
	if ( q->ntype!=nJunction ) return NULL;
	if ( q->jtype!=aSubBlk ) return NULL;
	if ( !q->guess ) return NULL;

	return q;
}

/* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node
 * of (...)?;  This function ignores actions and predicates.
 */

Junction *
#ifdef __USE_PROTOS
first_item_is_guess_block( Junction *q )
#else
first_item_is_guess_block( q )
Junction *q;
#endif
{
	Junction * qOriginal = q;	/* DEBUG */

    /* MR14  Couldn't find aSubBlock which was a guess block when it lay
             behind aLoopBlk.  The aLoopBlk only appear in conjunction with
             aLoopBegin, but the routine didn't know that.  I think.

       MR14a Added extra parentheses to clarify precedence

	   MR30  This appears to have been a mistake.  The First set was then
	         computed incorrectly for:

					r : ( (A)? B
					    | C
						)*
			 
			 The routine analysis_point was seeing the guess block when
			 it was still analyzing the loopBegin block.  As a consequence,
			 when it looked for the analysis_point it was processing the B, but
			 skipping over the C alternative altogether because it thought
			 it was looking at a guess block, not realizing there was a loop
			 block in front of the loopBegin.

             loopBegin  loopBlk  subBlk/guess  A  G  EB  G  B EB EB  EB  ER
			    |          |          |                     ^   ^
				|		   |                                |   |
                |          +-> G  C G ----------------------+   |
                |                                               |
				+--- G G G -------------------------------------+
    
			 Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu).

		MR30  This is still more complicated.  This fix caused ambiguity messages
		to be reported for "( (A B)? )* A B" but not for "( (A B)? )+".  Why is
		there a difference when these are outwardly identical ?  It is because the
		start of a (...)* block is represented by two nodes: a loopBegin block
		followed by a loopBlock whereas the start of a (...)+ block is
		represented as a single node: a plusBlock.  So if first_item_is_guess_block
		is called when the current node is a loopBegin it starts with the
		loop block rather than the sub block which follows the loop block.
		However, we can't just skip past the loop block because some routines
		depend on the old implementation.  So, we provide a new implementation
		which does skip the loopBlock.  However, which should be called when ?
		I'm not sure, but my guess is that first_item_is_guess_block_extra (the
		new one) should only be called for the ambiguity routines.

    */

	while ( q!=NULL &&
            (  ( q->ntype==nAction ) ||
               ( q->ntype==nJunction &&
                    (q->jtype==Generic /*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/
               )
            )
          )
	{
		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
		else q = (Junction *) ((ActionNode *)q)->next;
	}

	if ( q==NULL ) return NULL;
	if ( q->ntype!=nJunction ) return NULL;
	if ( q->jtype!=aSubBlk ) return NULL;
	if ( !q->guess ) return NULL;

	return q;
}

/* MR1				                 					    */
/* MR1  10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs  */
/* MR1				                                                        */

#define STRINGIZEBUFSIZE 1024

static char stringizeBuf[STRINGIZEBUFSIZE];
char *
#ifdef __USE_PROTOS
stringize(char * s)
#else
stringize(s)
char *s;
#endif

{
  char		*p;
  char		*stop;

  p=stringizeBuf;
  stop=&stringizeBuf[1015];

  if (s != 0) {
    while (*s != 0) {
      if (p >= stop) {
	goto stringizeStop;
      } else if (*s == '\n') {
        *p++='\\';
        *p++='n';
        *p++='\\';
	*p++=*s++;
      } else if (*s == '\\') {
	*p++=*s;
	*p++=*s++;
      } else if (*s == '\"') {
        *p++='\\';
	*p++=*s++;
        while (*s != 0) {
          if (p >= stop) {
	     goto stringizeStop;
	  } else if (*s == '\n') {
	    *p++='\\';
	    *p++=*s++;
	  } else if (*s == '\\') {
	    *p++=*s++;
	    *p++=*s++;
	  } else if (*s == '\"') {
	    *p++='\\';
	    *p++=*s++;
	    break;
	  } else {
	    *p++=*s++;
          };
        };
      } else if (*s == '\'') {
	*p++=*s++;
        while (*s != 0) {
          if (p >= stop) {
	     goto stringizeStop;
	  } else if (*s == '\'') {
	    *p++=*s++;
	    break;
	  } else if (*s == '\\') {
	    *p++=*s++;
	    *p++=*s++;
	  } else if (*s == '\"') {
	    *p++='\\';
	    *p++=*s++;
	    break;
	  } else {
	    *p++=*s++;
          };
        };
      } else {
        *p++=*s++;
      };
    };
  };
  goto stringizeExit;
stringizeStop:
  *p++='.';        	
  *p++='.';        	
  *p++='.';        	
stringizeExit:
  *p=0;
  return stringizeBuf;
}

#ifdef __USE_PROTOS
int isNullAction(char *s)
#else
int isNullAction(s)
  char  *s;
#endif
{
  char  *p;
  for (p=s; *p != '\0' ; p++) {
    if (*p != ';' && *p !=' ') return 0;
  };
  return 1;
}
/* MR1									                                    */
/* MR1	End of Routine to stringize code for failed predicates msgs         */
/* MR1				                                                        */

/* Generate an action.  Don't if action is NULL which means that it was already
 * handled as an init action.
 */
void
#ifdef __USE_PROTOS
genAction( ActionNode *p )
#else
genAction( p )
ActionNode *p;
#endif
{
	require(p!=NULL,			"genAction: invalid node and/or rule");
	require(p->ntype==nAction,	"genAction: not action");

	if ( !p->done )  /* MR10 */ /* MR11 */
	{
		if ( p->is_predicate)
		{
			if ( p->guardpred != NULL )
			{
                Predicate *guardDup=predicate_dup(p->guardpred); /* MR10 */
                gen("if (!");
       			guardDup=genPredTreeMain(guardDup, (Node *)p);
                predicate_free(guardDup);
			}
/* MR10 */  else if (p->ampersandPred != NULL) {
/* MR10 */      gen("if (!");
/* MR10 */      p->ampersandPred=genPredTreeMain(p->ampersandPred, (Node *)p);
/* MR10 */  }
			else
			{
				gen("if (!(");
				/* make sure that '#line n' is on front of line */
				if ( GenLineInfo && p->file != -1 ) _gen("\n");
				dumpPredAction(p,p->action, output, 0, p->file, p->line, 0);
				_gen(")");
			}

/* MR23 Change failed predicate macro to have three arguments:

        macro arg 1: The stringized predicate itself
        macro arg 2: 0 => no user-defined error action
                     1 => user-defined error action
        macro arg 3: The user-defined error action

   This gives the user more control of the error action.
*/
			tabs++;
			gen3(") {zzfailed_pred(\"%s\",%s, { %s } );}\n",         /* MR23 */
					stringize(p->action),	                         /* MR23 */
                    (p->pred_fail == NULL ?                          /* MR23/MR27 */
                       	"0 /* report */" : "1 /* user action */"),   /* MR23/MR27 */
                    (p->pred_fail == NULL ?                          /* MR23 */
                        "; /* no user action */" : p->pred_fail));   /* MR23 */
			tabs--;
		}
		else    /* not a predicate */
		{
            if (! isNullAction(p->action) && !p->noHoist) {
  	  		  if ( FoundGuessBlk ) {
				if ( GenCC ) {
                  gen("if ( !guessing ) {\n");
                } else {
				  gen("zzNON_GUESS_MODE {\n");
                };
              };
			  dumpActionPlus(p, p->action, output, tabs, p->file, p->line, 1); /* MR21 */
			  if ( FoundGuessBlk ) gen("}\n");
            };
		}
	}
	TRANS(p->next)
}

/*
 *		if invoking rule has !noAST pass zzSTR to rule ref and zzlink it in
 *		else pass addr of temp root ptr (&_ast) (don't zzlink it in).
 *
 *		if ! modifies rule-ref, then never link it in and never pass zzSTR.
 *		Always pass address of temp root ptr.
 */
void
#ifdef __USE_PROTOS
genRuleRef( RuleRefNode *p )
#else
genRuleRef( p )
RuleRefNode *p;
#endif
{
	Junction *q;
	char *handler_id = "";
	RuleEntry *r, *r2;
	char *parm = "", *exsig = "";

    int     genRuleRef_emittedGuessGuard=0;     /* MR10 */

	require(p!=NULL,			"genRuleRef: invalid node and/or rule");
	require(p->ntype==nRuleRef, "genRuleRef: not rule reference");
	
	if ( p->altstart!=NULL && p->altstart->exception_label!=NULL )
		handler_id = p->altstart->exception_label;

	r = (RuleEntry *) hash_get(Rname, p->text);
	if ( r == NULL )
	{
		warnFL( eMsg1("rule %s not defined",
					  p->text), FileStr[p->file], p->line );
		return;
	}

/* MR8 5-Aug-97     Reported by S.Bochnak@microtool.com.pl                  */
/*                  Don't do assign when no return values declared          */
/*                  Move definition of q up and use it to guard p->assign   */

	q = RulePtr[r->rulenum];	/* find definition of ref'd rule */  /* MR8 */

	r2 = (RuleEntry *) hash_get(Rname, p->rname);
	if ( r2 == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}

    OutLineInfo(output,p->line,FileStr[p->file]);

	if ( GenCC && GenAST ) {
		gen("_ast = NULL;\n");
	}

	if ( FoundGuessBlk && p->assign!=NULL && q->ret != NULL ) {      /* MR8 */
		if ( GenCC ) {
          gen("if ( !guessing ) {\n");
        } else {
          gen("zzNON_GUESS_MODE {\n");
        };
        tabs++;                                                      /* MR11 */
        genRuleRef_emittedGuessGuard=1;                              /* MR11 */
    };

	if ( FoundException ) exsig = "&_signal";

	tab();
	if ( GenAST )
	{
		if ( GenCC ) {
/****			if ( r2->noAST || p->astnode==ASTexclude )
****/
			{
/****				_gen("_ast = NULL;\n");
****/
				parm = "&_ast";
			}
/*** we always want to set just a pointer now, then set correct
pointer after

			else {
				_gen("_astp =
(_tail==NULL)?(&_sibling):(&(_tail->_right));\n");
				parm = "_astp";
			}
****/
		}
		else {
			if ( r2->noAST || p->astnode==ASTexclude )
			{
				_gen("_ast = NULL; ");
				parm = "&_ast";
			}
			else parm = "zzSTR";
		}
		if ( p->assign!=NULL && q->ret!=NULL )                       /* MR8 */
		{
			if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */
			else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum);
		}
		if ( FoundException ) {
			_gen5("%s%s(%s,&_signal%s%s); ",
				  RulePrefix,
				  p->text,
				  parm,
				  (p->parms!=NULL)?",":"",
				  (p->parms!=NULL)?p->parms:"");
			if ( p->ex_group!=NULL ) {
				_gen("\n");
				gen("if (_signal) {\n");
				tabs++;
				dumpException(p->ex_group, 0);
				tabs--;
				gen("}");
			}
			else {
				_gen1("if (_signal) goto %s_handler;", handler_id);
			}
		}
		else {
			_gen5("%s%s(%s%s%s);",
				  RulePrefix,
				  p->text,
				  parm,
				  (p->parms!=NULL)?",":"",
				  (p->parms!=NULL)?p->parms:"");
		}
		if ( GenCC && (r2->noAST || p->astnode==ASTexclude) )
		{
			/* rule has a ! or element does */
			/* still need to assign to #i so we can play with it */
			_gen("\n");
			gen2("_ast%d%d = (AST *)_ast;", BlkLevel-1, p->elnum);
		}
		else if ( !r2->noAST && p->astnode == ASTinclude )
		{
			/* rule doesn't have a ! and neither does element */
/* MR10 */  if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) {
/* MR10 */    _gen("\n");
/* MR10 */    if (GenCC) gen ("if (!guessing) {    /* MR10 */")
/* MR10 */          else gen ("if (!zzguessing) {    /* MR10 */\n");
/* MR10 */    tabs++;
/* MR10 */  };
			if ( GenCC ) {
				_gen("\n");
				gen("if ( _tail==NULL ) _sibling = _ast; else _tail->setRight(_ast);\n");
				gen2("_ast%d%d = (AST *)_ast;\n", BlkLevel-1, p->elnum);
				tab();
			}
			else _gen(" ");
            if ( GenCC ) {
                _gen("ASTBase::"); }
                else _gen("zz");
			_gen("link(_root, &_sibling, &_tail);");

/* MR10 */  if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) {     /* MR10 */
/* MR10 */    _gen("\n");
/* MR10 */    tabs--;
/* MR10 */    if (GenCC) gen ("};    /* MR10 */")
/* MR10 */          else gen ("};    /* MR10 */");
/* MR10 */  };
		}
	}
	else
	{
		if ( p->assign!=NULL && q->ret!=NULL )                       /* MR8 */
		{
			if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */
			else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum);
		}
		if ( FoundException ) {
			_gen4("%s%s(&_signal%s%s); ",
				  RulePrefix,
				  p->text,
				  (p->parms!=NULL)?",":"",
				  (p->parms!=NULL)?p->parms:"");
			if ( p->ex_group!=NULL ) {
				_gen("\n");
				gen("if (_signal) {\n");
				tabs++;
				dumpException(p->ex_group, 0);
				tabs--;
				gen("}");
			}
			else {
				_gen1("if (_signal) goto %s_handler;", handler_id);
			}
		}
		else {
			_gen3("%s%s(%s);",
				  RulePrefix,
				  p->text,
				  (p->parms!=NULL)?p->parms:"");
		}
		if ( p->assign!=NULL && q->ret!=NULL ) _gen("\n");           /* MR8 */
	}

	if ( p->assign!=NULL && q->ret!=NULL) {                          /* MR8 */
		if ( hasMultipleOperands(p->assign) )                        /* MR23 */
		{
			_gen("\n");
			dumpRetValAssign(p->assign, q->ret, p);                  /* MR30 */
			_gen("}");
		}
	}
	_gen("\n");

	/* Handle element labels now */
	if ( p->el_label!=NULL )
	{
		if ( GenAST )
		{
			if ( GenCC ) {
				gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
			}
			else {gen1("%s_ast = zzastCur;\n", p->el_label);}
		}
       	else if (!GenCC ) {
			gen1("%s = zzaCur;\n", p->el_label);
        }
	}

	if ( FoundGuessBlk && p->assign!=NULL && q->ret!=NULL ) {       /* MR8 */
		/* in guessing mode, don't branch to handler upon error */
        tabs--;                                                     /* MR11 */
		gen("} else {\n");
        tabs++;                                                     /* MR11 */
		if ( FoundException ) {
			gen6("%s%s(%s%s&_signal%s%s);\n",
				 RulePrefix,
				 p->text,
				 parm,
                 (*parm!='\0')?",":"",
                 (p->parms!=NULL)?",":"",
				 (p->parms!=NULL)?p->parms:"");
		}
		else {
			gen5("%s%s(%s%s%s);\n",
				 RulePrefix,
				 p->text,
				 parm,
				 (p->parms!=NULL && *parm!='\0')?",":"",
				 (p->parms!=NULL)?p->parms:"");
		}
        tabs--;                                                     /* MR11 */
		gen("}\n");
	}
	TRANS(p->next)
}

/*
 * Generate code to match a token.
 *
 * Getting the next token is tricky.  We want to ensure that any action
 * following a token is executed before the next GetToken();
 */
void
#ifdef __USE_PROTOS
genToken( TokNode *p )
#else
genToken( p )
TokNode *p;
#endif
{
	RuleEntry *r;
	char *handler_id = "";
	ActionNode *a;
	char *set_name;
	char *set_nameErrSet;
	int complement;
	int ast_label_in_action = 0;	/* MR27 */
	int pushedCmodeAST = 0;			/* MR27 */

	require(p!=NULL,			"genToken: invalid node and/or rule");
	require(p->ntype==nToken,	"genToken: not token");
	if ( p->altstart!=NULL && p->altstart->exception_label!=NULL )
		handler_id = p->altstart->exception_label;

	r = (RuleEntry *) hash_get(Rname, p->rname);
	if ( r == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}

/*
 * MR27 Has the element label been referenced as an AST (with the # operator) ?
 *      If so, then we'll want to build the AST even though the user has used
 *      the ! operator.
 */
/* MR27 */	if (GenAST && p->el_label != NULL) {
/* MR27 */		ast_label_in_action = list_search_cstring(r->ast_labels_in_actions,
/* MR27 */		                                          p->el_label);
/* MR27 */	}
	
    OutLineInfo(output,p->line,FileStr[p->file]);

	if ( !set_nil(p->tset) )	/* implies '.', ~Tok, or tokenclass */
	{
		unsigned e;
		unsigned eErrSet = 0;
		set b;
		set bErrSet;					/* MR23 */
		b = set_dup(p->tset);
		bErrSet = set_dup(p->tset);	    /* MR23 */
		complement = p->complement; /* MR23 */
		if ( p->tclass!=NULL  && complement == 0 /* MR23 */) { /* token class not complemented*/
			static char buf[MaxRuleName+20];	    /* MR23 */
			static char bufErrSet[MaxRuleName+20];	/* MR23 */
			if ( p->tclass->dumped ) {
				e = p->tclass->setnum;
				eErrSet = p->tclass->setnumErrSet;
			}
			else {
				e = DefErrSet(&b, 0, TokenString(p->token));
				eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errset");
				p->tclass->dumped = 1;	/* indicate set has been created */
				p->tclass->setnum = e;
				p->tclass->setnumErrSet = eErrSet;					/* MR23 */
			}
			sprintf(buf, "%s_set", TokenString(p->token));
			sprintf(bufErrSet, "%s_errset", TokenString(p->token));	/* MR23 */
			set_name = buf;
			set_nameErrSet = bufErrSet;								/* MR23 */
		}

		/* MR23 - Forgot about the case of ~TOKCLASS. */

		else if ( p->tclass!=NULL  && complement != 0 /* MR23 */)
		{
			static char buf[MaxRuleName+20];	    /* MR23 */
			static char bufErrSet[MaxRuleName+20];	/* MR23 */
			if ( p->tclass->dumpedComplement ) {
				e = p->tclass->setnumComplement;
				eErrSet = p->tclass->setnumErrSetComplement;
			}
			else {
				e = DefErrSetWithSuffix(0, &b, 0, TokenString(p->token), "_setbar");
				eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errsetbar");
				p->tclass->dumpedComplement = 1;	/* indicate set has been created */
				p->tclass->setnumComplement = e;
				p->tclass->setnumErrSetComplement = eErrSet;					/* MR23 */
			}
			sprintf(buf, "%s_setbar", TokenString(p->token));
			sprintf(bufErrSet, "%s_errsetbar", TokenString(p->token));	/* MR23 */
			set_name = buf;
			set_nameErrSet = bufErrSet;								/* MR23 */
		}
		else {					/* wild card */
			static char buf[sizeof("zzerr")+11];
			static char bufErrSet[sizeof("zzerr")+11];
			int n = DefErrSet( &b, 0, NULL );
			int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set");
			if ( GenCC ) snprintf(buf, 11, "err%d", n);
			else snprintf(buf, 11, "zzerr%d", n);
			if ( GenCC ) sprintf(bufErrSet, "err%d", nErrSet);
			else snprintf(bufErrSet, 11, "zzerr%d", nErrSet);
			set_name = buf;
			set_nameErrSet = bufErrSet;
		}

		if ( !FoundException ) {
/* MR23 */		gen2("zzsetmatch(%s, %s);", set_name, set_nameErrSet);
		}
		else if ( p->ex_group==NULL ) {
            if ( p->use_def_MT_handler )
                gen3("zzsetmatch_wdfltsig(%s,(ANTLRTokenType)%d,%s);",
                     set_name,
                     p->token,
                     tokenFollowSet(p))
            else
                gen2("zzsetmatch_wsig(%s, %s_handler);",
                     set_name,
                     handler_id);
		}
		else
		{
			gen1("if ( !_setmatch_wsig(%s) ) {\n", set_name);
			tabs++;
/* MR6 */	if (FoundGuessBlk) {
/* MR6 */	  if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
/* MR6 */	  else gen("if ( zzguessing ) goto fail;\n");
/* MR6 */	};
			gen("_signal=MismatchedToken;\n");
			dumpException(p->ex_group, 0);
			tabs--;
			gen("}\n");
		}
		set_free(b);
		set_free(bErrSet);
	}
	else if ( TokenString(p->token)!=NULL )
	{
		if ( FoundException ) {
			if ( p->use_def_MT_handler )
				gen2("zzmatch_wdfltsig(%s,%s);",TokenString(p->token),tokenFollowSet(p))
			else if ( p->ex_group==NULL )
			{
				gen2("zzmatch_wsig(%s, %s_handler);",
					 TokenString(p->token),
					 handler_id);
			}
			else
			{
/* MR6 */		if (GenCC) {
/* MR6 */		  gen1("if ( !_match_wsig(%s) ) {\n", TokenString(p->token));
/* MR6 */		} else {
/* MR6 */		  gen1("if ( !_zzmatch_wsig(%s) ) {\n", TokenString(p->token));
/* MR6 */		};
				tabs++;
/* MR6 */		if (FoundGuessBlk) {
/* MR6 */	  	  if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
/* MR6 */		  else gen("if ( zzguessing ) goto fail;\n");
/* MR6 */		};
				gen("_signal=MismatchedToken;\n");
				dumpException(p->ex_group, 0);
				tabs--;
				gen("}\n");
			}
		}
		else gen1("zzmatch(%s);", TokenString(p->token));
	}
	else {
        if ( FoundException ) {
            if ( p->use_def_MT_handler )
				gen2("zzmatch_wdfltsig((ANTLRTokenType)%d,%s);",
					 p->token,tokenFollowSet(p))
            else
                gen2("zzmatch_wsig(%d,%s_handler);",p->token,handler_id);
        }
		else {gen1("zzmatch(%d);", p->token);}
	}

	a = findImmedAction( p->next );
	/* generate the token labels */
	if ( GenCC && p->elnum>0 )
	{
		/* If building trees in C++, always gen the LT() assigns */
		if ( set_el(p->elnum, tokensRefdInBlock) || GenAST )
		{
/* MR10 */	if ( FoundGuessBlk ) {
/* MR10 */    gen("\n");
/* MR10 */    if (p->label_used_in_semantic_pred) {
/* MR10 */		gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);  /* MR10 */\n", BlkLevel-1, p->elnum);
/* MR10 */    } else {
/* MR10 */		gen("if ( !guessing ) {\n"); tab();
/* MR10 */		_gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);\n", BlkLevel-1, p->elnum);
/* MR10 */      gen("}\n");
/* MR10 */    };
/* MR10 */  } else {
/* MR10 */	  _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);", BlkLevel-1, p->elnum);
/* MR10 */  };
/* MR10 */
		}

/*
 *  MR23 labase is never used in the C++ runtime library.
 *       and this code is generated only in C++ mode
 */

/***		if ( LL_k>1 )                                    / * MR23 disabled */
/***			if ( !DemandLookahead ) _gen(" labase++;");  / * MR23 disabled */
/***		_gen("\n");                                      / * MR23 disabled */
/***		tab();                                           / * MR23 disabled */
	}
	if ( GenAST )
	{
		if ( FoundGuessBlk &&
				(ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) )
		{
			if ( GenCC ) {_gen("if ( !guessing ) {\n"); tab();}
			else {_gen("zzNON_GUESS_MODE {\n"); tab();}
		}

/* MR27 addition when labels referenced when operator ! used */

		pushedCmodeAST = 0; /* MR27 */
		if (ast_label_in_action && (p->astnode == ASTexclude || r->noAST)) {
			_gen("\n");
			if (GenCC) {
/* MR13 */      if (NewAST) {
/* MR13 */    	    gen4("_ast%d%d = newAST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
/* MR13 */      } else {
/* MR13 */    	    gen4("_ast%d%d = new AST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
/* MR13 */      }
			}
			else {
				pushedCmodeAST = 1;
				gen("zzastPush(zzmk_ast(zzastnew(),zzaCur)); /* MR27 */");
			}
		}

/* end MR27 addition for labels referenced when operator ! used */

		if (!r->noAST )
		{
			if (GenCC && !(p->astnode == ASTexclude) ) {
				_gen("\n");
/* MR13 */      if (NewAST) {
/* MR13 */    	    gen4("_ast%d%d = newAST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
/* MR13 */      } else {
/* MR13 */    	    gen4("_ast%d%d = new AST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
/* MR13 */      }
				tab();
			}
			if ( GenCC && !(p->astnode == ASTexclude) )
				{_gen2("_ast%d%d->", BlkLevel-1, p->elnum);}
			else _gen(" ");
			if ( p->astnode==ASTchild ) {
				if ( !GenCC ) _gen("zz");
				_gen("subchild(_root, &_sibling, &_tail);");
			}
			else if ( p->astnode==ASTroot ) {
				if ( !GenCC ) _gen("zz");
				_gen("subroot(_root, &_sibling, &_tail);");
			}
			if ( GenCC && !(p->astnode == ASTexclude) ) {
				_gen("\n");
				tab();
			}
		}
		else if ( !GenCC ) {
			if (! pushedCmodeAST) _gen(" zzastDPush;");
		}
		if ( FoundGuessBlk &&
				(ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) )
			{gen("}\n"); tab();}
	}

	/* Handle element labels now */
	if ( p->el_label!=NULL )
	{
        int     done_NON_GUESSMODE=0;

		_gen("\n");

/* MR10 */    /* do Attrib / Token ptr for token label used in semantic pred */
/* MR10 */    /* for these cases do assign even in guess mode                */
/* MR10 */
/* MR10 */    if (p->label_used_in_semantic_pred) {
/* MR10 */      if ( GenCC ) {
/* MR10 */        if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) {
/* MR10 */          gen3("%s = _t%d%d;", p->el_label, BlkLevel-1, p->elnum);
/* MR10 */        } else {
/* MR10 */          gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label);
/* MR10 */        };
/* MR10 */      } else {
/* MR10 */		  gen1("%s = zzaCur;", p->el_label);
/* MR10 */      };
/* MR10 */      if (FoundGuessBlk) _gen("  /* MR10 */");
/* MR10 */      _gen("\n");
/* MR10 */    };

		/* Do Attrib / Token ptr */

/* MR10 */  if (! p->label_used_in_semantic_pred) {
/* MR10 */
/* MR10 */      if ( FoundGuessBlk ) {
/* MR10 */        if (! done_NON_GUESSMODE) {
/* MR10 */          done_NON_GUESSMODE=1;
/* MR10 */          if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();}
/* MR10 */          else {gen("zzNON_GUESS_MODE {\n"); tab();}
/* MR10 */        };
/* MR10 */      };
/* MR10 */
/* MR10 */      if ( GenCC ) {
/* MR10 */        if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) {
/* MR10 */          gen3("%s = _t%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
/* MR10 */        } else {
/* MR10 */          gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label);
/* MR10 */        };
/* MR10 */      } else {
/* MR10 */        gen1("%s = zzaCur;\n", p->el_label);
/* MR10 */      };
/* MR10 */  };

		/* Do AST ptr */

		if (GenAST && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST) )) /* MR27 */
		{

/* MR10 */      if ( FoundGuessBlk ) {
/* MR10 */        if (! done_NON_GUESSMODE) {
/* MR10 */          done_NON_GUESSMODE=1;
/* MR10 */          if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();}
/* MR10 */          else {gen("zzNON_GUESS_MODE {\n"); tab();}
/* MR10 */        };
/* MR10 */      };

			if ( GenCC ) {
				gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
			}
			else {gen1("%s_ast = zzastCur;\n", p->el_label);}
		}

/* MR10 */  if (done_NON_GUESSMODE) {
/* MR10 */    gen("}\n"); tab();
/* MR10 */  };

	}

	/* Handle any actions immediately following action */
	if ( a != NULL )  /* MR10 */ /* MR11 */
    {
    	/* delay next token fetch until after action */
		_gen("\n");
		if ( a->is_predicate)
		{
#if 0
/* Disabled in MR30 ************************************************************
   And moved into genAction
   *****************************************************************************
*/
 
    	    gen("if (!(");

			/* make sure that '#line n' is on front of line */  /* MR14 */
			if ( GenLineInfo && p->file != -1 ) _gen("\n");     /* MR14 */
			dumpPredAction(a,a->action, output, 0, a->file, a->line, 0);

/* MR23 Change failed predicate macro to have three arguments:

        macro arg 1: The stringized predicate itself
        macro arg 2: 0 => no user-defined error action
                     1 => user-defined error action
        macro arg 3: The user-defined error action

   This gives the user more control of the error action.
*/
			_gen(")) \n");
			tabs++;
			gen3(" {zzfailed_pred(\"%s\",%s,{ %s } );}\n",           /* MR23 */
					stringize(a->action),	                         /* MR23 */
                    (a->pred_fail == NULL ?                          /* MR23/MR27 */
                       	"0 /* report */" : "1 /* user action */"),   /* MR23/MR27 */
                    (a->pred_fail == NULL ?                          /* MR23 */
                        "; /* no user action */" : a->pred_fail));   /* MR23 */
			tabs--;
/* Disabled in MR30 ************************************************************
   And moved into genAction
   *****************************************************************************
*/
#endif
		}
		else    /* MR9 a regular action - not a predicate action */
		{

/* MR23: Search an action which is not a predicate for LT(i),
         LA(i), or LATEXT(i) in order to warn novice users that
         it refers to the previous matched token, not the next
         one.  This is different than the case for semantic
         predicates.
*/
                                 
/* MR23 */    if (GenCC) {
/* MR23 */	    if (strstr(a->action, "LT(") != NULL) LTinTokenAction = 1;
/* MR23 */    }
/* MR23 */    else {
/* MR23 */      if (strstr(a->action, "LA(") != NULL) LTinTokenAction = 1;            
/* MR23 */      if (strstr(a->action, "LATEXT(") != NULL) LTinTokenAction = 1;
/* MR23 */    }

			if ( FoundGuessBlk ) {
   				if ( GenCC ) {gen("if ( !guessing ) {\n");}
   				else gen("zzNON_GUESS_MODE {\n");
			}
   			dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); /* MR21 */
       		if ( FoundGuessBlk ) gen("}\n");
			a->done = 1; /* MR30 */
 		}
/***    a->done = 1;  MR30 Moved up into then branch for true actions, but not predicates ***/
		if ( !DemandLookahead ) {
			if ( GenCC ) {
				if ( FoundException && p->use_def_MT_handler ) gen("if (!_signal)");
				_gen(" consume();")
                if ( FoundException && p->use_def_MT_handler )
                    _gen(" _signal=NoSignal;");
                _gen("\n");
			}
            else
            {
                if ( FoundException && p->use_def_MT_handler ) _gen("if (!_signal)");
					_gen(" zzCONSUME;\n");
                if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;");
                _gen("\n");
            }
		}
		else gen("\n");
		if (a->done) {			/* MR30 */
			TRANS( a->next );   /* MR30 */
		}						/* MR30 */
		else {					/* MR30 */
			TRANS( p->next );	/* MR30 */
		}						/* MR30 */
	}
	else
	{
        if ( !DemandLookahead ) {
			if ( GenCC ) {
				if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)");
				_gen(" consume();")
				if (FoundException&&p->use_def_MT_handler) _gen(" _signal=NoSignal;");
				_gen("\n");
			}
			else {
				if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)");
				_gen(" zzCONSUME;");
				if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;");
				_gen("\n");
			}
		}
		else _gen("\n");
		TRANS(p->next);
	}
}

/*  MR21
 *
 *  There was a bug in the code generation for {...} which causes it
 *  to omit the optional tokens from the error messages.  The easiest
 *  way to fix this was to make the opt block look like a sub block:
 *
 *          { a | b | c }
 *
 *  becomes (internally):
 *
 *          ( a | b | c | )
 *
 *  The code for genOptBlk is now identical to genSubBlk except for
 *  cosmetic changes.
 */

void
#ifdef __USE_PROTOS
genOptBlk( Junction *q )
#else
genOptBlk( q )
Junction *q;
#endif
{
	int max_k;
	set f;
	int need_right_curly;
	set savetkref;
	int lastAltEmpty;			/* MR23 */
	savetkref = tokensRefdInBlock;
	require(q->ntype == nJunction,	"genOptBlk: not junction");
	require(q->jtype == aOptBlk,	"genOptBlk: not opt block");

    OutLineInfo(output,q->line,FileStr[q->file]);
	BLOCK_Preamble(q);
	BlkLevel++;
    BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */
	f = genBlk(q, aOptBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
/* MR23
   Bypass error clause generation when exceptions are used in {...} block 
   See multi-line note in genBlk near call to isEmptyAlt.
*/
	if (! FoundException) {
	    if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
	}
	else {
		gen("/* MR23 skip error clause for {...} when exceptions in use */\n");
	}
	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
	freeBlkFsets(q);
	--BlkLevel;
	BLOCK_Tail();

	if ( q->guess )
	{
		gen("zzGUESS_DONE\n");
	}

	/* must duplicate if (alpha)?; one guesses (validates), the
	 * second pass matches */
	if ( q->guess && analysis_point(q)==q )
	{
        OutLineInfo(output,q->line,FileStr[q->file]);
		BLOCK_Preamble(q);
		BlkLevel++;
		f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
		{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
		freeBlkFsets(q);
		--BlkLevel;
		BLOCK_Tail();
	}

	tokensRefdInBlock = savetkref;
	if (q->end->p1 != NULL) TRANS(q->end->p1);
}

/*
 * Generate code for a loop blk of form:
 *
 *				 |---|
 *				 v   |
 *			   --o-G-o-->o--
 */
void
#ifdef __USE_PROTOS
genLoopBlk( Junction *begin, Junction *q, Junction *start, int max_k )
#else
genLoopBlk( begin, q, start, max_k )
Junction *begin;
Junction *q;
Junction *start;	/* where to start generating code from */
int max_k;
#endif
{
	set         f;
	int         need_right_curly;
	set         savetkref;
    Junction    *guessBlock;    /* MR10 */
    int         singleAlt;      /* MR10 */
	int			lastAltEmpty;	/* MR23 */

	savetkref = tokensRefdInBlock;
	require(q->ntype == nJunction,	"genLoopBlk: not junction");
	require(q->jtype == aLoopBlk,	"genLoopBlk: not loop block");

	if ( q->visited ) return;
	q->visited = TRUE;

    /* first_item_is_guess_block doesn't care what kind of node it is */

    guessBlock=first_item_is_guess_block( (Junction *) q->p1);  /* MR10 */
    singleAlt=q->p2==NULL;                                      /* MR10 */

	if (singleAlt && !guessBlock)	    /* MR10 */ /* only one alternative? */
	{
		if ( DemandLookahead ) {
			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
			else gen1("look(%d);\n", max_k);
		}
		gen("while ( ");
		if ( begin!=NULL ) genExpr(begin);
		else genExpr(q);
		/* if no predicates have been hoisted for this single alt (..)*
		 * do so now
		 */
        require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
		if ( ParseWithPredicates && begin->predicate==NULL )
		{
			Predicate *a = MR_find_predicates_and_supp((Node *)q->p1);
            require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");

			if ( a!=NULL )
			{
				_gen("&&");
				a=genPredTreeMain(a, (Node *)q);    /* MR10 */
			}
/* MR10 */  if (MRhoisting) {
/* MR10 */    predicate_free(a);
/* MR10 */  };
		}
		_gen(" ) {\n");
		tabs++;
		TRANS(q->p1);
		if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
		if ( DemandLookahead ) {
			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
			else gen1("look(%d);\n", max_k);
		}
		--tabs;
		gen("}\n");
		freeBlkFsets(q);
		q->visited = FALSE;
		tokensRefdInBlock = savetkref;
		return;
	}
	gen("for (;;) {\n");        /* MR20 G. Hobbelt */
	tabs++;
/* MR6				                					*/
/* MR6 	   "begin" can never be null when called from genLoopBegin	*/
/* MR6     because q==(Junction *)begin->p1 and we know q is valid	*/
/* MR6								                            	*/
/* MR6	   from genLoopBegin:						                */
/* MR6			                						            */
/* MR6		 if ( LL_k>1 && !set_nil(q->fset[2]) )			        */
/* MR6	 	   genLoopBlk( q, (Junction *)q->p1, q, max_k );	    */
/* MR6		else genLoopBlk( q, (Junction *)q->p1, NULL, max_k );	*/
/* MR6				                				            	*/
	if ( begin!=NULL )
	{
		if ( DemandLookahead )
		{
			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
			else gen1("look(%d);\n", max_k);
		}
		/* The bypass arc of the (...)* predicts what to do when you fail, but
		 * ONLY after having tested the loop start expression.  To avoid this,
		 * we simply break out of the (...)* loop when we find something that
		 * is not in the prediction of the loop (all alts thereof).
		 */
		gen("if ( !(");

/***	TJP says: It used to use the prediction expression for the bypass arc
     	of the (...)*.  HOWEVER, if a non LL^1(k) decision was found, this
    	thing would miss the ftree stored in the aLoopBegin node and generate
    	an LL^1(k) decision anyway.

 ***		genExpr((Junction *)begin->p2);
 ***/

            genExpr((Junction *)begin);
            _gen(")) break;\n");

	}

	/* generate code for terminating loop (this is optional branch) */

	f = genBlk(q, aLoopBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
	set_free(f);
	freeBlkFsets(q);

	/* generate code for terminating loop (this is optional branch) */

/* MR6 						                    			            */
/* MR6  30-May-97 Bug reported by Manuel Ornato				            */
/* MR6            A definite bug involving the exit from a loop block   */
/* MR6 		  In 1.23 and later versions (including 1.33) Instead       */
/* MR6              exiting the block and reporting a syntax error the  */
/* MR6		    code loops forever.     				                */
/* MR6	          Looking at 1.20 which generates proper code it is not */
/* MR6		    clear which of two changes should be undone.            */
/* MR6		  This is my best guess.                                    */
/* MR6		  From earlier MR6 note we know that begin can never be     */
/* MR6		    null when genLoopBlk called from genLoopBegin           */
/* MR6 */
/* MR6 */ if ( begin==NULL) {
/* MR6 */   /* code for exiting loop "for sure" */
/* MR6 */   gen("/* Suppressed by MR6 */ /*** else break; ***/\n");
/* MR6 */ };

/* MR10 */if (singleAlt && guessBlock) {
/* MR10 */  tabs--;
/* MR6 */   gen("} else break; /* MR6 code for exiting loop \"for sure\" */\n");
/* MR10 */  need_right_curly--;
/* MR10 */ } else {
/* MR6 */   gen("else break; /* MR6 code for exiting loop \"for sure\" */\n");
/* MR10 */ };

	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
	if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
	--tabs;
	gen("}\n");
	q->visited = FALSE;
	tokensRefdInBlock = savetkref;
}

/*
 * Generate code for a loop blk of form:
 *
 * 				         |---|
 *					     v   |
 *			   --o-->o-->o-G-o-->o--
 *                   |           ^
 *                   v           |
 *					 o-----------o
 *
 * q->end points to the last node (far right) in the blk.
 *
 * Note that q->end->jtype must be 'EndBlk'.
 *
 * Generate code roughly of the following form:
 *
 *	do {
 *		... code for alternatives ...
 *  } while ( First Set of aLoopBlk );
 *
 *	OR if > 1 alternative
 *
 *	do {
 *		... code for alternatives ...
 *		else break;
 *  } while ( 1 );
 */
void
#ifdef __USE_PROTOS
genLoopBegin( Junction *q )
#else
genLoopBegin( q )
Junction *q;
#endif
{
	set f;
	int i;
	int max_k;
	set savetkref;
	savetkref = tokensRefdInBlock;
	require(q!=NULL,				"genLoopBegin: invalid node and/or rule");
	require(q->ntype == nJunction,	"genLoopBegin: not junction");
	require(q->jtype == aLoopBegin,	"genLoopBegin: not loop block");
	require(q->p2!=NULL,			"genLoopBegin: invalid Loop Graph");

    OutLineInfo(output,q->line,FileStr[q->file]);

	BLOCK_Preamble(q);
	BlkLevel++;
    BlockPreambleOption(q,q->pFirstSetSymbol);       /* MR21 */
	f = First(q, 1, aLoopBegin, &max_k);
	/* If not simple LL(1), must specify to start at LoopBegin, not LoopBlk */
	if ( LL_k>1 && !set_nil(q->fset[2]) )
		genLoopBlk( q, (Junction *)q->p1, q, max_k );
	else genLoopBlk( q, (Junction *)q->p1, NULL, max_k );

	for (i=1; i<=CLL_k; i++) set_free(q->fset[i]);
	for (i=1; i<=CLL_k; i++) set_free(((Junction *)q->p2)->fset[i]);
	--BlkLevel;
	BLOCK_Tail();
	set_free(f);
	tokensRefdInBlock = savetkref;
/* MR21 */	if (MR_BlkErr) {
/* MR21 */		set f, fArray[2];
/* MR21 */		f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ );
/* MR21 */      fArray[0]= empty;
/* MR21 */		fArray[1]= set_dup(f);
/* MR21 */      gen("if (");
/* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
/* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
/* MR21 */      tabs++;
/* MR21 */      tab();
/* MR21 */      _gen("/* nothing */ }\n");
/* MR21 */      tab();
/* MR21 */      makeErrorClause(q,f,1,0 /* use plus block bypass ? */ );  /* frees set */
/* MR21 */      tabs--;
/* MR21 */	};
	if (q->end->p1 != NULL) TRANS(q->end->p1);
}

/*
 * Generate code for a loop blk of form:
 *
 * 					 |---|
 *					 v   |
 *			       --o-G-o-->o--
 *
 * q->end points to the last node (far right) in the blk.
 * Note that q->end->jtype must be 'EndBlk'.
 *
 * Generate code roughly of the following form:
 *
 *	do {
 *		... code for alternatives ...
 *  } while ( First Set of aPlusBlk );
 *
 *	OR if > 1 alternative
 *
 *	do {
 *		... code for alternatives ...
 *		else if not 1st time through, break;
 *  } while ( 1 );
 */
void
#ifdef __USE_PROTOS
genPlusBlk( Junction *q )
#else
genPlusBlk( q )
Junction *q;
#endif
{
	int         max_k;
	set         f;
	int         need_right_curly;
	int			lastAltEmpty;	/* MR23 */
	set         savetkref;
    Junction    *guessBlock;    /* MR10 */
    int         singleAlt;      /* MR10 */

	savetkref = tokensRefdInBlock;
	require(q!=NULL,				"genPlusBlk: invalid node and/or rule");
	require(q->ntype == nJunction,	"genPlusBlk: not junction");
	require(q->jtype == aPlusBlk,	"genPlusBlk: not Plus block");
	require(q->p2 != NULL,			"genPlusBlk: not a valid Plus block");

	if ( q->visited ) return;
	q->visited = TRUE;
    OutLineInfo(output,q->line,FileStr[q->file]);
	BLOCK_Preamble(q);
	BlkLevel++;

    BlockPreambleOption((Junction *)q, q->pFirstSetSymbol);       /* MR21 */
    
    /* first_item_is_guess_block  doesn't care what kind of node it is */

    guessBlock=first_item_is_guess_block( (Junction *)q->p1);   /* MR10 */

	/* if the ignore flag is set on the 2nd alt and that alt is empty,
	 * then it is the implied optional alternative that we added for (...)+
	 * and, hence, only 1 alt.
	 */

/* MR10  Reported by Pulkkinen Esa (esap@cs.tut.fi)
 *       Outer code for guess blocks ignored when there is only one alt
 *         for a (...)+ block.
 *       Force use of regular code rather than "optimized" code for that case
 */

    singleAlt=( ( (Junction *) q->p2)->p2 == NULL) &&
        	  ( ( (Junction *) q->p2)->ignore );			/* only one alternative? */

    if (singleAlt && !guessBlock)   /* MR10 */
	{

		Predicate *a=NULL;
		/* if the only alt has a semantic predicate, hoist it; must test before
		 * entering loop.
		 */
		if ( ParseWithPredicates )
		{
            require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
			a = MR_find_predicates_and_supp((Node *)q);
            require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");

			if ( a!=NULL ) {
				gen("if (");
				a=genPredTreeMain(a, (Node *)q);    /* MR10 */
				_gen(") {\n");
			}
		}
		gen("do {\n");
		tabs++;
		TRANS(q->p1);
		if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
		f = First(q, 1, aPlusBlk, &max_k);
		if ( DemandLookahead ) {
			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
			else gen1("look(%d);\n", max_k);
		}
		--tabs;
		gen("} while ( ");
		if ( q->parm!=NULL && q->predparm ) _gen1("(%s) && ", q->parm);
		genExpr(q);
		if ( ParseWithPredicates && a!=NULL )
		{
            if (! MR_comparePredicates(q->predicate,a)) {
    			_gen("&&");
    			a=genPredTreeMain(a, (Node *)q);    /* MR10 */
            };
		}
		_gen(" );\n");
		if ( ParseWithPredicates && a!=NULL ) gen("}\n");
		--BlkLevel;
		BLOCK_Tail();
		q->visited = FALSE;
		freeBlkFsets(q);
		set_free(f);
		tokensRefdInBlock = savetkref;
/* MR21 */	if (MR_BlkErr) {
/* MR21 */		set f, fArray[2];
/* MR21 */		f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ );
/* MR21 */      fArray[0]= empty;
/* MR21 */		fArray[1]= set_dup(f);
/* MR21 */      gen("if (");
/* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
/* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
/* MR21 */      tabs++;
/* MR21 */      tab();
/* MR21 */      _gen("/* nothing */ }\n");
/* MR21 */      tab();
/* MR21 */      makeErrorClause(q,f,1,1 /* use plus block bypass ? */ );  /* frees set */
/* MR21 */      tabs--;
/* MR21 */	};
		if (q->end->p1 != NULL) TRANS(q->end->p1);
/* MR10 */  if (MRhoisting) {
/* MR10 */    predicate_free(a);
/* MR10 */  };
		return;
	}
	gen("do {\n");
	tabs++;
	f = genBlk(q, aPlusBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
/* MR6              									        */
/* MR6	Sinan Karasu	(sinan@tardis.ds.boeing.com)			*/
/* MR6    Failed to turn off guess mode when leaving block		*/
/* MR6				                           					*/
/* MR6  */ if ( has_guess_block_as_last_item(q) ) {
/* MR10 */   gen("/* MR10 ()+ */ else {\n");
/* MR10 */   tabs++;
/* MR10 */   need_right_curly++;
/* MR10 */   gen("/* MR10 ()+ */ if ( !zzrv ) zzGUESS_DONE;\n");
/* MR6  */   gen("/* MR10 ()+ */ if ( zzcnt > 1 ) break;\n");
/* MR10 */ } else {
/* MR10 */   gen("/* MR10 ()+ */ else {\n");
/* MR10 */   tabs++;
/* MR10 */   need_right_curly++;
/* MR10 */   gen("if ( zzcnt > 1 ) break;\n");
/* MR10 */ };

/* MR21 */	if (MR_BlkErr && 1 >= max_k) {
/* MR21 */		set f;
/* MR21 */		f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ );
/* MR21 */      tabs++;
/* MR21 */      tab();
/* MR21 */      makeErrorClause(q,f,1,0 /* use plus block bypass ? */ );  /* frees set */
/* MR21 */      tabs--;
/* MR21 */	}
/* MR21 */  else {
				tab();
                makeErrorClause(q,f,max_k,1 /* use plus block bypass ? */);
										    /* MR21 I think this generates the wrong set ? */
                                            /* MR21 because it includes the plus block bypass ? */
										    /* MR21 but I'm afraid to change it without additional checking */
            }

	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
	freeBlkFsets(q);
	gen("zzcnt++;");
	if ( !GenCC ) _gen1(" zzLOOP(zztasp%d);", BlkLevel-1);
	_gen("\n");
	if ( DemandLookahead ) {
		if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
		else gen1("look(%d);\n", max_k);
	}
	--tabs;
	if ( q->parm!=NULL && q->predparm ) {gen1("} while (%s);\n", q->parm);}
	else gen("} while ( 1 );\n");
	--BlkLevel;
	BLOCK_Tail();
	q->visited = FALSE;
	tokensRefdInBlock = savetkref;
/* MR21 */	if (MR_BlkErr) {
/* MR21 */		set f, fArray[2];
/* MR21 */		f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ );
/* MR21 */      fArray[0]= empty;
/* MR21 */		fArray[1]= set_dup(f);
/* MR21 */      gen("if (");
/* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
/* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
/* MR21 */      tabs++;
/* MR21 */      tab();
/* MR21 */      _gen("/* nothing */ }\n");
/* MR21 */      tab();
/* MR21 */      makeErrorClause(q,f,1,1 /* use plus block bypass ? */ );  /* frees set */
/* MR21 */      tabs--;
/* MR21 */	};
	if (q->end->p1 != NULL) TRANS(q->end->p1);
}

/*
 * Generate code for a sub blk of alternatives of form:
 *
 *			       --o-G1--o--
 *					 |     ^
 *					 v    /|
 *			         o-G2-o|
 *					 |     ^
 *					 v     |
 *				   ..........
 *					 |     ^
 *					 v    /
 *			         o-Gn-o
 *
 * q points to the 1st junction of blk (upper-left).
 * q->end points to the last node (far right) in the blk.
 * Note that q->end->jtype must be 'EndBlk'.
 * The last node in every alt points to q->end.
 *
 * Generate code of the following form:
 *	if ( First(G1) ) {
 *		...code for G1...
 *	}
 *	else if ( First(G2) ) {
 *		...code for G2...
 *	}
 *	...
 *	else {
 *		...code for Gn...
 *	}
 */

void
#ifdef __USE_PROTOS
genSubBlk( Junction *q )
#else
genSubBlk( q )
Junction *q;
#endif
{
	int max_k;
	set f;
	int need_right_curly;
	int lastAltEmpty;		/* MR23 */
	set savetkref;
	savetkref = tokensRefdInBlock;
	require(q->ntype == nJunction,	"genSubBlk: not junction");
	require(q->jtype == aSubBlk,	"genSubBlk: not subblock");

    OutLineInfo(output,q->line,FileStr[q->file]);
	BLOCK_Preamble(q);
	BlkLevel++;
    BlockPreambleOption(q,q->pFirstSetSymbol);       /* MR21 */
	f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);

/* MR23
   Bypass error clause generation when exceptions are used in a sub block
   in which the last alternative is epsilon.  Example: "(A | B | )". 
   See multi-line note in genBlk near call to isEmptyAlt.
*/
	if (FoundException && lastAltEmpty) {
		gen("/* MR23 skip error clause for (...| epsilon) when exceptions in use */\n");
	}
	else {
		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
	}
    
	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
	freeBlkFsets(q);
	--BlkLevel;
	BLOCK_Tail();

	if ( q->guess )
	{
		gen("zzGUESS_DONE\n");
	}

	/* must duplicate if (alpha)?; one guesses (validates), the
	 * second pass matches */
	if ( q->guess && analysis_point(q)==q )
	{
        OutLineInfo(output,q->line,FileStr[q->file]);
		BLOCK_Preamble(q);
		BlkLevel++;
		f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */);}
		{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
		freeBlkFsets(q);
		--BlkLevel;
		BLOCK_Tail();
	}

	tokensRefdInBlock = savetkref;
	if (q->end->p1 != NULL) TRANS(q->end->p1);
}

static int TnodesAllocatedPrevRule=0;

/*
 * Generate code for a rule.
 *
 *		rule--> o-->o-Alternatives-o-->o
 * Or,
 *		rule--> o-->o-Alternative-o-->o
 *
 * The 1st junction is a RuleBlk.  The second can be a SubBlk or just a junction
 * (one alternative--no block), the last is EndRule.
 * The second to last is EndBlk if more than one alternative exists in the rule.
 *
 * To get to the init-action for a rule, we must bypass the RuleBlk,
 * and possible SubBlk.
 * Mark any init-action as generated so genBlk() does not regenerate it.
 */
void
#ifdef __USE_PROTOS
genRule( Junction *q )
#else
genRule( q )
Junction *q;
#endif
{

	const char * returnValueInitializer;

do {    /* MR10     Change recursion into iteration         */

	int max_k;
	set follow, rk, f;
	ActionNode *a;
	RuleEntry *r;
	int lastAltEmpty;		/* MR23 */
	static int file = -1;
	int need_right_curly;
	require(q->ntype == nJunction,	"genRule: not junction");
	require(q->jtype == RuleBlk,	"genRule: not rule");

/* MR14 */    require (MR_BackTraceStack.count == 0,"-alpha MR_BackTraceStack.count != 0");
/* MR14 */    MR_pointerStackReset(&MR_BackTraceStack);
/* MR14 */    if (AlphaBetaTrace) MR_MaintainBackTrace=1;

    CurRule=q->rname;                               /* MR11 */

	r = (RuleEntry *) hash_get(Rname, q->rname);
	if ( r == NULL ) warnNoFL("Rule hash table is screwed up beyond belief");
	if ( q->file != file )		/* open new output file if need to */
	{
/* MR6              									*/
/* MR6  Simpler to debug when output goes to stdout rather than a file 	*/
/* MR6				                					*/
/* MR6 */	if (UseStdout) {
/* MR6 */	  output = stdout;
/* MR6 */	} else {
/* MR6 */  	  if ( output != NULL) fclose( output );
/* MR6 */	  output = fopen(OutMetaName(outname(FileStr[q->file])), "w");
/* MR6 */	};
		require(output != NULL, "genRule: can't open output file");

#ifdef SPECIAL_FOPEN
       special_fopen_actions(OutMetaName(outname(FileStr[q->file]))); /* MR1 */
#endif
		if ( file == -1 ) genHdr1(q->file);
		else genHdr(q->file);
		file = q->file;
	}

    if (InfoM) {
      fprintf(stderr,"    rule %s\n",q->rname);
      fflush(output);
    };

#if 0
    if (strcmp(q->rname,"***debug***") == 0) {
      fprintf(stderr,"***debug*** %s reached\n",q->rname);
      MR_break();
    };
#endif

	DumpFuncHeader(q,r);
	tabs++;

	/* MR23 
	   
	   If there is a single return value then it can be initialized in 
	   the declaration using assignment syntax.  If there are multiple
	   return values then antlr creates a struct and initialization takes
	   place element by element for each element of the struct.  For
       multiple elements the initialization is by assignment so we have
       to wait until all declarations are done before emitting that code -
       because of restrictions in C which don't exist in C++.

       In the past (before MR23) the only kind of initialization was
	   the PURIFY macro which was just a memset() of 0.  Now we allow
	   the user to specify an initial value.  PURIFY is still used in C
	   mode because C does not have constructors.  However, PURIFY is
	   not used in C++ mode because it might overwrite information created
	   by elements which have their own ctor.
       
	*/

	if ( q->ret!=NULL )
	{
		if ( hasMultipleOperands(q->ret) )                         /* MR23 */
		{

            /* Emit initialization code later. */

			gen1("struct _rv%d _retv;\n",r->rulenum);
		}
		else
		{
            /* Emit initialization code now. */

			tab();
			DumpType(q->ret, output);
            returnValueInitializer = getInitializer(q->ret);
            if (returnValueInitializer == NULL) {                  /* MR23 */
      			gen(" _retv;\n");                     		    /* MR1 MR3 */
            }                                                      /* MR23 */
            else {                                                 /* MR23 */
                gen1(" _retv = %s;\n", returnValueInitializer);    /* MR23 */
            }                                                      /* MR23 */
		}
	}

    OutLineInfo(output,q->line,FileStr[q->file]);

    if (InfoM) {
      fflush(output);
    };

	gen("zzRULE;\n");
	if ( FoundException )
	{
		gen("int _sva=1;\n");
	}
	if ( GenCC && GenAST )
		gen("ASTBase *_ast = NULL, *_sibling = NULL, *_tail = NULL;\n");
	if ( GenCC ) genTokenPointers(q);
	if ( GenCC&&GenAST ) genASTPointers(q);
	if ( q->el_labels!=NULL ) genElementLabels(q->el_labels);
	if ( FoundException ) gen("int _signal=NoSignal;\n");

	if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel);

/* MR10 */  /* move zzTRACEIN to before init action */

/* MR10 */	if ( TraceGen ) {
/* MR10 */		if ( GenCC ) {gen1("zzTRACEIN(\"%s\");\n", q->rname);}
/* MR10 */		else gen1("zzTRACEIN((ANTLRChar *)\"%s\");\n", q->rname);
/* MR10 */	}

/* MR7      Moved PURIFY() to after all local variables have been declared */
/* MR7      so that the generated code is valid C as well as C++           */
/* MR7        Jan Mikkelsen 10-June-1997                                   */


     /*
       MR23    Do the PURIFY macro only for C mode.
               C++ users should use constructors or initialization expressions.
     */

	if ( q->ret != NULL )                                            /* MR7 */
	{                                                                /* MR7 */
		if (hasMultipleOperands(q->ret)) {                           /* MR23 */
			if (PURIFY == TRUE) {
                gen1("PCCTS_PURIFY(_retv,sizeof(struct _rv%d))\n",r->rulenum); /* MR23 */
            }
        }                                                            /* MR7 */
		else {                                                       /* MR7 */

			/* MR23
			   If there were only one return value operand and
			   it had an initializer then it would have been
			   initialized in the declaration.
			*/

			returnValueInitializer = getInitializer(q->ret);         /* MR23 */
			if (returnValueInitializer == NULL) {                    /* MR23 */
    			if (PURIFY == TRUE) {
        			gen("PCCTS_PURIFY(_retv,sizeof(");               /* MR23 */
	    			DumpType(q->ret, output);                        /* MR7 */
					gen("))\n");                                     /* MR7 */
				}
			}                                                        /* MR23 */
		}                                                            /* MR7 */

        if (hasMultipleOperands(q->ret)) {                           /* MR23 */
          DumpInitializers(output, r, q->ret);                       /* MR23 */
        }

	}
	if ( !GenCC ) gen("zzMake0;\n");
	if ( FoundException ) gen("*_retsignal = NoSignal;\n");

	if ( !GenCC ) gen("{\n");

	if ( has_guess_block_as_first_item((Junction *)q->p1) )
	{
		gen("zzGUESS_BLOCK\n");
	}

	/* L o o k  F o r  I n i t  A c t i o n */
	if ( ((Junction *)q->p1)->jtype == aSubBlk )
		a = findImmedAction( ((Junction *)q->p1)->p1 );
	else
		a = findImmedAction( q->p1 );	/* only one alternative in rule */
	if ( a!=NULL && !a->is_predicate)
	{
 /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1);
  		    a->done = 1;	/* ignore action. We have already handled it */
	}

	BlkLevel++;
	q->visited = TRUE;				/* mark RULE as visited for FIRST/FOLLOW */
    BlockPreambleOption((Junction *)q->p1, NULL);   /* MR21 */
	f = genBlk((Junction *)q->p1, RuleBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
	if ( q->p1 != NULL )
		if ( ((Junction *)q->p1)->p2 != NULL )
			{tab(); makeErrorClause((Junction *)q->p1,f,max_k,0 /* use plus block bypass ? */);}
	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
	freeBlkFsets((Junction *)q->p1);
	q->visited = FALSE;
	--BlkLevel;
	if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel);

    genTraceOut(q);

	if ( q->ret!=NULL ) gen("return _retv;\n") else gen("return;\n");
	/* E r r o r  R e c o v e r y */
	NewSet();
	rk = empty;

/* MR14 */    if (r->dontComputeErrorSet) {
/* MR14 */      follow=empty;
              } else {
                MR_pointerStackReset(&MR_BackTraceStack);   /* MR14 */
                MR_ErrorSetComputationActive=1;
                REACH(q->end, 1, &rk, follow);
                MR_ErrorSetComputationActive=0;
                require (MR_BackTraceStack.count == 0,"K: MR_BackTraceStack.count != 0");
              }

  FillSet( follow );
	set_free( follow );

  /* MR20 G. Hobbelt 
     Isn't it so that "fail:" is ONLY referenced when:

      	 !FoundException || FoundGuessBlk ?

     Therefore add the "if" around this piece of code generation...

     Should guessing mode also use _handler label instead of "fail"
     when exception handling is active? gen can automatically put 
     "if (guessing)" there so as to skip all kinds of user code.

   */

	if ( !FoundException || FoundGuessBlk )  /* MR20 G. Hobbelt */
  {                                          /* MR20 G. Hobbelt */
	_gen("fail:\n");
	if ( !GenCC ) gen("zzEXIT(zztasp1);\n");
	if ( FoundGuessBlk ) {
	   	if ( !GenCC ) {gen("if ( zzguessing ) zzGUESS_FAIL;\n");}
		else gen("if ( guessing ) zzGUESS_FAIL;\n");
	}
	if ( q->erraction!=NULL )
		dumpAction(q->erraction, output, tabs, q->file, q->line, 1);
	if ( GenCC )
	{
		gen1("syn(zzBadTok, %s, zzMissSet, zzMissTok, zzErrk);\n",
			 r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup);
	}
	else
	{
		gen1("zzsyn(zzMissText, zzBadTok, %s, zzMissSet, zzMissTok, zzErrk, zzBadText);\n",
			 r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup);
	}
	gen3("%sresynch(setwd%d, 0x%x);\n", GenCC?"":"zz", wordnum, 1<<setnum);

	if ( q->ret!=NULL ) {
      genTraceOut(q);
      gen("return _retv;\n");
    } else if ( q->exceptions!=NULL ) {
      genTraceOut(q);
      gen("return;\n");
    } else if (!FoundException) {       /* MR10 */
      genTraceOut(q);                   /* MR10 */
    };

  }                                        /* MR20 G. Hobbelt */

	if ( !GenCC ) gen("}\n");

	/* Gen code for exception handlers */
    /* make sure each path out contains genTraceOut() */

	if ( q->exceptions!=NULL )
	{

		gen("/* exception handlers */\n");

		dumpExceptions(q->exceptions);

        if ( !r->has_rule_exception )
        {
            _gen("_handler:\n");
            gen("zzdflthandlers(_signal,_retsignal);\n");
        }
/*  MR20 G. Gobbelt   The label "adios" is never referenced */

#if 0
	_gen("_adios:\n");
#endif
    if ( q->ret!=NULL ) {
            genTraceOut(q);
            gen("return _retv;\n");
        }
		else {
            genTraceOut(q);
            gen("return;\n");
        }
	}
	else if ( FoundException )
	{
      _gen("_handler:\n");
      gen("zzdflthandlers(_signal,_retsignal);\n");

/* MR1                                                                      */
/* MR1	 7-Apr-97 Fix suggested by: John Bair (jbair@iftime.com)            */
/* MR1							                                            */

   	  if ( q->ret != NULL) {			                             /* MR1 */
            genTraceOut(q);                                          /* MR10 */
            gen("return _retv;\n");			                         /* MR1 */
      } else {					                                     /* MR1 */
            genTraceOut(q);                                          /* MR10 */
            gen("return;\n")    ;				                     /* MR1 */
      };						                                     /* MR1 */
	}

	tabs--;
	gen("}\n");

/* MR10     Tired of looking at stacks that are as deep as the number of    */
/* MR10       rules.  Changes recursion to iteration.                       */

    MR_releaseResourcesUsedInRule( (Node *) q );      /* MR10 */

    if (InfoT) {
      fprintf(output,"\n/* tnodes created for rule %s:  %d */\n",
                q->rname, (TnodesAllocated-TnodesAllocatedPrevRule) );
    };

    TnodesAllocatedPrevRule=TnodesAllocated;

    if (q->p2 == NULL) dumpAfterActions( output );
    q=(Junction *)q->p2;
    require(q==NULL || q->jtype==RuleBlk,"RuleBlk p2 does not point to another RuleBlk");

} while (q != NULL);

/**** The old code                           ****/
/****	if ( q->p2 != NULL ) {TRANS(q->p2);} ****/ /* generate code for next rule too */
/****	else dumpAfterActions( output );     ****/

}


/* This is for the function definition, not the declaration. */

static void
#ifdef __USE_PROTOS
DumpFuncHeader( Junction *q, RuleEntry *r )
#else
DumpFuncHeader( q, r )
Junction *q;
RuleEntry *r;
#endif
{
/*								                                            */
/*  MR1 10-Apr-97  MR1  Simplify insertion of commas in function header     */
/*								                                            */
	int	needComma;					                                 /* MR1 */


	/* A N S I */
	_gen("\n");
	if ( q->ret!=NULL )
	{
		if ( hasMultipleOperands(q->ret) )                            /* MR23 */
		{
			if (GenCC) gen2("%s::_rv%d\n", CurrentClassName, r->rulenum)
			else gen1("struct _rv%d\n",r->rulenum);
		}
		else
		{
			DumpType(q->ret, output);
			gen("\n");
		}
	}
	else
	{
		_gen("void\n");
	}
/*  MR1			                                                            */
/*  MR1	10-Apr-97  133MR1	Replace __STDC__ with __USE_PROTOS              */
/*  MR1								                                        */
	if ( !GenCC ) _gen("#ifdef __USE_PROTOS\n");		     /* MR1 */
	if ( !GenCC ) gen2("%s%s(", RulePrefix, q->rname)
	else gen3("%s::%s%s(", CurrentClassName, RulePrefix,q->rname);

    	/* If we generate C++ method names, we must hide default arguments */
        /* which can appear in the parameter declaration list.             */
        /* NOTICE: this is done only here, for the method definition, but  */
        /*         not for the method declaration inside the class         */
        /*         definition. This is exactly the behaviour defined in    */
        /*         C++ standard for default parameters.                    */

	DumpANSIFunctionArgDef(output,q, 0 /* emit initializers ? */);
	_gen("\n");

	if ( GenCC ) {
      gen("{\n");
      return;
    }

	/* K & R */
	gen("#else\n");
	gen2("%s%s(", RulePrefix, q->rname);
	needComma=0;						                             /* MR1 */
	if ( GenAST )						                             /* MR1 */
	{							                                     /* MR1 */
		_gen("_root");					                             /* MR1 */
		needComma=1;					                             /* MR1 */
	}							                                     /* MR1 */
	if ( FoundException )					                         /* MR1 */
	{							                                     /* MR1 */
		if (needComma) {_gen(",");needComma=0;};	                 /* MR1 */
		_gen("_retsignal");				                             /* MR1 */
		needComma=1;					                             /* MR1 */
	}							                                     /* MR1 */
/* MR5	Change below by Jan Mikkelsen (janm@zeta.org.au) 26-May-97      MR5 */
	DumpListOfParmNames( q->pdecl, output, needComma );	             /* MR5 */
	gen(")\n");
	if ( GenAST ) gen("AST **_root;\n");
	if ( FoundException ) gen("int *_retsignal;\n");
	DumpOldStyleParms( q->pdecl, output );
	gen("#endif\n");
    gen("{\n");
}

void
#ifdef __USE_PROTOS
DumpANSIFunctionArgDef(FILE *f, Junction *q, int bInitializer)
#else
DumpANSIFunctionArgDef(f,q,bInitializer)
FILE *f;
Junction *q;
int bInitializer;
#endif
{
	if ( GenAST )
	{
		if ( GenCC ) {fprintf(f,"ASTBase **_root");}
		else fprintf(f,"AST**_root");
		if ( !FoundException && q->pdecl!=NULL ) fprintf(f,",");
	}
	if ( FoundException )
	{
		if ( GenAST ) fprintf(f,",");
		fprintf(f,"int *_retsignal");
		if ( q->pdecl!=NULL ) {
            fprintf(f,",");
        }
	}
	if ( q->pdecl!=NULL ) {
        DumpFormals(f, q->pdecl, bInitializer);     /* MR23 */
    }
	else {
        if ( !GenAST && !FoundException ) {
            fprintf(f,"void");
        }
    }
	fprintf(f,")");
}

void
#ifdef __USE_PROTOS
genJunction( Junction *q )
#else
genJunction( q )
Junction *q;
#endif
{
	require(q->ntype == nJunction,	"genJunction: not junction");
	require(q->jtype == Generic,	"genJunction: not generic junction");

	if ( q->p1 != NULL ) TRANS(q->p1);
	if ( q->p2 != NULL ) TRANS(q->p2);
}

void
#ifdef __USE_PROTOS
genEndBlk( Junction *q )
#else
genEndBlk( q )
Junction *q;
#endif
{
}

void
#ifdef __USE_PROTOS
genEndRule( Junction *q )
#else
genEndRule( q )
Junction *q;
#endif
{
}

void
#ifdef __USE_PROTOS
genHdr( int file )
#else
genHdr( file )
int file;
#endif
{
    int     i;

	_gen("/*\n");
	_gen(" * A n t l r  T r a n s l a t i o n  H e a d e r\n");
	_gen(" *\n");
	_gen(" * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
	_gen(" * Purdue University Electrical Engineering\n");
	_gen(" * With AHPCRC, University of Minnesota\n");
	_gen1(" * ANTLR Version %s\n", Version);
	_gen(" *\n");
/* MR10 */    _gen(" *  ");
/* MR10 */    for (i=0 ; i < Save_argc ; i++) {
/* MR10 */      _gen(" ");
/* MR10 */      _gen1("%s", Save_argv[i]);
/* MR10 */    };
	_gen("\n");
	_gen(" *\n");
    _gen(" */\n\n");
	if (FirstAction != NULL ) dumpAction( FirstAction, output, 0, -1, 0, 1);    /* MR11 MR15b */
	_gen1("#define ANTLR_VERSION	%s\n", VersionDef);
	_gen("#include \"pcctscfg.h\"\n");
	_gen("#include \"pccts_stdio.h\"\n");
	if ( strcmp(ParserName, DefaultParserName)!=0 )
		_gen2("#define %s %s\n", DefaultParserName, ParserName);
   	if ( strcmp(ParserName, DefaultParserName)!=0 )
		{_gen1("#include \"%s\"\n", RemapFileName);}
    OutLineInfo(output,1,FileStr[file]);
	if ( GenCC ) {
		if ( UserTokenDefsFile != NULL )
			fprintf(output, "#include %s\n", UserTokenDefsFile);
		else
			fprintf(output, "#include \"%s\"\n", DefFileName);
	}

	if ( HdrAction != NULL ) dumpAction( HdrAction, output, 0, -1, 0, 1);
	if ( !GenCC && FoundGuessBlk )
	{
		_gen("#define ZZCAN_GUESS\n");
		_gen("#include \"pccts_setjmp.h\"\n");  /* MR15 K.J. Cummings (cummings@peritus.com) */
	}
	if ( FoundException )
	{
		_gen("#define EXCEPTION_HANDLING\n");
		_gen1("#define NUM_SIGNALS %d\n", NumSignals);
	}
	if ( !GenCC && OutputLL_k > 1 ) _gen1("#define LL_K %d\n", OutputLL_k);
	if ( GenAST&&!GenCC ) _gen("#define GENAST\n\n");
	if ( GenAST ) {
		if ( GenCC ) {_gen1("#include \"%s\"\n\n", ASTBASE_H);}
		else _gen("#include \"ast.h\"\n\n");
	}
	if ( !GenCC && DemandLookahead ) _gen("#define DEMAND_LOOK\n\n");
#ifdef DUM
	if ( !GenCC && LexGen ) {
		_gen1("#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken));
	}
#endif
	/* ###WARNING: This will have to change when SetWordSize changes */
	if ( !GenCC ) _gen1("#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned));
    if (TraceGen) {
      _gen("#ifndef zzTRACE_RULES\n");  /* MR20 */
      _gen("#define zzTRACE_RULES\n");  /* MR20 */
      _gen("#endif\n");                 /* MR22 */
    };
	if ( !GenCC ) {_gen("#include \"antlr.h\"\n");}
	else {
		_gen1("#include \"%s\"\n", APARSER_H);
		_gen1("#include \"%s.h\"\n", CurrentClassName);
	}
	if ( !GenCC ) {
		if ( UserDefdTokens )
			{_gen1("#include %s\n", UserTokenDefsFile);}
		/* still need this one as it has the func prototypes */
		_gen1("#include \"%s\"\n", DefFileName);
	}
	/* still need this one as it defines the DLG interface */
	if ( !GenCC ) _gen("#include \"dlgdef.h\"\n");
	if ( LexGen && GenCC ) _gen1("#include \"%s\"\n", DLEXERBASE_H);
	if ( GenCC ) _gen1("#include \"%s\"\n", ATOKPTR_H);
	if ( !GenCC && LexGen ) _gen1("#include \"%s\"\n", ModeFileName);

/* MR10  Ofer Ben-Ami (gremlin@cs.huji.ac.il)           */
/* MR10    Finally, a definition of the Purify macro    */

    if (PURIFY == TRUE) {                                                   /* MR23 */
        _gen("\n/* MR23 In order to remove calls to PURIFY use the antlr"); /* MR23 */
        _gen(" -nopurify option */\n\n");                                   /* MR23 */
    	_gen("#ifndef PCCTS_PURIFY\n");
        _gen("#define PCCTS_PURIFY(r,s) memset((char *) &(r),'\\0',(s));\n");
        _gen("#endif\n\n");
    }                                                                       /* MR23 */
}

void
#ifdef __USE_PROTOS
genHdr1( int file )
#else
genHdr1( file )
int file;
#endif
{
	ListNode *p;

	genHdr(file);
	if ( GenAST )
	{
		if ( !GenCC ) {
			_gen("#include \"ast.c\"\n");
			_gen("zzASTgvars\n\n");
		}
	}
	if ( !GenCC ) _gen("ANTLR_INFO\n");
	if ( BeforeActions != NULL )
	{
		for (p = BeforeActions->next; p!=NULL; p=p->next)
		{
			UserAction *ua = (UserAction *)p->elem;
			dumpAction( ua->action, output, 0, ua->file, ua->line, 1);
		}
	}

	if ( !FoundException ) return;

	if ( GenCC )
	{
		_gen1("\nvoid %s::\n", CurrentClassName);
		_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
		_gen("{\n");
	}
	else
	{
		_gen("\nvoid\n");
/*  MR1				                                                        */
/*  MR1	10-Apr-97  133MR1	Replace __STDC__ with __USE_PROTOS              */
/*  MR1	                                                                    */
	    _gen("#ifdef __USE_PROTOS\n");                               /* MR1 */
		_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
		_gen("#else\n");
		_gen("zzdflthandlers( _signal, _retsignal )\n");
		_gen("int _signal;\n");
		_gen("int *_retsignal;\n");
		_gen("#endif\n");
		_gen("{\n");
	}
	tabs++;
	if ( DefaultExGroup!=NULL )
	{
		dumpException(DefaultExGroup, 1);
		if ( !hasDefaultException(DefaultExGroup) )
		{
			gen("default :\n");
			tabs++;
			gen("*_retsignal = _signal;\n");
			tabs--;
			gen("}\n");
		}
	}
	else {
		gen("*_retsignal = _signal;\n");
	}

	tabs--;
	_gen("}\n\n");
}

void
#ifdef __USE_PROTOS
genStdPCCTSIncludeFile( FILE *f,char *gate )    /* MR10 */
#else
genStdPCCTSIncludeFile( f , gate)               /* MR10 */
FILE *f;
char * gate;                                    /* MR10 */
#endif
{
/* MR10 Ramanathan Santhanam (ps@kumaran.com)           */
/* MR10 Same preprocessor symbol use to gate stdpccts.h */
/* MR10   even when two grammars are in use.            */
/* MR10 Derive gate symbol from -fh filename            */

    if (gate == NULL) {
      fprintf(f,"#ifndef STDPCCTS_H\n");          /* MR10 */
      fprintf(f,"#define STDPCCTS_H\n");          /* MR10 */
    } else {
      fprintf(f,"#ifndef STDPCCTS_%s_H\n",gate);  /* MR10 */
      fprintf(f,"#define STDPCCTS_%s_H\n",gate);  /* MR10 */
    };
	fprintf(f,"/*\n");
    if (gate == NULL) {
	  fprintf(f," * %s -- P C C T S  I n c l u d e\n", stdpccts);
    } else {
	  fprintf(f," * Standard PCCTS include file with -fh %s -- P C C T S  I n c l u d e\n", stdpccts);
    }
	fprintf(f," *\n");
	fprintf(f," * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
	fprintf(f," * Purdue University Electrical Engineering\n");
	fprintf(f," * With AHPCRC, University of Minnesota\n");
	fprintf(f," * ANTLR Version %s\n", Version);
	fprintf(f," */\n\n");

    fprintf(f,"#ifndef ANTLR_VERSION\n");
	fprintf(f,"#define ANTLR_VERSION	%s\n", VersionDef);
    fprintf(f,"#endif\n\n");

    if (FirstAction != NULL ) dumpAction(FirstAction, f, 0, -1, 0, 1);  /* MR11 */

	fprintf(f,"#include \"pcctscfg.h\"\n");
	fprintf(f,"#include \"pccts_stdio.h\"\n");
	if ( GenCC )
	{
		if ( UserDefdTokens )
			fprintf(f, "#include %s\n", UserTokenDefsFile);
		else {
			fprintf(f, "#include \"%s\"\n", DefFileName);
		}

		fprintf(f, "#include \"%s\"\n", ATOKEN_H);

		if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1);

		fprintf(f, "#include \"%s\"\n", ATOKENBUFFER_H);

		if ( OutputLL_k > 1 ) fprintf(f,"static const unsigned LL_K=%d;\n", OutputLL_k);
		if ( GenAST ) {
			fprintf(f, "#include \"%s\"\n", ASTBASE_H);
		}

        if (TraceGen) {
          fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
          fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
          fprintf(f,"#endif\n");                 /* MR22 */
        };

		fprintf(f,"#include \"%s\"\n", APARSER_H);
		fprintf(f,"#include \"%s.h\"\n", CurrentClassName);
		if ( LexGen ) fprintf(f,"#include \"%s\"\n", DLEXERBASE_H);
		fprintf(f, "#endif\n");
		return;
	}

	if ( strcmp(ParserName, DefaultParserName)!=0 )
		fprintf(f, "#define %s %s\n", DefaultParserName, ParserName);
	if ( strcmp(ParserName, DefaultParserName)!=0 )
		fprintf(f, "#include \"%s\"\n", RemapFileName);
	if ( UserTokenDefsFile != NULL )
	   fprintf(f, "#include %s\n", UserTokenDefsFile);
	if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1);
	if ( FoundGuessBlk )
	{
		fprintf(f,"#define ZZCAN_GUESS\n");
		fprintf(f,"#include \"pccts_setjmp.h\"\n");
	}
    if (TraceGen) {
      fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
      fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
      fprintf(f,"#endif\n");                 /* MR22 */
    };
	if ( OutputLL_k > 1 ) fprintf(f,"#define LL_K %d\n", OutputLL_k);
	if ( GenAST ) fprintf(f,"#define GENAST\n");
	if ( FoundException )
	{
/* MR1	 7-Apr-97  1.33MR1					                           */
/* MR1	 	   Fix suggested by:				                   */
/* MR1		   Francois-Xavier Fontaine (fontaine_f@istvax.ist.lu)         */

		fprintf(f,"#define EXCEPTION_HANDLING\n");	            /* MR1 */
		fprintf(f,"#define NUM_SIGNALS %d\n", NumSignals);          /* MR1 */
	}
	if ( DemandLookahead ) fprintf(f,"#define DEMAND_LOOK\n");
#ifdef DUM
	if ( LexGen ) fprintf(f, "#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken));
#endif
	/* ###WARNING: This will have to change when SetWordSize changes */
	fprintf(f, "#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned));
    if (TraceGen) {
      fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
      fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
      fprintf(f,"#endif\n");                 /* MR22 */
    };
	fprintf(f,"#include \"antlr.h\"\n");
	if ( GenAST ) fprintf(f,"#include \"ast.h\"\n");
	if ( UserDefdTokens )
		fprintf(f, "#include %s\n", UserTokenDefsFile);
	/* still need this one as it has the func prototypes */
	fprintf(f, "#include \"%s\"\n", DefFileName);
	/* still need this one as it defines the DLG interface */
	fprintf(f,"#include \"dlgdef.h\"\n");
	/* don't need this one unless DLG is used */
	if ( LexGen ) fprintf(f,"#include \"%s\"\n", ModeFileName);
	fprintf(f,"#endif\n");
}

/* dump action 's' to file 'output' starting at "local" tab 'tabs'
   Dump line information in front of action if GenLineInfo is set
   If file == -1 then GenLineInfo is ignored.
   The user may redefine the LineInfoFormatStr to his/her liking
   most compilers will like the default, however.

   June '93; changed so that empty lines are left alone so that
   line information is correct for the compiler/debuggers.
*/
void
#ifdef __USE_PROTOS
dumpAction( char *s, FILE *output, int tabs, int file, int line,
int final_newline )
#else
dumpAction( s, output, tabs, file, line, final_newline )
char *s;
FILE *output;
int tabs;
int file;
int line;
int final_newline;
#endif
{
    int inDQuote, inSQuote;
    require(s!=NULL, 		"dumpAction: NULL action");
    require(output!=NULL,	eMsg1("dumpAction: output FILE is NULL for %s",s));

	if ( GenLineInfo && file != -1 )
	{
        OutLineInfo(output,line,FileStr[file]);
	}
    PastWhiteSpace( s );
	/* don't print a tab if first non-white char is a # (preprocessor command) */
	if ( *s!='#' ) {TAB;}
    inDQuote = inSQuote = FALSE;
    while ( *s != '\0' )
    {
        if ( *s == '\\' )
        {
            fputc( *s++, output ); /* Avoid '"' Case */
            if ( *s == '\0' ) return;
            if ( *s == '\'' ) fputc( *s++, output );
            if ( *s == '\"' ) fputc( *s++, output );
        }
        if ( *s == '\'' )
        {
            if ( !inDQuote ) inSQuote = !inSQuote;
        }
        if ( *s == '"' )
        {
            if ( !inSQuote ) inDQuote = !inDQuote;
        }
        if ( *s == '\n' )
        {
            fputc('\n', output);
			s++;
            PastWhiteSpace( s );
            if ( *s == '}' )
            {
                --tabs;
				TAB;
                fputc( *s++, output );
                continue;
            }
            if ( *s == '\0' ) return;
			if ( *s != '#' )	/* #define, #endif etc.. start at col 1 */
            {
				TAB;
			}
        }
        if ( *s == '}' && !(inSQuote || inDQuote) )
        {
            --tabs;            /* Indent one fewer */
        }
        if ( *s == '{' && !(inSQuote || inDQuote) )
        {
            tabs++;            /* Indent one more */
        }
        fputc( *s, output );
        s++;
    }
    if ( final_newline ) fputc('\n', output);
}

static void
#ifdef __USE_PROTOS
dumpAfterActions( FILE *output )
#else
dumpAfterActions( output )
FILE *output;
#endif
{
	ListNode *p;
	require(output!=NULL, "dumpAfterActions: output file was NULL for some reason");
	if ( AfterActions != NULL )
	{
		for (p = AfterActions->next; p!=NULL; p=p->next)
		{
			UserAction *ua = (UserAction *)p->elem;
			dumpAction( ua->action, output, 0, ua->file, ua->line, 1);
		}
	}
	fclose( output );
}

/*
 * Find the next action in the stream of execution.  Do not pass
 * junctions with more than one path leaving them.
 * Only pass generic junctions.
 *
 *	Scan forward while (generic junction with p2==NULL)
 *	If we stop on an action, return ptr to the action
 *	else return NULL;
 */
static ActionNode *
#ifdef __USE_PROTOS
findImmedAction( Node *q )
#else
findImmedAction( q )
Node *q;
#endif
{
	Junction *j;
	require(q!=NULL, "findImmedAction: NULL node");
	require(q->ntype>=1 && q->ntype<=NumNodeTypes, "findImmedAction: invalid node");
	
	while ( q->ntype == nJunction )
	{
		j = (Junction *)q;
		if ( j->jtype != Generic || j->p2 != NULL ) return NULL;
		q = j->p1;
		if ( q == NULL ) return NULL;
	}
	if ( q->ntype == nAction ) return (ActionNode *)q;
	return NULL;
}

static void
#ifdef __USE_PROTOS
dumpRetValAssign( char *retval, char *ret_def, RuleRefNode * ruleRef /* MR30 */)
#else
dumpRetValAssign( retval, ret_def, ruleRef /* MR30 */)
char *retval;
char *ret_def;
RuleRefNode *ruleRefNode;
#endif
{
	char *q = ret_def;
	
	tab();
	while ( *retval != '\0' && *q != '\0')
	{
		while ( isspace((*retval)) ) retval++;
		while ( *retval!=',' && *retval!='\0' ) fputc(*retval++, output);
		fprintf(output, " = _trv.");
		
		DumpNextNameInDef(&q, output);
		while ( isspace(*q) ) q++;
		fputc(';', output); fputc(' ', output);
		if ( *retval == ',' ) retval++;
	}
	if (*retval == '\0' && *q != '\0') {
/* MR30 */    errFL("Fewer output values than output formals for rule reference",
/* MR30 */                 FileStr[ruleRef->file],ruleRef->line);
	}
	if (*retval != '\0' && *q == '\0') {
/* MR30 */    errFL("More output actuals than output formals for rule reference",
/* MR30 */                 FileStr[ruleRef->file],ruleRef->line);
	}
}

/* This function computes the set of tokens that can possibly be seen k
 * tokens in the future from point j
 */

static set
#ifdef __USE_PROTOS
ComputeErrorSet( Junction *j, int k, int usePlusBlockBypass)
#else
ComputeErrorSet( j, k, usePlusBlockBypass )
Junction *j;
int k;
int usePlusBlockBypass;
#endif
{
	Junction *alt1;
	set a, rk, f;
	require(j->ntype==nJunction, "ComputeErrorSet: non junction passed");

	f = rk = empty;
	for (alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2)
	{
        if (alt1->ignore && ! usePlusBlockBypass) continue;     /* MR21 - Ignore aPlusBlk forward p2 */
		REACH(alt1->p1, k, &rk, a);
		require(set_nil(rk), "ComputeErrorSet: rk != nil");
		set_free(rk);
		set_orin(&f, a);
		set_free(a);
	}
	return f;
}

static char *
#ifdef __USE_PROTOS
tokenFollowSet(TokNode *p)
#else
tokenFollowSet(p)
TokNode *p;
#endif
{
    static char buf[100];
    set rk, a;
    int n;
    rk = empty;

    REACH(p->next, 1, &rk, a);
    require(set_nil(rk), "rk != nil");
    set_free(rk);
    n = DefErrSet( &a, 0, NULL );
    set_free(a);
    if ( GenCC )
        sprintf(buf, "err%d", n);
    else
        sprintf(buf, "zzerr%d", n);
    return buf;
}

static void
#ifdef __USE_PROTOS
makeErrorClause( Junction *q, set f, int max_k, int usePlusBlockBypass )
#else
makeErrorClause( q, f, max_k, usePlusBlockBypass )
Junction *q;
set f;
int max_k;
int usePlusBlockBypass;
#endif
{
    char *  handler_id="";                                           /* MR7 */
    int     nilf=0;                                                  /* MR13 */
    RuleEntry *ruleEntry;                                            /* MR14 */

	if ( FoundException )
	{
		_gen("else {\n");
		tabs++;
		if ( FoundGuessBlk )
		{
			if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
			else gen("if ( zzguessing ) goto fail;\n");
		}
		gen("if (_sva) _signal=NoViableAlt;\n");
		gen("else _signal=NoSemViableAlt;\n");
        if (q->outerEG != NULL) {
          handler_id=q->outerEG->altID;
#if 0
        } else {
          printf("q->curAltNum=%d q->exception_label=%s\n",q->curAltNum,q->exception_label);
          gen("*** DEBUG *** outerEG==NULL\n");
#endif
        };
		gen1("goto %s_handler;  /* MR7 */\n",handler_id);    /* MR7 */
		tabs--;
		gen("}\n");
		return;
	}

	if ( max_k == 1 )
	{
/* MR13 */  nilf=set_nil(f);
    	  	if ( GenCC ) {
              _gen1("else {FAIL(1,err%d", DefErrSet1(1,&f,1,NULL));
            } else {
               _gen1("else {zzFAIL(1,zzerr%d", DefErrSet1(1,&f,1,NULL));
            };
    		set_free(f);
	}
	else
	{
		int i;
		set_free(f);
		if ( GenCC ) {_gen1("else {FAIL(%d", max_k);}
		else _gen1("else {zzFAIL(%d", max_k);

    ruleEntry = (RuleEntry *) hash_get(Rname,q->rname);

		for (i=1; i<=max_k; i++)
		{
/* MR14 */  if (ruleEntry->dontComputeErrorSet) {
/* MR14 */    f=empty;
            } else {
      	      f = ComputeErrorSet(q, i, usePlusBlockBypass /* use plus block bypass ? */ );
            }

      if ( GenCC ) {_gen1(",err%d", DefErrSet( &f, 1, NULL ));}
			else _gen1(",zzerr%d", DefErrSet( &f, 1, NULL ));
			
			set_free(f);
		}
	}
	_gen(",&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;}\n");
/* MR13 */  if (nilf) {
/* MR13 */    errFL("empty error set for alt - probably because of undefined rule or infinite left recursion",
/* MR13 */                 FileStr[q->file],q->line);
/* MR13 */    gen(" /* MR13 empty error set for this alt - undef rule ? infinite left recursion ? */");
/* MR13 */  };
}

static                                                               /* MR7 */
#ifdef __USE_PROTOS
char * findOuterHandlerLabel(ExceptionGroup *eg)                     /* MR7 */
#else
char * findOuterHandlerLabel(eg)                                     /* MR7 */
ExceptionGroup *eg;                                                  /* MR7 */
#endif
{
  char              *label=NULL;                                     /* MR7 */
  ExceptionGroup    *outerEG;                                        /* MR7 */

  if (eg->forRule == 0) {                                            /* MR7 */
    if (eg->labelEntry != NULL) {                                    /* MR7 */
      outerEG=eg->labelEntry->outerEG;                               /* MR7 */
      if (outerEG != NULL) {                                         /* MR7 */
        label=outerEG->altID;                                        /* MR7 */
        outerEG->used=1;                                             /* MR7 */
      };                                                             /* MR7 */
    } else if (eg->outerEG != NULL) {                                /* MR7 */
      outerEG=eg->outerEG;                                           /* MR7 */
      label=outerEG->altID;                                          /* MR7 */
      outerEG->used=1;                                               /* MR7 */
    };                                                               /* MR7 */
  };                                                                 /* MR7 */
  return (label==NULL ? "" : label);                                 /* MR7 */
}                                                                    /* MR7 */

/*** debug ***/
#if 0
** static                                                               /* MR7 */
** #ifdef __USE_PROTOS
** char * findOuterAltHandlerLabel(Junction *startJ)                    /* MR7 */
** #else
** char * findOuterAltHandlerLabel(startJ)                              /* MR7 */
** Junction *startJ;                                                    /* MR7 */
** #endif
** {                                                                    /* MR7 */
**   char      *label=NULL;                                             /* MR7 */
**   Junction  *alt;                                                    /* MR7 */
**                                                                      /* MR7 */
**   for (alt=startJ; alt != NULL; alt=alt->outerAltstart) {            /* MR7 */
**     label=alt->exception_label;                                      /* MR7 */
**     if (label != NULL) break;                                        /* MR7 */
**   };                                                                 /* MR7 */
**   return (label==NULL ? "" : label);                                 /* MR7 */
** }                                                                    /* MR7 */
#endif

#ifdef __USE_PROTOS
static void OutLineInfo(FILE *file,int line,char *fileName)
#else
static void OutLineInfo(file,line,fileName)
  FILE *    file;
  int       line;
  char *    fileName;
#endif
{
    static  char * prevFileName=NULL;
    static  char * prevFileNameMS=NULL;

    char *  p;
    char *  q;

    if (! GenLineInfo) return;

    if (!GenLineInfoMS) {
	    fprintf(file, LineInfoFormatStr,line,fileName);
    } else {
      if (fileName == prevFileName) {
	    fprintf(file, LineInfoFormatStr,line,prevFileNameMS);
      } else {
        if (prevFileNameMS != NULL) free (prevFileNameMS);
        prevFileNameMS=(char *)calloc(1,strlen(fileName)+1);
        require(prevFileNameMS != NULL,"why not do this in calloc wrapper");
        q=prevFileNameMS;
        for (p=fileName; *p != 0; p++) {
            *q=*p;
            if (*q == '\\') *q='/';
            q++;
        }
      }
      prevFileName=fileName;
    };
}

#if 0

/* MR21 */

#ifdef __USE_PROTOS
void OutFirstSetSymbol(Junction *q, char * pSymbol)
#else
void OutFirstSetSymbol(q, pSymbol)
    Junction* q;
	char * pSymbol
#endif
{

	set f;
    if (pSymbol == NULL) return;
	gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol);
    f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */);
    DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, "");
    set_free(f);
}
#endif

/* MR21 */

#ifdef __USE_PROTOS
void BlockPreambleOption(Junction *q, char * pSymbol)
#else
void BlockPreambleOption(q, pSymbol)
    Junction* q;
	char * pSymbol;
#endif
{
	set f = empty;
    if (pSymbol != NULL) {
        f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */);
    	gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol);
        DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, "");
    }
    set_free(f);
}

/* MR21 */

void
#ifdef __USE_PROTOS
dumpActionPlus(ActionNode *a, char *s, FILE *output, int tabs, int file, int line,
int final_newline )
#else
dumpActionPlus(a, s, output, tabs, file, line, final_newline )
ActionNode *a;
char *s;
FILE *output;
int tabs;
int file;
int line;
int final_newline;
#endif
{
    dumpAction(s,output,tabs,file,line,final_newline);
}


#if 0
** #ifdef __USE_PROTOS
** void MR_ErrorSets(Junction *q, int max_k, int usePlusBlockBypass)
** #else
** void MR_ErrorSets(q, max_k, usePlusBlockBypass)
** Junction *q;
** int max_k;
** int usePlusBlockBypass;
** #endif
** {
**     int k;
**     set setResult;
** 	Junction* alt1;
** 	Junction* p;
** 	set rk;
** 
**     require (max_k <= CLL_k, "k > CLL_k");
** 
** 
**     for (k = 1; k <= CLL_k; k++) {set_clr(q->fset[k]); }
** 
**     for (k = 1; k <= max_k; k++) {
**         for (alt1=q; alt1 != NULL; alt1 = (Junction *)alt1->p2)
**     	{
**             if (alt1->ignore && ! usePlusBlockBypass) continue;
**         	p = analysis_point((Junction *)alt1->p1);
**     		REACH(p, k, &rk, setResult);
**     		require(set_nil(rk), "rk != nil");
**             set_orin(&q->fset[k], setResult);
**     	}
**     }
** }
#endif


#ifdef __USE_PROTOS
void DumpInitializers(FILE* output, RuleEntry *r, char * pReturn)
#else
void DumpInitializers(output, r, pReturn)
FILE* output;
RuleEntry *r;
char * pReturn;
#endif
{
	char *p = pReturn;
	char *pDataType;
	char *pSymbol;
	char *pEqualSign;
	char *pValue;
	char *pSeparator;
	int nest = 0;
    char *q;

	require(pReturn!=NULL, "DumpInitializer: invalid string"); 

    while (*p != 0) {
    	p = endFormal(p,
    			      &pDataType,
    				  &pSymbol,
    				  &pEqualSign,
    				  &pValue,
    				  &pSeparator,
    				  &nest);
        if (nest != 0) return;
        if (pValue != NULL) {
			tab();
            q = strBetween(pSymbol, pEqualSign, pSeparator);
            fprintf(output, "_retv.%s", q);
            q = strBetween(pValue, NULL, pSeparator);
            fprintf(output, " = %s;\n", q);
        }
    }
}

#ifdef __USE_PROTOS
void DumpFormals(FILE* output, char * pReturn, int bInitializer)
#else
void DumpFormals(output, pReturn, bInitializer)
FILE* output;
char * pReturn;
int bInitializer;
#endif
{
	char *p = pReturn;
	char *pDataType;
	char *pSymbol;
	char *pEqualSign;
	char *pValue;
	char *pSeparator;
	int nest = 0;
    char *q;
    int count = 0;

	require(pReturn!=NULL, "DumpFormals: invalid string"); 

    while (*p != 0) {
    	p = endFormal(p,
    			      &pDataType,
    				  &pSymbol,
    				  &pEqualSign,
    				  &pValue,
    				  &pSeparator,
    				  &nest);
        if (nest != 0) return;
        if (count > 0) fprintf(output,",");
        if (pDataType != NULL && pSymbol != NULL) {
            q = strBetween(pDataType, pSymbol, pSeparator);
            fprintf(output, "%s", q);
            q = strBetween(pSymbol, pEqualSign, pSeparator);
            fprintf(output," %s",q);
            if (pValue != NULL) {
                q = strBetween(pValue, NULL, pSeparator);
                if (bInitializer != 0) {
                    fprintf(output, " = %s", q);
                }
            }
        }
        count++;
    }
}

/* MR23 Check for empty alt in a more intelligent way.
        Previously, an empty alt for genBlk had to point directly
		to the endBlock.  This did not work once I changed {...}
		blocks to look like (...|...| epsilon) since there were
		intervening generics.  This fixes the problem for this
		particular case.  Things like actions or empty blocks of
		various kinds will still cause problems, but I wasn't
		prepared to handle pathological cases like (A|()*). It
		does handle (A | ()), which is a recommended idiom for
		epsilon.

        Actually, this isn't quite correct since it doesn't handle
		the case of the ignore bit in the plus block bypass, but
		I'm too tired to figure out the correct fix, and will just
		work around it.
*/

#ifdef __USE_PROTOS
int isEmptyAlt(Node * alt, Node * endBlock)
#else
int isEmptyAlt(alt, endBlock)
Node * alt;
Node * endBlock;
#endif
{
	Node * n = alt;
	Junction * j;
	while (n != endBlock) {
		switch (n->ntype) {

			case nRuleRef:
				return 0;

			case nToken:
				return 0;

			case nAction:
				return 0;

			case nJunction:
				goto JUNCTION;

			default:
				fatal_internal("Invalid node type");
				return 0;
		}
JUNCTION:
		j = (Junction *) n;

		switch (j->jtype) {
			case Generic:
				{
					n = j->p1;
					goto NEXT;
				}

			case aSubBlk:
				{
					n = j->p1;	/* MR26 */
					goto NEXT;	/* MR26 */
				}

			case EndBlk:
					return 0;

			case EndRule:
					return 1;

			default:
					return 0;
		}
NEXT: continue;
	}
	return 1;
}
