gen.c revision 4fd606d1f5abe38e1f42c38de1d2e895166bd0f4
/*
* gen.c
*
* Generate C code (ANSI, K&R, C++)
*
* SOFTWARE RIGHTS
*
* We reserve no LEGAL rights to the Purdue Compiler Construction Tool
* Set (PCCTS) -- PCCTS is in the public domain. An individual or
* company may do whatever they wish with source code distributed with
* PCCTS or the code generated by PCCTS, including the incorporation of
* PCCTS, or its output, into commerical software.
*
* We encourage users to develop software with PCCTS. However, we do ask
* that credit is given to us for developing PCCTS. By "credit",
* we mean that if you incorporate our source code into one of your
* programs (commercial product, research project, or otherwise) that you
* acknowledge this fact somewhere in the documentation, research report,
* etc... If you like PCCTS and have developed a nice tool with the
* output, please mention that you developed it using PCCTS. In
* addition, we ask that this header remain intact in our source code.
* As long as these guidelines are kept, we expect to continue enhancing
* this system and expect to make other tools available as they are
* completed.
*
* ANTLR 1.33
* Terence Parr
* Parr Research Corporation
* with Purdue University and AHPCRC, University of Minnesota
* 1989-2001
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "pcctscfg.h"
#include "set.h"
#include "syn.h"
#include "hash.h"
#include "generic.h"
#include "dlgdef.h"
#define NumExprPerLine 4
static int on1line=0;
static set tokensRefdInBlock;
/* T r a n s l a t i o n T a b l e s */
/* C_Trans[node type] == pointer to function that knows how to translate that node. */
#ifdef __cplusplus
NULL,
NULL, /* See next table.
Junctions have many types */
(void (*)(...)) genRuleRef,
(void (*)(...)) genToken,
(void (*)(...)) genAction
};
#else
NULL,
NULL, /* See next table.
Junctions have many types */
};
#endif
/* C_JTrans[Junction type] == pointer to function that knows how to translate that
* kind of junction node.
*/
#ifdef __cplusplus
NULL,
(void (*)(...)) genSubBlk,
(void (*)(...)) genOptBlk,
(void (*)(...)) genLoopBlk,
(void (*)(...)) genEndBlk,
(void (*)(...)) genRule,
(void (*)(...)) genJunction,
(void (*)(...)) genEndRule,
(void (*)(...)) genPlusBlk,
(void (*)(...)) genLoopBegin
};
#else
NULL,
};
#endif
static int tabs = 0;
/* MR6 Got tired of text running off page when using standard tab stops */
#define TAB { int i; \
if (TabWidth==0) { \
} else { \
}; \
}
static void
#ifdef __USE_PROTOS
tab( void )
#else
tab( )
#endif
#ifdef __USE_PROTOS
static char *tokenFollowSet(TokNode *);
static int has_guess_block_as_first_item(Junction *);
static int genExprSets(set *, int);
static void genExprTree( Tree *t, int k );
#else
static char *tokenFollowSet();
static ActionNode *findImmedAction();
static void dumpRetValAssign();
static void dumpAfterActions();
static set ComputeErrorSet();
static void makeErrorClause();
static void DumpFuncHeader();
static int has_guess_block_as_first_item();
static int genExprSets();
static void genExprTree();
static void genExprTreeOriginal(); /* MR10 */
static char * findOuterHandlerLabel(); /* MR7 */
static void OutLineInfo(); /* MR14 */
#endif
/* MR11 a convenient place to set a break point */
#ifdef __USE_PROTOS
void MR_break(void)
#else
void MR_break()
#endif
{
return;
}
/* MR10 genTraceOut(Junction *) */
#ifdef __USE_PROTOS
static void genTraceOut(Junction *q)
#else
static void genTraceOut(q)
Junction *q;
#endif
{
if ( TraceGen ) {
}
}
static void
#ifdef __USE_PROTOS
#else
#endif
{
static int warned_already=0;
if ( !DemandLookahead || warned_already ) return;
warned_already = 1;
warnNoFL("-gk option could cause trouble for <<...>>? predicates");
}
void
#ifdef __USE_PROTOS
freeBlkFsets( Junction *q )
#else
freeBlkFsets( q )
Junction *q;
#endif
{
int i;
{
}
}
/*
* Generate a local variable allocation for each token references
* in this block.
*/
static void
#ifdef __USE_PROTOS
genTokenPointers( Junction *q )
#else
genTokenPointers( q )
Junction *q;
#endif
{
/* Rule refs are counted and can be referenced, but their
* value is not set to anything useful ever.
*
* The ptrs are to be named _tij where i is the current level
* and j is the element number within an alternative.
*/
int first=1, t=0;
set a;
tokensRefdInBlock = q->tokrefs;
gen("ANTLRTokenPtr ");
{
t = set_int(a);
else _gen(",");
else _gen("=NULL");
}
_gen(";\n");
set_free(a);
}
static int
#ifdef __USE_PROTOS
#else
#endif
{
ListNode *q;
{
return 1;
}
}
return 0;
}
static void
#ifdef __USE_PROTOS
#else
int no_default_case;
#endif
{
char *outerLabel; /* MR7 */
int altHandler=0; /* MR7 */
int namedHandler=0; /* MR7 */
/* nothing */ /* MR20 */
} else { /* MR7 */
}; /* MR7 */
#if 0
** }; /* MR7 */
#endif
if (namedHandler) { /* MR7 */
} else { /* MR7 */
}; /* MR7 */
{
ListNode *q;
{
gen("default :\n");
tabs++;
tabs--;
gen("}\n");
/* copied from later code in dumpException */ /* MR7 */
if (namedHandler) { /* MR7 */
} else if (altHandler) { /* MR7 */
};
return;
}
tabs++;
{
}
tabs--;
}
}
if ( no_default_case ) return;
gen("default :\n");
tabs++; /* MR7 */
tabs--; /* MR7 */
tabs++;
/***** gen("*_retsignal = _signal;\n"); *****/
tabs--;
gen("}\n");
if (namedHandler) { /* MR7 */
} else if (altHandler) { /* MR7 */
};
}
static void
#ifdef __USE_PROTOS
#else
#endif
{
ListNode *p;
{
_gen2("%s%s_handler:\n",
else {
/* This must be the rule exception handler */
if ( !hasDefaultException(eg) )
{
gen("default :\n");
tabs++;
gen("zzdflthandlers(_signal,_retsignal);\n");
tabs--;
gen("}\n");
}
}
}
}
/* For each element label that is found in a rule, generate a unique
* Attribute (and AST pointer if GenAST) variable.
*/
void
#ifdef __USE_PROTOS
#else
#endif
{
int first=1;
ListNode *p;
else {gen("Attrib");}
{
else _gen(",");
}
_gen(";\n");
if ( !GenAST ) return;
first = 1;
gen("AST");
{
else _gen(",");
}
_gen(";\n");
}
/*
* Generate a local variable allocation for each token or rule reference
* in this block.
*/
static void
#ifdef __USE_PROTOS
genASTPointers( Junction *q )
#else
genASTPointers( q )
Junction *q;
#endif
{
int first=1, t;
set a;
if ( set_deg(a) > 0 )
{
gen("AST ");
{
t = set_int(a);
else _gen(",");
}
set_free(a);
}
_gen(";\n");
}
static void
#ifdef __USE_PROTOS
BLOCK_Head( void )
#else
BLOCK_Head( )
#endif
{
gen("{\n");
tabs++;
}
static void
#ifdef __USE_PROTOS
BLOCK_Tail( void )
#else
BLOCK_Tail( )
#endif
{
tabs--;
gen("}\n");
}
static void
#ifdef __USE_PROTOS
BLOCK_Preamble( Junction *q )
#else
BLOCK_Preamble( q )
Junction *q;
#endif
{
ActionNode *a;
BLOCK_Head();
if ( GenCC ) genTokenPointers(q);
else begin = q;
if ( has_guess_block_as_first_item(begin) )
{
gen("zzGUESS_BLOCK\n");
}
if ( q->jtype == aLoopBegin )
else
a = findImmedAction( q->p1 );
if ( a!=NULL && !a->is_predicate) {
}
}
void
#ifdef __USE_PROTOS
#else
Predicate *p;
#endif
{
#ifdef DBG_PRED
#endif
{
/*** if ( p->k>1 && p->tcontext!=NULL ) ***/
{
_gen("(");
_gen(")");
}
/*** else if ( p->k==1 && set_deg(p->scontext[1])>0 ) ***/
{
_gen("(");
genExprSets(&(ctx[0]), p->k);
_gen(")");
}
fatal_internal("pred tree is orphan OR or AND list");
}
else {
if (! HoistPredicateContext) {
_gen(" 1 /* no context: prc is off */ ");
} else {
fatal_internal("pred tree context is empty");
};
}
return;
}
/* MR10 - make AND just like OR */
if ( p->expr == PRED_AND_LIST )
{
{
};
return;
}
if ( p->expr == PRED_OR_LIST )
{
{
};
return;
};
fatal("pred tree is really wacked");
}
/* [genCombinedPredTreeContext] */
void
#ifdef __USE_PROTOS
#else
Predicate *p;
#endif
{
Tree *t;
int predDepth=0;
if (0 && ! MR_usingPredNames && ! MRhoisting) {
} else {
/* MR13 */
/* MR13 */ } else {
/* MR13 */ };
} else {
if (t == NULL) {
_gen(" 1 /* MR12 no context (-prc off) */ ");
} else {
_gen("(");
genExprTree(t, 1);
Tfree(t); /* MR10 */
_gen(")");
};
};
};
}
/* [genPredTreeGate] */
void
#ifdef __USE_PROTOS
#else
genPredTreeGate( p, in_and_expr )
Predicate *p;
int in_and_expr;
#endif
{
if ( in_and_expr )
{
_gen("!(");
_gen(")||");
}
else
{
_gen("(");
_gen(")&&");
}
}
#ifdef __USE_PROTOS
#else
void genPredEntry(p,outer)
Predicate *p;
int outer;
#endif
{
int inverted=0;
Predicate *q;
int localOuter=outer;
int needRP=0;
if (p == NULL) return;
_gen("! /* inverted pred */ (");
needRP=1;
} else {
needRP=1;
};
return;
};
if (inverted) {
_gen(" ! /* inverted pred */ (");
localOuter=1;
};
if (p->expr == PRED_OR_LIST) {
genPredEntry(q,0);
};
} else if (p->expr == PRED_AND_LIST) {
genPredEntry(q,0);
};
} else {
};
if (inverted) {
_gen(")");
}
}
void
#ifdef __USE_PROTOS
#else
char *s;
int tabs;
int file;
int line;
int final_newline;
#endif
{
/* inline predicate literal */
} else {
/* a reference to a predicate - possibly with an inverted source */
} else {
};
};
}
/* [genPred] */
void
#ifdef __USE_PROTOS
#else
genPred(p,j,suppress_sva)
Predicate *p;
Node *j;
int suppress_sva;
#endif
{
else {_gen("(");}
_gen("(");
genExprSets(&(ctx[0]), p->k);
_gen(") && ");
} else {
_gen("( ");
_gen(" ) && ");
};
};
else {_gen(")");}
}
void
#ifdef __USE_PROTOS
#else
Predicate *p;
Node *j;
int in_and_expr;
#endif
{
Predicate *q;
_gen(" /* MR10 Distinct OR context optimization */ \n");
if (in_and_expr) {
gen("zzpf=0,\n");
gen("( ");
_gen(" && (zzpf=1, ");
genPred(q,j,0);
_gen(" )) ||\n");
};
gen("!zzpf)");
} else {
require (0,
"MR_distinctORcontextOpt: can't get here when using MR_predSimplify");
#if 0
** gen("( ");
** genCombinedPredTreeContext(q);
** _gen(" && ");
** genPred(q,j);
** _gen(" ) ||\n");
** };
** };
** gen(")");
#endif
};
}
void
#ifdef __USE_PROTOS
#else
genPredTreeOrig( p, j, in_and_expr )
Predicate *p;
Node *j;
int in_and_expr;
#endif
{
if ( ! noneHaveContext ) /* MR10 context guards ignored when -prc off */
{
_gen("(");
}
/* if leaf node, just gen predicate */
{
genPred(p,j,0);
return;
}
/* if AND list, do both preds (only two possible) */
if ( p->expr == PRED_AND_LIST )
{
#if 0
** _gen("(");
** _gen("&&");
** _gen(")");
** return;
#endif
/* MR11 - make it work with AND with more than two children - like OR */
_gen("(");
{
}
_gen(")");
return;
};
if ( p->expr == PRED_OR_LIST )
{
_gen("(");
{
genPredTreeOrig(list, j, 0);
}
_gen(")");
return;
}
fatal_internal("genPredTreeOrig: predicate tree is wacked");
}
#if 0
**
** if (MRhoisting) {
** if ( !noneHaveContext &&
** ! in_and_expr &&
** p->source->dummyPredicateDepth > 0 &&
** _gen("(");
** genCombinedPredTreeContext(p);
** _gen(" )\n");
** return;
** };
** };
#endif
/* [genPredTree] */
/* in_and_expr
what to do if the context is wrong
what to do if the context is correct but the predicate is false
remember: if the context is wrong it's the same as if the
predicate is true as far as enabling an alternative
Consider (AND p q r)
if in an ... && ... expression then you don't want
the entire predicate chain to fail just because the
context for one component is wrong: so return true
Consider (OR p q r)
if in an ... || ... expression then you don't want
the entire predicate chain to succeed just because
the context for one component is correct when the
corresponding test is false: so return false when
the context is correct but the test is false.
*/
void
#ifdef __USE_PROTOS
#else
Predicate *p;
Node *j;
int in_and_expr;
int suppress_sva;
#endif
{
int allHaveContext=1;
int noneHaveContext=1;
Predicate *q;
if (0 && !MR_usingPredNames && !MRhoisting) {
genPredTreeOrig(p,j,in_and_expr);
return;
};
if ( ! noneHaveContext ) { /* MR10 context guards ignored when -prc off */
_gen("(");
/* MR10 optimize OR predicates which are all leaves */
break;
};
};
if (q == NULL) {
_gen("/* MR10 individual OR gates suppressed when all predicates are leaves");
_gen(" with identical context */\n");
} else {
return;
};
/* MR12 optimize AND predicates which are all leaves */
break;
};
};
if (q == NULL) {
_gen("/* MR12 individual AND gates suppressed when all predicates are leaves");
_gen(" with identical context */\n");
} else {
};
} else {
};
}
/* if leaf node, just gen predicate */
{
genPred(p,j,suppress_sva);
return;
}
/* if AND list, do both preds (only two possible) */
/* MR10 not any more ! */
if ( p->expr == PRED_AND_LIST )
{
_gen("(");
} else {
};
};
_gen(")");
return;
}
if ( p->expr == PRED_OR_LIST )
{
_gen("(");
{
} else {
};
}
_gen(")");
return;
}
fatal_internal("predicate tree is wacked");
}
/* [genPredTreeMainXX] */
Predicate * /* MR10 */
#ifdef __USE_PROTOS
#else
genPredTreeMainXX( p, j ,in_and_expr)
Predicate *p;
Node *j;
int in_and_expr;
#endif
{
int allHaveContext=1;
int noneHaveContext=1;
#if 0
dumppred(p);
dumppred(p);
#endif
p=MR_predSimplifyALL(p); /* MR10 */
MR_cleanup_pred_trees(p); /* MR10 */
if (!noneHaveContext & !allHaveContext) {
warnFL("predicate contains elements both with and without context",
};
if (InfoP) {
_gen("\n#if 0\n\n");
MR_dumpPred(p,1);
_gen("#endif\n");
};
genPredTree(p,j,in_and_expr,0);
return p;
}
Predicate * /* MR10 */
#ifdef __USE_PROTOS
#else
genPredTreeMain( p, j)
Predicate *p;
Node *j;
#endif
{
return genPredTreeMainXX(p,j,1);
}
static void
#ifdef __USE_PROTOS
genExprTreeOriginal( Tree *t, int k )
#else
genExprTreeOriginal( t, k )
Tree *t;
int k;
#endif
{
{
{
_gen("||");
on1line++;
}
return;
}
_gen1("LA(%d)==",k);
{
_gen("&&");
on1line++;
}
{
_gen("||");
on1line++;
}
}
#ifdef __USE_PROTOS
static void MR_LAtokenString(int k,int token)
#else
static void MR_LAtokenString(k,token)
int k;
int token;
#endif
{
char *ts;
} else {
};
}
#ifdef __USE_PROTOS
static int MR_countLeaves(Tree *t)
#else
static int MR_countLeaves(t)
Tree *t;
#endif
{
if (t == NULL) return 0;
} else {
};
}
#ifdef __USE_PROTOS
#else
static void MR_genOneLine(tree,k)
int k;
#endif
{
} else {
_gen(" &&");
_gen(" && (");
_gen(")");
};
};
_gen(" ||");
};
}
static int across;
static int depth;
static int lastkonline;
#ifdef __USE_PROTOS
#else
static void MR_genMultiLine(tree,k)
int k;
#endif
{
int i;
MR_genMultiLine(tree,k);
} else {
lastkonline=k;
across++;
if (across > 3) {
_gen("\n");
across=0;
lastkonline=0;
_gen("&&");
} else {
_gen(" &&");
};
_gen("\n");
lastkonline=0;
across=0;
_gen("&& (");
_gen(")");
};
};
if (k < lastkonline) {
_gen("\n");
across=0;
lastkonline=0;
_gen("||");
} else if (across > 3 ) {
_gen("\n");
across=0;
lastkonline=0;
_gen("||");
} else {
_gen(" ||");
};
};
}
#ifdef __USE_PROTOS
#else
static void genExprTree(tree,k)
int k;
#endif
{
int count;
#if 0
/* MR20 THM This was probably an error.
The routine should probably reference that static
"across" and this declaration hides it.
*/
int across;
#endif
require (k > 0,"genExprTree: k <= 0");
if (0 && !MRhoisting) { /* MR11 make new version standard */
} else {
if (count < 5) {
MR_genOneLine(tree,k);
} else {
_gen("\n");
across=0;
depth=0;
lastkonline=0;
MR_genMultiLine(tree,k);
_gen("\n");
};
};
}
/*
* Generate LL(k) type expressions of the form:
*
* (LA(1) == T1 || LA(1) == T2 || ... || LA(1) == Tn) &&
* (LA(2) == T1 || LA(2) == T2 || ... || LA(2) == Tn) &&
* .....
* (LA(k) == T1 || LA(k) == T2 || ... || LA(k) == Tn)
*
* If GenExprSetsOpt generate:
*
* (setwdi[LA(1)]&(1<<j)) && (setwdi[LA(2)]&(1<<j)) ...
*
* where n is set_deg(expr) and Ti is some random token and k is the last nonempty
* set in fset <=CLL_k.
* k=1..CLL_k where CLL_k >= 1.
*
* This routine is visible only to this file and cannot answer a TRANS message.
*
*/
/* [genExpr] */
static int
#ifdef __USE_PROTOS
#else
genExpr( j )
Junction *j;
#endif
{
int max_k;
/* if full LL(k) is sufficient, then don't use approximate (-ck) lookahead
* from CLL_k..LL_k
*/
{
int limit;
}
/* Do tests for real tuples from other productions that conflict with
* artificial tuples generated by compression (using sets of tokens
* rather than k-trees).
*/
{
}
{
_gen("&&");
}
return max_k;
}
static int
#ifdef __USE_PROTOS
#else
int limit;
#endif
{
int k = 1;
int max_k = 0;
unsigned *e, *g, firstTime=1;
_gen(" 0 /* MR13 empty set expression - undefined rule ? infinite left recursion ? */ ");
};
if ( GenExprSetsOpt )
{
{
{
int e;
_gen1("(LA(%d)==",k);
}
else
{
NewSet();
}
if ( k == CLL_k ) break;
k++;
on1line++;
}
return max_k;
}
{
for (; *e!=nil; e++)
{
on1line++;
_gen1("LA(%d)==",k);
}
free( (char *)g );
_gen(")");
if ( k == CLL_k ) break;
k++;
on1line++;
}
return max_k;
}
/*
* Generate code for any type of block. If the last alternative in the block is
* empty (not even an action) don't bother doing it. This permits us to handle
* optional and loop blocks as well.
*
* Only do this block, return after completing the block.
* This routine is visible only to this file and cannot answer a TRANS message.
*/
static set
#ifdef __USE_PROTOS
#else
Junction *q;
int jtype;
int *max_k;
int *need_right_curly;
int *lastAltEmpty; /* MR23 */
#endif
{
set f;
int a_guess_in_block = 0;
*need_right_curly=0;
*lastAltEmpty = 0; /* MR23 */
{
{
};
/* MR10 disable */ /**** gen("if ( !zzrv )\n"); ****/
};
return empty; /* no decision to be made-->no error set */
}
{
{
{
/* we have empty alt */
/* MR23
There is a conflict between giving good error information for non-exceptions
and making life easy for those using parser exception handling. Consider:
r: { A } b;
b: B;
with input "C"
Before MR21 the error message would be "expecting B - found C". After MR21
the error message would be "expcect A, B - found C". This was good, but it
caused problems for those using parser exceptions because the reference to
B was generated inside the {...} where B really wasn't part of the block.
In MR23 this has been changed for the case where exceptions are in use to
not generate the extra check in the tail of the {A} block.
*/
/* MR23 */ if (FoundException) {
/* MR23 */ /* code to restore state if a prev alt didn't follow guess */
/* MR23 */ }
/* MR23 */ break;
/* MR23 */ };
/* MR28 */ break;
/* MR28 */ }
/* MR23 */ }
}
} /* end of for loop on alt */
/* MR10 */ };
/* MR10 */ };
else
{
if ( DemandLookahead ) {
}
}
if ( alt!=q )
{
_gen("{\n");
tabs++;
(*need_right_curly)++;
/* code to restore state if a prev alt didn't follow guess */
if ( a_guess_in_block )
gen("if ( !zzrv ) zzGUESS_DONE;\n");
}
{
a_guess_in_block = 1;
gen("zzGUESS\n");
}
gen("if ( ");
_gen(" ) ");
_gen("{\n");
tabs++;
--tabs;
gen("}\n");
/* MR10 */ tabs++;
/* MR10 */ (*need_right_curly)++;
/* MR10 */ /* code to restore state if a prev alt didn't follow guess */
/* MR10 */ };
/* MR10 */ };
}
return f;
}
static int
#ifdef __USE_PROTOS
#else
Junction *q;
#endif
{
{
}
return 0;
}
static int
#ifdef __USE_PROTOS
#else
Junction *q;
#endif
{
if (q == NULL) return 0;
}
/* MR30 See description of first_item_is_guess_block for background */
Junction *
#ifdef __USE_PROTOS
#else
Junction *q;
#endif
{
while ( q!=NULL &&
)
)
)
{
}
return q;
}
/* return NULL if 1st item of alt is NOT (...)? block; else return ptr to aSubBlk node
* of (...)?; This function ignores actions and predicates.
*/
Junction *
#ifdef __USE_PROTOS
#else
Junction *q;
#endif
{
/* MR14 Couldn't find aSubBlock which was a guess block when it lay
behind aLoopBlk. The aLoopBlk only appear in conjunction with
aLoopBegin, but the routine didn't know that. I think.
MR14a Added extra parentheses to clarify precedence
MR30 This appears to have been a mistake. The First set was then
computed incorrectly for:
r : ( (A)? B
| C
)*
The routine analysis_point was seeing the guess block when
it was still analyzing the loopBegin block. As a consequence,
when it looked for the analysis_point it was processing the B, but
skipping over the C alternative altogether because it thought
it was looking at a guess block, not realizing there was a loop
block in front of the loopBegin.
| | | ^ ^
| | | |
| +-> G C G ----------------------+ |
| |
+--- G G G -------------------------------------+
Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu).
MR30 This is still more complicated. This fix caused ambiguity messages
to be reported for "( (A B)? )* A B" but not for "( (A B)? )+". Why is
there a difference when these are outwardly identical ? It is because the
start of a (...)* block is represented by two nodes: a loopBegin block
followed by a loopBlock whereas the start of a (...)+ block is
represented as a single node: a plusBlock. So if first_item_is_guess_block
is called when the current node is a loopBegin it starts with the
loop block rather than the the sub block which follows the loop block.
However, we can't just skip past the loop block because some routines
depend on the old implementation. So, we provide a new implementation
which does skip the loopBlock. However, which should be called when ?
I'm not sure, but my guess is that first_item_is_guess_block_extra (the
new one) should only be called for the ambiguity routines.
*/
while ( q!=NULL &&
)
)
)
{
}
return q;
}
/* MR1 */
/* MR1 10-Apr-97 MR1 Routine to stringize failed semantic predicates msgs */
/* MR1 */
#define STRINGIZEBUFSIZE 1024
static char stringizeBuf[STRINGIZEBUFSIZE];
char *
#ifdef __USE_PROTOS
stringize(char * s)
#else
stringize(s)
char *s;
#endif
{
char *p;
char *stop;
p=stringizeBuf;
if (s != 0) {
while (*s != 0) {
if (p >= stop) {
goto stringizeStop;
} else if (*s == '\n') {
*p++='\\';
*p++='n';
*p++='\\';
*p++=*s++;
} else if (*s == '\\') {
*p++=*s;
*p++=*s++;
} else if (*s == '\"') {
*p++='\\';
*p++=*s++;
while (*s != 0) {
if (p >= stop) {
goto stringizeStop;
} else if (*s == '\n') {
*p++='\\';
*p++=*s++;
} else if (*s == '\\') {
*p++=*s++;
*p++=*s++;
} else if (*s == '\"') {
*p++='\\';
*p++=*s++;
break;
} else {
*p++=*s++;
};
};
} else if (*s == '\'') {
*p++=*s++;
while (*s != 0) {
if (p >= stop) {
goto stringizeStop;
} else if (*s == '\'') {
*p++=*s++;
break;
} else if (*s == '\\') {
*p++=*s++;
*p++=*s++;
} else if (*s == '\"') {
*p++='\\';
*p++=*s++;
break;
} else {
*p++=*s++;
};
};
} else {
*p++=*s++;
};
};
};
goto stringizeExit;
*p++='.';
*p++='.';
*p++='.';
*p=0;
return stringizeBuf;
}
#ifdef __USE_PROTOS
int isNullAction(char *s)
#else
int isNullAction(s)
char *s;
#endif
{
char *p;
for (p=s; *p != '\0' ; p++) {
if (*p != ';' && *p !=' ') return 0;
};
return 1;
}
/* MR1 */
/* MR1 End of Routine to stringize code for failed predicates msgs */
/* MR1 */
/* Generate an action. Don't if action is NULL which means that it was already
* handled as an init action.
*/
void
#ifdef __USE_PROTOS
genAction( ActionNode *p )
#else
genAction( p )
ActionNode *p;
#endif
{
{
if ( p->is_predicate)
{
{
gen("if (!");
}
/* MR10 */ }
else
{
gen("if (!(");
/* make sure that '#line n' is on front of line */
_gen(")");
}
/* MR23 Change failed predicate macro to have three arguments:
macro arg 1: The stringized predicate itself
macro arg 2: 0 => no user-defined error action
1 => user-defined error action
macro arg 3: The user-defined error action
This gives the user more control of the error action.
*/
tabs++;
tabs--;
}
else /* not a predicate */
{
if ( FoundGuessBlk ) {
if ( GenCC ) {
gen("if ( !guessing ) {\n");
} else {
gen("zzNON_GUESS_MODE {\n");
};
};
};
}
}
}
/*
* if invoking rule has !noAST pass zzSTR to rule ref and zzlink it in
* else pass addr of temp root ptr (&_ast) (don't zzlink it in).
*
* if ! modifies rule-ref, then never link it in and never pass zzSTR.
* Always pass address of temp root ptr.
*/
void
#ifdef __USE_PROTOS
genRuleRef( RuleRefNode *p )
#else
genRuleRef( p )
RuleRefNode *p;
#endif
{
Junction *q;
char *handler_id = "";
int genRuleRef_emittedGuessGuard=0; /* MR10 */
if ( r == NULL )
{
return;
}
/* MR8 5-Aug-97 Reported by S.Bochnak@microtool.com.pl */
/* Don't do assign when no return values declared */
/* Move definition of q up and use it to guard p->assign */
gen("_ast = NULL;\n");
}
if ( GenCC ) {
gen("if ( !guessing ) {\n");
} else {
gen("zzNON_GUESS_MODE {\n");
};
tabs++; /* MR11 */
};
tab();
if ( GenAST )
{
if ( GenCC ) {
/**** if ( r2->noAST || p->astnode==ASTexclude )
****/
{
/**** _gen("_ast = NULL;\n");
****/
parm = "&_ast";
}
/*** we always want to set just a pointer now, then set correct
pointer after
else {
_gen("_astp =
(_tail==NULL)?(&_sibling):(&(_tail->_right));\n");
parm = "_astp";
}
****/
}
else {
{
_gen("_ast = NULL; ");
parm = "&_ast";
}
else parm = "zzSTR";
}
{
}
if ( FoundException ) {
_gen5("%s%s(%s,&_signal%s%s); ",
p->text,
parm,
_gen("\n");
gen("if (_signal) {\n");
tabs++;
dumpException(p->ex_group, 0);
tabs--;
gen("}");
}
else {
}
}
else {
_gen5("%s%s(%s%s%s);",
p->text,
parm,
}
{
/* rule has a ! or element does */
/* still need to assign to #i so we can play with it */
_gen("\n");
}
{
/* rule doesn't have a ! and neither does element */
/* MR10 */ tabs++;
/* MR10 */ };
if ( GenCC ) {
_gen("\n");
gen("if ( _tail==NULL ) _sibling = _ast; else _tail->setRight(_ast);\n");
tab();
}
else _gen(" ");
if ( GenCC ) {
_gen("ASTBase::"); }
else _gen("zz");
_gen("link(_root, &_sibling, &_tail);");
/* MR10 */ tabs--;
/* MR10 */ };
}
}
else
{
{
}
if ( FoundException ) {
_gen4("%s%s(&_signal%s%s); ",
p->text,
_gen("\n");
gen("if (_signal) {\n");
tabs++;
dumpException(p->ex_group, 0);
tabs--;
gen("}");
}
else {
}
}
else {
_gen3("%s%s(%s);",
p->text,
}
}
{
_gen("\n");
_gen("}");
}
}
_gen("\n");
/* Handle element labels now */
{
if ( GenAST )
{
if ( GenCC ) {
}
}
else if (!GenCC ) {
}
}
/* in guessing mode, don't branch to handler upon error */
tabs--; /* MR11 */
gen("} else {\n");
tabs++; /* MR11 */
if ( FoundException ) {
gen6("%s%s(%s%s&_signal%s%s);\n",
p->text,
parm,
}
else {
gen5("%s%s(%s%s%s);\n",
p->text,
parm,
}
tabs--; /* MR11 */
gen("}\n");
}
}
/*
* Generate code to match a token.
*
* Getting the next token is tricky. We want to ensure that any action
* following a token is executed before the next GetToken();
*/
void
#ifdef __USE_PROTOS
#else
genToken( p )
TokNode *p;
#endif
{
RuleEntry *r;
char *handler_id = "";
ActionNode *a;
char *set_name;
char *set_nameErrSet;
int complement;
int ast_label_in_action = 0; /* MR27 */
int pushedCmodeAST = 0; /* MR27 */
/*
* MR27 Has the element label been referenced as an AST (with the # operator) ?
* If so, then we'll want to build the AST even though the user has used
* the ! operator.
*/
/* MR27 */ p->el_label);
/* MR27 */ }
{
unsigned e;
unsigned eErrSet = 0;
set b;
}
else {
}
}
/* MR23 - Forgot about the case of ~TOKCLASS. */
{
if ( p->tclass->dumpedComplement ) {
e = p->tclass->setnumComplement;
}
else {
p->tclass->setnumComplement = e;
}
}
else { /* wild card */
}
if ( !FoundException ) {
}
if ( p->use_def_MT_handler )
gen3("zzsetmatch_wdfltsig(%s,(ANTLRTokenType)%d,%s);",
p->token,
tokenFollowSet(p))
else
gen2("zzsetmatch_wsig(%s, %s_handler);",
}
else
{
tabs++;
/* MR6 */ if (FoundGuessBlk) {
/* MR6 */ };
gen("_signal=MismatchedToken;\n");
dumpException(p->ex_group, 0);
tabs--;
gen("}\n");
}
set_free(b);
}
{
if ( FoundException ) {
if ( p->use_def_MT_handler )
{
gen2("zzmatch_wsig(%s, %s_handler);",
TokenString(p->token),
}
else
{
/* MR6 */ if (GenCC) {
/* MR6 */ } else {
/* MR6 */ };
tabs++;
/* MR6 */ if (FoundGuessBlk) {
/* MR6 */ };
gen("_signal=MismatchedToken;\n");
dumpException(p->ex_group, 0);
tabs--;
gen("}\n");
}
}
}
else {
if ( FoundException ) {
if ( p->use_def_MT_handler )
gen2("zzmatch_wdfltsig((ANTLRTokenType)%d,%s);",
p->token,tokenFollowSet(p))
else
}
}
a = findImmedAction( p->next );
/* generate the token labels */
{
/* If building trees in C++, always gen the LT() assigns */
{
/* MR10 */ if ( FoundGuessBlk ) {
/* MR10 */ if (p->label_used_in_semantic_pred) {
/* MR10 */ } else {
/* MR10 */ };
/* MR10 */ } else {
/* MR10 */ };
/* MR10 */
}
/*
* MR23 labase is never used in the C++ runtime library.
* and this code is generated only in C++ mode
*/
/*** if ( LL_k>1 ) / * MR23 disabled */
/*** if ( !DemandLookahead ) _gen(" labase++;"); / * MR23 disabled */
/*** _gen("\n"); / * MR23 disabled */
/*** tab(); / * MR23 disabled */
}
if ( GenAST )
{
if ( FoundGuessBlk &&
{
}
/* MR27 addition when labels referenced when operator ! used */
pushedCmodeAST = 0; /* MR27 */
_gen("\n");
if (GenCC) {
/* MR13 */ if (NewAST) {
/* MR13 */ gen4("_ast%d%d = newAST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
/* MR13 */ } else {
/* MR13 */ gen4("_ast%d%d = new AST(_t%d%d); /* MR27 */\n", BlkLevel-1, p->elnum, BlkLevel-1, p->elnum);
/* MR13 */ }
}
else {
pushedCmodeAST = 1;
gen("zzastPush(zzmk_ast(zzastnew(),zzaCur)); /* MR27 */");
}
}
/* end MR27 addition for labels referenced when operator ! used */
if (!r->noAST )
{
_gen("\n");
/* MR13 */ if (NewAST) {
/* MR13 */ } else {
/* MR13 */ }
tab();
}
else _gen(" ");
_gen("subchild(_root, &_sibling, &_tail);");
}
_gen("subroot(_root, &_sibling, &_tail);");
}
_gen("\n");
tab();
}
}
else if ( !GenCC ) {
}
if ( FoundGuessBlk &&
}
/* Handle element labels now */
{
int done_NON_GUESSMODE=0;
_gen("\n");
/* MR10 */ /* do Attrib / Token ptr for token label used in semantic pred */
/* MR10 */ /* for these cases do assign even in guess mode */
/* MR10 */
/* MR10 */ if (p->label_used_in_semantic_pred) {
/* MR10 */ if ( GenCC ) {
/* MR10 */ } else {
/* MR10 */ };
/* MR10 */ } else {
/* MR10 */ };
/* MR10 */ };
/* Do Attrib / Token ptr */
/* MR10 */ if (! p->label_used_in_semantic_pred) {
/* MR10 */
/* MR10 */ if ( FoundGuessBlk ) {
/* MR10 */ if (! done_NON_GUESSMODE) {
/* MR10 */ };
/* MR10 */ };
/* MR10 */
/* MR10 */ if ( GenCC ) {
/* MR10 */ } else {
/* MR10 */ };
/* MR10 */ } else {
/* MR10 */ };
/* MR10 */ };
/* Do AST ptr */
{
/* MR10 */ if ( FoundGuessBlk ) {
/* MR10 */ if (! done_NON_GUESSMODE) {
/* MR10 */ };
/* MR10 */ };
if ( GenCC ) {
}
}
/* MR10 */ if (done_NON_GUESSMODE) {
/* MR10 */ };
}
/* Handle any actions immediately following action */
{
/* delay next token fetch until after action */
_gen("\n");
if ( a->is_predicate)
{
#if 0
/* Disabled in MR30 ************************************************************
And moved into genAction
*****************************************************************************
*/
gen("if (!(");
/* make sure that '#line n' is on front of line */ /* MR14 */
/* MR23 Change failed predicate macro to have three arguments:
macro arg 1: The stringized predicate itself
macro arg 2: 0 => no user-defined error action
1 => user-defined error action
macro arg 3: The user-defined error action
This gives the user more control of the error action.
*/
_gen(")) \n");
tabs++;
tabs--;
/* Disabled in MR30 ************************************************************
And moved into genAction
*****************************************************************************
*/
#endif
}
else /* MR9 a regular action - not a predicate action */
{
/* MR23: Search an action which is not a predicate for LT(i),
LA(i), or LATEXT(i) in order to warn novice users that
it refers to the previous matched token, not the next
one. This is different than the case for semantic
predicates.
*/
/* MR23 */ if (GenCC) {
/* MR23 */ }
/* MR23 */ else {
/* MR23 */ }
if ( FoundGuessBlk ) {
else gen("zzNON_GUESS_MODE {\n");
}
}
/*** a->done = 1; MR30 Moved up into then branch for true actions, but not predicates ***/
if ( !DemandLookahead ) {
if ( GenCC ) {
_gen(" consume();")
if ( FoundException && p->use_def_MT_handler )
_gen(" _signal=NoSignal;");
_gen("\n");
}
else
{
_gen(" zzCONSUME;\n");
_gen("\n");
}
}
else gen("\n");
if (a->done) { /* MR30 */
} /* MR30 */
else { /* MR30 */
} /* MR30 */
}
else
{
if ( !DemandLookahead ) {
if ( GenCC ) {
_gen(" consume();")
_gen("\n");
}
else {
_gen(" zzCONSUME;");
_gen("\n");
}
}
else _gen("\n");
}
}
/* MR21
*
* There was a bug in the code generation for {...} which causes it
* to omit the optional tokens from the error messages. The easiest
* way to fix this was to make the opt block look like a sub block:
*
* { a | b | c }
*
* becomes (internally):
*
* ( a | b | c | )
*
* The code for genOptBlk is now identical to genSubBlk except for
* cosmetic changes.
*/
void
#ifdef __USE_PROTOS
#else
genOptBlk( q )
Junction *q;
#endif
{
int max_k;
set f;
int need_right_curly;
int lastAltEmpty; /* MR23 */
BLOCK_Preamble(q);
BlkLevel++;
/* MR23
Bypass error clause generation when exceptions are used in {...} block
See multi-line note in genBlk near call to isEmptyAlt.
*/
if (! FoundException) {
}
else {
gen("/* MR23 skip error clause for {...} when exceptions in use */\n");
}
freeBlkFsets(q);
--BlkLevel;
BLOCK_Tail();
if ( q->guess )
{
gen("zzGUESS_DONE\n");
}
/* must duplicate if (alpha)?; one guesses (validates), the
* second pass matches */
if ( q->guess && analysis_point(q)==q )
{
BLOCK_Preamble(q);
BlkLevel++;
freeBlkFsets(q);
--BlkLevel;
BLOCK_Tail();
}
}
/*
* Generate code for a loop blk of form:
*
* |---|
* v |
* --o-G-o-->o--
*/
void
#ifdef __USE_PROTOS
#else
Junction *q;
int max_k;
#endif
{
set f;
int need_right_curly;
int singleAlt; /* MR10 */
int lastAltEmpty; /* MR23 */
if ( q->visited ) return;
/* first_item_is_guess_block doesn't care what kind of node it is */
{
if ( DemandLookahead ) {
}
gen("while ( ");
else genExpr(q);
/* if no predicates have been hoisted for this single alt (..)*
* do so now
*/
{
if ( a!=NULL )
{
_gen("&&");
}
/* MR10 */ if (MRhoisting) {
/* MR10 */ predicate_free(a);
/* MR10 */ };
}
_gen(" ) {\n");
tabs++;
if ( DemandLookahead ) {
}
--tabs;
gen("}\n");
freeBlkFsets(q);
return;
}
tabs++;
/* MR6 */
/* MR6 "begin" can never be null when called from genLoopBegin */
/* MR6 because q==(Junction *)begin->p1 and we know q is valid */
/* MR6 */
/* MR6 from genLoopBegin: */
/* MR6 */
/* MR6 if ( LL_k>1 && !set_nil(q->fset[2]) ) */
/* MR6 genLoopBlk( q, (Junction *)q->p1, q, max_k ); */
/* MR6 else genLoopBlk( q, (Junction *)q->p1, NULL, max_k ); */
/* MR6 */
{
if ( DemandLookahead )
{
}
/* The bypass arc of the (...)* predicts what to do when you fail, but
* ONLY after having tested the loop start expression. To avoid this,
* we simply break out of the (...)* loop when we find something that
* is not in the prediction of the loop (all alts thereof).
*/
gen("if ( !(");
/*** TJP says: It used to use the prediction expression for the bypass arc
of the (...)*. HOWEVER, if a non LL^1(k) decision was found, this
thing would miss the ftree stored in the aLoopBegin node and generate
an LL^1(k) decision anyway.
*** genExpr((Junction *)begin->p2);
***/
_gen(")) break;\n");
}
/* generate code for terminating loop (this is optional branch) */
set_free(f);
freeBlkFsets(q);
/* generate code for terminating loop (this is optional branch) */
/* MR6 */
/* MR6 30-May-97 Bug reported by Manuel Ornato */
/* MR6 A definite bug involving the exit from a loop block */
/* MR6 In 1.23 and later versions (including 1.33) Instead */
/* MR6 exiting the block and reporting a syntax error the */
/* MR6 code loops forever. */
/* MR6 Looking at 1.20 which generates proper code it is not */
/* MR6 clear which of two changes should be undone. */
/* MR6 This is my best guess. */
/* MR6 From earlier MR6 note we know that begin can never be */
/* MR6 null when genLoopBlk called from genLoopBegin */
/* MR6 */
/* MR6 */ /* code for exiting loop "for sure" */
/* MR6 */ };
/* MR10 */ tabs--;
/* MR10 */ need_right_curly--;
/* MR10 */ } else {
/* MR10 */ };
--tabs;
gen("}\n");
}
/*
* Generate code for a loop blk of form:
*
* |---|
* v |
* --o-->o-->o-G-o-->o--
* | ^
* v |
* o-----------o
*
* q->end points to the last node (far right) in the blk.
*
* Note that q->end->jtype must be 'EndBlk'.
*
* Generate code roughly of the following form:
*
* do {
* ... code for alternatives ...
* } while ( First Set of aLoopBlk );
*
* OR if > 1 alternative
*
* do {
* ... code for alternatives ...
* else break;
* } while ( 1 );
*/
void
#ifdef __USE_PROTOS
genLoopBegin( Junction *q )
#else
genLoopBegin( q )
Junction *q;
#endif
{
set f;
int i;
int max_k;
BLOCK_Preamble(q);
BlkLevel++;
/* If not simple LL(1), must specify to start at LoopBegin, not LoopBlk */
--BlkLevel;
BLOCK_Tail();
set_free(f);
/* MR21 */ if (MR_BlkErr) {
/* MR21 */ tabs++;
/* MR21 */ tab();
/* MR21 */ tab();
/* MR21 */ tabs--;
/* MR21 */ };
}
/*
* Generate code for a loop blk of form:
*
* |---|
* v |
* --o-G-o-->o--
*
* q->end points to the last node (far right) in the blk.
* Note that q->end->jtype must be 'EndBlk'.
*
* Generate code roughly of the following form:
*
* do {
* ... code for alternatives ...
* } while ( First Set of aPlusBlk );
*
* OR if > 1 alternative
*
* do {
* ... code for alternatives ...
* else if not 1st time through, break;
* } while ( 1 );
*/
void
#ifdef __USE_PROTOS
genPlusBlk( Junction *q )
#else
genPlusBlk( q )
Junction *q;
#endif
{
int max_k;
set f;
int need_right_curly;
int lastAltEmpty; /* MR23 */
int singleAlt; /* MR10 */
if ( q->visited ) return;
BLOCK_Preamble(q);
BlkLevel++;
/* first_item_is_guess_block doesn't care what kind of node it is */
/* if the ignore flag is set on the 2nd alt and that alt is empty,
* then it is the implied optional alternative that we added for (...)+
* and, hence, only 1 alt.
*/
/* MR10 Reported by Pulkkinen Esa (esap@cs.tut.fi)
* Outer code for guess blocks ignored when there is only one alt
* for a (...)+ block.
* Force use of regular code rather than "optimized" code for that case
*/
{
/* if the only alt has a semantic predicate, hoist it; must test before
* entering loop.
*/
if ( ParseWithPredicates )
{
a = MR_find_predicates_and_supp((Node *)q);
if ( a!=NULL ) {
gen("if (");
_gen(") {\n");
}
}
gen("do {\n");
tabs++;
if ( DemandLookahead ) {
}
--tabs;
gen("} while ( ");
genExpr(q);
if ( ParseWithPredicates && a!=NULL )
{
if (! MR_comparePredicates(q->predicate,a)) {
_gen("&&");
};
}
_gen(" );\n");
--BlkLevel;
BLOCK_Tail();
freeBlkFsets(q);
set_free(f);
/* MR21 */ if (MR_BlkErr) {
/* MR21 */ tabs++;
/* MR21 */ tab();
/* MR21 */ tab();
/* MR21 */ tabs--;
/* MR21 */ };
/* MR10 */ if (MRhoisting) {
/* MR10 */ predicate_free(a);
/* MR10 */ };
return;
}
gen("do {\n");
tabs++;
/* MR6 */
/* MR6 Sinan Karasu (sinan@tardis.ds.boeing.com) */
/* MR6 Failed to turn off guess mode when leaving block */
/* MR6 */
/* MR6 */ if ( has_guess_block_as_last_item(q) ) {
/* MR10 */ tabs++;
/* MR10 */ need_right_curly++;
/* MR10 */ } else {
/* MR10 */ tabs++;
/* MR10 */ need_right_curly++;
/* MR10 */ };
/* MR21 */ set f;
/* MR21 */ tabs++;
/* MR21 */ tab();
/* MR21 */ tabs--;
/* MR21 */ }
/* MR21 */ else {
tab();
/* MR21 I think this generates the wrong set ? */
/* MR21 because it includes the plus block bypass ? */
/* MR21 but I'm afraid to change it without additional checking */
}
freeBlkFsets(q);
gen("zzcnt++;");
_gen("\n");
if ( DemandLookahead ) {
}
--tabs;
else gen("} while ( 1 );\n");
--BlkLevel;
BLOCK_Tail();
/* MR21 */ if (MR_BlkErr) {
/* MR21 */ tabs++;
/* MR21 */ tab();
/* MR21 */ tab();
/* MR21 */ tabs--;
/* MR21 */ };
}
/*
* Generate code for a sub blk of alternatives of form:
*
* --o-G1--o--
* | ^
* v /|
* o-G2-o|
* | ^
* v |
* ..........
* | ^
* v /
* o-Gn-o
*
* q points to the 1st junction of blk (upper-left).
* q->end points to the last node (far right) in the blk.
* Note that q->end->jtype must be 'EndBlk'.
* The last node in every alt points to q->end.
*
* Generate code of the following form:
* if ( First(G1) ) {
* ...code for G1...
* }
* else if ( First(G2) ) {
* ...code for G2...
* }
* ...
* else {
* ...code for Gn...
* }
*/
void
#ifdef __USE_PROTOS
#else
genSubBlk( q )
Junction *q;
#endif
{
int max_k;
set f;
int need_right_curly;
int lastAltEmpty; /* MR23 */
BLOCK_Preamble(q);
BlkLevel++;
/* MR23
Bypass error clause generation when exceptions are used in a sub block
in which the last alternative is epsilon. Example: "(A | B | )".
See multi-line note in genBlk near call to isEmptyAlt.
*/
if (FoundException && lastAltEmpty) {
gen("/* MR23 skip error clause for (...| epsilon) when exceptions in use */\n");
}
else {
}
freeBlkFsets(q);
--BlkLevel;
BLOCK_Tail();
if ( q->guess )
{
gen("zzGUESS_DONE\n");
}
/* must duplicate if (alpha)?; one guesses (validates), the
* second pass matches */
if ( q->guess && analysis_point(q)==q )
{
BLOCK_Preamble(q);
BlkLevel++;
freeBlkFsets(q);
--BlkLevel;
BLOCK_Tail();
}
}
static int TnodesAllocatedPrevRule=0;
/*
* Generate code for a rule.
*
* rule--> o-->o-Alternatives-o-->o
* Or,
* rule--> o-->o-Alternative-o-->o
*
* The 1st junction is a RuleBlk. The second can be a SubBlk or just a junction
* (one alternative--no block), the last is EndRule.
* The second to last is EndBlk if more than one alternative exists in the rule.
*
* To get to the init-action for a rule, we must bypass the RuleBlk,
* and possible SubBlk.
* Mark any init-action as generated so genBlk() does not regenerate it.
*/
void
#ifdef __USE_PROTOS
#else
genRule( q )
Junction *q;
#endif
{
const char * returnValueInitializer;
do { /* MR10 Change recursion into iteration */
int max_k;
ActionNode *a;
RuleEntry *r;
int lastAltEmpty; /* MR23 */
static int file = -1;
int need_right_curly;
{
/* MR6 */
/* MR6 Simpler to debug when output goes to stdout rather than a file */
/* MR6 */
/* MR6 */ if (UseStdout) {
/* MR6 */ } else {
/* MR6 */ };
#ifdef SPECIAL_FOPEN
#endif
}
if (InfoM) {
};
#if 0
MR_break();
};
#endif
DumpFuncHeader(q,r);
tabs++;
/* MR23
If there is a single return value then it can be initialized in
the declaration using assignment syntax. If there are multiple
return values then antlr creates a struct and initialization takes
place element by element for each element of the struct. For
multiple elements the initialization is by assignment so we have
to wait until all declarations are done before emitting that code -
because of restrictions in C which don't exist in C++.
In the past (before MR23) the only kind of initialization was
the PURIFY macro which was just a memset() of 0. Now we allow
the user to specify an initial value. PURIFY is still used in C
mode because C does not have constructors. However, PURIFY is
not used in C++ mode because it might overwrite information created
by elements which have their own ctor.
*/
{
{
/* Emit initialization code later. */
}
else
{
/* Emit initialization code now. */
tab();
} /* MR23 */
else { /* MR23 */
} /* MR23 */
}
}
if (InfoM) {
};
gen("zzRULE;\n");
if ( FoundException )
{
gen("int _sva=1;\n");
}
gen("ASTBase *_ast = NULL, *_sibling = NULL, *_tail = NULL;\n");
if ( GenCC ) genTokenPointers(q);
/* MR10 */ /* move zzTRACEIN to before init action */
/* MR10 */ if ( TraceGen ) {
/* MR10 */ }
/* MR7 Moved PURIFY() to after all local variables have been declared */
/* MR7 so that the generated code is valid C as well as C++ */
/* MR7 Jan Mikkelsen 10-June-1997 */
/*
MR23 Do the PURIFY macro only for C mode.
C++ users should use constructors or initialization expressions.
*/
{ /* MR7 */
}
} /* MR7 */
else { /* MR7 */
/* MR23
If there were only one return value operand and
it had an initializer then it would have been
initiailized in the declaration.
*/
}
} /* MR23 */
} /* MR7 */
}
}
{
gen("zzGUESS_BLOCK\n");
}
/* L o o k F o r I n i t A c t i o n */
else
if ( a!=NULL && !a->is_predicate)
{
}
BlkLevel++;
--BlkLevel;
genTraceOut(q);
/* E r r o r R e c o v e r y */
NewSet();
/* MR14 */ if (r->dontComputeErrorSet) {
} else {
}
/* MR20 G. Hobbelt
Isn't it so that "fail:" is ONLY referenced when:
!FoundException || FoundGuessBlk ?
Therefore add the "if" around this piece of code generation...
Should guessing mode also use _handler label instead of "fail"
when exception handling is active? gen can automatically put
"if (guessing)" there so as to skip all kinds of user code.
*/
{ /* MR20 G. Hobbelt */
_gen("fail:\n");
if ( FoundGuessBlk ) {
else gen("if ( guessing ) zzGUESS_FAIL;\n");
}
if ( GenCC )
{
gen1("syn(zzBadTok, %s, zzMissSet, zzMissTok, zzErrk);\n",
}
else
{
gen1("zzsyn(zzMissText, zzBadTok, %s, zzMissSet, zzMissTok, zzErrk, zzBadText);\n",
}
genTraceOut(q);
gen("return _retv;\n");
} else if ( q->exceptions!=NULL ) {
genTraceOut(q);
gen("return;\n");
} else if (!FoundException) { /* MR10 */
genTraceOut(q); /* MR10 */
};
} /* MR20 G. Hobbelt */
/* Gen code for exception handlers */
/* make sure each path out contains genTraceOut() */
if ( q->exceptions!=NULL )
{
gen("/* exception handlers */\n");
dumpExceptions(q->exceptions);
if ( !r->has_rule_exception )
{
_gen("_handler:\n");
gen("zzdflthandlers(_signal,_retsignal);\n");
}
/* MR20 G. Gobbelt The label "adios" is never referenced */
#if 0
_gen("_adios:\n");
#endif
genTraceOut(q);
gen("return _retv;\n");
}
else {
genTraceOut(q);
gen("return;\n");
}
}
else if ( FoundException )
{
_gen("_handler:\n");
gen("zzdflthandlers(_signal,_retsignal);\n");
/* MR1 */
/* MR1 7-Apr-97 Fix suggested by: John Bair (jbair@iftime.com) */
/* MR1 */
genTraceOut(q); /* MR10 */
} else { /* MR1 */
genTraceOut(q); /* MR10 */
}; /* MR1 */
}
tabs--;
gen("}\n");
/* MR10 Tired of looking at stacks that are as deep as the number of */
/* MR10 rules. Changes recursion to iteration. */
if (InfoT) {
};
} while (q != NULL);
/**** The old code ****/
/**** if ( q->p2 != NULL ) {TRANS(q->p2);} ****/ /* generate code for next rule too */
/**** else dumpAfterActions( output ); ****/
}
/* This is for the function definition, not the declaration. */
static void
#ifdef __USE_PROTOS
#else
DumpFuncHeader( q, r )
Junction *q;
RuleEntry *r;
#endif
{
/* */
/* MR1 10-Apr-97 MR1 Simplify insertion of commas in function header */
/* */
int needComma; /* MR1 */
/* A N S I */
_gen("\n");
{
{
}
else
{
gen("\n");
}
}
else
{
_gen("void\n");
}
/* MR1 */
/* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */
/* MR1 */
/* If we generate C++ method names, we must hide default arguments */
/* which can appear in the parameter declaration list. */
/* NOTICE: this is done only here, for the method definition, but */
/* not for the method declaration inside the class */
/* definition. This is exactly the behaviour defined in */
/* C++ standard for default paramters. */
_gen("\n");
if ( GenCC ) {
gen("{\n");
return;
}
/* K & R */
gen("#else\n");
needComma=0; /* MR1 */
if ( GenAST ) /* MR1 */
{ /* MR1 */
} /* MR1 */
if ( FoundException ) /* MR1 */
{ /* MR1 */
} /* MR1 */
/* MR5 Change below by Jan Mikkelsen (janm@zeta.org.au) 26-May-97 MR5 */
gen(")\n");
gen("#endif\n");
gen("{\n");
}
void
#ifdef __USE_PROTOS
#else
FILE *f;
Junction *q;
int bInitializer;
#endif
{
if ( GenAST )
{
else fprintf(f,"AST**_root");
}
if ( FoundException )
{
fprintf(f,"int *_retsignal");
fprintf(f,",");
}
}
}
else {
if ( !GenAST && !FoundException ) {
fprintf(f,"void");
}
}
fprintf(f,")");
}
void
#ifdef __USE_PROTOS
genJunction( Junction *q )
#else
genJunction( q )
Junction *q;
#endif
{
}
void
#ifdef __USE_PROTOS
#else
genEndBlk( q )
Junction *q;
#endif
{
}
void
#ifdef __USE_PROTOS
genEndRule( Junction *q )
#else
genEndRule( q )
Junction *q;
#endif
{
}
void
#ifdef __USE_PROTOS
#else
int file;
#endif
{
int i;
_gen("/*\n");
_gen(" * A n t l r T r a n s l a t i o n H e a d e r\n");
_gen(" *\n");
_gen(" * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
_gen(" * Purdue University Electrical Engineering\n");
_gen(" * With AHPCRC, University of Minnesota\n");
_gen(" *\n");
/* MR10 */ for (i=0 ; i < Save_argc ; i++) {
/* MR10 */ };
_gen("\n");
_gen(" *\n");
_gen(" */\n\n");
_gen("#include \"pcctscfg.h\"\n");
_gen("#include \"pccts_stdio.h\"\n");
if ( GenCC ) {
if ( UserTokenDefsFile != NULL )
else
}
if ( !GenCC && FoundGuessBlk )
{
_gen("#define ZZCAN_GUESS\n");
}
if ( FoundException )
{
_gen("#define EXCEPTION_HANDLING\n");
}
if ( GenAST ) {
}
#ifdef DUM
}
#endif
/* ###WARNING: This will have to change when SetWordSize changes */
if (TraceGen) {
};
else {
}
if ( !GenCC ) {
if ( UserDefdTokens )
/* still need this one as it has the func prototypes */
}
/* still need this one as it defines the DLG interface */
/* MR10 Ofer Ben-Ami (gremlin@cs.huji.ac.il) */
/* MR10 Finally, a definition of the Purify macro */
_gen("#ifndef PCCTS_PURIFY\n");
_gen("#define PCCTS_PURIFY(r,s) memset((char *) &(r),'\\0',(s));\n");
_gen("#endif\n\n");
} /* MR23 */
}
void
#ifdef __USE_PROTOS
#else
int file;
#endif
{
ListNode *p;
if ( GenAST )
{
if ( !GenCC ) {
_gen("zzASTgvars\n\n");
}
}
if ( BeforeActions != NULL )
{
{
}
}
if ( !FoundException ) return;
if ( GenCC )
{
_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
_gen("{\n");
}
else
{
_gen("\nvoid\n");
/* MR1 */
/* MR1 10-Apr-97 133MR1 Replace __STDC__ with __USE_PROTOS */
/* MR1 */
_gen("zzdflthandlers( int _signal, int *_retsignal )\n");
_gen("#else\n");
_gen("zzdflthandlers( _signal, _retsignal )\n");
_gen("int _signal;\n");
_gen("int *_retsignal;\n");
_gen("#endif\n");
_gen("{\n");
}
tabs++;
if ( DefaultExGroup!=NULL )
{
if ( !hasDefaultException(DefaultExGroup) )
{
gen("default :\n");
tabs++;
gen("*_retsignal = _signal;\n");
tabs--;
gen("}\n");
}
}
else {
gen("*_retsignal = _signal;\n");
}
tabs--;
_gen("}\n\n");
}
void
#ifdef __USE_PROTOS
#else
FILE *f;
char * gate; /* MR10 */
#endif
{
/* MR10 Ramanathan Santhanam (ps@kumaran.com) */
/* MR10 Same preprocessor symbol use to gate stdpccts.h */
/* MR10 even when two grammars are in use. */
/* MR10 Derive gate symbol from -fh filename */
} else {
};
fprintf(f,"/*\n");
} else {
}
fprintf(f," *\n");
fprintf(f," * Terence Parr, Will Cohen, and Hank Dietz: 1989-2001\n");
fprintf(f," * Purdue University Electrical Engineering\n");
fprintf(f," * With AHPCRC, University of Minnesota\n");
fprintf(f," */\n\n");
fprintf(f,"#ifndef ANTLR_VERSION\n");
fprintf(f,"#endif\n\n");
fprintf(f,"#include \"pcctscfg.h\"\n");
fprintf(f,"#include \"pccts_stdio.h\"\n");
if ( GenCC )
{
if ( UserDefdTokens )
else {
}
if ( GenAST ) {
}
if (TraceGen) {
};
fprintf(f, "#endif\n");
return;
}
if ( UserTokenDefsFile != NULL )
if ( FoundGuessBlk )
{
fprintf(f,"#define ZZCAN_GUESS\n");
fprintf(f,"#include \"pccts_setjmp.h\"\n");
}
if (TraceGen) {
};
if ( FoundException )
{
/* MR1 7-Apr-97 1.33MR1 */
/* MR1 Fix suggested by: */
/* MR1 Francois-Xavier Fontaine (fontaine_f@istvax.ist.lu) */
}
#ifdef DUM
#endif
/* ###WARNING: This will have to change when SetWordSize changes */
if (TraceGen) {
};
if ( UserDefdTokens )
/* still need this one as it has the func prototypes */
/* still need this one as it defines the DLG interface */
/* don't need this one unless DLG is used */
fprintf(f,"#endif\n");
}
/* dump action 's' to file 'output' starting at "local" tab 'tabs'
Dump line information in front of action if GenLineInfo is set
If file == -1 then GenLineInfo is ignored.
most compilers will like the default, however.
June '93; changed so that empty lines are left alone so that
*/
void
#ifdef __USE_PROTOS
int final_newline )
#else
char *s;
int tabs;
int file;
int line;
int final_newline;
#endif
{
{
}
PastWhiteSpace( s );
/* don't print a tab if first non-white char is a # (preprocessor command) */
if ( *s!='#' ) {TAB;}
while ( *s != '\0' )
{
if ( *s == '\\' )
{
if ( *s == '\0' ) return;
}
if ( *s == '\'' )
{
}
if ( *s == '"' )
{
}
if ( *s == '\n' )
{
s++;
PastWhiteSpace( s );
if ( *s == '}' )
{
--tabs;
TAB;
continue;
}
if ( *s == '\0' ) return;
if ( *s != '#' ) /* #define, #endif etc.. start at col 1 */
{
TAB;
}
}
{
--tabs; /* Indent one fewer */
}
{
tabs++; /* Indent one more */
}
s++;
}
}
static void
#ifdef __USE_PROTOS
#else
#endif
{
ListNode *p;
if ( AfterActions != NULL )
{
{
}
}
}
/*
* Find the next action in the stream of execution. Do not pass
* junctions with more than one path leaving them.
* Only pass generic junctions.
*
* Scan forward while (generic junction with p2==NULL)
* If we stop on an action, return ptr to the action
* else return NULL;
*/
static ActionNode *
#ifdef __USE_PROTOS
findImmedAction( Node *q )
#else
findImmedAction( q )
Node *q;
#endif
{
Junction *j;
{
j = (Junction *)q;
q = j->p1;
}
return NULL;
}
static void
#ifdef __USE_PROTOS
#else
char *retval;
char *ret_def;
#endif
{
char *q = ret_def;
tab();
{
DumpNextNameInDef(&q, output);
while ( isspace(*q) ) q++;
}
}
}
}
/* This function computes the set of tokens that can possibly be seen k
* tokens in the future from point j
*/
static set
#ifdef __USE_PROTOS
#else
ComputeErrorSet( j, k, usePlusBlockBypass )
Junction *j;
int k;
int usePlusBlockBypass;
#endif
{
{
set_orin(&f, a);
set_free(a);
}
return f;
}
static char *
#ifdef __USE_PROTOS
#else
TokNode *p;
#endif
{
static char buf[100];
int n;
set_free(a);
if ( GenCC )
else
return buf;
}
static void
#ifdef __USE_PROTOS
#else
Junction *q;
set f;
int max_k;
int usePlusBlockBypass;
#endif
{
int nilf=0; /* MR13 */
if ( FoundException )
{
_gen("else {\n");
tabs++;
if ( FoundGuessBlk )
{
else gen("if ( zzguessing ) goto fail;\n");
}
gen("if (_sva) _signal=NoViableAlt;\n");
gen("else _signal=NoSemViableAlt;\n");
#if 0
} else {
gen("*** DEBUG *** outerEG==NULL\n");
#endif
};
tabs--;
gen("}\n");
return;
}
if ( max_k == 1 )
{
if ( GenCC ) {
} else {
};
set_free(f);
}
else
{
int i;
set_free(f);
for (i=1; i<=max_k; i++)
{
/* MR14 */ f=empty;
} else {
}
set_free(f);
}
}
_gen(",&zzMissSet,&zzMissText,&zzBadTok,&zzBadText,&zzErrk); goto fail;}\n");
/* MR13 */ if (nilf) {
/* MR13 */ errFL("empty error set for alt - probably because of undefined rule or infinite left recursion",
/* MR13 */ gen(" /* MR13 empty error set for this alt - undef rule ? infinite left recursion ? */");
/* MR13 */ };
}
static /* MR7 */
#ifdef __USE_PROTOS
#else
#endif
{
}; /* MR7 */
}; /* MR7 */
}; /* MR7 */
} /* MR7 */
/*** debug ***/
#if 0
** static /* MR7 */
** #ifdef __USE_PROTOS
** #else
** #endif
** { /* MR7 */
** /* MR7 */
** }; /* MR7 */
** } /* MR7 */
#endif
#ifdef __USE_PROTOS
#else
int line;
char * fileName;
#endif
{
static char * prevFileName=NULL;
static char * prevFileNameMS=NULL;
char * p;
char * q;
if (! GenLineInfo) return;
if (!GenLineInfoMS) {
} else {
if (fileName == prevFileName) {
} else {
for (p=fileName; *p != 0; p++) {
*q=*p;
if (*q == '\\') *q='/';
q++;
}
}
};
}
#if 0
/* MR21 */
#ifdef __USE_PROTOS
#else
void OutFirstSetSymbol(q, pSymbol)
Junction* q;
char * pSymbol
#endif
{
set f;
set_free(f);
}
#endif
/* MR21 */
#ifdef __USE_PROTOS
#else
void BlockPreambleOption(q, pSymbol)
Junction* q;
char * pSymbol;
#endif
{
}
set_free(f);
}
/* MR21 */
void
#ifdef __USE_PROTOS
int final_newline )
#else
ActionNode *a;
char *s;
int tabs;
int file;
int line;
int final_newline;
#endif
{
}
#if 0
** #ifdef __USE_PROTOS
** #else
** Junction *q;
** int max_k;
** int usePlusBlockBypass;
** #endif
** {
** int k;
** Junction* p;
**
**
**
**
** for (k = 1; k <= max_k; k++) {
** {
** }
** }
** }
#endif
#ifdef __USE_PROTOS
#else
RuleEntry *r;
char * pReturn;
#endif
{
char *p = pReturn;
char *pDataType;
char *pSymbol;
char *pEqualSign;
char *pValue;
char *pSeparator;
int nest = 0;
char *q;
while (*p != 0) {
p = endFormal(p,
&pSymbol,
&pValue,
&nest);
if (nest != 0) return;
tab();
}
}
}
#ifdef __USE_PROTOS
#else
char * pReturn;
int bInitializer;
#endif
{
char *p = pReturn;
char *pDataType;
char *pSymbol;
char *pEqualSign;
char *pValue;
char *pSeparator;
int nest = 0;
char *q;
int count = 0;
while (*p != 0) {
p = endFormal(p,
&pSymbol,
&pValue,
&nest);
if (nest != 0) return;
if (bInitializer != 0) {
}
}
}
count++;
}
}
/* MR23 Check for empty alt in a more intelligent way.
Previously, an empty alt for genBlk had to point directly
to the endBlock. This did not work once I changed {...}
blocks to look like (...|...| epsilon) since there were
intervening generics. This fixes the problem for this
particular case. Things like actions or empty blocks of
various kinds will still cause problems, but I wasnt't
prepared to handle pathological cases like (A|()*). It
does handle (A | ()), which is a recommended idiom for
epsilon.
Actually, this isn't quite correct since it doesn't handle
the case of the ignore bit in the plus block bypass, but
I'm too tired to figure out the correct fix, and will just
work around it.
*/
#ifdef __USE_PROTOS
#else
#endif
{
Junction * j;
while (n != endBlock) {
switch (n->ntype) {
case nRuleRef:
return 0;
case nToken:
return 0;
case nAction:
return 0;
case nJunction:
goto JUNCTION;
default:
fatal_internal("Invalid node type");
return 0;
}
j = (Junction *) n;
switch (j->jtype) {
case Generic:
{
n = j->p1;
goto NEXT;
}
case aSubBlk:
{
n = j->p1; /* MR26 */
goto NEXT; /* MR26 */
}
case EndBlk:
return 0;
case EndRule:
return 1;
default:
return 0;
}
NEXT: continue;
}
return 1;
}