mirror of https://github.com/acidanthera/audk.git
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 "expcect A, B - found C". This was good, but it
|
||
|
caused problems for those using parser exceptions because the reference to
|
||
|
B was generated inside the {...} where B really wasn't part of the block.
|
||
|
|
||
|
In MR23 this has been changed for the case where exceptions are in use to
|
||
|
not generate the extra check in the tail of the {A} block.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/* MR23 */ if (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 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 */
|
||
|
"0; /* 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")+10];
|
||
|
static char bufErrSet[sizeof("zzerr")+10];
|
||
|
int n = DefErrSet( &b, 0, NULL );
|
||
|
int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set");
|
||
|
if ( GenCC ) sprintf(buf, "err%d", n);
|
||
|
else sprintf(buf, "zzerr%d", n);
|
||
|
if ( GenCC ) sprintf(bufErrSet, "err%d", nErrSet);
|
||
|
else sprintf(bufErrSet, "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 */
|
||
|
"0; /* 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
|
||
|
initiailized 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 paramters. */
|
||
|
|
||
|
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 */ _gen(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 %d\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 %d\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 wasnt't
|
||
|
prepared to handle pathological cases like (A|()*). It
|
||
|
does handle (A | ()), which is a recommended idiom for
|
||
|
epsilon.
|
||
|
|
||
|
Actually, this isn't quite correct since it doesn't handle
|
||
|
the case of the ignore bit in the plus block bypass, but
|
||
|
I'm too tired to figure out the correct fix, and will just
|
||
|
work around it.
|
||
|
*/
|
||
|
|
||
|
#ifdef __USE_PROTOS
|
||
|
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;
|
||
|
}
|