Various typo in BaseTools. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Coeur <coeur@gmx.fr> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			4798 lines
		
	
	
		
			137 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4798 lines
		
	
	
		
			137 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * gen.c
 | |
|  *
 | |
|  * Generate C code (ANSI, K&R, C++)
 | |
|  *
 | |
|  * SOFTWARE RIGHTS
 | |
|  *
 | |
|  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
 | |
|  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
 | |
|  * company may do whatever they wish with source code distributed with
 | |
|  * PCCTS or the code generated by PCCTS, including the incorporation of
 | |
|  * PCCTS, or its output, into commerical software.
 | |
|  *
 | |
|  * We encourage users to develop software with PCCTS.  However, we do ask
 | |
|  * that credit is given to us for developing PCCTS.  By "credit",
 | |
|  * we mean that if you incorporate our source code into one of your
 | |
|  * programs (commercial product, research project, or otherwise) that you
 | |
|  * acknowledge this fact somewhere in the documentation, research report,
 | |
|  * etc...  If you like PCCTS and have developed a nice tool with the
 | |
|  * output, please mention that you developed it using PCCTS.  In
 | |
|  * addition, we ask that this header remain intact in our source code.
 | |
|  * As long as these guidelines are kept, we expect to continue enhancing
 | |
|  * this system and expect to make other tools available as they are
 | |
|  * completed.
 | |
|  *
 | |
|  * ANTLR 1.33
 | |
|  * Terence Parr
 | |
|  * Parr Research Corporation
 | |
|  * with Purdue University and AHPCRC, University of Minnesota
 | |
|  * 1989-2001
 | |
|  */
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <ctype.h>
 | |
| #include "pcctscfg.h"
 | |
| #include "set.h"
 | |
| #include "syn.h"
 | |
| #include "hash.h"
 | |
| #include "generic.h"
 | |
| #include "dlgdef.h"
 | |
| 
 | |
| #define NumExprPerLine	4
 | |
| static int on1line=0;
 | |
| static set tokensRefdInBlock;
 | |
| 
 | |
| 					/* T r a n s l a t i o n  T a b l e s */
 | |
| 
 | |
| /* C_Trans[node type] == pointer to function that knows how to translate that node. */
 | |
| #ifdef __cplusplus
 | |
| void (*C_Trans[NumNodeTypes+1])(...) = {
 | |
| 	NULL,
 | |
| 	NULL,					/* See next table.
 | |
| Junctions have many types */
 | |
| 	(void (*)(...)) genRuleRef,
 | |
| 	(void (*)(...)) genToken,
 | |
| 	(void (*)(...)) genAction
 | |
|  };
 | |
| #else
 | |
| void (*C_Trans[NumNodeTypes+1])() = {
 | |
| 	NULL,
 | |
| 	NULL,					/* See next table.
 | |
| Junctions have many types */
 | |
| 	genRuleRef,
 | |
| 	genToken,
 | |
| 	genAction
 | |
|  };
 | |
| #endif
 | |
| 
 | |
| /* C_JTrans[Junction type] == pointer to function that knows how to translate that
 | |
|  * kind of junction node.
 | |
|  */
 | |
| #ifdef __cplusplus
 | |
| void (*C_JTrans[NumJuncTypes+1])(...) = {
 | |
| 	NULL,
 | |
| 	(void (*)(...)) genSubBlk,
 | |
| 	(void (*)(...)) genOptBlk,
 | |
| 	(void (*)(...)) genLoopBlk,
 | |
| 	(void (*)(...)) genEndBlk,
 | |
| 	(void (*)(...)) genRule,
 | |
| 	(void (*)(...)) genJunction,
 | |
| 	(void (*)(...)) genEndRule,
 | |
| 	(void (*)(...)) genPlusBlk,
 | |
| 	(void (*)(...)) genLoopBegin
 | |
|  };
 | |
| #else
 | |
| void (*C_JTrans[NumJuncTypes+1])() = {
 | |
| 	NULL,
 | |
| 	genSubBlk,
 | |
| 	genOptBlk,
 | |
| 	genLoopBlk,
 | |
| 	genEndBlk,
 | |
| 	genRule,
 | |
| 	genJunction,
 | |
| 	genEndRule,
 | |
| 	genPlusBlk,
 | |
| 	genLoopBegin
 | |
|  };
 | |
| #endif
 | |
| 
 | |
| #define PastWhiteSpace(s)	while (*(s) == ' ' || *(s) == '\t') {s++;}
 | |
| 
 | |
| static int tabs = 0;
 | |
| 
 | |
| /* MR6	Got tired of text running off page when using standard tab stops */
 | |
| 
 | |
| #define TAB { int i; 					                		\
 | |
| 	      if (TabWidth==0) { 					                \
 | |
| 	         for (i=0; i<tabs; i++) fputc('\t', output);		                \
 | |
| 	      } else {           							\
 | |
| 		 for (i=0; i<tabs*TabWidth; i++) fputc(' ',output);     	        \
 | |
| 	      };	                						\
 | |
| 	    }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| tab( void )
 | |
| #else
 | |
| tab( )
 | |
| #endif
 | |
| TAB
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static char *tokenFollowSet(TokNode *);
 | |
| static ActionNode *findImmedAction( Node * );
 | |
| static void dumpRetValAssign(char *, char *, RuleRefNode *);		/* MR30 */
 | |
| static void dumpAfterActions(FILE *output);
 | |
| static set ComputeErrorSet(Junction *, int, int);
 | |
| static void makeErrorClause(Junction *, set, int, int);
 | |
| static void DumpFuncHeader( Junction *, RuleEntry * );
 | |
| static int has_guess_block_as_first_item(Junction *);
 | |
| static int genExprSets(set *, int);
 | |
| static void genExprTree( Tree *t, int k );
 | |
| static void genExprTreeOriginal( Tree *t, int k );                  /* MR10 */
 | |
| static char * findOuterHandlerLabel(ExceptionGroup *eg);            /* MR7 */
 | |
| static void OutLineInfo(FILE *file,int line,char *fileName);        /* MR14 */
 | |
| #else
 | |
| static char *tokenFollowSet();
 | |
| static ActionNode *findImmedAction();
 | |
| static void dumpRetValAssign();
 | |
| static void dumpAfterActions();
 | |
| static set ComputeErrorSet();
 | |
| static void makeErrorClause();
 | |
| static void DumpFuncHeader();
 | |
| static int has_guess_block_as_first_item();
 | |
| static int genExprSets();
 | |
| static void genExprTree();
 | |
| static void genExprTreeOriginal();                                  /* MR10 */
 | |
| static char * findOuterHandlerLabel();                              /* MR7 */
 | |
| static void OutLineInfo();                                          /* MR14 */
 | |
| #endif
 | |
| 
 | |
| #define gen(s)			{tab(); fprintf(output, s);}
 | |
| #define gen1(s,a)		{tab(); fprintf(output, s,a);}
 | |
| #define gen2(s,a,b)		{tab(); fprintf(output, s,a,b);}
 | |
| #define gen3(s,a,b,c)	{tab(); fprintf(output, s,a,b,c);}
 | |
| #define gen4(s,a,b,c,d)	{tab(); fprintf(output, s,a,b,c,d);}
 | |
| #define gen5(s,a,b,c,d,e)	{tab(); fprintf(output, s,a,b,c,d,e);}
 | |
| #define gen6(s,a,b,c,d,e,f)	{tab(); fprintf(output, s,a,b,c,d,e,f);}
 | |
| #define gen7(s,a,b,c,d,e,f,g)	{tab(); fprintf(output, s,a,b,c,d,e,f,g);}
 | |
| 
 | |
| #define _gen(s)			{fprintf(output, s);}
 | |
| #define _gen1(s,a)		{fprintf(output, s,a);}
 | |
| #define _gen2(s,a,b)	{fprintf(output, s,a,b);}
 | |
| #define _gen3(s,a,b,c)	{fprintf(output, s,a,b,c);}
 | |
| #define _gen4(s,a,b,c,d){fprintf(output, s,a,b,c,d);}
 | |
| #define _gen5(s,a,b,c,d,e){fprintf(output, s,a,b,c,d,e);}
 | |
| #define _gen6(s,a,b,c,d,e,f){fprintf(output, s,a,b,c,d,e,f);}
 | |
| #define _gen7(s,a,b,c,d,e,f,g){fprintf(output, s,a,b,c,d,e,f,g);}
 | |
| 
 | |
| 
 | |
| /* MR11 a convenient place to set a break point */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void MR_break(void) 
 | |
| #else
 | |
| void MR_break() 
 | |
| #endif
 | |
| {
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /* MR10 genTraceOut(Junction *)      */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static void genTraceOut(Junction *q)
 | |
| #else
 | |
| static void genTraceOut(q)
 | |
|   Junction  *q;
 | |
| #endif
 | |
| {
 | |
|   if ( TraceGen ) {
 | |
| 		if ( GenCC ) {gen1("zzTRACEOUT(\"%s\");\n", q->rname);}
 | |
|     		else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q->rname);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| warn_about_using_gk_option(void)
 | |
| #else
 | |
| warn_about_using_gk_option()
 | |
| #endif
 | |
| {
 | |
| 	static int warned_already=0;
 | |
| 
 | |
| 	if ( !DemandLookahead || warned_already ) return;
 | |
| 	warned_already = 1;
 | |
| 	warnNoFL("-gk option could cause trouble for <<...>>? predicates");
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| freeBlkFsets( Junction *q )
 | |
| #else
 | |
| freeBlkFsets( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	int i;
 | |
| 	Junction *alt;
 | |
| 	require(q!=NULL, "freeBlkFsets: invalid node");
 | |
| 
 | |
| 	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
 | |
| 	{
 | |
| 		for (i=1; i<=CLL_k; i++) set_free(alt->fset[i]);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate a local variable allocation for each token references
 | |
|  * in this block.
 | |
|  */
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| genTokenPointers( Junction *q )
 | |
| #else
 | |
| genTokenPointers( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	/* Rule refs are counted and can be referenced, but their
 | |
| 	 * value is not set to anything useful ever.
 | |
| 	 *
 | |
|      * The ptrs are to be named _tij where i is the current level
 | |
| 	 * and j is the element number within an alternative.
 | |
| 	 */
 | |
| 	int first=1, t=0;
 | |
| 	set a;
 | |
| 	tokensRefdInBlock = q->tokrefs;
 | |
| 
 | |
| 	if ( set_deg(q->tokrefs) == 0 ) return;
 | |
| 	a = set_dup(q->tokrefs);
 | |
| 	gen("ANTLRTokenPtr ");
 | |
| 	for (; !set_nil(a); set_rm(t, a))
 | |
| 	{
 | |
| 		t = set_int(a);
 | |
| 		if ( first ) first = 0;
 | |
| 		else _gen(",");
 | |
| 		if ( !DontCopyTokens ) _gen2("_tv%d%d,", BlkLevel, t);
 | |
| 		_gen2("_t%d%d", BlkLevel, t);
 | |
| 		if ( !DontCopyTokens ) {_gen2("= &_tv%d%d", BlkLevel, t);}
 | |
| 		else _gen("=NULL");
 | |
| 	}
 | |
| 	_gen(";\n");
 | |
| 	set_free(a);
 | |
| }
 | |
| 
 | |
| static int
 | |
| #ifdef __USE_PROTOS
 | |
| hasDefaultException(ExceptionGroup *eg)
 | |
| #else
 | |
| hasDefaultException(eg)
 | |
| ExceptionGroup *eg;
 | |
| #endif
 | |
| {
 | |
|     ListNode *q;
 | |
| 
 | |
|     for (q = eg->handlers->next; q!=NULL; q=q->next)
 | |
|     {
 | |
|         ExceptionHandler *eh = (ExceptionHandler *)q->elem;
 | |
|         if ( strcmp("default", eh->signalname)==0 ) {
 | |
|             return 1;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| dumpException(ExceptionGroup *eg, int no_default_case)
 | |
| #else
 | |
| dumpException(eg, no_default_case)
 | |
| ExceptionGroup *eg;
 | |
| int no_default_case;
 | |
| #endif
 | |
| {
 | |
|     char    *outerLabel;                                             /* MR7 */
 | |
|     int     altHandler=0;                                            /* MR7 */
 | |
|     int     namedHandler=0;                                          /* MR7 */
 | |
| 
 | |
|     outerLabel=findOuterHandlerLabel(eg);                            /* MR7 */
 | |
| 
 | |
|     if (eg->label != NULL) {                                         /* MR7 */
 | |
|       namedHandler=1;                                                /* MR7 */
 | |
|     } else if (eg->forRule) {                                        /* MR7 */
 | |
|       /* nothing */                                                  /* MR20 */
 | |
|     } else {                                                         /* MR7 */
 | |
|       altHandler=1;                                                  /* MR7 */
 | |
|     };                                                               /* MR7 */
 | |
| 
 | |
| #if 0
 | |
| **     if (! eg->used) {                                             /* MR7 */
 | |
| **     	warnFL("exception group never used",                         /* MR7 */
 | |
| **             FileStr[eg->altstart->file],eg->altstart->line);      /* MR7 */
 | |
| **     };                                                            /* MR7 */
 | |
| #endif
 | |
| 
 | |
|     if (namedHandler) {                                              /* MR7 */
 | |
| 	  gen1("switch ( _signal ) {  /* [%s] */\n",eg->label);          /* MR7 */
 | |
|     } else {                                                         /* MR7 */
 | |
| 	  gen("switch ( _signal ) {\n");                                 /* MR7 */
 | |
|       gen("case NoSignal: break;  /* MR7 */\n");                     /* MR7 */
 | |
|     };                                                               /* MR7 */
 | |
| 	{
 | |
| 		ListNode *q;
 | |
| 		for (q = eg->handlers->next; q!=NULL; q=q->next)
 | |
| 		{
 | |
| 			ExceptionHandler *eh = (ExceptionHandler *)q->elem;
 | |
| 			if ( strcmp("default", eh->signalname)==0 ) {
 | |
| 				gen("default :\n");
 | |
| 				tabs++;
 | |
| 				dumpAction(eh->action, output, tabs, -1, 1, 1);
 | |
|                 gen("_signal=NoSignal;  /* MR7 */\n");                  /* MR7 */
 | |
|                 gen("break;  /* MR7 */\n");                             /* MR7 */
 | |
| 				tabs--;
 | |
| 				gen("}\n");
 | |
| 
 | |
|                 /* copied from later code in dumpException */        /* MR7 */
 | |
| 
 | |
|                 if (namedHandler) {                                  /* MR7 */
 | |
|                   gen("if (_signal != NoSignal)");                   /* MR7 */
 | |
|                   _gen1(" goto %s_handler;  /* MR7 */\n",outerLabel);/* MR7 */
 | |
|                 } else if (altHandler) {                             /* MR7 */
 | |
|                   gen1("goto %s_handler;  /* MR7 */\n",outerLabel);  /* MR7 */
 | |
|                 };
 | |
| 				return;
 | |
| 			}
 | |
| 			gen1("case %s :\n", eh->signalname);
 | |
| 			tabs++;
 | |
| 			if ( eh->action != NULL )
 | |
| 			{
 | |
| 				dumpAction(eh->action, output, tabs, -1, 1, 1);
 | |
|                 gen("break;  /* MR7 */\n");                          /* MR7 */
 | |
| 			}
 | |
| 			tabs--;
 | |
| 		}
 | |
| 	}
 | |
| 	if ( no_default_case ) return;
 | |
| 
 | |
| 	gen("default :\n");
 | |
|     tabs++;                                                         /* MR7 */
 | |
|     gen("break;  /* MR7 */\n");                                     /* MR7 */
 | |
|     tabs--;                                                         /* MR7 */
 | |
| 
 | |
| 	tabs++;
 | |
| /*****	gen("*_retsignal = _signal;\n"); *****/
 | |
| 
 | |
| 	tabs--;
 | |
| 	gen("}\n");
 | |
| 
 | |
|     if (namedHandler) {                                             /* MR7 */
 | |
|       gen("if (_signal != NoSignal)");                              /* MR7 */
 | |
|       _gen1(" goto %s_handler;  /* MR7 */\n",outerLabel);           /* MR7 */
 | |
|     } else if (altHandler) {                                        /* MR7 */
 | |
|       gen1("goto %s_handler;  /* MR7 */\n",outerLabel);             /* MR7 */
 | |
|     };
 | |
| 
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| dumpExceptions(ListNode *list)
 | |
| #else
 | |
| dumpExceptions(list)
 | |
| ListNode *list;
 | |
| #endif
 | |
| {
 | |
| 	ListNode *p;
 | |
| 
 | |
| 	for (p = list->next; p!=NULL; p=p->next)
 | |
| 	{
 | |
| 		ExceptionGroup *eg = (ExceptionGroup *) p->elem;
 | |
| 		_gen2("%s%s_handler:\n",
 | |
| 			  eg->label==NULL?"":eg->label,
 | |
| 			  eg->altID==NULL?"":eg->altID);
 | |
| 		if ( eg->altID!=NULL ) dumpException(eg, 0);
 | |
| 		else {
 | |
| 			/* This must be the rule exception handler */
 | |
| 			dumpException(eg, 1);
 | |
| 			if ( !hasDefaultException(eg) )
 | |
|             {
 | |
|                 gen("default :\n");
 | |
|                 tabs++;
 | |
|                 gen("zzdflthandlers(_signal,_retsignal);\n");
 | |
|                 tabs--;
 | |
|                 gen("}\n");
 | |
|             }
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* For each element label that is found in a rule, generate a unique
 | |
|  * Attribute (and AST pointer if GenAST) variable.
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genElementLabels(ListNode *list)
 | |
| #else
 | |
| genElementLabels(list)
 | |
| ListNode *list;
 | |
| #endif
 | |
| {
 | |
| 	int first=1;
 | |
| 	ListNode *p;
 | |
| 
 | |
| 	if ( GenCC ) {gen("ANTLRTokenPtr");}
 | |
| 	else {gen("Attrib");}
 | |
| 	for (p = list->next; p!=NULL; p=p->next)
 | |
| 	{
 | |
| 		char *ep = (char *)p->elem;
 | |
| 		if ( first ) first = 0;
 | |
| 		else _gen(",");
 | |
| 		if ( GenCC ) {_gen1(" %s=NULL",ep);}
 | |
| 		else {_gen1(" %s",ep);}
 | |
| 	}
 | |
| 	_gen(";\n");
 | |
| 
 | |
| 	if ( !GenAST ) return;
 | |
| 
 | |
| 	first = 1;
 | |
| 	gen("AST");
 | |
| 	for (p = list->next; p!=NULL; p=p->next)
 | |
| 	{
 | |
| 		char *ep = (char *)p->elem;
 | |
| 		if ( first ) first = 0;
 | |
| 		else _gen(",");
 | |
| 		_gen1(" *%s_ast=NULL",ep);
 | |
| 	}
 | |
| 	_gen(";\n");
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate a local variable allocation for each token or rule reference
 | |
|  * in this block.
 | |
|  */
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| genASTPointers( Junction *q )
 | |
| #else
 | |
| genASTPointers( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	int first=1, t;
 | |
| 	set a;
 | |
| 
 | |
| 	a = set_or(q->tokrefs, q->rulerefs);
 | |
| 	if ( set_deg(a) > 0 )
 | |
| 	{
 | |
| 		gen("AST ");
 | |
| 		for (; !set_nil(a); set_rm(t, a))
 | |
| 		{
 | |
| 			t = set_int(a);
 | |
| 			if ( first ) first = 0;
 | |
| 			else _gen(",");
 | |
| 			_gen2("*_ast%d%d=NULL", BlkLevel, t);
 | |
| 		}
 | |
| 		set_free(a);
 | |
| 	}
 | |
| 	_gen(";\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| BLOCK_Head( void )
 | |
| #else
 | |
| BLOCK_Head( )
 | |
| #endif
 | |
| {
 | |
| 	gen("{\n");
 | |
| 	tabs++;
 | |
| 	if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel);
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| BLOCK_Tail( void )
 | |
| #else
 | |
| BLOCK_Tail( )
 | |
| #endif
 | |
| {
 | |
| 	if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel);
 | |
| 	if ( !GenCC ) gen("}\n");
 | |
| 	tabs--;
 | |
| 	gen("}\n");
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| BLOCK_Preamble( Junction *q )
 | |
| #else
 | |
| BLOCK_Preamble( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	ActionNode *a;
 | |
| 	Junction *begin;
 | |
| 
 | |
| 	BLOCK_Head();
 | |
| 	if ( GenCC ) genTokenPointers(q);
 | |
| 	if ( GenCC&&GenAST ) genASTPointers(q);
 | |
| 	if ( q->jtype == aPlusBlk ) gen("int zzcnt=1;\n");
 | |
| 	if ( q->parm != NULL && !q->predparm ) gen1("zzaPush(%s);\n", q->parm)
 | |
| 	else if ( !GenCC ) gen("zzMake0;\n");
 | |
| 	if ( !GenCC ) gen("{\n");
 | |
| 	if ( q->jtype == aLoopBegin ) begin = (Junction *) ((Junction *)q->p1);
 | |
| 	else begin = q;
 | |
| 	if ( has_guess_block_as_first_item(begin) )
 | |
| 	{
 | |
| 		gen("zzGUESS_BLOCK\n");
 | |
| 	}
 | |
| 	if ( q->jtype == aLoopBegin )
 | |
| 		a = findImmedAction( ((Junction *)q->p1)->p1 );	/* look at aLoopBlk */
 | |
| 	else
 | |
| 		a = findImmedAction( q->p1 );
 | |
| 	if ( a!=NULL && !a->is_predicate) {
 | |
| /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1);
 | |
| 		   a->done = 1;	/* remove action. We have already handled it */
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genCombinedPredTreeContextOrig( Predicate *p )
 | |
| #else
 | |
| genCombinedPredTreeContextOrig( p )
 | |
| Predicate *p;
 | |
| #endif
 | |
| {
 | |
| 	static set *ctx=NULL;		/* genExprSets() is destructive, make copy*/
 | |
| 	require(p!=NULL, "can't make context tree for NULL pred tree");
 | |
| 
 | |
| #ifdef DBG_PRED
 | |
| 	fprintf(stderr, "enter genCombinedPredTreeContextOrig(%s,0x%x) with sets:\n", p->expr, p);
 | |
| 	s_fprT(stderr, p->scontext[1]);
 | |
| 	fprintf(stderr, "\n");
 | |
| #endif
 | |
| 	if ( p->down == NULL )
 | |
| 	{
 | |
| /***	if ( p->k>1 && p->tcontext!=NULL ) ***/
 | |
| 		if ( p->tcontext!=NULL )
 | |
| 		{
 | |
| 			_gen("(");
 | |
| 			genExprTree(p->tcontext, 1);
 | |
| 			_gen(")");
 | |
| 		}
 | |
| /***	else if ( p->k==1 && set_deg(p->scontext[1])>0 ) ***/
 | |
| 		else if ( set_deg(p->scontext[1])>0 )
 | |
| 		{
 | |
| 			if ( ctx==NULL ) ctx = (set *)calloc(CLL_k+1, sizeof(set));
 | |
| 			require(ctx!=NULL, "ctx cannot allocate");
 | |
| 			ctx[0]=empty;
 | |
| 			ctx[1]=set_dup(p->scontext[1]);
 | |
| 			_gen("(");
 | |
| 			genExprSets(&(ctx[0]), p->k);
 | |
| 			_gen(")");
 | |
| 			set_free(ctx[1]);
 | |
| 		}
 | |
| 		else if ( p->expr==PRED_AND_LIST || p->expr==PRED_OR_LIST ) {
 | |
| 			fatal_internal("pred tree is orphan OR or AND list");
 | |
| 		}
 | |
| 		else {
 | |
|             if (! HoistPredicateContext) {
 | |
|               _gen(" 1 /* no context: prc is off */ ");
 | |
|             } else {
 | |
|               fatal_internal("pred tree context is empty");
 | |
|             };
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| /* MR10 - make AND just like OR */
 | |
| 
 | |
| 	if ( p->expr == PRED_AND_LIST )
 | |
| 	{
 | |
|         Predicate *list = p->down;
 | |
|         for (; list!=NULL; list=list->right)
 | |
|         {
 | |
|      	     genCombinedPredTreeContextOrig(list);
 | |
|        		 if ( list->right!=NULL ) _gen("|| /* MR10 was wrong */ ");
 | |
|         };
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if ( p->expr == PRED_OR_LIST )
 | |
| 	{
 | |
|         Predicate *list = p->down;
 | |
|         for (; list!=NULL; list=list->right)
 | |
|         {
 | |
|            genCombinedPredTreeContextOrig(list);
 | |
|            if ( list->right!=NULL ) _gen("||");
 | |
|         };
 | |
|         return;
 | |
|      };
 | |
| 
 | |
| 	fatal("pred tree is really wacked");
 | |
| }
 | |
| 
 | |
| /* [genCombinedPredTreeContext] */
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genCombinedPredTreeContext( Predicate *p )
 | |
| #else
 | |
| genCombinedPredTreeContext( p )
 | |
| Predicate *p;
 | |
| #endif
 | |
| {
 | |
|   Tree  *t;
 | |
|   int   predDepth=0;
 | |
| 
 | |
|   if (0 && ! MR_usingPredNames && ! MRhoisting) {
 | |
|     genCombinedPredTreeContextOrig(p);
 | |
|   } else {
 | |
| /* MR13 */    MR_pred_depth(p,&predDepth);
 | |
| /* MR13 */    if (predDepth == 1) {
 | |
| /* MR13 */
 | |
| /* MR13 */      set   scontext[2];
 | |
| /* MR13 */      scontext[0]=empty;
 | |
| /* MR13 */      scontext[1]=MR_compute_pred_set(p);
 | |
| /* MR13 */      if (set_nil(scontext[1])) {
 | |
| /* MR13 */        _gen(" 1 /* MR12 no context (-prc off) */ ");
 | |
| /* MR13 */      } else {
 | |
| /* MR13 */        _gen("(");
 | |
| /* MR13 */        genExprSets(&scontext[0], 1);
 | |
| /* MR13 */        set_free(scontext[1]);
 | |
| /* MR13 */        _gen(")");
 | |
| /* MR13 */      };
 | |
| 
 | |
|     } else {
 | |
|       t=MR_compute_pred_tree_context(p);
 | |
|       if (t == NULL) {
 | |
|         _gen(" 1 /* MR12 no context (-prc off) */ ");
 | |
|       } else {
 | |
|         _gen("(");
 | |
|         genExprTree(t, 1);
 | |
|         Tfree(t);   /* MR10 */
 | |
|         _gen(")");
 | |
|       };
 | |
|     };
 | |
|   };
 | |
| }
 | |
| 
 | |
| /* [genPredTreeGate] */
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genPredTreeGate( Predicate *p, int in_and_expr )
 | |
| #else
 | |
| genPredTreeGate( p, in_and_expr )
 | |
| Predicate *p;
 | |
| int in_and_expr;
 | |
| #endif
 | |
| {
 | |
| 	if ( in_and_expr )
 | |
| 	{
 | |
| 		_gen("!(");
 | |
| 		genCombinedPredTreeContext(p);
 | |
| 		_gen(")||");
 | |
| 		if ( p->down!=NULL ) _gen("\n");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		_gen("(");
 | |
| 		genCombinedPredTreeContext(p);
 | |
| 		_gen(")&&");
 | |
| 		if ( p->down!=NULL ) _gen("\n");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void genPredEntry(Predicate *p,int outer)
 | |
| #else
 | |
| void genPredEntry(p,outer)
 | |
|   Predicate     *p;
 | |
|   int           outer;
 | |
| #endif
 | |
| {
 | |
|     int         inverted=0;
 | |
|     Predicate   *q;
 | |
|     int         localOuter=outer;
 | |
|     int         needRP=0;
 | |
| 
 | |
|     if (p == NULL) return;
 | |
| 
 | |
|     if (p->predEntry != NULL && p->predEntry->predLiteral != NULL) {
 | |
|       if (p->inverted != p->predEntry->pred->inverted) {
 | |
|         _gen("! /* inverted pred */ (");
 | |
|         needRP=1;
 | |
|       } else {
 | |
|         if (!localOuter) _gen("(");
 | |
|         needRP=1;
 | |
|       };
 | |
|       dumpAction(p->predEntry->predLiteral,output,0,p->source->file,p->source->line,0);
 | |
|       if (needRP) _gen(")");
 | |
|       return;
 | |
|     };
 | |
| 
 | |
|     inverted=p->inverted;
 | |
| 
 | |
|     if (inverted) {
 | |
|       _gen(" ! /* inverted pred */ (");
 | |
|       localOuter=1;
 | |
|     };
 | |
| 
 | |
|     if (p->expr == PRED_OR_LIST) {
 | |
|       if (!localOuter) _gen("(");
 | |
|       for (q=p->down; q != NULL ; q=q->right) {
 | |
|         genPredEntry(q,0);
 | |
|         if (q->right != NULL) _gen(" || ");
 | |
|       };
 | |
|       if (!localOuter) _gen(")");
 | |
|     } else if (p->expr == PRED_AND_LIST) {
 | |
|       if (!localOuter) _gen("(");
 | |
|       for (q=p->down; q != NULL ; q=q->right) {
 | |
|         genPredEntry(q,0);
 | |
|         if (q->right != NULL) _gen(" && ");
 | |
|       };
 | |
|       if (!localOuter) _gen(")");
 | |
|     } else {
 | |
|       if (!localOuter) _gen("(");
 | |
|       require (p->source != NULL,"predEntry->source == NULL");
 | |
|       require (p->source->inverted == 0,"dumpPredEntry p->source->inverted != 0");
 | |
|       dumpAction(p->source->action,output,0,p->source->file,p->source->line,0);
 | |
|       if (!localOuter) _gen(")");
 | |
|     };
 | |
| 
 | |
|     if (inverted) {
 | |
|         _gen(")");
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| dumpPredAction(ActionNode *anode,
 | |
|                     char *s,FILE *output,int tabs,int file,int line,int final_newline)
 | |
| #else
 | |
| dumpPredAction(anode,
 | |
|                     s,output,tabs,file,line,final_newline)
 | |
| 
 | |
|     ActionNode  *anode;
 | |
|     char        *s;
 | |
|     FILE        *output;
 | |
|     int         tabs;
 | |
|     int         file;
 | |
|     int         line;
 | |
|     int         final_newline;
 | |
| #endif
 | |
| {
 | |
|     PredEntry   *predEntry=anode->predEntry;
 | |
|     int         inverted=anode->inverted;
 | |
|     Predicate   *workPred;
 | |
| 
 | |
|     if (predEntry == NULL) {
 | |
| 
 | |
|       /* inline predicate literal */
 | |
| 
 | |
|       require(inverted == 0,"dumpPredAction action->inverted");
 | |
|   	  dumpAction(s,output,tabs,file,line,final_newline);
 | |
| 
 | |
|     } else {
 | |
| 
 | |
|       /* a reference to a predicate - possibly with an inverted source */
 | |
| 
 | |
|       if (predEntry->predLiteral != NULL) {
 | |
|         if (inverted) _gen("! /* inverted pred */ (");
 | |
|         dumpAction(predEntry->predLiteral,output,0,anode->file,anode->line,0);
 | |
|         if (inverted) _gen(")");
 | |
|       } else {
 | |
|         workPred=predicate_dup(predEntry->pred);
 | |
|         if (inverted) workPred->inverted=!workPred->inverted;
 | |
|         genPredEntry(workPred,1);
 | |
|         predicate_free(workPred);
 | |
|       };
 | |
|     };
 | |
| }
 | |
| 
 | |
| /* [genPred] */
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genPred(Predicate *p, Node *j,int suppress_sva)
 | |
| #else
 | |
| genPred(p,j,suppress_sva)
 | |
|     Predicate   *p;
 | |
|     Node        *j;
 | |
|     int         suppress_sva;
 | |
| #endif
 | |
| {
 | |
| 	if ( FoundException && !suppress_sva) {_gen("(_sva=(");}    /* MR11 suppress_sva */
 | |
| 	else {_gen("(");}
 | |
| 	if ( GenLineInfo && j->file != -1 ) _gen("\n");
 | |
|     if (p->source != NULL && p->source->ampersandPred != NULL) {
 | |
|       if (p->source->ampersandPred->k == 1) {
 | |
| 
 | |
|             set     ctx[2];
 | |
| 
 | |
| 			ctx[0]=empty;
 | |
| 			ctx[1]=set_dup(p->source->ampersandPred->scontext[1]);
 | |
| 
 | |
| 			_gen("(");
 | |
| 			genExprSets(&(ctx[0]), p->k);
 | |
| 			_gen(") && ");
 | |
| 			set_free(ctx[1]);
 | |
|       } else {
 | |
|         _gen("( ");
 | |
|         genExprTree(p->source->ampersandPred->tcontext,1);
 | |
| 		_gen(" ) && ");
 | |
|       };
 | |
|     };
 | |
| 
 | |
|     dumpPredAction((ActionNode *)p->source,
 | |
|                 p->expr, output, 0, -1 /*indicates no line info*/, j->line, 0);
 | |
| 
 | |
| 	if ( FoundException && !suppress_sva)   /* MR11 suppress_sva */
 | |
|          {_gen("),_sva)");}    /* MR10 - get red of "meant ==" messages */
 | |
| 	else {_gen(")");}
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| MR_distinctORcontextOpt(Predicate *p,Node *j,int in_and_expr)
 | |
| #else
 | |
| MR_distinctORcontextOpt(p,j,in_and_expr)
 | |
|     Predicate   *p;
 | |
|     Node        *j;
 | |
|     int         in_and_expr;
 | |
| #endif
 | |
| {
 | |
|     Predicate   *q;
 | |
| 
 | |
|     _gen(" /* MR10 Distinct OR context optimization */ \n");
 | |
| 
 | |
|     if (in_and_expr) {
 | |
|       gen("zzpf=0,\n");
 | |
|       for (q=p->down; q != NULL; q=q->right) {
 | |
|         gen("(  ");
 | |
|         genCombinedPredTreeContext(q);
 | |
|         _gen(" && (zzpf=1, ");
 | |
|         genPred(q,j,0);
 | |
|         _gen("  )) ||\n");
 | |
|       };
 | |
|       gen("!zzpf)");
 | |
|     } else {
 | |
|       require (0,
 | |
|             "MR_distinctORcontextOpt: can't get here when using MR_predSimplify");
 | |
| #if 0
 | |
| **      for (q=p->down; q != NULL; q=q->right) {
 | |
| **        gen("(  ");
 | |
| **        genCombinedPredTreeContext(q);
 | |
| **        _gen(" && ");
 | |
| **        genPred(q,j);
 | |
| **        if (q->right != NULL) {
 | |
| **          _gen("  ) ||\n");
 | |
| **        };
 | |
| **      };
 | |
| **      gen(")");
 | |
| #endif
 | |
|    };
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genPredTreeOrig( Predicate *p, Node *j, int in_and_expr )
 | |
| #else
 | |
| genPredTreeOrig( p, j, in_and_expr )
 | |
| Predicate *p;
 | |
| Node *j;
 | |
| int in_and_expr;
 | |
| #endif
 | |
| {
 | |
| 
 | |
| /* MR10 */  int     allHaveContext=1;
 | |
| /* MR10 */  int     noneHaveContext=1;
 | |
| 
 | |
| /* MR10 */  MR_predContextPresent(p,&allHaveContext,&noneHaveContext);
 | |
| 
 | |
| 	if ( ! noneHaveContext )                  /* MR10 context guards ignored when -prc off */
 | |
| 	{
 | |
| 		_gen("(");
 | |
| 		genPredTreeGate(p, in_and_expr);
 | |
| 	}
 | |
| 
 | |
| 	/* if leaf node, just gen predicate */
 | |
| 
 | |
| 	if ( p->down==NULL )
 | |
| 	{
 | |
| 		genPred(p,j,0);
 | |
| 		if ( ! noneHaveContext ) _gen(")");   /* MR10 context guards ignored when -prc off */
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* if AND list, do both preds (only two possible) */
 | |
| 	if ( p->expr == PRED_AND_LIST )
 | |
| 	{
 | |
| #if 0
 | |
| **		_gen("(");
 | |
| **		genPredTreeOrig(p->down, j, 1);
 | |
| **		_gen("&&");
 | |
| **		genPredTreeOrig(p->down->right, j, 1);
 | |
| **		_gen(")");
 | |
| **		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
 | |
| **		return;
 | |
| #endif
 | |
|         /* MR11 - make it work with AND with more than two children - like OR */
 | |
| 
 | |
| 		Predicate *list;
 | |
| 		_gen("(");
 | |
| 		list = p->down;
 | |
| 		for (; list!=NULL; list=list->right)
 | |
| 		{
 | |
| 			genPredTreeOrig(list, j, 1);
 | |
| 			if ( list->right!=NULL ) _gen("&&");
 | |
| 		}
 | |
| 		_gen(")");
 | |
| 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
 | |
| 		return;
 | |
|     };
 | |
| 
 | |
| 	if ( p->expr == PRED_OR_LIST )
 | |
| 	{
 | |
| 		Predicate *list;
 | |
| 		_gen("(");
 | |
| 		list = p->down;
 | |
| 		for (; list!=NULL; list=list->right)
 | |
| 		{
 | |
| 			genPredTreeOrig(list, j, 0);
 | |
| 			if ( list->right!=NULL ) _gen("||");
 | |
| 		}
 | |
| 		_gen(")");
 | |
| 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	fatal_internal("genPredTreeOrig: predicate tree is wacked");
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| **   Predicate member dummyPredDepth is no longer used in MR10
 | |
| **     but we might need it again in the future
 | |
| **
 | |
| **   if (MRhoisting) {
 | |
| **     if ( !noneHaveContext &&
 | |
| **          ! in_and_expr &&
 | |
| **          p->source != NULL &&
 | |
| **          p->source->dummyPredicateDepth > 0 &&
 | |
| **          p->down == NULL) {
 | |
| ** 		_gen("(");
 | |
| ** 		genCombinedPredTreeContext(p);
 | |
| ** 		_gen("  )\n");
 | |
| ** 		return;
 | |
| **     };
 | |
| **   };
 | |
| #endif
 | |
| 
 | |
| /* [genPredTree] */
 | |
| 
 | |
| /* in_and_expr
 | |
| 
 | |
|    what to do if the context is wrong
 | |
|    what to do if the context is correct but the predicate is false
 | |
| 
 | |
|    remember: if the context is wrong it's the same as if the
 | |
|              predicate is true as far as enabling an alternative
 | |
| 
 | |
|         Consider (AND p q r)
 | |
| 
 | |
|         if in an ... && ... expression then you don't want
 | |
|         the entire predicate chain to fail just because the
 | |
|         context for one component is wrong: so return true
 | |
| 
 | |
|         Consider (OR p q r)
 | |
| 
 | |
|         if in an ... || ... expression then you don't want
 | |
|         the entire predicate chain to succeed just because
 | |
|         the context for one component is correct when the
 | |
|         corresponding test is false: so return false when
 | |
|         the context is correct but the test is false.
 | |
| */
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genPredTree( Predicate *p, Node *j, int in_and_expr, int suppress_sva )
 | |
| #else
 | |
| genPredTree( p, j, in_and_expr, suppress_sva)
 | |
|   Predicate     *p;
 | |
|   Node          *j;
 | |
|   int           in_and_expr;
 | |
|   int           suppress_sva;
 | |
| #endif
 | |
| {
 | |
| 
 | |
|     int         allHaveContext=1;
 | |
|     int         noneHaveContext=1;
 | |
|     Tree        *groupTree;
 | |
|     Tree        *oneTree;
 | |
|     Predicate   *q;
 | |
|     int         identicalORcontextOptimization=0;
 | |
|     int         identicalANDcontextOptimization=0;
 | |
| 
 | |
|     if (0 && !MR_usingPredNames && !MRhoisting) {
 | |
|       genPredTreeOrig(p,j,in_and_expr);
 | |
|       return;
 | |
|     };
 | |
| 
 | |
|     MR_predContextPresent(p,&allHaveContext,&noneHaveContext);
 | |
| 
 | |
| 	if ( ! noneHaveContext ) {                 /* MR10 context guards ignored when -prc off */
 | |
| 
 | |
|       _gen("(");
 | |
| 
 | |
|             /* MR10 optimize OR predicates which are all leaves */
 | |
| 
 | |
|       if (p->expr == PRED_OR_LIST && MR_allPredLeaves(p->down)) {
 | |
|         groupTree=MR_compute_pred_tree_context(p);
 | |
|         for (q=p->down ; q != NULL ; q=q->right) {
 | |
|           oneTree=MR_compute_pred_tree_context(q);
 | |
|           if (! MR_tree_equ(groupTree,oneTree)) {
 | |
|             Tfree(oneTree);
 | |
|             break;
 | |
|           };
 | |
|           Tfree(oneTree);
 | |
|         };
 | |
|         Tfree(groupTree);
 | |
|         if (q == NULL) {
 | |
|           _gen("/* MR10 individual OR gates suppressed when all predicates are leaves");
 | |
|           _gen(" with identical context */\n");
 | |
|           genPredTreeGate(p,in_and_expr);   /* use the parent's in_and_expr for this gate */
 | |
|           identicalORcontextOptimization=1;
 | |
|         } else {
 | |
|           MR_distinctORcontextOpt(p,j,in_and_expr);
 | |
|           return;
 | |
|         };
 | |
|       } else if (p->expr == PRED_AND_LIST && MR_allPredLeaves(p->down)) {
 | |
| 
 | |
|             /* MR12 optimize AND predicates which are all leaves */
 | |
| 
 | |
|         groupTree=MR_compute_pred_tree_context(p);
 | |
|         for (q=p->down ; q != NULL ; q=q->right) {
 | |
|           oneTree=MR_compute_pred_tree_context(q);
 | |
|           if (! MR_tree_equ(groupTree,oneTree)) {
 | |
|             Tfree(oneTree);
 | |
|             break;
 | |
|           };
 | |
|           Tfree(oneTree);
 | |
|         };
 | |
|         Tfree(groupTree);
 | |
|         if (q == NULL) {
 | |
|           _gen("/* MR12 individual AND gates suppressed when all predicates are leaves");
 | |
|           _gen(" with identical context */\n");
 | |
|           genPredTreeGate(p,in_and_expr);   /* use the parent's in_and_expr for this gate */
 | |
|           identicalANDcontextOptimization=1;
 | |
|         } else {
 | |
|           genPredTreeGate(p, in_and_expr);
 | |
|         };
 | |
|       } else {
 | |
|   	    genPredTreeGate(p, in_and_expr);
 | |
|       };
 | |
| 	}
 | |
| 
 | |
| 	/* if leaf node, just gen predicate */
 | |
| 
 | |
| 	if ( p->down==NULL )
 | |
| 	{
 | |
| 		genPred(p,j,suppress_sva);
 | |
| 		if ( ! noneHaveContext ) _gen(")");   /* MR10 context guards ignored when -prc off */
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* if AND list, do both preds (only two possible) */
 | |
|     /* MR10    not any more ! */
 | |
| 
 | |
| 	if ( p->expr == PRED_AND_LIST )
 | |
| 	{
 | |
| 		Predicate *list;
 | |
| 		_gen("(");
 | |
| 		list = p->down;
 | |
|         for (; list != NULL; list=list->right) {
 | |
|           if (identicalANDcontextOptimization) {
 | |
|             genPred(list, j,suppress_sva);
 | |
|           } else {
 | |
| 	   	    genPredTree(list, j, 1, suppress_sva);  /* in and context */
 | |
|           };
 | |
|           if ( list->right!=NULL ) _gen("&&");
 | |
|         };
 | |
| 		_gen(")");
 | |
| 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if ( p->expr == PRED_OR_LIST )
 | |
| 	{
 | |
| 		Predicate *list;
 | |
| 		_gen("(");
 | |
| 		list = p->down;
 | |
| 		for (; list!=NULL; list=list->right)
 | |
| 		{
 | |
|             if (identicalORcontextOptimization) {
 | |
| 	          genPred(list, j,suppress_sva);
 | |
|             } else {
 | |
| 	   	      genPredTree(list, j, 0, suppress_sva);
 | |
|             };
 | |
| 			if ( list->right!=NULL ) _gen("||");
 | |
| 		}
 | |
| 		_gen(")");
 | |
| 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	fatal_internal("predicate tree is wacked");
 | |
| }
 | |
| 
 | |
| /* [genPredTreeMainXX] */
 | |
| 
 | |
| Predicate *     /* MR10 */
 | |
| #ifdef __USE_PROTOS
 | |
| genPredTreeMainXX( Predicate *p, Node *j ,int in_and_expr)
 | |
| #else
 | |
| genPredTreeMainXX( p, j ,in_and_expr)
 | |
|     Predicate   *p;
 | |
|     Node        *j;
 | |
|     int         in_and_expr;
 | |
| #endif
 | |
| {
 | |
| 
 | |
|     int     allHaveContext=1;
 | |
|     int     noneHaveContext=1;
 | |
| 
 | |
| #if 0
 | |
|     fprintf(stderr,"Pred before\n");
 | |
|     dumppred(p);
 | |
|     fprintf(stderr,"\n");
 | |
|     fprintf(stderr,"Pred after\n");
 | |
|     dumppred(p);
 | |
|     fprintf(stderr,"\n");
 | |
| #endif
 | |
| 
 | |
|     p=MR_predSimplifyALL(p);    /* MR10 */
 | |
| 
 | |
|     require (MR_predicate_context_completed(p),"predicate context is not complete");
 | |
| 
 | |
|     MR_cleanup_pred_trees(p);   /* MR10 */
 | |
| 
 | |
|     MR_predContextPresent(p,&allHaveContext,&noneHaveContext);
 | |
|     if (!noneHaveContext & !allHaveContext) {
 | |
|       warnFL("predicate contains elements both with and without context",
 | |
|                 FileStr[j->file],j->line);
 | |
|     };
 | |
| 
 | |
|     if (InfoP) {
 | |
|        _gen("\n#if 0\n\n");
 | |
|        MR_dumpPred(p,1);
 | |
|        _gen("#endif\n");
 | |
|     };
 | |
| 	genPredTree(p,j,in_and_expr,0);
 | |
|     return p;
 | |
| }
 | |
| 
 | |
| Predicate *     /* MR10 */
 | |
| #ifdef __USE_PROTOS
 | |
| genPredTreeMain( Predicate *p, Node *j)
 | |
| #else
 | |
| genPredTreeMain( p, j)
 | |
|     Predicate   *p;
 | |
|     Node        *j;
 | |
| #endif
 | |
| {
 | |
|   return genPredTreeMainXX(p,j,1);
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| genExprTreeOriginal( Tree *t, int k )
 | |
| #else
 | |
| genExprTreeOriginal( t, k )
 | |
| Tree *t;
 | |
| int k;
 | |
| #endif
 | |
| {
 | |
| 	require(t!=NULL, "genExprTreeOriginal: NULL tree");
 | |
| 	
 | |
| 	if ( t->token == ALT )
 | |
| 	{
 | |
| 		_gen("("); genExprTreeOriginal(t->down, k); _gen(")");
 | |
| 		if ( t->right!=NULL )
 | |
| 		{
 | |
| 			_gen("||");
 | |
| 			on1line++;
 | |
| 			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
 | |
| 			_gen("("); genExprTreeOriginal(t->right, k); _gen(")");
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 	if ( t->down!=NULL ) _gen("(");
 | |
| 	_gen1("LA(%d)==",k);
 | |
| 	if ( TokenString(t->token) == NULL ) _gen1("%d", t->token)
 | |
| 	else _gen1("%s", TokenString(t->token));
 | |
| 	if ( t->down!=NULL )
 | |
| 	{
 | |
| 		_gen("&&");
 | |
| 		on1line++;
 | |
| 		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
 | |
| 		_gen("("); genExprTreeOriginal(t->down, k+1); _gen(")");
 | |
| 	}
 | |
| 	if ( t->down!=NULL ) _gen(")");
 | |
| 	if ( t->right!=NULL )
 | |
| 	{
 | |
| 		_gen("||");
 | |
| 		on1line++;
 | |
| 		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
 | |
| 		_gen("("); genExprTreeOriginal(t->right, k); _gen(")");
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static void MR_LAtokenString(int k,int token)
 | |
| #else
 | |
| static void MR_LAtokenString(k,token)
 | |
|   int   k;
 | |
|   int   token;
 | |
| #endif
 | |
| {
 | |
|     char    *ts;
 | |
| 
 | |
|     ts=TokenString(token);
 | |
|     if (ts == NULL) {
 | |
|       _gen2(" LA(%d)==%d",k,token);
 | |
|     } else {
 | |
|       _gen2(" LA(%d)==%s",k,ts);
 | |
|     };
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static int MR_countLeaves(Tree *t)
 | |
| #else
 | |
| static int MR_countLeaves(t)
 | |
|   Tree  *t;
 | |
| #endif
 | |
| {
 | |
|   if (t == NULL) return 0;
 | |
|   if (t->token == ALT) {
 | |
|     return MR_countLeaves(t->down)+MR_countLeaves(t->right);
 | |
|   } else {
 | |
|     return 1+MR_countLeaves(t->down)+MR_countLeaves(t->right);
 | |
|   };
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static void MR_genOneLine(Tree *tree,int k)
 | |
| #else
 | |
| static void MR_genOneLine(tree,k)
 | |
|   Tree      *tree;
 | |
|   int       k;
 | |
| #endif
 | |
| {
 | |
|     if (tree == NULL) return;
 | |
|     if (tree->token == ALT) {
 | |
|        MR_genOneLine(tree->down,k);
 | |
|     } else {
 | |
|        MR_LAtokenString(k,tree->token);
 | |
|        if (tree->down != NULL &&
 | |
|            tree->down->right == NULL) {
 | |
|           _gen(" &&");
 | |
|           MR_genOneLine(tree->down,k+1);
 | |
|        } else if (tree->down != NULL) {
 | |
|          _gen(" && (");
 | |
|          MR_genOneLine(tree->down,k+1);
 | |
|          _gen(")");
 | |
|        };
 | |
|     };
 | |
|     if (tree->right != NULL) {
 | |
|       _gen(" ||");
 | |
|       MR_genOneLine(tree->right,k);
 | |
|     };
 | |
| }
 | |
| 
 | |
| static int across;
 | |
| static int depth;
 | |
| static int lastkonline;
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static void MR_genMultiLine(Tree *tree,int k)
 | |
| #else
 | |
| static void MR_genMultiLine(tree,k)
 | |
|   Tree  *tree;
 | |
|   int   k;
 | |
| #endif
 | |
| {
 | |
|     int     i;
 | |
| 
 | |
|     if (tree == NULL) return;
 | |
|     if (tree->token == ALT) {
 | |
|       MR_genMultiLine(tree,k);
 | |
|     } else {
 | |
|       MR_LAtokenString(k,tree->token);
 | |
|       lastkonline=k;
 | |
|       across++;
 | |
|       if (tree->down != NULL && tree->down->right == NULL) {
 | |
|         if (across > 3) {
 | |
|           _gen("\n");
 | |
|           across=0;
 | |
|           lastkonline=0;
 | |
|           for (i=0 ; i < depth+k ; i++) _gen("   ");
 | |
|           _gen("&&");
 | |
|         } else {
 | |
|           _gen(" &&");
 | |
|         };
 | |
|         MR_genMultiLine(tree->down,k+1);
 | |
|       } else if (tree->down != NULL) {
 | |
|         _gen("\n");
 | |
|         lastkonline=0;
 | |
|         across=0;
 | |
|         for (i=0 ; i < depth+k ; i++) _gen("   ");
 | |
|         _gen("&& (");
 | |
|         MR_genMultiLine(tree->down,k+1);
 | |
|         _gen(")");
 | |
|       };
 | |
|     };
 | |
|     if (tree->right != NULL) {
 | |
|       if (k < lastkonline) {
 | |
|         _gen("\n");
 | |
|         across=0;
 | |
|         lastkonline=0;
 | |
|         for (i=0; i < depth+k-1 ; i++) _gen("   ");
 | |
|         _gen("||");
 | |
|       } else if (across > 3 ) {
 | |
|         _gen("\n");
 | |
|         across=0;
 | |
|         lastkonline=0;
 | |
|         for (i=0; i < depth+k ; i++) _gen("   ");
 | |
|         _gen("||");
 | |
|       } else {
 | |
|         _gen(" ||");
 | |
|       };
 | |
|       MR_genMultiLine(tree->right,k);
 | |
|     };
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static void genExprTree(Tree *tree,int k)
 | |
| #else
 | |
| static void genExprTree(tree,k)
 | |
|   Tree  *tree;
 | |
|   int   k;
 | |
| #endif
 | |
| {
 | |
|     int     count;
 | |
| 
 | |
| #if 0
 | |
|     /* MR20 THM This was probably an error.
 | |
|             The routine should probably reference that static 
 | |
|             "across" and this declaration hides it.
 | |
|     */
 | |
| 
 | |
|     int     across;
 | |
| #endif
 | |
|   
 | |
|     require (tree != NULL,"genExprTree: tree is NULL");
 | |
|     require (k > 0,"genExprTree: k <= 0");
 | |
| 
 | |
|     if (0 && !MRhoisting) {   /* MR11 make new version standard */
 | |
|       genExprTreeOriginal(tree,k);
 | |
|     } else {
 | |
|       count=MR_countLeaves(tree);
 | |
|       if (count < 5) {
 | |
|         MR_genOneLine(tree,k);
 | |
|       } else {
 | |
|         _gen("\n");
 | |
|         across=0;
 | |
|         depth=0;
 | |
|         lastkonline=0;
 | |
|         MR_genMultiLine(tree,k);
 | |
|         _gen("\n");
 | |
|       };
 | |
|     };
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * Generate LL(k) type expressions of the form:
 | |
|  *
 | |
|  *		 (LA(1) == T1 || LA(1) == T2 || ... || LA(1) == Tn) &&
 | |
|  *		 (LA(2) == T1 || LA(2) == T2 || ... || LA(2) == Tn) &&
 | |
|  *			.....
 | |
|  *		 (LA(k) == T1 || LA(k) == T2 || ... || LA(k) == Tn)
 | |
|  *
 | |
|  * If GenExprSetsOpt generate:
 | |
|  *
 | |
|  *		(setwdi[LA(1)]&(1<<j)) && (setwdi[LA(2)]&(1<<j)) ...
 | |
|  *
 | |
|  * where n is set_deg(expr) and Ti is some random token and k is the last nonempty
 | |
|  * set in fset <=CLL_k.
 | |
|  * k=1..CLL_k where CLL_k >= 1.
 | |
|  *
 | |
|  * This routine is visible only to this file and cannot answer a TRANS message.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| /*  [genExpr] */
 | |
| 
 | |
| static int
 | |
| #ifdef __USE_PROTOS
 | |
| genExpr( Junction *j )
 | |
| #else
 | |
| genExpr( j )
 | |
| Junction *j;
 | |
| #endif
 | |
| {
 | |
| 	int max_k;
 | |
| 
 | |
| 	/* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead
 | |
| 	 * from CLL_k..LL_k
 | |
| 	 */
 | |
| 	{
 | |
| 		int limit;
 | |
| 		if ( j->ftree!=NULL ) limit = LL_k;
 | |
| 		else limit = CLL_k;
 | |
| 		max_k = genExprSets(j->fset, limit);
 | |
| 	}
 | |
| 
 | |
| 	/* Do tests for real tuples from other productions that conflict with
 | |
| 	 * artificial tuples generated by compression (using sets of tokens
 | |
| 	 * rather than k-trees).
 | |
| 	 */
 | |
| 	if ( j->ftree != NULL )
 | |
| 	{
 | |
| 		_gen(" && !("); genExprTree(j->ftree, 1); _gen(")");
 | |
| 	}
 | |
| 
 | |
| 	if ( ParseWithPredicates && j->predicate!=NULL )
 | |
| 	{
 | |
| 		Predicate *p = j->predicate;
 | |
| 		warn_about_using_gk_option();
 | |
| 		_gen("&&");
 | |
| 		j->predicate=genPredTreeMain(p, (Node *)j);     /* MR10 */
 | |
| 	}
 | |
| 
 | |
| 	return max_k;
 | |
| }
 | |
| 
 | |
| static int
 | |
| #ifdef __USE_PROTOS
 | |
| genExprSets( set *fset, int limit )
 | |
| #else
 | |
| genExprSets( fset, limit )
 | |
| set *fset;
 | |
| int limit;
 | |
| #endif
 | |
| {
 | |
| 	int k = 1;
 | |
| 	int max_k = 0;
 | |
| 	unsigned *e, *g, firstTime=1;
 | |
| 
 | |
|     if (set_nil(fset[1])) {
 | |
|       _gen(" 0 /* MR13 empty set expression  - undefined rule ? infinite left recursion ? */ ");
 | |
|       MR_BadExprSets++;
 | |
|     };
 | |
| 
 | |
| 	if ( GenExprSetsOpt )
 | |
| 	{
 | |
| 		while ( k <= limit && !set_nil(fset[k]) )   /* MR11 */
 | |
| 		{
 | |
| 			if ( set_deg(fset[k])==1 )	/* too simple for a set? */
 | |
| 			{
 | |
| 				int e;
 | |
| 				_gen1("(LA(%d)==",k);
 | |
| 				e = set_int(fset[k]);
 | |
| 				if ( TokenString(e) == NULL ) _gen1("%d)", e)
 | |
| 				else _gen1("%s)", TokenString(e));
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				NewSet();
 | |
| 				FillSet( fset[k] );
 | |
| 				_gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<<setnum);
 | |
| 			}
 | |
| 			if ( k>max_k ) max_k = k;
 | |
| 			if ( k == CLL_k ) break;
 | |
| 			k++;
 | |
| 			if ( k<=limit && !set_nil(fset[k]) ) _gen(" && ");  /* MR11 */
 | |
| 			on1line++;
 | |
| 			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
 | |
| 		}
 | |
| 		return max_k;
 | |
| 	}
 | |
| 
 | |
| 	while ( k<= limit &&  !set_nil(fset[k]) )       /* MR11 */
 | |
| 	{
 | |
| 		if ( (e=g=set_pdq(fset[k])) == NULL ) fatal_internal("genExpr: cannot allocate IF expr pdq set");
 | |
| 		for (; *e!=nil; e++)
 | |
| 		{
 | |
| 			if ( !firstTime ) _gen(" || ") else { _gen("("); firstTime = 0; }
 | |
| 			on1line++;
 | |
| 			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
 | |
| 			_gen1("LA(%d)==",k);
 | |
| 			if ( TokenString(*e) == NULL ) _gen1("%d", *e)
 | |
| 			else _gen1("%s", TokenString(*e));
 | |
| 		}
 | |
| 		free( (char *)g );
 | |
| 		_gen(")");
 | |
| 		if ( k>max_k ) max_k = k;
 | |
| 		if ( k == CLL_k ) break;
 | |
| 		k++;
 | |
| 		if ( k <= limit && !set_nil(fset[k]) ) { firstTime=1; _gen(" && "); }   /* MR11 */
 | |
| 		on1line++;
 | |
| 		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
 | |
| 	}
 | |
| 	return max_k;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate code for any type of block.  If the last alternative in the block is
 | |
|  * empty (not even an action) don't bother doing it.  This permits us to handle
 | |
|  * optional and loop blocks as well.
 | |
|  *
 | |
|  * Only do this block, return after completing the block.
 | |
|  * This routine is visible only to this file and cannot answer a TRANS message.
 | |
|  */
 | |
| static set
 | |
| #ifdef __USE_PROTOS
 | |
| genBlk( Junction *q, int jtype, int *max_k, int *need_right_curly, int * lastAltEmpty /* MR23 */)
 | |
| #else
 | |
| genBlk( q, jtype, max_k, need_right_curly, lastAltEmpty /* MR23 */)
 | |
| Junction *q;
 | |
| int jtype;
 | |
| int *max_k;
 | |
| int *need_right_curly;
 | |
| int *lastAltEmpty; /* MR23 */
 | |
| #endif
 | |
| {
 | |
| 	set f;
 | |
| 	Junction *alt;
 | |
| 	int a_guess_in_block = 0;
 | |
| 	require(q!=NULL,				"genBlk: invalid node");
 | |
| 	require(q->ntype == nJunction,	"genBlk: not junction");
 | |
| 	*need_right_curly=0;
 | |
| 	*lastAltEmpty = 0;		/* MR23 */
 | |
| 	if ( q->p2 == NULL )	/* only one alternative?  Then don't need if */
 | |
| 	{	
 | |
| 		if (first_item_is_guess_block((Junction *)q->p1)!=NULL )
 | |
| 		{
 | |
|             if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) {
 | |
|   			  warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line);
 | |
|             };
 | |
|    	   	    gen("zzGUESS\n");	/* guess anyway to make output code consistent */
 | |
| /* MR10 disable */  /**** gen("if ( !zzrv )\n"); ****/
 | |
| /* MR10 */          gen("if ( !zzrv ) {\n"); tabs++; (*need_right_curly)++;
 | |
|         };
 | |
| 		TRANS(q->p1);
 | |
| 		return empty;		/* no decision to be made-->no error set */
 | |
| 	}
 | |
| 
 | |
| 	f = First(q, 1, jtype, max_k);
 | |
| 	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
 | |
| 	{
 | |
| 		if ( alt->p2 == NULL )					/* chk for empty alt */
 | |
| 		{	
 | |
| 			Node *p = alt->p1;
 | |
| 			if ( p->ntype == nJunction )
 | |
| 			{
 | |
| 				/* we have empty alt */
 | |
| /* MR23
 | |
|    There is a conflict between giving good error information for non-exceptions
 | |
|    and making life easy for those using parser exception handling.  Consider:
 | |
| 
 | |
|          r: { A } b;
 | |
| 		 b: B;
 | |
| 		 
 | |
| 		   with input "C"
 | |
| 
 | |
|    Before MR21 the error message would be "expecting B - found C".  After MR21
 | |
|    the error message would be "expect A, B - found C".  This was good, but it
 | |
|    caused problems for those using parser exceptions because the reference to
 | |
|    B was generated inside the {...} where B really wasn't part of the block.
 | |
| 
 | |
|    In MR23 this has been changed for the case where exceptions are in use to
 | |
|    not generate the extra check in the tail of the {A} block.
 | |
| */
 | |
| 
 | |
| 
 | |
| /* MR23 */	if (isEmptyAlt( ((Junction *)p)->p1, (Node *)q->end)) {
 | |
| /* MR23 */      *lastAltEmpty = 1;
 | |
| /* MR23 */		if (FoundException) {
 | |
| /* MR23 */			/* code to restore state if a prev alt didn't follow guess */
 | |
| /* MR23 */			if ( a_guess_in_block && jtype != aPlusBlk) {
 | |
| /* MR23 */				gen("if ( !zzrv ) zzGUESS_DONE; /* MR28 */\n");
 | |
| /* MR23 */			}
 | |
| /* MR23 */			break;
 | |
| /* MR23 */		};
 | |
| /* MR28 */      if (jtype == aPlusBlk) {
 | |
| /* MR28 */          break;
 | |
| /* MR28 */      }
 | |
| /* MR23 */	}
 | |
| 		}
 | |
| 	} /* end of for loop on alt */
 | |
| 
 | |
| /* MR10 */        if (alt->p2 == NULL &&
 | |
| /* MR10 */               ( q->jtype == aSubBlk || q->jtype == RuleBlk) ) {
 | |
| /* MR10 */          if (first_item_is_guess_block(alt)) {
 | |
| /* MR10 */               warnFL("(...)? as last alternative of block is unnecessary",
 | |
| /* MR10 */                                FileStr[alt->file],alt->line);
 | |
| /* MR10 */          };
 | |
| /* MR10 */        };
 | |
| 
 | |
| 		if ( alt != q ) gen("else ")
 | |
| 		else
 | |
| 		{
 | |
| 			if ( DemandLookahead ) {
 | |
| 				if ( !GenCC ) {gen1("LOOK(%d);\n", *max_k);}
 | |
| 				else gen1("look(%d);\n", *max_k);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if ( alt!=q )
 | |
| 		{
 | |
| 			_gen("{\n");
 | |
| 			tabs++;
 | |
| 			(*need_right_curly)++;
 | |
| 			/* code to restore state if a prev alt didn't follow guess */
 | |
| 			if ( a_guess_in_block )
 | |
| 				gen("if ( !zzrv ) zzGUESS_DONE;\n");
 | |
| 		}
 | |
| 		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL )
 | |
| 		{
 | |
| 			a_guess_in_block = 1;
 | |
| 			gen("zzGUESS\n");
 | |
| 		}
 | |
| 		gen("if ( ");
 | |
| 		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) _gen("!zzrv && ");
 | |
| 		genExpr(alt);
 | |
| 		_gen(" ) ");
 | |
| 		_gen("{\n");
 | |
| 		tabs++;
 | |
| 		TRANS(alt->p1);
 | |
| 		--tabs;
 | |
| 		gen("}\n");
 | |
| /* MR10 */        if (alt->p2 == NULL) {
 | |
| /* MR10 */          if (first_item_is_guess_block(alt)) {
 | |
| /* MR10 */            gen("/* MR10 */ else {\n");
 | |
| /* MR10 */            tabs++;
 | |
| /* MR10 */  		  (*need_right_curly)++;
 | |
| /* MR10 */  		  /* code to restore state if a prev alt didn't follow guess */
 | |
| /* MR10 */            gen("/* MR10 */ if ( !zzrv ) zzGUESS_DONE;\n");
 | |
| /* MR10 */            gen("/* MR10 */ if (0) {}     /* last alternative of block is guess block */\n");
 | |
| /* MR10 */          };
 | |
| /* MR10 */        };
 | |
| 	}
 | |
| 	return f;
 | |
| }
 | |
| 
 | |
| static int
 | |
| #ifdef __USE_PROTOS
 | |
| has_guess_block_as_first_item( Junction *q )
 | |
| #else
 | |
| has_guess_block_as_first_item( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	Junction *alt;
 | |
| 
 | |
| 	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
 | |
| 	{
 | |
| 		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) return 1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| #ifdef __USE_PROTOS
 | |
| has_guess_block_as_last_item( Junction *q )
 | |
| #else
 | |
| has_guess_block_as_last_item( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	Junction *alt;
 | |
| 
 | |
|     if (q == NULL) return 0;
 | |
| 	for (alt=q; alt->p2 != NULL && !( (Junction *) alt->p2)->ignore; alt= (Junction *) alt->p2 ) {};
 | |
|     return first_item_is_guess_block( (Junction *) alt->p1) != NULL;
 | |
| }
 | |
| 
 | |
| /* MR30 See description of first_item_is_guess_block for background */
 | |
| 
 | |
| Junction *
 | |
| #ifdef __USE_PROTOS
 | |
| first_item_is_guess_block_extra(Junction *q )
 | |
| #else
 | |
| first_item_is_guess_block_extra(q)
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	while ( q!=NULL &&
 | |
|             (  ( q->ntype==nAction ) ||
 | |
|                ( q->ntype==nJunction &&
 | |
|                     (q->jtype==Generic || q->jtype == aLoopBlk) 
 | |
|                )
 | |
|             )
 | |
|           )
 | |
| 	{
 | |
| 		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
 | |
| 		else q = (Junction *) ((ActionNode *)q)->next;
 | |
| 	}
 | |
| 
 | |
| 	if ( q==NULL ) return NULL;
 | |
| 	if ( q->ntype!=nJunction ) return NULL;
 | |
| 	if ( q->jtype!=aSubBlk ) return NULL;
 | |
| 	if ( !q->guess ) return NULL;
 | |
| 
 | |
| 	return q;
 | |
| }
 | |
| 
 | |
| /* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node
 | |
|  * of (...)?;  This function ignores actions and predicates.
 | |
|  */
 | |
| 
 | |
| Junction *
 | |
| #ifdef __USE_PROTOS
 | |
| first_item_is_guess_block( Junction *q )
 | |
| #else
 | |
| first_item_is_guess_block( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	Junction * qOriginal = q;	/* DEBUG */
 | |
| 
 | |
|     /* MR14  Couldn't find aSubBlock which was a guess block when it lay
 | |
|              behind aLoopBlk.  The aLoopBlk only appear in conjunction with
 | |
|              aLoopBegin, but the routine didn't know that.  I think.
 | |
| 
 | |
|        MR14a Added extra parentheses to clarify precedence
 | |
| 
 | |
| 	   MR30  This appears to have been a mistake.  The First set was then
 | |
| 	         computed incorrectly for:
 | |
| 
 | |
| 					r : ( (A)? B
 | |
| 					    | C
 | |
| 						)*
 | |
| 			 
 | |
| 			 The routine analysis_point was seeing the guess block when
 | |
| 			 it was still analyzing the loopBegin block.  As a consequence,
 | |
| 			 when it looked for the analysis_point it was processing the B, but
 | |
| 			 skipping over the C alternative altogether because it thought
 | |
| 			 it was looking at a guess block, not realizing there was a loop
 | |
| 			 block in front of the loopBegin.
 | |
| 
 | |
|              loopBegin  loopBlk  subBlk/guess  A  G  EB  G  B EB EB  EB  ER
 | |
| 			    |          |          |                     ^   ^
 | |
| 				|		   |                                |   |
 | |
|                 |          +-> G  C G ----------------------+   |
 | |
|                 |                                               |
 | |
| 				+--- G G G -------------------------------------+
 | |
|     
 | |
| 			 Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu).
 | |
| 
 | |
| 		MR30  This is still more complicated.  This fix caused ambiguity messages
 | |
| 		to be reported for "( (A B)? )* A B" but not for "( (A B)? )+".  Why is
 | |
| 		there a difference when these are outwardly identical ?  It is because the
 | |
| 		start of a (...)* block is represented by two nodes: a loopBegin block
 | |
| 		followed by a loopBlock whereas the start of a (...)+ block is
 | |
| 		represented as a single node: a plusBlock.  So if first_item_is_guess_block
 | |
| 		is called when the current node is a loopBegin it starts with the
 | |
| 		loop block rather than the sub block which follows the loop block.
 | |
| 		However, we can't just skip past the loop block because some routines
 | |
| 		depend on the old implementation.  So, we provide a new implementation
 | |
| 		which does skip the loopBlock.  However, which should be called when ?
 | |
| 		I'm not sure, but my guess is that first_item_is_guess_block_extra (the
 | |
| 		new one) should only be called for the ambiguity routines.
 | |
| 
 | |
|     */
 | |
| 
 | |
| 	while ( q!=NULL &&
 | |
|             (  ( q->ntype==nAction ) ||
 | |
|                ( q->ntype==nJunction &&
 | |
|                     (q->jtype==Generic /*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/
 | |
|                )
 | |
|             )
 | |
|           )
 | |
| 	{
 | |
| 		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
 | |
| 		else q = (Junction *) ((ActionNode *)q)->next;
 | |
| 	}
 | |
| 
 | |
| 	if ( q==NULL ) return NULL;
 | |
| 	if ( q->ntype!=nJunction ) return NULL;
 | |
| 	if ( q->jtype!=aSubBlk ) return NULL;
 | |
| 	if ( !q->guess ) return NULL;
 | |
| 
 | |
| 	return q;
 | |
| }
 | |
| 
 | |
| /* MR1				                 					    */
 | |
| /* MR1  10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs  */
 | |
| /* MR1				                                                        */
 | |
| 
 | |
| #define STRINGIZEBUFSIZE 1024
 | |
| 
 | |
| static char stringizeBuf[STRINGIZEBUFSIZE];
 | |
| char *
 | |
| #ifdef __USE_PROTOS
 | |
| stringize(char * s)
 | |
| #else
 | |
| stringize(s)
 | |
| char *s;
 | |
| #endif
 | |
| 
 | |
| {
 | |
|   char		*p;
 | |
|   char		*stop;
 | |
| 
 | |
|   p=stringizeBuf;
 | |
|   stop=&stringizeBuf[1015];
 | |
| 
 | |
|   if (s != 0) {
 | |
|     while (*s != 0) {
 | |
|       if (p >= stop) {
 | |
| 	goto stringizeStop;
 | |
|       } else if (*s == '\n') {
 | |
|         *p++='\\';
 | |
|         *p++='n';
 | |
|         *p++='\\';
 | |
| 	*p++=*s++;
 | |
|       } else if (*s == '\\') {
 | |
| 	*p++=*s;
 | |
| 	*p++=*s++;
 | |
|       } else if (*s == '\"') {
 | |
|         *p++='\\';
 | |
| 	*p++=*s++;
 | |
|         while (*s != 0) {
 | |
|           if (p >= stop) {
 | |
| 	     goto stringizeStop;
 | |
| 	  } else if (*s == '\n') {
 | |
| 	    *p++='\\';
 | |
| 	    *p++=*s++;
 | |
| 	  } else if (*s == '\\') {
 | |
| 	    *p++=*s++;
 | |
| 	    *p++=*s++;
 | |
| 	  } else if (*s == '\"') {
 | |
| 	    *p++='\\';
 | |
| 	    *p++=*s++;
 | |
| 	    break;
 | |
| 	  } else {
 | |
| 	    *p++=*s++;
 | |
|           };
 | |
|         };
 | |
|       } else if (*s == '\'') {
 | |
| 	*p++=*s++;
 | |
|         while (*s != 0) {
 | |
|           if (p >= stop) {
 | |
| 	     goto stringizeStop;
 | |
| 	  } else if (*s == '\'') {
 | |
| 	    *p++=*s++;
 | |
| 	    break;
 | |
| 	  } else if (*s == '\\') {
 | |
| 	    *p++=*s++;
 | |
| 	    *p++=*s++;
 | |
| 	  } else if (*s == '\"') {
 | |
| 	    *p++='\\';
 | |
| 	    *p++=*s++;
 | |
| 	    break;
 | |
| 	  } else {
 | |
| 	    *p++=*s++;
 | |
|           };
 | |
|         };
 | |
|       } else {
 | |
|         *p++=*s++;
 | |
|       };
 | |
|     };
 | |
|   };
 | |
|   goto stringizeExit;
 | |
| stringizeStop:
 | |
|   *p++='.';        	
 | |
|   *p++='.';        	
 | |
|   *p++='.';        	
 | |
| stringizeExit:
 | |
|   *p=0;
 | |
|   return stringizeBuf;
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| int isNullAction(char *s)
 | |
| #else
 | |
| int isNullAction(s)
 | |
|   char  *s;
 | |
| #endif
 | |
| {
 | |
|   char  *p;
 | |
|   for (p=s; *p != '\0' ; p++) {
 | |
|     if (*p != ';' && *p !=' ') return 0;
 | |
|   };
 | |
|   return 1;
 | |
| }
 | |
| /* MR1									                                    */
 | |
| /* MR1	End of Routine to stringize code for failed predicates msgs         */
 | |
| /* MR1				                                                        */
 | |
| 
 | |
| /* Generate an action.  Don't if action is NULL which means that it was already
 | |
|  * handled as an init action.
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genAction( ActionNode *p )
 | |
| #else
 | |
| genAction( p )
 | |
| ActionNode *p;
 | |
| #endif
 | |
| {
 | |
| 	require(p!=NULL,			"genAction: invalid node and/or rule");
 | |
| 	require(p->ntype==nAction,	"genAction: not action");
 | |
| 
 | |
| 	if ( !p->done )  /* MR10 */ /* MR11 */
 | |
| 	{
 | |
| 		if ( p->is_predicate)
 | |
| 		{
 | |
| 			if ( p->guardpred != NULL )
 | |
| 			{
 | |
|                 Predicate *guardDup=predicate_dup(p->guardpred); /* MR10 */
 | |
|                 gen("if (!");
 | |
|        			guardDup=genPredTreeMain(guardDup, (Node *)p);
 | |
|                 predicate_free(guardDup);
 | |
| 			}
 | |
| /* MR10 */  else if (p->ampersandPred != NULL) {
 | |
| /* MR10 */      gen("if (!");
 | |
| /* MR10 */      p->ampersandPred=genPredTreeMain(p->ampersandPred, (Node *)p);
 | |
| /* MR10 */  }
 | |
| 			else
 | |
| 			{
 | |
| 				gen("if (!(");
 | |
| 				/* make sure that '#line n' is on front of line */
 | |
| 				if ( GenLineInfo && p->file != -1 ) _gen("\n");
 | |
| 				dumpPredAction(p,p->action, output, 0, p->file, p->line, 0);
 | |
| 				_gen(")");
 | |
| 			}
 | |
| 
 | |
| /* MR23 Change failed predicate macro to have three arguments:
 | |
| 
 | |
|         macro arg 1: The stringized predicate itself
 | |
|         macro arg 2: 0 => no user-defined error action
 | |
|                      1 => user-defined error action
 | |
|         macro arg 3: The user-defined error action
 | |
| 
 | |
|    This gives the user more control of the error action.
 | |
| */
 | |
| 			tabs++;
 | |
| 			gen3(") {zzfailed_pred(\"%s\",%s, { %s } );}\n",         /* MR23 */
 | |
| 					stringize(p->action),	                         /* MR23 */
 | |
|                     (p->pred_fail == NULL ?                          /* MR23/MR27 */
 | |
|                        	"0 /* report */" : "1 /* user action */"),   /* MR23/MR27 */
 | |
|                     (p->pred_fail == NULL ?                          /* MR23 */
 | |
|                         "; /* no user action */" : p->pred_fail));   /* MR23 */
 | |
| 			tabs--;
 | |
| 		}
 | |
| 		else    /* not a predicate */
 | |
| 		{
 | |
|             if (! isNullAction(p->action) && !p->noHoist) {
 | |
|   	  		  if ( FoundGuessBlk ) {
 | |
| 				if ( GenCC ) {
 | |
|                   gen("if ( !guessing ) {\n");
 | |
|                 } else {
 | |
| 				  gen("zzNON_GUESS_MODE {\n");
 | |
|                 };
 | |
|               };
 | |
| 			  dumpActionPlus(p, p->action, output, tabs, p->file, p->line, 1); /* MR21 */
 | |
| 			  if ( FoundGuessBlk ) gen("}\n");
 | |
|             };
 | |
| 		}
 | |
| 	}
 | |
| 	TRANS(p->next)
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *		if invoking rule has !noAST pass zzSTR to rule ref and zzlink it in
 | |
|  *		else pass addr of temp root ptr (&_ast) (don't zzlink it in).
 | |
|  *
 | |
|  *		if ! modifies rule-ref, then never link it in and never pass zzSTR.
 | |
|  *		Always pass address of temp root ptr.
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genRuleRef( RuleRefNode *p )
 | |
| #else
 | |
| genRuleRef( p )
 | |
| RuleRefNode *p;
 | |
| #endif
 | |
| {
 | |
| 	Junction *q;
 | |
| 	char *handler_id = "";
 | |
| 	RuleEntry *r, *r2;
 | |
| 	char *parm = "", *exsig = "";
 | |
| 
 | |
|     int     genRuleRef_emittedGuessGuard=0;     /* MR10 */
 | |
| 
 | |
| 	require(p!=NULL,			"genRuleRef: invalid node and/or rule");
 | |
| 	require(p->ntype==nRuleRef, "genRuleRef: not rule reference");
 | |
| 	
 | |
| 	if ( p->altstart!=NULL && p->altstart->exception_label!=NULL )
 | |
| 		handler_id = p->altstart->exception_label;
 | |
| 
 | |
| 	r = (RuleEntry *) hash_get(Rname, p->text);
 | |
| 	if ( r == NULL )
 | |
| 	{
 | |
| 		warnFL( eMsg1("rule %s not defined",
 | |
| 					  p->text), FileStr[p->file], p->line );
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| /* MR8 5-Aug-97     Reported by S.Bochnak@microtool.com.pl                  */
 | |
| /*                  Don't do assign when no return values declared          */
 | |
| /*                  Move definition of q up and use it to guard p->assign   */
 | |
| 
 | |
| 	q = RulePtr[r->rulenum];	/* find definition of ref'd rule */  /* MR8 */
 | |
| 
 | |
| 	r2 = (RuleEntry *) hash_get(Rname, p->rname);
 | |
| 	if ( r2 == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}
 | |
| 
 | |
|     OutLineInfo(output,p->line,FileStr[p->file]);
 | |
| 
 | |
| 	if ( GenCC && GenAST ) {
 | |
| 		gen("_ast = NULL;\n");
 | |
| 	}
 | |
| 
 | |
| 	if ( FoundGuessBlk && p->assign!=NULL && q->ret != NULL ) {      /* MR8 */
 | |
| 		if ( GenCC ) {
 | |
|           gen("if ( !guessing ) {\n");
 | |
|         } else {
 | |
|           gen("zzNON_GUESS_MODE {\n");
 | |
|         };
 | |
|         tabs++;                                                      /* MR11 */
 | |
|         genRuleRef_emittedGuessGuard=1;                              /* MR11 */
 | |
|     };
 | |
| 
 | |
| 	if ( FoundException ) exsig = "&_signal";
 | |
| 
 | |
| 	tab();
 | |
| 	if ( GenAST )
 | |
| 	{
 | |
| 		if ( GenCC ) {
 | |
| /****			if ( r2->noAST || p->astnode==ASTexclude )
 | |
| ****/
 | |
| 			{
 | |
| /****				_gen("_ast = NULL;\n");
 | |
| ****/
 | |
| 				parm = "&_ast";
 | |
| 			}
 | |
| /*** we always want to set just a pointer now, then set correct
 | |
| pointer after
 | |
| 
 | |
| 			else {
 | |
| 				_gen("_astp =
 | |
| (_tail==NULL)?(&_sibling):(&(_tail->_right));\n");
 | |
| 				parm = "_astp";
 | |
| 			}
 | |
| ****/
 | |
| 		}
 | |
| 		else {
 | |
| 			if ( r2->noAST || p->astnode==ASTexclude )
 | |
| 			{
 | |
| 				_gen("_ast = NULL; ");
 | |
| 				parm = "&_ast";
 | |
| 			}
 | |
| 			else parm = "zzSTR";
 | |
| 		}
 | |
| 		if ( p->assign!=NULL && q->ret!=NULL )                       /* MR8 */
 | |
| 		{
 | |
| 			if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */
 | |
| 			else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum);
 | |
| 		}
 | |
| 		if ( FoundException ) {
 | |
| 			_gen5("%s%s(%s,&_signal%s%s); ",
 | |
| 				  RulePrefix,
 | |
| 				  p->text,
 | |
| 				  parm,
 | |
| 				  (p->parms!=NULL)?",":"",
 | |
| 				  (p->parms!=NULL)?p->parms:"");
 | |
| 			if ( p->ex_group!=NULL ) {
 | |
| 				_gen("\n");
 | |
| 				gen("if (_signal) {\n");
 | |
| 				tabs++;
 | |
| 				dumpException(p->ex_group, 0);
 | |
| 				tabs--;
 | |
| 				gen("}");
 | |
| 			}
 | |
| 			else {
 | |
| 				_gen1("if (_signal) goto %s_handler;", handler_id);
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			_gen5("%s%s(%s%s%s);",
 | |
| 				  RulePrefix,
 | |
| 				  p->text,
 | |
| 				  parm,
 | |
| 				  (p->parms!=NULL)?",":"",
 | |
| 				  (p->parms!=NULL)?p->parms:"");
 | |
| 		}
 | |
| 		if ( GenCC && (r2->noAST || p->astnode==ASTexclude) )
 | |
| 		{
 | |
| 			/* rule has a ! or element does */
 | |
| 			/* still need to assign to #i so we can play with it */
 | |
| 			_gen("\n");
 | |
| 			gen2("_ast%d%d = (AST *)_ast;", BlkLevel-1, p->elnum);
 | |
| 		}
 | |
| 		else if ( !r2->noAST && p->astnode == ASTinclude )
 | |
| 		{
 | |
| 			/* rule doesn't have a ! and neither does element */
 | |
| /* MR10 */  if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) {
 | |
| /* MR10 */    _gen("\n");
 | |
| /* MR10 */    if (GenCC) gen ("if (!guessing) {    /* MR10 */")
 | |
| /* MR10 */          else gen ("if (!zzguessing) {    /* MR10 */\n");
 | |
| /* MR10 */    tabs++;
 | |
| /* MR10 */  };
 | |
| 			if ( GenCC ) {
 | |
| 				_gen("\n");
 | |
| 				gen("if ( _tail==NULL ) _sibling = _ast; else _tail->setRight(_ast);\n");
 | |
| 				gen2("_ast%d%d = (AST *)_ast;\n", BlkLevel-1, p->elnum);
 | |
| 				tab();
 | |
| 			}
 | |
| 			else _gen(" ");
 | |
|             if ( GenCC ) {
 | |
|                 _gen("ASTBase::"); }
 | |
|                 else _gen("zz");
 | |
| 			_gen("link(_root, &_sibling, &_tail);");
 | |
| 
 | |
| /* MR10 */  if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) {     /* MR10 */
 | |
| /* MR10 */    _gen("\n");
 | |
| /* MR10 */    tabs--;
 | |
| /* MR10 */    if (GenCC) gen ("};    /* MR10 */")
 | |
| /* MR10 */          else gen ("};    /* MR10 */");
 | |
| /* MR10 */  };
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if ( p->assign!=NULL && q->ret!=NULL )                       /* MR8 */
 | |
| 		{
 | |
| 			if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */
 | |
| 			else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum);
 | |
| 		}
 | |
| 		if ( FoundException ) {
 | |
| 			_gen4("%s%s(&_signal%s%s); ",
 | |
| 				  RulePrefix,
 | |
| 				  p->text,
 | |
| 				  (p->parms!=NULL)?",":"",
 | |
| 				  (p->parms!=NULL)?p->parms:"");
 | |
| 			if ( p->ex_group!=NULL ) {
 | |
| 				_gen("\n");
 | |
| 				gen("if (_signal) {\n");
 | |
| 				tabs++;
 | |
| 				dumpException(p->ex_group, 0);
 | |
| 				tabs--;
 | |
| 				gen("}");
 | |
| 			}
 | |
| 			else {
 | |
| 				_gen1("if (_signal) goto %s_handler;", handler_id);
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			_gen3("%s%s(%s);",
 | |
| 				  RulePrefix,
 | |
| 				  p->text,
 | |
| 				  (p->parms!=NULL)?p->parms:"");
 | |
| 		}
 | |
| 		if ( p->assign!=NULL && q->ret!=NULL ) _gen("\n");           /* MR8 */
 | |
| 	}
 | |
| 
 | |
| 	if ( p->assign!=NULL && q->ret!=NULL) {                          /* MR8 */
 | |
| 		if ( hasMultipleOperands(p->assign) )                        /* MR23 */
 | |
| 		{
 | |
| 			_gen("\n");
 | |
| 			dumpRetValAssign(p->assign, q->ret, p);                  /* MR30 */
 | |
| 			_gen("}");
 | |
| 		}
 | |
| 	}
 | |
| 	_gen("\n");
 | |
| 
 | |
| 	/* Handle element labels now */
 | |
| 	if ( p->el_label!=NULL )
 | |
| 	{
 | |
| 		if ( GenAST )
 | |
| 		{
 | |
| 			if ( GenCC ) {
 | |
| 				gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
 | |
| 			}
 | |
| 			else {gen1("%s_ast = zzastCur;\n", p->el_label);}
 | |
| 		}
 | |
|        	else if (!GenCC ) {
 | |
| 			gen1("%s = zzaCur;\n", p->el_label);
 | |
|         }
 | |
| 	}
 | |
| 
 | |
| 	if ( FoundGuessBlk && p->assign!=NULL && q->ret!=NULL ) {       /* MR8 */
 | |
| 		/* in guessing mode, don't branch to handler upon error */
 | |
|         tabs--;                                                     /* MR11 */
 | |
| 		gen("} else {\n");
 | |
|         tabs++;                                                     /* MR11 */
 | |
| 		if ( FoundException ) {
 | |
| 			gen6("%s%s(%s%s&_signal%s%s);\n",
 | |
| 				 RulePrefix,
 | |
| 				 p->text,
 | |
| 				 parm,
 | |
|                  (*parm!='\0')?",":"",
 | |
|                  (p->parms!=NULL)?",":"",
 | |
| 				 (p->parms!=NULL)?p->parms:"");
 | |
| 		}
 | |
| 		else {
 | |
| 			gen5("%s%s(%s%s%s);\n",
 | |
| 				 RulePrefix,
 | |
| 				 p->text,
 | |
| 				 parm,
 | |
| 				 (p->parms!=NULL && *parm!='\0')?",":"",
 | |
| 				 (p->parms!=NULL)?p->parms:"");
 | |
| 		}
 | |
|         tabs--;                                                     /* MR11 */
 | |
| 		gen("}\n");
 | |
| 	}
 | |
| 	TRANS(p->next)
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate code to match a token.
 | |
|  *
 | |
|  * Getting the next token is tricky.  We want to ensure that any action
 | |
|  * following a token is executed before the next GetToken();
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genToken( TokNode *p )
 | |
| #else
 | |
| genToken( p )
 | |
| TokNode *p;
 | |
| #endif
 | |
| {
 | |
| 	RuleEntry *r;
 | |
| 	char *handler_id = "";
 | |
| 	ActionNode *a;
 | |
| 	char *set_name;
 | |
| 	char *set_nameErrSet;
 | |
| 	int complement;
 | |
| 	int ast_label_in_action = 0;	/* MR27 */
 | |
| 	int pushedCmodeAST = 0;			/* MR27 */
 | |
| 
 | |
| 	require(p!=NULL,			"genToken: invalid node and/or rule");
 | |
| 	require(p->ntype==nToken,	"genToken: not token");
 | |
| 	if ( p->altstart!=NULL && p->altstart->exception_label!=NULL )
 | |
| 		handler_id = p->altstart->exception_label;
 | |
| 
 | |
| 	r = (RuleEntry *) hash_get(Rname, p->rname);
 | |
| 	if ( r == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}
 | |
| 
 | |
| /*
 | |
|  * MR27 Has the element label been referenced as an AST (with the # operator) ?
 | |
|  *      If so, then we'll want to build the AST even though the user has used
 | |
|  *      the ! operator.
 | |
|  */
 | |
| /* MR27 */	if (GenAST && p->el_label != NULL) {
 | |
| /* MR27 */		ast_label_in_action = list_search_cstring(r->ast_labels_in_actions,
 | |
| /* MR27 */		                                          p->el_label);
 | |
| /* MR27 */	}
 | |
| 	
 | |
|     OutLineInfo(output,p->line,FileStr[p->file]);
 | |
| 
 | |
| 	if ( !set_nil(p->tset) )	/* implies '.', ~Tok, or tokenclass */
 | |
| 	{
 | |
| 		unsigned e;
 | |
| 		unsigned eErrSet = 0;
 | |
| 		set b;
 | |
| 		set bErrSet;					/* MR23 */
 | |
| 		b = set_dup(p->tset);
 | |
| 		bErrSet = set_dup(p->tset);	    /* MR23 */
 | |
| 		complement = p->complement; /* MR23 */
 | |
| 		if ( p->tclass!=NULL  && complement == 0 /* MR23 */) { /* token class not complemented*/
 | |
| 			static char buf[MaxRuleName+20];	    /* MR23 */
 | |
| 			static char bufErrSet[MaxRuleName+20];	/* MR23 */
 | |
| 			if ( p->tclass->dumped ) {
 | |
| 				e = p->tclass->setnum;
 | |
| 				eErrSet = p->tclass->setnumErrSet;
 | |
| 			}
 | |
| 			else {
 | |
| 				e = DefErrSet(&b, 0, TokenString(p->token));
 | |
| 				eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errset");
 | |
| 				p->tclass->dumped = 1;	/* indicate set has been created */
 | |
| 				p->tclass->setnum = e;
 | |
| 				p->tclass->setnumErrSet = eErrSet;					/* MR23 */
 | |
| 			}
 | |
| 			sprintf(buf, "%s_set", TokenString(p->token));
 | |
| 			sprintf(bufErrSet, "%s_errset", TokenString(p->token));	/* MR23 */
 | |
| 			set_name = buf;
 | |
| 			set_nameErrSet = bufErrSet;								/* MR23 */
 | |
| 		}
 | |
| 
 | |
| 		/* MR23 - Forgot about the case of ~TOKCLASS. */
 | |
| 
 | |
| 		else if ( p->tclass!=NULL  && complement != 0 /* MR23 */)
 | |
| 		{
 | |
| 			static char buf[MaxRuleName+20];	    /* MR23 */
 | |
| 			static char bufErrSet[MaxRuleName+20];	/* MR23 */
 | |
| 			if ( p->tclass->dumpedComplement ) {
 | |
| 				e = p->tclass->setnumComplement;
 | |
| 				eErrSet = p->tclass->setnumErrSetComplement;
 | |
| 			}
 | |
| 			else {
 | |
| 				e = DefErrSetWithSuffix(0, &b, 0, TokenString(p->token), "_setbar");
 | |
| 				eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errsetbar");
 | |
| 				p->tclass->dumpedComplement = 1;	/* indicate set has been created */
 | |
| 				p->tclass->setnumComplement = e;
 | |
| 				p->tclass->setnumErrSetComplement = eErrSet;					/* MR23 */
 | |
| 			}
 | |
| 			sprintf(buf, "%s_setbar", TokenString(p->token));
 | |
| 			sprintf(bufErrSet, "%s_errsetbar", TokenString(p->token));	/* MR23 */
 | |
| 			set_name = buf;
 | |
| 			set_nameErrSet = bufErrSet;								/* MR23 */
 | |
| 		}
 | |
| 		else {					/* wild card */
 | |
| 			static char buf[sizeof("zzerr")+10];
 | |
| 			static char bufErrSet[sizeof("zzerr")+10];
 | |
| 			int n = DefErrSet( &b, 0, NULL );
 | |
| 			int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set");
 | |
| 			if ( GenCC ) sprintf(buf, "err%d", n);
 | |
| 			else sprintf(buf, "zzerr%d", n);
 | |
| 			if ( GenCC ) sprintf(bufErrSet, "err%d", nErrSet);
 | |
| 			else sprintf(bufErrSet, "zzerr%d", nErrSet);
 | |
| 			set_name = buf;
 | |
| 			set_nameErrSet = bufErrSet;
 | |
| 		}
 | |
| 
 | |
| 		if ( !FoundException ) {
 | |
| /* MR23 */		gen2("zzsetmatch(%s, %s);", set_name, set_nameErrSet);
 | |
| 		}
 | |
| 		else if ( p->ex_group==NULL ) {
 | |
|             if ( p->use_def_MT_handler )
 | |
|                 gen3("zzsetmatch_wdfltsig(%s,(ANTLRTokenType)%d,%s);",
 | |
|                      set_name,
 | |
|                      p->token,
 | |
|                      tokenFollowSet(p))
 | |
|             else
 | |
|                 gen2("zzsetmatch_wsig(%s, %s_handler);",
 | |
|                      set_name,
 | |
|                      handler_id);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			gen1("if ( !_setmatch_wsig(%s) ) {\n", set_name);
 | |
| 			tabs++;
 | |
| /* MR6 */	if (FoundGuessBlk) {
 | |
| /* MR6 */	  if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
 | |
| /* MR6 */	  else gen("if ( zzguessing ) goto fail;\n");
 | |
| /* MR6 */	};
 | |
| 			gen("_signal=MismatchedToken;\n");
 | |
| 			dumpException(p->ex_group, 0);
 | |
| 			tabs--;
 | |
| 			gen("}\n");
 | |
| 		}
 | |
| 		set_free(b);
 | |
| 		set_free(bErrSet);
 | |
| 	}
 | |
| 	else if ( TokenString(p->token)!=NULL )
 | |
| 	{
 | |
| 		if ( FoundException ) {
 | |
| 			if ( p->use_def_MT_handler )
 | |
| 				gen2("zzmatch_wdfltsig(%s,%s);",TokenString(p->token),tokenFollowSet(p))
 | |
| 			else if ( p->ex_group==NULL )
 | |
| 			{
 | |
| 				gen2("zzmatch_wsig(%s, %s_handler);",
 | |
| 					 TokenString(p->token),
 | |
| 					 handler_id);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| /* MR6 */		if (GenCC) {
 | |
| /* MR6 */		  gen1("if ( !_match_wsig(%s) ) {\n", TokenString(p->token));
 | |
| /* MR6 */		} else {
 | |
| /* MR6 */		  gen1("if ( !_zzmatch_wsig(%s) ) {\n", TokenString(p->token));
 | |
| /* MR6 */		};
 | |
| 				tabs++;
 | |
| /* MR6 */		if (FoundGuessBlk) {
 | |
| /* MR6 */	  	  if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
 | |
| /* MR6 */		  else gen("if ( zzguessing ) goto fail;\n");
 | |
| /* MR6 */		};
 | |
| 				gen("_signal=MismatchedToken;\n");
 | |
| 				dumpException(p->ex_group, 0);
 | |
| 				tabs--;
 | |
| 				gen("}\n");
 | |
| 			}
 | |
| 		}
 | |
| 		else gen1("zzmatch(%s);", TokenString(p->token));
 | |
| 	}
 | |
| 	else {
 | |
|         if ( FoundException ) {
 | |
|             if ( p->use_def_MT_handler )
 | |
| 				gen2("zzmatch_wdfltsig((ANTLRTokenType)%d,%s);",
 | |
| 					 p->token,tokenFollowSet(p))
 | |
|             else
 | |
|                 gen2("zzmatch_wsig(%d,%s_handler);",p->token,handler_id);
 | |
|         }
 | |
| 		else {gen1("zzmatch(%d);", p->token);}
 | |
| 	}
 | |
| 
 | |
| 	a = findImmedAction( p->next );
 | |
| 	/* generate the token labels */
 | |
| 	if ( GenCC && p->elnum>0 )
 | |
| 	{
 | |
| 		/* If building trees in C++, always gen the LT() assigns */
 | |
| 		if ( set_el(p->elnum, tokensRefdInBlock) || GenAST )
 | |
| 		{
 | |
| /* MR10 */	if ( FoundGuessBlk ) {
 | |
| /* MR10 */    gen("\n");
 | |
| /* MR10 */    if (p->label_used_in_semantic_pred) {
 | |
| /* MR10 */		gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);  /* MR10 */\n", BlkLevel-1, p->elnum);
 | |
| /* MR10 */    } else {
 | |
| /* MR10 */		gen("if ( !guessing ) {\n"); tab();
 | |
| /* MR10 */		_gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);\n", BlkLevel-1, p->elnum);
 | |
| /* MR10 */      gen("}\n");
 | |
| /* MR10 */    };
 | |
| /* MR10 */  } else {
 | |
| /* MR10 */	  _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);", BlkLevel-1, p->elnum);
 | |
| /* MR10 */  };
 | |
| /* MR10 */
 | |
| 		}
 | |
| 
 | |
| /*
 | |
|  *  MR23 labase is never used in the C++ runtime library.
 | |
|  *       and this code is generated only in C++ mode
 | |
|  */
 | |
| 
 | |
| /***		if ( LL_k>1 )                                    / * MR23 disabled */
 | |
| /***			if ( !DemandLookahead ) _gen(" labase++;");  / * MR23 disabled */
 | |
| /***		_gen("\n");                                      / * MR23 disabled */
 | |
| /***		tab();                                           / * MR23 disabled */
 | |
| 	}
 | |
| 	if ( GenAST )
 | |
| 	{
 | |
| 		if ( FoundGuessBlk &&
 | |
| 				(ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) )
 | |
| 		{
 | |
| 			if ( GenCC ) {_gen("if ( !guessing ) {\n"); tab();}
 | |
| 			else {_gen("zzNON_GUESS_MODE {\n"); tab();}
 | |
| 		}
 | |
| 
 | |
| /* MR27 addition when labels referenced when operator ! used */
 | |
| 
 | |
| 		pushedCmodeAST = 0; /* MR27 */
 | |
| 		if (ast_label_in_action && (p->astnode == ASTexclude || r->noAST)) {
 | |
| 			_gen("\n");
 | |
| 			if (GenCC) {
 | |
| /* MR13 */      if (NewAST) {
 | |
| /* MR13 */    	    gen4("_ast%d%d = newAST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
 | |
| /* MR13 */      } else {
 | |
| /* MR13 */    	    gen4("_ast%d%d = new AST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
 | |
| /* MR13 */      }
 | |
| 			}
 | |
| 			else {
 | |
| 				pushedCmodeAST = 1;
 | |
| 				gen("zzastPush(zzmk_ast(zzastnew(),zzaCur)); /* MR27 */");
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| /* end MR27 addition for labels referenced when operator ! used */
 | |
| 
 | |
| 		if (!r->noAST )
 | |
| 		{
 | |
| 			if (GenCC && !(p->astnode == ASTexclude) ) {
 | |
| 				_gen("\n");
 | |
| /* MR13 */      if (NewAST) {
 | |
| /* MR13 */    	    gen4("_ast%d%d = newAST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
 | |
| /* MR13 */      } else {
 | |
| /* MR13 */    	    gen4("_ast%d%d = new AST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
 | |
| /* MR13 */      }
 | |
| 				tab();
 | |
| 			}
 | |
| 			if ( GenCC && !(p->astnode == ASTexclude) )
 | |
| 				{_gen2("_ast%d%d->", BlkLevel-1, p->elnum);}
 | |
| 			else _gen(" ");
 | |
| 			if ( p->astnode==ASTchild ) {
 | |
| 				if ( !GenCC ) _gen("zz");
 | |
| 				_gen("subchild(_root, &_sibling, &_tail);");
 | |
| 			}
 | |
| 			else if ( p->astnode==ASTroot ) {
 | |
| 				if ( !GenCC ) _gen("zz");
 | |
| 				_gen("subroot(_root, &_sibling, &_tail);");
 | |
| 			}
 | |
| 			if ( GenCC && !(p->astnode == ASTexclude) ) {
 | |
| 				_gen("\n");
 | |
| 				tab();
 | |
| 			}
 | |
| 		}
 | |
| 		else if ( !GenCC ) {
 | |
| 			if (! pushedCmodeAST) _gen(" zzastDPush;");
 | |
| 		}
 | |
| 		if ( FoundGuessBlk &&
 | |
| 				(ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) )
 | |
| 			{gen("}\n"); tab();}
 | |
| 	}
 | |
| 
 | |
| 	/* Handle element labels now */
 | |
| 	if ( p->el_label!=NULL )
 | |
| 	{
 | |
|         int     done_NON_GUESSMODE=0;
 | |
| 
 | |
| 		_gen("\n");
 | |
| 
 | |
| /* MR10 */    /* do Attrib / Token ptr for token label used in semantic pred */
 | |
| /* MR10 */    /* for these cases do assign even in guess mode                */
 | |
| /* MR10 */
 | |
| /* MR10 */    if (p->label_used_in_semantic_pred) {
 | |
| /* MR10 */      if ( GenCC ) {
 | |
| /* MR10 */        if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) {
 | |
| /* MR10 */          gen3("%s = _t%d%d;", p->el_label, BlkLevel-1, p->elnum);
 | |
| /* MR10 */        } else {
 | |
| /* MR10 */          gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label);
 | |
| /* MR10 */        };
 | |
| /* MR10 */      } else {
 | |
| /* MR10 */		  gen1("%s = zzaCur;", p->el_label);
 | |
| /* MR10 */      };
 | |
| /* MR10 */      if (FoundGuessBlk) _gen("  /* MR10 */");
 | |
| /* MR10 */      _gen("\n");
 | |
| /* MR10 */    };
 | |
| 
 | |
| 		/* Do Attrib / Token ptr */
 | |
| 
 | |
| /* MR10 */  if (! p->label_used_in_semantic_pred) {
 | |
| /* MR10 */
 | |
| /* MR10 */      if ( FoundGuessBlk ) {
 | |
| /* MR10 */        if (! done_NON_GUESSMODE) {
 | |
| /* MR10 */          done_NON_GUESSMODE=1;
 | |
| /* MR10 */          if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();}
 | |
| /* MR10 */          else {gen("zzNON_GUESS_MODE {\n"); tab();}
 | |
| /* MR10 */        };
 | |
| /* MR10 */      };
 | |
| /* MR10 */
 | |
| /* MR10 */      if ( GenCC ) {
 | |
| /* MR10 */        if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) {
 | |
| /* MR10 */          gen3("%s = _t%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
 | |
| /* MR10 */        } else {
 | |
| /* MR10 */          gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label);
 | |
| /* MR10 */        };
 | |
| /* MR10 */      } else {
 | |
| /* MR10 */        gen1("%s = zzaCur;\n", p->el_label);
 | |
| /* MR10 */      };
 | |
| /* MR10 */  };
 | |
| 
 | |
| 		/* Do AST ptr */
 | |
| 
 | |
| 		if (GenAST && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST) )) /* MR27 */
 | |
| 		{
 | |
| 
 | |
| /* MR10 */      if ( FoundGuessBlk ) {
 | |
| /* MR10 */        if (! done_NON_GUESSMODE) {
 | |
| /* MR10 */          done_NON_GUESSMODE=1;
 | |
| /* MR10 */          if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();}
 | |
| /* MR10 */          else {gen("zzNON_GUESS_MODE {\n"); tab();}
 | |
| /* MR10 */        };
 | |
| /* MR10 */      };
 | |
| 
 | |
| 			if ( GenCC ) {
 | |
| 				gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
 | |
| 			}
 | |
| 			else {gen1("%s_ast = zzastCur;\n", p->el_label);}
 | |
| 		}
 | |
| 
 | |
| /* MR10 */  if (done_NON_GUESSMODE) {
 | |
| /* MR10 */    gen("}\n"); tab();
 | |
| /* MR10 */  };
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	/* Handle any actions immediately following action */
 | |
| 	if ( a != NULL )  /* MR10 */ /* MR11 */
 | |
|     {
 | |
|     	/* delay next token fetch until after action */
 | |
| 		_gen("\n");
 | |
| 		if ( a->is_predicate)
 | |
| 		{
 | |
| #if 0
 | |
| /* Disabled in MR30 ************************************************************
 | |
|    And moved into genAction
 | |
|    *****************************************************************************
 | |
| */
 | |
|  
 | |
|     	    gen("if (!(");
 | |
| 
 | |
| 			/* make sure that '#line n' is on front of line */  /* MR14 */
 | |
| 			if ( GenLineInfo && p->file != -1 ) _gen("\n");     /* MR14 */
 | |
| 			dumpPredAction(a,a->action, output, 0, a->file, a->line, 0);
 | |
| 
 | |
| /* MR23 Change failed predicate macro to have three arguments:
 | |
| 
 | |
|         macro arg 1: The stringized predicate itself
 | |
|         macro arg 2: 0 => no user-defined error action
 | |
|                      1 => user-defined error action
 | |
|         macro arg 3: The user-defined error action
 | |
| 
 | |
|    This gives the user more control of the error action.
 | |
| */
 | |
| 			_gen(")) \n");
 | |
| 			tabs++;
 | |
| 			gen3(" {zzfailed_pred(\"%s\",%s,{ %s } );}\n",           /* MR23 */
 | |
| 					stringize(a->action),	                         /* MR23 */
 | |
|                     (a->pred_fail == NULL ?                          /* MR23/MR27 */
 | |
|                        	"0 /* report */" : "1 /* user action */"),   /* MR23/MR27 */
 | |
|                     (a->pred_fail == NULL ?                          /* MR23 */
 | |
|                         "; /* no user action */" : a->pred_fail));   /* MR23 */
 | |
| 			tabs--;
 | |
| /* Disabled in MR30 ************************************************************
 | |
|    And moved into genAction
 | |
|    *****************************************************************************
 | |
| */
 | |
| #endif
 | |
| 		}
 | |
| 		else    /* MR9 a regular action - not a predicate action */
 | |
| 		{
 | |
| 
 | |
| /* MR23: Search an action which is not a predicate for LT(i),
 | |
|          LA(i), or LATEXT(i) in order to warn novice users that
 | |
|          it refers to the previous matched token, not the next
 | |
|          one.  This is different than the case for semantic
 | |
|          predicates.
 | |
| */
 | |
|                                  
 | |
| /* MR23 */    if (GenCC) {
 | |
| /* MR23 */	    if (strstr(a->action, "LT(") != NULL) LTinTokenAction = 1;
 | |
| /* MR23 */    }
 | |
| /* MR23 */    else {
 | |
| /* MR23 */      if (strstr(a->action, "LA(") != NULL) LTinTokenAction = 1;            
 | |
| /* MR23 */      if (strstr(a->action, "LATEXT(") != NULL) LTinTokenAction = 1;
 | |
| /* MR23 */    }
 | |
| 
 | |
| 			if ( FoundGuessBlk ) {
 | |
|    				if ( GenCC ) {gen("if ( !guessing ) {\n");}
 | |
|    				else gen("zzNON_GUESS_MODE {\n");
 | |
| 			}
 | |
|    			dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); /* MR21 */
 | |
|        		if ( FoundGuessBlk ) gen("}\n");
 | |
| 			a->done = 1; /* MR30 */
 | |
|  		}
 | |
| /***    a->done = 1;  MR30 Moved up into then branch for true actions, but not predicates ***/
 | |
| 		if ( !DemandLookahead ) {
 | |
| 			if ( GenCC ) {
 | |
| 				if ( FoundException && p->use_def_MT_handler ) gen("if (!_signal)");
 | |
| 				_gen(" consume();")
 | |
|                 if ( FoundException && p->use_def_MT_handler )
 | |
|                     _gen(" _signal=NoSignal;");
 | |
|                 _gen("\n");
 | |
| 			}
 | |
|             else
 | |
|             {
 | |
|                 if ( FoundException && p->use_def_MT_handler ) _gen("if (!_signal)");
 | |
| 					_gen(" zzCONSUME;\n");
 | |
|                 if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;");
 | |
|                 _gen("\n");
 | |
|             }
 | |
| 		}
 | |
| 		else gen("\n");
 | |
| 		if (a->done) {			/* MR30 */
 | |
| 			TRANS( a->next );   /* MR30 */
 | |
| 		}						/* MR30 */
 | |
| 		else {					/* MR30 */
 | |
| 			TRANS( p->next );	/* MR30 */
 | |
| 		}						/* MR30 */
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
|         if ( !DemandLookahead ) {
 | |
| 			if ( GenCC ) {
 | |
| 				if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)");
 | |
| 				_gen(" consume();")
 | |
| 				if (FoundException&&p->use_def_MT_handler) _gen(" _signal=NoSignal;");
 | |
| 				_gen("\n");
 | |
| 			}
 | |
| 			else {
 | |
| 				if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)");
 | |
| 				_gen(" zzCONSUME;");
 | |
| 				if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;");
 | |
| 				_gen("\n");
 | |
| 			}
 | |
| 		}
 | |
| 		else _gen("\n");
 | |
| 		TRANS(p->next);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /*  MR21
 | |
|  *
 | |
|  *  There was a bug in the code generation for {...} which causes it
 | |
|  *  to omit the optional tokens from the error messages.  The easiest
 | |
|  *  way to fix this was to make the opt block look like a sub block:
 | |
|  *
 | |
|  *          { a | b | c }
 | |
|  *
 | |
|  *  becomes (internally):
 | |
|  *
 | |
|  *          ( a | b | c | )
 | |
|  *
 | |
|  *  The code for genOptBlk is now identical to genSubBlk except for
 | |
|  *  cosmetic changes.
 | |
|  */
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genOptBlk( Junction *q )
 | |
| #else
 | |
| genOptBlk( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	int max_k;
 | |
| 	set f;
 | |
| 	int need_right_curly;
 | |
| 	set savetkref;
 | |
| 	int lastAltEmpty;			/* MR23 */
 | |
| 	savetkref = tokensRefdInBlock;
 | |
| 	require(q->ntype == nJunction,	"genOptBlk: not junction");
 | |
| 	require(q->jtype == aOptBlk,	"genOptBlk: not opt block");
 | |
| 
 | |
|     OutLineInfo(output,q->line,FileStr[q->file]);
 | |
| 	BLOCK_Preamble(q);
 | |
| 	BlkLevel++;
 | |
|     BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */
 | |
| 	f = genBlk(q, aOptBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
 | |
| /* MR23
 | |
|    Bypass error clause generation when exceptions are used in {...} block 
 | |
|    See multi-line note in genBlk near call to isEmptyAlt.
 | |
| */
 | |
| 	if (! FoundException) {
 | |
| 	    if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
 | |
| 	}
 | |
| 	else {
 | |
| 		gen("/* MR23 skip error clause for {...} when exceptions in use */\n");
 | |
| 	}
 | |
| 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
 | |
| 	freeBlkFsets(q);
 | |
| 	--BlkLevel;
 | |
| 	BLOCK_Tail();
 | |
| 
 | |
| 	if ( q->guess )
 | |
| 	{
 | |
| 		gen("zzGUESS_DONE\n");
 | |
| 	}
 | |
| 
 | |
| 	/* must duplicate if (alpha)?; one guesses (validates), the
 | |
| 	 * second pass matches */
 | |
| 	if ( q->guess && analysis_point(q)==q )
 | |
| 	{
 | |
|         OutLineInfo(output,q->line,FileStr[q->file]);
 | |
| 		BLOCK_Preamble(q);
 | |
| 		BlkLevel++;
 | |
| 		f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
 | |
| 		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
 | |
| 		{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
 | |
| 		freeBlkFsets(q);
 | |
| 		--BlkLevel;
 | |
| 		BLOCK_Tail();
 | |
| 	}
 | |
| 
 | |
| 	tokensRefdInBlock = savetkref;
 | |
| 	if (q->end->p1 != NULL) TRANS(q->end->p1);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate code for a loop blk of form:
 | |
|  *
 | |
|  *				 |---|
 | |
|  *				 v   |
 | |
|  *			   --o-G-o-->o--
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genLoopBlk( Junction *begin, Junction *q, Junction *start, int max_k )
 | |
| #else
 | |
| genLoopBlk( begin, q, start, max_k )
 | |
| Junction *begin;
 | |
| Junction *q;
 | |
| Junction *start;	/* where to start generating code from */
 | |
| int max_k;
 | |
| #endif
 | |
| {
 | |
| 	set         f;
 | |
| 	int         need_right_curly;
 | |
| 	set         savetkref;
 | |
|     Junction    *guessBlock;    /* MR10 */
 | |
|     int         singleAlt;      /* MR10 */
 | |
| 	int			lastAltEmpty;	/* MR23 */
 | |
| 
 | |
| 	savetkref = tokensRefdInBlock;
 | |
| 	require(q->ntype == nJunction,	"genLoopBlk: not junction");
 | |
| 	require(q->jtype == aLoopBlk,	"genLoopBlk: not loop block");
 | |
| 
 | |
| 	if ( q->visited ) return;
 | |
| 	q->visited = TRUE;
 | |
| 
 | |
|     /* first_item_is_guess_block doesn't care what kind of node it is */
 | |
| 
 | |
|     guessBlock=first_item_is_guess_block( (Junction *) q->p1);  /* MR10 */
 | |
|     singleAlt=q->p2==NULL;                                      /* MR10 */
 | |
| 
 | |
| 	if (singleAlt && !guessBlock)	    /* MR10 */ /* only one alternative? */
 | |
| 	{
 | |
| 		if ( DemandLookahead ) {
 | |
| 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
 | |
| 			else gen1("look(%d);\n", max_k);
 | |
| 		}
 | |
| 		gen("while ( ");
 | |
| 		if ( begin!=NULL ) genExpr(begin);
 | |
| 		else genExpr(q);
 | |
| 		/* if no predicates have been hoisted for this single alt (..)*
 | |
| 		 * do so now
 | |
| 		 */
 | |
|         require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
 | |
| 		if ( ParseWithPredicates && begin->predicate==NULL )
 | |
| 		{
 | |
| 			Predicate *a = MR_find_predicates_and_supp((Node *)q->p1);
 | |
|             require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
 | |
| 
 | |
| 			if ( a!=NULL )
 | |
| 			{
 | |
| 				_gen("&&");
 | |
| 				a=genPredTreeMain(a, (Node *)q);    /* MR10 */
 | |
| 			}
 | |
| /* MR10 */  if (MRhoisting) {
 | |
| /* MR10 */    predicate_free(a);
 | |
| /* MR10 */  };
 | |
| 		}
 | |
| 		_gen(" ) {\n");
 | |
| 		tabs++;
 | |
| 		TRANS(q->p1);
 | |
| 		if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
 | |
| 		if ( DemandLookahead ) {
 | |
| 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
 | |
| 			else gen1("look(%d);\n", max_k);
 | |
| 		}
 | |
| 		--tabs;
 | |
| 		gen("}\n");
 | |
| 		freeBlkFsets(q);
 | |
| 		q->visited = FALSE;
 | |
| 		tokensRefdInBlock = savetkref;
 | |
| 		return;
 | |
| 	}
 | |
| 	gen("for (;;) {\n");        /* MR20 G. Hobbelt */
 | |
| 	tabs++;
 | |
| /* MR6				                					*/
 | |
| /* MR6 	   "begin" can never be null when called from genLoopBegin	*/
 | |
| /* MR6     because q==(Junction *)begin->p1 and we know q is valid	*/
 | |
| /* MR6								                            	*/
 | |
| /* MR6	   from genLoopBegin:						                */
 | |
| /* MR6			                						            */
 | |
| /* MR6		 if ( LL_k>1 && !set_nil(q->fset[2]) )			        */
 | |
| /* MR6	 	   genLoopBlk( q, (Junction *)q->p1, q, max_k );	    */
 | |
| /* MR6		else genLoopBlk( q, (Junction *)q->p1, NULL, max_k );	*/
 | |
| /* MR6				                				            	*/
 | |
| 	if ( begin!=NULL )
 | |
| 	{
 | |
| 		if ( DemandLookahead )
 | |
| 		{
 | |
| 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
 | |
| 			else gen1("look(%d);\n", max_k);
 | |
| 		}
 | |
| 		/* The bypass arc of the (...)* predicts what to do when you fail, but
 | |
| 		 * ONLY after having tested the loop start expression.  To avoid this,
 | |
| 		 * we simply break out of the (...)* loop when we find something that
 | |
| 		 * is not in the prediction of the loop (all alts thereof).
 | |
| 		 */
 | |
| 		gen("if ( !(");
 | |
| 
 | |
| /***	TJP says: It used to use the prediction expression for the bypass arc
 | |
|      	of the (...)*.  HOWEVER, if a non LL^1(k) decision was found, this
 | |
|     	thing would miss the ftree stored in the aLoopBegin node and generate
 | |
|     	an LL^1(k) decision anyway.
 | |
| 
 | |
|  ***		genExpr((Junction *)begin->p2);
 | |
|  ***/
 | |
| 
 | |
|             genExpr((Junction *)begin);
 | |
|             _gen(")) break;\n");
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	/* generate code for terminating loop (this is optional branch) */
 | |
| 
 | |
| 	f = genBlk(q, aLoopBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
 | |
| 	set_free(f);
 | |
| 	freeBlkFsets(q);
 | |
| 
 | |
| 	/* generate code for terminating loop (this is optional branch) */
 | |
| 
 | |
| /* MR6 						                    			            */
 | |
| /* MR6  30-May-97 Bug reported by Manuel Ornato				            */
 | |
| /* MR6            A definite bug involving the exit from a loop block   */
 | |
| /* MR6 		  In 1.23 and later versions (including 1.33) Instead       */
 | |
| /* MR6              exiting the block and reporting a syntax error the  */
 | |
| /* MR6		    code loops forever.     				                */
 | |
| /* MR6	          Looking at 1.20 which generates proper code it is not */
 | |
| /* MR6		    clear which of two changes should be undone.            */
 | |
| /* MR6		  This is my best guess.                                    */
 | |
| /* MR6		  From earlier MR6 note we know that begin can never be     */
 | |
| /* MR6		    null when genLoopBlk called from genLoopBegin           */
 | |
| /* MR6 */
 | |
| /* MR6 */ if ( begin==NULL) {
 | |
| /* MR6 */   /* code for exiting loop "for sure" */
 | |
| /* MR6 */   gen("/* Suppressed by MR6 */ /*** else break; ***/\n");
 | |
| /* MR6 */ };
 | |
| 
 | |
| /* MR10 */if (singleAlt && guessBlock) {
 | |
| /* MR10 */  tabs--;
 | |
| /* MR6 */   gen("} else break; /* MR6 code for exiting loop \"for sure\" */\n");
 | |
| /* MR10 */  need_right_curly--;
 | |
| /* MR10 */ } else {
 | |
| /* MR6 */   gen("else break; /* MR6 code for exiting loop \"for sure\" */\n");
 | |
| /* MR10 */ };
 | |
| 
 | |
| 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
 | |
| 	if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
 | |
| 	--tabs;
 | |
| 	gen("}\n");
 | |
| 	q->visited = FALSE;
 | |
| 	tokensRefdInBlock = savetkref;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate code for a loop blk of form:
 | |
|  *
 | |
|  * 				         |---|
 | |
|  *					     v   |
 | |
|  *			   --o-->o-->o-G-o-->o--
 | |
|  *                   |           ^
 | |
|  *                   v           |
 | |
|  *					 o-----------o
 | |
|  *
 | |
|  * q->end points to the last node (far right) in the blk.
 | |
|  *
 | |
|  * Note that q->end->jtype must be 'EndBlk'.
 | |
|  *
 | |
|  * Generate code roughly of the following form:
 | |
|  *
 | |
|  *	do {
 | |
|  *		... code for alternatives ...
 | |
|  *  } while ( First Set of aLoopBlk );
 | |
|  *
 | |
|  *	OR if > 1 alternative
 | |
|  *
 | |
|  *	do {
 | |
|  *		... code for alternatives ...
 | |
|  *		else break;
 | |
|  *  } while ( 1 );
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genLoopBegin( Junction *q )
 | |
| #else
 | |
| genLoopBegin( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	set f;
 | |
| 	int i;
 | |
| 	int max_k;
 | |
| 	set savetkref;
 | |
| 	savetkref = tokensRefdInBlock;
 | |
| 	require(q!=NULL,				"genLoopBegin: invalid node and/or rule");
 | |
| 	require(q->ntype == nJunction,	"genLoopBegin: not junction");
 | |
| 	require(q->jtype == aLoopBegin,	"genLoopBegin: not loop block");
 | |
| 	require(q->p2!=NULL,			"genLoopBegin: invalid Loop Graph");
 | |
| 
 | |
|     OutLineInfo(output,q->line,FileStr[q->file]);
 | |
| 
 | |
| 	BLOCK_Preamble(q);
 | |
| 	BlkLevel++;
 | |
|     BlockPreambleOption(q,q->pFirstSetSymbol);       /* MR21 */
 | |
| 	f = First(q, 1, aLoopBegin, &max_k);
 | |
| 	/* If not simple LL(1), must specify to start at LoopBegin, not LoopBlk */
 | |
| 	if ( LL_k>1 && !set_nil(q->fset[2]) )
 | |
| 		genLoopBlk( q, (Junction *)q->p1, q, max_k );
 | |
| 	else genLoopBlk( q, (Junction *)q->p1, NULL, max_k );
 | |
| 
 | |
| 	for (i=1; i<=CLL_k; i++) set_free(q->fset[i]);
 | |
| 	for (i=1; i<=CLL_k; i++) set_free(((Junction *)q->p2)->fset[i]);
 | |
| 	--BlkLevel;
 | |
| 	BLOCK_Tail();
 | |
| 	set_free(f);
 | |
| 	tokensRefdInBlock = savetkref;
 | |
| /* MR21 */	if (MR_BlkErr) {
 | |
| /* MR21 */		set f, fArray[2];
 | |
| /* MR21 */		f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ );
 | |
| /* MR21 */      fArray[0]= empty;
 | |
| /* MR21 */		fArray[1]= set_dup(f);
 | |
| /* MR21 */      gen("if (");
 | |
| /* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
 | |
| /* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
 | |
| /* MR21 */      tabs++;
 | |
| /* MR21 */      tab();
 | |
| /* MR21 */      _gen("/* nothing */ }\n");
 | |
| /* MR21 */      tab();
 | |
| /* MR21 */      makeErrorClause(q,f,1,0 /* use plus block bypass ? */ );  /* frees set */
 | |
| /* MR21 */      tabs--;
 | |
| /* MR21 */	};
 | |
| 	if (q->end->p1 != NULL) TRANS(q->end->p1);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate code for a loop blk of form:
 | |
|  *
 | |
|  * 					 |---|
 | |
|  *					 v   |
 | |
|  *			       --o-G-o-->o--
 | |
|  *
 | |
|  * q->end points to the last node (far right) in the blk.
 | |
|  * Note that q->end->jtype must be 'EndBlk'.
 | |
|  *
 | |
|  * Generate code roughly of the following form:
 | |
|  *
 | |
|  *	do {
 | |
|  *		... code for alternatives ...
 | |
|  *  } while ( First Set of aPlusBlk );
 | |
|  *
 | |
|  *	OR if > 1 alternative
 | |
|  *
 | |
|  *	do {
 | |
|  *		... code for alternatives ...
 | |
|  *		else if not 1st time through, break;
 | |
|  *  } while ( 1 );
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genPlusBlk( Junction *q )
 | |
| #else
 | |
| genPlusBlk( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	int         max_k;
 | |
| 	set         f;
 | |
| 	int         need_right_curly;
 | |
| 	int			lastAltEmpty;	/* MR23 */
 | |
| 	set         savetkref;
 | |
|     Junction    *guessBlock;    /* MR10 */
 | |
|     int         singleAlt;      /* MR10 */
 | |
| 
 | |
| 	savetkref = tokensRefdInBlock;
 | |
| 	require(q!=NULL,				"genPlusBlk: invalid node and/or rule");
 | |
| 	require(q->ntype == nJunction,	"genPlusBlk: not junction");
 | |
| 	require(q->jtype == aPlusBlk,	"genPlusBlk: not Plus block");
 | |
| 	require(q->p2 != NULL,			"genPlusBlk: not a valid Plus block");
 | |
| 
 | |
| 	if ( q->visited ) return;
 | |
| 	q->visited = TRUE;
 | |
|     OutLineInfo(output,q->line,FileStr[q->file]);
 | |
| 	BLOCK_Preamble(q);
 | |
| 	BlkLevel++;
 | |
| 
 | |
|     BlockPreambleOption((Junction *)q, q->pFirstSetSymbol);       /* MR21 */
 | |
|     
 | |
|     /* first_item_is_guess_block  doesn't care what kind of node it is */
 | |
| 
 | |
|     guessBlock=first_item_is_guess_block( (Junction *)q->p1);   /* MR10 */
 | |
| 
 | |
| 	/* if the ignore flag is set on the 2nd alt and that alt is empty,
 | |
| 	 * then it is the implied optional alternative that we added for (...)+
 | |
| 	 * and, hence, only 1 alt.
 | |
| 	 */
 | |
| 
 | |
| /* MR10  Reported by Pulkkinen Esa (esap@cs.tut.fi)
 | |
|  *       Outer code for guess blocks ignored when there is only one alt
 | |
|  *         for a (...)+ block.
 | |
|  *       Force use of regular code rather than "optimized" code for that case
 | |
|  */
 | |
| 
 | |
|     singleAlt=( ( (Junction *) q->p2)->p2 == NULL) &&
 | |
|         	  ( ( (Junction *) q->p2)->ignore );			/* only one alternative? */
 | |
| 
 | |
|     if (singleAlt && !guessBlock)   /* MR10 */
 | |
| 	{
 | |
| 
 | |
| 		Predicate *a=NULL;
 | |
| 		/* if the only alt has a semantic predicate, hoist it; must test before
 | |
| 		 * entering loop.
 | |
| 		 */
 | |
| 		if ( ParseWithPredicates )
 | |
| 		{
 | |
|             require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
 | |
| 			a = MR_find_predicates_and_supp((Node *)q);
 | |
|             require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
 | |
| 
 | |
| 			if ( a!=NULL ) {
 | |
| 				gen("if (");
 | |
| 				a=genPredTreeMain(a, (Node *)q);    /* MR10 */
 | |
| 				_gen(") {\n");
 | |
| 			}
 | |
| 		}
 | |
| 		gen("do {\n");
 | |
| 		tabs++;
 | |
| 		TRANS(q->p1);
 | |
| 		if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
 | |
| 		f = First(q, 1, aPlusBlk, &max_k);
 | |
| 		if ( DemandLookahead ) {
 | |
| 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
 | |
| 			else gen1("look(%d);\n", max_k);
 | |
| 		}
 | |
| 		--tabs;
 | |
| 		gen("} while ( ");
 | |
| 		if ( q->parm!=NULL && q->predparm ) _gen1("(%s) && ", q->parm);
 | |
| 		genExpr(q);
 | |
| 		if ( ParseWithPredicates && a!=NULL )
 | |
| 		{
 | |
|             if (! MR_comparePredicates(q->predicate,a)) {
 | |
|     			_gen("&&");
 | |
|     			a=genPredTreeMain(a, (Node *)q);    /* MR10 */
 | |
|             };
 | |
| 		}
 | |
| 		_gen(" );\n");
 | |
| 		if ( ParseWithPredicates && a!=NULL ) gen("}\n");
 | |
| 		--BlkLevel;
 | |
| 		BLOCK_Tail();
 | |
| 		q->visited = FALSE;
 | |
| 		freeBlkFsets(q);
 | |
| 		set_free(f);
 | |
| 		tokensRefdInBlock = savetkref;
 | |
| /* MR21 */	if (MR_BlkErr) {
 | |
| /* MR21 */		set f, fArray[2];
 | |
| /* MR21 */		f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ );
 | |
| /* MR21 */      fArray[0]= empty;
 | |
| /* MR21 */		fArray[1]= set_dup(f);
 | |
| /* MR21 */      gen("if (");
 | |
| /* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
 | |
| /* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
 | |
| /* MR21 */      tabs++;
 | |
| /* MR21 */      tab();
 | |
| /* MR21 */      _gen("/* nothing */ }\n");
 | |
| /* MR21 */      tab();
 | |
| /* MR21 */      makeErrorClause(q,f,1,1 /* use plus block bypass ? */ );  /* frees set */
 | |
| /* MR21 */      tabs--;
 | |
| /* MR21 */	};
 | |
| 		if (q->end->p1 != NULL) TRANS(q->end->p1);
 | |
| /* MR10 */  if (MRhoisting) {
 | |
| /* MR10 */    predicate_free(a);
 | |
| /* MR10 */  };
 | |
| 		return;
 | |
| 	}
 | |
| 	gen("do {\n");
 | |
| 	tabs++;
 | |
| 	f = genBlk(q, aPlusBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
 | |
| /* MR6              									        */
 | |
| /* MR6	Sinan Karasu	(sinan@tardis.ds.boeing.com)			*/
 | |
| /* MR6    Failed to turn off guess mode when leaving block		*/
 | |
| /* MR6				                           					*/
 | |
| /* MR6  */ if ( has_guess_block_as_last_item(q) ) {
 | |
| /* MR10 */   gen("/* MR10 ()+ */ else {\n");
 | |
| /* MR10 */   tabs++;
 | |
| /* MR10 */   need_right_curly++;
 | |
| /* MR10 */   gen("/* MR10 ()+ */ if ( !zzrv ) zzGUESS_DONE;\n");
 | |
| /* MR6  */   gen("/* MR10 ()+ */ if ( zzcnt > 1 ) break;\n");
 | |
| /* MR10 */ } else {
 | |
| /* MR10 */   gen("/* MR10 ()+ */ else {\n");
 | |
| /* MR10 */   tabs++;
 | |
| /* MR10 */   need_right_curly++;
 | |
| /* MR10 */   gen("if ( zzcnt > 1 ) break;\n");
 | |
| /* MR10 */ };
 | |
| 
 | |
| /* MR21 */	if (MR_BlkErr && 1 >= max_k) {
 | |
| /* MR21 */		set f;
 | |
| /* MR21 */		f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ );
 | |
| /* MR21 */      tabs++;
 | |
| /* MR21 */      tab();
 | |
| /* MR21 */      makeErrorClause(q,f,1,0 /* use plus block bypass ? */ );  /* frees set */
 | |
| /* MR21 */      tabs--;
 | |
| /* MR21 */	}
 | |
| /* MR21 */  else {
 | |
| 				tab();
 | |
|                 makeErrorClause(q,f,max_k,1 /* use plus block bypass ? */);
 | |
| 										    /* MR21 I think this generates the wrong set ? */
 | |
|                                             /* MR21 because it includes the plus block bypass ? */
 | |
| 										    /* MR21 but I'm afraid to change it without additional checking */
 | |
|             }
 | |
| 
 | |
| 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
 | |
| 	freeBlkFsets(q);
 | |
| 	gen("zzcnt++;");
 | |
| 	if ( !GenCC ) _gen1(" zzLOOP(zztasp%d);", BlkLevel-1);
 | |
| 	_gen("\n");
 | |
| 	if ( DemandLookahead ) {
 | |
| 		if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
 | |
| 		else gen1("look(%d);\n", max_k);
 | |
| 	}
 | |
| 	--tabs;
 | |
| 	if ( q->parm!=NULL && q->predparm ) {gen1("} while (%s);\n", q->parm);}
 | |
| 	else gen("} while ( 1 );\n");
 | |
| 	--BlkLevel;
 | |
| 	BLOCK_Tail();
 | |
| 	q->visited = FALSE;
 | |
| 	tokensRefdInBlock = savetkref;
 | |
| /* MR21 */	if (MR_BlkErr) {
 | |
| /* MR21 */		set f, fArray[2];
 | |
| /* MR21 */		f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ );
 | |
| /* MR21 */      fArray[0]= empty;
 | |
| /* MR21 */		fArray[1]= set_dup(f);
 | |
| /* MR21 */      gen("if (");
 | |
| /* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
 | |
| /* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
 | |
| /* MR21 */      tabs++;
 | |
| /* MR21 */      tab();
 | |
| /* MR21 */      _gen("/* nothing */ }\n");
 | |
| /* MR21 */      tab();
 | |
| /* MR21 */      makeErrorClause(q,f,1,1 /* use plus block bypass ? */ );  /* frees set */
 | |
| /* MR21 */      tabs--;
 | |
| /* MR21 */	};
 | |
| 	if (q->end->p1 != NULL) TRANS(q->end->p1);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Generate code for a sub blk of alternatives of form:
 | |
|  *
 | |
|  *			       --o-G1--o--
 | |
|  *					 |     ^
 | |
|  *					 v    /|
 | |
|  *			         o-G2-o|
 | |
|  *					 |     ^
 | |
|  *					 v     |
 | |
|  *				   ..........
 | |
|  *					 |     ^
 | |
|  *					 v    /
 | |
|  *			         o-Gn-o
 | |
|  *
 | |
|  * q points to the 1st junction of blk (upper-left).
 | |
|  * q->end points to the last node (far right) in the blk.
 | |
|  * Note that q->end->jtype must be 'EndBlk'.
 | |
|  * The last node in every alt points to q->end.
 | |
|  *
 | |
|  * Generate code of the following form:
 | |
|  *	if ( First(G1) ) {
 | |
|  *		...code for G1...
 | |
|  *	}
 | |
|  *	else if ( First(G2) ) {
 | |
|  *		...code for G2...
 | |
|  *	}
 | |
|  *	...
 | |
|  *	else {
 | |
|  *		...code for Gn...
 | |
|  *	}
 | |
|  */
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genSubBlk( Junction *q )
 | |
| #else
 | |
| genSubBlk( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	int max_k;
 | |
| 	set f;
 | |
| 	int need_right_curly;
 | |
| 	int lastAltEmpty;		/* MR23 */
 | |
| 	set savetkref;
 | |
| 	savetkref = tokensRefdInBlock;
 | |
| 	require(q->ntype == nJunction,	"genSubBlk: not junction");
 | |
| 	require(q->jtype == aSubBlk,	"genSubBlk: not subblock");
 | |
| 
 | |
|     OutLineInfo(output,q->line,FileStr[q->file]);
 | |
| 	BLOCK_Preamble(q);
 | |
| 	BlkLevel++;
 | |
|     BlockPreambleOption(q,q->pFirstSetSymbol);       /* MR21 */
 | |
| 	f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
 | |
| 
 | |
| /* MR23
 | |
|    Bypass error clause generation when exceptions are used in a sub block
 | |
|    in which the last alternative is epsilon.  Example: "(A | B | )". 
 | |
|    See multi-line note in genBlk near call to isEmptyAlt.
 | |
| */
 | |
| 	if (FoundException && lastAltEmpty) {
 | |
| 		gen("/* MR23 skip error clause for (...| epsilon) when exceptions in use */\n");
 | |
| 	}
 | |
| 	else {
 | |
| 		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
 | |
| 	}
 | |
|     
 | |
| 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
 | |
| 	freeBlkFsets(q);
 | |
| 	--BlkLevel;
 | |
| 	BLOCK_Tail();
 | |
| 
 | |
| 	if ( q->guess )
 | |
| 	{
 | |
| 		gen("zzGUESS_DONE\n");
 | |
| 	}
 | |
| 
 | |
| 	/* must duplicate if (alpha)?; one guesses (validates), the
 | |
| 	 * second pass matches */
 | |
| 	if ( q->guess && analysis_point(q)==q )
 | |
| 	{
 | |
|         OutLineInfo(output,q->line,FileStr[q->file]);
 | |
| 		BLOCK_Preamble(q);
 | |
| 		BlkLevel++;
 | |
| 		f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
 | |
| 		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */);}
 | |
| 		{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
 | |
| 		freeBlkFsets(q);
 | |
| 		--BlkLevel;
 | |
| 		BLOCK_Tail();
 | |
| 	}
 | |
| 
 | |
| 	tokensRefdInBlock = savetkref;
 | |
| 	if (q->end->p1 != NULL) TRANS(q->end->p1);
 | |
| }
 | |
| 
 | |
| static int TnodesAllocatedPrevRule=0;
 | |
| 
 | |
| /*
 | |
|  * Generate code for a rule.
 | |
|  *
 | |
|  *		rule--> o-->o-Alternatives-o-->o
 | |
|  * Or,
 | |
|  *		rule--> o-->o-Alternative-o-->o
 | |
|  *
 | |
|  * The 1st junction is a RuleBlk.  The second can be a SubBlk or just a junction
 | |
|  * (one alternative--no block), the last is EndRule.
 | |
|  * The second to last is EndBlk if more than one alternative exists in the rule.
 | |
|  *
 | |
|  * To get to the init-action for a rule, we must bypass the RuleBlk,
 | |
|  * and possible SubBlk.
 | |
|  * Mark any init-action as generated so genBlk() does not regenerate it.
 | |
|  */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genRule( Junction *q )
 | |
| #else
 | |
| genRule( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 
 | |
| 	const char * returnValueInitializer;
 | |
| 
 | |
| do {    /* MR10     Change recursion into iteration         */
 | |
| 
 | |
| 	int max_k;
 | |
| 	set follow, rk, f;
 | |
| 	ActionNode *a;
 | |
| 	RuleEntry *r;
 | |
| 	int lastAltEmpty;		/* MR23 */
 | |
| 	static int file = -1;
 | |
| 	int need_right_curly;
 | |
| 	require(q->ntype == nJunction,	"genRule: not junction");
 | |
| 	require(q->jtype == RuleBlk,	"genRule: not rule");
 | |
| 
 | |
| /* MR14 */    require (MR_BackTraceStack.count == 0,"-alpha MR_BackTraceStack.count != 0");
 | |
| /* MR14 */    MR_pointerStackReset(&MR_BackTraceStack);
 | |
| /* MR14 */    if (AlphaBetaTrace) MR_MaintainBackTrace=1;
 | |
| 
 | |
|     CurRule=q->rname;                               /* MR11 */
 | |
| 
 | |
| 	r = (RuleEntry *) hash_get(Rname, q->rname);
 | |
| 	if ( r == NULL ) warnNoFL("Rule hash table is screwed up beyond belief");
 | |
| 	if ( q->file != file )		/* open new output file if need to */
 | |
| 	{
 | |
| /* MR6              									*/
 | |
| /* MR6  Simpler to debug when output goes to stdout rather than a file 	*/
 | |
| /* MR6				                					*/
 | |
| /* MR6 */	if (UseStdout) {
 | |
| /* MR6 */	  output = stdout;
 | |
| /* MR6 */	} else {
 | |
| /* MR6 */  	  if ( output != NULL) fclose( output );
 | |
| /* MR6 */	  output = fopen(OutMetaName(outname(FileStr[q->file])), "w");
 | |
| /* MR6 */	};
 | |
| 		require(output != NULL, "genRule: can't open output file");
 | |
| 
 | |
| #ifdef SPECIAL_FOPEN
 | |
|        special_fopen_actions(OutMetaName(outname(FileStr[q->file]))); /* MR1 */
 | |
| #endif
 | |
| 		if ( file == -1 ) genHdr1(q->file);
 | |
| 		else genHdr(q->file);
 | |
| 		file = q->file;
 | |
| 	}
 | |
| 
 | |
|     if (InfoM) {
 | |
|       fprintf(stderr,"    rule %s\n",q->rname);
 | |
|       fflush(output);
 | |
|     };
 | |
| 
 | |
| #if 0
 | |
|     if (strcmp(q->rname,"***debug***") == 0) {
 | |
|       fprintf(stderr,"***debug*** %s reached\n",q->rname);
 | |
|       MR_break();
 | |
|     };
 | |
| #endif
 | |
| 
 | |
| 	DumpFuncHeader(q,r);
 | |
| 	tabs++;
 | |
| 
 | |
| 	/* MR23 
 | |
| 	   
 | |
| 	   If there is a single return value then it can be initialized in 
 | |
| 	   the declaration using assignment syntax.  If there are multiple
 | |
| 	   return values then antlr creates a struct and initialization takes
 | |
| 	   place element by element for each element of the struct.  For
 | |
|        multiple elements the initialization is by assignment so we have
 | |
|        to wait until all declarations are done before emitting that code -
 | |
|        because of restrictions in C which don't exist in C++.
 | |
| 
 | |
|        In the past (before MR23) the only kind of initialization was
 | |
| 	   the PURIFY macro which was just a memset() of 0.  Now we allow
 | |
| 	   the user to specify an initial value.  PURIFY is still used in C
 | |
| 	   mode because C does not have constructors.  However, PURIFY is
 | |
| 	   not used in C++ mode because it might overwrite information created
 | |
| 	   by elements which have their own ctor.
 | |
|        
 | |
| 	*/
 | |
| 
 | |
| 	if ( q->ret!=NULL )
 | |
| 	{
 | |
| 		if ( hasMultipleOperands(q->ret) )                         /* MR23 */
 | |
| 		{
 | |
| 
 | |
|             /* Emit initialization code later. */
 | |
| 
 | |
| 			gen1("struct _rv%d _retv;\n",r->rulenum);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
|             /* Emit initialization code now. */
 | |
| 
 | |
| 			tab();
 | |
| 			DumpType(q->ret, output);
 | |
|             returnValueInitializer = getInitializer(q->ret);
 | |
|             if (returnValueInitializer == NULL) {                  /* MR23 */
 | |
|       			gen(" _retv;\n");                     		    /* MR1 MR3 */
 | |
|             }                                                      /* MR23 */
 | |
|             else {                                                 /* MR23 */
 | |
|                 gen1(" _retv = %s;\n", returnValueInitializer);    /* MR23 */
 | |
|             }                                                      /* MR23 */
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
|     OutLineInfo(output,q->line,FileStr[q->file]);
 | |
| 
 | |
|     if (InfoM) {
 | |
|       fflush(output);
 | |
|     };
 | |
| 
 | |
| 	gen("zzRULE;\n");
 | |
| 	if ( FoundException )
 | |
| 	{
 | |
| 		gen("int _sva=1;\n");
 | |
| 	}
 | |
| 	if ( GenCC && GenAST )
 | |
| 		gen("ASTBase *_ast = NULL, *_sibling = NULL, *_tail = NULL;\n");
 | |
| 	if ( GenCC ) genTokenPointers(q);
 | |
| 	if ( GenCC&&GenAST ) genASTPointers(q);
 | |
| 	if ( q->el_labels!=NULL ) genElementLabels(q->el_labels);
 | |
| 	if ( FoundException ) gen("int _signal=NoSignal;\n");
 | |
| 
 | |
| 	if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel);
 | |
| 
 | |
| /* MR10 */  /* move zzTRACEIN to before init action */
 | |
| 
 | |
| /* MR10 */	if ( TraceGen ) {
 | |
| /* MR10 */		if ( GenCC ) {gen1("zzTRACEIN(\"%s\");\n", q->rname);}
 | |
| /* MR10 */		else gen1("zzTRACEIN((ANTLRChar *)\"%s\");\n", q->rname);
 | |
| /* MR10 */	}
 | |
| 
 | |
| /* MR7      Moved PURIFY() to after all local variables have been declared */
 | |
| /* MR7      so that the generated code is valid C as well as C++           */
 | |
| /* MR7        Jan Mikkelsen 10-June-1997                                   */
 | |
| 
 | |
| 
 | |
|      /*
 | |
|        MR23    Do the PURIFY macro only for C mode.
 | |
|                C++ users should use constructors or initialization expressions.
 | |
|      */
 | |
| 
 | |
| 	if ( q->ret != NULL )                                            /* MR7 */
 | |
| 	{                                                                /* MR7 */
 | |
| 		if (hasMultipleOperands(q->ret)) {                           /* MR23 */
 | |
| 			if (PURIFY == TRUE) {
 | |
|                 gen1("PCCTS_PURIFY(_retv,sizeof(struct _rv%d))\n",r->rulenum); /* MR23 */
 | |
|             }
 | |
|         }                                                            /* MR7 */
 | |
| 		else {                                                       /* MR7 */
 | |
| 
 | |
| 			/* MR23
 | |
| 			   If there were only one return value operand and
 | |
| 			   it had an initializer then it would have been
 | |
| 			   initialized in the declaration.
 | |
| 			*/
 | |
| 
 | |
| 			returnValueInitializer = getInitializer(q->ret);         /* MR23 */
 | |
| 			if (returnValueInitializer == NULL) {                    /* MR23 */
 | |
|     			if (PURIFY == TRUE) {
 | |
|         			gen("PCCTS_PURIFY(_retv,sizeof(");               /* MR23 */
 | |
| 	    			DumpType(q->ret, output);                        /* MR7 */
 | |
| 					gen("))\n");                                     /* MR7 */
 | |
| 				}
 | |
| 			}                                                        /* MR23 */
 | |
| 		}                                                            /* MR7 */
 | |
| 
 | |
|         if (hasMultipleOperands(q->ret)) {                           /* MR23 */
 | |
|           DumpInitializers(output, r, q->ret);                       /* MR23 */
 | |
|         }
 | |
| 
 | |
| 	}
 | |
| 	if ( !GenCC ) gen("zzMake0;\n");
 | |
| 	if ( FoundException ) gen("*_retsignal = NoSignal;\n");
 | |
| 
 | |
| 	if ( !GenCC ) gen("{\n");
 | |
| 
 | |
| 	if ( has_guess_block_as_first_item((Junction *)q->p1) )
 | |
| 	{
 | |
| 		gen("zzGUESS_BLOCK\n");
 | |
| 	}
 | |
| 
 | |
| 	/* L o o k  F o r  I n i t  A c t i o n */
 | |
| 	if ( ((Junction *)q->p1)->jtype == aSubBlk )
 | |
| 		a = findImmedAction( ((Junction *)q->p1)->p1 );
 | |
| 	else
 | |
| 		a = findImmedAction( q->p1 );	/* only one alternative in rule */
 | |
| 	if ( a!=NULL && !a->is_predicate)
 | |
| 	{
 | |
|  /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1);
 | |
|   		    a->done = 1;	/* ignore action. We have already handled it */
 | |
| 	}
 | |
| 
 | |
| 	BlkLevel++;
 | |
| 	q->visited = TRUE;				/* mark RULE as visited for FIRST/FOLLOW */
 | |
|     BlockPreambleOption((Junction *)q->p1, NULL);   /* MR21 */
 | |
| 	f = genBlk((Junction *)q->p1, RuleBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
 | |
| 	if ( q->p1 != NULL )
 | |
| 		if ( ((Junction *)q->p1)->p2 != NULL )
 | |
| 			{tab(); makeErrorClause((Junction *)q->p1,f,max_k,0 /* use plus block bypass ? */);}
 | |
| 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
 | |
| 	freeBlkFsets((Junction *)q->p1);
 | |
| 	q->visited = FALSE;
 | |
| 	--BlkLevel;
 | |
| 	if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel);
 | |
| 
 | |
|     genTraceOut(q);
 | |
| 
 | |
| 	if ( q->ret!=NULL ) gen("return _retv;\n") else gen("return;\n");
 | |
| 	/* E r r o r  R e c o v e r y */
 | |
| 	NewSet();
 | |
| 	rk = empty;
 | |
| 
 | |
| /* MR14 */    if (r->dontComputeErrorSet) {
 | |
| /* MR14 */      follow=empty;
 | |
|               } else {
 | |
|                 MR_pointerStackReset(&MR_BackTraceStack);   /* MR14 */
 | |
|                 MR_ErrorSetComputationActive=1;
 | |
|                 REACH(q->end, 1, &rk, follow);
 | |
|                 MR_ErrorSetComputationActive=0;
 | |
|                 require (MR_BackTraceStack.count == 0,"K: MR_BackTraceStack.count != 0");
 | |
|               }
 | |
| 
 | |
|   FillSet( follow );
 | |
| 	set_free( follow );
 | |
| 
 | |
|   /* MR20 G. Hobbelt 
 | |
|      Isn't it so that "fail:" is ONLY referenced when:
 | |
| 
 | |
|       	 !FoundException || FoundGuessBlk ?
 | |
| 
 | |
|      Therefore add the "if" around this piece of code generation...
 | |
| 
 | |
|      Should guessing mode also use _handler label instead of "fail"
 | |
|      when exception handling is active? gen can automatically put 
 | |
|      "if (guessing)" there so as to skip all kinds of user code.
 | |
| 
 | |
|    */
 | |
| 
 | |
| 	if ( !FoundException || FoundGuessBlk )  /* MR20 G. Hobbelt */
 | |
|   {                                          /* MR20 G. Hobbelt */
 | |
| 	_gen("fail:\n");
 | |
| 	if ( !GenCC ) gen("zzEXIT(zztasp1);\n");
 | |
| 	if ( FoundGuessBlk ) {
 | |
| 	   	if ( !GenCC ) {gen("if ( zzguessing ) zzGUESS_FAIL;\n");}
 | |
| 		else gen("if ( guessing ) zzGUESS_FAIL;\n");
 | |
| 	}
 | |
| 	if ( q->erraction!=NULL )
 | |
| 		dumpAction(q->erraction, output, tabs, q->file, q->line, 1);
 | |
| 	if ( GenCC )
 | |
| 	{
 | |
| 		gen1("syn(zzBadTok, %s, zzMissSet, zzMissTok, zzErrk);\n",
 | |
| 			 r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		gen1("zzsyn(zzMissText, zzBadTok, %s, zzMissSet, zzMissTok, zzErrk, zzBadText);\n",
 | |
| 			 r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup);
 | |
| 	}
 | |
| 	gen3("%sresynch(setwd%d, 0x%x);\n", GenCC?"":"zz", wordnum, 1<<setnum);
 | |
| 
 | |
| 	if ( q->ret!=NULL ) {
 | |
|       genTraceOut(q);
 | |
|       gen("return _retv;\n");
 | |
|     } else if ( q->exceptions!=NULL ) {
 | |
|       genTraceOut(q);
 | |
|       gen("return;\n");
 | |
|     } else if (!FoundException) {       /* MR10 */
 | |
|       genTraceOut(q);                   /* MR10 */
 | |
|     };
 | |
| 
 | |
|   }                                        /* MR20 G. Hobbelt */
 | |
| 
 | |
| 	if ( !GenCC ) gen("}\n");
 | |
| 
 | |
| 	/* Gen code for exception handlers */
 | |
|     /* make sure each path out contains genTraceOut() */
 | |
| 
 | |
| 	if ( q->exceptions!=NULL )
 | |
| 	{
 | |
| 
 | |
| 		gen("/* exception handlers */\n");
 | |
| 
 | |
| 		dumpExceptions(q->exceptions);
 | |
| 
 | |
|         if ( !r->has_rule_exception )
 | |
|         {
 | |
|             _gen("_handler:\n");
 | |
|             gen("zzdflthandlers(_signal,_retsignal);\n");
 | |
|         }
 | |
| /*  MR20 G. Gobbelt   The label "adios" is never referenced */
 | |
| 
 | |
| #if 0
 | |
| 	_gen("_adios:\n");
 | |
| #endif
 | |
|     if ( q->ret!=NULL ) {
 | |
|             genTraceOut(q);
 | |
|             gen("return _retv;\n");
 | |
|         }
 | |
| 		else {
 | |
|             genTraceOut(q);
 | |
|             gen("return;\n");
 | |
|         }
 | |
| 	}
 | |
| 	else if ( FoundException )
 | |
| 	{
 | |
|       _gen("_handler:\n");
 | |
|       gen("zzdflthandlers(_signal,_retsignal);\n");
 | |
| 
 | |
| /* MR1                                                                      */
 | |
| /* MR1	 7-Apr-97 Fix suggested by: John Bair (jbair@iftime.com)            */
 | |
| /* MR1							                                            */
 | |
| 
 | |
|    	  if ( q->ret != NULL) {			                             /* MR1 */
 | |
|             genTraceOut(q);                                          /* MR10 */
 | |
|             gen("return _retv;\n");			                         /* MR1 */
 | |
|       } else {					                                     /* MR1 */
 | |
|             genTraceOut(q);                                          /* MR10 */
 | |
|             gen("return;\n")    ;				                     /* MR1 */
 | |
|       };						                                     /* MR1 */
 | |
| 	}
 | |
| 
 | |
| 	tabs--;
 | |
| 	gen("}\n");
 | |
| 
 | |
| /* MR10     Tired of looking at stacks that are as deep as the number of    */
 | |
| /* MR10       rules.  Changes recursion to iteration.                       */
 | |
| 
 | |
|     MR_releaseResourcesUsedInRule( (Node *) q );      /* MR10 */
 | |
| 
 | |
|     if (InfoT) {
 | |
|       fprintf(output,"\n/* tnodes created for rule %s:  %d */\n",
 | |
|                 q->rname, (TnodesAllocated-TnodesAllocatedPrevRule) );
 | |
|     };
 | |
| 
 | |
|     TnodesAllocatedPrevRule=TnodesAllocated;
 | |
| 
 | |
|     if (q->p2 == NULL) dumpAfterActions( output );
 | |
|     q=(Junction *)q->p2;
 | |
|     require(q==NULL || q->jtype==RuleBlk,"RuleBlk p2 does not point to another RuleBlk");
 | |
| 
 | |
| } while (q != NULL);
 | |
| 
 | |
| /**** The old code                           ****/
 | |
| /****	if ( q->p2 != NULL ) {TRANS(q->p2);} ****/ /* generate code for next rule too */
 | |
| /****	else dumpAfterActions( output );     ****/
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /* This is for the function definition, not the declaration. */
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| DumpFuncHeader( Junction *q, RuleEntry *r )
 | |
| #else
 | |
| DumpFuncHeader( q, r )
 | |
| Junction *q;
 | |
| RuleEntry *r;
 | |
| #endif
 | |
| {
 | |
| /*								                                            */
 | |
| /*  MR1 10-Apr-97  MR1  Simplify insertion of commas in function header     */
 | |
| /*								                                            */
 | |
| 	int	needComma;					                                 /* MR1 */
 | |
| 
 | |
| 
 | |
| 	/* A N S I */
 | |
| 	_gen("\n");
 | |
| 	if ( q->ret!=NULL )
 | |
| 	{
 | |
| 		if ( hasMultipleOperands(q->ret) )                            /* MR23 */
 | |
| 		{
 | |
| 			if (GenCC) gen2("%s::_rv%d\n", CurrentClassName, r->rulenum)
 | |
| 			else gen1("struct _rv%d\n",r->rulenum);
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			DumpType(q->ret, output);
 | |
| 			gen("\n");
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		_gen("void\n");
 | |
| 	}
 | |
| /*  MR1			                                                            */
 | |
| /*  MR1	10-Apr-97  133MR1	Replace __STDC__ with __USE_PROTOS              */
 | |
| /*  MR1								                                        */
 | |
| 	if ( !GenCC ) _gen("#ifdef __USE_PROTOS\n");		     /* MR1 */
 | |
| 	if ( !GenCC ) gen2("%s%s(", RulePrefix, q->rname)
 | |
| 	else gen3("%s::%s%s(", CurrentClassName, RulePrefix,q->rname);
 | |
| 
 | |
|     	/* If we generate C++ method names, we must hide default arguments */
 | |
|         /* which can appear in the parameter declaration list.             */
 | |
|         /* NOTICE: this is done only here, for the method definition, but  */
 | |
|         /*         not for the method declaration inside the class         */
 | |
|         /*         definition. This is exactly the behaviour defined in    */
 | |
|         /*         C++ standard for default parameters.                    */
 | |
| 
 | |
| 	DumpANSIFunctionArgDef(output,q, 0 /* emit initializers ? */);
 | |
| 	_gen("\n");
 | |
| 
 | |
| 	if ( GenCC ) {
 | |
|       gen("{\n");
 | |
|       return;
 | |
|     }
 | |
| 
 | |
| 	/* K & R */
 | |
| 	gen("#else\n");
 | |
| 	gen2("%s%s(", RulePrefix, q->rname);
 | |
| 	needComma=0;						                             /* MR1 */
 | |
| 	if ( GenAST )						                             /* MR1 */
 | |
| 	{							                                     /* MR1 */
 | |
| 		_gen("_root");					                             /* MR1 */
 | |
| 		needComma=1;					                             /* MR1 */
 | |
| 	}							                                     /* MR1 */
 | |
| 	if ( FoundException )					                         /* MR1 */
 | |
| 	{							                                     /* MR1 */
 | |
| 		if (needComma) {_gen(",");needComma=0;};	                 /* MR1 */
 | |
| 		_gen("_retsignal");				                             /* MR1 */
 | |
| 		needComma=1;					                             /* MR1 */
 | |
| 	}							                                     /* MR1 */
 | |
| /* MR5	Change below by Jan Mikkelsen (janm@zeta.org.au) 26-May-97      MR5 */
 | |
| 	DumpListOfParmNames( q->pdecl, output, needComma );	             /* MR5 */
 | |
| 	gen(")\n");
 | |
| 	if ( GenAST ) gen("AST **_root;\n");
 | |
| 	if ( FoundException ) gen("int *_retsignal;\n");
 | |
| 	DumpOldStyleParms( q->pdecl, output );
 | |
| 	gen("#endif\n");
 | |
|     gen("{\n");
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| DumpANSIFunctionArgDef(FILE *f, Junction *q, int bInitializer)
 | |
| #else
 | |
| DumpANSIFunctionArgDef(f,q,bInitializer)
 | |
| FILE *f;
 | |
| Junction *q;
 | |
| int bInitializer;
 | |
| #endif
 | |
| {
 | |
| 	if ( GenAST )
 | |
| 	{
 | |
| 		if ( GenCC ) {fprintf(f,"ASTBase **_root");}
 | |
| 		else fprintf(f,"AST**_root");
 | |
| 		if ( !FoundException && q->pdecl!=NULL ) fprintf(f,",");
 | |
| 	}
 | |
| 	if ( FoundException )
 | |
| 	{
 | |
| 		if ( GenAST ) fprintf(f,",");
 | |
| 		fprintf(f,"int *_retsignal");
 | |
| 		if ( q->pdecl!=NULL ) {
 | |
|             fprintf(f,",");
 | |
|         }
 | |
| 	}
 | |
| 	if ( q->pdecl!=NULL ) {
 | |
|         DumpFormals(f, q->pdecl, bInitializer);     /* MR23 */
 | |
|     }
 | |
| 	else {
 | |
|         if ( !GenAST && !FoundException ) {
 | |
|             fprintf(f,"void");
 | |
|         }
 | |
|     }
 | |
| 	fprintf(f,")");
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genJunction( Junction *q )
 | |
| #else
 | |
| genJunction( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| 	require(q->ntype == nJunction,	"genJunction: not junction");
 | |
| 	require(q->jtype == Generic,	"genJunction: not generic junction");
 | |
| 
 | |
| 	if ( q->p1 != NULL ) TRANS(q->p1);
 | |
| 	if ( q->p2 != NULL ) TRANS(q->p2);
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genEndBlk( Junction *q )
 | |
| #else
 | |
| genEndBlk( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genEndRule( Junction *q )
 | |
| #else
 | |
| genEndRule( q )
 | |
| Junction *q;
 | |
| #endif
 | |
| {
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genHdr( int file )
 | |
| #else
 | |
| genHdr( file )
 | |
| int file;
 | |
| #endif
 | |
| {
 | |
|     int     i;
 | |
| 
 | |
| 	_gen("/*\n");
 | |
| 	_gen(" * A n t l r  T r a n s l a t i o n  H e a d e r\n");
 | |
| 	_gen(" *\n");
 | |
| 	_gen(" * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
 | |
| 	_gen(" * Purdue University Electrical Engineering\n");
 | |
| 	_gen(" * With AHPCRC, University of Minnesota\n");
 | |
| 	_gen1(" * ANTLR Version %s\n", Version);
 | |
| 	_gen(" *\n");
 | |
| /* MR10 */    _gen(" *  ");
 | |
| /* MR10 */    for (i=0 ; i < Save_argc ; i++) {
 | |
| /* MR10 */      _gen(" ");
 | |
| /* MR10 */      _gen1("%s", Save_argv[i]);
 | |
| /* MR10 */    };
 | |
| 	_gen("\n");
 | |
| 	_gen(" *\n");
 | |
|     _gen(" */\n\n");
 | |
| 	if (FirstAction != NULL ) dumpAction( FirstAction, output, 0, -1, 0, 1);    /* MR11 MR15b */
 | |
| 	_gen1("#define ANTLR_VERSION	%s\n", VersionDef);
 | |
| 	_gen("#include \"pcctscfg.h\"\n");
 | |
| 	_gen("#include \"pccts_stdio.h\"\n");
 | |
| 	if ( strcmp(ParserName, DefaultParserName)!=0 )
 | |
| 		_gen2("#define %s %s\n", DefaultParserName, ParserName);
 | |
|    	if ( strcmp(ParserName, DefaultParserName)!=0 )
 | |
| 		{_gen1("#include \"%s\"\n", RemapFileName);}
 | |
|     OutLineInfo(output,1,FileStr[file]);
 | |
| 	if ( GenCC ) {
 | |
| 		if ( UserTokenDefsFile != NULL )
 | |
| 			fprintf(output, "#include %s\n", UserTokenDefsFile);
 | |
| 		else
 | |
| 			fprintf(output, "#include \"%s\"\n", DefFileName);
 | |
| 	}
 | |
| 
 | |
| 	if ( HdrAction != NULL ) dumpAction( HdrAction, output, 0, -1, 0, 1);
 | |
| 	if ( !GenCC && FoundGuessBlk )
 | |
| 	{
 | |
| 		_gen("#define ZZCAN_GUESS\n");
 | |
| 		_gen("#include \"pccts_setjmp.h\"\n");  /* MR15 K.J. Cummings (cummings@peritus.com) */
 | |
| 	}
 | |
| 	if ( FoundException )
 | |
| 	{
 | |
| 		_gen("#define EXCEPTION_HANDLING\n");
 | |
| 		_gen1("#define NUM_SIGNALS %d\n", NumSignals);
 | |
| 	}
 | |
| 	if ( !GenCC && OutputLL_k > 1 ) _gen1("#define LL_K %d\n", OutputLL_k);
 | |
| 	if ( GenAST&&!GenCC ) _gen("#define GENAST\n\n");
 | |
| 	if ( GenAST ) {
 | |
| 		if ( GenCC ) {_gen1("#include \"%s\"\n\n", ASTBASE_H);}
 | |
| 		else _gen("#include \"ast.h\"\n\n");
 | |
| 	}
 | |
| 	if ( !GenCC && DemandLookahead ) _gen("#define DEMAND_LOOK\n\n");
 | |
| #ifdef DUM
 | |
| 	if ( !GenCC && LexGen ) {
 | |
| 		_gen1("#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken));
 | |
| 	}
 | |
| #endif
 | |
| 	/* ###WARNING: This will have to change when SetWordSize changes */
 | |
| 	if ( !GenCC ) _gen1("#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned));
 | |
|     if (TraceGen) {
 | |
|       _gen("#ifndef zzTRACE_RULES\n");  /* MR20 */
 | |
|       _gen("#define zzTRACE_RULES\n");  /* MR20 */
 | |
|       _gen("#endif\n");                 /* MR22 */
 | |
|     };
 | |
| 	if ( !GenCC ) {_gen("#include \"antlr.h\"\n");}
 | |
| 	else {
 | |
| 		_gen1("#include \"%s\"\n", APARSER_H);
 | |
| 		_gen1("#include \"%s.h\"\n", CurrentClassName);
 | |
| 	}
 | |
| 	if ( !GenCC ) {
 | |
| 		if ( UserDefdTokens )
 | |
| 			{_gen1("#include %s\n", UserTokenDefsFile);}
 | |
| 		/* still need this one as it has the func prototypes */
 | |
| 		_gen1("#include \"%s\"\n", DefFileName);
 | |
| 	}
 | |
| 	/* still need this one as it defines the DLG interface */
 | |
| 	if ( !GenCC ) _gen("#include \"dlgdef.h\"\n");
 | |
| 	if ( LexGen && GenCC ) _gen1("#include \"%s\"\n", DLEXERBASE_H);
 | |
| 	if ( GenCC ) _gen1("#include \"%s\"\n", ATOKPTR_H);
 | |
| 	if ( !GenCC && LexGen ) _gen1("#include \"%s\"\n", ModeFileName);
 | |
| 
 | |
| /* MR10  Ofer Ben-Ami (gremlin@cs.huji.ac.il)           */
 | |
| /* MR10    Finally, a definition of the Purify macro    */
 | |
| 
 | |
|     if (PURIFY == TRUE) {                                                   /* MR23 */
 | |
|         _gen("\n/* MR23 In order to remove calls to PURIFY use the antlr"); /* MR23 */
 | |
|         _gen(" -nopurify option */\n\n");                                   /* MR23 */
 | |
|     	_gen("#ifndef PCCTS_PURIFY\n");
 | |
|         _gen("#define PCCTS_PURIFY(r,s) memset((char *) &(r),'\\0',(s));\n");
 | |
|         _gen("#endif\n\n");
 | |
|     }                                                                       /* MR23 */
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genHdr1( int file )
 | |
| #else
 | |
| genHdr1( file )
 | |
| int file;
 | |
| #endif
 | |
| {
 | |
| 	ListNode *p;
 | |
| 
 | |
| 	genHdr(file);
 | |
| 	if ( GenAST )
 | |
| 	{
 | |
| 		if ( !GenCC ) {
 | |
| 			_gen("#include \"ast.c\"\n");
 | |
| 			_gen("zzASTgvars\n\n");
 | |
| 		}
 | |
| 	}
 | |
| 	if ( !GenCC ) _gen("ANTLR_INFO\n");
 | |
| 	if ( BeforeActions != NULL )
 | |
| 	{
 | |
| 		for (p = BeforeActions->next; p!=NULL; p=p->next)
 | |
| 		{
 | |
| 			UserAction *ua = (UserAction *)p->elem;
 | |
| 			dumpAction( ua->action, output, 0, ua->file, ua->line, 1);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if ( !FoundException ) return;
 | |
| 
 | |
| 	if ( GenCC )
 | |
| 	{
 | |
| 		_gen1("\nvoid %s::\n", CurrentClassName);
 | |
| 		_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
 | |
| 		_gen("{\n");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		_gen("\nvoid\n");
 | |
| /*  MR1				                                                        */
 | |
| /*  MR1	10-Apr-97  133MR1	Replace __STDC__ with __USE_PROTOS              */
 | |
| /*  MR1	                                                                    */
 | |
| 	    _gen("#ifdef __USE_PROTOS\n");                               /* MR1 */
 | |
| 		_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
 | |
| 		_gen("#else\n");
 | |
| 		_gen("zzdflthandlers( _signal, _retsignal )\n");
 | |
| 		_gen("int _signal;\n");
 | |
| 		_gen("int *_retsignal;\n");
 | |
| 		_gen("#endif\n");
 | |
| 		_gen("{\n");
 | |
| 	}
 | |
| 	tabs++;
 | |
| 	if ( DefaultExGroup!=NULL )
 | |
| 	{
 | |
| 		dumpException(DefaultExGroup, 1);
 | |
| 		if ( !hasDefaultException(DefaultExGroup) )
 | |
| 		{
 | |
| 			gen("default :\n");
 | |
| 			tabs++;
 | |
| 			gen("*_retsignal = _signal;\n");
 | |
| 			tabs--;
 | |
| 			gen("}\n");
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		gen("*_retsignal = _signal;\n");
 | |
| 	}
 | |
| 
 | |
| 	tabs--;
 | |
| 	_gen("}\n\n");
 | |
| }
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| genStdPCCTSIncludeFile( FILE *f,char *gate )    /* MR10 */
 | |
| #else
 | |
| genStdPCCTSIncludeFile( f , gate)               /* MR10 */
 | |
| FILE *f;
 | |
| char * gate;                                    /* MR10 */
 | |
| #endif
 | |
| {
 | |
| /* MR10 Ramanathan Santhanam (ps@kumaran.com)           */
 | |
| /* MR10 Same preprocessor symbol use to gate stdpccts.h */
 | |
| /* MR10   even when two grammars are in use.            */
 | |
| /* MR10 Derive gate symbol from -fh filename            */
 | |
| 
 | |
|     if (gate == NULL) {
 | |
|       fprintf(f,"#ifndef STDPCCTS_H\n");          /* MR10 */
 | |
|       fprintf(f,"#define STDPCCTS_H\n");          /* MR10 */
 | |
|     } else {
 | |
|       fprintf(f,"#ifndef STDPCCTS_%s_H\n",gate);  /* MR10 */
 | |
|       fprintf(f,"#define STDPCCTS_%s_H\n",gate);  /* MR10 */
 | |
|     };
 | |
| 	fprintf(f,"/*\n");
 | |
|     if (gate == NULL) {
 | |
| 	  fprintf(f," * %s -- P C C T S  I n c l u d e\n", stdpccts);
 | |
|     } else {
 | |
| 	  fprintf(f," * Standard PCCTS include file with -fh %s -- P C C T S  I n c l u d e\n", stdpccts);
 | |
|     }
 | |
| 	fprintf(f," *\n");
 | |
| 	fprintf(f," * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
 | |
| 	fprintf(f," * Purdue University Electrical Engineering\n");
 | |
| 	fprintf(f," * With AHPCRC, University of Minnesota\n");
 | |
| 	fprintf(f," * ANTLR Version %s\n", Version);
 | |
| 	fprintf(f," */\n\n");
 | |
| 
 | |
|     fprintf(f,"#ifndef ANTLR_VERSION\n");
 | |
| 	fprintf(f,"#define ANTLR_VERSION	%s\n", VersionDef);
 | |
|     fprintf(f,"#endif\n\n");
 | |
| 
 | |
|     if (FirstAction != NULL ) dumpAction(FirstAction, f, 0, -1, 0, 1);  /* MR11 */
 | |
| 
 | |
| 	fprintf(f,"#include \"pcctscfg.h\"\n");
 | |
| 	fprintf(f,"#include \"pccts_stdio.h\"\n");
 | |
| 	if ( GenCC )
 | |
| 	{
 | |
| 		if ( UserDefdTokens )
 | |
| 			fprintf(f, "#include %s\n", UserTokenDefsFile);
 | |
| 		else {
 | |
| 			fprintf(f, "#include \"%s\"\n", DefFileName);
 | |
| 		}
 | |
| 
 | |
| 		fprintf(f, "#include \"%s\"\n", ATOKEN_H);
 | |
| 
 | |
| 		if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1);
 | |
| 
 | |
| 		fprintf(f, "#include \"%s\"\n", ATOKENBUFFER_H);
 | |
| 
 | |
| 		if ( OutputLL_k > 1 ) fprintf(f,"static const unsigned LL_K=%d;\n", OutputLL_k);
 | |
| 		if ( GenAST ) {
 | |
| 			fprintf(f, "#include \"%s\"\n", ASTBASE_H);
 | |
| 		}
 | |
| 
 | |
|         if (TraceGen) {
 | |
|           fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
 | |
|           fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
 | |
|           fprintf(f,"#endif\n");                 /* MR22 */
 | |
|         };
 | |
| 
 | |
| 		fprintf(f,"#include \"%s\"\n", APARSER_H);
 | |
| 		fprintf(f,"#include \"%s.h\"\n", CurrentClassName);
 | |
| 		if ( LexGen ) fprintf(f,"#include \"%s\"\n", DLEXERBASE_H);
 | |
| 		fprintf(f, "#endif\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if ( strcmp(ParserName, DefaultParserName)!=0 )
 | |
| 		fprintf(f, "#define %s %s\n", DefaultParserName, ParserName);
 | |
| 	if ( strcmp(ParserName, DefaultParserName)!=0 )
 | |
| 		fprintf(f, "#include \"%s\"\n", RemapFileName);
 | |
| 	if ( UserTokenDefsFile != NULL )
 | |
| 	   fprintf(f, "#include %s\n", UserTokenDefsFile);
 | |
| 	if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1);
 | |
| 	if ( FoundGuessBlk )
 | |
| 	{
 | |
| 		fprintf(f,"#define ZZCAN_GUESS\n");
 | |
| 		fprintf(f,"#include \"pccts_setjmp.h\"\n");
 | |
| 	}
 | |
|     if (TraceGen) {
 | |
|       fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
 | |
|       fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
 | |
|       fprintf(f,"#endif\n");                 /* MR22 */
 | |
|     };
 | |
| 	if ( OutputLL_k > 1 ) fprintf(f,"#define LL_K %d\n", OutputLL_k);
 | |
| 	if ( GenAST ) fprintf(f,"#define GENAST\n");
 | |
| 	if ( FoundException )
 | |
| 	{
 | |
| /* MR1	 7-Apr-97  1.33MR1					                           */
 | |
| /* MR1	 	   Fix suggested by:				                   */
 | |
| /* MR1		   Francois-Xavier Fontaine (fontaine_f@istvax.ist.lu)         */
 | |
| 
 | |
| 		fprintf(f,"#define EXCEPTION_HANDLING\n");	            /* MR1 */
 | |
| 		fprintf(f,"#define NUM_SIGNALS %d\n", NumSignals);          /* MR1 */
 | |
| 	}
 | |
| 	if ( DemandLookahead ) fprintf(f,"#define DEMAND_LOOK\n");
 | |
| #ifdef DUM
 | |
| 	if ( LexGen ) fprintf(f, "#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken));
 | |
| #endif
 | |
| 	/* ###WARNING: This will have to change when SetWordSize changes */
 | |
| 	fprintf(f, "#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned));
 | |
|     if (TraceGen) {
 | |
|       fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
 | |
|       fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
 | |
|       fprintf(f,"#endif\n");                 /* MR22 */
 | |
|     };
 | |
| 	fprintf(f,"#include \"antlr.h\"\n");
 | |
| 	if ( GenAST ) fprintf(f,"#include \"ast.h\"\n");
 | |
| 	if ( UserDefdTokens )
 | |
| 		fprintf(f, "#include %s\n", UserTokenDefsFile);
 | |
| 	/* still need this one as it has the func prototypes */
 | |
| 	fprintf(f, "#include \"%s\"\n", DefFileName);
 | |
| 	/* still need this one as it defines the DLG interface */
 | |
| 	fprintf(f,"#include \"dlgdef.h\"\n");
 | |
| 	/* don't need this one unless DLG is used */
 | |
| 	if ( LexGen ) fprintf(f,"#include \"%s\"\n", ModeFileName);
 | |
| 	fprintf(f,"#endif\n");
 | |
| }
 | |
| 
 | |
| /* dump action 's' to file 'output' starting at "local" tab 'tabs'
 | |
|    Dump line information in front of action if GenLineInfo is set
 | |
|    If file == -1 then GenLineInfo is ignored.
 | |
|    The user may redefine the LineInfoFormatStr to his/her liking
 | |
|    most compilers will like the default, however.
 | |
| 
 | |
|    June '93; changed so that empty lines are left alone so that
 | |
|    line information is correct for the compiler/debuggers.
 | |
| */
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| dumpAction( char *s, FILE *output, int tabs, int file, int line,
 | |
| int final_newline )
 | |
| #else
 | |
| dumpAction( s, output, tabs, file, line, final_newline )
 | |
| char *s;
 | |
| FILE *output;
 | |
| int tabs;
 | |
| int file;
 | |
| int line;
 | |
| int final_newline;
 | |
| #endif
 | |
| {
 | |
|     int inDQuote, inSQuote;
 | |
|     require(s!=NULL, 		"dumpAction: NULL action");
 | |
|     require(output!=NULL,	eMsg1("dumpAction: output FILE is NULL for %s",s));
 | |
| 
 | |
| 	if ( GenLineInfo && file != -1 )
 | |
| 	{
 | |
|         OutLineInfo(output,line,FileStr[file]);
 | |
| 	}
 | |
|     PastWhiteSpace( s );
 | |
| 	/* don't print a tab if first non-white char is a # (preprocessor command) */
 | |
| 	if ( *s!='#' ) {TAB;}
 | |
|     inDQuote = inSQuote = FALSE;
 | |
|     while ( *s != '\0' )
 | |
|     {
 | |
|         if ( *s == '\\' )
 | |
|         {
 | |
|             fputc( *s++, output ); /* Avoid '"' Case */
 | |
|             if ( *s == '\0' ) return;
 | |
|             if ( *s == '\'' ) fputc( *s++, output );
 | |
|             if ( *s == '\"' ) fputc( *s++, output );
 | |
|         }
 | |
|         if ( *s == '\'' )
 | |
|         {
 | |
|             if ( !inDQuote ) inSQuote = !inSQuote;
 | |
|         }
 | |
|         if ( *s == '"' )
 | |
|         {
 | |
|             if ( !inSQuote ) inDQuote = !inDQuote;
 | |
|         }
 | |
|         if ( *s == '\n' )
 | |
|         {
 | |
|             fputc('\n', output);
 | |
| 			s++;
 | |
|             PastWhiteSpace( s );
 | |
|             if ( *s == '}' )
 | |
|             {
 | |
|                 --tabs;
 | |
| 				TAB;
 | |
|                 fputc( *s++, output );
 | |
|                 continue;
 | |
|             }
 | |
|             if ( *s == '\0' ) return;
 | |
| 			if ( *s != '#' )	/* #define, #endif etc.. start at col 1 */
 | |
|             {
 | |
| 				TAB;
 | |
| 			}
 | |
|         }
 | |
|         if ( *s == '}' && !(inSQuote || inDQuote) )
 | |
|         {
 | |
|             --tabs;            /* Indent one fewer */
 | |
|         }
 | |
|         if ( *s == '{' && !(inSQuote || inDQuote) )
 | |
|         {
 | |
|             tabs++;            /* Indent one more */
 | |
|         }
 | |
|         fputc( *s, output );
 | |
|         s++;
 | |
|     }
 | |
|     if ( final_newline ) fputc('\n', output);
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| dumpAfterActions( FILE *output )
 | |
| #else
 | |
| dumpAfterActions( output )
 | |
| FILE *output;
 | |
| #endif
 | |
| {
 | |
| 	ListNode *p;
 | |
| 	require(output!=NULL, "dumpAfterActions: output file was NULL for some reason");
 | |
| 	if ( AfterActions != NULL )
 | |
| 	{
 | |
| 		for (p = AfterActions->next; p!=NULL; p=p->next)
 | |
| 		{
 | |
| 			UserAction *ua = (UserAction *)p->elem;
 | |
| 			dumpAction( ua->action, output, 0, ua->file, ua->line, 1);
 | |
| 		}
 | |
| 	}
 | |
| 	fclose( output );
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Find the next action in the stream of execution.  Do not pass
 | |
|  * junctions with more than one path leaving them.
 | |
|  * Only pass generic junctions.
 | |
|  *
 | |
|  *	Scan forward while (generic junction with p2==NULL)
 | |
|  *	If we stop on an action, return ptr to the action
 | |
|  *	else return NULL;
 | |
|  */
 | |
| static ActionNode *
 | |
| #ifdef __USE_PROTOS
 | |
| findImmedAction( Node *q )
 | |
| #else
 | |
| findImmedAction( q )
 | |
| Node *q;
 | |
| #endif
 | |
| {
 | |
| 	Junction *j;
 | |
| 	require(q!=NULL, "findImmedAction: NULL node");
 | |
| 	require(q->ntype>=1 && q->ntype<=NumNodeTypes, "findImmedAction: invalid node");
 | |
| 	
 | |
| 	while ( q->ntype == nJunction )
 | |
| 	{
 | |
| 		j = (Junction *)q;
 | |
| 		if ( j->jtype != Generic || j->p2 != NULL ) return NULL;
 | |
| 		q = j->p1;
 | |
| 		if ( q == NULL ) return NULL;
 | |
| 	}
 | |
| 	if ( q->ntype == nAction ) return (ActionNode *)q;
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| dumpRetValAssign( char *retval, char *ret_def, RuleRefNode * ruleRef /* MR30 */)
 | |
| #else
 | |
| dumpRetValAssign( retval, ret_def, ruleRef /* MR30 */)
 | |
| char *retval;
 | |
| char *ret_def;
 | |
| RuleRefNode *ruleRefNode;
 | |
| #endif
 | |
| {
 | |
| 	char *q = ret_def;
 | |
| 	
 | |
| 	tab();
 | |
| 	while ( *retval != '\0' && *q != '\0')
 | |
| 	{
 | |
| 		while ( isspace((*retval)) ) retval++;
 | |
| 		while ( *retval!=',' && *retval!='\0' ) fputc(*retval++, output);
 | |
| 		fprintf(output, " = _trv.");
 | |
| 		
 | |
| 		DumpNextNameInDef(&q, output);
 | |
| 		while ( isspace(*q) ) q++;
 | |
| 		fputc(';', output); fputc(' ', output);
 | |
| 		if ( *retval == ',' ) retval++;
 | |
| 	}
 | |
| 	if (*retval == '\0' && *q != '\0') {
 | |
| /* MR30 */    errFL("Fewer output values than output formals for rule reference",
 | |
| /* MR30 */                 FileStr[ruleRef->file],ruleRef->line);
 | |
| 	}
 | |
| 	if (*retval != '\0' && *q == '\0') {
 | |
| /* MR30 */    errFL("More output actuals than output formals for rule reference",
 | |
| /* MR30 */                 FileStr[ruleRef->file],ruleRef->line);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* This function computes the set of tokens that can possibly be seen k
 | |
|  * tokens in the future from point j
 | |
|  */
 | |
| 
 | |
| static set
 | |
| #ifdef __USE_PROTOS
 | |
| ComputeErrorSet( Junction *j, int k, int usePlusBlockBypass)
 | |
| #else
 | |
| ComputeErrorSet( j, k, usePlusBlockBypass )
 | |
| Junction *j;
 | |
| int k;
 | |
| int usePlusBlockBypass;
 | |
| #endif
 | |
| {
 | |
| 	Junction *alt1;
 | |
| 	set a, rk, f;
 | |
| 	require(j->ntype==nJunction, "ComputeErrorSet: non junction passed");
 | |
| 
 | |
| 	f = rk = empty;
 | |
| 	for (alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2)
 | |
| 	{
 | |
|         if (alt1->ignore && ! usePlusBlockBypass) continue;     /* MR21 - Ignore aPlusBlk forward p2 */
 | |
| 		REACH(alt1->p1, k, &rk, a);
 | |
| 		require(set_nil(rk), "ComputeErrorSet: rk != nil");
 | |
| 		set_free(rk);
 | |
| 		set_orin(&f, a);
 | |
| 		set_free(a);
 | |
| 	}
 | |
| 	return f;
 | |
| }
 | |
| 
 | |
| static char *
 | |
| #ifdef __USE_PROTOS
 | |
| tokenFollowSet(TokNode *p)
 | |
| #else
 | |
| tokenFollowSet(p)
 | |
| TokNode *p;
 | |
| #endif
 | |
| {
 | |
|     static char buf[100];
 | |
|     set rk, a;
 | |
|     int n;
 | |
|     rk = empty;
 | |
| 
 | |
|     REACH(p->next, 1, &rk, a);
 | |
|     require(set_nil(rk), "rk != nil");
 | |
|     set_free(rk);
 | |
|     n = DefErrSet( &a, 0, NULL );
 | |
|     set_free(a);
 | |
|     if ( GenCC )
 | |
|         sprintf(buf, "err%d", n);
 | |
|     else
 | |
|         sprintf(buf, "zzerr%d", n);
 | |
|     return buf;
 | |
| }
 | |
| 
 | |
| static void
 | |
| #ifdef __USE_PROTOS
 | |
| makeErrorClause( Junction *q, set f, int max_k, int usePlusBlockBypass )
 | |
| #else
 | |
| makeErrorClause( q, f, max_k, usePlusBlockBypass )
 | |
| Junction *q;
 | |
| set f;
 | |
| int max_k;
 | |
| int usePlusBlockBypass;
 | |
| #endif
 | |
| {
 | |
|     char *  handler_id="";                                           /* MR7 */
 | |
|     int     nilf=0;                                                  /* MR13 */
 | |
|     RuleEntry *ruleEntry;                                            /* MR14 */
 | |
| 
 | |
| 	if ( FoundException )
 | |
| 	{
 | |
| 		_gen("else {\n");
 | |
| 		tabs++;
 | |
| 		if ( FoundGuessBlk )
 | |
| 		{
 | |
| 			if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
 | |
| 			else gen("if ( zzguessing ) goto fail;\n");
 | |
| 		}
 | |
| 		gen("if (_sva) _signal=NoViableAlt;\n");
 | |
| 		gen("else _signal=NoSemViableAlt;\n");
 | |
|         if (q->outerEG != NULL) {
 | |
|           handler_id=q->outerEG->altID;
 | |
| #if 0
 | |
|         } else {
 | |
|           printf("q->curAltNum=%d q->exception_label=%s\n",q->curAltNum,q->exception_label);
 | |
|           gen("*** DEBUG *** outerEG==NULL\n");
 | |
| #endif
 | |
|         };
 | |
| 		gen1("goto %s_handler;  /* MR7 */\n",handler_id);    /* MR7 */
 | |
| 		tabs--;
 | |
| 		gen("}\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if ( max_k == 1 )
 | |
| 	{
 | |
| /* MR13 */  nilf=set_nil(f);
 | |
|     	  	if ( GenCC ) {
 | |
|               _gen1("else {FAIL(1,err%d", DefErrSet1(1,&f,1,NULL));
 | |
|             } else {
 | |
|                _gen1("else {zzFAIL(1,zzerr%d", DefErrSet1(1,&f,1,NULL));
 | |
|             };
 | |
|     		set_free(f);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		int i;
 | |
| 		set_free(f);
 | |
| 		if ( GenCC ) {_gen1("else {FAIL(%d", max_k);}
 | |
| 		else _gen1("else {zzFAIL(%d", max_k);
 | |
| 
 | |
|     ruleEntry = (RuleEntry *) hash_get(Rname,q->rname);
 | |
| 
 | |
| 		for (i=1; i<=max_k; i++)
 | |
| 		{
 | |
| /* MR14 */  if (ruleEntry->dontComputeErrorSet) {
 | |
| /* MR14 */    f=empty;
 | |
|             } else {
 | |
|       	      f = ComputeErrorSet(q, i, usePlusBlockBypass /* use plus block bypass ? */ );
 | |
|             }
 | |
| 
 | |
|       if ( GenCC ) {_gen1(",err%d", DefErrSet( &f, 1, NULL ));}
 | |
| 			else _gen1(",zzerr%d", DefErrSet( &f, 1, NULL ));
 | |
| 			
 | |
| 			set_free(f);
 | |
| 		}
 | |
| 	}
 | |
| 	_gen(",&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;}\n");
 | |
| /* MR13 */  if (nilf) {
 | |
| /* MR13 */    errFL("empty error set for alt - probably because of undefined rule or infinite left recursion",
 | |
| /* MR13 */                 FileStr[q->file],q->line);
 | |
| /* MR13 */    gen(" /* MR13 empty error set for this alt - undef rule ? infinite left recursion ? */");
 | |
| /* MR13 */  };
 | |
| }
 | |
| 
 | |
| static                                                               /* MR7 */
 | |
| #ifdef __USE_PROTOS
 | |
| char * findOuterHandlerLabel(ExceptionGroup *eg)                     /* MR7 */
 | |
| #else
 | |
| char * findOuterHandlerLabel(eg)                                     /* MR7 */
 | |
| ExceptionGroup *eg;                                                  /* MR7 */
 | |
| #endif
 | |
| {
 | |
|   char              *label=NULL;                                     /* MR7 */
 | |
|   ExceptionGroup    *outerEG;                                        /* MR7 */
 | |
| 
 | |
|   if (eg->forRule == 0) {                                            /* MR7 */
 | |
|     if (eg->labelEntry != NULL) {                                    /* MR7 */
 | |
|       outerEG=eg->labelEntry->outerEG;                               /* MR7 */
 | |
|       if (outerEG != NULL) {                                         /* MR7 */
 | |
|         label=outerEG->altID;                                        /* MR7 */
 | |
|         outerEG->used=1;                                             /* MR7 */
 | |
|       };                                                             /* MR7 */
 | |
|     } else if (eg->outerEG != NULL) {                                /* MR7 */
 | |
|       outerEG=eg->outerEG;                                           /* MR7 */
 | |
|       label=outerEG->altID;                                          /* MR7 */
 | |
|       outerEG->used=1;                                               /* MR7 */
 | |
|     };                                                               /* MR7 */
 | |
|   };                                                                 /* MR7 */
 | |
|   return (label==NULL ? "" : label);                                 /* MR7 */
 | |
| }                                                                    /* MR7 */
 | |
| 
 | |
| /*** debug ***/
 | |
| #if 0
 | |
| ** static                                                               /* MR7 */
 | |
| ** #ifdef __USE_PROTOS
 | |
| ** char * findOuterAltHandlerLabel(Junction *startJ)                    /* MR7 */
 | |
| ** #else
 | |
| ** char * findOuterAltHandlerLabel(startJ)                              /* MR7 */
 | |
| ** Junction *startJ;                                                    /* MR7 */
 | |
| ** #endif
 | |
| ** {                                                                    /* MR7 */
 | |
| **   char      *label=NULL;                                             /* MR7 */
 | |
| **   Junction  *alt;                                                    /* MR7 */
 | |
| **                                                                      /* MR7 */
 | |
| **   for (alt=startJ; alt != NULL; alt=alt->outerAltstart) {            /* MR7 */
 | |
| **     label=alt->exception_label;                                      /* MR7 */
 | |
| **     if (label != NULL) break;                                        /* MR7 */
 | |
| **   };                                                                 /* MR7 */
 | |
| **   return (label==NULL ? "" : label);                                 /* MR7 */
 | |
| ** }                                                                    /* MR7 */
 | |
| #endif
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| static void OutLineInfo(FILE *file,int line,char *fileName)
 | |
| #else
 | |
| static void OutLineInfo(file,line,fileName)
 | |
|   FILE *    file;
 | |
|   int       line;
 | |
|   char *    fileName;
 | |
| #endif
 | |
| {
 | |
|     static  char * prevFileName=NULL;
 | |
|     static  char * prevFileNameMS=NULL;
 | |
| 
 | |
|     char *  p;
 | |
|     char *  q;
 | |
| 
 | |
|     if (! GenLineInfo) return;
 | |
| 
 | |
|     if (!GenLineInfoMS) {
 | |
| 	    fprintf(file, LineInfoFormatStr,line,fileName);
 | |
|     } else {
 | |
|       if (fileName == prevFileName) {
 | |
| 	    fprintf(file, LineInfoFormatStr,line,prevFileNameMS);
 | |
|       } else {
 | |
|         if (prevFileNameMS != NULL) free (prevFileNameMS);
 | |
|         prevFileNameMS=(char *)calloc(1,strlen(fileName)+1);
 | |
|         require(prevFileNameMS != NULL,"why not do this in calloc wrapper");
 | |
|         q=prevFileNameMS;
 | |
|         for (p=fileName; *p != 0; p++) {
 | |
|             *q=*p;
 | |
|             if (*q == '\\') *q='/';
 | |
|             q++;
 | |
|         }
 | |
|       }
 | |
|       prevFileName=fileName;
 | |
|     };
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| 
 | |
| /* MR21 */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void OutFirstSetSymbol(Junction *q, char * pSymbol)
 | |
| #else
 | |
| void OutFirstSetSymbol(q, pSymbol)
 | |
|     Junction* q;
 | |
| 	char * pSymbol
 | |
| #endif
 | |
| {
 | |
| 
 | |
| 	set f;
 | |
|     if (pSymbol == NULL) return;
 | |
| 	gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol);
 | |
|     f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */);
 | |
|     DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, "");
 | |
|     set_free(f);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* MR21 */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void BlockPreambleOption(Junction *q, char * pSymbol)
 | |
| #else
 | |
| void BlockPreambleOption(q, pSymbol)
 | |
|     Junction* q;
 | |
| 	char * pSymbol;
 | |
| #endif
 | |
| {
 | |
| 	set f = empty;
 | |
|     if (pSymbol != NULL) {
 | |
|         f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */);
 | |
|     	gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol);
 | |
|         DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, "");
 | |
|     }
 | |
|     set_free(f);
 | |
| }
 | |
| 
 | |
| /* MR21 */
 | |
| 
 | |
| void
 | |
| #ifdef __USE_PROTOS
 | |
| dumpActionPlus(ActionNode *a, char *s, FILE *output, int tabs, int file, int line,
 | |
| int final_newline )
 | |
| #else
 | |
| dumpActionPlus(a, s, output, tabs, file, line, final_newline )
 | |
| ActionNode *a;
 | |
| char *s;
 | |
| FILE *output;
 | |
| int tabs;
 | |
| int file;
 | |
| int line;
 | |
| int final_newline;
 | |
| #endif
 | |
| {
 | |
|     dumpAction(s,output,tabs,file,line,final_newline);
 | |
| }
 | |
| 
 | |
| 
 | |
| #if 0
 | |
| ** #ifdef __USE_PROTOS
 | |
| ** void MR_ErrorSets(Junction *q, int max_k, int usePlusBlockBypass)
 | |
| ** #else
 | |
| ** void MR_ErrorSets(q, max_k, usePlusBlockBypass)
 | |
| ** Junction *q;
 | |
| ** int max_k;
 | |
| ** int usePlusBlockBypass;
 | |
| ** #endif
 | |
| ** {
 | |
| **     int k;
 | |
| **     set setResult;
 | |
| ** 	Junction* alt1;
 | |
| ** 	Junction* p;
 | |
| ** 	set rk;
 | |
| ** 
 | |
| **     require (max_k <= CLL_k, "k > CLL_k");
 | |
| ** 
 | |
| ** 
 | |
| **     for (k = 1; k <= CLL_k; k++) {set_clr(q->fset[k]); }
 | |
| ** 
 | |
| **     for (k = 1; k <= max_k; k++) {
 | |
| **         for (alt1=q; alt1 != NULL; alt1 = (Junction *)alt1->p2)
 | |
| **     	{
 | |
| **             if (alt1->ignore && ! usePlusBlockBypass) continue;
 | |
| **         	p = analysis_point((Junction *)alt1->p1);
 | |
| **     		REACH(p, k, &rk, setResult);
 | |
| **     		require(set_nil(rk), "rk != nil");
 | |
| **             set_orin(&q->fset[k], setResult);
 | |
| **     	}
 | |
| **     }
 | |
| ** }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void DumpInitializers(FILE* output, RuleEntry *r, char * pReturn)
 | |
| #else
 | |
| void DumpInitializers(output, r, pReturn)
 | |
| FILE* output;
 | |
| RuleEntry *r;
 | |
| char * pReturn;
 | |
| #endif
 | |
| {
 | |
| 	char *p = pReturn;
 | |
| 	char *pDataType;
 | |
| 	char *pSymbol;
 | |
| 	char *pEqualSign;
 | |
| 	char *pValue;
 | |
| 	char *pSeparator;
 | |
| 	int nest = 0;
 | |
|     char *q;
 | |
| 
 | |
| 	require(pReturn!=NULL, "DumpInitializer: invalid string"); 
 | |
| 
 | |
|     while (*p != 0) {
 | |
|     	p = endFormal(p,
 | |
|     			      &pDataType,
 | |
|     				  &pSymbol,
 | |
|     				  &pEqualSign,
 | |
|     				  &pValue,
 | |
|     				  &pSeparator,
 | |
|     				  &nest);
 | |
|         if (nest != 0) return;
 | |
|         if (pValue != NULL) {
 | |
| 			tab();
 | |
|             q = strBetween(pSymbol, pEqualSign, pSeparator);
 | |
|             fprintf(output, "_retv.%s", q);
 | |
|             q = strBetween(pValue, NULL, pSeparator);
 | |
|             fprintf(output, " = %s;\n", q);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| void DumpFormals(FILE* output, char * pReturn, int bInitializer)
 | |
| #else
 | |
| void DumpFormals(output, pReturn, bInitializer)
 | |
| FILE* output;
 | |
| char * pReturn;
 | |
| int bInitializer;
 | |
| #endif
 | |
| {
 | |
| 	char *p = pReturn;
 | |
| 	char *pDataType;
 | |
| 	char *pSymbol;
 | |
| 	char *pEqualSign;
 | |
| 	char *pValue;
 | |
| 	char *pSeparator;
 | |
| 	int nest = 0;
 | |
|     char *q;
 | |
|     int count = 0;
 | |
| 
 | |
| 	require(pReturn!=NULL, "DumpFormals: invalid string"); 
 | |
| 
 | |
|     while (*p != 0) {
 | |
|     	p = endFormal(p,
 | |
|     			      &pDataType,
 | |
|     				  &pSymbol,
 | |
|     				  &pEqualSign,
 | |
|     				  &pValue,
 | |
|     				  &pSeparator,
 | |
|     				  &nest);
 | |
|         if (nest != 0) return;
 | |
|         if (count > 0) fprintf(output,",");
 | |
|         if (pDataType != NULL && pSymbol != NULL) {
 | |
|             q = strBetween(pDataType, pSymbol, pSeparator);
 | |
|             fprintf(output, "%s", q);
 | |
|             q = strBetween(pSymbol, pEqualSign, pSeparator);
 | |
|             fprintf(output," %s",q);
 | |
|             if (pValue != NULL) {
 | |
|                 q = strBetween(pValue, NULL, pSeparator);
 | |
|                 if (bInitializer != 0) {
 | |
|                     fprintf(output, " = %s", q);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         count++;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* MR23 Check for empty alt in a more intelligent way.
 | |
|         Previously, an empty alt for genBlk had to point directly
 | |
| 		to the endBlock.  This did not work once I changed {...}
 | |
| 		blocks to look like (...|...| epsilon) since there were
 | |
| 		intervening generics.  This fixes the problem for this
 | |
| 		particular case.  Things like actions or empty blocks of
 | |
| 		various kinds will still cause problems, but I wasn't
 | |
| 		prepared to handle pathological cases like (A|()*). It
 | |
| 		does handle (A | ()), which is a recommended idiom for
 | |
| 		epsilon.
 | |
| 
 | |
|         Actually, this isn't quite correct since it doesn't handle
 | |
| 		the case of the ignore bit in the plus block bypass, but
 | |
| 		I'm too tired to figure out the correct fix, and will just
 | |
| 		work around it.
 | |
| */
 | |
| 
 | |
| #ifdef __USE_PROTOS
 | |
| int isEmptyAlt(Node * alt, Node * endBlock)
 | |
| #else
 | |
| int isEmptyAlt(alt, endBlock)
 | |
| Node * alt;
 | |
| Node * endBlock;
 | |
| #endif
 | |
| {
 | |
| 	Node * n = alt;
 | |
| 	Junction * j;
 | |
| 	while (n != endBlock) {
 | |
| 		switch (n->ntype) {
 | |
| 
 | |
| 			case nRuleRef:
 | |
| 				return 0;
 | |
| 
 | |
| 			case nToken:
 | |
| 				return 0;
 | |
| 
 | |
| 			case nAction:
 | |
| 				return 0;
 | |
| 
 | |
| 			case nJunction:
 | |
| 				goto JUNCTION;
 | |
| 
 | |
| 			default:
 | |
| 				fatal_internal("Invalid node type");
 | |
| 				return 0;
 | |
| 		}
 | |
| JUNCTION:
 | |
| 		j = (Junction *) n;
 | |
| 
 | |
| 		switch (j->jtype) {
 | |
| 			case Generic:
 | |
| 				{
 | |
| 					n = j->p1;
 | |
| 					goto NEXT;
 | |
| 				}
 | |
| 
 | |
| 			case aSubBlk:
 | |
| 				{
 | |
| 					n = j->p1;	/* MR26 */
 | |
| 					goto NEXT;	/* MR26 */
 | |
| 				}
 | |
| 
 | |
| 			case EndBlk:
 | |
| 					return 0;
 | |
| 
 | |
| 			case EndRule:
 | |
| 					return 1;
 | |
| 
 | |
| 			default:
 | |
| 					return 0;
 | |
| 		}
 | |
| NEXT: continue;
 | |
| 	}
 | |
| 	return 1;
 | |
| }
 |