]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/CCode/Source/Pccts/antlr/gen.c
Fixed all scripts to use new directory layout.
[mirror_edk2.git] / Tools / CCode / Source / Pccts / antlr / gen.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
3830 genEndBlk( Junction *q )
3831 #else
3832 genEndBlk( q )
3833 Junction *q;
3834 #endif
3835 {
3836 }
3837
3838 void
3839 #ifdef __USE_PROTOS
3840 genEndRule( Junction *q )
3841 #else
3842 genEndRule( q )
3843 Junction *q;
3844 #endif
3845 {
3846 }
3847
3848 void
3849 #ifdef __USE_PROTOS
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 */ _gen(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 %d\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
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
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 %d\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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }