4 * Generate C code (ANSI, K&R, C++)
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.
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
28 * Parr Research Corporation
29 * with Purdue University and AHPCRC, University of Minnesota
43 #define NumExprPerLine 4
45 static set tokensRefdInBlock
;
47 /* T r a n s l a t i o n T a b l e s */
49 /* C_Trans[node type] == pointer to function that knows how to translate that node. */
51 void (*C_Trans
[NumNodeTypes
+1])(...) = {
53 NULL
, /* See next table.
54 Junctions have many types */
55 (void (*)(...)) genRuleRef
,
56 (void (*)(...)) genToken
,
57 (void (*)(...)) genAction
60 void (*C_Trans
[NumNodeTypes
+1])() = {
62 NULL
, /* See next table.
63 Junctions have many types */
70 /* C_JTrans[Junction type] == pointer to function that knows how to translate that
71 * kind of junction node.
74 void (*C_JTrans
[NumJuncTypes
+1])(...) = {
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
87 void (*C_JTrans
[NumJuncTypes
+1])() = {
101 #define PastWhiteSpace(s) while (*(s) == ' ' || *(s) == '\t') {s++;}
105 /* MR6 Got tired of text running off page when using standard tab stops */
107 #define TAB { int i; \
109 for (i=0; i<tabs; i++) fputc('\t', output); \
111 for (i=0; i<tabs*TabWidth; i++) fputc(' ',output); \
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 */
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 */
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);}
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);}
172 /* MR11 a convenient place to set a break point */
183 /* MR10 genTraceOut(Junction *) */
186 static void genTraceOut(Junction
*q
)
188 static void genTraceOut(q
)
193 if ( GenCC
) {gen1("zzTRACEOUT(\"%s\");\n", q
->rname
);}
194 else gen1("zzTRACEOUT((ANTLRChar *)\"%s\");\n", q
->rname
);
200 warn_about_using_gk_option(void)
202 warn_about_using_gk_option()
205 static int warned_already
=0;
207 if ( !DemandLookahead
|| warned_already
) return;
209 warnNoFL("-gk option could cause trouble for <<...>>? predicates");
214 freeBlkFsets( Junction
*q
)
222 require(q
!=NULL
, "freeBlkFsets: invalid node");
224 for (alt
=q
; alt
!= NULL
; alt
= (Junction
*) alt
->p2
)
226 for (i
=1; i
<=CLL_k
; i
++) set_free(alt
->fset
[i
]);
231 * Generate a local variable allocation for each token references
236 genTokenPointers( Junction
*q
)
238 genTokenPointers( q
)
242 /* Rule refs are counted and can be referenced, but their
243 * value is not set to anything useful ever.
245 * The ptrs are to be named _tij where i is the current level
246 * and j is the element number within an alternative.
250 tokensRefdInBlock
= q
->tokrefs
;
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
))
258 if ( first
) first
= 0;
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
);}
271 hasDefaultException(ExceptionGroup
*eg
)
273 hasDefaultException(eg
)
279 for (q
= eg
->handlers
->next
; q
!=NULL
; q
=q
->next
)
281 ExceptionHandler
*eh
= (ExceptionHandler
*)q
->elem
;
282 if ( strcmp("default", eh
->signalname
)==0 ) {
290 dumpException(ExceptionGroup
*eg
, int no_default_case
)
292 dumpException(eg
, no_default_case
)
297 char *outerLabel
; /* MR7 */
298 int altHandler
=0; /* MR7 */
299 int namedHandler
=0; /* MR7 */
301 outerLabel
=findOuterHandlerLabel(eg
); /* MR7 */
303 if (eg
->label
!= NULL
) { /* MR7 */
304 namedHandler
=1; /* MR7 */
305 } else if (eg
->forRule
) { /* MR7 */
306 /* nothing */ /* MR20 */
308 altHandler
=1; /* MR7 */
312 ** if (! eg
->used
) { /* MR7 */
313 ** warnFL("exception group never used", /* MR7 */
314 ** FileStr
[eg
->altstart
->file
],eg
->altstart
->line
); /* MR7 */
318 if (namedHandler
) { /* MR7 */
319 gen1("switch ( _signal ) { /* [%s] */\n",eg
->label
); /* MR7 */
321 gen("switch ( _signal ) {\n"); /* MR7 */
322 gen("case NoSignal: break; /* MR7 */\n"); /* MR7 */
326 for (q
= eg
->handlers
->next
; q
!=NULL
; q
=q
->next
)
328 ExceptionHandler
*eh
= (ExceptionHandler
*)q
->elem
;
329 if ( strcmp("default", eh
->signalname
)==0 ) {
332 dumpAction(eh
->action
, output
, tabs
, -1, 1, 1);
333 gen("_signal=NoSignal; /* MR7 */\n"); /* MR7 */
334 gen("break; /* MR7 */\n"); /* MR7 */
338 /* copied from later code in dumpException */ /* MR7 */
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 */
348 gen1("case %s :\n", eh
->signalname
);
350 if ( eh
->action
!= NULL
)
352 dumpAction(eh
->action
, output
, tabs
, -1, 1, 1);
353 gen("break; /* MR7 */\n"); /* MR7 */
358 if ( no_default_case
) return;
362 gen("break; /* MR7 */\n"); /* MR7 */
366 /***** gen("*_retsignal = _signal;\n"); *****/
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 */
382 dumpExceptions(ListNode
*list
)
390 for (p
= list
->next
; p
!=NULL
; p
=p
->next
)
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);
398 /* This must be the rule exception handler */
399 dumpException(eg
, 1);
400 if ( !hasDefaultException(eg
) )
404 gen("zzdflthandlers(_signal,_retsignal);\n");
412 /* For each element label that is found in a rule, generate a unique
413 * Attribute (and AST pointer if GenAST) variable.
417 genElementLabels(ListNode
*list
)
419 genElementLabels(list
)
426 if ( GenCC
) {gen("ANTLRTokenPtr");}
427 else {gen("Attrib");}
428 for (p
= list
->next
; p
!=NULL
; p
=p
->next
)
430 char *ep
= (char *)p
->elem
;
431 if ( first
) first
= 0;
433 if ( GenCC
) {_gen1(" %s=NULL",ep
);}
434 else {_gen1(" %s",ep
);}
438 if ( !GenAST
) return;
442 for (p
= list
->next
; p
!=NULL
; p
=p
->next
)
444 char *ep
= (char *)p
->elem
;
445 if ( first
) first
= 0;
447 _gen1(" *%s_ast=NULL",ep
);
453 * Generate a local variable allocation for each token or rule reference
458 genASTPointers( Junction
*q
)
467 a
= set_or(q
->tokrefs
, q
->rulerefs
);
468 if ( set_deg(a
) > 0 )
471 for (; !set_nil(a
); set_rm(t
, a
))
474 if ( first
) first
= 0;
476 _gen2("*_ast%d%d=NULL", BlkLevel
, t
);
492 if ( !GenCC
) gen1("zzBLOCK(zztasp%d);\n", BlkLevel
);
502 if ( !GenCC
) gen1("zzEXIT(zztasp%d);\n", BlkLevel
);
503 if ( !GenCC
) gen("}\n");
510 BLOCK_Preamble( Junction
*q
)
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
);
528 if ( has_guess_block_as_first_item(begin
) )
530 gen("zzGUESS_BLOCK\n");
532 if ( q
->jtype
== aLoopBegin
)
533 a
= findImmedAction( ((Junction
*)q
->p1
)->p1
); /* look at aLoopBlk */
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 */
544 genCombinedPredTreeContextOrig( Predicate
*p
)
546 genCombinedPredTreeContextOrig( p
)
550 static set
*ctx
=NULL
; /* genExprSets() is destructive, make copy*/
551 require(p
!=NULL
, "can't make context tree for NULL pred tree");
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");
558 if ( p
->down
== NULL
)
560 /*** if ( p->k>1 && p->tcontext!=NULL ) ***/
561 if ( p
->tcontext
!=NULL
)
564 genExprTree(p
->tcontext
, 1);
567 /*** else if ( p->k==1 && set_deg(p->scontext[1])>0 ) ***/
568 else if ( set_deg(p
->scontext
[1])>0 )
570 if ( ctx
==NULL
) ctx
= (set
*)calloc(CLL_k
+1, sizeof(set
));
571 require(ctx
!=NULL
, "ctx cannot allocate");
573 ctx
[1]=set_dup(p
->scontext
[1]);
575 genExprSets(&(ctx
[0]), p
->k
);
579 else if ( p
->expr
==PRED_AND_LIST
|| p
->expr
==PRED_OR_LIST
) {
580 fatal_internal("pred tree is orphan OR or AND list");
583 if (! HoistPredicateContext
) {
584 _gen(" 1 /* no context: prc is off */ ");
586 fatal_internal("pred tree context is empty");
592 /* MR10 - make AND just like OR */
594 if ( p
->expr
== PRED_AND_LIST
)
596 Predicate
*list
= p
->down
;
597 for (; list
!=NULL
; list
=list
->right
)
599 genCombinedPredTreeContextOrig(list
);
600 if ( list
->right
!=NULL
) _gen("|| /* MR10 was wrong */ ");
605 if ( p
->expr
== PRED_OR_LIST
)
607 Predicate
*list
= p
->down
;
608 for (; list
!=NULL
; list
=list
->right
)
610 genCombinedPredTreeContextOrig(list
);
611 if ( list
->right
!=NULL
) _gen("||");
616 fatal("pred tree is really wacked");
619 /* [genCombinedPredTreeContext] */
623 genCombinedPredTreeContext( Predicate
*p
)
625 genCombinedPredTreeContext( p
)
632 if (0 && ! MR_usingPredNames
&& ! MRhoisting
) {
633 genCombinedPredTreeContextOrig(p
);
635 /* MR13 */ MR_pred_depth(p
,&predDepth
);
636 /* MR13 */ if (predDepth
== 1) {
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) */ ");
644 /* MR13 */ _gen("(");
645 /* MR13 */ genExprSets(&scontext
[0], 1);
646 /* MR13 */ set_free(scontext
[1]);
647 /* MR13 */ _gen(")");
651 t
=MR_compute_pred_tree_context(p
);
653 _gen(" 1 /* MR12 no context (-prc off) */ ");
664 /* [genPredTreeGate] */
668 genPredTreeGate( Predicate
*p
, int in_and_expr
)
670 genPredTreeGate( p
, in_and_expr
)
678 genCombinedPredTreeContext(p
);
680 if ( p
->down
!=NULL
) _gen("\n");
685 genCombinedPredTreeContext(p
);
687 if ( p
->down
!=NULL
) _gen("\n");
692 void genPredEntry(Predicate
*p
,int outer
)
694 void genPredEntry(p
,outer
)
701 int localOuter
=outer
;
704 if (p
== NULL
) return;
706 if (p
->predEntry
!= NULL
&& p
->predEntry
->predLiteral
!= NULL
) {
707 if (p
->inverted
!= p
->predEntry
->pred
->inverted
) {
708 _gen("! /* inverted pred */ (");
711 if (!localOuter
) _gen("(");
714 dumpAction(p
->predEntry
->predLiteral
,output
,0,p
->source
->file
,p
->source
->line
,0);
715 if (needRP
) _gen(")");
719 inverted
=p
->inverted
;
722 _gen(" ! /* inverted pred */ (");
726 if (p
->expr
== PRED_OR_LIST
) {
727 if (!localOuter
) _gen("(");
728 for (q
=p
->down
; q
!= NULL
; q
=q
->right
) {
730 if (q
->right
!= NULL
) _gen(" || ");
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
) {
737 if (q
->right
!= NULL
) _gen(" && ");
739 if (!localOuter
) _gen(")");
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(")");
755 dumpPredAction(ActionNode
*anode
,
756 char *s
,FILE *output
,int tabs
,int file
,int line
,int final_newline
)
758 dumpPredAction(anode
,
759 s
,output
,tabs
,file
,line
,final_newline
)
770 PredEntry
*predEntry
=anode
->predEntry
;
771 int inverted
=anode
->inverted
;
774 if (predEntry
== NULL
) {
776 /* inline predicate literal */
778 require(inverted
== 0,"dumpPredAction action->inverted");
779 dumpAction(s
,output
,tabs
,file
,line
,final_newline
);
783 /* a reference to a predicate - possibly with an inverted source */
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(")");
790 workPred
=predicate_dup(predEntry
->pred
);
791 if (inverted
) workPred
->inverted
=!workPred
->inverted
;
792 genPredEntry(workPred
,1);
793 predicate_free(workPred
);
802 genPred(Predicate
*p
, Node
*j
,int suppress_sva
)
804 genPred(p
,j
,suppress_sva
)
810 if ( FoundException
&& !suppress_sva
) {_gen("(_sva=(");} /* MR11 suppress_sva */
812 if ( GenLineInfo
&& j
->file
!= -1 ) _gen("\n");
813 if (p
->source
!= NULL
&& p
->source
->ampersandPred
!= NULL
) {
814 if (p
->source
->ampersandPred
->k
== 1) {
819 ctx
[1]=set_dup(p
->source
->ampersandPred
->scontext
[1]);
822 genExprSets(&(ctx
[0]), p
->k
);
827 genExprTree(p
->source
->ampersandPred
->tcontext
,1);
832 dumpPredAction((ActionNode
*)p
->source
,
833 p
->expr
, output
, 0, -1 /*indicates no line info*/, j
->line
, 0);
835 if ( FoundException
&& !suppress_sva
) /* MR11 suppress_sva */
836 {_gen("),_sva)");} /* MR10 - get red of "meant ==" messages */
842 MR_distinctORcontextOpt(Predicate
*p
,Node
*j
,int in_and_expr
)
844 MR_distinctORcontextOpt(p
,j
,in_and_expr
)
852 _gen(" /* MR10 Distinct OR context optimization */ \n");
856 for (q
=p
->down
; q
!= NULL
; q
=q
->right
) {
858 genCombinedPredTreeContext(q
);
859 _gen(" && (zzpf=1, ");
866 "MR_distinctORcontextOpt: can't get here when using MR_predSimplify");
868 ** for (q
=p
->down
; q
!= NULL
; q
=q
->right
) {
870 ** genCombinedPredTreeContext(q
);
873 ** if (q
->right
!= NULL
) {
884 genPredTreeOrig( Predicate
*p
, Node
*j
, int in_and_expr
)
886 genPredTreeOrig( p
, j
, in_and_expr
)
893 /* MR10 */ int allHaveContext
=1;
894 /* MR10 */ int noneHaveContext
=1;
896 /* MR10 */ MR_predContextPresent(p
,&allHaveContext
,&noneHaveContext
);
898 if ( ! noneHaveContext
) /* MR10 context guards ignored when -prc off */
901 genPredTreeGate(p
, in_and_expr
);
904 /* if leaf node, just gen predicate */
909 if ( ! noneHaveContext
) _gen(")"); /* MR10 context guards ignored when -prc off */
913 /* if AND list, do both preds (only two possible) */
914 if ( p
->expr
== PRED_AND_LIST
)
918 ** genPredTreeOrig(p
->down
, j
, 1);
920 ** genPredTreeOrig(p
->down
->right
, j
, 1);
922 ** if ( ! noneHaveContext
) _gen(")"); /* MR10 context guards ignored when -prc off */
925 /* MR11 - make it work with AND with more than two children - like OR */
930 for (; list
!=NULL
; list
=list
->right
)
932 genPredTreeOrig(list
, j
, 1);
933 if ( list
->right
!=NULL
) _gen("&&");
936 if ( ! noneHaveContext
) _gen(")"); /* MR10 context guards ignored when -prc off */
940 if ( p
->expr
== PRED_OR_LIST
)
945 for (; list
!=NULL
; list
=list
->right
)
947 genPredTreeOrig(list
, j
, 0);
948 if ( list
->right
!=NULL
) _gen("||");
951 if ( ! noneHaveContext
) _gen(")"); /* MR10 context guards ignored when -prc off */
955 fatal_internal("genPredTreeOrig: predicate tree is wacked");
959 ** Predicate member dummyPredDepth is no longer used in MR10
960 ** but we might need it again in the future
963 ** if ( !noneHaveContext
&&
965 ** p
->source
!= NULL
&&
966 ** p
->source
->dummyPredicateDepth
> 0 &&
967 ** p
->down
== NULL
) {
969 ** genCombinedPredTreeContext(p
);
980 what to do if the context is wrong
981 what to do if the context is correct but the predicate is false
983 remember: if the context is wrong it's the same as if the
984 predicate is true as far as enabling an alternative
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
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.
1003 genPredTree( Predicate
*p
, Node
*j
, int in_and_expr
, int suppress_sva
)
1005 genPredTree( p
, j
, in_and_expr
, suppress_sva
)
1013 int allHaveContext
=1;
1014 int noneHaveContext
=1;
1018 int identicalORcontextOptimization
=0;
1019 int identicalANDcontextOptimization
=0;
1021 if (0 && !MR_usingPredNames
&& !MRhoisting
) {
1022 genPredTreeOrig(p
,j
,in_and_expr
);
1026 MR_predContextPresent(p
,&allHaveContext
,&noneHaveContext
);
1028 if ( ! noneHaveContext
) { /* MR10 context guards ignored when -prc off */
1032 /* MR10 optimize OR predicates which are all leaves */
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
)) {
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;
1051 MR_distinctORcontextOpt(p
,j
,in_and_expr
);
1054 } else if (p
->expr
== PRED_AND_LIST
&& MR_allPredLeaves(p
->down
)) {
1056 /* MR12 optimize AND predicates which are all leaves */
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
)) {
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;
1074 genPredTreeGate(p
, in_and_expr
);
1077 genPredTreeGate(p
, in_and_expr
);
1081 /* if leaf node, just gen predicate */
1083 if ( p
->down
==NULL
)
1085 genPred(p
,j
,suppress_sva
);
1086 if ( ! noneHaveContext
) _gen(")"); /* MR10 context guards ignored when -prc off */
1090 /* if AND list, do both preds (only two possible) */
1091 /* MR10 not any more ! */
1093 if ( p
->expr
== PRED_AND_LIST
)
1098 for (; list
!= NULL
; list
=list
->right
) {
1099 if (identicalANDcontextOptimization
) {
1100 genPred(list
, j
,suppress_sva
);
1102 genPredTree(list
, j
, 1, suppress_sva
); /* in and context */
1104 if ( list
->right
!=NULL
) _gen("&&");
1107 if ( ! noneHaveContext
) _gen(")"); /* MR10 context guards ignored when -prc off */
1111 if ( p
->expr
== PRED_OR_LIST
)
1116 for (; list
!=NULL
; list
=list
->right
)
1118 if (identicalORcontextOptimization
) {
1119 genPred(list
, j
,suppress_sva
);
1121 genPredTree(list
, j
, 0, suppress_sva
);
1123 if ( list
->right
!=NULL
) _gen("||");
1126 if ( ! noneHaveContext
) _gen(")"); /* MR10 context guards ignored when -prc off */
1130 fatal_internal("predicate tree is wacked");
1133 /* [genPredTreeMainXX] */
1135 Predicate
* /* MR10 */
1137 genPredTreeMainXX( Predicate
*p
, Node
*j
,int in_and_expr
)
1139 genPredTreeMainXX( p
, j
,in_and_expr
)
1146 int allHaveContext
=1;
1147 int noneHaveContext
=1;
1150 fprintf(stderr
,"Pred before\n");
1152 fprintf(stderr
,"\n");
1153 fprintf(stderr
,"Pred after\n");
1155 fprintf(stderr
,"\n");
1158 p
=MR_predSimplifyALL(p
); /* MR10 */
1160 require (MR_predicate_context_completed(p
),"predicate context is not complete");
1162 MR_cleanup_pred_trees(p
); /* MR10 */
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
);
1171 _gen("\n#if 0\n\n");
1175 genPredTree(p
,j
,in_and_expr
,0);
1179 Predicate
* /* MR10 */
1181 genPredTreeMain( Predicate
*p
, Node
*j
)
1183 genPredTreeMain( p
, j
)
1188 return genPredTreeMainXX(p
,j
,1);
1193 genExprTreeOriginal( Tree
*t
, int k
)
1195 genExprTreeOriginal( t
, k
)
1200 require(t
!=NULL
, "genExprTreeOriginal: NULL tree");
1202 if ( t
->token
== ALT
)
1204 _gen("("); genExprTreeOriginal(t
->down
, k
); _gen(")");
1205 if ( t
->right
!=NULL
)
1209 if ( on1line
> NumExprPerLine
) { on1line
=0; _gen("\n"); }
1210 _gen("("); genExprTreeOriginal(t
->right
, k
); _gen(")");
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
)
1222 if ( on1line
> NumExprPerLine
) { on1line
=0; _gen("\n"); }
1223 _gen("("); genExprTreeOriginal(t
->down
, k
+1); _gen(")");
1225 if ( t
->down
!=NULL
) _gen(")");
1226 if ( t
->right
!=NULL
)
1230 if ( on1line
> NumExprPerLine
) { on1line
=0; _gen("\n"); }
1231 _gen("("); genExprTreeOriginal(t
->right
, k
); _gen(")");
1236 static void MR_LAtokenString(int k
,int token
)
1238 static void MR_LAtokenString(k
,token
)
1245 ts
=TokenString(token
);
1247 _gen2(" LA(%d)==%d",k
,token
);
1249 _gen2(" LA(%d)==%s",k
,ts
);
1255 static int MR_countLeaves(Tree
*t
)
1257 static int MR_countLeaves(t
)
1261 if (t
== NULL
) return 0;
1262 if (t
->token
== ALT
) {
1263 return MR_countLeaves(t
->down
)+MR_countLeaves(t
->right
);
1265 return 1+MR_countLeaves(t
->down
)+MR_countLeaves(t
->right
);
1270 static void MR_genOneLine(Tree
*tree
,int k
)
1272 static void MR_genOneLine(tree
,k
)
1277 if (tree
== NULL
) return;
1278 if (tree
->token
== ALT
) {
1279 MR_genOneLine(tree
->down
,k
);
1281 MR_LAtokenString(k
,tree
->token
);
1282 if (tree
->down
!= NULL
&&
1283 tree
->down
->right
== NULL
) {
1285 MR_genOneLine(tree
->down
,k
+1);
1286 } else if (tree
->down
!= NULL
) {
1288 MR_genOneLine(tree
->down
,k
+1);
1292 if (tree
->right
!= NULL
) {
1294 MR_genOneLine(tree
->right
,k
);
1300 static int lastkonline
;
1303 static void MR_genMultiLine(Tree
*tree
,int k
)
1305 static void MR_genMultiLine(tree
,k
)
1312 if (tree
== NULL
) return;
1313 if (tree
->token
== ALT
) {
1314 MR_genMultiLine(tree
,k
);
1316 MR_LAtokenString(k
,tree
->token
);
1319 if (tree
->down
!= NULL
&& tree
->down
->right
== NULL
) {
1324 for (i
=0 ; i
< depth
+k
; i
++) _gen(" ");
1329 MR_genMultiLine(tree
->down
,k
+1);
1330 } else if (tree
->down
!= NULL
) {
1334 for (i
=0 ; i
< depth
+k
; i
++) _gen(" ");
1336 MR_genMultiLine(tree
->down
,k
+1);
1340 if (tree
->right
!= NULL
) {
1341 if (k
< lastkonline
) {
1345 for (i
=0; i
< depth
+k
-1 ; i
++) _gen(" ");
1347 } else if (across
> 3 ) {
1351 for (i
=0; i
< depth
+k
; i
++) _gen(" ");
1356 MR_genMultiLine(tree
->right
,k
);
1361 static void genExprTree(Tree
*tree
,int k
)
1363 static void genExprTree(tree
,k
)
1371 /* MR20 THM This was probably an error.
1372 The routine should probably reference that static
1373 "across" and this declaration hides it.
1379 require (tree
!= NULL
,"genExprTree: tree is NULL");
1380 require (k
> 0,"genExprTree: k <= 0");
1382 if (0 && !MRhoisting
) { /* MR11 make new version standard */
1383 genExprTreeOriginal(tree
,k
);
1385 count
=MR_countLeaves(tree
);
1387 MR_genOneLine(tree
,k
);
1393 MR_genMultiLine(tree
,k
);
1401 * Generate LL(k) type expressions of the form:
1403 * (LA(1) == T1 || LA(1) == T2 || ... || LA(1) == Tn) &&
1404 * (LA(2) == T1 || LA(2) == T2 || ... || LA(2) == Tn) &&
1406 * (LA(k) == T1 || LA(k) == T2 || ... || LA(k) == Tn)
1408 * If GenExprSetsOpt generate:
1410 * (setwdi[LA(1)]&(1<<j)) && (setwdi[LA(2)]&(1<<j)) ...
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.
1416 * This routine is visible only to this file and cannot answer a TRANS message.
1424 genExpr( Junction
*j
)
1432 /* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead
1437 if ( j
->ftree
!=NULL
) limit
= LL_k
;
1439 max_k
= genExprSets(j
->fset
, limit
);
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).
1446 if ( j
->ftree
!= NULL
)
1448 _gen(" && !("); genExprTree(j
->ftree
, 1); _gen(")");
1451 if ( ParseWithPredicates
&& j
->predicate
!=NULL
)
1453 Predicate
*p
= j
->predicate
;
1454 warn_about_using_gk_option();
1456 j
->predicate
=genPredTreeMain(p
, (Node
*)j
); /* MR10 */
1464 genExprSets( set
*fset
, int limit
)
1466 genExprSets( fset
, limit
)
1473 unsigned *e
, *g
, firstTime
=1;
1475 if (set_nil(fset
[1])) {
1476 _gen(" 0 /* MR13 empty set expression - undefined rule ? infinite left recursion ? */ ");
1480 if ( GenExprSetsOpt
)
1482 while ( k
<= limit
&& !set_nil(fset
[k
]) ) /* MR11 */
1484 if ( set_deg(fset
[k
])==1 ) /* too simple for a set? */
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
));
1496 _gen3("(setwd%d[LA(%d)]&0x%x)", wordnum
, k
, 1<<setnum
);
1498 if ( k
>max_k
) max_k
= k
;
1499 if ( k
== CLL_k
) break;
1501 if ( k
<=limit
&& !set_nil(fset
[k
]) ) _gen(" && "); /* MR11 */
1503 if ( on1line
> NumExprPerLine
) { on1line
=0; _gen("\n"); }
1508 while ( k
<= limit
&& !set_nil(fset
[k
]) ) /* MR11 */
1510 if ( (e
=g
=set_pdq(fset
[k
])) == NULL
) fatal_internal("genExpr: cannot allocate IF expr pdq set");
1511 for (; *e
!=nil
; e
++)
1513 if ( !firstTime
) _gen(" || ") else { _gen("("); firstTime
= 0; }
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
));
1522 if ( k
>max_k
) max_k
= k
;
1523 if ( k
== CLL_k
) break;
1525 if ( k
<= limit
&& !set_nil(fset
[k
]) ) { firstTime
=1; _gen(" && "); } /* MR11 */
1527 if ( on1line
> NumExprPerLine
) { on1line
=0; _gen("\n"); }
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.
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.
1542 genBlk( Junction
*q
, int jtype
, int *max_k
, int *need_right_curly
, int * lastAltEmpty
/* MR23 */)
1544 genBlk( q
, jtype
, max_k
, need_right_curly
, lastAltEmpty
/* MR23 */)
1548 int *need_right_curly
;
1549 int *lastAltEmpty
; /* MR23 */
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 */
1561 if (first_item_is_guess_block((Junction
*)q
->p1
)!=NULL
)
1563 if (jtype
!= aLoopBlk
&& jtype
!= aOptBlk
&& jtype
!= aPlusBlk
) {
1564 warnFL("(...)? as only alternative of block is unnecessary", FileStr
[q
->file
], q
->line
);
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
)++;
1571 return empty
; /* no decision to be made-->no error set */
1574 f
= First(q
, 1, jtype
, max_k
);
1575 for (alt
=q
; alt
!= NULL
; alt
= (Junction
*) alt
->p2
)
1577 if ( alt
->p2
== NULL
) /* chk for empty alt */
1580 if ( p
->ntype
== nJunction
)
1582 /* we have empty alt */
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:
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.
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.
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");
1611 /* MR28 */ if (jtype
== aPlusBlk
) {
1616 } /* end of for loop on alt */
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
);
1626 if ( alt
!= q
) gen("else ")
1629 if ( DemandLookahead
) {
1630 if ( !GenCC
) {gen1("LOOK(%d);\n", *max_k
);}
1631 else gen1("look(%d);\n", *max_k
);
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");
1644 if ( first_item_is_guess_block((Junction
*)alt
->p1
)!=NULL
)
1646 a_guess_in_block
= 1;
1650 if ( first_item_is_guess_block((Junction
*)alt
->p1
)!=NULL
) _gen("!zzrv && ");
1658 /* MR10 */ if (alt
->p2
== NULL
) {
1659 /* MR10 */ if (first_item_is_guess_block(alt
)) {
1660 /* MR10 */ gen("/* MR10 */ else {\n");
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");
1674 has_guess_block_as_first_item( Junction
*q
)
1676 has_guess_block_as_first_item( q
)
1682 for (alt
=q
; alt
!= NULL
; alt
= (Junction
*) alt
->p2
)
1684 if ( first_item_is_guess_block((Junction
*)alt
->p1
)!=NULL
) return 1;
1691 has_guess_block_as_last_item( Junction
*q
)
1693 has_guess_block_as_last_item( q
)
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
;
1704 /* MR30 See description of first_item_is_guess_block for background */
1708 first_item_is_guess_block_extra(Junction
*q
)
1710 first_item_is_guess_block_extra(q
)
1715 ( ( q
->ntype
==nAction
) ||
1716 ( q
->ntype
==nJunction
&&
1717 (q
->jtype
==Generic
|| q
->jtype
== aLoopBlk
)
1722 if ( q
->ntype
==nJunction
) q
= (Junction
*)q
->p1
;
1723 else q
= (Junction
*) ((ActionNode
*)q
)->next
;
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
;
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.
1740 first_item_is_guess_block( Junction
*q
)
1742 first_item_is_guess_block( q
)
1746 Junction
* qOriginal
= q
; /* DEBUG */
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.
1752 MR14a Added extra parentheses to clarify precedence
1754 MR30 This appears to have been a mistake. The First set was then
1755 computed incorrectly for:
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.
1768 loopBegin loopBlk subBlk/guess A G EB G B EB EB EB ER
1771 | +-> G C G ----------------------+ |
1773 +--- G G G -------------------------------------+
1775 Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu).
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.
1794 ( ( q
->ntype
==nAction
) ||
1795 ( q
->ntype
==nJunction
&&
1796 (q
->jtype
==Generic
/*** || q->jtype == aLoopBlk ***/ ) /*** MR30 Undo MR14 change ***/
1801 if ( q
->ntype
==nJunction
) q
= (Junction
*)q
->p1
;
1802 else q
= (Junction
*) ((ActionNode
*)q
)->next
;
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
;
1814 /* MR1 10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs */
1817 #define STRINGIZEBUFSIZE 1024
1819 static char stringizeBuf
[STRINGIZEBUFSIZE
];
1833 stop
=&stringizeBuf
[1015];
1839 } else if (*s
== '\n') {
1844 } else if (*s
== '\\') {
1847 } else if (*s
== '\"') {
1853 } else if (*s
== '\n') {
1856 } else if (*s
== '\\') {
1859 } else if (*s
== '\"') {
1867 } else if (*s
== '\'') {
1872 } else if (*s
== '\'') {
1875 } else if (*s
== '\\') {
1878 } else if (*s
== '\"') {
1898 return stringizeBuf
;
1902 int isNullAction(char *s
)
1909 for (p
=s
; *p
!= '\0' ; p
++) {
1910 if (*p
!= ';' && *p
!=' ') return 0;
1915 /* MR1 End of Routine to stringize code for failed predicates msgs */
1918 /* Generate an action. Don't if action is NULL which means that it was already
1919 * handled as an init action.
1923 genAction( ActionNode
*p
)
1929 require(p
!=NULL
, "genAction: invalid node and/or rule");
1930 require(p
->ntype
==nAction
, "genAction: not action");
1932 if ( !p
->done
) /* MR10 */ /* MR11 */
1934 if ( p
->is_predicate
)
1936 if ( p
->guardpred
!= NULL
)
1938 Predicate
*guardDup
=predicate_dup(p
->guardpred
); /* MR10 */
1940 guardDup
=genPredTreeMain(guardDup
, (Node
*)p
);
1941 predicate_free(guardDup
);
1943 /* MR10 */ else if (p
->ampersandPred
!= NULL
) {
1944 /* MR10 */ gen("if (!");
1945 /* MR10 */ p
->ampersandPred
=genPredTreeMain(p
->ampersandPred
, (Node
*)p
);
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);
1956 /* MR23 Change failed predicate macro to have three arguments:
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
1963 This gives the user more control of the error action.
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 */
1974 else /* not a predicate */
1976 if (! isNullAction(p
->action
) && !p
->noHoist
) {
1977 if ( FoundGuessBlk
) {
1979 gen("if ( !guessing ) {\n");
1981 gen("zzNON_GUESS_MODE {\n");
1984 dumpActionPlus(p
, p
->action
, output
, tabs
, p
->file
, p
->line
, 1); /* MR21 */
1985 if ( FoundGuessBlk
) gen("}\n");
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).
1996 * if ! modifies rule-ref, then never link it in and never pass zzSTR.
1997 * Always pass address of temp root ptr.
2001 genRuleRef( RuleRefNode
*p
)
2008 char *handler_id
= "";
2010 char *parm
= "", *exsig
= "";
2012 int genRuleRef_emittedGuessGuard
=0; /* MR10 */
2014 require(p
!=NULL
, "genRuleRef: invalid node and/or rule");
2015 require(p
->ntype
==nRuleRef
, "genRuleRef: not rule reference");
2017 if ( p
->altstart
!=NULL
&& p
->altstart
->exception_label
!=NULL
)
2018 handler_id
= p
->altstart
->exception_label
;
2020 r
= (RuleEntry
*) hash_get(Rname
, p
->text
);
2023 warnFL( eMsg1("rule %s not defined",
2024 p
->text
), FileStr
[p
->file
], p
->line
);
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 */
2032 q
= RulePtr
[r
->rulenum
]; /* find definition of ref'd rule */ /* MR8 */
2034 r2
= (RuleEntry
*) hash_get(Rname
, p
->rname
);
2035 if ( r2
== NULL
) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}
2037 OutLineInfo(output
,p
->line
,FileStr
[p
->file
]);
2039 if ( GenCC
&& GenAST
) {
2040 gen("_ast = NULL;\n");
2043 if ( FoundGuessBlk
&& p
->assign
!=NULL
&& q
->ret
!= NULL
) { /* MR8 */
2045 gen("if ( !guessing ) {\n");
2047 gen("zzNON_GUESS_MODE {\n");
2050 genRuleRef_emittedGuessGuard
=1; /* MR11 */
2053 if ( FoundException
) exsig
= "&_signal";
2059 /**** if ( r2->noAST || p->astnode==ASTexclude )
2062 /**** _gen("_ast = NULL;\n");
2066 /*** we always want to set just a pointer now, then set correct
2071 (_tail==NULL)?(&_sibling):(&(_tail->_right));\n");
2077 if ( r2
->noAST
|| p
->astnode
==ASTexclude
)
2079 _gen("_ast = NULL; ");
2082 else parm
= "zzSTR";
2084 if ( p
->assign
!=NULL
&& q
->ret
!=NULL
) /* MR8 */
2086 if ( !hasMultipleOperands(p
->assign
) ) {_gen1("%s = ",p
->assign
);} /* MR23 */
2087 else _gen1("{ struct _rv%d _trv; _trv = ", r
->rulenum
);
2089 if ( FoundException
) {
2090 _gen5("%s%s(%s,&_signal%s%s); ",
2094 (p
->parms
!=NULL
)?",":"",
2095 (p
->parms
!=NULL
)?p
->parms
:"");
2096 if ( p
->ex_group
!=NULL
) {
2098 gen("if (_signal) {\n");
2100 dumpException(p
->ex_group
, 0);
2105 _gen1("if (_signal) goto %s_handler;", handler_id
);
2109 _gen5("%s%s(%s%s%s);",
2113 (p
->parms
!=NULL
)?",":"",
2114 (p
->parms
!=NULL
)?p
->parms
:"");
2116 if ( GenCC
&& (r2
->noAST
|| p
->astnode
==ASTexclude
) )
2118 /* rule has a ! or element does */
2119 /* still need to assign to #i so we can play with it */
2121 gen2("_ast%d%d = (AST *)_ast;", BlkLevel
-1, p
->elnum
);
2123 else if ( !r2
->noAST
&& p
->astnode
== ASTinclude
)
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");
2134 gen("if ( _tail==NULL ) _sibling = _ast; else _tail->setRight(_ast);\n");
2135 gen2("_ast%d%d = (AST *)_ast;\n", BlkLevel
-1, p
->elnum
);
2140 _gen("ASTBase::"); }
2142 _gen("link(_root, &_sibling, &_tail);");
2144 /* MR10 */ if (FoundGuessBlk
&& !genRuleRef_emittedGuessGuard
) { /* MR10 */
2145 /* MR10 */ _gen("\n");
2147 /* MR10 */ if (GenCC
) gen ("}; /* MR10 */")
2148 /* MR10 */ else gen ("}; /* MR10 */");
2154 if ( p
->assign
!=NULL
&& q
->ret
!=NULL
) /* MR8 */
2156 if ( !hasMultipleOperands(p
->assign
) ) {_gen1("%s = ",p
->assign
);} /* MR23 */
2157 else _gen1("{ struct _rv%d _trv; _trv = ", r
->rulenum
);
2159 if ( FoundException
) {
2160 _gen4("%s%s(&_signal%s%s); ",
2163 (p
->parms
!=NULL
)?",":"",
2164 (p
->parms
!=NULL
)?p
->parms
:"");
2165 if ( p
->ex_group
!=NULL
) {
2167 gen("if (_signal) {\n");
2169 dumpException(p
->ex_group
, 0);
2174 _gen1("if (_signal) goto %s_handler;", handler_id
);
2181 (p
->parms
!=NULL
)?p
->parms
:"");
2183 if ( p
->assign
!=NULL
&& q
->ret
!=NULL
) _gen("\n"); /* MR8 */
2186 if ( p
->assign
!=NULL
&& q
->ret
!=NULL
) { /* MR8 */
2187 if ( hasMultipleOperands(p
->assign
) ) /* MR23 */
2190 dumpRetValAssign(p
->assign
, q
->ret
, p
); /* MR30 */
2196 /* Handle element labels now */
2197 if ( p
->el_label
!=NULL
)
2202 gen3("%s_ast = _ast%d%d;\n", p
->el_label
, BlkLevel
-1, p
->elnum
);
2204 else {gen1("%s_ast = zzastCur;\n", p
->el_label
);}
2207 gen1("%s = zzaCur;\n", p
->el_label
);
2211 if ( FoundGuessBlk
&& p
->assign
!=NULL
&& q
->ret
!=NULL
) { /* MR8 */
2212 /* in guessing mode, don't branch to handler upon error */
2216 if ( FoundException
) {
2217 gen6("%s%s(%s%s&_signal%s%s);\n",
2221 (*parm
!='\0')?",":"",
2222 (p
->parms
!=NULL
)?",":"",
2223 (p
->parms
!=NULL
)?p
->parms
:"");
2226 gen5("%s%s(%s%s%s);\n",
2230 (p
->parms
!=NULL
&& *parm
!='\0')?",":"",
2231 (p
->parms
!=NULL
)?p
->parms
:"");
2240 * Generate code to match a token.
2242 * Getting the next token is tricky. We want to ensure that any action
2243 * following a token is executed before the next GetToken();
2247 genToken( TokNode
*p
)
2254 char *handler_id
= "";
2257 char *set_nameErrSet
;
2259 int ast_label_in_action
= 0; /* MR27 */
2260 int pushedCmodeAST
= 0; /* MR27 */
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
;
2267 r
= (RuleEntry
*) hash_get(Rname
, p
->rname
);
2268 if ( r
== NULL
) {warnNoFL("Rule hash table is screwed up beyond belief"); return;}
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
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
);
2280 OutLineInfo(output
,p
->line
,FileStr
[p
->file
]);
2282 if ( !set_nil(p
->tset
) ) /* implies '.', ~Tok, or tokenclass */
2285 unsigned eErrSet
= 0;
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
;
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 */
2305 sprintf(buf
, "%s_set", TokenString(p
->token
));
2306 sprintf(bufErrSet
, "%s_errset", TokenString(p
->token
)); /* MR23 */
2308 set_nameErrSet
= bufErrSet
; /* MR23 */
2311 /* MR23 - Forgot about the case of ~TOKCLASS. */
2313 else if ( p
->tclass
!=NULL
&& complement
!= 0 /* MR23 */)
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
;
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 */
2328 sprintf(buf
, "%s_setbar", TokenString(p
->token
));
2329 sprintf(bufErrSet
, "%s_errsetbar", TokenString(p
->token
)); /* MR23 */
2331 set_nameErrSet
= bufErrSet
; /* MR23 */
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
);
2343 set_nameErrSet
= bufErrSet
;
2346 if ( !FoundException
) {
2347 /* MR23 */ gen2("zzsetmatch(%s, %s);", set_name
, set_nameErrSet
);
2349 else if ( p
->ex_group
==NULL
) {
2350 if ( p
->use_def_MT_handler
)
2351 gen3("zzsetmatch_wdfltsig(%s,(ANTLRTokenType)%d,%s);",
2356 gen2("zzsetmatch_wsig(%s, %s_handler);",
2362 gen1("if ( !_setmatch_wsig(%s) ) {\n", set_name
);
2364 /* MR6 */ if (FoundGuessBlk
) {
2365 /* MR6 */ if ( GenCC
) {gen("if ( guessing ) goto fail;\n");}
2366 /* MR6 */ else gen("if ( zzguessing ) goto fail;\n");
2368 gen("_signal=MismatchedToken;\n");
2369 dumpException(p
->ex_group
, 0);
2376 else if ( TokenString(p
->token
)!=NULL
)
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
)
2383 gen2("zzmatch_wsig(%s, %s_handler);",
2384 TokenString(p
->token
),
2389 /* MR6 */ if (GenCC
) {
2390 /* MR6 */ gen1("if ( !_match_wsig(%s) ) {\n", TokenString(p
->token
));
2392 /* MR6 */ gen1("if ( !_zzmatch_wsig(%s) ) {\n", TokenString(p
->token
));
2395 /* MR6 */ if (FoundGuessBlk
) {
2396 /* MR6 */ if ( GenCC
) {gen("if ( guessing ) goto fail;\n");}
2397 /* MR6 */ else gen("if ( zzguessing ) goto fail;\n");
2399 gen("_signal=MismatchedToken;\n");
2400 dumpException(p
->ex_group
, 0);
2405 else gen1("zzmatch(%s);", TokenString(p
->token
));
2408 if ( FoundException
) {
2409 if ( p
->use_def_MT_handler
)
2410 gen2("zzmatch_wdfltsig((ANTLRTokenType)%d,%s);",
2411 p
->token
,tokenFollowSet(p
))
2413 gen2("zzmatch_wsig(%d,%s_handler);",p
->token
,handler_id
);
2415 else {gen1("zzmatch(%d);", p
->token
);}
2418 a
= findImmedAction( p
->next
);
2419 /* generate the token labels */
2420 if ( GenCC
&& p
->elnum
>0 )
2422 /* If building trees in C++, always gen the LT() assigns */
2423 if ( set_el(p
->elnum
, tokensRefdInBlock
) || GenAST
)
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
);
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");
2435 /* MR10 */ _gen2(" _t%d%d = (ANTLRTokenPtr)LT(1);", BlkLevel
-1, p
->elnum
);
2441 * MR23 labase is never used in the C++ runtime library.
2442 * and this code is generated only in C++ mode
2445 /*** if ( LL_k>1 ) / * MR23 disabled */
2446 /*** if ( !DemandLookahead ) _gen(" labase++;"); / * MR23 disabled */
2447 /*** _gen("\n"); / * MR23 disabled */
2448 /*** tab(); / * MR23 disabled */
2452 if ( FoundGuessBlk
&&
2453 (ast_label_in_action
|| !(p
->astnode
== ASTexclude
|| r
->noAST
)) )
2455 if ( GenCC
) {_gen("if ( !guessing ) {\n"); tab();}
2456 else {_gen("zzNON_GUESS_MODE {\n"); tab();}
2459 /* MR27 addition when labels referenced when operator ! used */
2461 pushedCmodeAST
= 0; /* MR27 */
2462 if (ast_label_in_action
&& (p
->astnode
== ASTexclude
|| r
->noAST
)) {
2465 /* MR13 */ if (NewAST
) {
2466 /* MR13 */ gen4("_ast%d%d = newAST(_t%d%d); /* MR27 */\n", BlkLevel
-1, p
->elnum
, BlkLevel
-1, p
->elnum
);
2468 /* MR13 */ gen4("_ast%d%d = new AST(_t%d%d); /* MR27 */\n", BlkLevel
-1, p
->elnum
, BlkLevel
-1, p
->elnum
);
2473 gen("zzastPush(zzmk_ast(zzastnew(),zzaCur)); /* MR27 */");
2477 /* end MR27 addition for labels referenced when operator ! used */
2481 if (GenCC
&& !(p
->astnode
== ASTexclude
) ) {
2483 /* MR13 */ if (NewAST
) {
2484 /* MR13 */ gen4("_ast%d%d = newAST(_t%d%d);\n", BlkLevel
-1, p
->elnum
, BlkLevel
-1, p
->elnum
);
2486 /* MR13 */ gen4("_ast%d%d = new AST(_t%d%d);\n", BlkLevel
-1, p
->elnum
, BlkLevel
-1, p
->elnum
);
2490 if ( GenCC
&& !(p
->astnode
== ASTexclude
) )
2491 {_gen2("_ast%d%d->", BlkLevel
-1, p
->elnum
);}
2493 if ( p
->astnode
==ASTchild
) {
2494 if ( !GenCC
) _gen("zz");
2495 _gen("subchild(_root, &_sibling, &_tail);");
2497 else if ( p
->astnode
==ASTroot
) {
2498 if ( !GenCC
) _gen("zz");
2499 _gen("subroot(_root, &_sibling, &_tail);");
2501 if ( GenCC
&& !(p
->astnode
== ASTexclude
) ) {
2506 else if ( !GenCC
) {
2507 if (! pushedCmodeAST
) _gen(" zzastDPush;");
2509 if ( FoundGuessBlk
&&
2510 (ast_label_in_action
|| !(p
->astnode
== ASTexclude
|| r
->noAST
)) )
2511 {gen("}\n"); tab();}
2514 /* Handle element labels now */
2515 if ( p
->el_label
!=NULL
)
2517 int done_NON_GUESSMODE
=0;
2521 /* MR10 */ /* do Attrib / Token ptr for token label used in semantic pred */
2522 /* MR10 */ /* for these cases do assign even in guess mode */
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
);
2529 /* MR10 */ gen1("%s = (ANTLRTokenPtr)LT(1);\n", p
->el_label
);
2532 /* MR10 */ gen1("%s = zzaCur;", p
->el_label
);
2534 /* MR10 */ if (FoundGuessBlk
) _gen(" /* MR10 */");
2535 /* MR10 */ _gen("\n");
2538 /* Do Attrib / Token ptr */
2540 /* MR10 */ if (! p
->label_used_in_semantic_pred
) {
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();}
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
);
2554 /* MR10 */ gen1("%s = (ANTLRTokenPtr)LT(1);\n", p
->el_label
);
2557 /* MR10 */ gen1("%s = zzaCur;\n", p
->el_label
);
2563 if (GenAST
&& (ast_label_in_action
|| !(p
->astnode
== ASTexclude
|| r
->noAST
) )) /* MR27 */
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();}
2575 gen3("%s_ast = _ast%d%d;\n", p
->el_label
, BlkLevel
-1, p
->elnum
);
2577 else {gen1("%s_ast = zzastCur;\n", p
->el_label
);}
2580 /* MR10 */ if (done_NON_GUESSMODE
) {
2581 /* MR10 */ gen("}\n"); tab();
2586 /* Handle any actions immediately following action */
2587 if ( a
!= NULL
) /* MR10 */ /* MR11 */
2589 /* delay next token fetch until after action */
2591 if ( a
->is_predicate
)
2594 /* Disabled in MR30 ************************************************************
2595 And moved into genAction
2596 *****************************************************************************
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);
2605 /* MR23 Change failed predicate macro to have three arguments:
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
2612 This gives the user more control of the error action.
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 */
2623 /* Disabled in MR30 ************************************************************
2624 And moved into genAction
2625 *****************************************************************************
2629 else /* MR9 a regular action - not a predicate action */
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
2639 /* MR23 */ if (GenCC
) {
2640 /* MR23 */ if (strstr(a
->action
, "LT(") != NULL
) LTinTokenAction
= 1;
2643 /* MR23 */ if (strstr(a
->action
, "LA(") != NULL
) LTinTokenAction
= 1;
2644 /* MR23 */ if (strstr(a
->action
, "LATEXT(") != NULL
) LTinTokenAction
= 1;
2647 if ( FoundGuessBlk
) {
2648 if ( GenCC
) {gen("if ( !guessing ) {\n");}
2649 else gen("zzNON_GUESS_MODE {\n");
2651 dumpActionPlus(a
, a
->action
, output
, tabs
, a
->file
, a
->line
, 1); /* MR21 */
2652 if ( FoundGuessBlk
) gen("}\n");
2653 a
->done
= 1; /* MR30 */
2655 /*** a->done = 1; MR30 Moved up into then branch for true actions, but not predicates ***/
2656 if ( !DemandLookahead
) {
2658 if ( FoundException
&& p
->use_def_MT_handler
) gen("if (!_signal)");
2660 if ( FoundException
&& p
->use_def_MT_handler
)
2661 _gen(" _signal=NoSignal;");
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;");
2673 if (a
->done
) { /* MR30 */
2674 TRANS( a
->next
); /* MR30 */
2677 TRANS( p
->next
); /* MR30 */
2682 if ( !DemandLookahead
) {
2684 if (FoundException
&& p
->use_def_MT_handler
) _gen("if (!_signal)");
2686 if (FoundException
&&p
->use_def_MT_handler
) _gen(" _signal=NoSignal;");
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;");
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:
2709 * becomes (internally):
2713 * The code for genOptBlk is now identical to genSubBlk except for
2719 genOptBlk( Junction
*q
)
2727 int need_right_curly
;
2729 int lastAltEmpty
; /* MR23 */
2730 savetkref
= tokensRefdInBlock
;
2731 require(q
->ntype
== nJunction
, "genOptBlk: not junction");
2732 require(q
->jtype
== aOptBlk
, "genOptBlk: not opt block");
2734 OutLineInfo(output
,q
->line
,FileStr
[q
->file
]);
2737 BlockPreambleOption(q
,q
->pFirstSetSymbol
); /* MR21 */
2738 f
= genBlk(q
, aOptBlk
, &max_k
, &need_right_curly
, &lastAltEmpty
/* MR23 */);
2740 Bypass error clause generation when exceptions are used in {...} block
2741 See multi-line note in genBlk near call to isEmptyAlt.
2743 if (! FoundException
) {
2744 if ( q
->p2
!= NULL
) {tab(); makeErrorClause(q
,f
,max_k
,0 /* use plus block bypass ? */ );}
2747 gen("/* MR23 skip error clause for {...} when exceptions in use */\n");
2749 { int i
; for (i
=1; i
<=need_right_curly
; i
++) {tabs
--; gen("}\n");} }
2756 gen("zzGUESS_DONE\n");
2759 /* must duplicate if (alpha)?; one guesses (validates), the
2760 * second pass matches */
2761 if ( q
->guess
&& analysis_point(q
)==q
)
2763 OutLineInfo(output
,q
->line
,FileStr
[q
->file
]);
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");} }
2774 tokensRefdInBlock
= savetkref
;
2775 if (q
->end
->p1
!= NULL
) TRANS(q
->end
->p1
);
2779 * Generate code for a loop blk of form:
2787 genLoopBlk( Junction
*begin
, Junction
*q
, Junction
*start
, int max_k
)
2789 genLoopBlk( begin
, q
, start
, max_k
)
2792 Junction
*start
; /* where to start generating code from */
2797 int need_right_curly
;
2799 Junction
*guessBlock
; /* MR10 */
2800 int singleAlt
; /* MR10 */
2801 int lastAltEmpty
; /* MR23 */
2803 savetkref
= tokensRefdInBlock
;
2804 require(q
->ntype
== nJunction
, "genLoopBlk: not junction");
2805 require(q
->jtype
== aLoopBlk
, "genLoopBlk: not loop block");
2807 if ( q
->visited
) return;
2810 /* first_item_is_guess_block doesn't care what kind of node it is */
2812 guessBlock
=first_item_is_guess_block( (Junction
*) q
->p1
); /* MR10 */
2813 singleAlt
=q
->p2
==NULL
; /* MR10 */
2815 if (singleAlt
&& !guessBlock
) /* MR10 */ /* only one alternative? */
2817 if ( DemandLookahead
) {
2818 if ( !GenCC
) {gen1("LOOK(%d);\n", max_k
);}
2819 else gen1("look(%d);\n", max_k
);
2822 if ( begin
!=NULL
) genExpr(begin
);
2824 /* if no predicates have been hoisted for this single alt (..)*
2827 require(MR_PredRuleRefStack
.count
== 0,"PredRuleRef stack not empty");
2828 if ( ParseWithPredicates
&& begin
->predicate
==NULL
)
2830 Predicate
*a
= MR_find_predicates_and_supp((Node
*)q
->p1
);
2831 require(MR_PredRuleRefStack
.count
== 0,"PredRuleRef stack not empty");
2836 a
=genPredTreeMain(a
, (Node
*)q
); /* MR10 */
2838 /* MR10 */ if (MRhoisting
) {
2839 /* MR10 */ predicate_free(a
);
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
);
2854 tokensRefdInBlock
= savetkref
;
2857 gen("for (;;) {\n"); /* MR20 G. Hobbelt */
2860 /* MR6 "begin" can never be null when called from genLoopBegin */
2861 /* MR6 because q==(Junction *)begin->p1 and we know q is valid */
2863 /* MR6 from genLoopBegin: */
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 ); */
2871 if ( DemandLookahead
)
2873 if ( !GenCC
) {gen1("LOOK(%d);\n", max_k
);}
2874 else gen1("look(%d);\n", max_k
);
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).
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.
2888 *** genExpr((Junction *)begin->p2);
2891 genExpr((Junction
*)begin
);
2892 _gen(")) break;\n");
2896 /* generate code for terminating loop (this is optional branch) */
2898 f
= genBlk(q
, aLoopBlk
, &max_k
, &need_right_curly
, &lastAltEmpty
/* MR23 */);
2902 /* generate code for terminating loop (this is optional branch) */
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 */
2916 /* MR6 */ if ( begin
==NULL
) {
2917 /* MR6 */ /* code for exiting loop "for sure" */
2918 /* MR6 */ gen("/* Suppressed by MR6 */ /*** else break; ***/\n");
2921 /* MR10 */if (singleAlt
&& guessBlock
) {
2923 /* MR6 */ gen("} else break; /* MR6 code for exiting loop \"for sure\" */\n");
2924 /* MR10 */ need_right_curly
--;
2926 /* MR6 */ gen("else break; /* MR6 code for exiting loop \"for sure\" */\n");
2929 { int i
; for (i
=1; i
<=need_right_curly
; i
++) {tabs
--; gen("}\n");} }
2930 if ( !GenCC
) gen1("zzLOOP(zztasp%d);\n", BlkLevel
-1);
2934 tokensRefdInBlock
= savetkref
;
2938 * Generate code for a loop blk of form:
2942 * --o-->o-->o-G-o-->o--
2947 * q->end points to the last node (far right) in the blk.
2949 * Note that q->end->jtype must be 'EndBlk'.
2951 * Generate code roughly of the following form:
2954 * ... code for alternatives ...
2955 * } while ( First Set of aLoopBlk );
2957 * OR if > 1 alternative
2960 * ... code for alternatives ...
2966 genLoopBegin( Junction
*q
)
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");
2982 OutLineInfo(output
,q
->line
,FileStr
[q
->file
]);
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
);
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
]);
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");
3009 /* MR21 */ _gen("/* nothing */ }\n");
3011 /* MR21 */ makeErrorClause(q
,f
,1,0 /* use plus block bypass ? */ ); /* frees set */
3014 if (q
->end
->p1
!= NULL
) TRANS(q
->end
->p1
);
3018 * Generate code for a loop blk of form:
3024 * q->end points to the last node (far right) in the blk.
3025 * Note that q->end->jtype must be 'EndBlk'.
3027 * Generate code roughly of the following form:
3030 * ... code for alternatives ...
3031 * } while ( First Set of aPlusBlk );
3033 * OR if > 1 alternative
3036 * ... code for alternatives ...
3037 * else if not 1st time through, break;
3042 genPlusBlk( Junction
*q
)
3050 int need_right_curly
;
3051 int lastAltEmpty
; /* MR23 */
3053 Junction
*guessBlock
; /* MR10 */
3054 int singleAlt
; /* MR10 */
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");
3062 if ( q
->visited
) return;
3064 OutLineInfo(output
,q
->line
,FileStr
[q
->file
]);
3068 BlockPreambleOption((Junction
*)q
, q
->pFirstSetSymbol
); /* MR21 */
3070 /* first_item_is_guess_block doesn't care what kind of node it is */
3072 guessBlock
=first_item_is_guess_block( (Junction
*)q
->p1
); /* MR10 */
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.
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
3085 singleAlt
=( ( (Junction
*) q
->p2
)->p2
== NULL
) &&
3086 ( ( (Junction
*) q
->p2
)->ignore
); /* only one alternative? */
3088 if (singleAlt
&& !guessBlock
) /* MR10 */
3092 /* if the only alt has a semantic predicate, hoist it; must test before
3095 if ( ParseWithPredicates
)
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");
3103 a
=genPredTreeMain(a
, (Node
*)q
); /* MR10 */
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
);
3118 if ( q
->parm
!=NULL
&& q
->predparm
) _gen1("(%s) && ", q
->parm
);
3120 if ( ParseWithPredicates
&& a
!=NULL
)
3122 if (! MR_comparePredicates(q
->predicate
,a
)) {
3124 a
=genPredTreeMain(a
, (Node
*)q
); /* MR10 */
3128 if ( ParseWithPredicates
&& a
!=NULL
) gen("}\n");
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");
3145 /* MR21 */ _gen("/* nothing */ }\n");
3147 /* MR21 */ makeErrorClause(q
,f
,1,1 /* use plus block bypass ? */ ); /* frees set */
3150 if (q
->end
->p1
!= NULL
) TRANS(q
->end
->p1
);
3151 /* MR10 */ if (MRhoisting
) {
3152 /* MR10 */ predicate_free(a
);
3158 f
= genBlk(q
, aPlusBlk
, &max_k
, &need_right_curly
, &lastAltEmpty
/* MR23 */);
3160 /* MR6 Sinan Karasu (sinan@tardis.ds.boeing.com) */
3161 /* MR6 Failed to turn off guess mode when leaving block */
3163 /* MR6 */ if ( has_guess_block_as_last_item(q
) ) {
3164 /* MR10 */ gen("/* MR10 ()+ */ else {\n");
3166 /* MR10 */ need_right_curly
++;
3167 /* MR10 */ gen("/* MR10 ()+ */ if ( !zzrv ) zzGUESS_DONE;\n");
3168 /* MR6 */ gen("/* MR10 ()+ */ if ( zzcnt > 1 ) break;\n");
3170 /* MR10 */ gen("/* MR10 ()+ */ else {\n");
3172 /* MR10 */ need_right_curly
++;
3173 /* MR10 */ gen("if ( zzcnt > 1 ) break;\n");
3176 /* MR21 */ if (MR_BlkErr
&& 1 >= max_k
) {
3178 /* MR21 */ f
= ComputeErrorSet(q
,1,0 /* use plus block bypass ? */ );
3181 /* MR21 */ makeErrorClause(q
,f
,1,0 /* use plus block bypass ? */ ); /* frees set */
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 */
3192 { int i
; for (i
=1; i
<=need_right_curly
; i
++) {tabs
--; gen("}\n");} }
3195 if ( !GenCC
) _gen1(" zzLOOP(zztasp%d);", BlkLevel
-1);
3197 if ( DemandLookahead
) {
3198 if ( !GenCC
) {gen1("LOOK(%d);\n", max_k
);}
3199 else gen1("look(%d);\n", max_k
);
3202 if ( q
->parm
!=NULL
&& q
->predparm
) {gen1("} while (%s);\n", q
->parm
);}
3203 else gen("} while ( 1 );\n");
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");
3218 /* MR21 */ _gen("/* nothing */ }\n");
3220 /* MR21 */ makeErrorClause(q
,f
,1,1 /* use plus block bypass ? */ ); /* frees set */
3223 if (q
->end
->p1
!= NULL
) TRANS(q
->end
->p1
);
3227 * Generate code for a sub blk of alternatives of form:
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.
3245 * Generate code of the following form:
3246 * if ( First(G1) ) {
3249 * else if ( First(G2) ) {
3260 genSubBlk( Junction
*q
)
3268 int need_right_curly
;
3269 int lastAltEmpty
; /* MR23 */
3271 savetkref
= tokensRefdInBlock
;
3272 require(q
->ntype
== nJunction
, "genSubBlk: not junction");
3273 require(q
->jtype
== aSubBlk
, "genSubBlk: not subblock");
3275 OutLineInfo(output
,q
->line
,FileStr
[q
->file
]);
3278 BlockPreambleOption(q
,q
->pFirstSetSymbol
); /* MR21 */
3279 f
= genBlk(q
, aSubBlk
, &max_k
, &need_right_curly
, &lastAltEmpty
/* 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.
3286 if (FoundException
&& lastAltEmpty
) {
3287 gen("/* MR23 skip error clause for (...| epsilon) when exceptions in use */\n");
3290 if ( q
->p2
!= NULL
) {tab(); makeErrorClause(q
,f
,max_k
,0 /* use plus block bypass ? */ );}
3293 { int i
; for (i
=1; i
<=need_right_curly
; i
++) {tabs
--; gen("}\n");} }
3300 gen("zzGUESS_DONE\n");
3303 /* must duplicate if (alpha)?; one guesses (validates), the
3304 * second pass matches */
3305 if ( q
->guess
&& analysis_point(q
)==q
)
3307 OutLineInfo(output
,q
->line
,FileStr
[q
->file
]);
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");} }
3318 tokensRefdInBlock
= savetkref
;
3319 if (q
->end
->p1
!= NULL
) TRANS(q
->end
->p1
);
3322 static int TnodesAllocatedPrevRule
=0;
3325 * Generate code for a rule.
3327 * rule--> o-->o-Alternatives-o-->o
3329 * rule--> o-->o-Alternative-o-->o
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.
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.
3341 genRule( Junction
*q
)
3348 const char * returnValueInitializer
;
3350 do { /* MR10 Change recursion into iteration */
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");
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;
3366 CurRule
=q
->rname
; /* MR11 */
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 */
3373 /* MR6 Simpler to debug when output goes to stdout rather than a file */
3375 /* MR6 */ if (UseStdout
) {
3376 /* MR6 */ output
= stdout
;
3378 /* MR6 */ if ( output
!= NULL
) fclose( output
);
3379 /* MR6 */ output
= fopen(OutMetaName(outname(FileStr
[q
->file
])), "w");
3381 require(output
!= NULL
, "genRule: can't open output file");
3383 #ifdef SPECIAL_FOPEN
3384 special_fopen_actions(OutMetaName(outname(FileStr
[q
->file
]))); /* MR1 */
3386 if ( file
== -1 ) genHdr1(q
->file
);
3387 else genHdr(q
->file
);
3392 fprintf(stderr
," rule %s\n",q
->rname
);
3397 if (strcmp(q
->rname
,"***debug***") == 0) {
3398 fprintf(stderr
,"***debug*** %s reached\n",q
->rname
);
3403 DumpFuncHeader(q
,r
);
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++.
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.
3427 if ( hasMultipleOperands(q
->ret
) ) /* MR23 */
3430 /* Emit initialization code later. */
3432 gen1("struct _rv%d _retv;\n",r
->rulenum
);
3436 /* Emit initialization code now. */
3439 DumpType(q
->ret
, output
);
3440 returnValueInitializer
= getInitializer(q
->ret
);
3441 if (returnValueInitializer
== NULL
) { /* MR23 */
3442 gen(" _retv;\n"); /* MR1 MR3 */
3445 gen1(" _retv = %s;\n", returnValueInitializer
); /* MR23 */
3450 OutLineInfo(output
,q
->line
,FileStr
[q
->file
]);
3457 if ( FoundException
)
3459 gen("int _sva=1;\n");
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");
3468 if ( !GenCC
) gen1("zzBLOCK(zztasp%d);\n", BlkLevel
);
3470 /* MR10 */ /* move zzTRACEIN to before init action */
3472 /* MR10 */ if ( TraceGen
) {
3473 /* MR10 */ if ( GenCC
) {gen1("zzTRACEIN(\"%s\");\n", q
->rname
);}
3474 /* MR10 */ else gen1("zzTRACEIN((ANTLRChar *)\"%s\");\n", q
->rname
);
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 */
3483 MR23 Do the PURIFY macro only for C mode.
3484 C++ users should use constructors or initialization expressions.
3487 if ( q
->ret
!= NULL
) /* MR7 */
3489 if (hasMultipleOperands(q
->ret
)) { /* MR23 */
3490 if (PURIFY
== TRUE
) {
3491 gen1("PCCTS_PURIFY(_retv,sizeof(struct _rv%d))\n",r
->rulenum
); /* 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.
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 */
3512 if (hasMultipleOperands(q
->ret
)) { /* MR23 */
3513 DumpInitializers(output
, r
, q
->ret
); /* MR23 */
3517 if ( !GenCC
) gen("zzMake0;\n");
3518 if ( FoundException
) gen("*_retsignal = NoSignal;\n");
3520 if ( !GenCC
) gen("{\n");
3522 if ( has_guess_block_as_first_item((Junction
*)q
->p1
) )
3524 gen("zzGUESS_BLOCK\n");
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
);
3531 a
= findImmedAction( q
->p1
); /* only one alternative in rule */
3532 if ( a
!=NULL
&& !a
->is_predicate
)
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 */
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
);
3549 if ( !GenCC
) gen1("zzEXIT(zztasp%d);\n", BlkLevel
);
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 */
3558 /* MR14 */ if (r
->dontComputeErrorSet
) {
3559 /* MR14 */ follow
=empty
;
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");
3572 Isn't it so that "fail:" is ONLY referenced when:
3574 !FoundException || FoundGuessBlk ?
3576 Therefore add the "if" around this piece of code generation...
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.
3584 if ( !FoundException
|| FoundGuessBlk
) /* MR20 G. Hobbelt */
3585 { /* MR20 G. Hobbelt */
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");
3592 if ( q
->erraction
!=NULL
)
3593 dumpAction(q
->erraction
, output
, tabs
, q
->file
, q
->line
, 1);
3596 gen1("syn(zzBadTok, %s, zzMissSet, zzMissTok, zzErrk);\n",
3597 r
->egroup
==NULL
?"(ANTLRChar *)\"\"":r
->egroup
);
3601 gen1("zzsyn(zzMissText, zzBadTok, %s, zzMissSet, zzMissTok, zzErrk, zzBadText);\n",
3602 r
->egroup
==NULL
?"(ANTLRChar *)\"\"":r
->egroup
);
3604 gen3("%sresynch(setwd%d, 0x%x);\n", GenCC
?"":"zz", wordnum
, 1<<setnum
);
3606 if ( q
->ret
!=NULL
) {
3608 gen("return _retv;\n");
3609 } else if ( q
->exceptions
!=NULL
) {
3612 } else if (!FoundException
) { /* MR10 */
3613 genTraceOut(q
); /* MR10 */
3616 } /* MR20 G. Hobbelt */
3618 if ( !GenCC
) gen("}\n");
3620 /* Gen code for exception handlers */
3621 /* make sure each path out contains genTraceOut() */
3623 if ( q
->exceptions
!=NULL
)
3626 gen("/* exception handlers */\n");
3628 dumpExceptions(q
->exceptions
);
3630 if ( !r
->has_rule_exception
)
3632 _gen("_handler:\n");
3633 gen("zzdflthandlers(_signal,_retsignal);\n");
3635 /* MR20 G. Gobbelt The label "adios" is never referenced */
3640 if ( q
->ret
!=NULL
) {
3642 gen("return _retv;\n");
3649 else if ( FoundException
)
3651 _gen("_handler:\n");
3652 gen("zzdflthandlers(_signal,_retsignal);\n");
3655 /* MR1 7-Apr-97 Fix suggested by: John Bair (jbair@iftime.com) */
3658 if ( q
->ret
!= NULL
) { /* MR1 */
3659 genTraceOut(q
); /* MR10 */
3660 gen("return _retv;\n"); /* MR1 */
3662 genTraceOut(q
); /* MR10 */
3663 gen("return;\n") ; /* MR1 */
3670 /* MR10 Tired of looking at stacks that are as deep as the number of */
3671 /* MR10 rules. Changes recursion to iteration. */
3673 MR_releaseResourcesUsedInRule( (Node
*) q
); /* MR10 */
3676 fprintf(output
,"\n/* tnodes created for rule %s: %d */\n",
3677 q
->rname
, (TnodesAllocated
-TnodesAllocatedPrevRule
) );
3680 TnodesAllocatedPrevRule
=TnodesAllocated
;
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");
3686 } while (q
!= NULL
);
3688 /**** The old code ****/
3689 /**** if ( q->p2 != NULL ) {TRANS(q->p2);} ****/ /* generate code for next rule too */
3690 /**** else dumpAfterActions( output ); ****/
3695 /* This is for the function definition, not the declaration. */
3699 DumpFuncHeader( Junction
*q
, RuleEntry
*r
)
3701 DumpFuncHeader( q
, r
)
3707 /* MR1 10-Apr-97 MR1 Simplify insertion of commas in function header */
3709 int needComma
; /* MR1 */
3716 if ( hasMultipleOperands(q
->ret
) ) /* MR23 */
3718 if (GenCC
) gen2("%s::_rv%d\n", CurrentClassName
, r
->rulenum
)
3719 else gen1("struct _rv%d\n",r
->rulenum
);
3723 DumpType(q
->ret
, output
);
3732 /* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */
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
);
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. */
3745 DumpANSIFunctionArgDef(output
,q
, 0 /* emit initializers ? */);
3755 gen2("%s%s(", RulePrefix
, q
->rname
);
3756 needComma
=0; /* MR1 */
3757 if ( GenAST
) /* MR1 */
3759 _gen("_root"); /* MR1 */
3760 needComma
=1; /* MR1 */
3762 if ( FoundException
) /* MR1 */
3764 if (needComma
) {_gen(",");needComma
=0;}; /* MR1 */
3765 _gen("_retsignal"); /* MR1 */
3766 needComma
=1; /* MR1 */
3768 /* MR5 Change below by Jan Mikkelsen (janm@zeta.org.au) 26-May-97 MR5 */
3769 DumpListOfParmNames( q
->pdecl
, output
, needComma
); /* MR5 */
3771 if ( GenAST
) gen("AST **_root;\n");
3772 if ( FoundException
) gen("int *_retsignal;\n");
3773 DumpOldStyleParms( q
->pdecl
, output
);
3780 DumpANSIFunctionArgDef(FILE *f
, Junction
*q
, int bInitializer
)
3782 DumpANSIFunctionArgDef(f
,q
,bInitializer
)
3790 if ( GenCC
) {fprintf(f
,"ASTBase **_root");}
3791 else fprintf(f
,"AST**_root");
3792 if ( !FoundException
&& q
->pdecl
!=NULL
) fprintf(f
,",");
3794 if ( FoundException
)
3796 if ( GenAST
) fprintf(f
,",");
3797 fprintf(f
,"int *_retsignal");
3798 if ( q
->pdecl
!=NULL
) {
3802 if ( q
->pdecl
!=NULL
) {
3803 DumpFormals(f
, q
->pdecl
, bInitializer
); /* MR23 */
3806 if ( !GenAST
&& !FoundException
) {
3815 genJunction( Junction
*q
)
3821 require(q
->ntype
== nJunction
, "genJunction: not junction");
3822 require(q
->jtype
== Generic
, "genJunction: not generic junction");
3824 if ( q
->p1
!= NULL
) TRANS(q
->p1
);
3825 if ( q
->p2
!= NULL
) TRANS(q
->p2
);
3830 genEndBlk( Junction
*q
)
3840 genEndRule( Junction
*q
)
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");
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
);
3866 /* MR10 */ _gen(" * ");
3867 /* MR10 */ for (i
=0 ; i
< Save_argc
; i
++) {
3868 /* MR10 */ _gen(" ");
3869 /* MR10 */ _gen1("%s", Save_argv
[i
]);
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
]);
3884 if ( UserTokenDefsFile
!= NULL
)
3885 fprintf(output
, "#include %s\n", UserTokenDefsFile
);
3887 fprintf(output
, "#include \"%s\"\n", DefFileName
);
3890 if ( HdrAction
!= NULL
) dumpAction( HdrAction
, output
, 0, -1, 0, 1);
3891 if ( !GenCC
&& FoundGuessBlk
)
3893 _gen("#define ZZCAN_GUESS\n");
3894 _gen("#include \"pccts_setjmp.h\"\n"); /* MR15 K.J. Cummings (cummings@peritus.com) */
3896 if ( FoundException
)
3898 _gen("#define EXCEPTION_HANDLING\n");
3899 _gen1("#define NUM_SIGNALS %d\n", NumSignals
);
3901 if ( !GenCC
&& OutputLL_k
> 1 ) _gen1("#define LL_K %d\n", OutputLL_k
);
3902 if ( GenAST
&&!GenCC
) _gen("#define GENAST\n\n");
3904 if ( GenCC
) {_gen1("#include \"%s\"\n\n", ASTBASE_H
);}
3905 else _gen("#include \"ast.h\"\n\n");
3907 if ( !GenCC
&& DemandLookahead
) _gen("#define DEMAND_LOOK\n\n");
3909 if ( !GenCC
&& LexGen
) {
3910 _gen1("#define zzEOF_TOKEN %d\n", (TokenInd
!=NULL
?TokenInd
[EofToken
]:EofToken
));
3913 /* ###WARNING: This will have to change when SetWordSize changes */
3914 if ( !GenCC
) _gen1("#define zzSET_SIZE %d\n", NumWords(TokenNum
-1)*sizeof(unsigned));
3916 _gen("#ifndef zzTRACE_RULES\n"); /* MR20 */
3917 _gen("#define zzTRACE_RULES\n"); /* MR20 */
3918 _gen("#endif\n"); /* MR22 */
3920 if ( !GenCC
) {_gen("#include \"antlr.h\"\n");}
3922 _gen1("#include \"%s\"\n", APARSER_H
);
3923 _gen1("#include \"%s.h\"\n", CurrentClassName
);
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
);
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
);
3937 /* MR10 Ofer Ben-Ami (gremlin@cs.huji.ac.il) */
3938 /* MR10 Finally, a definition of the Purify macro */
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");
3963 _gen("#include \"ast.c\"\n");
3964 _gen("zzASTgvars\n\n");
3967 if ( !GenCC
) _gen("ANTLR_INFO\n");
3968 if ( BeforeActions
!= NULL
)
3970 for (p
= BeforeActions
->next
; p
!=NULL
; p
=p
->next
)
3972 UserAction
*ua
= (UserAction
*)p
->elem
;
3973 dumpAction( ua
->action
, output
, 0, ua
->file
, ua
->line
, 1);
3977 if ( !FoundException
) return;
3981 _gen1("\nvoid %s::\n", CurrentClassName
);
3982 _gen("zzdflthandlers( int _signal, int *_retsignal )\n");
3989 /* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */
3991 _gen("#ifdef __USE_PROTOS\n"); /* MR1 */
3992 _gen("zzdflthandlers( int _signal, int *_retsignal )\n");
3994 _gen("zzdflthandlers( _signal, _retsignal )\n");
3995 _gen("int _signal;\n");
3996 _gen("int *_retsignal;\n");
4001 if ( DefaultExGroup
!=NULL
)
4003 dumpException(DefaultExGroup
, 1);
4004 if ( !hasDefaultException(DefaultExGroup
) )
4008 gen("*_retsignal = _signal;\n");
4014 gen("*_retsignal = _signal;\n");
4023 genStdPCCTSIncludeFile( FILE *f
,char *gate
) /* MR10 */
4025 genStdPCCTSIncludeFile( f
, gate
) /* MR10 */
4027 char * gate
; /* MR10 */
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 */
4036 fprintf(f
,"#ifndef STDPCCTS_H\n"); /* MR10 */
4037 fprintf(f
,"#define STDPCCTS_H\n"); /* MR10 */
4039 fprintf(f
,"#ifndef STDPCCTS_%s_H\n",gate
); /* MR10 */
4040 fprintf(f
,"#define STDPCCTS_%s_H\n",gate
); /* MR10 */
4044 fprintf(f
," * %s -- P C C T S I n c l u d e\n", stdpccts
);
4046 fprintf(f
," * Standard PCCTS include file with -fh %s -- P C C T S I n c l u d e\n", stdpccts
);
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");
4055 fprintf(f
,"#ifndef ANTLR_VERSION\n");
4056 fprintf(f
,"#define ANTLR_VERSION %s\n", VersionDef
);
4057 fprintf(f
,"#endif\n\n");
4059 if (FirstAction
!= NULL
) dumpAction(FirstAction
, f
, 0, -1, 0, 1); /* MR11 */
4061 fprintf(f
,"#include \"pcctscfg.h\"\n");
4062 fprintf(f
,"#include \"pccts_stdio.h\"\n");
4065 if ( UserDefdTokens
)
4066 fprintf(f
, "#include %s\n", UserTokenDefsFile
);
4068 fprintf(f
, "#include \"%s\"\n", DefFileName
);
4071 fprintf(f
, "#include \"%s\"\n", ATOKEN_H
);
4073 if ( HdrAction
!= NULL
) dumpAction( HdrAction
, f
, 0, -1, 0, 1);
4075 fprintf(f
, "#include \"%s\"\n", ATOKENBUFFER_H
);
4077 if ( OutputLL_k
> 1 ) fprintf(f
,"static const unsigned LL_K=%d;\n", OutputLL_k
);
4079 fprintf(f
, "#include \"%s\"\n", ASTBASE_H
);
4083 fprintf(f
,"#ifndef zzTRACE_RULES\n"); /* MR20 */
4084 fprintf(f
,"#define zzTRACE_RULES\n"); /* MR20 */
4085 fprintf(f
,"#endif\n"); /* MR22 */
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");
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
)
4104 fprintf(f
,"#define ZZCAN_GUESS\n");
4105 fprintf(f
,"#include \"pccts_setjmp.h\"\n");
4108 fprintf(f
,"#ifndef zzTRACE_RULES\n"); /* MR20 */
4109 fprintf(f
,"#define zzTRACE_RULES\n"); /* MR20 */
4110 fprintf(f
,"#endif\n"); /* MR22 */
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
)
4116 /* MR1 7-Apr-97 1.33MR1 */
4117 /* MR1 Fix suggested by: */
4118 /* MR1 Francois-Xavier Fontaine (fontaine_f@istvax.ist.lu) */
4120 fprintf(f
,"#define EXCEPTION_HANDLING\n"); /* MR1 */
4121 fprintf(f
,"#define NUM_SIGNALS %d\n", NumSignals
); /* MR1 */
4123 if ( DemandLookahead
) fprintf(f
,"#define DEMAND_LOOK\n");
4125 if ( LexGen
) fprintf(f
, "#define zzEOF_TOKEN %d\n", (TokenInd
!=NULL
?TokenInd
[EofToken
]:EofToken
));
4127 /* ###WARNING: This will have to change when SetWordSize changes */
4128 fprintf(f
, "#define zzSET_SIZE %d\n", NumWords(TokenNum
-1)*sizeof(unsigned));
4130 fprintf(f
,"#ifndef zzTRACE_RULES\n"); /* MR20 */
4131 fprintf(f
,"#define zzTRACE_RULES\n"); /* MR20 */
4132 fprintf(f
,"#endif\n"); /* MR22 */
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");
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.
4153 June '93; changed so that empty lines are left alone so that
4154 line information is correct for the compiler/debuggers.
4158 dumpAction( char *s
, FILE *output
, int tabs
, int file
, int line
,
4161 dumpAction( s
, output
, tabs
, file
, line
, final_newline
)
4170 int inDQuote
, inSQuote
;
4171 require(s
!=NULL
, "dumpAction: NULL action");
4172 require(output
!=NULL
, eMsg1("dumpAction: output FILE is NULL for %s",s
));
4174 if ( GenLineInfo
&& file
!= -1 )
4176 OutLineInfo(output
,line
,FileStr
[file
]);
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' )
4186 fputc( *s
++, output
); /* Avoid '"' Case */
4187 if ( *s
== '\0' ) return;
4188 if ( *s
== '\'' ) fputc( *s
++, output
);
4189 if ( *s
== '\"' ) fputc( *s
++, output
);
4193 if ( !inDQuote
) inSQuote
= !inSQuote
;
4197 if ( !inSQuote
) inDQuote
= !inDQuote
;
4201 fputc('\n', output
);
4203 PastWhiteSpace( s
);
4208 fputc( *s
++, output
);
4211 if ( *s
== '\0' ) return;
4212 if ( *s
!= '#' ) /* #define, #endif etc.. start at col 1 */
4217 if ( *s
== '}' && !(inSQuote
|| inDQuote
) )
4219 --tabs
; /* Indent one fewer */
4221 if ( *s
== '{' && !(inSQuote
|| inDQuote
) )
4223 tabs
++; /* Indent one more */
4225 fputc( *s
, output
);
4228 if ( final_newline
) fputc('\n', output
);
4233 dumpAfterActions( FILE *output
)
4235 dumpAfterActions( output
)
4240 require(output
!=NULL
, "dumpAfterActions: output file was NULL for some reason");
4241 if ( AfterActions
!= NULL
)
4243 for (p
= AfterActions
->next
; p
!=NULL
; p
=p
->next
)
4245 UserAction
*ua
= (UserAction
*)p
->elem
;
4246 dumpAction( ua
->action
, output
, 0, ua
->file
, ua
->line
, 1);
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.
4257 * Scan forward while (generic junction with p2==NULL)
4258 * If we stop on an action, return ptr to the action
4263 findImmedAction( Node
*q
)
4265 findImmedAction( q
)
4270 require(q
!=NULL
, "findImmedAction: NULL node");
4271 require(q
->ntype
>=1 && q
->ntype
<=NumNodeTypes
, "findImmedAction: invalid node");
4273 while ( q
->ntype
== nJunction
)
4276 if ( j
->jtype
!= Generic
|| j
->p2
!= NULL
) return NULL
;
4278 if ( q
== NULL
) return NULL
;
4280 if ( q
->ntype
== nAction
) return (ActionNode
*)q
;
4286 dumpRetValAssign( char *retval
, char *ret_def
, RuleRefNode
* ruleRef
/* MR30 */)
4288 dumpRetValAssign( retval
, ret_def
, ruleRef
/* MR30 */)
4291 RuleRefNode
*ruleRefNode
;
4297 while ( *retval
!= '\0' && *q
!= '\0')
4299 while ( isspace((*retval
)) ) retval
++;
4300 while ( *retval
!=',' && *retval
!='\0' ) fputc(*retval
++, output
);
4301 fprintf(output
, " = _trv.");
4303 DumpNextNameInDef(&q
, output
);
4304 while ( isspace(*q
) ) q
++;
4305 fputc(';', output
); fputc(' ', output
);
4306 if ( *retval
== ',' ) retval
++;
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
);
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
);
4318 /* This function computes the set of tokens that can possibly be seen k
4319 * tokens in the future from point j
4324 ComputeErrorSet( Junction
*j
, int k
, int usePlusBlockBypass
)
4326 ComputeErrorSet( j
, k
, usePlusBlockBypass
)
4329 int usePlusBlockBypass
;
4334 require(j
->ntype
==nJunction
, "ComputeErrorSet: non junction passed");
4337 for (alt1
=j
; alt1
!=NULL
; alt1
= (Junction
*)alt1
->p2
)
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");
4351 tokenFollowSet(TokNode
*p
)
4357 static char buf
[100];
4362 REACH(p
->next
, 1, &rk
, a
);
4363 require(set_nil(rk
), "rk != nil");
4365 n
= DefErrSet( &a
, 0, NULL
);
4368 sprintf(buf
, "err%d", n
);
4370 sprintf(buf
, "zzerr%d", n
);
4376 makeErrorClause( Junction
*q
, set f
, int max_k
, int usePlusBlockBypass
)
4378 makeErrorClause( q
, f
, max_k
, usePlusBlockBypass
)
4382 int usePlusBlockBypass
;
4385 char * handler_id
=""; /* MR7 */
4386 int nilf
=0; /* MR13 */
4387 RuleEntry
*ruleEntry
; /* MR14 */
4389 if ( FoundException
)
4393 if ( FoundGuessBlk
)
4395 if ( GenCC
) {gen("if ( guessing ) goto fail;\n");}
4396 else gen("if ( zzguessing ) goto fail;\n");
4398 gen("if (_sva) _signal=NoViableAlt;\n");
4399 gen("else _signal=NoSemViableAlt;\n");
4400 if (q
->outerEG
!= NULL
) {
4401 handler_id
=q
->outerEG
->altID
;
4404 printf("q->curAltNum=%d q->exception_label=%s\n",q
->curAltNum
,q
->exception_label
);
4405 gen("*** DEBUG *** outerEG==NULL\n");
4408 gen1("goto %s_handler; /* MR7 */\n",handler_id
); /* MR7 */
4416 /* MR13 */ nilf
=set_nil(f
);
4418 _gen1("else {FAIL(1,err%d", DefErrSet1(1,&f
,1,NULL
));
4420 _gen1("else {zzFAIL(1,zzerr%d", DefErrSet1(1,&f
,1,NULL
));
4428 if ( GenCC
) {_gen1("else {FAIL(%d", max_k
);}
4429 else _gen1("else {zzFAIL(%d", max_k
);
4431 ruleEntry
= (RuleEntry
*) hash_get(Rname
,q
->rname
);
4433 for (i
=1; i
<=max_k
; i
++)
4435 /* MR14 */ if (ruleEntry
->dontComputeErrorSet
) {
4438 f
= ComputeErrorSet(q
, i
, usePlusBlockBypass
/* use plus block bypass ? */ );
4441 if ( GenCC
) {_gen1(",err%d", DefErrSet( &f
, 1, NULL
));}
4442 else _gen1(",zzerr%d", DefErrSet( &f
, 1, NULL
));
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 ? */");
4457 char * findOuterHandlerLabel(ExceptionGroup
*eg
) /* MR7 */
4459 char * findOuterHandlerLabel(eg
) /* MR7 */
4460 ExceptionGroup
*eg
; /* MR7 */
4463 char *label
=NULL
; /* MR7 */
4464 ExceptionGroup
*outerEG
; /* MR7 */
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 */
4473 } else if (eg
->outerEG
!= NULL
) { /* MR7 */
4474 outerEG
=eg
->outerEG
; /* MR7 */
4475 label
=outerEG
->altID
; /* MR7 */
4476 outerEG
->used
=1; /* MR7 */
4479 return (label
==NULL
? "" : label
); /* MR7 */
4485 ** #ifdef __USE_PROTOS
4486 ** char * findOuterAltHandlerLabel(Junction
*startJ
) /* MR7 */
4488 ** char * findOuterAltHandlerLabel(startJ
) /* MR7 */
4489 ** Junction
*startJ
; /* MR7 */
4492 ** char *label
=NULL
; /* MR7 */
4493 ** Junction
*alt
; /* MR7 */
4495 ** for (alt
=startJ
; alt
!= NULL
; alt
=alt
->outerAltstart
) { /* MR7 */
4496 ** label
=alt
->exception_label
; /* MR7 */
4497 ** if (label
!= NULL
) break; /* MR7 */
4499 ** return (label
==NULL
? "" : label
); /* MR7 */
4504 static void OutLineInfo(FILE *file
,int line
,char *fileName
)
4506 static void OutLineInfo(file
,line
,fileName
)
4512 static char * prevFileName
=NULL
;
4513 static char * prevFileNameMS
=NULL
;
4518 if (! GenLineInfo
) return;
4520 if (!GenLineInfoMS
) {
4521 fprintf(file
, LineInfoFormatStr
,line
,fileName
);
4523 if (fileName
== prevFileName
) {
4524 fprintf(file
, LineInfoFormatStr
,line
,prevFileNameMS
);
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");
4530 for (p
=fileName
; *p
!= 0; p
++) {
4532 if (*q
== '\\') *q
='/';
4536 prevFileName
=fileName
;
4545 void OutFirstSetSymbol(Junction
*q
, char * pSymbol
)
4547 void OutFirstSetSymbol(q
, pSymbol
)
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
, "");
4565 void BlockPreambleOption(Junction
*q
, char * pSymbol
)
4567 void BlockPreambleOption(q
, pSymbol
)
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
, "");
4585 dumpActionPlus(ActionNode
*a
, char *s
, FILE *output
, int tabs
, int file
, int line
,
4588 dumpActionPlus(a
, s
, output
, tabs
, file
, line
, final_newline
)
4598 dumpAction(s
,output
,tabs
,file
,line
,final_newline
);
4603 ** #ifdef __USE_PROTOS
4604 ** void MR_ErrorSets(Junction
*q
, int max_k
, int usePlusBlockBypass
)
4606 ** void MR_ErrorSets(q
, max_k
, usePlusBlockBypass
)
4609 ** int usePlusBlockBypass
;
4618 ** require (max_k
<= CLL_k
, "k > CLL_k");
4621 ** for (k
= 1; k
<= CLL_k
; k
++) {set_clr(q
->fset
[k
]); }
4623 ** for (k
= 1; k
<= max_k
; k
++) {
4624 ** for (alt1
=q
; alt1
!= NULL
; alt1
= (Junction
*)alt1
->p2
)
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
);
4638 void DumpInitializers(FILE* output
, RuleEntry
*r
, char * pReturn
)
4640 void DumpInitializers(output
, r
, pReturn
)
4655 require(pReturn
!=NULL
, "DumpInitializer: invalid string");
4665 if (nest
!= 0) return;
4666 if (pValue
!= NULL
) {
4668 q
= strBetween(pSymbol
, pEqualSign
, pSeparator
);
4669 fprintf(output
, "_retv.%s", q
);
4670 q
= strBetween(pValue
, NULL
, pSeparator
);
4671 fprintf(output
, " = %s;\n", q
);
4677 void DumpFormals(FILE* output
, char * pReturn
, int bInitializer
)
4679 void DumpFormals(output
, pReturn
, bInitializer
)
4695 require(pReturn
!=NULL
, "DumpFormals: invalid string");
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
);
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
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
4741 int isEmptyAlt(Node
* alt
, Node
* endBlock
)
4743 int isEmptyAlt(alt
, endBlock
)
4750 while (n
!= endBlock
) {
4766 fatal_internal("Invalid node type");
4781 n
= j
->p1
; /* MR26 */
4782 goto NEXT
; /* MR26 */