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