• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * gen.c
3  *
4  * Generate C code (ANSI, K&R, C++)
5  *
6  * SOFTWARE RIGHTS
7  *
8  * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
9  * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
10  * company may do whatever they wish with source code distributed with
11  * PCCTS or the code generated by PCCTS, including the incorporation of
12  * PCCTS, or its output, into commerical software.
13  *
14  * We encourage users to develop software with PCCTS.  However, we do ask
15  * that credit is given to us for developing PCCTS.  By "credit",
16  * we mean that if you incorporate our source code into one of your
17  * programs (commercial product, research project, or otherwise) that you
18  * acknowledge this fact somewhere in the documentation, research report,
19  * etc...  If you like PCCTS and have developed a nice tool with the
20  * output, please mention that you developed it using PCCTS.  In
21  * addition, we ask that this header remain intact in our source code.
22  * As long as these guidelines are kept, we expect to continue enhancing
23  * this system and expect to make other tools available as they are
24  * completed.
25  *
26  * ANTLR 1.33
27  * Terence Parr
28  * Parr Research Corporation
29  * with Purdue University and AHPCRC, University of Minnesota
30  * 1989-2001
31  */
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include "pcctscfg.h"
37 #include "set.h"
38 #include "syn.h"
39 #include "hash.h"
40 #include "generic.h"
41 #include "dlgdef.h"
42 
43 #define NumExprPerLine	4
44 static int on1line=0;
45 static set tokensRefdInBlock;
46 
47 					/* T r a n s l a t i o n  T a b l e s */
48 
49 /* C_Trans[node type] == pointer to function that knows how to translate that node. */
50 #ifdef __cplusplus
51 void (*C_Trans[NumNodeTypes+1])(...) = {
52 	NULL,
53 	NULL,					/* See next table.
54 Junctions have many types */
55 	(void (*)(...)) genRuleRef,
56 	(void (*)(...)) genToken,
57 	(void (*)(...)) genAction
58  };
59 #else
60 void (*C_Trans[NumNodeTypes+1])() = {
61 	NULL,
62 	NULL,					/* See next table.
63 Junctions have many types */
64 	genRuleRef,
65 	genToken,
66 	genAction
67  };
68 #endif
69 
70 /* C_JTrans[Junction type] == pointer to function that knows how to translate that
71  * kind of junction node.
72  */
73 #ifdef __cplusplus
74 void (*C_JTrans[NumJuncTypes+1])(...) = {
75 	NULL,
76 	(void (*)(...)) genSubBlk,
77 	(void (*)(...)) genOptBlk,
78 	(void (*)(...)) genLoopBlk,
79 	(void (*)(...)) genEndBlk,
80 	(void (*)(...)) genRule,
81 	(void (*)(...)) genJunction,
82 	(void (*)(...)) genEndRule,
83 	(void (*)(...)) genPlusBlk,
84 	(void (*)(...)) genLoopBegin
85  };
86 #else
87 void (*C_JTrans[NumJuncTypes+1])() = {
88 	NULL,
89 	genSubBlk,
90 	genOptBlk,
91 	genLoopBlk,
92 	genEndBlk,
93 	genRule,
94 	genJunction,
95 	genEndRule,
96 	genPlusBlk,
97 	genLoopBegin
98  };
99 #endif
100 
101 #define PastWhiteSpace(s)	while (*(s) == ' ' || *(s) == '\t') {s++;}
102 
103 static int tabs = 0;
104 
105 /* MR6	Got tired of text running off page when using standard tab stops */
106 
107 #define TAB { int i; 					                		\
108 	      if (TabWidth==0) { 					                \
109 	         for (i=0; i<tabs; i++) fputc('\t', output);		                \
110 	      } else {           							\
111 		 for (i=0; i<tabs*TabWidth; i++) fputc(' ',output);     	        \
112 	      };	                						\
113 	    }
114 
115 static void
116 #ifdef __USE_PROTOS
117 tab( void )
118 #else
119 tab( )
120 #endif
121 TAB
122 
123 #ifdef __USE_PROTOS
124 static char *tokenFollowSet(TokNode *);
125 static ActionNode *findImmedAction( Node * );
126 static void dumpRetValAssign(char *, char *, RuleRefNode *);		/* MR30 */
127 static void dumpAfterActions(FILE *output);
128 static set ComputeErrorSet(Junction *, int, int);
129 static void makeErrorClause(Junction *, set, int, int);
130 static void DumpFuncHeader( Junction *, RuleEntry * );
131 static int has_guess_block_as_first_item(Junction *);
132 static int genExprSets(set *, int);
133 static void genExprTree( Tree *t, int k );
134 static void genExprTreeOriginal( Tree *t, int k );                  /* MR10 */
135 static char * findOuterHandlerLabel(ExceptionGroup *eg);            /* MR7 */
136 static void OutLineInfo(FILE *file,int line,char *fileName);        /* MR14 */
137 #else
138 static char *tokenFollowSet();
139 static ActionNode *findImmedAction();
140 static void dumpRetValAssign();
141 static void dumpAfterActions();
142 static set ComputeErrorSet();
143 static void makeErrorClause();
144 static void DumpFuncHeader();
145 static int has_guess_block_as_first_item();
146 static int genExprSets();
147 static void genExprTree();
148 static void genExprTreeOriginal();                                  /* MR10 */
149 static char * findOuterHandlerLabel();                              /* MR7 */
150 static void OutLineInfo();                                          /* MR14 */
151 #endif
152 
153 #define gen(s)			{tab(); fprintf(output, s);}
154 #define gen1(s,a)		{tab(); fprintf(output, s,a);}
155 #define gen2(s,a,b)		{tab(); fprintf(output, s,a,b);}
156 #define gen3(s,a,b,c)	{tab(); fprintf(output, s,a,b,c);}
157 #define gen4(s,a,b,c,d)	{tab(); fprintf(output, s,a,b,c,d);}
158 #define gen5(s,a,b,c,d,e)	{tab(); fprintf(output, s,a,b,c,d,e);}
159 #define gen6(s,a,b,c,d,e,f)	{tab(); fprintf(output, s,a,b,c,d,e,f);}
160 #define gen7(s,a,b,c,d,e,f,g)	{tab(); fprintf(output, s,a,b,c,d,e,f,g);}
161 
162 #define _gen(s)			{fprintf(output, s);}
163 #define _gen1(s,a)		{fprintf(output, s,a);}
164 #define _gen2(s,a,b)	{fprintf(output, s,a,b);}
165 #define _gen3(s,a,b,c)	{fprintf(output, s,a,b,c);}
166 #define _gen4(s,a,b,c,d){fprintf(output, s,a,b,c,d);}
167 #define _gen5(s,a,b,c,d,e){fprintf(output, s,a,b,c,d,e);}
168 #define _gen6(s,a,b,c,d,e,f){fprintf(output, s,a,b,c,d,e,f);}
169 #define _gen7(s,a,b,c,d,e,f,g){fprintf(output, s,a,b,c,d,e,f,g);}
170 
171 
172 /* MR11 a convenient place to set a break point */
173 
174 #ifdef __USE_PROTOS
MR_break(void)175 void MR_break(void)
176 #else
177 void MR_break()
178 #endif
179 {
180   return;
181 }
182 
183 /* MR10 genTraceOut(Junction *)      */
184 
185 #ifdef __USE_PROTOS
genTraceOut(Junction * q)186 static void genTraceOut(Junction *q)
187 #else
188 static void genTraceOut(q)
189   Junction  *q;
190 #endif
191 {
192   if ( TraceGen ) {
193 		if ( GenCC ) {gen1("zzTRACEOUT(\"%s\");\n", q->rname);}
194     		else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q->rname);
195   }
196 }
197 
198 static void
199 #ifdef __USE_PROTOS
warn_about_using_gk_option(void)200 warn_about_using_gk_option(void)
201 #else
202 warn_about_using_gk_option()
203 #endif
204 {
205 	static int warned_already=0;
206 
207 	if ( !DemandLookahead || warned_already ) return;
208 	warned_already = 1;
209 	warnNoFL("-gk option could cause trouble for <<...>>? predicates");
210 }
211 
212 void
213 #ifdef __USE_PROTOS
freeBlkFsets(Junction * q)214 freeBlkFsets( Junction *q )
215 #else
216 freeBlkFsets( q )
217 Junction *q;
218 #endif
219 {
220 	int i;
221 	Junction *alt;
222 	require(q!=NULL, "freeBlkFsets: invalid node");
223 
224 	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
225 	{
226 		for (i=1; i<=CLL_k; i++) set_free(alt->fset[i]);
227 	}
228 }
229 
230 /*
231  * Generate a local variable allocation for each token references
232  * in this block.
233  */
234 static void
235 #ifdef __USE_PROTOS
genTokenPointers(Junction * q)236 genTokenPointers( Junction *q )
237 #else
238 genTokenPointers( q )
239 Junction *q;
240 #endif
241 {
242 	/* Rule refs are counted and can be referenced, but their
243 	 * value is not set to anything useful ever.
244 	 *
245      * The ptrs are to be named _tij where i is the current level
246 	 * and j is the element number within an alternative.
247 	 */
248 	int first=1, t=0;
249 	set a;
250 	tokensRefdInBlock = q->tokrefs;
251 
252 	if ( set_deg(q->tokrefs) == 0 ) return;
253 	a = set_dup(q->tokrefs);
254 	gen("ANTLRTokenPtr ");
255 	for (; !set_nil(a); set_rm(t, a))
256 	{
257 		t = set_int(a);
258 		if ( first ) first = 0;
259 		else _gen(",");
260 		if ( !DontCopyTokens ) _gen2("_tv%d%d,", BlkLevel, t);
261 		_gen2("_t%d%d", BlkLevel, t);
262 		if ( !DontCopyTokens ) {_gen2("= &_tv%d%d", BlkLevel, t);}
263 		else _gen("=NULL");
264 	}
265 	_gen(";\n");
266 	set_free(a);
267 }
268 
269 static int
270 #ifdef __USE_PROTOS
hasDefaultException(ExceptionGroup * eg)271 hasDefaultException(ExceptionGroup *eg)
272 #else
273 hasDefaultException(eg)
274 ExceptionGroup *eg;
275 #endif
276 {
277     ListNode *q;
278 
279     for (q = eg->handlers->next; q!=NULL; q=q->next)
280     {
281         ExceptionHandler *eh = (ExceptionHandler *)q->elem;
282         if ( strcmp("default", eh->signalname)==0 ) {
283             return 1;
284         }
285     }
286     return 0;
287 }
288 static void
289 #ifdef __USE_PROTOS
dumpException(ExceptionGroup * eg,int no_default_case)290 dumpException(ExceptionGroup *eg, int no_default_case)
291 #else
292 dumpException(eg, no_default_case)
293 ExceptionGroup *eg;
294 int no_default_case;
295 #endif
296 {
297     char    *outerLabel;                                             /* MR7 */
298     int     altHandler=0;                                            /* MR7 */
299     int     namedHandler=0;                                          /* MR7 */
300 
301     outerLabel=findOuterHandlerLabel(eg);                            /* MR7 */
302 
303     if (eg->label != NULL) {                                         /* MR7 */
304       namedHandler=1;                                                /* MR7 */
305     } else if (eg->forRule) {                                        /* MR7 */
306       /* nothing */                                                  /* MR20 */
307     } else {                                                         /* MR7 */
308       altHandler=1;                                                  /* MR7 */
309     };                                                               /* MR7 */
310 
311 #if 0
312 **     if (! eg->used) {                                             /* MR7 */
313 **     	warnFL("exception group never used",                         /* MR7 */
314 **             FileStr[eg->altstart->file],eg->altstart->line);      /* MR7 */
315 **     };                                                            /* MR7 */
316 #endif
317 
318     if (namedHandler) {                                              /* MR7 */
319 	  gen1("switch ( _signal ) {  /* [%s] */\n",eg->label);          /* MR7 */
320     } else {                                                         /* MR7 */
321 	  gen("switch ( _signal ) {\n");                                 /* MR7 */
322       gen("case NoSignal: break;  /* MR7 */\n");                     /* MR7 */
323     };                                                               /* MR7 */
324 	{
325 		ListNode *q;
326 		for (q = eg->handlers->next; q!=NULL; q=q->next)
327 		{
328 			ExceptionHandler *eh = (ExceptionHandler *)q->elem;
329 			if ( strcmp("default", eh->signalname)==0 ) {
330 				gen("default :\n");
331 				tabs++;
332 				dumpAction(eh->action, output, tabs, -1, 1, 1);
333                 gen("_signal=NoSignal;  /* MR7 */\n");                  /* MR7 */
334                 gen("break;  /* MR7 */\n");                             /* MR7 */
335 				tabs--;
336 				gen("}\n");
337 
338                 /* copied from later code in dumpException */        /* MR7 */
339 
340                 if (namedHandler) {                                  /* MR7 */
341                   gen("if (_signal != NoSignal)");                   /* MR7 */
342                   _gen1(" goto %s_handler;  /* MR7 */\n",outerLabel);/* MR7 */
343                 } else if (altHandler) {                             /* MR7 */
344                   gen1("goto %s_handler;  /* MR7 */\n",outerLabel);  /* MR7 */
345                 };
346 				return;
347 			}
348 			gen1("case %s :\n", eh->signalname);
349 			tabs++;
350 			if ( eh->action != NULL )
351 			{
352 				dumpAction(eh->action, output, tabs, -1, 1, 1);
353                 gen("break;  /* MR7 */\n");                          /* MR7 */
354 			}
355 			tabs--;
356 		}
357 	}
358 	if ( no_default_case ) return;
359 
360 	gen("default :\n");
361     tabs++;                                                         /* MR7 */
362     gen("break;  /* MR7 */\n");                                     /* MR7 */
363     tabs--;                                                         /* MR7 */
364 
365 	tabs++;
366 /*****	gen("*_retsignal = _signal;\n"); *****/
367 
368 	tabs--;
369 	gen("}\n");
370 
371     if (namedHandler) {                                             /* MR7 */
372       gen("if (_signal != NoSignal)");                              /* MR7 */
373       _gen1(" goto %s_handler;  /* MR7 */\n",outerLabel);           /* MR7 */
374     } else if (altHandler) {                                        /* MR7 */
375       gen1("goto %s_handler;  /* MR7 */\n",outerLabel);             /* MR7 */
376     };
377 
378 }
379 
380 static void
381 #ifdef __USE_PROTOS
dumpExceptions(ListNode * list)382 dumpExceptions(ListNode *list)
383 #else
384 dumpExceptions(list)
385 ListNode *list;
386 #endif
387 {
388 	ListNode *p;
389 
390 	for (p = list->next; p!=NULL; p=p->next)
391 	{
392 		ExceptionGroup *eg = (ExceptionGroup *) p->elem;
393 		_gen2("%s%s_handler:\n",
394 			  eg->label==NULL?"":eg->label,
395 			  eg->altID==NULL?"":eg->altID);
396 		if ( eg->altID!=NULL ) dumpException(eg, 0);
397 		else {
398 			/* This must be the rule exception handler */
399 			dumpException(eg, 1);
400 			if ( !hasDefaultException(eg) )
401             {
402                 gen("default :\n");
403                 tabs++;
404                 gen("zzdflthandlers(_signal,_retsignal);\n");
405                 tabs--;
406                 gen("}\n");
407             }
408 		}
409 	}
410 }
411 
412 /* For each element label that is found in a rule, generate a unique
413  * Attribute (and AST pointer if GenAST) variable.
414  */
415 void
416 #ifdef __USE_PROTOS
genElementLabels(ListNode * list)417 genElementLabels(ListNode *list)
418 #else
419 genElementLabels(list)
420 ListNode *list;
421 #endif
422 {
423 	int first=1;
424 	ListNode *p;
425 
426 	if ( GenCC ) {gen("ANTLRTokenPtr");}
427 	else {gen("Attrib");}
428 	for (p = list->next; p!=NULL; p=p->next)
429 	{
430 		char *ep = (char *)p->elem;
431 		if ( first ) first = 0;
432 		else _gen(",");
433 		if ( GenCC ) {_gen1(" %s=NULL",ep);}
434 		else {_gen1(" %s",ep);}
435 	}
436 	_gen(";\n");
437 
438 	if ( !GenAST ) return;
439 
440 	first = 1;
441 	gen("AST");
442 	for (p = list->next; p!=NULL; p=p->next)
443 	{
444 		char *ep = (char *)p->elem;
445 		if ( first ) first = 0;
446 		else _gen(",");
447 		_gen1(" *%s_ast=NULL",ep);
448 	}
449 	_gen(";\n");
450 }
451 
452 /*
453  * Generate a local variable allocation for each token or rule reference
454  * in this block.
455  */
456 static void
457 #ifdef __USE_PROTOS
genASTPointers(Junction * q)458 genASTPointers( Junction *q )
459 #else
460 genASTPointers( q )
461 Junction *q;
462 #endif
463 {
464 	int first=1, t;
465 	set a;
466 
467 	a = set_or(q->tokrefs, q->rulerefs);
468 	if ( set_deg(a) > 0 )
469 	{
470 		gen("AST ");
471 		for (; !set_nil(a); set_rm(t, a))
472 		{
473 			t = set_int(a);
474 			if ( first ) first = 0;
475 			else _gen(",");
476 			_gen2("*_ast%d%d=NULL", BlkLevel, t);
477 		}
478 		set_free(a);
479 	}
480 	_gen(";\n");
481 }
482 
483 static void
484 #ifdef __USE_PROTOS
BLOCK_Head(void)485 BLOCK_Head( void )
486 #else
487 BLOCK_Head( )
488 #endif
489 {
490 	gen("{\n");
491 	tabs++;
492 	if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel);
493 }
494 
495 static void
496 #ifdef __USE_PROTOS
BLOCK_Tail(void)497 BLOCK_Tail( void )
498 #else
499 BLOCK_Tail( )
500 #endif
501 {
502 	if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel);
503 	if ( !GenCC ) gen("}\n");
504 	tabs--;
505 	gen("}\n");
506 }
507 
508 static void
509 #ifdef __USE_PROTOS
BLOCK_Preamble(Junction * q)510 BLOCK_Preamble( Junction *q )
511 #else
512 BLOCK_Preamble( q )
513 Junction *q;
514 #endif
515 {
516 	ActionNode *a;
517 	Junction *begin;
518 
519 	BLOCK_Head();
520 	if ( GenCC ) genTokenPointers(q);
521 	if ( GenCC&&GenAST ) genASTPointers(q);
522 	if ( q->jtype == aPlusBlk ) gen("int zzcnt=1;\n");
523 	if ( q->parm != NULL && !q->predparm ) gen1("zzaPush(%s);\n", q->parm)
524 	else if ( !GenCC ) gen("zzMake0;\n");
525 	if ( !GenCC ) gen("{\n");
526 	if ( q->jtype == aLoopBegin ) begin = (Junction *) ((Junction *)q->p1);
527 	else begin = q;
528 	if ( has_guess_block_as_first_item(begin) )
529 	{
530 		gen("zzGUESS_BLOCK\n");
531 	}
532 	if ( q->jtype == aLoopBegin )
533 		a = findImmedAction( ((Junction *)q->p1)->p1 );	/* look at aLoopBlk */
534 	else
535 		a = findImmedAction( q->p1 );
536 	if ( a!=NULL && !a->is_predicate) {
537 /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1);
538 		   a->done = 1;	/* remove action. We have already handled it */
539 	}
540 }
541 
542 void
543 #ifdef __USE_PROTOS
genCombinedPredTreeContextOrig(Predicate * p)544 genCombinedPredTreeContextOrig( Predicate *p )
545 #else
546 genCombinedPredTreeContextOrig( p )
547 Predicate *p;
548 #endif
549 {
550 	static set *ctx=NULL;		/* genExprSets() is destructive, make copy*/
551 	require(p!=NULL, "can't make context tree for NULL pred tree");
552 
553 #ifdef DBG_PRED
554 	fprintf(stderr, "enter genCombinedPredTreeContextOrig(%s,0x%x) with sets:\n", p->expr, p);
555 	s_fprT(stderr, p->scontext[1]);
556 	fprintf(stderr, "\n");
557 #endif
558 	if ( p->down == NULL )
559 	{
560 /***	if ( p->k>1 && p->tcontext!=NULL ) ***/
561 		if ( p->tcontext!=NULL )
562 		{
563 			_gen("(");
564 			genExprTree(p->tcontext, 1);
565 			_gen(")");
566 		}
567 /***	else if ( p->k==1 && set_deg(p->scontext[1])>0 ) ***/
568 		else if ( set_deg(p->scontext[1])>0 )
569 		{
570 			if ( ctx==NULL ) ctx = (set *)calloc(CLL_k+1, sizeof(set));
571 			require(ctx!=NULL, "ctx cannot allocate");
572 			ctx[0]=empty;
573 			ctx[1]=set_dup(p->scontext[1]);
574 			_gen("(");
575 			genExprSets(&(ctx[0]), p->k);
576 			_gen(")");
577 			set_free(ctx[1]);
578 		}
579 		else if ( p->expr==PRED_AND_LIST || p->expr==PRED_OR_LIST ) {
580 			fatal_internal("pred tree is orphan OR or AND list");
581 		}
582 		else {
583             if (! HoistPredicateContext) {
584               _gen(" 1 /* no context: prc is off */ ");
585             } else {
586               fatal_internal("pred tree context is empty");
587             };
588 		}
589 		return;
590 	}
591 
592 /* MR10 - make AND just like OR */
593 
594 	if ( p->expr == PRED_AND_LIST )
595 	{
596         Predicate *list = p->down;
597         for (; list!=NULL; list=list->right)
598         {
599      	     genCombinedPredTreeContextOrig(list);
600        		 if ( list->right!=NULL ) _gen("|| /* MR10 was wrong */ ");
601         };
602 		return;
603 	}
604 
605 	if ( p->expr == PRED_OR_LIST )
606 	{
607         Predicate *list = p->down;
608         for (; list!=NULL; list=list->right)
609         {
610            genCombinedPredTreeContextOrig(list);
611            if ( list->right!=NULL ) _gen("||");
612         };
613         return;
614      };
615 
616 	fatal("pred tree is really wacked");
617 }
618 
619 /* [genCombinedPredTreeContext] */
620 
621 void
622 #ifdef __USE_PROTOS
genCombinedPredTreeContext(Predicate * p)623 genCombinedPredTreeContext( Predicate *p )
624 #else
625 genCombinedPredTreeContext( p )
626 Predicate *p;
627 #endif
628 {
629   Tree  *t;
630   int   predDepth=0;
631 
632   if (0 && ! MR_usingPredNames && ! MRhoisting) {
633     genCombinedPredTreeContextOrig(p);
634   } else {
635 /* MR13 */    MR_pred_depth(p,&predDepth);
636 /* MR13 */    if (predDepth == 1) {
637 /* MR13 */
638 /* MR13 */      set   scontext[2];
639 /* MR13 */      scontext[0]=empty;
640 /* MR13 */      scontext[1]=MR_compute_pred_set(p);
641 /* MR13 */      if (set_nil(scontext[1])) {
642 /* MR13 */        _gen(" 1 /* MR12 no context (-prc off) */ ");
643 /* MR13 */      } else {
644 /* MR13 */        _gen("(");
645 /* MR13 */        genExprSets(&scontext[0], 1);
646 /* MR13 */        set_free(scontext[1]);
647 /* MR13 */        _gen(")");
648 /* MR13 */      };
649 
650     } else {
651       t=MR_compute_pred_tree_context(p);
652       if (t == NULL) {
653         _gen(" 1 /* MR12 no context (-prc off) */ ");
654       } else {
655         _gen("(");
656         genExprTree(t, 1);
657         Tfree(t);   /* MR10 */
658         _gen(")");
659       };
660     };
661   };
662 }
663 
664 /* [genPredTreeGate] */
665 
666 void
667 #ifdef __USE_PROTOS
genPredTreeGate(Predicate * p,int in_and_expr)668 genPredTreeGate( Predicate *p, int in_and_expr )
669 #else
670 genPredTreeGate( p, in_and_expr )
671 Predicate *p;
672 int in_and_expr;
673 #endif
674 {
675 	if ( in_and_expr )
676 	{
677 		_gen("!(");
678 		genCombinedPredTreeContext(p);
679 		_gen(")||");
680 		if ( p->down!=NULL ) _gen("\n");
681 	}
682 	else
683 	{
684 		_gen("(");
685 		genCombinedPredTreeContext(p);
686 		_gen(")&&");
687 		if ( p->down!=NULL ) _gen("\n");
688 	}
689 }
690 
691 #ifdef __USE_PROTOS
genPredEntry(Predicate * p,int outer)692 void genPredEntry(Predicate *p,int outer)
693 #else
694 void genPredEntry(p,outer)
695   Predicate     *p;
696   int           outer;
697 #endif
698 {
699     int         inverted=0;
700     Predicate   *q;
701     int         localOuter=outer;
702     int         needRP=0;
703 
704     if (p == NULL) return;
705 
706     if (p->predEntry != NULL && p->predEntry->predLiteral != NULL) {
707       if (p->inverted != p->predEntry->pred->inverted) {
708         _gen("! /* inverted pred */ (");
709         needRP=1;
710       } else {
711         if (!localOuter) _gen("(");
712         needRP=1;
713       };
714       dumpAction(p->predEntry->predLiteral,output,0,p->source->file,p->source->line,0);
715       if (needRP) _gen(")");
716       return;
717     };
718 
719     inverted=p->inverted;
720 
721     if (inverted) {
722       _gen(" ! /* inverted pred */ (");
723       localOuter=1;
724     };
725 
726     if (p->expr == PRED_OR_LIST) {
727       if (!localOuter) _gen("(");
728       for (q=p->down; q != NULL ; q=q->right) {
729         genPredEntry(q,0);
730         if (q->right != NULL) _gen(" || ");
731       };
732       if (!localOuter) _gen(")");
733     } else if (p->expr == PRED_AND_LIST) {
734       if (!localOuter) _gen("(");
735       for (q=p->down; q != NULL ; q=q->right) {
736         genPredEntry(q,0);
737         if (q->right != NULL) _gen(" && ");
738       };
739       if (!localOuter) _gen(")");
740     } else {
741       if (!localOuter) _gen("(");
742       require (p->source != NULL,"predEntry->source == NULL");
743       require (p->source->inverted == 0,"dumpPredEntry p->source->inverted != 0");
744       dumpAction(p->source->action,output,0,p->source->file,p->source->line,0);
745       if (!localOuter) _gen(")");
746     };
747 
748     if (inverted) {
749         _gen(")");
750     }
751 }
752 
753 void
754 #ifdef __USE_PROTOS
dumpPredAction(ActionNode * anode,char * s,FILE * output,int tabs,int file,int line,int final_newline)755 dumpPredAction(ActionNode *anode,
756                     char *s,FILE *output,int tabs,int file,int line,int final_newline)
757 #else
758 dumpPredAction(anode,
759                     s,output,tabs,file,line,final_newline)
760 
761     ActionNode  *anode;
762     char        *s;
763     FILE        *output;
764     int         tabs;
765     int         file;
766     int         line;
767     int         final_newline;
768 #endif
769 {
770     PredEntry   *predEntry=anode->predEntry;
771     int         inverted=anode->inverted;
772     Predicate   *workPred;
773 
774     if (predEntry == NULL) {
775 
776       /* inline predicate literal */
777 
778       require(inverted == 0,"dumpPredAction action->inverted");
779   	  dumpAction(s,output,tabs,file,line,final_newline);
780 
781     } else {
782 
783       /* a reference to a predicate - possibly with an inverted source */
784 
785       if (predEntry->predLiteral != NULL) {
786         if (inverted) _gen("! /* inverted pred */ (");
787         dumpAction(predEntry->predLiteral,output,0,anode->file,anode->line,0);
788         if (inverted) _gen(")");
789       } else {
790         workPred=predicate_dup(predEntry->pred);
791         if (inverted) workPred->inverted=!workPred->inverted;
792         genPredEntry(workPred,1);
793         predicate_free(workPred);
794       };
795     };
796 }
797 
798 /* [genPred] */
799 
800 void
801 #ifdef __USE_PROTOS
genPred(Predicate * p,Node * j,int suppress_sva)802 genPred(Predicate *p, Node *j,int suppress_sva)
803 #else
804 genPred(p,j,suppress_sva)
805     Predicate   *p;
806     Node        *j;
807     int         suppress_sva;
808 #endif
809 {
810 	if ( FoundException && !suppress_sva) {_gen("(_sva=(");}    /* MR11 suppress_sva */
811 	else {_gen("(");}
812 	if ( GenLineInfo && j->file != -1 ) _gen("\n");
813     if (p->source != NULL && p->source->ampersandPred != NULL) {
814       if (p->source->ampersandPred->k == 1) {
815 
816             set     ctx[2];
817 
818 			ctx[0]=empty;
819 			ctx[1]=set_dup(p->source->ampersandPred->scontext[1]);
820 
821 			_gen("(");
822 			genExprSets(&(ctx[0]), p->k);
823 			_gen(") && ");
824 			set_free(ctx[1]);
825       } else {
826         _gen("( ");
827         genExprTree(p->source->ampersandPred->tcontext,1);
828 		_gen(" ) && ");
829       };
830     };
831 
832     dumpPredAction((ActionNode *)p->source,
833                 p->expr, output, 0, -1 /*indicates no line info*/, j->line, 0);
834 
835 	if ( FoundException && !suppress_sva)   /* MR11 suppress_sva */
836          {_gen("),_sva)");}    /* MR10 - get red of "meant ==" messages */
837 	else {_gen(")");}
838 }
839 
840 void
841 #ifdef __USE_PROTOS
MR_distinctORcontextOpt(Predicate * p,Node * j,int in_and_expr)842 MR_distinctORcontextOpt(Predicate *p,Node *j,int in_and_expr)
843 #else
844 MR_distinctORcontextOpt(p,j,in_and_expr)
845     Predicate   *p;
846     Node        *j;
847     int         in_and_expr;
848 #endif
849 {
850     Predicate   *q;
851 
852     _gen(" /* MR10 Distinct OR context optimization */ \n");
853 
854     if (in_and_expr) {
855       gen("zzpf=0,\n");
856       for (q=p->down; q != NULL; q=q->right) {
857         gen("(  ");
858         genCombinedPredTreeContext(q);
859         _gen(" && (zzpf=1, ");
860         genPred(q,j,0);
861         _gen("  )) ||\n");
862       };
863       gen("!zzpf)");
864     } else {
865       require (0,
866             "MR_distinctORcontextOpt: can't get here when using MR_predSimplify");
867 #if 0
868 **      for (q=p->down; q != NULL; q=q->right) {
869 **        gen("(  ");
870 **        genCombinedPredTreeContext(q);
871 **        _gen(" && ");
872 **        genPred(q,j);
873 **        if (q->right != NULL) {
874 **          _gen("  ) ||\n");
875 **        };
876 **      };
877 **      gen(")");
878 #endif
879    };
880 }
881 
882 void
883 #ifdef __USE_PROTOS
genPredTreeOrig(Predicate * p,Node * j,int in_and_expr)884 genPredTreeOrig( Predicate *p, Node *j, int in_and_expr )
885 #else
886 genPredTreeOrig( p, j, in_and_expr )
887 Predicate *p;
888 Node *j;
889 int in_and_expr;
890 #endif
891 {
892 
893 /* MR10 */  int     allHaveContext=1;
894 /* MR10 */  int     noneHaveContext=1;
895 
896 /* MR10 */  MR_predContextPresent(p,&allHaveContext,&noneHaveContext);
897 
898 	if ( ! noneHaveContext )                  /* MR10 context guards ignored when -prc off */
899 	{
900 		_gen("(");
901 		genPredTreeGate(p, in_and_expr);
902 	}
903 
904 	/* if leaf node, just gen predicate */
905 
906 	if ( p->down==NULL )
907 	{
908 		genPred(p,j,0);
909 		if ( ! noneHaveContext ) _gen(")");   /* MR10 context guards ignored when -prc off */
910 		return;
911 	}
912 
913 	/* if AND list, do both preds (only two possible) */
914 	if ( p->expr == PRED_AND_LIST )
915 	{
916 #if 0
917 **		_gen("(");
918 **		genPredTreeOrig(p->down, j, 1);
919 **		_gen("&&");
920 **		genPredTreeOrig(p->down->right, j, 1);
921 **		_gen(")");
922 **		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
923 **		return;
924 #endif
925         /* MR11 - make it work with AND with more than two children - like OR */
926 
927 		Predicate *list;
928 		_gen("(");
929 		list = p->down;
930 		for (; list!=NULL; list=list->right)
931 		{
932 			genPredTreeOrig(list, j, 1);
933 			if ( list->right!=NULL ) _gen("&&");
934 		}
935 		_gen(")");
936 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
937 		return;
938     };
939 
940 	if ( p->expr == PRED_OR_LIST )
941 	{
942 		Predicate *list;
943 		_gen("(");
944 		list = p->down;
945 		for (; list!=NULL; list=list->right)
946 		{
947 			genPredTreeOrig(list, j, 0);
948 			if ( list->right!=NULL ) _gen("||");
949 		}
950 		_gen(")");
951 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
952 		return;
953 	}
954 
955 	fatal_internal("genPredTreeOrig: predicate tree is wacked");
956 }
957 
958 #if 0
959 **   Predicate member dummyPredDepth is no longer used in MR10
960 **     but we might need it again in the future
961 **
962 **   if (MRhoisting) {
963 **     if ( !noneHaveContext &&
964 **          ! in_and_expr &&
965 **          p->source != NULL &&
966 **          p->source->dummyPredicateDepth > 0 &&
967 **          p->down == NULL) {
968 ** 		_gen("(");
969 ** 		genCombinedPredTreeContext(p);
970 ** 		_gen("  )\n");
971 ** 		return;
972 **     };
973 **   };
974 #endif
975 
976 /* [genPredTree] */
977 
978 /* in_and_expr
979 
980    what to do if the context is wrong
981    what to do if the context is correct but the predicate is false
982 
983    remember: if the context is wrong it's the same as if the
984              predicate is true as far as enabling an alternative
985 
986         Consider (AND p q r)
987 
988         if in an ... && ... expression then you don't want
989         the entire predicate chain to fail just because the
990         context for one component is wrong: so return true
991 
992         Consider (OR p q r)
993 
994         if in an ... || ... expression then you don't want
995         the entire predicate chain to succeed just because
996         the context for one component is correct when the
997         corresponding test is false: so return false when
998         the context is correct but the test is false.
999 */
1000 
1001 void
1002 #ifdef __USE_PROTOS
genPredTree(Predicate * p,Node * j,int in_and_expr,int suppress_sva)1003 genPredTree( Predicate *p, Node *j, int in_and_expr, int suppress_sva )
1004 #else
1005 genPredTree( p, j, in_and_expr, suppress_sva)
1006   Predicate     *p;
1007   Node          *j;
1008   int           in_and_expr;
1009   int           suppress_sva;
1010 #endif
1011 {
1012 
1013     int         allHaveContext=1;
1014     int         noneHaveContext=1;
1015     Tree        *groupTree;
1016     Tree        *oneTree;
1017     Predicate   *q;
1018     int         identicalORcontextOptimization=0;
1019     int         identicalANDcontextOptimization=0;
1020 
1021     if (0 && !MR_usingPredNames && !MRhoisting) {
1022       genPredTreeOrig(p,j,in_and_expr);
1023       return;
1024     };
1025 
1026     MR_predContextPresent(p,&allHaveContext,&noneHaveContext);
1027 
1028 	if ( ! noneHaveContext ) {                 /* MR10 context guards ignored when -prc off */
1029 
1030       _gen("(");
1031 
1032             /* MR10 optimize OR predicates which are all leaves */
1033 
1034       if (p->expr == PRED_OR_LIST && MR_allPredLeaves(p->down)) {
1035         groupTree=MR_compute_pred_tree_context(p);
1036         for (q=p->down ; q != NULL ; q=q->right) {
1037           oneTree=MR_compute_pred_tree_context(q);
1038           if (! MR_tree_equ(groupTree,oneTree)) {
1039             Tfree(oneTree);
1040             break;
1041           };
1042           Tfree(oneTree);
1043         };
1044         Tfree(groupTree);
1045         if (q == NULL) {
1046           _gen("/* MR10 individual OR gates suppressed when all predicates are leaves");
1047           _gen(" with identical context */\n");
1048           genPredTreeGate(p,in_and_expr);   /* use the parent's in_and_expr for this gate */
1049           identicalORcontextOptimization=1;
1050         } else {
1051           MR_distinctORcontextOpt(p,j,in_and_expr);
1052           return;
1053         };
1054       } else if (p->expr == PRED_AND_LIST && MR_allPredLeaves(p->down)) {
1055 
1056             /* MR12 optimize AND predicates which are all leaves */
1057 
1058         groupTree=MR_compute_pred_tree_context(p);
1059         for (q=p->down ; q != NULL ; q=q->right) {
1060           oneTree=MR_compute_pred_tree_context(q);
1061           if (! MR_tree_equ(groupTree,oneTree)) {
1062             Tfree(oneTree);
1063             break;
1064           };
1065           Tfree(oneTree);
1066         };
1067         Tfree(groupTree);
1068         if (q == NULL) {
1069           _gen("/* MR12 individual AND gates suppressed when all predicates are leaves");
1070           _gen(" with identical context */\n");
1071           genPredTreeGate(p,in_and_expr);   /* use the parent's in_and_expr for this gate */
1072           identicalANDcontextOptimization=1;
1073         } else {
1074           genPredTreeGate(p, in_and_expr);
1075         };
1076       } else {
1077   	    genPredTreeGate(p, in_and_expr);
1078       };
1079 	}
1080 
1081 	/* if leaf node, just gen predicate */
1082 
1083 	if ( p->down==NULL )
1084 	{
1085 		genPred(p,j,suppress_sva);
1086 		if ( ! noneHaveContext ) _gen(")");   /* MR10 context guards ignored when -prc off */
1087 		return;
1088 	}
1089 
1090 	/* if AND list, do both preds (only two possible) */
1091     /* MR10    not any more ! */
1092 
1093 	if ( p->expr == PRED_AND_LIST )
1094 	{
1095 		Predicate *list;
1096 		_gen("(");
1097 		list = p->down;
1098         for (; list != NULL; list=list->right) {
1099           if (identicalANDcontextOptimization) {
1100             genPred(list, j,suppress_sva);
1101           } else {
1102 	   	    genPredTree(list, j, 1, suppress_sva);  /* in and context */
1103           };
1104           if ( list->right!=NULL ) _gen("&&");
1105         };
1106 		_gen(")");
1107 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
1108 		return;
1109 	}
1110 
1111 	if ( p->expr == PRED_OR_LIST )
1112 	{
1113 		Predicate *list;
1114 		_gen("(");
1115 		list = p->down;
1116 		for (; list!=NULL; list=list->right)
1117 		{
1118             if (identicalORcontextOptimization) {
1119 	          genPred(list, j,suppress_sva);
1120             } else {
1121 	   	      genPredTree(list, j, 0, suppress_sva);
1122             };
1123 			if ( list->right!=NULL ) _gen("||");
1124 		}
1125 		_gen(")");
1126 		if ( ! noneHaveContext ) _gen(")");    /* MR10 context guards ignored when -prc off */
1127 		return;
1128 	}
1129 
1130 	fatal_internal("predicate tree is wacked");
1131 }
1132 
1133 /* [genPredTreeMainXX] */
1134 
1135 Predicate *     /* MR10 */
1136 #ifdef __USE_PROTOS
genPredTreeMainXX(Predicate * p,Node * j,int in_and_expr)1137 genPredTreeMainXX( Predicate *p, Node *j ,int in_and_expr)
1138 #else
1139 genPredTreeMainXX( p, j ,in_and_expr)
1140     Predicate   *p;
1141     Node        *j;
1142     int         in_and_expr;
1143 #endif
1144 {
1145 
1146     int     allHaveContext=1;
1147     int     noneHaveContext=1;
1148 
1149 #if 0
1150     fprintf(stderr,"Pred before\n");
1151     dumppred(p);
1152     fprintf(stderr,"\n");
1153     fprintf(stderr,"Pred after\n");
1154     dumppred(p);
1155     fprintf(stderr,"\n");
1156 #endif
1157 
1158     p=MR_predSimplifyALL(p);    /* MR10 */
1159 
1160     require (MR_predicate_context_completed(p),"predicate context is not complete");
1161 
1162     MR_cleanup_pred_trees(p);   /* MR10 */
1163 
1164     MR_predContextPresent(p,&allHaveContext,&noneHaveContext);
1165     if (!noneHaveContext & !allHaveContext) {
1166       warnFL("predicate contains elements both with and without context",
1167                 FileStr[j->file],j->line);
1168     };
1169 
1170     if (InfoP) {
1171        _gen("\n#if 0\n\n");
1172        MR_dumpPred(p,1);
1173        _gen("#endif\n");
1174     };
1175 	genPredTree(p,j,in_and_expr,0);
1176     return p;
1177 }
1178 
1179 Predicate *     /* MR10 */
1180 #ifdef __USE_PROTOS
genPredTreeMain(Predicate * p,Node * j)1181 genPredTreeMain( Predicate *p, Node *j)
1182 #else
1183 genPredTreeMain( p, j)
1184     Predicate   *p;
1185     Node        *j;
1186 #endif
1187 {
1188   return genPredTreeMainXX(p,j,1);
1189 }
1190 
1191 static void
1192 #ifdef __USE_PROTOS
genExprTreeOriginal(Tree * t,int k)1193 genExprTreeOriginal( Tree *t, int k )
1194 #else
1195 genExprTreeOriginal( t, k )
1196 Tree *t;
1197 int k;
1198 #endif
1199 {
1200 	require(t!=NULL, "genExprTreeOriginal: NULL tree");
1201 
1202 	if ( t->token == ALT )
1203 	{
1204 		_gen("("); genExprTreeOriginal(t->down, k); _gen(")");
1205 		if ( t->right!=NULL )
1206 		{
1207 			_gen("||");
1208 			on1line++;
1209 			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
1210 			_gen("("); genExprTreeOriginal(t->right, k); _gen(")");
1211 		}
1212 		return;
1213 	}
1214 	if ( t->down!=NULL ) _gen("(");
1215 	_gen1("LA(%d)==",k);
1216 	if ( TokenString(t->token) == NULL ) _gen1("%d", t->token)
1217 	else _gen1("%s", TokenString(t->token));
1218 	if ( t->down!=NULL )
1219 	{
1220 		_gen("&&");
1221 		on1line++;
1222 		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
1223 		_gen("("); genExprTreeOriginal(t->down, k+1); _gen(")");
1224 	}
1225 	if ( t->down!=NULL ) _gen(")");
1226 	if ( t->right!=NULL )
1227 	{
1228 		_gen("||");
1229 		on1line++;
1230 		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
1231 		_gen("("); genExprTreeOriginal(t->right, k); _gen(")");
1232 	}
1233 }
1234 
1235 #ifdef __USE_PROTOS
MR_LAtokenString(int k,int token)1236 static void MR_LAtokenString(int k,int token)
1237 #else
1238 static void MR_LAtokenString(k,token)
1239   int   k;
1240   int   token;
1241 #endif
1242 {
1243     char    *ts;
1244 
1245     ts=TokenString(token);
1246     if (ts == NULL) {
1247       _gen2(" LA(%d)==%d",k,token);
1248     } else {
1249       _gen2(" LA(%d)==%s",k,ts);
1250     };
1251 }
1252 
1253 
1254 #ifdef __USE_PROTOS
MR_countLeaves(Tree * t)1255 static int MR_countLeaves(Tree *t)
1256 #else
1257 static int MR_countLeaves(t)
1258   Tree  *t;
1259 #endif
1260 {
1261   if (t == NULL) return 0;
1262   if (t->token == ALT) {
1263     return MR_countLeaves(t->down)+MR_countLeaves(t->right);
1264   } else {
1265     return 1+MR_countLeaves(t->down)+MR_countLeaves(t->right);
1266   };
1267 }
1268 
1269 #ifdef __USE_PROTOS
MR_genOneLine(Tree * tree,int k)1270 static void MR_genOneLine(Tree *tree,int k)
1271 #else
1272 static void MR_genOneLine(tree,k)
1273   Tree      *tree;
1274   int       k;
1275 #endif
1276 {
1277     if (tree == NULL) return;
1278     if (tree->token == ALT) {
1279        MR_genOneLine(tree->down,k);
1280     } else {
1281        MR_LAtokenString(k,tree->token);
1282        if (tree->down != NULL &&
1283            tree->down->right == NULL) {
1284           _gen(" &&");
1285           MR_genOneLine(tree->down,k+1);
1286        } else if (tree->down != NULL) {
1287          _gen(" && (");
1288          MR_genOneLine(tree->down,k+1);
1289          _gen(")");
1290        };
1291     };
1292     if (tree->right != NULL) {
1293       _gen(" ||");
1294       MR_genOneLine(tree->right,k);
1295     };
1296 }
1297 
1298 static int across;
1299 static int depth;
1300 static int lastkonline;
1301 
1302 #ifdef __USE_PROTOS
MR_genMultiLine(Tree * tree,int k)1303 static void MR_genMultiLine(Tree *tree,int k)
1304 #else
1305 static void MR_genMultiLine(tree,k)
1306   Tree  *tree;
1307   int   k;
1308 #endif
1309 {
1310     int     i;
1311 
1312     if (tree == NULL) return;
1313     if (tree->token == ALT) {
1314       MR_genMultiLine(tree,k);
1315     } else {
1316       MR_LAtokenString(k,tree->token);
1317       lastkonline=k;
1318       across++;
1319       if (tree->down != NULL && tree->down->right == NULL) {
1320         if (across > 3) {
1321           _gen("\n");
1322           across=0;
1323           lastkonline=0;
1324           for (i=0 ; i < depth+k ; i++) _gen("   ");
1325           _gen("&&");
1326         } else {
1327           _gen(" &&");
1328         };
1329         MR_genMultiLine(tree->down,k+1);
1330       } else if (tree->down != NULL) {
1331         _gen("\n");
1332         lastkonline=0;
1333         across=0;
1334         for (i=0 ; i < depth+k ; i++) _gen("   ");
1335         _gen("&& (");
1336         MR_genMultiLine(tree->down,k+1);
1337         _gen(")");
1338       };
1339     };
1340     if (tree->right != NULL) {
1341       if (k < lastkonline) {
1342         _gen("\n");
1343         across=0;
1344         lastkonline=0;
1345         for (i=0; i < depth+k-1 ; i++) _gen("   ");
1346         _gen("||");
1347       } else if (across > 3 ) {
1348         _gen("\n");
1349         across=0;
1350         lastkonline=0;
1351         for (i=0; i < depth+k ; i++) _gen("   ");
1352         _gen("||");
1353       } else {
1354         _gen(" ||");
1355       };
1356       MR_genMultiLine(tree->right,k);
1357     };
1358 }
1359 
1360 #ifdef __USE_PROTOS
genExprTree(Tree * tree,int k)1361 static void genExprTree(Tree *tree,int k)
1362 #else
1363 static void genExprTree(tree,k)
1364   Tree  *tree;
1365   int   k;
1366 #endif
1367 {
1368     int     count;
1369 
1370 #if 0
1371     /* MR20 THM This was probably an error.
1372             The routine should probably reference that static
1373             "across" and this declaration hides it.
1374     */
1375 
1376     int     across;
1377 #endif
1378 
1379     require (tree != NULL,"genExprTree: tree is NULL");
1380     require (k > 0,"genExprTree: k <= 0");
1381 
1382     if (0 && !MRhoisting) {   /* MR11 make new version standard */
1383       genExprTreeOriginal(tree,k);
1384     } else {
1385       count=MR_countLeaves(tree);
1386       if (count < 5) {
1387         MR_genOneLine(tree,k);
1388       } else {
1389         _gen("\n");
1390         across=0;
1391         depth=0;
1392         lastkonline=0;
1393         MR_genMultiLine(tree,k);
1394         _gen("\n");
1395       };
1396     };
1397 }
1398 
1399 
1400 /*
1401  * Generate LL(k) type expressions of the form:
1402  *
1403  *		 (LA(1) == T1 || LA(1) == T2 || ... || LA(1) == Tn) &&
1404  *		 (LA(2) == T1 || LA(2) == T2 || ... || LA(2) == Tn) &&
1405  *			.....
1406  *		 (LA(k) == T1 || LA(k) == T2 || ... || LA(k) == Tn)
1407  *
1408  * If GenExprSetsOpt generate:
1409  *
1410  *		(setwdi[LA(1)]&(1<<j)) && (setwdi[LA(2)]&(1<<j)) ...
1411  *
1412  * where n is set_deg(expr) and Ti is some random token and k is the last nonempty
1413  * set in fset <=CLL_k.
1414  * k=1..CLL_k where CLL_k >= 1.
1415  *
1416  * This routine is visible only to this file and cannot answer a TRANS message.
1417  *
1418  */
1419 
1420 /*  [genExpr] */
1421 
1422 static int
1423 #ifdef __USE_PROTOS
genExpr(Junction * j)1424 genExpr( Junction *j )
1425 #else
1426 genExpr( j )
1427 Junction *j;
1428 #endif
1429 {
1430 	int max_k;
1431 
1432 	/* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead
1433 	 * from CLL_k..LL_k
1434 	 */
1435 	{
1436 		int limit;
1437 		if ( j->ftree!=NULL ) limit = LL_k;
1438 		else limit = CLL_k;
1439 		max_k = genExprSets(j->fset, limit);
1440 	}
1441 
1442 	/* Do tests for real tuples from other productions that conflict with
1443 	 * artificial tuples generated by compression (using sets of tokens
1444 	 * rather than k-trees).
1445 	 */
1446 	if ( j->ftree != NULL )
1447 	{
1448 		_gen(" && !("); genExprTree(j->ftree, 1); _gen(")");
1449 	}
1450 
1451 	if ( ParseWithPredicates && j->predicate!=NULL )
1452 	{
1453 		Predicate *p = j->predicate;
1454 		warn_about_using_gk_option();
1455 		_gen("&&");
1456 		j->predicate=genPredTreeMain(p, (Node *)j);     /* MR10 */
1457 	}
1458 
1459 	return max_k;
1460 }
1461 
1462 static int
1463 #ifdef __USE_PROTOS
genExprSets(set * fset,int limit)1464 genExprSets( set *fset, int limit )
1465 #else
1466 genExprSets( fset, limit )
1467 set *fset;
1468 int limit;
1469 #endif
1470 {
1471 	int k = 1;
1472 	int max_k = 0;
1473 	unsigned *e, *g, firstTime=1;
1474 
1475     if (set_nil(fset[1])) {
1476       _gen(" 0 /* MR13 empty set expression  - undefined rule ? infinite left recursion ? */ ");
1477       MR_BadExprSets++;
1478     };
1479 
1480 	if ( GenExprSetsOpt )
1481 	{
1482 		while ( k <= limit && !set_nil(fset[k]) )   /* MR11 */
1483 		{
1484 			if ( set_deg(fset[k])==1 )	/* too simple for a set? */
1485 			{
1486 				int e;
1487 				_gen1("(LA(%d)==",k);
1488 				e = set_int(fset[k]);
1489 				if ( TokenString(e) == NULL ) _gen1("%d)", e)
1490 				else _gen1("%s)", TokenString(e));
1491 			}
1492 			else
1493 			{
1494 				NewSet();
1495 				FillSet( fset[k] );
1496 				_gen3("(setwd%d[LA(%d)]&0x%x)", wordnum, k, 1<<setnum);
1497 			}
1498 			if ( k>max_k ) max_k = k;
1499 			if ( k == CLL_k ) break;
1500 			k++;
1501 			if ( k<=limit && !set_nil(fset[k]) ) _gen(" && ");  /* MR11 */
1502 			on1line++;
1503 			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
1504 		}
1505 		return max_k;
1506 	}
1507 
1508 	while ( k<= limit &&  !set_nil(fset[k]) )       /* MR11 */
1509 	{
1510 		if ( (e=g=set_pdq(fset[k])) == NULL ) fatal_internal("genExpr: cannot allocate IF expr pdq set");
1511 		for (; *e!=nil; e++)
1512 		{
1513 			if ( !firstTime ) _gen(" || ") else { _gen("("); firstTime = 0; }
1514 			on1line++;
1515 			if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
1516 			_gen1("LA(%d)==",k);
1517 			if ( TokenString(*e) == NULL ) _gen1("%d", *e)
1518 			else _gen1("%s", TokenString(*e));
1519 		}
1520 		free( (char *)g );
1521 		_gen(")");
1522 		if ( k>max_k ) max_k = k;
1523 		if ( k == CLL_k ) break;
1524 		k++;
1525 		if ( k <= limit && !set_nil(fset[k]) ) { firstTime=1; _gen(" && "); }   /* MR11 */
1526 		on1line++;
1527 		if ( on1line > NumExprPerLine ) { on1line=0; _gen("\n"); }
1528 	}
1529 	return max_k;
1530 }
1531 
1532 /*
1533  * Generate code for any type of block.  If the last alternative in the block is
1534  * empty (not even an action) don't bother doing it.  This permits us to handle
1535  * optional and loop blocks as well.
1536  *
1537  * Only do this block, return after completing the block.
1538  * This routine is visible only to this file and cannot answer a TRANS message.
1539  */
1540 static set
1541 #ifdef __USE_PROTOS
genBlk(Junction * q,int jtype,int * max_k,int * need_right_curly,int * lastAltEmpty)1542 genBlk( Junction *q, int jtype, int *max_k, int *need_right_curly, int * lastAltEmpty /* MR23 */)
1543 #else
1544 genBlk( q, jtype, max_k, need_right_curly, lastAltEmpty /* MR23 */)
1545 Junction *q;
1546 int jtype;
1547 int *max_k;
1548 int *need_right_curly;
1549 int *lastAltEmpty; /* MR23 */
1550 #endif
1551 {
1552 	set f;
1553 	Junction *alt;
1554 	int a_guess_in_block = 0;
1555 	require(q!=NULL,				"genBlk: invalid node");
1556 	require(q->ntype == nJunction,	"genBlk: not junction");
1557 	*need_right_curly=0;
1558 	*lastAltEmpty = 0;		/* MR23 */
1559 	if ( q->p2 == NULL )	/* only one alternative?  Then don't need if */
1560 	{
1561 		if (first_item_is_guess_block((Junction *)q->p1)!=NULL )
1562 		{
1563             if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) {
1564   			  warnFL("(...)? as only alternative of block is unnecessary", FileStr[q->file], q->line);
1565             };
1566    	   	    gen("zzGUESS\n");	/* guess anyway to make output code consistent */
1567 /* MR10 disable */  /**** gen("if ( !zzrv )\n"); ****/
1568 /* MR10 */          gen("if ( !zzrv ) {\n"); tabs++; (*need_right_curly)++;
1569         };
1570 		TRANS(q->p1);
1571 		return empty;		/* no decision to be made-->no error set */
1572 	}
1573 
1574 	f = First(q, 1, jtype, max_k);
1575 	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
1576 	{
1577 		if ( alt->p2 == NULL )					/* chk for empty alt */
1578 		{
1579 			Node *p = alt->p1;
1580 			if ( p->ntype == nJunction )
1581 			{
1582 				/* we have empty alt */
1583 /* MR23
1584    There is a conflict between giving good error information for non-exceptions
1585    and making life easy for those using parser exception handling.  Consider:
1586 
1587          r: { A } b;
1588 		 b: B;
1589 
1590 		   with input "C"
1591 
1592    Before MR21 the error message would be "expecting B - found C".  After MR21
1593    the error message would be "expcect A, B - found C".  This was good, but it
1594    caused problems for those using parser exceptions because the reference to
1595    B was generated inside the {...} where B really wasn't part of the block.
1596 
1597    In MR23 this has been changed for the case where exceptions are in use to
1598    not generate the extra check in the tail of the {A} block.
1599 */
1600 
1601 
1602 /* MR23 */	if (isEmptyAlt( ((Junction *)p)->p1, (Node *)q->end)) {
1603 /* MR23 */      *lastAltEmpty = 1;
1604 /* MR23 */		if (FoundException) {
1605 /* MR23 */			/* code to restore state if a prev alt didn't follow guess */
1606 /* MR23 */			if ( a_guess_in_block && jtype != aPlusBlk) {
1607 /* MR23 */				gen("if ( !zzrv ) zzGUESS_DONE; /* MR28 */\n");
1608 /* MR23 */			}
1609 /* MR23 */			break;
1610 /* MR23 */		};
1611 /* MR28 */      if (jtype == aPlusBlk) {
1612 /* MR28 */          break;
1613 /* MR28 */      }
1614 /* MR23 */	}
1615 		}
1616 	} /* end of for loop on alt */
1617 
1618 /* MR10 */        if (alt->p2 == NULL &&
1619 /* MR10 */               ( q->jtype == aSubBlk || q->jtype == RuleBlk) ) {
1620 /* MR10 */          if (first_item_is_guess_block(alt)) {
1621 /* MR10 */               warnFL("(...)? as last alternative of block is unnecessary",
1622 /* MR10 */                                FileStr[alt->file],alt->line);
1623 /* MR10 */          };
1624 /* MR10 */        };
1625 
1626 		if ( alt != q ) gen("else ")
1627 		else
1628 		{
1629 			if ( DemandLookahead ) {
1630 				if ( !GenCC ) {gen1("LOOK(%d);\n", *max_k);}
1631 				else gen1("look(%d);\n", *max_k);
1632 			}
1633 		}
1634 
1635 		if ( alt!=q )
1636 		{
1637 			_gen("{\n");
1638 			tabs++;
1639 			(*need_right_curly)++;
1640 			/* code to restore state if a prev alt didn't follow guess */
1641 			if ( a_guess_in_block )
1642 				gen("if ( !zzrv ) zzGUESS_DONE;\n");
1643 		}
1644 		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL )
1645 		{
1646 			a_guess_in_block = 1;
1647 			gen("zzGUESS\n");
1648 		}
1649 		gen("if ( ");
1650 		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) _gen("!zzrv && ");
1651 		genExpr(alt);
1652 		_gen(" ) ");
1653 		_gen("{\n");
1654 		tabs++;
1655 		TRANS(alt->p1);
1656 		--tabs;
1657 		gen("}\n");
1658 /* MR10 */        if (alt->p2 == NULL) {
1659 /* MR10 */          if (first_item_is_guess_block(alt)) {
1660 /* MR10 */            gen("/* MR10 */ else {\n");
1661 /* MR10 */            tabs++;
1662 /* MR10 */  		  (*need_right_curly)++;
1663 /* MR10 */  		  /* code to restore state if a prev alt didn't follow guess */
1664 /* MR10 */            gen("/* MR10 */ if ( !zzrv ) zzGUESS_DONE;\n");
1665 /* MR10 */            gen("/* MR10 */ if (0) {}     /* last alternative of block is guess block */\n");
1666 /* MR10 */          };
1667 /* MR10 */        };
1668 	}
1669 	return f;
1670 }
1671 
1672 static int
1673 #ifdef __USE_PROTOS
has_guess_block_as_first_item(Junction * q)1674 has_guess_block_as_first_item( Junction *q )
1675 #else
1676 has_guess_block_as_first_item( q )
1677 Junction *q;
1678 #endif
1679 {
1680 	Junction *alt;
1681 
1682 	for (alt=q; alt != NULL; alt= (Junction *) alt->p2 )
1683 	{
1684 		if ( first_item_is_guess_block((Junction *)alt->p1)!=NULL ) return 1;
1685 	}
1686 	return 0;
1687 }
1688 
1689 static int
1690 #ifdef __USE_PROTOS
has_guess_block_as_last_item(Junction * q)1691 has_guess_block_as_last_item( Junction *q )
1692 #else
1693 has_guess_block_as_last_item( q )
1694 Junction *q;
1695 #endif
1696 {
1697 	Junction *alt;
1698 
1699     if (q == NULL) return 0;
1700 	for (alt=q; alt->p2 != NULL && !( (Junction *) alt->p2)->ignore; alt= (Junction *) alt->p2 ) {};
1701     return first_item_is_guess_block( (Junction *) alt->p1) != NULL;
1702 }
1703 
1704 /* MR30 See description of first_item_is_guess_block for background */
1705 
1706 Junction *
1707 #ifdef __USE_PROTOS
first_item_is_guess_block_extra(Junction * q)1708 first_item_is_guess_block_extra(Junction *q )
1709 #else
1710 first_item_is_guess_block_extra(q)
1711 Junction *q;
1712 #endif
1713 {
1714 	while ( q!=NULL &&
1715             (  ( q->ntype==nAction ) ||
1716                ( q->ntype==nJunction &&
1717                     (q->jtype==Generic || q->jtype == aLoopBlk)
1718                )
1719             )
1720           )
1721 	{
1722 		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
1723 		else q = (Junction *) ((ActionNode *)q)->next;
1724 	}
1725 
1726 	if ( q==NULL ) return NULL;
1727 	if ( q->ntype!=nJunction ) return NULL;
1728 	if ( q->jtype!=aSubBlk ) return NULL;
1729 	if ( !q->guess ) return NULL;
1730 
1731 	return q;
1732 }
1733 
1734 /* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node
1735  * of (...)?;  This function ignores actions and predicates.
1736  */
1737 
1738 Junction *
1739 #ifdef __USE_PROTOS
first_item_is_guess_block(Junction * q)1740 first_item_is_guess_block( Junction *q )
1741 #else
1742 first_item_is_guess_block( q )
1743 Junction *q;
1744 #endif
1745 {
1746 	Junction * qOriginal = q;	/* DEBUG */
1747 
1748     /* MR14  Couldn't find aSubBlock which was a guess block when it lay
1749              behind aLoopBlk.  The aLoopBlk only appear in conjunction with
1750              aLoopBegin, but the routine didn't know that.  I think.
1751 
1752        MR14a Added extra parentheses to clarify precedence
1753 
1754 	   MR30  This appears to have been a mistake.  The First set was then
1755 	         computed incorrectly for:
1756 
1757 					r : ( (A)? B
1758 					    | C
1759 						)*
1760 
1761 			 The routine analysis_point was seeing the guess block when
1762 			 it was still analyzing the loopBegin block.  As a consequence,
1763 			 when it looked for the analysis_point it was processing the B, but
1764 			 skipping over the C alternative altogether because it thought
1765 			 it was looking at a guess block, not realizing there was a loop
1766 			 block in front of the loopBegin.
1767 
1768              loopBegin  loopBlk  subBlk/guess  A  G  EB  G  B EB EB  EB  ER
1769 			    |          |          |                     ^   ^
1770 				|		   |                                |   |
1771                 |          +-> G  C G ----------------------+   |
1772                 |                                               |
1773 				+--- G G G -------------------------------------+
1774 
1775 			 Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu).
1776 
1777 		MR30  This is still more complicated.  This fix caused ambiguity messages
1778 		to be reported for "( (A B)? )* A B" but not for "( (A B)? )+".  Why is
1779 		there a difference when these are outwardly identical ?  It is because the
1780 		start of a (...)* block is represented by two nodes: a loopBegin block
1781 		followed by a loopBlock whereas the start of a (...)+ block is
1782 		represented as a single node: a plusBlock.  So if first_item_is_guess_block
1783 		is called when the current node is a loopBegin it starts with the
1784 		loop block rather than the the sub block which follows the loop block.
1785 		However, we can't just skip past the loop block because some routines
1786 		depend on the old implementation.  So, we provide a new implementation
1787 		which does skip the loopBlock.  However, which should be called when ?
1788 		I'm not sure, but my guess is that first_item_is_guess_block_extra (the
1789 		new one) should only be called for the ambiguity routines.
1790 
1791     */
1792 
1793 	while ( q!=NULL &&
1794             (  ( q->ntype==nAction ) ||
1795                ( q->ntype==nJunction &&
1796                     (q->jtype==Generic /*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/
1797                )
1798             )
1799           )
1800 	{
1801 		if ( q->ntype==nJunction ) q = (Junction *)q->p1;
1802 		else q = (Junction *) ((ActionNode *)q)->next;
1803 	}
1804 
1805 	if ( q==NULL ) return NULL;
1806 	if ( q->ntype!=nJunction ) return NULL;
1807 	if ( q->jtype!=aSubBlk ) return NULL;
1808 	if ( !q->guess ) return NULL;
1809 
1810 	return q;
1811 }
1812 
1813 /* MR1				                 					    */
1814 /* MR1  10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs  */
1815 /* MR1				                                                        */
1816 
1817 #define STRINGIZEBUFSIZE 1024
1818 
1819 static char stringizeBuf[STRINGIZEBUFSIZE];
1820 char *
1821 #ifdef __USE_PROTOS
stringize(char * s)1822 stringize(char * s)
1823 #else
1824 stringize(s)
1825 char *s;
1826 #endif
1827 
1828 {
1829   char		*p;
1830   char		*stop;
1831 
1832   p=stringizeBuf;
1833   stop=&stringizeBuf[1015];
1834 
1835   if (s != 0) {
1836     while (*s != 0) {
1837       if (p >= stop) {
1838 	goto stringizeStop;
1839       } else if (*s == '\n') {
1840         *p++='\\';
1841         *p++='n';
1842         *p++='\\';
1843 	*p++=*s++;
1844       } else if (*s == '\\') {
1845 	*p++=*s;
1846 	*p++=*s++;
1847       } else if (*s == '\"') {
1848         *p++='\\';
1849 	*p++=*s++;
1850         while (*s != 0) {
1851           if (p >= stop) {
1852 	     goto stringizeStop;
1853 	  } else if (*s == '\n') {
1854 	    *p++='\\';
1855 	    *p++=*s++;
1856 	  } else if (*s == '\\') {
1857 	    *p++=*s++;
1858 	    *p++=*s++;
1859 	  } else if (*s == '\"') {
1860 	    *p++='\\';
1861 	    *p++=*s++;
1862 	    break;
1863 	  } else {
1864 	    *p++=*s++;
1865           };
1866         };
1867       } else if (*s == '\'') {
1868 	*p++=*s++;
1869         while (*s != 0) {
1870           if (p >= stop) {
1871 	     goto stringizeStop;
1872 	  } else if (*s == '\'') {
1873 	    *p++=*s++;
1874 	    break;
1875 	  } else if (*s == '\\') {
1876 	    *p++=*s++;
1877 	    *p++=*s++;
1878 	  } else if (*s == '\"') {
1879 	    *p++='\\';
1880 	    *p++=*s++;
1881 	    break;
1882 	  } else {
1883 	    *p++=*s++;
1884           };
1885         };
1886       } else {
1887         *p++=*s++;
1888       };
1889     };
1890   };
1891   goto stringizeExit;
1892 stringizeStop:
1893   *p++='.';
1894   *p++='.';
1895   *p++='.';
1896 stringizeExit:
1897   *p=0;
1898   return stringizeBuf;
1899 }
1900 
1901 #ifdef __USE_PROTOS
isNullAction(char * s)1902 int isNullAction(char *s)
1903 #else
1904 int isNullAction(s)
1905   char  *s;
1906 #endif
1907 {
1908   char  *p;
1909   for (p=s; *p != '\0' ; p++) {
1910     if (*p != ';' && *p !=' ') return 0;
1911   };
1912   return 1;
1913 }
1914 /* MR1									                                    */
1915 /* MR1	End of Routine to stringize code for failed predicates msgs         */
1916 /* MR1				                                                        */
1917 
1918 /* Generate an action.  Don't if action is NULL which means that it was already
1919  * handled as an init action.
1920  */
1921 void
1922 #ifdef __USE_PROTOS
genAction(ActionNode * p)1923 genAction( ActionNode *p )
1924 #else
1925 genAction( p )
1926 ActionNode *p;
1927 #endif
1928 {
1929 	require(p!=NULL,			"genAction: invalid node and/or rule");
1930 	require(p->ntype==nAction,	"genAction: not action");
1931 
1932 	if ( !p->done )  /* MR10 */ /* MR11 */
1933 	{
1934 		if ( p->is_predicate)
1935 		{
1936 			if ( p->guardpred != NULL )
1937 			{
1938                 Predicate *guardDup=predicate_dup(p->guardpred); /* MR10 */
1939                 gen("if (!");
1940        			guardDup=genPredTreeMain(guardDup, (Node *)p);
1941                 predicate_free(guardDup);
1942 			}
1943 /* MR10 */  else if (p->ampersandPred != NULL) {
1944 /* MR10 */      gen("if (!");
1945 /* MR10 */      p->ampersandPred=genPredTreeMain(p->ampersandPred, (Node *)p);
1946 /* MR10 */  }
1947 			else
1948 			{
1949 				gen("if (!(");
1950 				/* make sure that '#line n' is on front of line */
1951 				if ( GenLineInfo && p->file != -1 ) _gen("\n");
1952 				dumpPredAction(p,p->action, output, 0, p->file, p->line, 0);
1953 				_gen(")");
1954 			}
1955 
1956 /* MR23 Change failed predicate macro to have three arguments:
1957 
1958         macro arg 1: The stringized predicate itself
1959         macro arg 2: 0 => no user-defined error action
1960                      1 => user-defined error action
1961         macro arg 3: The user-defined error action
1962 
1963    This gives the user more control of the error action.
1964 */
1965 			tabs++;
1966 			gen3(") {zzfailed_pred(\"%s\",%s, { %s } );}\n",         /* MR23 */
1967 					stringize(p->action),	                         /* MR23 */
1968                     (p->pred_fail == NULL ?                          /* MR23/MR27 */
1969                        	"0 /* report */" : "1 /* user action */"),   /* MR23/MR27 */
1970                     (p->pred_fail == NULL ?                          /* MR23 */
1971                         "0; /* no user action */" : p->pred_fail));  /* MR23 */
1972 			tabs--;
1973 		}
1974 		else    /* not a predicate */
1975 		{
1976             if (! isNullAction(p->action) && !p->noHoist) {
1977   	  		  if ( FoundGuessBlk ) {
1978 				if ( GenCC ) {
1979                   gen("if ( !guessing ) {\n");
1980                 } else {
1981 				  gen("zzNON_GUESS_MODE {\n");
1982                 };
1983               };
1984 			  dumpActionPlus(p, p->action, output, tabs, p->file, p->line, 1); /* MR21 */
1985 			  if ( FoundGuessBlk ) gen("}\n");
1986             };
1987 		}
1988 	}
1989 	TRANS(p->next)
1990 }
1991 
1992 /*
1993  *		if invoking rule has !noAST pass zzSTR to rule ref and zzlink it in
1994  *		else pass addr of temp root ptr (&_ast) (don't zzlink it in).
1995  *
1996  *		if ! modifies rule-ref, then never link it in and never pass zzSTR.
1997  *		Always pass address of temp root ptr.
1998  */
1999 void
2000 #ifdef __USE_PROTOS
genRuleRef(RuleRefNode * p)2001 genRuleRef( RuleRefNode *p )
2002 #else
2003 genRuleRef( p )
2004 RuleRefNode *p;
2005 #endif
2006 {
2007 	Junction *q;
2008 	char *handler_id = "";
2009 	RuleEntry *r, *r2;
2010 	char *parm = "", *exsig = "";
2011 
2012     int     genRuleRef_emittedGuessGuard=0;     /* MR10 */
2013 
2014 	require(p!=NULL,			"genRuleRef: invalid node and/or rule");
2015 	require(p->ntype==nRuleRef, "genRuleRef: not rule reference");
2016 
2017 	if ( p->altstart!=NULL && p->altstart->exception_label!=NULL )
2018 		handler_id = p->altstart->exception_label;
2019 
2020 	r = (RuleEntry *) hash_get(Rname, p->text);
2021 	if ( r == NULL )
2022 	{
2023 		warnFL( eMsg1("rule %s not defined",
2024 					  p->text), FileStr[p->file], p->line );
2025 		return;
2026 	}
2027 
2028 /* MR8 5-Aug-97     Reported by S.Bochnak@microtool.com.pl                  */
2029 /*                  Don't do assign when no return values declared          */
2030 /*                  Move definition of q up and use it to guard p->assign   */
2031 
2032 	q = RulePtr[r->rulenum];	/* find definition of ref'd rule */  /* MR8 */
2033 
2034 	r2 = (RuleEntry *) hash_get(Rname, p->rname);
2035 	if ( r2 == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}
2036 
2037     OutLineInfo(output,p->line,FileStr[p->file]);
2038 
2039 	if ( GenCC && GenAST ) {
2040 		gen("_ast = NULL;\n");
2041 	}
2042 
2043 	if ( FoundGuessBlk && p->assign!=NULL && q->ret != NULL ) {      /* MR8 */
2044 		if ( GenCC ) {
2045           gen("if ( !guessing ) {\n");
2046         } else {
2047           gen("zzNON_GUESS_MODE {\n");
2048         };
2049         tabs++;                                                      /* MR11 */
2050         genRuleRef_emittedGuessGuard=1;                              /* MR11 */
2051     };
2052 
2053 	if ( FoundException ) exsig = "&_signal";
2054 
2055 	tab();
2056 	if ( GenAST )
2057 	{
2058 		if ( GenCC ) {
2059 /****			if ( r2->noAST || p->astnode==ASTexclude )
2060 ****/
2061 			{
2062 /****				_gen("_ast = NULL;\n");
2063 ****/
2064 				parm = "&_ast";
2065 			}
2066 /*** we always want to set just a pointer now, then set correct
2067 pointer after
2068 
2069 			else {
2070 				_gen("_astp =
2071 (_tail==NULL)?(&_sibling):(&(_tail->_right));\n");
2072 				parm = "_astp";
2073 			}
2074 ****/
2075 		}
2076 		else {
2077 			if ( r2->noAST || p->astnode==ASTexclude )
2078 			{
2079 				_gen("_ast = NULL; ");
2080 				parm = "&_ast";
2081 			}
2082 			else parm = "zzSTR";
2083 		}
2084 		if ( p->assign!=NULL && q->ret!=NULL )                       /* MR8 */
2085 		{
2086 			if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */
2087 			else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum);
2088 		}
2089 		if ( FoundException ) {
2090 			_gen5("%s%s(%s,&_signal%s%s); ",
2091 				  RulePrefix,
2092 				  p->text,
2093 				  parm,
2094 				  (p->parms!=NULL)?",":"",
2095 				  (p->parms!=NULL)?p->parms:"");
2096 			if ( p->ex_group!=NULL ) {
2097 				_gen("\n");
2098 				gen("if (_signal) {\n");
2099 				tabs++;
2100 				dumpException(p->ex_group, 0);
2101 				tabs--;
2102 				gen("}");
2103 			}
2104 			else {
2105 				_gen1("if (_signal) goto %s_handler;", handler_id);
2106 			}
2107 		}
2108 		else {
2109 			_gen5("%s%s(%s%s%s);",
2110 				  RulePrefix,
2111 				  p->text,
2112 				  parm,
2113 				  (p->parms!=NULL)?",":"",
2114 				  (p->parms!=NULL)?p->parms:"");
2115 		}
2116 		if ( GenCC && (r2->noAST || p->astnode==ASTexclude) )
2117 		{
2118 			/* rule has a ! or element does */
2119 			/* still need to assign to #i so we can play with it */
2120 			_gen("\n");
2121 			gen2("_ast%d%d = (AST *)_ast;", BlkLevel-1, p->elnum);
2122 		}
2123 		else if ( !r2->noAST && p->astnode == ASTinclude )
2124 		{
2125 			/* rule doesn't have a ! and neither does element */
2126 /* MR10 */  if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) {
2127 /* MR10 */    _gen("\n");
2128 /* MR10 */    if (GenCC) gen ("if (!guessing) {    /* MR10 */")
2129 /* MR10 */          else gen ("if (!zzguessing) {    /* MR10 */\n");
2130 /* MR10 */    tabs++;
2131 /* MR10 */  };
2132 			if ( GenCC ) {
2133 				_gen("\n");
2134 				gen("if ( _tail==NULL ) _sibling = _ast; else _tail->setRight(_ast);\n");
2135 				gen2("_ast%d%d = (AST *)_ast;\n", BlkLevel-1, p->elnum);
2136 				tab();
2137 			}
2138 			else _gen(" ");
2139             if ( GenCC ) {
2140                 _gen("ASTBase::"); }
2141                 else _gen("zz");
2142 			_gen("link(_root, &_sibling, &_tail);");
2143 
2144 /* MR10 */  if (FoundGuessBlk && !genRuleRef_emittedGuessGuard) {     /* MR10 */
2145 /* MR10 */    _gen("\n");
2146 /* MR10 */    tabs--;
2147 /* MR10 */    if (GenCC) gen ("};    /* MR10 */")
2148 /* MR10 */          else gen ("};    /* MR10 */");
2149 /* MR10 */  };
2150 		}
2151 	}
2152 	else
2153 	{
2154 		if ( p->assign!=NULL && q->ret!=NULL )                       /* MR8 */
2155 		{
2156 			if ( !hasMultipleOperands(p->assign) ) {_gen1("%s = ",p->assign);} /* MR23 */
2157 			else _gen1("{ struct _rv%d _trv; _trv = ", r->rulenum);
2158 		}
2159 		if ( FoundException ) {
2160 			_gen4("%s%s(&_signal%s%s); ",
2161 				  RulePrefix,
2162 				  p->text,
2163 				  (p->parms!=NULL)?",":"",
2164 				  (p->parms!=NULL)?p->parms:"");
2165 			if ( p->ex_group!=NULL ) {
2166 				_gen("\n");
2167 				gen("if (_signal) {\n");
2168 				tabs++;
2169 				dumpException(p->ex_group, 0);
2170 				tabs--;
2171 				gen("}");
2172 			}
2173 			else {
2174 				_gen1("if (_signal) goto %s_handler;", handler_id);
2175 			}
2176 		}
2177 		else {
2178 			_gen3("%s%s(%s);",
2179 				  RulePrefix,
2180 				  p->text,
2181 				  (p->parms!=NULL)?p->parms:"");
2182 		}
2183 		if ( p->assign!=NULL && q->ret!=NULL ) _gen("\n");           /* MR8 */
2184 	}
2185 
2186 	if ( p->assign!=NULL && q->ret!=NULL) {                          /* MR8 */
2187 		if ( hasMultipleOperands(p->assign) )                        /* MR23 */
2188 		{
2189 			_gen("\n");
2190 			dumpRetValAssign(p->assign, q->ret, p);                  /* MR30 */
2191 			_gen("}");
2192 		}
2193 	}
2194 	_gen("\n");
2195 
2196 	/* Handle element labels now */
2197 	if ( p->el_label!=NULL )
2198 	{
2199 		if ( GenAST )
2200 		{
2201 			if ( GenCC ) {
2202 				gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
2203 			}
2204 			else {gen1("%s_ast = zzastCur;\n", p->el_label);}
2205 		}
2206        	else if (!GenCC ) {
2207 			gen1("%s = zzaCur;\n", p->el_label);
2208         }
2209 	}
2210 
2211 	if ( FoundGuessBlk && p->assign!=NULL && q->ret!=NULL ) {       /* MR8 */
2212 		/* in guessing mode, don't branch to handler upon error */
2213         tabs--;                                                     /* MR11 */
2214 		gen("} else {\n");
2215         tabs++;                                                     /* MR11 */
2216 		if ( FoundException ) {
2217 			gen6("%s%s(%s%s&_signal%s%s);\n",
2218 				 RulePrefix,
2219 				 p->text,
2220 				 parm,
2221                  (*parm!='\0')?",":"",
2222                  (p->parms!=NULL)?",":"",
2223 				 (p->parms!=NULL)?p->parms:"");
2224 		}
2225 		else {
2226 			gen5("%s%s(%s%s%s);\n",
2227 				 RulePrefix,
2228 				 p->text,
2229 				 parm,
2230 				 (p->parms!=NULL && *parm!='\0')?",":"",
2231 				 (p->parms!=NULL)?p->parms:"");
2232 		}
2233         tabs--;                                                     /* MR11 */
2234 		gen("}\n");
2235 	}
2236 	TRANS(p->next)
2237 }
2238 
2239 /*
2240  * Generate code to match a token.
2241  *
2242  * Getting the next token is tricky.  We want to ensure that any action
2243  * following a token is executed before the next GetToken();
2244  */
2245 void
2246 #ifdef __USE_PROTOS
genToken(TokNode * p)2247 genToken( TokNode *p )
2248 #else
2249 genToken( p )
2250 TokNode *p;
2251 #endif
2252 {
2253 	RuleEntry *r;
2254 	char *handler_id = "";
2255 	ActionNode *a;
2256 	char *set_name;
2257 	char *set_nameErrSet;
2258 	int complement;
2259 	int ast_label_in_action = 0;	/* MR27 */
2260 	int pushedCmodeAST = 0;			/* MR27 */
2261 
2262 	require(p!=NULL,			"genToken: invalid node and/or rule");
2263 	require(p->ntype==nToken,	"genToken: not token");
2264 	if ( p->altstart!=NULL && p->altstart->exception_label!=NULL )
2265 		handler_id = p->altstart->exception_label;
2266 
2267 	r = (RuleEntry *) hash_get(Rname, p->rname);
2268 	if ( r == NULL ) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}
2269 
2270 /*
2271  * MR27 Has the element label been referenced as an AST (with the # operator) ?
2272  *      If so, then we'll want to build the AST even though the user has used
2273  *      the ! operator.
2274  */
2275 /* MR27 */	if (GenAST && p->el_label != NULL) {
2276 /* MR27 */		ast_label_in_action = list_search_cstring(r->ast_labels_in_actions,
2277 /* MR27 */		                                          p->el_label);
2278 /* MR27 */	}
2279 
2280     OutLineInfo(output,p->line,FileStr[p->file]);
2281 
2282 	if ( !set_nil(p->tset) )	/* implies '.', ~Tok, or tokenclass */
2283 	{
2284 		unsigned e;
2285 		unsigned eErrSet = 0;
2286 		set b;
2287 		set bErrSet;					/* MR23 */
2288 		b = set_dup(p->tset);
2289 		bErrSet = set_dup(p->tset);	    /* MR23 */
2290 		complement = p->complement; /* MR23 */
2291 		if ( p->tclass!=NULL  && complement == 0 /* MR23 */) { /* token class not complemented*/
2292 			static char buf[MaxRuleName+20];	    /* MR23 */
2293 			static char bufErrSet[MaxRuleName+20];	/* MR23 */
2294 			if ( p->tclass->dumped ) {
2295 				e = p->tclass->setnum;
2296 				eErrSet = p->tclass->setnumErrSet;
2297 			}
2298 			else {
2299 				e = DefErrSet(&b, 0, TokenString(p->token));
2300 				eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errset");
2301 				p->tclass->dumped = 1;	/* indicate set has been created */
2302 				p->tclass->setnum = e;
2303 				p->tclass->setnumErrSet = eErrSet;					/* MR23 */
2304 			}
2305 			sprintf(buf, "%s_set", TokenString(p->token));
2306 			sprintf(bufErrSet, "%s_errset", TokenString(p->token));	/* MR23 */
2307 			set_name = buf;
2308 			set_nameErrSet = bufErrSet;								/* MR23 */
2309 		}
2310 
2311 		/* MR23 - Forgot about the case of ~TOKCLASS. */
2312 
2313 		else if ( p->tclass!=NULL  && complement != 0 /* MR23 */)
2314 		{
2315 			static char buf[MaxRuleName+20];	    /* MR23 */
2316 			static char bufErrSet[MaxRuleName+20];	/* MR23 */
2317 			if ( p->tclass->dumpedComplement ) {
2318 				e = p->tclass->setnumComplement;
2319 				eErrSet = p->tclass->setnumErrSetComplement;
2320 			}
2321 			else {
2322 				e = DefErrSetWithSuffix(0, &b, 0, TokenString(p->token), "_setbar");
2323 				eErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, TokenString(p->token), "_errsetbar");
2324 				p->tclass->dumpedComplement = 1;	/* indicate set has been created */
2325 				p->tclass->setnumComplement = e;
2326 				p->tclass->setnumErrSetComplement = eErrSet;					/* MR23 */
2327 			}
2328 			sprintf(buf, "%s_setbar", TokenString(p->token));
2329 			sprintf(bufErrSet, "%s_errsetbar", TokenString(p->token));	/* MR23 */
2330 			set_name = buf;
2331 			set_nameErrSet = bufErrSet;								/* MR23 */
2332 		}
2333 		else {					/* wild card */
2334 			static char buf[sizeof("zzerr")+10];
2335 			static char bufErrSet[sizeof("zzerr")+10];
2336 			int n = DefErrSet( &b, 0, NULL );
2337 			int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set");
2338 			if ( GenCC ) sprintf(buf, "err%d", n);
2339 			else sprintf(buf, "zzerr%d", n);
2340 			if ( GenCC ) sprintf(bufErrSet, "err%d", nErrSet);
2341 			else sprintf(bufErrSet, "zzerr%d", nErrSet);
2342 			set_name = buf;
2343 			set_nameErrSet = bufErrSet;
2344 		}
2345 
2346 		if ( !FoundException ) {
2347 /* MR23 */		gen2("zzsetmatch(%s, %s);", set_name, set_nameErrSet);
2348 		}
2349 		else if ( p->ex_group==NULL ) {
2350             if ( p->use_def_MT_handler )
2351                 gen3("zzsetmatch_wdfltsig(%s,(ANTLRTokenType)%d,%s);",
2352                      set_name,
2353                      p->token,
2354                      tokenFollowSet(p))
2355             else
2356                 gen2("zzsetmatch_wsig(%s, %s_handler);",
2357                      set_name,
2358                      handler_id);
2359 		}
2360 		else
2361 		{
2362 			gen1("if ( !_setmatch_wsig(%s) ) {\n", set_name);
2363 			tabs++;
2364 /* MR6 */	if (FoundGuessBlk) {
2365 /* MR6 */	  if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
2366 /* MR6 */	  else gen("if ( zzguessing ) goto fail;\n");
2367 /* MR6 */	};
2368 			gen("_signal=MismatchedToken;\n");
2369 			dumpException(p->ex_group, 0);
2370 			tabs--;
2371 			gen("}\n");
2372 		}
2373 		set_free(b);
2374 		set_free(bErrSet);
2375 	}
2376 	else if ( TokenString(p->token)!=NULL )
2377 	{
2378 		if ( FoundException ) {
2379 			if ( p->use_def_MT_handler )
2380 				gen2("zzmatch_wdfltsig(%s,%s);",TokenString(p->token),tokenFollowSet(p))
2381 			else if ( p->ex_group==NULL )
2382 			{
2383 				gen2("zzmatch_wsig(%s, %s_handler);",
2384 					 TokenString(p->token),
2385 					 handler_id);
2386 			}
2387 			else
2388 			{
2389 /* MR6 */		if (GenCC) {
2390 /* MR6 */		  gen1("if ( !_match_wsig(%s) ) {\n", TokenString(p->token));
2391 /* MR6 */		} else {
2392 /* MR6 */		  gen1("if ( !_zzmatch_wsig(%s) ) {\n", TokenString(p->token));
2393 /* MR6 */		};
2394 				tabs++;
2395 /* MR6 */		if (FoundGuessBlk) {
2396 /* MR6 */	  	  if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
2397 /* MR6 */		  else gen("if ( zzguessing ) goto fail;\n");
2398 /* MR6 */		};
2399 				gen("_signal=MismatchedToken;\n");
2400 				dumpException(p->ex_group, 0);
2401 				tabs--;
2402 				gen("}\n");
2403 			}
2404 		}
2405 		else gen1("zzmatch(%s);", TokenString(p->token));
2406 	}
2407 	else {
2408         if ( FoundException ) {
2409             if ( p->use_def_MT_handler )
2410 				gen2("zzmatch_wdfltsig((ANTLRTokenType)%d,%s);",
2411 					 p->token,tokenFollowSet(p))
2412             else
2413                 gen2("zzmatch_wsig(%d,%s_handler);",p->token,handler_id);
2414         }
2415 		else {gen1("zzmatch(%d);", p->token);}
2416 	}
2417 
2418 	a = findImmedAction( p->next );
2419 	/* generate the token labels */
2420 	if ( GenCC && p->elnum>0 )
2421 	{
2422 		/* If building trees in C++, always gen the LT() assigns */
2423 		if ( set_el(p->elnum, tokensRefdInBlock) || GenAST )
2424 		{
2425 /* MR10 */	if ( FoundGuessBlk ) {
2426 /* MR10 */    gen("\n");
2427 /* MR10 */    if (p->label_used_in_semantic_pred) {
2428 /* MR10 */		gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);  /* MR10 */\n", BlkLevel-1, p->elnum);
2429 /* MR10 */    } else {
2430 /* MR10 */		gen("if ( !guessing ) {\n"); tab();
2431 /* MR10 */		_gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);\n", BlkLevel-1, p->elnum);
2432 /* MR10 */      gen("}\n");
2433 /* MR10 */    };
2434 /* MR10 */  } else {
2435 /* MR10 */	  _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);", BlkLevel-1, p->elnum);
2436 /* MR10 */  };
2437 /* MR10 */
2438 		}
2439 
2440 /*
2441  *  MR23 labase is never used in the C++ runtime library.
2442  *       and this code is generated only in C++ mode
2443  */
2444 
2445 /***		if ( LL_k>1 )                                    / * MR23 disabled */
2446 /***			if ( !DemandLookahead ) _gen(" labase++;");  / * MR23 disabled */
2447 /***		_gen("\n");                                      / * MR23 disabled */
2448 /***		tab();                                           / * MR23 disabled */
2449 	}
2450 	if ( GenAST )
2451 	{
2452 		if ( FoundGuessBlk &&
2453 				(ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) )
2454 		{
2455 			if ( GenCC ) {_gen("if ( !guessing ) {\n"); tab();}
2456 			else {_gen("zzNON_GUESS_MODE {\n"); tab();}
2457 		}
2458 
2459 /* MR27 addition when labels referenced when operator ! used */
2460 
2461 		pushedCmodeAST = 0; /* MR27 */
2462 		if (ast_label_in_action && (p->astnode == ASTexclude || r->noAST)) {
2463 			_gen("\n");
2464 			if (GenCC) {
2465 /* MR13 */      if (NewAST) {
2466 /* MR13 */    	    gen4("_ast%d%d = newAST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
2467 /* MR13 */      } else {
2468 /* MR13 */    	    gen4("_ast%d%d = new AST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
2469 /* MR13 */      }
2470 			}
2471 			else {
2472 				pushedCmodeAST = 1;
2473 				gen("zzastPush(zzmk_ast(zzastnew(),zzaCur)); /* MR27 */");
2474 			}
2475 		}
2476 
2477 /* end MR27 addition for labels referenced when operator ! used */
2478 
2479 		if (!r->noAST )
2480 		{
2481 			if (GenCC && !(p->astnode == ASTexclude) ) {
2482 				_gen("\n");
2483 /* MR13 */      if (NewAST) {
2484 /* MR13 */    	    gen4("_ast%d%d = newAST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
2485 /* MR13 */      } else {
2486 /* MR13 */    	    gen4("_ast%d%d = new AST(_t%d%d);\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
2487 /* MR13 */      }
2488 				tab();
2489 			}
2490 			if ( GenCC && !(p->astnode == ASTexclude) )
2491 				{_gen2("_ast%d%d->", BlkLevel-1, p->elnum);}
2492 			else _gen(" ");
2493 			if ( p->astnode==ASTchild ) {
2494 				if ( !GenCC ) _gen("zz");
2495 				_gen("subchild(_root, &_sibling, &_tail);");
2496 			}
2497 			else if ( p->astnode==ASTroot ) {
2498 				if ( !GenCC ) _gen("zz");
2499 				_gen("subroot(_root, &_sibling, &_tail);");
2500 			}
2501 			if ( GenCC && !(p->astnode == ASTexclude) ) {
2502 				_gen("\n");
2503 				tab();
2504 			}
2505 		}
2506 		else if ( !GenCC ) {
2507 			if (! pushedCmodeAST) _gen(" zzastDPush;");
2508 		}
2509 		if ( FoundGuessBlk &&
2510 				(ast_label_in_action || !(p->astnode == ASTexclude || r->noAST)) )
2511 			{gen("}\n"); tab();}
2512 	}
2513 
2514 	/* Handle element labels now */
2515 	if ( p->el_label!=NULL )
2516 	{
2517         int     done_NON_GUESSMODE=0;
2518 
2519 		_gen("\n");
2520 
2521 /* MR10 */    /* do Attrib / Token ptr for token label used in semantic pred */
2522 /* MR10 */    /* for these cases do assign even in guess mode                */
2523 /* MR10 */
2524 /* MR10 */    if (p->label_used_in_semantic_pred) {
2525 /* MR10 */      if ( GenCC ) {
2526 /* MR10 */        if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) {
2527 /* MR10 */          gen3("%s = _t%d%d;", p->el_label, BlkLevel-1, p->elnum);
2528 /* MR10 */        } else {
2529 /* MR10 */          gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label);
2530 /* MR10 */        };
2531 /* MR10 */      } else {
2532 /* MR10 */		  gen1("%s = zzaCur;", p->el_label);
2533 /* MR10 */      };
2534 /* MR10 */      if (FoundGuessBlk) _gen("  /* MR10 */");
2535 /* MR10 */      _gen("\n");
2536 /* MR10 */    };
2537 
2538 		/* Do Attrib / Token ptr */
2539 
2540 /* MR10 */  if (! p->label_used_in_semantic_pred) {
2541 /* MR10 */
2542 /* MR10 */      if ( FoundGuessBlk ) {
2543 /* MR10 */        if (! done_NON_GUESSMODE) {
2544 /* MR10 */          done_NON_GUESSMODE=1;
2545 /* MR10 */          if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();}
2546 /* MR10 */          else {gen("zzNON_GUESS_MODE {\n"); tab();}
2547 /* MR10 */        };
2548 /* MR10 */      };
2549 /* MR10 */
2550 /* MR10 */      if ( GenCC ) {
2551 /* MR10 */        if ( set_el(p->elnum, tokensRefdInBlock) || GenAST ) {
2552 /* MR10 */          gen3("%s = _t%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
2553 /* MR10 */        } else {
2554 /* MR10 */          gen1("%s = (ANTLRTokenPtr)LT(1);\n", p->el_label);
2555 /* MR10 */        };
2556 /* MR10 */      } else {
2557 /* MR10 */        gen1("%s = zzaCur;\n", p->el_label);
2558 /* MR10 */      };
2559 /* MR10 */  };
2560 
2561 		/* Do AST ptr */
2562 
2563 		if (GenAST && (ast_label_in_action || !(p->astnode == ASTexclude || r->noAST) )) /* MR27 */
2564 		{
2565 
2566 /* MR10 */      if ( FoundGuessBlk ) {
2567 /* MR10 */        if (! done_NON_GUESSMODE) {
2568 /* MR10 */          done_NON_GUESSMODE=1;
2569 /* MR10 */          if ( GenCC ) {gen("if ( !guessing ) {\n"); tab();}
2570 /* MR10 */          else {gen("zzNON_GUESS_MODE {\n"); tab();}
2571 /* MR10 */        };
2572 /* MR10 */      };
2573 
2574 			if ( GenCC ) {
2575 				gen3("%s_ast = _ast%d%d;\n", p->el_label, BlkLevel-1, p->elnum);
2576 			}
2577 			else {gen1("%s_ast = zzastCur;\n", p->el_label);}
2578 		}
2579 
2580 /* MR10 */  if (done_NON_GUESSMODE) {
2581 /* MR10 */    gen("}\n"); tab();
2582 /* MR10 */  };
2583 
2584 	}
2585 
2586 	/* Handle any actions immediately following action */
2587 	if ( a != NULL )  /* MR10 */ /* MR11 */
2588     {
2589     	/* delay next token fetch until after action */
2590 		_gen("\n");
2591 		if ( a->is_predicate)
2592 		{
2593 #if 0
2594 /* Disabled in MR30 ************************************************************
2595    And moved into genAction
2596    *****************************************************************************
2597 */
2598 
2599     	    gen("if (!(");
2600 
2601 			/* make sure that '#line n' is on front of line */  /* MR14 */
2602 			if ( GenLineInfo && p->file != -1 ) _gen("\n");     /* MR14 */
2603 			dumpPredAction(a,a->action, output, 0, a->file, a->line, 0);
2604 
2605 /* MR23 Change failed predicate macro to have three arguments:
2606 
2607         macro arg 1: The stringized predicate itself
2608         macro arg 2: 0 => no user-defined error action
2609                      1 => user-defined error action
2610         macro arg 3: The user-defined error action
2611 
2612    This gives the user more control of the error action.
2613 */
2614 			_gen(")) \n");
2615 			tabs++;
2616 			gen3(" {zzfailed_pred(\"%s\",%s,{ %s } );}\n",           /* MR23 */
2617 					stringize(a->action),	                         /* MR23 */
2618                     (a->pred_fail == NULL ?                          /* MR23/MR27 */
2619                        	"0 /* report */" : "1 /* user action */"),   /* MR23/MR27 */
2620                     (a->pred_fail == NULL ?                          /* MR23 */
2621                         "0; /* no user action */" : a->pred_fail));  /* MR23 */
2622 			tabs--;
2623 /* Disabled in MR30 ************************************************************
2624    And moved into genAction
2625    *****************************************************************************
2626 */
2627 #endif
2628 		}
2629 		else    /* MR9 a regular action - not a predicate action */
2630 		{
2631 
2632 /* MR23: Search an action which is not a predicate for LT(i),
2633          LA(i), or LATEXT(i) in order to warn novice users that
2634          it refers to the previous matched token, not the next
2635          one.  This is different than the case for semantic
2636          predicates.
2637 */
2638 
2639 /* MR23 */    if (GenCC) {
2640 /* MR23 */	    if (strstr(a->action, "LT(") != NULL) LTinTokenAction = 1;
2641 /* MR23 */    }
2642 /* MR23 */    else {
2643 /* MR23 */      if (strstr(a->action, "LA(") != NULL) LTinTokenAction = 1;
2644 /* MR23 */      if (strstr(a->action, "LATEXT(") != NULL) LTinTokenAction = 1;
2645 /* MR23 */    }
2646 
2647 			if ( FoundGuessBlk ) {
2648    				if ( GenCC ) {gen("if ( !guessing ) {\n");}
2649    				else gen("zzNON_GUESS_MODE {\n");
2650 			}
2651    			dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1); /* MR21 */
2652        		if ( FoundGuessBlk ) gen("}\n");
2653 			a->done = 1; /* MR30 */
2654  		}
2655 /***    a->done = 1;  MR30 Moved up into then branch for true actions, but not predicates ***/
2656 		if ( !DemandLookahead ) {
2657 			if ( GenCC ) {
2658 				if ( FoundException && p->use_def_MT_handler ) gen("if (!_signal)");
2659 				_gen(" consume();")
2660                 if ( FoundException && p->use_def_MT_handler )
2661                     _gen(" _signal=NoSignal;");
2662                 _gen("\n");
2663 			}
2664             else
2665             {
2666                 if ( FoundException && p->use_def_MT_handler ) _gen("if (!_signal)");
2667 					_gen(" zzCONSUME;\n");
2668                 if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;");
2669                 _gen("\n");
2670             }
2671 		}
2672 		else gen("\n");
2673 		if (a->done) {			/* MR30 */
2674 			TRANS( a->next );   /* MR30 */
2675 		}						/* MR30 */
2676 		else {					/* MR30 */
2677 			TRANS( p->next );	/* MR30 */
2678 		}						/* MR30 */
2679 	}
2680 	else
2681 	{
2682         if ( !DemandLookahead ) {
2683 			if ( GenCC ) {
2684 				if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)");
2685 				_gen(" consume();")
2686 				if (FoundException&&p->use_def_MT_handler) _gen(" _signal=NoSignal;");
2687 				_gen("\n");
2688 			}
2689 			else {
2690 				if (FoundException && p->use_def_MT_handler) _gen("if (!_signal)");
2691 				_gen(" zzCONSUME;");
2692 				if ( FoundException && p->use_def_MT_handler ) _gen(" _signal=NoSignal;");
2693 				_gen("\n");
2694 			}
2695 		}
2696 		else _gen("\n");
2697 		TRANS(p->next);
2698 	}
2699 }
2700 
2701 /*  MR21
2702  *
2703  *  There was a bug in the code generation for {...} which causes it
2704  *  to omit the optional tokens from the error messages.  The easiest
2705  *  way to fix this was to make the opt block look like a sub block:
2706  *
2707  *          { a | b | c }
2708  *
2709  *  becomes (internally):
2710  *
2711  *          ( a | b | c | )
2712  *
2713  *  The code for genOptBlk is now identical to genSubBlk except for
2714  *  cosmetic changes.
2715  */
2716 
2717 void
2718 #ifdef __USE_PROTOS
genOptBlk(Junction * q)2719 genOptBlk( Junction *q )
2720 #else
2721 genOptBlk( q )
2722 Junction *q;
2723 #endif
2724 {
2725 	int max_k;
2726 	set f;
2727 	int need_right_curly;
2728 	set savetkref;
2729 	int lastAltEmpty;			/* MR23 */
2730 	savetkref = tokensRefdInBlock;
2731 	require(q->ntype == nJunction,	"genOptBlk: not junction");
2732 	require(q->jtype == aOptBlk,	"genOptBlk: not opt block");
2733 
2734     OutLineInfo(output,q->line,FileStr[q->file]);
2735 	BLOCK_Preamble(q);
2736 	BlkLevel++;
2737     BlockPreambleOption(q,q->pFirstSetSymbol); /* MR21 */
2738 	f = genBlk(q, aOptBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
2739 /* MR23
2740    Bypass error clause generation when exceptions are used in {...} block
2741    See multi-line note in genBlk near call to isEmptyAlt.
2742 */
2743 	if (! FoundException) {
2744 	    if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
2745 	}
2746 	else {
2747 		gen("/* MR23 skip error clause for {...} when exceptions in use */\n");
2748 	}
2749 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
2750 	freeBlkFsets(q);
2751 	--BlkLevel;
2752 	BLOCK_Tail();
2753 
2754 	if ( q->guess )
2755 	{
2756 		gen("zzGUESS_DONE\n");
2757 	}
2758 
2759 	/* must duplicate if (alpha)?; one guesses (validates), the
2760 	 * second pass matches */
2761 	if ( q->guess && analysis_point(q)==q )
2762 	{
2763         OutLineInfo(output,q->line,FileStr[q->file]);
2764 		BLOCK_Preamble(q);
2765 		BlkLevel++;
2766 		f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
2767 		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
2768 		{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
2769 		freeBlkFsets(q);
2770 		--BlkLevel;
2771 		BLOCK_Tail();
2772 	}
2773 
2774 	tokensRefdInBlock = savetkref;
2775 	if (q->end->p1 != NULL) TRANS(q->end->p1);
2776 }
2777 
2778 /*
2779  * Generate code for a loop blk of form:
2780  *
2781  *				 |---|
2782  *				 v   |
2783  *			   --o-G-o-->o--
2784  */
2785 void
2786 #ifdef __USE_PROTOS
genLoopBlk(Junction * begin,Junction * q,Junction * start,int max_k)2787 genLoopBlk( Junction *begin, Junction *q, Junction *start, int max_k )
2788 #else
2789 genLoopBlk( begin, q, start, max_k )
2790 Junction *begin;
2791 Junction *q;
2792 Junction *start;	/* where to start generating code from */
2793 int max_k;
2794 #endif
2795 {
2796 	set         f;
2797 	int         need_right_curly;
2798 	set         savetkref;
2799     Junction    *guessBlock;    /* MR10 */
2800     int         singleAlt;      /* MR10 */
2801 	int			lastAltEmpty;	/* MR23 */
2802 
2803 	savetkref = tokensRefdInBlock;
2804 	require(q->ntype == nJunction,	"genLoopBlk: not junction");
2805 	require(q->jtype == aLoopBlk,	"genLoopBlk: not loop block");
2806 
2807 	if ( q->visited ) return;
2808 	q->visited = TRUE;
2809 
2810     /* first_item_is_guess_block doesn't care what kind of node it is */
2811 
2812     guessBlock=first_item_is_guess_block( (Junction *) q->p1);  /* MR10 */
2813     singleAlt=q->p2==NULL;                                      /* MR10 */
2814 
2815 	if (singleAlt && !guessBlock)	    /* MR10 */ /* only one alternative? */
2816 	{
2817 		if ( DemandLookahead ) {
2818 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
2819 			else gen1("look(%d);\n", max_k);
2820 		}
2821 		gen("while ( ");
2822 		if ( begin!=NULL ) genExpr(begin);
2823 		else genExpr(q);
2824 		/* if no predicates have been hoisted for this single alt (..)*
2825 		 * do so now
2826 		 */
2827         require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
2828 		if ( ParseWithPredicates && begin->predicate==NULL )
2829 		{
2830 			Predicate *a = MR_find_predicates_and_supp((Node *)q->p1);
2831             require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
2832 
2833 			if ( a!=NULL )
2834 			{
2835 				_gen("&&");
2836 				a=genPredTreeMain(a, (Node *)q);    /* MR10 */
2837 			}
2838 /* MR10 */  if (MRhoisting) {
2839 /* MR10 */    predicate_free(a);
2840 /* MR10 */  };
2841 		}
2842 		_gen(" ) {\n");
2843 		tabs++;
2844 		TRANS(q->p1);
2845 		if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
2846 		if ( DemandLookahead ) {
2847 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
2848 			else gen1("look(%d);\n", max_k);
2849 		}
2850 		--tabs;
2851 		gen("}\n");
2852 		freeBlkFsets(q);
2853 		q->visited = FALSE;
2854 		tokensRefdInBlock = savetkref;
2855 		return;
2856 	}
2857 	gen("for (;;) {\n");        /* MR20 G. Hobbelt */
2858 	tabs++;
2859 /* MR6				                					*/
2860 /* MR6 	   "begin" can never be null when called from genLoopBegin	*/
2861 /* MR6     because q==(Junction *)begin->p1 and we know q is valid	*/
2862 /* MR6								                            	*/
2863 /* MR6	   from genLoopBegin:						                */
2864 /* MR6			                						            */
2865 /* MR6		 if ( LL_k>1 && !set_nil(q->fset[2]) )			        */
2866 /* MR6	 	   genLoopBlk( q, (Junction *)q->p1, q, max_k );	    */
2867 /* MR6		else genLoopBlk( q, (Junction *)q->p1, NULL, max_k );	*/
2868 /* MR6				                				            	*/
2869 	if ( begin!=NULL )
2870 	{
2871 		if ( DemandLookahead )
2872 		{
2873 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
2874 			else gen1("look(%d);\n", max_k);
2875 		}
2876 		/* The bypass arc of the (...)* predicts what to do when you fail, but
2877 		 * ONLY after having tested the loop start expression.  To avoid this,
2878 		 * we simply break out of the (...)* loop when we find something that
2879 		 * is not in the prediction of the loop (all alts thereof).
2880 		 */
2881 		gen("if ( !(");
2882 
2883 /***	TJP says: It used to use the prediction expression for the bypass arc
2884      	of the (...)*.  HOWEVER, if a non LL^1(k) decision was found, this
2885     	thing would miss the ftree stored in the aLoopBegin node and generate
2886     	an LL^1(k) decision anyway.
2887 
2888  ***		genExpr((Junction *)begin->p2);
2889  ***/
2890 
2891             genExpr((Junction *)begin);
2892             _gen(")) break;\n");
2893 
2894 	}
2895 
2896 	/* generate code for terminating loop (this is optional branch) */
2897 
2898 	f = genBlk(q, aLoopBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
2899 	set_free(f);
2900 	freeBlkFsets(q);
2901 
2902 	/* generate code for terminating loop (this is optional branch) */
2903 
2904 /* MR6 						                    			            */
2905 /* MR6  30-May-97 Bug reported by Manuel Ornato				            */
2906 /* MR6            A definite bug involving the exit from a loop block   */
2907 /* MR6 		  In 1.23 and later versions (including 1.33) Instead       */
2908 /* MR6              exiting the block and reporting a syntax error the  */
2909 /* MR6		    code loops forever.     				                */
2910 /* MR6	          Looking at 1.20 which generates proper code it is not */
2911 /* MR6		    clear which of two changes should be undone.            */
2912 /* MR6		  This is my best guess.                                    */
2913 /* MR6		  From earlier MR6 note we know that begin can never be     */
2914 /* MR6		    null when genLoopBlk called from genLoopBegin           */
2915 /* MR6 */
2916 /* MR6 */ if ( begin==NULL) {
2917 /* MR6 */   /* code for exiting loop "for sure" */
2918 /* MR6 */   gen("/* Suppressed by MR6 */ /*** else break; ***/\n");
2919 /* MR6 */ };
2920 
2921 /* MR10 */if (singleAlt && guessBlock) {
2922 /* MR10 */  tabs--;
2923 /* MR6 */   gen("} else break; /* MR6 code for exiting loop \"for sure\" */\n");
2924 /* MR10 */  need_right_curly--;
2925 /* MR10 */ } else {
2926 /* MR6 */   gen("else break; /* MR6 code for exiting loop \"for sure\" */\n");
2927 /* MR10 */ };
2928 
2929 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
2930 	if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
2931 	--tabs;
2932 	gen("}\n");
2933 	q->visited = FALSE;
2934 	tokensRefdInBlock = savetkref;
2935 }
2936 
2937 /*
2938  * Generate code for a loop blk of form:
2939  *
2940  * 				         |---|
2941  *					     v   |
2942  *			   --o-->o-->o-G-o-->o--
2943  *                   |           ^
2944  *                   v           |
2945  *					 o-----------o
2946  *
2947  * q->end points to the last node (far right) in the blk.
2948  *
2949  * Note that q->end->jtype must be 'EndBlk'.
2950  *
2951  * Generate code roughly of the following form:
2952  *
2953  *	do {
2954  *		... code for alternatives ...
2955  *  } while ( First Set of aLoopBlk );
2956  *
2957  *	OR if > 1 alternative
2958  *
2959  *	do {
2960  *		... code for alternatives ...
2961  *		else break;
2962  *  } while ( 1 );
2963  */
2964 void
2965 #ifdef __USE_PROTOS
genLoopBegin(Junction * q)2966 genLoopBegin( Junction *q )
2967 #else
2968 genLoopBegin( q )
2969 Junction *q;
2970 #endif
2971 {
2972 	set f;
2973 	int i;
2974 	int max_k;
2975 	set savetkref;
2976 	savetkref = tokensRefdInBlock;
2977 	require(q!=NULL,				"genLoopBegin: invalid node and/or rule");
2978 	require(q->ntype == nJunction,	"genLoopBegin: not junction");
2979 	require(q->jtype == aLoopBegin,	"genLoopBegin: not loop block");
2980 	require(q->p2!=NULL,			"genLoopBegin: invalid Loop Graph");
2981 
2982     OutLineInfo(output,q->line,FileStr[q->file]);
2983 
2984 	BLOCK_Preamble(q);
2985 	BlkLevel++;
2986     BlockPreambleOption(q,q->pFirstSetSymbol);       /* MR21 */
2987 	f = First(q, 1, aLoopBegin, &max_k);
2988 	/* If not simple LL(1), must specify to start at LoopBegin, not LoopBlk */
2989 	if ( LL_k>1 && !set_nil(q->fset[2]) )
2990 		genLoopBlk( q, (Junction *)q->p1, q, max_k );
2991 	else genLoopBlk( q, (Junction *)q->p1, NULL, max_k );
2992 
2993 	for (i=1; i<=CLL_k; i++) set_free(q->fset[i]);
2994 	for (i=1; i<=CLL_k; i++) set_free(((Junction *)q->p2)->fset[i]);
2995 	--BlkLevel;
2996 	BLOCK_Tail();
2997 	set_free(f);
2998 	tokensRefdInBlock = savetkref;
2999 /* MR21 */	if (MR_BlkErr) {
3000 /* MR21 */		set f, fArray[2];
3001 /* MR21 */		f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ );
3002 /* MR21 */      fArray[0]= empty;
3003 /* MR21 */		fArray[1]= set_dup(f);
3004 /* MR21 */      gen("if (");
3005 /* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
3006 /* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
3007 /* MR21 */      tabs++;
3008 /* MR21 */      tab();
3009 /* MR21 */      _gen("/* nothing */ }\n");
3010 /* MR21 */      tab();
3011 /* MR21 */      makeErrorClause(q,f,1,0 /* use plus block bypass ? */ );  /* frees set */
3012 /* MR21 */      tabs--;
3013 /* MR21 */	};
3014 	if (q->end->p1 != NULL) TRANS(q->end->p1);
3015 }
3016 
3017 /*
3018  * Generate code for a loop blk of form:
3019  *
3020  * 					 |---|
3021  *					 v   |
3022  *			       --o-G-o-->o--
3023  *
3024  * q->end points to the last node (far right) in the blk.
3025  * Note that q->end->jtype must be 'EndBlk'.
3026  *
3027  * Generate code roughly of the following form:
3028  *
3029  *	do {
3030  *		... code for alternatives ...
3031  *  } while ( First Set of aPlusBlk );
3032  *
3033  *	OR if > 1 alternative
3034  *
3035  *	do {
3036  *		... code for alternatives ...
3037  *		else if not 1st time through, break;
3038  *  } while ( 1 );
3039  */
3040 void
3041 #ifdef __USE_PROTOS
genPlusBlk(Junction * q)3042 genPlusBlk( Junction *q )
3043 #else
3044 genPlusBlk( q )
3045 Junction *q;
3046 #endif
3047 {
3048 	int         max_k;
3049 	set         f;
3050 	int         need_right_curly;
3051 	int			lastAltEmpty;	/* MR23 */
3052 	set         savetkref;
3053     Junction    *guessBlock;    /* MR10 */
3054     int         singleAlt;      /* MR10 */
3055 
3056 	savetkref = tokensRefdInBlock;
3057 	require(q!=NULL,				"genPlusBlk: invalid node and/or rule");
3058 	require(q->ntype == nJunction,	"genPlusBlk: not junction");
3059 	require(q->jtype == aPlusBlk,	"genPlusBlk: not Plus block");
3060 	require(q->p2 != NULL,			"genPlusBlk: not a valid Plus block");
3061 
3062 	if ( q->visited ) return;
3063 	q->visited = TRUE;
3064     OutLineInfo(output,q->line,FileStr[q->file]);
3065 	BLOCK_Preamble(q);
3066 	BlkLevel++;
3067 
3068     BlockPreambleOption((Junction *)q, q->pFirstSetSymbol);       /* MR21 */
3069 
3070     /* first_item_is_guess_block  doesn't care what kind of node it is */
3071 
3072     guessBlock=first_item_is_guess_block( (Junction *)q->p1);   /* MR10 */
3073 
3074 	/* if the ignore flag is set on the 2nd alt and that alt is empty,
3075 	 * then it is the implied optional alternative that we added for (...)+
3076 	 * and, hence, only 1 alt.
3077 	 */
3078 
3079 /* MR10  Reported by Pulkkinen Esa (esap@cs.tut.fi)
3080  *       Outer code for guess blocks ignored when there is only one alt
3081  *         for a (...)+ block.
3082  *       Force use of regular code rather than "optimized" code for that case
3083  */
3084 
3085     singleAlt=( ( (Junction *) q->p2)->p2 == NULL) &&
3086         	  ( ( (Junction *) q->p2)->ignore );			/* only one alternative? */
3087 
3088     if (singleAlt && !guessBlock)   /* MR10 */
3089 	{
3090 
3091 		Predicate *a=NULL;
3092 		/* if the only alt has a semantic predicate, hoist it; must test before
3093 		 * entering loop.
3094 		 */
3095 		if ( ParseWithPredicates )
3096 		{
3097             require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
3098 			a = MR_find_predicates_and_supp((Node *)q);
3099             require(MR_PredRuleRefStack.count == 0,"PredRuleRef stack not empty");
3100 
3101 			if ( a!=NULL ) {
3102 				gen("if (");
3103 				a=genPredTreeMain(a, (Node *)q);    /* MR10 */
3104 				_gen(") {\n");
3105 			}
3106 		}
3107 		gen("do {\n");
3108 		tabs++;
3109 		TRANS(q->p1);
3110 		if ( !GenCC ) gen1("zzLOOP(zztasp%d);\n", BlkLevel-1);
3111 		f = First(q, 1, aPlusBlk, &max_k);
3112 		if ( DemandLookahead ) {
3113 			if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
3114 			else gen1("look(%d);\n", max_k);
3115 		}
3116 		--tabs;
3117 		gen("} while ( ");
3118 		if ( q->parm!=NULL && q->predparm ) _gen1("(%s) && ", q->parm);
3119 		genExpr(q);
3120 		if ( ParseWithPredicates && a!=NULL )
3121 		{
3122             if (! MR_comparePredicates(q->predicate,a)) {
3123     			_gen("&&");
3124     			a=genPredTreeMain(a, (Node *)q);    /* MR10 */
3125             };
3126 		}
3127 		_gen(" );\n");
3128 		if ( ParseWithPredicates && a!=NULL ) gen("}\n");
3129 		--BlkLevel;
3130 		BLOCK_Tail();
3131 		q->visited = FALSE;
3132 		freeBlkFsets(q);
3133 		set_free(f);
3134 		tokensRefdInBlock = savetkref;
3135 /* MR21 */	if (MR_BlkErr) {
3136 /* MR21 */		set f, fArray[2];
3137 /* MR21 */		f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ );
3138 /* MR21 */      fArray[0]= empty;
3139 /* MR21 */		fArray[1]= set_dup(f);
3140 /* MR21 */      gen("if (");
3141 /* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
3142 /* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
3143 /* MR21 */      tabs++;
3144 /* MR21 */      tab();
3145 /* MR21 */      _gen("/* nothing */ }\n");
3146 /* MR21 */      tab();
3147 /* MR21 */      makeErrorClause(q,f,1,1 /* use plus block bypass ? */ );  /* frees set */
3148 /* MR21 */      tabs--;
3149 /* MR21 */	};
3150 		if (q->end->p1 != NULL) TRANS(q->end->p1);
3151 /* MR10 */  if (MRhoisting) {
3152 /* MR10 */    predicate_free(a);
3153 /* MR10 */  };
3154 		return;
3155 	}
3156 	gen("do {\n");
3157 	tabs++;
3158 	f = genBlk(q, aPlusBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
3159 /* MR6              									        */
3160 /* MR6	Sinan Karasu	(sinan@tardis.ds.boeing.com)			*/
3161 /* MR6    Failed to turn off guess mode when leaving block		*/
3162 /* MR6				                           					*/
3163 /* MR6  */ if ( has_guess_block_as_last_item(q) ) {
3164 /* MR10 */   gen("/* MR10 ()+ */ else {\n");
3165 /* MR10 */   tabs++;
3166 /* MR10 */   need_right_curly++;
3167 /* MR10 */   gen("/* MR10 ()+ */ if ( !zzrv ) zzGUESS_DONE;\n");
3168 /* MR6  */   gen("/* MR10 ()+ */ if ( zzcnt > 1 ) break;\n");
3169 /* MR10 */ } else {
3170 /* MR10 */   gen("/* MR10 ()+ */ else {\n");
3171 /* MR10 */   tabs++;
3172 /* MR10 */   need_right_curly++;
3173 /* MR10 */   gen("if ( zzcnt > 1 ) break;\n");
3174 /* MR10 */ };
3175 
3176 /* MR21 */	if (MR_BlkErr && 1 >= max_k) {
3177 /* MR21 */		set f;
3178 /* MR21 */		f = ComputeErrorSet(q,1,0 /* use plus block bypass ? */ );
3179 /* MR21 */      tabs++;
3180 /* MR21 */      tab();
3181 /* MR21 */      makeErrorClause(q,f,1,0 /* use plus block bypass ? */ );  /* frees set */
3182 /* MR21 */      tabs--;
3183 /* MR21 */	}
3184 /* MR21 */  else {
3185 				tab();
3186                 makeErrorClause(q,f,max_k,1 /* use plus block bypass ? */);
3187 										    /* MR21 I think this generates the wrong set ? */
3188                                             /* MR21 because it includes the plus block bypass ? */
3189 										    /* MR21 but I'm afraid to change it without additional checking */
3190             }
3191 
3192 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
3193 	freeBlkFsets(q);
3194 	gen("zzcnt++;");
3195 	if ( !GenCC ) _gen1(" zzLOOP(zztasp%d);", BlkLevel-1);
3196 	_gen("\n");
3197 	if ( DemandLookahead ) {
3198 		if ( !GenCC ) {gen1("LOOK(%d);\n", max_k);}
3199 		else gen1("look(%d);\n", max_k);
3200 	}
3201 	--tabs;
3202 	if ( q->parm!=NULL && q->predparm ) {gen1("} while (%s);\n", q->parm);}
3203 	else gen("} while ( 1 );\n");
3204 	--BlkLevel;
3205 	BLOCK_Tail();
3206 	q->visited = FALSE;
3207 	tokensRefdInBlock = savetkref;
3208 /* MR21 */	if (MR_BlkErr) {
3209 /* MR21 */		set f, fArray[2];
3210 /* MR21 */		f = ComputeErrorSet(q,1,1 /* use plus block bypass ? */ );
3211 /* MR21 */      fArray[0]= empty;
3212 /* MR21 */		fArray[1]= set_dup(f);
3213 /* MR21 */      gen("if (");
3214 /* MR21 */      genExprSets(fArray,1);  /* note: destroys set arguments */
3215 /* MR21 */      _gen(") { /* MR21 option -mrblksynerr */\n");
3216 /* MR21 */      tabs++;
3217 /* MR21 */      tab();
3218 /* MR21 */      _gen("/* nothing */ }\n");
3219 /* MR21 */      tab();
3220 /* MR21 */      makeErrorClause(q,f,1,1 /* use plus block bypass ? */ );  /* frees set */
3221 /* MR21 */      tabs--;
3222 /* MR21 */	};
3223 	if (q->end->p1 != NULL) TRANS(q->end->p1);
3224 }
3225 
3226 /*
3227  * Generate code for a sub blk of alternatives of form:
3228  *
3229  *			       --o-G1--o--
3230  *					 |     ^
3231  *					 v    /|
3232  *			         o-G2-o|
3233  *					 |     ^
3234  *					 v     |
3235  *				   ..........
3236  *					 |     ^
3237  *					 v    /
3238  *			         o-Gn-o
3239  *
3240  * q points to the 1st junction of blk (upper-left).
3241  * q->end points to the last node (far right) in the blk.
3242  * Note that q->end->jtype must be 'EndBlk'.
3243  * The last node in every alt points to q->end.
3244  *
3245  * Generate code of the following form:
3246  *	if ( First(G1) ) {
3247  *		...code for G1...
3248  *	}
3249  *	else if ( First(G2) ) {
3250  *		...code for G2...
3251  *	}
3252  *	...
3253  *	else {
3254  *		...code for Gn...
3255  *	}
3256  */
3257 
3258 void
3259 #ifdef __USE_PROTOS
genSubBlk(Junction * q)3260 genSubBlk( Junction *q )
3261 #else
3262 genSubBlk( q )
3263 Junction *q;
3264 #endif
3265 {
3266 	int max_k;
3267 	set f;
3268 	int need_right_curly;
3269 	int lastAltEmpty;		/* MR23 */
3270 	set savetkref;
3271 	savetkref = tokensRefdInBlock;
3272 	require(q->ntype == nJunction,	"genSubBlk: not junction");
3273 	require(q->jtype == aSubBlk,	"genSubBlk: not subblock");
3274 
3275     OutLineInfo(output,q->line,FileStr[q->file]);
3276 	BLOCK_Preamble(q);
3277 	BlkLevel++;
3278     BlockPreambleOption(q,q->pFirstSetSymbol);       /* MR21 */
3279 	f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
3280 
3281 /* MR23
3282    Bypass error clause generation when exceptions are used in a sub block
3283    in which the last alternative is epsilon.  Example: "(A | B | )".
3284    See multi-line note in genBlk near call to isEmptyAlt.
3285 */
3286 	if (FoundException && lastAltEmpty) {
3287 		gen("/* MR23 skip error clause for (...| epsilon) when exceptions in use */\n");
3288 	}
3289 	else {
3290 		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */ );}
3291 	}
3292 
3293 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
3294 	freeBlkFsets(q);
3295 	--BlkLevel;
3296 	BLOCK_Tail();
3297 
3298 	if ( q->guess )
3299 	{
3300 		gen("zzGUESS_DONE\n");
3301 	}
3302 
3303 	/* must duplicate if (alpha)?; one guesses (validates), the
3304 	 * second pass matches */
3305 	if ( q->guess && analysis_point(q)==q )
3306 	{
3307         OutLineInfo(output,q->line,FileStr[q->file]);
3308 		BLOCK_Preamble(q);
3309 		BlkLevel++;
3310 		f = genBlk(q, aSubBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
3311 		if ( q->p2 != NULL ) {tab(); makeErrorClause(q,f,max_k,0 /* use plus block bypass ? */);}
3312 		{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
3313 		freeBlkFsets(q);
3314 		--BlkLevel;
3315 		BLOCK_Tail();
3316 	}
3317 
3318 	tokensRefdInBlock = savetkref;
3319 	if (q->end->p1 != NULL) TRANS(q->end->p1);
3320 }
3321 
3322 static int TnodesAllocatedPrevRule=0;
3323 
3324 /*
3325  * Generate code for a rule.
3326  *
3327  *		rule--> o-->o-Alternatives-o-->o
3328  * Or,
3329  *		rule--> o-->o-Alternative-o-->o
3330  *
3331  * The 1st junction is a RuleBlk.  The second can be a SubBlk or just a junction
3332  * (one alternative--no block), the last is EndRule.
3333  * The second to last is EndBlk if more than one alternative exists in the rule.
3334  *
3335  * To get to the init-action for a rule, we must bypass the RuleBlk,
3336  * and possible SubBlk.
3337  * Mark any init-action as generated so genBlk() does not regenerate it.
3338  */
3339 void
3340 #ifdef __USE_PROTOS
genRule(Junction * q)3341 genRule( Junction *q )
3342 #else
3343 genRule( q )
3344 Junction *q;
3345 #endif
3346 {
3347 
3348 	const char * returnValueInitializer;
3349 
3350 do {    /* MR10     Change recursion into iteration         */
3351 
3352 	int max_k;
3353 	set follow, rk, f;
3354 	ActionNode *a;
3355 	RuleEntry *r;
3356 	int lastAltEmpty;		/* MR23 */
3357 	static int file = -1;
3358 	int need_right_curly;
3359 	require(q->ntype == nJunction,	"genRule: not junction");
3360 	require(q->jtype == RuleBlk,	"genRule: not rule");
3361 
3362 /* MR14 */    require (MR_BackTraceStack.count == 0,"-alpha MR_BackTraceStack.count != 0");
3363 /* MR14 */    MR_pointerStackReset(&MR_BackTraceStack);
3364 /* MR14 */    if (AlphaBetaTrace) MR_MaintainBackTrace=1;
3365 
3366     CurRule=q->rname;                               /* MR11 */
3367 
3368 	r = (RuleEntry *) hash_get(Rname, q->rname);
3369 	if ( r == NULL ) warnNoFL("Rule hash table is screwed up beyond belief");
3370 	if ( q->file != file )		/* open new output file if need to */
3371 	{
3372 /* MR6              									*/
3373 /* MR6  Simpler to debug when output goes to stdout rather than a file 	*/
3374 /* MR6				                					*/
3375 /* MR6 */	if (UseStdout) {
3376 /* MR6 */	  output = stdout;
3377 /* MR6 */	} else {
3378 /* MR6 */  	  if ( output != NULL) fclose( output );
3379 /* MR6 */	  output = fopen(OutMetaName(outname(FileStr[q->file])), "w");
3380 /* MR6 */	};
3381 		require(output != NULL, "genRule: can't open output file");
3382 
3383 #ifdef SPECIAL_FOPEN
3384        special_fopen_actions(OutMetaName(outname(FileStr[q->file]))); /* MR1 */
3385 #endif
3386 		if ( file == -1 ) genHdr1(q->file);
3387 		else genHdr(q->file);
3388 		file = q->file;
3389 	}
3390 
3391     if (InfoM) {
3392       fprintf(stderr,"    rule %s\n",q->rname);
3393       fflush(output);
3394     };
3395 
3396 #if 0
3397     if (strcmp(q->rname,"***debug***") == 0) {
3398       fprintf(stderr,"***debug*** %s reached\n",q->rname);
3399       MR_break();
3400     };
3401 #endif
3402 
3403 	DumpFuncHeader(q,r);
3404 	tabs++;
3405 
3406 	/* MR23
3407 
3408 	   If there is a single return value then it can be initialized in
3409 	   the declaration using assignment syntax.  If there are multiple
3410 	   return values then antlr creates a struct and initialization takes
3411 	   place element by element for each element of the struct.  For
3412        multiple elements the initialization is by assignment so we have
3413        to wait until all declarations are done before emitting that code -
3414        because of restrictions in C which don't exist in C++.
3415 
3416        In the past (before MR23) the only kind of initialization was
3417 	   the PURIFY macro which was just a memset() of 0.  Now we allow
3418 	   the user to specify an initial value.  PURIFY is still used in C
3419 	   mode because C does not have constructors.  However, PURIFY is
3420 	   not used in C++ mode because it might overwrite information created
3421 	   by elements which have their own ctor.
3422 
3423 	*/
3424 
3425 	if ( q->ret!=NULL )
3426 	{
3427 		if ( hasMultipleOperands(q->ret) )                         /* MR23 */
3428 		{
3429 
3430             /* Emit initialization code later. */
3431 
3432 			gen1("struct _rv%d _retv;\n",r->rulenum);
3433 		}
3434 		else
3435 		{
3436             /* Emit initialization code now. */
3437 
3438 			tab();
3439 			DumpType(q->ret, output);
3440             returnValueInitializer = getInitializer(q->ret);
3441             if (returnValueInitializer == NULL) {                  /* MR23 */
3442       			gen(" _retv;\n");                     		    /* MR1 MR3 */
3443             }                                                      /* MR23 */
3444             else {                                                 /* MR23 */
3445                 gen1(" _retv = %s;\n", returnValueInitializer);    /* MR23 */
3446             }                                                      /* MR23 */
3447 		}
3448 	}
3449 
3450     OutLineInfo(output,q->line,FileStr[q->file]);
3451 
3452     if (InfoM) {
3453       fflush(output);
3454     };
3455 
3456 	gen("zzRULE;\n");
3457 	if ( FoundException )
3458 	{
3459 		gen("int _sva=1;\n");
3460 	}
3461 	if ( GenCC && GenAST )
3462 		gen("ASTBase *_ast = NULL, *_sibling = NULL, *_tail = NULL;\n");
3463 	if ( GenCC ) genTokenPointers(q);
3464 	if ( GenCC&&GenAST ) genASTPointers(q);
3465 	if ( q->el_labels!=NULL ) genElementLabels(q->el_labels);
3466 	if ( FoundException ) gen("int _signal=NoSignal;\n");
3467 
3468 	if ( !GenCC ) gen1("zzBLOCK(zztasp%d);\n", BlkLevel);
3469 
3470 /* MR10 */  /* move zzTRACEIN to before init action */
3471 
3472 /* MR10 */	if ( TraceGen ) {
3473 /* MR10 */		if ( GenCC ) {gen1("zzTRACEIN(\"%s\");\n", q->rname);}
3474 /* MR10 */		else gen1("zzTRACEIN((ANTLRChar *)\"%s\");\n", q->rname);
3475 /* MR10 */	}
3476 
3477 /* MR7      Moved PURIFY() to after all local variables have been declared */
3478 /* MR7      so that the generated code is valid C as well as C++           */
3479 /* MR7        Jan Mikkelsen 10-June-1997                                   */
3480 
3481 
3482      /*
3483        MR23    Do the PURIFY macro only for C mode.
3484                C++ users should use constructors or initialization expressions.
3485      */
3486 
3487 	if ( q->ret != NULL )                                            /* MR7 */
3488 	{                                                                /* MR7 */
3489 		if (hasMultipleOperands(q->ret)) {                           /* MR23 */
3490 			if (PURIFY == TRUE) {
3491                 gen1("PCCTS_PURIFY(_retv,sizeof(struct _rv%d))\n",r->rulenum); /* MR23 */
3492             }
3493         }                                                            /* MR7 */
3494 		else {                                                       /* MR7 */
3495 
3496 			/* MR23
3497 			   If there were only one return value operand and
3498 			   it had an initializer then it would have been
3499 			   initiailized in the declaration.
3500 			*/
3501 
3502 			returnValueInitializer = getInitializer(q->ret);         /* MR23 */
3503 			if (returnValueInitializer == NULL) {                    /* MR23 */
3504     			if (PURIFY == TRUE) {
3505         			gen("PCCTS_PURIFY(_retv,sizeof(");               /* MR23 */
3506 	    			DumpType(q->ret, output);                        /* MR7 */
3507 					gen("))\n");                                     /* MR7 */
3508 				}
3509 			}                                                        /* MR23 */
3510 		}                                                            /* MR7 */
3511 
3512         if (hasMultipleOperands(q->ret)) {                           /* MR23 */
3513           DumpInitializers(output, r, q->ret);                       /* MR23 */
3514         }
3515 
3516 	}
3517 	if ( !GenCC ) gen("zzMake0;\n");
3518 	if ( FoundException ) gen("*_retsignal = NoSignal;\n");
3519 
3520 	if ( !GenCC ) gen("{\n");
3521 
3522 	if ( has_guess_block_as_first_item((Junction *)q->p1) )
3523 	{
3524 		gen("zzGUESS_BLOCK\n");
3525 	}
3526 
3527 	/* L o o k  F o r  I n i t  A c t i o n */
3528 	if ( ((Junction *)q->p1)->jtype == aSubBlk )
3529 		a = findImmedAction( ((Junction *)q->p1)->p1 );
3530 	else
3531 		a = findImmedAction( q->p1 );	/* only one alternative in rule */
3532 	if ( a!=NULL && !a->is_predicate)
3533 	{
3534  /* MR21 */ if (!a->noHoist) dumpActionPlus(a, a->action, output, tabs, a->file, a->line, 1);
3535   		    a->done = 1;	/* ignore action. We have already handled it */
3536 	}
3537 
3538 	BlkLevel++;
3539 	q->visited = TRUE;				/* mark RULE as visited for FIRST/FOLLOW */
3540     BlockPreambleOption((Junction *)q->p1, NULL);   /* MR21 */
3541 	f = genBlk((Junction *)q->p1, RuleBlk, &max_k, &need_right_curly, &lastAltEmpty /* MR23 */);
3542 	if ( q->p1 != NULL )
3543 		if ( ((Junction *)q->p1)->p2 != NULL )
3544 			{tab(); makeErrorClause((Junction *)q->p1,f,max_k,0 /* use plus block bypass ? */);}
3545 	{ int i; for (i=1; i<=need_right_curly; i++) {tabs--; gen("}\n");} }
3546 	freeBlkFsets((Junction *)q->p1);
3547 	q->visited = FALSE;
3548 	--BlkLevel;
3549 	if ( !GenCC ) gen1("zzEXIT(zztasp%d);\n", BlkLevel);
3550 
3551     genTraceOut(q);
3552 
3553 	if ( q->ret!=NULL ) gen("return _retv;\n") else gen("return;\n");
3554 	/* E r r o r  R e c o v e r y */
3555 	NewSet();
3556 	rk = empty;
3557 
3558 /* MR14 */    if (r->dontComputeErrorSet) {
3559 /* MR14 */      follow=empty;
3560               } else {
3561                 MR_pointerStackReset(&MR_BackTraceStack);   /* MR14 */
3562                 MR_ErrorSetComputationActive=1;
3563                 REACH(q->end, 1, &rk, follow);
3564                 MR_ErrorSetComputationActive=0;
3565                 require (MR_BackTraceStack.count == 0,"K: MR_BackTraceStack.count != 0");
3566               }
3567 
3568   FillSet( follow );
3569 	set_free( follow );
3570 
3571   /* MR20 G. Hobbelt
3572      Isn't it so that "fail:" is ONLY referenced when:
3573 
3574       	 !FoundException || FoundGuessBlk ?
3575 
3576      Therefore add the "if" around this piece of code generation...
3577 
3578      Should guessing mode also use _handler label instead of "fail"
3579      when exception handling is active? gen can automatically put
3580      "if (guessing)" there so as to skip all kinds of user code.
3581 
3582    */
3583 
3584 	if ( !FoundException || FoundGuessBlk )  /* MR20 G. Hobbelt */
3585   {                                          /* MR20 G. Hobbelt */
3586 	_gen("fail:\n");
3587 	if ( !GenCC ) gen("zzEXIT(zztasp1);\n");
3588 	if ( FoundGuessBlk ) {
3589 	   	if ( !GenCC ) {gen("if ( zzguessing ) zzGUESS_FAIL;\n");}
3590 		else gen("if ( guessing ) zzGUESS_FAIL;\n");
3591 	}
3592 	if ( q->erraction!=NULL )
3593 		dumpAction(q->erraction, output, tabs, q->file, q->line, 1);
3594 	if ( GenCC )
3595 	{
3596 		gen1("syn(zzBadTok, %s, zzMissSet, zzMissTok, zzErrk);\n",
3597 			 r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup);
3598 	}
3599 	else
3600 	{
3601 		gen1("zzsyn(zzMissText, zzBadTok, %s, zzMissSet, zzMissTok, zzErrk, zzBadText);\n",
3602 			 r->egroup==NULL?"(ANTLRChar *)\"\"":r->egroup);
3603 	}
3604 	gen3("%sresynch(setwd%d, 0x%x);\n", GenCC?"":"zz", wordnum, 1<<setnum);
3605 
3606 	if ( q->ret!=NULL ) {
3607       genTraceOut(q);
3608       gen("return _retv;\n");
3609     } else if ( q->exceptions!=NULL ) {
3610       genTraceOut(q);
3611       gen("return;\n");
3612     } else if (!FoundException) {       /* MR10 */
3613       genTraceOut(q);                   /* MR10 */
3614     };
3615 
3616   }                                        /* MR20 G. Hobbelt */
3617 
3618 	if ( !GenCC ) gen("}\n");
3619 
3620 	/* Gen code for exception handlers */
3621     /* make sure each path out contains genTraceOut() */
3622 
3623 	if ( q->exceptions!=NULL )
3624 	{
3625 
3626 		gen("/* exception handlers */\n");
3627 
3628 		dumpExceptions(q->exceptions);
3629 
3630         if ( !r->has_rule_exception )
3631         {
3632             _gen("_handler:\n");
3633             gen("zzdflthandlers(_signal,_retsignal);\n");
3634         }
3635 /*  MR20 G. Gobbelt   The label "adios" is never referenced */
3636 
3637 #if 0
3638 	_gen("_adios:\n");
3639 #endif
3640     if ( q->ret!=NULL ) {
3641             genTraceOut(q);
3642             gen("return _retv;\n");
3643         }
3644 		else {
3645             genTraceOut(q);
3646             gen("return;\n");
3647         }
3648 	}
3649 	else if ( FoundException )
3650 	{
3651       _gen("_handler:\n");
3652       gen("zzdflthandlers(_signal,_retsignal);\n");
3653 
3654 /* MR1                                                                      */
3655 /* MR1	 7-Apr-97 Fix suggested by: John Bair (jbair@iftime.com)            */
3656 /* MR1							                                            */
3657 
3658    	  if ( q->ret != NULL) {			                             /* MR1 */
3659             genTraceOut(q);                                          /* MR10 */
3660             gen("return _retv;\n");			                         /* MR1 */
3661       } else {					                                     /* MR1 */
3662             genTraceOut(q);                                          /* MR10 */
3663             gen("return;\n")    ;				                     /* MR1 */
3664       };						                                     /* MR1 */
3665 	}
3666 
3667 	tabs--;
3668 	gen("}\n");
3669 
3670 /* MR10     Tired of looking at stacks that are as deep as the number of    */
3671 /* MR10       rules.  Changes recursion to iteration.                       */
3672 
3673     MR_releaseResourcesUsedInRule( (Node *) q );      /* MR10 */
3674 
3675     if (InfoT) {
3676       fprintf(output,"\n/* tnodes created for rule %s:  %d */\n",
3677                 q->rname, (TnodesAllocated-TnodesAllocatedPrevRule) );
3678     };
3679 
3680     TnodesAllocatedPrevRule=TnodesAllocated;
3681 
3682     if (q->p2 == NULL) dumpAfterActions( output );
3683     q=(Junction *)q->p2;
3684     require(q==NULL || q->jtype==RuleBlk,"RuleBlk p2 does not point to another RuleBlk");
3685 
3686 } while (q != NULL);
3687 
3688 /**** The old code                           ****/
3689 /****	if ( q->p2 != NULL ) {TRANS(q->p2);} ****/ /* generate code for next rule too */
3690 /****	else dumpAfterActions( output );     ****/
3691 
3692 }
3693 
3694 
3695 /* This is for the function definition, not the declaration. */
3696 
3697 static void
3698 #ifdef __USE_PROTOS
DumpFuncHeader(Junction * q,RuleEntry * r)3699 DumpFuncHeader( Junction *q, RuleEntry *r )
3700 #else
3701 DumpFuncHeader( q, r )
3702 Junction *q;
3703 RuleEntry *r;
3704 #endif
3705 {
3706 /*								                                            */
3707 /*  MR1 10-Apr-97  MR1  Simplify insertion of commas in function header     */
3708 /*								                                            */
3709 	int	needComma;					                                 /* MR1 */
3710 
3711 
3712 	/* A N S I */
3713 	_gen("\n");
3714 	if ( q->ret!=NULL )
3715 	{
3716 		if ( hasMultipleOperands(q->ret) )                            /* MR23 */
3717 		{
3718 			if (GenCC) gen2("%s::_rv%d\n", CurrentClassName, r->rulenum)
3719 			else gen1("struct _rv%d\n",r->rulenum);
3720 		}
3721 		else
3722 		{
3723 			DumpType(q->ret, output);
3724 			gen("\n");
3725 		}
3726 	}
3727 	else
3728 	{
3729 		_gen("void\n");
3730 	}
3731 /*  MR1			                                                            */
3732 /*  MR1	10-Apr-97  133MR1	Replace __STDC__ with __USE_PROTOS              */
3733 /*  MR1								                                        */
3734 	if ( !GenCC ) _gen("#ifdef __USE_PROTOS\n");		     /* MR1 */
3735 	if ( !GenCC ) gen2("%s%s(", RulePrefix, q->rname)
3736 	else gen3("%s::%s%s(", CurrentClassName, RulePrefix,q->rname);
3737 
3738     	/* If we generate C++ method names, we must hide default arguments */
3739         /* which can appear in the parameter declaration list.             */
3740         /* NOTICE: this is done only here, for the method definition, but  */
3741         /*         not for the method declaration inside the class         */
3742         /*         definition. This is exactly the behaviour defined in    */
3743         /*         C++ standard for default paramters.                     */
3744 
3745 	DumpANSIFunctionArgDef(output,q, 0 /* emit initializers ? */);
3746 	_gen("\n");
3747 
3748 	if ( GenCC ) {
3749       gen("{\n");
3750       return;
3751     }
3752 
3753 	/* K & R */
3754 	gen("#else\n");
3755 	gen2("%s%s(", RulePrefix, q->rname);
3756 	needComma=0;						                             /* MR1 */
3757 	if ( GenAST )						                             /* MR1 */
3758 	{							                                     /* MR1 */
3759 		_gen("_root");					                             /* MR1 */
3760 		needComma=1;					                             /* MR1 */
3761 	}							                                     /* MR1 */
3762 	if ( FoundException )					                         /* MR1 */
3763 	{							                                     /* MR1 */
3764 		if (needComma) {_gen(",");needComma=0;};	                 /* MR1 */
3765 		_gen("_retsignal");				                             /* MR1 */
3766 		needComma=1;					                             /* MR1 */
3767 	}							                                     /* MR1 */
3768 /* MR5	Change below by Jan Mikkelsen (janm@zeta.org.au) 26-May-97      MR5 */
3769 	DumpListOfParmNames( q->pdecl, output, needComma );	             /* MR5 */
3770 	gen(")\n");
3771 	if ( GenAST ) gen("AST **_root;\n");
3772 	if ( FoundException ) gen("int *_retsignal;\n");
3773 	DumpOldStyleParms( q->pdecl, output );
3774 	gen("#endif\n");
3775     gen("{\n");
3776 }
3777 
3778 void
3779 #ifdef __USE_PROTOS
DumpANSIFunctionArgDef(FILE * f,Junction * q,int bInitializer)3780 DumpANSIFunctionArgDef(FILE *f, Junction *q, int bInitializer)
3781 #else
3782 DumpANSIFunctionArgDef(f,q,bInitializer)
3783 FILE *f;
3784 Junction *q;
3785 int bInitializer;
3786 #endif
3787 {
3788 	if ( GenAST )
3789 	{
3790 		if ( GenCC ) {fprintf(f,"ASTBase **_root");}
3791 		else fprintf(f,"AST**_root");
3792 		if ( !FoundException && q->pdecl!=NULL ) fprintf(f,",");
3793 	}
3794 	if ( FoundException )
3795 	{
3796 		if ( GenAST ) fprintf(f,",");
3797 		fprintf(f,"int *_retsignal");
3798 		if ( q->pdecl!=NULL ) {
3799             fprintf(f,",");
3800         }
3801 	}
3802 	if ( q->pdecl!=NULL ) {
3803         DumpFormals(f, q->pdecl, bInitializer);     /* MR23 */
3804     }
3805 	else {
3806         if ( !GenAST && !FoundException ) {
3807             fprintf(f,"void");
3808         }
3809     }
3810 	fprintf(f,")");
3811 }
3812 
3813 void
3814 #ifdef __USE_PROTOS
genJunction(Junction * q)3815 genJunction( Junction *q )
3816 #else
3817 genJunction( q )
3818 Junction *q;
3819 #endif
3820 {
3821 	require(q->ntype == nJunction,	"genJunction: not junction");
3822 	require(q->jtype == Generic,	"genJunction: not generic junction");
3823 
3824 	if ( q->p1 != NULL ) TRANS(q->p1);
3825 	if ( q->p2 != NULL ) TRANS(q->p2);
3826 }
3827 
3828 void
3829 #ifdef __USE_PROTOS
genEndBlk(Junction * q)3830 genEndBlk( Junction *q )
3831 #else
3832 genEndBlk( q )
3833 Junction *q;
3834 #endif
3835 {
3836 }
3837 
3838 void
3839 #ifdef __USE_PROTOS
genEndRule(Junction * q)3840 genEndRule( Junction *q )
3841 #else
3842 genEndRule( q )
3843 Junction *q;
3844 #endif
3845 {
3846 }
3847 
3848 void
3849 #ifdef __USE_PROTOS
genHdr(int file)3850 genHdr( int file )
3851 #else
3852 genHdr( file )
3853 int file;
3854 #endif
3855 {
3856     int     i;
3857 
3858 	_gen("/*\n");
3859 	_gen(" * A n t l r  T r a n s l a t i o n  H e a d e r\n");
3860 	_gen(" *\n");
3861 	_gen(" * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
3862 	_gen(" * Purdue University Electrical Engineering\n");
3863 	_gen(" * With AHPCRC, University of Minnesota\n");
3864 	_gen1(" * ANTLR Version %s\n", Version);
3865 	_gen(" *\n");
3866 /* MR10 */    _gen(" *  ");
3867 /* MR10 */    for (i=0 ; i < Save_argc ; i++) {
3868 /* MR10 */      _gen(" ");
3869 /* MR10 */      _gen1("%s", Save_argv[i]);
3870 /* MR10 */    };
3871 	_gen("\n");
3872 	_gen(" *\n");
3873     _gen(" */\n\n");
3874 	if (FirstAction != NULL ) dumpAction( FirstAction, output, 0, -1, 0, 1);    /* MR11 MR15b */
3875 	_gen1("#define ANTLR_VERSION	%s\n", VersionDef);
3876 	_gen("#include \"pcctscfg.h\"\n");
3877 	_gen("#include \"pccts_stdio.h\"\n");
3878 	if ( strcmp(ParserName, DefaultParserName)!=0 )
3879 		_gen2("#define %s %s\n", DefaultParserName, ParserName);
3880    	if ( strcmp(ParserName, DefaultParserName)!=0 )
3881 		{_gen1("#include \"%s\"\n", RemapFileName);}
3882     OutLineInfo(output,1,FileStr[file]);
3883 	if ( GenCC ) {
3884 		if ( UserTokenDefsFile != NULL )
3885 			fprintf(output, "#include %s\n", UserTokenDefsFile);
3886 		else
3887 			fprintf(output, "#include \"%s\"\n", DefFileName);
3888 	}
3889 
3890 	if ( HdrAction != NULL ) dumpAction( HdrAction, output, 0, -1, 0, 1);
3891 	if ( !GenCC && FoundGuessBlk )
3892 	{
3893 		_gen("#define ZZCAN_GUESS\n");
3894 		_gen("#include \"pccts_setjmp.h\"\n");  /* MR15 K.J. Cummings (cummings@peritus.com) */
3895 	}
3896 	if ( FoundException )
3897 	{
3898 		_gen("#define EXCEPTION_HANDLING\n");
3899 		_gen1("#define NUM_SIGNALS %d\n", NumSignals);
3900 	}
3901 	if ( !GenCC && OutputLL_k > 1 ) _gen1("#define LL_K %d\n", OutputLL_k);
3902 	if ( GenAST&&!GenCC ) _gen("#define GENAST\n\n");
3903 	if ( GenAST ) {
3904 		if ( GenCC ) {_gen1("#include \"%s\"\n\n", ASTBASE_H);}
3905 		else _gen("#include \"ast.h\"\n\n");
3906 	}
3907 	if ( !GenCC && DemandLookahead ) _gen("#define DEMAND_LOOK\n\n");
3908 #ifdef DUM
3909 	if ( !GenCC && LexGen ) {
3910 		_gen1("#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken));
3911 	}
3912 #endif
3913 	/* ###WARNING: This will have to change when SetWordSize changes */
3914 	if ( !GenCC ) _gen1("#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned));
3915     if (TraceGen) {
3916       _gen("#ifndef zzTRACE_RULES\n");  /* MR20 */
3917       _gen("#define zzTRACE_RULES\n");  /* MR20 */
3918       _gen("#endif\n");                 /* MR22 */
3919     };
3920 	if ( !GenCC ) {_gen("#include \"antlr.h\"\n");}
3921 	else {
3922 		_gen1("#include \"%s\"\n", APARSER_H);
3923 		_gen1("#include \"%s.h\"\n", CurrentClassName);
3924 	}
3925 	if ( !GenCC ) {
3926 		if ( UserDefdTokens )
3927 			{_gen1("#include %s\n", UserTokenDefsFile);}
3928 		/* still need this one as it has the func prototypes */
3929 		_gen1("#include \"%s\"\n", DefFileName);
3930 	}
3931 	/* still need this one as it defines the DLG interface */
3932 	if ( !GenCC ) _gen("#include \"dlgdef.h\"\n");
3933 	if ( LexGen && GenCC ) _gen1("#include \"%s\"\n", DLEXERBASE_H);
3934 	if ( GenCC ) _gen1("#include \"%s\"\n", ATOKPTR_H);
3935 	if ( !GenCC && LexGen ) _gen1("#include \"%s\"\n", ModeFileName);
3936 
3937 /* MR10  Ofer Ben-Ami (gremlin@cs.huji.ac.il)           */
3938 /* MR10    Finally, a definition of the Purify macro    */
3939 
3940     if (PURIFY == TRUE) {                                                   /* MR23 */
3941         _gen("\n/* MR23 In order to remove calls to PURIFY use the antlr"); /* MR23 */
3942         _gen(" -nopurify option */\n\n");                                   /* MR23 */
3943     	_gen("#ifndef PCCTS_PURIFY\n");
3944         _gen("#define PCCTS_PURIFY(r,s) memset((char *) &(r),'\\0',(s));\n");
3945         _gen("#endif\n\n");
3946     }                                                                       /* MR23 */
3947 }
3948 
3949 void
3950 #ifdef __USE_PROTOS
genHdr1(int file)3951 genHdr1( int file )
3952 #else
3953 genHdr1( file )
3954 int file;
3955 #endif
3956 {
3957 	ListNode *p;
3958 
3959 	genHdr(file);
3960 	if ( GenAST )
3961 	{
3962 		if ( !GenCC ) {
3963 			_gen("#include \"ast.c\"\n");
3964 			_gen("zzASTgvars\n\n");
3965 		}
3966 	}
3967 	if ( !GenCC ) _gen("ANTLR_INFO\n");
3968 	if ( BeforeActions != NULL )
3969 	{
3970 		for (p = BeforeActions->next; p!=NULL; p=p->next)
3971 		{
3972 			UserAction *ua = (UserAction *)p->elem;
3973 			dumpAction( ua->action, output, 0, ua->file, ua->line, 1);
3974 		}
3975 	}
3976 
3977 	if ( !FoundException ) return;
3978 
3979 	if ( GenCC )
3980 	{
3981 		_gen1("\nvoid %s::\n", CurrentClassName);
3982 		_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
3983 		_gen("{\n");
3984 	}
3985 	else
3986 	{
3987 		_gen("\nvoid\n");
3988 /*  MR1				                                                        */
3989 /*  MR1	10-Apr-97  133MR1	Replace __STDC__ with __USE_PROTOS              */
3990 /*  MR1	                                                                    */
3991 	    _gen("#ifdef __USE_PROTOS\n");                               /* MR1 */
3992 		_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
3993 		_gen("#else\n");
3994 		_gen("zzdflthandlers( _signal, _retsignal )\n");
3995 		_gen("int _signal;\n");
3996 		_gen("int *_retsignal;\n");
3997 		_gen("#endif\n");
3998 		_gen("{\n");
3999 	}
4000 	tabs++;
4001 	if ( DefaultExGroup!=NULL )
4002 	{
4003 		dumpException(DefaultExGroup, 1);
4004 		if ( !hasDefaultException(DefaultExGroup) )
4005 		{
4006 			gen("default :\n");
4007 			tabs++;
4008 			gen("*_retsignal = _signal;\n");
4009 			tabs--;
4010 			gen("}\n");
4011 		}
4012 	}
4013 	else {
4014 		gen("*_retsignal = _signal;\n");
4015 	}
4016 
4017 	tabs--;
4018 	_gen("}\n\n");
4019 }
4020 
4021 void
4022 #ifdef __USE_PROTOS
genStdPCCTSIncludeFile(FILE * f,char * gate)4023 genStdPCCTSIncludeFile( FILE *f,char *gate )    /* MR10 */
4024 #else
4025 genStdPCCTSIncludeFile( f , gate)               /* MR10 */
4026 FILE *f;
4027 char * gate;                                    /* MR10 */
4028 #endif
4029 {
4030 /* MR10 Ramanathan Santhanam (ps@kumaran.com)           */
4031 /* MR10 Same preprocessor symbol use to gate stdpccts.h */
4032 /* MR10   even when two grammars are in use.            */
4033 /* MR10 Derive gate symbol from -fh filename            */
4034 
4035     if (gate == NULL) {
4036       fprintf(f,"#ifndef STDPCCTS_H\n");          /* MR10 */
4037       fprintf(f,"#define STDPCCTS_H\n");          /* MR10 */
4038     } else {
4039       fprintf(f,"#ifndef STDPCCTS_%s_H\n",gate);  /* MR10 */
4040       fprintf(f,"#define STDPCCTS_%s_H\n",gate);  /* MR10 */
4041     };
4042 	fprintf(f,"/*\n");
4043     if (gate == NULL) {
4044 	  fprintf(f," * %s -- P C C T S  I n c l u d e\n", stdpccts);
4045     } else {
4046 	  fprintf(f," * Standard PCCTS include file with -fh %s -- P C C T S  I n c l u d e\n", stdpccts);
4047     }
4048 	fprintf(f," *\n");
4049 	fprintf(f," * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
4050 	fprintf(f," * Purdue University Electrical Engineering\n");
4051 	fprintf(f," * With AHPCRC, University of Minnesota\n");
4052 	fprintf(f," * ANTLR Version %s\n", Version);
4053 	fprintf(f," */\n\n");
4054 
4055     fprintf(f,"#ifndef ANTLR_VERSION\n");
4056 	fprintf(f,"#define ANTLR_VERSION	%s\n", VersionDef);
4057     fprintf(f,"#endif\n\n");
4058 
4059     if (FirstAction != NULL ) dumpAction(FirstAction, f, 0, -1, 0, 1);  /* MR11 */
4060 
4061 	fprintf(f,"#include \"pcctscfg.h\"\n");
4062 	fprintf(f,"#include \"pccts_stdio.h\"\n");
4063 	if ( GenCC )
4064 	{
4065 		if ( UserDefdTokens )
4066 			fprintf(f, "#include %s\n", UserTokenDefsFile);
4067 		else {
4068 			fprintf(f, "#include \"%s\"\n", DefFileName);
4069 		}
4070 
4071 		fprintf(f, "#include \"%s\"\n", ATOKEN_H);
4072 
4073 		if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1);
4074 
4075 		fprintf(f, "#include \"%s\"\n", ATOKENBUFFER_H);
4076 
4077 		if ( OutputLL_k > 1 ) fprintf(f,"static const unsigned LL_K=%d;\n", OutputLL_k);
4078 		if ( GenAST ) {
4079 			fprintf(f, "#include \"%s\"\n", ASTBASE_H);
4080 		}
4081 
4082         if (TraceGen) {
4083           fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
4084           fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
4085           fprintf(f,"#endif\n");                 /* MR22 */
4086         };
4087 
4088 		fprintf(f,"#include \"%s\"\n", APARSER_H);
4089 		fprintf(f,"#include \"%s.h\"\n", CurrentClassName);
4090 		if ( LexGen ) fprintf(f,"#include \"%s\"\n", DLEXERBASE_H);
4091 		fprintf(f, "#endif\n");
4092 		return;
4093 	}
4094 
4095 	if ( strcmp(ParserName, DefaultParserName)!=0 )
4096 		fprintf(f, "#define %s %s\n", DefaultParserName, ParserName);
4097 	if ( strcmp(ParserName, DefaultParserName)!=0 )
4098 		fprintf(f, "#include \"%s\"\n", RemapFileName);
4099 	if ( UserTokenDefsFile != NULL )
4100 	   fprintf(f, "#include %s\n", UserTokenDefsFile);
4101 	if ( HdrAction != NULL ) dumpAction( HdrAction, f, 0, -1, 0, 1);
4102 	if ( FoundGuessBlk )
4103 	{
4104 		fprintf(f,"#define ZZCAN_GUESS\n");
4105 		fprintf(f,"#include \"pccts_setjmp.h\"\n");
4106 	}
4107     if (TraceGen) {
4108       fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
4109       fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
4110       fprintf(f,"#endif\n");                 /* MR22 */
4111     };
4112 	if ( OutputLL_k > 1 ) fprintf(f,"#define LL_K %d\n", OutputLL_k);
4113 	if ( GenAST ) fprintf(f,"#define GENAST\n");
4114 	if ( FoundException )
4115 	{
4116 /* MR1	 7-Apr-97  1.33MR1					                           */
4117 /* MR1	 	   Fix suggested by:				                   */
4118 /* MR1		   Francois-Xavier Fontaine (fontaine_f@istvax.ist.lu)         */
4119 
4120 		fprintf(f,"#define EXCEPTION_HANDLING\n");	            /* MR1 */
4121 		fprintf(f,"#define NUM_SIGNALS %d\n", NumSignals);          /* MR1 */
4122 	}
4123 	if ( DemandLookahead ) fprintf(f,"#define DEMAND_LOOK\n");
4124 #ifdef DUM
4125 	if ( LexGen ) fprintf(f, "#define zzEOF_TOKEN %d\n", (TokenInd!=NULL?TokenInd[EofToken]:EofToken));
4126 #endif
4127 	/* ###WARNING: This will have to change when SetWordSize changes */
4128 	fprintf(f, "#define zzSET_SIZE %lu\n", NumWords(TokenNum-1)*sizeof(unsigned));
4129     if (TraceGen) {
4130       fprintf(f,"#ifndef zzTRACE_RULES\n");  /* MR20 */
4131       fprintf(f,"#define zzTRACE_RULES\n");  /* MR20 */
4132       fprintf(f,"#endif\n");                 /* MR22 */
4133     };
4134 	fprintf(f,"#include \"antlr.h\"\n");
4135 	if ( GenAST ) fprintf(f,"#include \"ast.h\"\n");
4136 	if ( UserDefdTokens )
4137 		fprintf(f, "#include %s\n", UserTokenDefsFile);
4138 	/* still need this one as it has the func prototypes */
4139 	fprintf(f, "#include \"%s\"\n", DefFileName);
4140 	/* still need this one as it defines the DLG interface */
4141 	fprintf(f,"#include \"dlgdef.h\"\n");
4142 	/* don't need this one unless DLG is used */
4143 	if ( LexGen ) fprintf(f,"#include \"%s\"\n", ModeFileName);
4144 	fprintf(f,"#endif\n");
4145 }
4146 
4147 /* dump action 's' to file 'output' starting at "local" tab 'tabs'
4148    Dump line information in front of action if GenLineInfo is set
4149    If file == -1 then GenLineInfo is ignored.
4150    The user may redefine the LineInfoFormatStr to his/her liking
4151    most compilers will like the default, however.
4152 
4153    June '93; changed so that empty lines are left alone so that
4154    line information is correct for the compiler/debuggers.
4155 */
4156 void
4157 #ifdef __USE_PROTOS
dumpAction(char * s,FILE * output,int tabs,int file,int line,int final_newline)4158 dumpAction( char *s, FILE *output, int tabs, int file, int line,
4159 int final_newline )
4160 #else
4161 dumpAction( s, output, tabs, file, line, final_newline )
4162 char *s;
4163 FILE *output;
4164 int tabs;
4165 int file;
4166 int line;
4167 int final_newline;
4168 #endif
4169 {
4170     int inDQuote, inSQuote;
4171     require(s!=NULL, 		"dumpAction: NULL action");
4172     require(output!=NULL,	eMsg1("dumpAction: output FILE is NULL for %s",s));
4173 
4174 	if ( GenLineInfo && file != -1 )
4175 	{
4176         OutLineInfo(output,line,FileStr[file]);
4177 	}
4178     PastWhiteSpace( s );
4179 	/* don't print a tab if first non-white char is a # (preprocessor command) */
4180 	if ( *s!='#' ) {TAB;}
4181     inDQuote = inSQuote = FALSE;
4182     while ( *s != '\0' )
4183     {
4184         if ( *s == '\\' )
4185         {
4186             fputc( *s++, output ); /* Avoid '"' Case */
4187             if ( *s == '\0' ) return;
4188             if ( *s == '\'' ) fputc( *s++, output );
4189             if ( *s == '\"' ) fputc( *s++, output );
4190         }
4191         if ( *s == '\'' )
4192         {
4193             if ( !inDQuote ) inSQuote = !inSQuote;
4194         }
4195         if ( *s == '"' )
4196         {
4197             if ( !inSQuote ) inDQuote = !inDQuote;
4198         }
4199         if ( *s == '\n' )
4200         {
4201             fputc('\n', output);
4202 			s++;
4203             PastWhiteSpace( s );
4204             if ( *s == '}' )
4205             {
4206                 --tabs;
4207 				TAB;
4208                 fputc( *s++, output );
4209                 continue;
4210             }
4211             if ( *s == '\0' ) return;
4212 			if ( *s != '#' )	/* #define, #endif etc.. start at col 1 */
4213             {
4214 				TAB;
4215 			}
4216         }
4217         if ( *s == '}' && !(inSQuote || inDQuote) )
4218         {
4219             --tabs;            /* Indent one fewer */
4220         }
4221         if ( *s == '{' && !(inSQuote || inDQuote) )
4222         {
4223             tabs++;            /* Indent one more */
4224         }
4225         fputc( *s, output );
4226         s++;
4227     }
4228     if ( final_newline ) fputc('\n', output);
4229 }
4230 
4231 static void
4232 #ifdef __USE_PROTOS
dumpAfterActions(FILE * output)4233 dumpAfterActions( FILE *output )
4234 #else
4235 dumpAfterActions( output )
4236 FILE *output;
4237 #endif
4238 {
4239 	ListNode *p;
4240 	require(output!=NULL, "dumpAfterActions: output file was NULL for some reason");
4241 	if ( AfterActions != NULL )
4242 	{
4243 		for (p = AfterActions->next; p!=NULL; p=p->next)
4244 		{
4245 			UserAction *ua = (UserAction *)p->elem;
4246 			dumpAction( ua->action, output, 0, ua->file, ua->line, 1);
4247 		}
4248 	}
4249 	fclose( output );
4250 }
4251 
4252 /*
4253  * Find the next action in the stream of execution.  Do not pass
4254  * junctions with more than one path leaving them.
4255  * Only pass generic junctions.
4256  *
4257  *	Scan forward while (generic junction with p2==NULL)
4258  *	If we stop on an action, return ptr to the action
4259  *	else return NULL;
4260  */
4261 static ActionNode *
4262 #ifdef __USE_PROTOS
findImmedAction(Node * q)4263 findImmedAction( Node *q )
4264 #else
4265 findImmedAction( q )
4266 Node *q;
4267 #endif
4268 {
4269 	Junction *j;
4270 	require(q!=NULL, "findImmedAction: NULL node");
4271 	require(q->ntype>=1 && q->ntype<=NumNodeTypes, "findImmedAction: invalid node");
4272 
4273 	while ( q->ntype == nJunction )
4274 	{
4275 		j = (Junction *)q;
4276 		if ( j->jtype != Generic || j->p2 != NULL ) return NULL;
4277 		q = j->p1;
4278 		if ( q == NULL ) return NULL;
4279 	}
4280 	if ( q->ntype == nAction ) return (ActionNode *)q;
4281 	return NULL;
4282 }
4283 
4284 static void
4285 #ifdef __USE_PROTOS
dumpRetValAssign(char * retval,char * ret_def,RuleRefNode * ruleRef)4286 dumpRetValAssign( char *retval, char *ret_def, RuleRefNode * ruleRef /* MR30 */)
4287 #else
4288 dumpRetValAssign( retval, ret_def, ruleRef /* MR30 */)
4289 char *retval;
4290 char *ret_def;
4291 RuleRefNode *ruleRefNode;
4292 #endif
4293 {
4294 	char *q = ret_def;
4295 
4296 	tab();
4297 	while ( *retval != '\0' && *q != '\0')
4298 	{
4299 		while ( isspace((*retval)) ) retval++;
4300 		while ( *retval!=',' && *retval!='\0' ) fputc(*retval++, output);
4301 		fprintf(output, " = _trv.");
4302 
4303 		DumpNextNameInDef(&q, output);
4304 		while ( isspace(*q) ) q++;
4305 		fputc(';', output); fputc(' ', output);
4306 		if ( *retval == ',' ) retval++;
4307 	}
4308 	if (*retval == '\0' && *q != '\0') {
4309 /* MR30 */    errFL("Fewer output values than output formals for rule reference",
4310 /* MR30 */                 FileStr[ruleRef->file],ruleRef->line);
4311 	}
4312 	if (*retval != '\0' && *q == '\0') {
4313 /* MR30 */    errFL("More output actuals than output formals for rule reference",
4314 /* MR30 */                 FileStr[ruleRef->file],ruleRef->line);
4315 	}
4316 }
4317 
4318 /* This function computes the set of tokens that can possibly be seen k
4319  * tokens in the future from point j
4320  */
4321 
4322 static set
4323 #ifdef __USE_PROTOS
ComputeErrorSet(Junction * j,int k,int usePlusBlockBypass)4324 ComputeErrorSet( Junction *j, int k, int usePlusBlockBypass)
4325 #else
4326 ComputeErrorSet( j, k, usePlusBlockBypass )
4327 Junction *j;
4328 int k;
4329 int usePlusBlockBypass;
4330 #endif
4331 {
4332 	Junction *alt1;
4333 	set a, rk, f;
4334 	require(j->ntype==nJunction, "ComputeErrorSet: non junction passed");
4335 
4336 	f = rk = empty;
4337 	for (alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2)
4338 	{
4339         if (alt1->ignore && ! usePlusBlockBypass) continue;     /* MR21 - Ignore aPlusBlk forward p2 */
4340 		REACH(alt1->p1, k, &rk, a);
4341 		require(set_nil(rk), "ComputeErrorSet: rk != nil");
4342 		set_free(rk);
4343 		set_orin(&f, a);
4344 		set_free(a);
4345 	}
4346 	return f;
4347 }
4348 
4349 static char *
4350 #ifdef __USE_PROTOS
tokenFollowSet(TokNode * p)4351 tokenFollowSet(TokNode *p)
4352 #else
4353 tokenFollowSet(p)
4354 TokNode *p;
4355 #endif
4356 {
4357     static char buf[100];
4358     set rk, a;
4359     int n;
4360     rk = empty;
4361 
4362     REACH(p->next, 1, &rk, a);
4363     require(set_nil(rk), "rk != nil");
4364     set_free(rk);
4365     n = DefErrSet( &a, 0, NULL );
4366     set_free(a);
4367     if ( GenCC )
4368         sprintf(buf, "err%d", n);
4369     else
4370         sprintf(buf, "zzerr%d", n);
4371     return buf;
4372 }
4373 
4374 static void
4375 #ifdef __USE_PROTOS
makeErrorClause(Junction * q,set f,int max_k,int usePlusBlockBypass)4376 makeErrorClause( Junction *q, set f, int max_k, int usePlusBlockBypass )
4377 #else
4378 makeErrorClause( q, f, max_k, usePlusBlockBypass )
4379 Junction *q;
4380 set f;
4381 int max_k;
4382 int usePlusBlockBypass;
4383 #endif
4384 {
4385     char *  handler_id="";                                           /* MR7 */
4386     int     nilf=0;                                                  /* MR13 */
4387     RuleEntry *ruleEntry;                                            /* MR14 */
4388 
4389 	if ( FoundException )
4390 	{
4391 		_gen("else {\n");
4392 		tabs++;
4393 		if ( FoundGuessBlk )
4394 		{
4395 			if ( GenCC ) {gen("if ( guessing ) goto fail;\n");}
4396 			else gen("if ( zzguessing ) goto fail;\n");
4397 		}
4398 		gen("if (_sva) _signal=NoViableAlt;\n");
4399 		gen("else _signal=NoSemViableAlt;\n");
4400         if (q->outerEG != NULL) {
4401           handler_id=q->outerEG->altID;
4402 #if 0
4403         } else {
4404           printf("q->curAltNum=%d q->exception_label=%s\n",q->curAltNum,q->exception_label);
4405           gen("*** DEBUG *** outerEG==NULL\n");
4406 #endif
4407         };
4408 		gen1("goto %s_handler;  /* MR7 */\n",handler_id);    /* MR7 */
4409 		tabs--;
4410 		gen("}\n");
4411 		return;
4412 	}
4413 
4414 	if ( max_k == 1 )
4415 	{
4416 /* MR13 */  nilf=set_nil(f);
4417     	  	if ( GenCC ) {
4418               _gen1("else {FAIL(1,err%d", DefErrSet1(1,&f,1,NULL));
4419             } else {
4420                _gen1("else {zzFAIL(1,zzerr%d", DefErrSet1(1,&f,1,NULL));
4421             };
4422     		set_free(f);
4423 	}
4424 	else
4425 	{
4426 		int i;
4427 		set_free(f);
4428 		if ( GenCC ) {_gen1("else {FAIL(%d", max_k);}
4429 		else _gen1("else {zzFAIL(%d", max_k);
4430 
4431     ruleEntry = (RuleEntry *) hash_get(Rname,q->rname);
4432 
4433 		for (i=1; i<=max_k; i++)
4434 		{
4435 /* MR14 */  if (ruleEntry->dontComputeErrorSet) {
4436 /* MR14 */    f=empty;
4437             } else {
4438       	      f = ComputeErrorSet(q, i, usePlusBlockBypass /* use plus block bypass ? */ );
4439             }
4440 
4441       if ( GenCC ) {_gen1(",err%d", DefErrSet( &f, 1, NULL ));}
4442 			else _gen1(",zzerr%d", DefErrSet( &f, 1, NULL ));
4443 
4444 			set_free(f);
4445 		}
4446 	}
4447 	_gen(",&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;}\n");
4448 /* MR13 */  if (nilf) {
4449 /* MR13 */    errFL("empty error set for alt - probably because of undefined rule or infinite left recursion",
4450 /* MR13 */                 FileStr[q->file],q->line);
4451 /* MR13 */    gen(" /* MR13 empty error set for this alt - undef rule ? infinite left recursion ? */");
4452 /* MR13 */  };
4453 }
4454 
4455 static                                                               /* MR7 */
4456 #ifdef __USE_PROTOS
findOuterHandlerLabel(ExceptionGroup * eg)4457 char * findOuterHandlerLabel(ExceptionGroup *eg)                     /* MR7 */
4458 #else
4459 char * findOuterHandlerLabel(eg)                                     /* MR7 */
4460 ExceptionGroup *eg;                                                  /* MR7 */
4461 #endif
4462 {
4463   char              *label=NULL;                                     /* MR7 */
4464   ExceptionGroup    *outerEG;                                        /* MR7 */
4465 
4466   if (eg->forRule == 0) {                                            /* MR7 */
4467     if (eg->labelEntry != NULL) {                                    /* MR7 */
4468       outerEG=eg->labelEntry->outerEG;                               /* MR7 */
4469       if (outerEG != NULL) {                                         /* MR7 */
4470         label=outerEG->altID;                                        /* MR7 */
4471         outerEG->used=1;                                             /* MR7 */
4472       };                                                             /* MR7 */
4473     } else if (eg->outerEG != NULL) {                                /* MR7 */
4474       outerEG=eg->outerEG;                                           /* MR7 */
4475       label=outerEG->altID;                                          /* MR7 */
4476       outerEG->used=1;                                               /* MR7 */
4477     };                                                               /* MR7 */
4478   };                                                                 /* MR7 */
4479   return (label==NULL ? "" : label);                                 /* MR7 */
4480 }                                                                    /* MR7 */
4481 
4482 /*** debug ***/
4483 #if 0
4484 ** static                                                               /* MR7 */
4485 ** #ifdef __USE_PROTOS
4486 ** char * findOuterAltHandlerLabel(Junction *startJ)                    /* MR7 */
4487 ** #else
4488 ** char * findOuterAltHandlerLabel(startJ)                              /* MR7 */
4489 ** Junction *startJ;                                                    /* MR7 */
4490 ** #endif
4491 ** {                                                                    /* MR7 */
4492 **   char      *label=NULL;                                             /* MR7 */
4493 **   Junction  *alt;                                                    /* MR7 */
4494 **                                                                      /* MR7 */
4495 **   for (alt=startJ; alt != NULL; alt=alt->outerAltstart) {            /* MR7 */
4496 **     label=alt->exception_label;                                      /* MR7 */
4497 **     if (label != NULL) break;                                        /* MR7 */
4498 **   };                                                                 /* MR7 */
4499 **   return (label==NULL ? "" : label);                                 /* MR7 */
4500 ** }                                                                    /* MR7 */
4501 #endif
4502 
4503 #ifdef __USE_PROTOS
OutLineInfo(FILE * file,int line,char * fileName)4504 static void OutLineInfo(FILE *file,int line,char *fileName)
4505 #else
4506 static void OutLineInfo(file,line,fileName)
4507   FILE *    file;
4508   int       line;
4509   char *    fileName;
4510 #endif
4511 {
4512     static  char * prevFileName=NULL;
4513     static  char * prevFileNameMS=NULL;
4514 
4515     char *  p;
4516     char *  q;
4517 
4518     if (! GenLineInfo) return;
4519 
4520     if (!GenLineInfoMS) {
4521 	    fprintf(file, LineInfoFormatStr,line,fileName);
4522     } else {
4523       if (fileName == prevFileName) {
4524 	    fprintf(file, LineInfoFormatStr,line,prevFileNameMS);
4525       } else {
4526         if (prevFileNameMS != NULL) free (prevFileNameMS);
4527         prevFileNameMS=(char *)calloc(1,strlen(fileName)+1);
4528         require(prevFileNameMS != NULL,"why not do this in calloc wrapper");
4529         q=prevFileNameMS;
4530         for (p=fileName; *p != 0; p++) {
4531             *q=*p;
4532             if (*q == '\\') *q='/';
4533             q++;
4534         }
4535       }
4536       prevFileName=fileName;
4537     };
4538 }
4539 
4540 #if 0
4541 
4542 /* MR21 */
4543 
4544 #ifdef __USE_PROTOS
4545 void OutFirstSetSymbol(Junction *q, char * pSymbol)
4546 #else
4547 void OutFirstSetSymbol(q, pSymbol)
4548     Junction* q;
4549 	char * pSymbol
4550 #endif
4551 {
4552 
4553 	set f;
4554     if (pSymbol == NULL) return;
4555 	gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol);
4556     f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */);
4557     DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, "");
4558     set_free(f);
4559 }
4560 #endif
4561 
4562 /* MR21 */
4563 
4564 #ifdef __USE_PROTOS
BlockPreambleOption(Junction * q,char * pSymbol)4565 void BlockPreambleOption(Junction *q, char * pSymbol)
4566 #else
4567 void BlockPreambleOption(q, pSymbol)
4568     Junction* q;
4569 	char * pSymbol;
4570 #endif
4571 {
4572 	set f = empty;
4573     if (pSymbol != NULL) {
4574         f = ComputeErrorSet(q, 1, 0 /* use plus block bypass ? */);
4575     	gen1("/** #FirstSetSymbol(%s) **/\n",pSymbol);
4576         DefErrSetWithSuffix (0 /* nil ok */, &f,0 /* no substitute */, pSymbol, "");
4577     }
4578     set_free(f);
4579 }
4580 
4581 /* MR21 */
4582 
4583 void
4584 #ifdef __USE_PROTOS
dumpActionPlus(ActionNode * a,char * s,FILE * output,int tabs,int file,int line,int final_newline)4585 dumpActionPlus(ActionNode *a, char *s, FILE *output, int tabs, int file, int line,
4586 int final_newline )
4587 #else
4588 dumpActionPlus(a, s, output, tabs, file, line, final_newline )
4589 ActionNode *a;
4590 char *s;
4591 FILE *output;
4592 int tabs;
4593 int file;
4594 int line;
4595 int final_newline;
4596 #endif
4597 {
4598     dumpAction(s,output,tabs,file,line,final_newline);
4599 }
4600 
4601 
4602 #if 0
4603 ** #ifdef __USE_PROTOS
4604 ** void MR_ErrorSets(Junction *q, int max_k, int usePlusBlockBypass)
4605 ** #else
4606 ** void MR_ErrorSets(q, max_k, usePlusBlockBypass)
4607 ** Junction *q;
4608 ** int max_k;
4609 ** int usePlusBlockBypass;
4610 ** #endif
4611 ** {
4612 **     int k;
4613 **     set setResult;
4614 ** 	Junction* alt1;
4615 ** 	Junction* p;
4616 ** 	set rk;
4617 **
4618 **     require (max_k <= CLL_k, "k > CLL_k");
4619 **
4620 **
4621 **     for (k = 1; k <= CLL_k; k++) {set_clr(q->fset[k]); }
4622 **
4623 **     for (k = 1; k <= max_k; k++) {
4624 **         for (alt1=q; alt1 != NULL; alt1 = (Junction *)alt1->p2)
4625 **     	{
4626 **             if (alt1->ignore && ! usePlusBlockBypass) continue;
4627 **         	p = analysis_point((Junction *)alt1->p1);
4628 **     		REACH(p, k, &rk, setResult);
4629 **     		require(set_nil(rk), "rk != nil");
4630 **             set_orin(&q->fset[k], setResult);
4631 **     	}
4632 **     }
4633 ** }
4634 #endif
4635 
4636 
4637 #ifdef __USE_PROTOS
DumpInitializers(FILE * output,RuleEntry * r,char * pReturn)4638 void DumpInitializers(FILE* output, RuleEntry *r, char * pReturn)
4639 #else
4640 void DumpInitializers(output, r, pReturn)
4641 FILE* output;
4642 RuleEntry *r;
4643 char * pReturn;
4644 #endif
4645 {
4646 	char *p = pReturn;
4647 	char *pDataType;
4648 	char *pSymbol;
4649 	char *pEqualSign;
4650 	char *pValue;
4651 	char *pSeparator;
4652 	int nest = 0;
4653     char *q;
4654 
4655 	require(pReturn!=NULL, "DumpInitializer: invalid string");
4656 
4657     while (*p != 0) {
4658     	p = endFormal(p,
4659     			      &pDataType,
4660     				  &pSymbol,
4661     				  &pEqualSign,
4662     				  &pValue,
4663     				  &pSeparator,
4664     				  &nest);
4665         if (nest != 0) return;
4666         if (pValue != NULL) {
4667 			tab();
4668             q = strBetween(pSymbol, pEqualSign, pSeparator);
4669             fprintf(output, "_retv.%s", q);
4670             q = strBetween(pValue, NULL, pSeparator);
4671             fprintf(output, " = %s;\n", q);
4672         }
4673     }
4674 }
4675 
4676 #ifdef __USE_PROTOS
DumpFormals(FILE * output,char * pReturn,int bInitializer)4677 void DumpFormals(FILE* output, char * pReturn, int bInitializer)
4678 #else
4679 void DumpFormals(output, pReturn, bInitializer)
4680 FILE* output;
4681 char * pReturn;
4682 int bInitializer;
4683 #endif
4684 {
4685 	char *p = pReturn;
4686 	char *pDataType;
4687 	char *pSymbol;
4688 	char *pEqualSign;
4689 	char *pValue;
4690 	char *pSeparator;
4691 	int nest = 0;
4692     char *q;
4693     int count = 0;
4694 
4695 	require(pReturn!=NULL, "DumpFormals: invalid string");
4696 
4697     while (*p != 0) {
4698     	p = endFormal(p,
4699     			      &pDataType,
4700     				  &pSymbol,
4701     				  &pEqualSign,
4702     				  &pValue,
4703     				  &pSeparator,
4704     				  &nest);
4705         if (nest != 0) return;
4706         if (count > 0) fprintf(output,",");
4707         if (pDataType != NULL && pSymbol != NULL) {
4708             q = strBetween(pDataType, pSymbol, pSeparator);
4709             fprintf(output, "%s", q);
4710             q = strBetween(pSymbol, pEqualSign, pSeparator);
4711             fprintf(output," %s",q);
4712             if (pValue != NULL) {
4713                 q = strBetween(pValue, NULL, pSeparator);
4714                 if (bInitializer != 0) {
4715                     fprintf(output, " = %s", q);
4716                 }
4717             }
4718         }
4719         count++;
4720     }
4721 }
4722 
4723 /* MR23 Check for empty alt in a more intelligent way.
4724         Previously, an empty alt for genBlk had to point directly
4725 		to the endBlock.  This did not work once I changed {...}
4726 		blocks to look like (...|...| epsilon) since there were
4727 		intervening generics.  This fixes the problem for this
4728 		particular case.  Things like actions or empty blocks of
4729 		various kinds will still cause problems, but I wasnt't
4730 		prepared to handle pathological cases like (A|()*). It
4731 		does handle (A | ()), which is a recommended idiom for
4732 		epsilon.
4733 
4734         Actually, this isn't quite correct since it doesn't handle
4735 		the case of the ignore bit in the plus block bypass, but
4736 		I'm too tired to figure out the correct fix, and will just
4737 		work around it.
4738 */
4739 
4740 #ifdef __USE_PROTOS
isEmptyAlt(Node * alt,Node * endBlock)4741 int isEmptyAlt(Node * alt, Node * endBlock)
4742 #else
4743 int isEmptyAlt(alt, endBlock)
4744 Node * alt;
4745 Node * endBlock;
4746 #endif
4747 {
4748 	Node * n = alt;
4749 	Junction * j;
4750 	while (n != endBlock) {
4751 		switch (n->ntype) {
4752 
4753 			case nRuleRef:
4754 				return 0;
4755 
4756 			case nToken:
4757 				return 0;
4758 
4759 			case nAction:
4760 				return 0;
4761 
4762 			case nJunction:
4763 				goto JUNCTION;
4764 
4765 			default:
4766 				fatal_internal("Invalid node type");
4767 				return 0;
4768 		}
4769 JUNCTION:
4770 		j = (Junction *) n;
4771 
4772 		switch (j->jtype) {
4773 			case Generic:
4774 				{
4775 					n = j->p1;
4776 					goto NEXT;
4777 				}
4778 
4779 			case aSubBlk:
4780 				{
4781 					n = j->p1;	/* MR26 */
4782 					goto NEXT;	/* MR26 */
4783 				}
4784 
4785 			case EndBlk:
4786 					return 0;
4787 
4788 			case EndRule:
4789 					return 1;
4790 
4791 			default:
4792 					return 0;
4793 		}
4794 NEXT: continue;
4795 	}
4796 	return 1;
4797 }
4798