mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-28 12:25:19 +01:00
b1264ef1e3
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
3031 lines
81 KiB
C
Executable File
3031 lines
81 KiB
C
Executable File
/*
|
|
* mrhoist.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.33MR10
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "pcctscfg.h"
|
|
|
|
#include "set.h"
|
|
#include "syn.h"
|
|
#include "hash.h"
|
|
#include "generic.h"
|
|
#include "dlgdef.h"
|
|
#include <ctype.h>
|
|
|
|
#ifdef __USE_PROTOS
|
|
void dumppred(Predicate *);
|
|
#else
|
|
void dumppred();
|
|
#endif
|
|
|
|
/*
|
|
Try to determine whether predicate "first" is true for
|
|
all cases where "second" is true. Comparison takes place
|
|
without regard to context.
|
|
Assumes that predicate symbols have been expanded.
|
|
Assumes that there are no NAND or NOR nodes
|
|
|
|
*/
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_secondPredicateUnreachable(Predicate *first,Predicate *second)
|
|
#else
|
|
int MR_secondPredicateUnreachable(first,second)
|
|
Predicate *first;
|
|
Predicate *second;
|
|
#endif
|
|
{
|
|
Predicate *f;
|
|
Predicate *s;
|
|
|
|
if (first == NULL) {
|
|
return 1;
|
|
} else if (second == NULL) {
|
|
return 0;
|
|
} else if (first->down == NULL && second->down == NULL) {
|
|
if (first->source == second->source &&
|
|
first->inverted == second->inverted) {
|
|
return 1; /* look identical - will never reach alt2 */
|
|
} else {
|
|
return 0; /* look different */
|
|
};
|
|
} else if (first->down == NULL && second->down != NULL) {
|
|
|
|
if (second->expr == PRED_AND_LIST) {
|
|
|
|
/* unreachable if first covers any child of second */
|
|
|
|
for (s=second->down; s != NULL; s=s->right) {
|
|
if (MR_secondPredicateUnreachable(first,s)) {
|
|
return 1;
|
|
};
|
|
};
|
|
return 0;
|
|
} else if (second->expr == PRED_OR_LIST) {
|
|
|
|
/* unreachable if first covers every child of second */
|
|
|
|
for (s=second->down; s != NULL; s=s->right) {
|
|
if (!MR_secondPredicateUnreachable(first,s)) {
|
|
return 0;
|
|
};
|
|
};
|
|
return 1;
|
|
} else {
|
|
require (0,"Illegal pred->expr");
|
|
return 0; /* MR20 Make compiler happy */
|
|
};
|
|
} else if (first->down != NULL && second->down == NULL) {
|
|
if (first->expr == PRED_AND_LIST) {
|
|
|
|
/* unreachable if every child of first covers second */
|
|
|
|
for (f=first->down; f != NULL; f=f->right) {
|
|
if (!MR_secondPredicateUnreachable(f,second)) {
|
|
return 0;
|
|
};
|
|
};
|
|
return 1;
|
|
} else if (first->expr == PRED_OR_LIST) {
|
|
|
|
/* unreachable if any child of first covers second */
|
|
|
|
for (f=first->down; f != NULL; f=f->right) {
|
|
if (MR_secondPredicateUnreachable(f,second)) {
|
|
return 1;
|
|
};
|
|
};
|
|
return 0;
|
|
} else {
|
|
require (0,"Illegal predicate->expr");
|
|
return 0; /* MR20 Make compiler happy */
|
|
};
|
|
} else {
|
|
|
|
if (first->expr == PRED_AND_LIST && second->expr == PRED_AND_LIST) {
|
|
|
|
/* unreachable if each child of first covers at least one child of second */
|
|
|
|
for (f=first->down; f != NULL ; f=f->right) {
|
|
for (s=second->down; s != NULL ; s=s->right) {
|
|
if (MR_secondPredicateUnreachable(f,s)) goto A_next_f;
|
|
};
|
|
return 0;
|
|
A_next_f:
|
|
continue;
|
|
};
|
|
return 1;
|
|
|
|
} else if (first->expr == PRED_AND_LIST && second->expr == PRED_OR_LIST) {
|
|
|
|
/* unreachable if each child of first covers ALL of second's children */
|
|
|
|
for (f=first->down; f != NULL ; f=f->right) {
|
|
for (s=second->down; s != NULL ; s=s->right) {
|
|
if (!MR_secondPredicateUnreachable(f,s)) return 0;
|
|
};
|
|
};
|
|
return 1;
|
|
|
|
} else if (first->expr == PRED_OR_LIST && second->expr == PRED_AND_LIST) {
|
|
|
|
/* unreachable if any child of second is covered by any child of first */
|
|
|
|
for (f=first->down; f != NULL ; f=f->right) {
|
|
for (s=second->down; s != NULL ; s=s->right) {
|
|
if (MR_secondPredicateUnreachable(f,s)) return 1;
|
|
};
|
|
};
|
|
return 0;
|
|
|
|
} else if (first->expr == PRED_OR_LIST && second->expr == PRED_OR_LIST) {
|
|
|
|
/* unreachable if every child of second is covered by some child of first */
|
|
|
|
for (f=first->down; f != NULL ; f=f->right) {
|
|
for (s=second->down; s != NULL ; s=s->right) {
|
|
if (MR_secondPredicateUnreachable(f,s)) goto B_next_f;
|
|
};
|
|
return 0;
|
|
B_next_f:
|
|
continue;
|
|
};
|
|
return 1;
|
|
|
|
} else {
|
|
require (0,"Illegal predicate->expr");
|
|
return 0; /* MR20 Make compiler happy */
|
|
};
|
|
};
|
|
return 0; /* MR20 MSVC 5.0 complains about missing return statement */
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_xxxIndent(FILE *f,int depth)
|
|
#else
|
|
void MR_xxxIndent(f,depth)
|
|
FILE *f;
|
|
int depth;
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<depth ; i++) {
|
|
fprintf(f," ");
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_stderrIndent(int depth)
|
|
#else
|
|
void MR_stderrIndent(depth)
|
|
int depth;
|
|
#endif
|
|
{
|
|
MR_xxxIndent(stderr,depth);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_outputIndent(int depth)
|
|
#else
|
|
void MR_outputIndent(depth)
|
|
int depth;
|
|
#endif
|
|
{
|
|
MR_xxxIndent(output,depth);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_set_reuse(set *s)
|
|
#else
|
|
void MR_set_reuse(s)
|
|
set *s;
|
|
#endif
|
|
{
|
|
set_free(*s);
|
|
*s=empty;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_dumpPredRuleRefStack(FILE *iounit,int indent)
|
|
#else
|
|
void MR_dumpPredRuleRefStack(iounit,indent)
|
|
FILE *iounit;
|
|
int indent;
|
|
#endif
|
|
{
|
|
int i;
|
|
int j;
|
|
int count=MR_PredRuleRefStack.count;
|
|
RuleRefNode *rrn=NULL;
|
|
Junction *lastOne;
|
|
|
|
if (count == 0) {
|
|
fprintf(iounit,"empty\n");
|
|
return;
|
|
};
|
|
for (i=0; i < count; i++) {
|
|
rrn=(RuleRefNode *) MR_PredRuleRefStack.data[i];
|
|
for (j=0; j<indent; j++) fprintf(iounit," ");
|
|
fprintf(iounit,"#%-2d in rule %s (line %d %s) to rule %s\n",
|
|
i,rrn->rname,rrn->line,FileStr[rrn->file],rrn->text);
|
|
};
|
|
lastOne=MR_ruleReferenced(rrn);
|
|
if (lastOne != NULL) {
|
|
for (j=0; j<indent; j++) fprintf(iounit," ");
|
|
fprintf(iounit,"#%-2d in rule %s (line %d %s)\n",
|
|
count,lastOne->rname,lastOne->line,FileStr[lastOne->file]);
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_dumpTreeF(FILE *f,int depth,Tree *tree,int across)
|
|
#else
|
|
void MR_dumpTreeF(f,depth,tree,across)
|
|
FILE *f;
|
|
Tree *tree;
|
|
int depth;
|
|
int across;
|
|
#endif
|
|
{
|
|
int newAcross=across;
|
|
|
|
if (tree == NULL ) return;
|
|
if (tree->down != NULL ) {
|
|
fprintf(output,"\n");
|
|
MR_outputIndent(depth);
|
|
fprintf(output, "(root =");
|
|
};
|
|
if (tree->token == ALT ) {
|
|
fprintf(output," %-16s","Alt");
|
|
} else if (tree->token==EpToken ) {
|
|
fprintf(output,"(%d)%13s",tree->v.rk," ");
|
|
} else {
|
|
fprintf(output," %-16s",TerminalString(tree->token));
|
|
};
|
|
if (tree->down != NULL) {
|
|
fprintf(output,"\n");
|
|
MR_outputIndent(depth+1);
|
|
MR_dumpTreeF(f,depth+1,tree->down,1);
|
|
newAcross=0;
|
|
fprintf(output,"\n");
|
|
MR_outputIndent(depth);
|
|
fprintf(output,")");
|
|
};
|
|
if (newAcross > 3) {
|
|
fprintf(output,"\n");
|
|
MR_outputIndent(depth);
|
|
newAcross=0;
|
|
};
|
|
MR_dumpTreeF(f,depth,tree->right,newAcross+1);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_dumpTreeX(int depth,Tree *tree,int across)
|
|
#else
|
|
void MR_dumpTreeX(depth,tree,across)
|
|
Tree *tree;
|
|
int depth;
|
|
int across;
|
|
#endif
|
|
{
|
|
MR_dumpTreeF(output,depth,tree,across);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_dumpTokenSet(FILE *f,int depth,set s)
|
|
#else
|
|
void MR_dumpTokenSet(f,depth,s)
|
|
FILE *f;
|
|
int depth;
|
|
set s;
|
|
#endif
|
|
{
|
|
int i;
|
|
int j;
|
|
|
|
unsigned *pdq;
|
|
|
|
if (set_nil(s)) {
|
|
fprintf(f,"\n");
|
|
MR_xxxIndent(f,depth+1);
|
|
fprintf(f,"nil\n");
|
|
return;
|
|
};
|
|
|
|
pdq=set_pdq(s);
|
|
require(pdq != NULL,"set_pdq failed");
|
|
i=0;
|
|
for (i=0 ; ; i=i+4) {
|
|
fprintf(f,"\n");
|
|
MR_xxxIndent(f,depth+1);
|
|
for (j=0; j < 4 ; j++) {
|
|
if (pdq[i+j] == nil) break;
|
|
fprintf(f," %-16s",TerminalString(pdq[i+j]));
|
|
};
|
|
if (pdq[i+j] == nil) break;
|
|
};
|
|
fprintf(f,"\n");
|
|
free( (char *) pdq);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_dumpPred1(int depth,Predicate *p,int withContext)
|
|
#else
|
|
void MR_dumpPred1(depth,p,withContext)
|
|
int depth;
|
|
Predicate *p;
|
|
int withContext;
|
|
#endif
|
|
{
|
|
unsigned k;
|
|
|
|
if (p == NULL) {
|
|
MR_outputIndent(depth);
|
|
fprintf(output,"The predicate is empty (or always true)\n\n");
|
|
return;
|
|
};
|
|
if (p->down != NULL) {
|
|
MR_outputIndent(depth);
|
|
if (p->inverted) {
|
|
|
|
/* MR14a Left out print expression in fprintf
|
|
Reported by Manuel Kessler (mlkessle@cip.physik.uni-wuerzburg.de)
|
|
*/
|
|
|
|
if (p->expr == PRED_AND_LIST) fprintf(output,"%s NAND (not AND) expr\n\n",p->expr);
|
|
if (p->expr == PRED_OR_LIST) fprintf(output,"%s NOR (not OR) expr\n\n",p->expr);
|
|
} else {
|
|
fprintf(output,"%s expr\n\n",p->expr);
|
|
};
|
|
} else {
|
|
MR_outputIndent(depth);
|
|
fprintf(output,"pred %s <<%s>>?\n",
|
|
(p->inverted ? " *not*" : ""),
|
|
(p->expr == NULL ? "null expr" : p->expr));
|
|
MR_outputIndent(depth+1);
|
|
fprintf(output," ");
|
|
fprintf(output," depth=k=%d",p->k);
|
|
if (p->source != NULL && p->source->guardpred) {
|
|
fprintf(output," (\"=>\" guard)");
|
|
}
|
|
if (p->source != NULL && p->source->ampersandPred != NULL) {
|
|
fprintf(output," (\"&&\" guard)");
|
|
};
|
|
k=set_int(p->completionSet);
|
|
if (k != nil) {
|
|
fprintf(output," Incomplete Set at k=%d !",k);
|
|
};
|
|
k=set_int(p->completionTree);
|
|
if (k != nil) {
|
|
fprintf(output," Incomplete Tree at k=%d !",k);
|
|
};
|
|
if (p->source != NULL) {
|
|
fprintf(output," rule %s line %d %s",
|
|
p->source->rname,p->source->line,FileStr[p->source->file]);
|
|
};
|
|
fprintf(output,"\n");
|
|
if (withContext &&
|
|
(HoistPredicateContext ||
|
|
! set_nil(p->scontext[1]) ||
|
|
p->tcontext != NULL)) {
|
|
if (p->k == 1) {
|
|
MR_outputIndent(depth+1);
|
|
fprintf(output,"set context: ");
|
|
MR_dumpTokenSet(output,depth+1,p->scontext[1]);
|
|
}
|
|
if (p->k != 1) {
|
|
MR_outputIndent(depth+1);
|
|
fprintf(output,"tree context:");
|
|
if (p->tcontext == NULL) {
|
|
fprintf(output," null");
|
|
} else {
|
|
MR_dumpTreeX(depth+2,p->tcontext,0);
|
|
};
|
|
fprintf(output,"\n");
|
|
};
|
|
};
|
|
fprintf(output,"\n");
|
|
};
|
|
if (p->down != NULL) {
|
|
MR_dumpPred1(depth+1,p->down,withContext);
|
|
};
|
|
if (p->right != NULL) {
|
|
MR_dumpPred1(depth,p->right,withContext);
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_dumpPred(Predicate *p,int withContext)
|
|
#else
|
|
void MR_dumpPred(p,withContext)
|
|
Predicate *p;
|
|
int withContext;
|
|
#endif
|
|
{
|
|
MR_dumpPred1(0,p,withContext);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree * MR_make_tree_from_set(set s)
|
|
#else
|
|
Tree * MR_make_tree_from_set(s)
|
|
set s;
|
|
#endif
|
|
{
|
|
Tree *t=NULL;
|
|
Tree *node;
|
|
Tree **tp=&t;
|
|
int i;
|
|
|
|
unsigned *pdq=set_pdq(s);
|
|
|
|
if (pdq != NULL) {
|
|
for (i=0 ; pdq[i] != nil ; i++) {
|
|
node=tnode( (int) pdq[i]);
|
|
*tp=node;
|
|
tp=&(node->right);
|
|
};
|
|
*tp=NULL;
|
|
free ( (char *) pdq);
|
|
};
|
|
return t;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_check_pred_too_long(Predicate *p,set completion)
|
|
#else
|
|
void MR_check_pred_too_long(p,completion)
|
|
Predicate *p;
|
|
set completion;
|
|
#endif
|
|
{
|
|
if (p != NULL &&
|
|
p->source != NULL &&
|
|
! p->source->predTooLong) {
|
|
if ( !set_nil(completion)) {
|
|
p->source->predTooLong=1;
|
|
warnFL("It is unusual (but ok) for a semantic predicate to test context past the end of its own rule",
|
|
FileStr[p->source->file],p->source->line);
|
|
};
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_predicate_context_completed(Predicate *p)
|
|
#else
|
|
int MR_predicate_context_completed(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
if (p == NULL) return 1;
|
|
if (p->expr != PRED_AND_LIST &&
|
|
p->expr != PRED_OR_LIST) {
|
|
if ( ! set_nil(p->completionSet)) return 0;
|
|
if ( ! set_nil(p->completionTree)) return 0;
|
|
};
|
|
return MR_predicate_context_completed(p->down) &
|
|
MR_predicate_context_completed(p->right);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Node * MR_advance(Node *n)
|
|
#else
|
|
Node * MR_advance(n)
|
|
Node *n;
|
|
#endif
|
|
{
|
|
if (n == NULL) return NULL;
|
|
switch (n->ntype) {
|
|
case nJunction: return ((Junction *)n)->p1;
|
|
case nToken: return ((TokNode *)n)->next;
|
|
case nRuleRef: return ((RuleRefNode *)n)->next;
|
|
case nAction: return ((ActionNode *)n)->next;
|
|
default: return NULL;
|
|
};
|
|
return NULL; /* MSVC 5.0 complains about missing return statement */
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Junction * MR_find_endRule(Node *n)
|
|
#else
|
|
Junction * MR_find_endRule(n)
|
|
Node *n;
|
|
#endif
|
|
{
|
|
Node *next;
|
|
if (n == NULL) return NULL;
|
|
for (next=n; next != NULL; next=MR_advance(next)) {
|
|
if (next->ntype == nJunction &&
|
|
( (Junction *) next)->jtype == EndRule) {
|
|
break;
|
|
};
|
|
};
|
|
return (Junction *)next;
|
|
}
|
|
|
|
/*
|
|
Intersection: a branch which is shorter is chosen
|
|
over one which is longer: (A B C) intersect (A B) yields (A B).
|
|
|
|
AND: a branch which is longer is chosen over the one
|
|
which is shorter: (A B C) AND (A B) yields (A B C)
|
|
|
|
*/
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree *MR_computeTreeIntersection(Tree *l,Tree *r)
|
|
#else
|
|
Tree *MR_computeTreeIntersection(l,r)
|
|
Tree *l;
|
|
Tree *r;
|
|
#endif
|
|
{
|
|
Tree *result=NULL;
|
|
Tree **tail;
|
|
Tree *p;
|
|
Tree *q;
|
|
Tree *match;
|
|
|
|
if (l == NULL || r == NULL) return NULL;
|
|
for (p=l; p != NULL; p=p->right) {
|
|
require(p->token != EpToken,"MR_computeTreeIntersection: p->EpToken unexpected\n");
|
|
require (p->token != ALT,"MR_computeTreeIntersection: p->ALT unexpected\n");
|
|
};
|
|
for (q=r; q != NULL; q=q->right) {
|
|
require(q->token != EpToken,"MR_computeTreeIntersection: q->EpToken unexpected\n");
|
|
require(q->token != ALT,"MR_computeTreeIntersection: q->ALT unexpected\n");
|
|
};
|
|
|
|
result=tnode(ALT);
|
|
tail=&(result->down);
|
|
|
|
for (p=l; p != NULL ; p=p->right) {
|
|
for (q=r; q != NULL ; q=q->right) {
|
|
if (p->token == q->token) {
|
|
match=tnode(p->token);
|
|
match->down=MR_computeTreeIntersection(p->down,q->down);
|
|
*tail=match;
|
|
tail=&(match->right);
|
|
};
|
|
};
|
|
};
|
|
|
|
*tail=NULL;
|
|
result=tshrink(result);
|
|
result=tflatten( result );
|
|
result=tleft_factor( result );
|
|
return result;
|
|
}
|
|
|
|
/* the predicates which are ANDed together have a common
|
|
context: they must all have common roots. Thus the
|
|
AND operation is more like an OR operation because
|
|
branches which are longer are grafted onto shorter
|
|
branches of the AND tree. For instance combining
|
|
(A B C) with (A B C D) gives (A B C D). There
|
|
should never be a case of (A B C) and (A B D) because
|
|
they have the same context.
|
|
|
|
Actually, this may not be true once one throws in
|
|
guard predicates which are defined by the user, not
|
|
the context.
|
|
*/
|
|
|
|
/* requires input trees to be in "canonical" format */
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree *MR_computeTreeAND(Tree *l,Tree *r)
|
|
#else
|
|
Tree *MR_computeTreeAND(l,r)
|
|
Tree *l;
|
|
Tree *r;
|
|
#endif
|
|
{
|
|
Tree *result=NULL;
|
|
Tree **tail;
|
|
Tree *p;
|
|
Tree *q;
|
|
Tree *match;
|
|
|
|
if (l == NULL) return tdup(r);
|
|
if (r == NULL) return tdup(l);
|
|
|
|
for (p=l; p != NULL; p=p->right) {
|
|
/**** require(p->token != EpToken,"MR_computeTreeAND: p->EpToken unexpected\n"); ****/
|
|
require (p->token != ALT,"MR_computeTreeAND: p->ALT unexpected\n");
|
|
};
|
|
for (q=r; q != NULL; q=q->right) {
|
|
/**** require(q->token != EpToken,"MR_computeTreeAND: q->EpToken unexpected\n"); ****/
|
|
require(q->token != ALT,"MR_computeTreeAND: q->ALT unexpected\n");
|
|
};
|
|
|
|
result=tnode(ALT);
|
|
tail=&(result->down);
|
|
|
|
for (p=l; p != NULL ; p=p->right) {
|
|
for (q=r; q != NULL ; q=q->right) {
|
|
if (p->token == q->token) {
|
|
match=tnode(p->token);
|
|
match->down=MR_computeTreeAND(p->down,q->down);
|
|
*tail=match;
|
|
tail=&(match->right);
|
|
};
|
|
};
|
|
};
|
|
|
|
*tail=NULL;
|
|
result=tshrink(result);
|
|
result=tflatten( result );
|
|
result=tleft_factor( result );
|
|
return result;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_union_plain_sets1(Predicate *p,set *theUnion)
|
|
#else
|
|
void MR_union_plain_sets1(p,theUnion)
|
|
Predicate *p;
|
|
set *theUnion;
|
|
#endif
|
|
{
|
|
if (p == NULL) return;
|
|
MR_union_plain_sets1(p->down,theUnion);
|
|
MR_union_plain_sets1(p->right,theUnion);
|
|
set_orin(theUnion,p->plainSet);
|
|
return;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
set MR_union_plain_sets(Predicate *p)
|
|
#else
|
|
set MR_union_plain_sets(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
set theUnion;
|
|
|
|
theUnion=empty;
|
|
|
|
MR_union_plain_sets1(p,&theUnion);
|
|
return theUnion;
|
|
}
|
|
|
|
/* does NOT left factor: do not want to merge
|
|
(A B) with (A) to get (A B)
|
|
in fact the opposite: (A B) with (A) gives (A)
|
|
*/
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree *MR_compute_pred_tree_ctxXX(Predicate *p)
|
|
#else
|
|
Tree *MR_compute_pred_tree_ctxXX(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
Tree *result=NULL;
|
|
Predicate *q;
|
|
Tree *t;
|
|
|
|
if (p == NULL) return NULL;
|
|
|
|
/* this appears strange: why do we OR the context
|
|
of and AND predicate ? It is because of the way
|
|
that predicates are evaluated: if the context is
|
|
wrong then it's the same as if the predicate was
|
|
true. That means that even when one leg of an
|
|
AND has unmatched context, if the other leg has
|
|
matched context and is true then the predicate
|
|
succeeds. It's only when all the legs have unmatched
|
|
context that this one can skip evaluation of the
|
|
predicates.
|
|
*/
|
|
if (p->expr == PRED_OR_LIST ||
|
|
p->expr == PRED_AND_LIST) {
|
|
for (q=p->down; q != NULL ; q=q->right) {
|
|
t=MR_compute_pred_tree_ctxXX(q);
|
|
result=tappend(result,t);
|
|
t=NULL;
|
|
};
|
|
|
|
result=tshrink(result);
|
|
result=tflatten( result );
|
|
|
|
/* does NOT left factor: do not want to merge
|
|
(A B) with (A) to get (A B)
|
|
in fact the opposite: (A B) with (A) gives (A)
|
|
*/
|
|
|
|
/**** result=tleft_factor( result ); ****/
|
|
return result;
|
|
};
|
|
|
|
#if 0
|
|
** if (p->expr == PRED_AND_LIST) {
|
|
**
|
|
** Predicate *l;
|
|
** Predicate *r;
|
|
** Tree *l1;
|
|
** Tree *r1;
|
|
** Tree *prevl1;
|
|
**
|
|
** l=p->down;
|
|
** require (l->right != NULL,"MR_compute_pred_tree - AND has only one child");
|
|
**
|
|
**/* l1 and r1 should already be in "canonical" format */
|
|
**
|
|
** l1=MR_compute_pred_tree(l);
|
|
** for (r=l->right; r != NULL; r=r->right) {
|
|
** r1=MR_compute_pred_tree(r);
|
|
** prevl1=l1;
|
|
** l1=MR_computeTreeAND(l1,r1);
|
|
** Tfree(r1);
|
|
** Tfree(prevl1);
|
|
** };
|
|
**
|
|
**/* result from computeTreeAND should be in "canonical" format */
|
|
**
|
|
** result=l1;
|
|
**
|
|
**/* result of MR_computeTreeAND should be in "canonical" format */
|
|
**
|
|
** return result;
|
|
** };
|
|
#endif
|
|
|
|
if (p->k == 1) {
|
|
result=MR_make_tree_from_set(p->scontext[1]);
|
|
} else {
|
|
result=tdup(p->tcontext);
|
|
result=MR_remove_epsilon_from_tree(result);
|
|
result=tshrink(result);
|
|
result=tflatten(result);
|
|
result=tleft_factor(result);
|
|
};
|
|
return result;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_pred_depth(Predicate *p,int *maxDepth)
|
|
#else
|
|
void MR_pred_depth(p,maxDepth)
|
|
Predicate *p;
|
|
int *maxDepth;
|
|
#endif
|
|
{
|
|
if (p == NULL) return;
|
|
if (p->expr != PRED_OR_LIST &&
|
|
p->expr != PRED_AND_LIST) {
|
|
if (p->k > *maxDepth) *maxDepth=p->k;
|
|
};
|
|
MR_pred_depth(p->down,maxDepth);
|
|
MR_pred_depth(p->right,maxDepth);
|
|
}
|
|
|
|
/* this computes the OR of all the contexts */
|
|
|
|
#ifdef __USE_PROTOS
|
|
set MR_compute_pred_set(Predicate *p)
|
|
#else
|
|
set MR_compute_pred_set(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
set result;
|
|
Predicate *q;
|
|
|
|
result=empty;
|
|
|
|
if (p == NULL) return empty;
|
|
|
|
if (p->expr == PRED_OR_LIST ||
|
|
p->expr == PRED_AND_LIST) { /* yes, I do mean PRED_AND_LIST ! */
|
|
/* remember: r1: (A)? => <<p>>? r2; */
|
|
/* r2: (B)? => <<q>>? r3; */
|
|
set t;
|
|
|
|
t=empty;
|
|
result=empty;
|
|
|
|
for (q=p->down; q != NULL; q=q->right) {
|
|
t=MR_compute_pred_set(q);
|
|
set_orin(&result,t);
|
|
set_free(t);
|
|
};
|
|
return result;
|
|
} else if (p->k > 1) {
|
|
return empty;
|
|
} else {
|
|
return set_dup(p->scontext[1]);
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
set MR_First(int ck,Junction *j,set *incomplete)
|
|
#else
|
|
set MR_First(ck,j,incomplete)
|
|
int ck;
|
|
Junction *j;
|
|
set *incomplete;
|
|
#endif
|
|
{
|
|
Junction *p;
|
|
set tokensUsed;
|
|
|
|
tokensUsed=empty;
|
|
|
|
require(j->ntype==nJunction, "MR_First: non junction passed");
|
|
|
|
p = analysis_point((Junction *)j->p1);
|
|
|
|
REACH(p,ck,incomplete,tokensUsed);
|
|
|
|
return tokensUsed;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_cleanup_pred_trees(Predicate *p)
|
|
#else
|
|
void MR_cleanup_pred_trees(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
Tree *t;
|
|
|
|
if (p == NULL) return;
|
|
if (p->expr != PRED_OR_LIST &&
|
|
p->expr != PRED_AND_LIST) {
|
|
t=p->tcontext;
|
|
t=tshrink(t);
|
|
t=tflatten(t);
|
|
t=tleft_factor(t);
|
|
p->tcontext=t;
|
|
};
|
|
MR_cleanup_pred_trees(p->down);
|
|
MR_cleanup_pred_trees(p->right);
|
|
}
|
|
|
|
/* does NOT return canonical tree */
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree * MR_remove_epsilon_from_tree(Tree *t)
|
|
#else
|
|
Tree * MR_remove_epsilon_from_tree(t)
|
|
Tree *t;
|
|
#endif
|
|
{
|
|
if (t == NULL) return NULL;
|
|
|
|
/* I think ALT can be ignored as a special case */
|
|
|
|
if (t->token != EpToken) {
|
|
t->down=MR_remove_epsilon_from_tree(t->down);
|
|
t->right=MR_remove_epsilon_from_tree(t->right);
|
|
return t;
|
|
} else {
|
|
Tree *u;
|
|
u=MR_remove_epsilon_from_tree(t->right);
|
|
t->right=NULL;
|
|
Tfree(t);
|
|
return u;
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_complete_set(int predDepth,set *tokensUsed,set *incomplete)
|
|
#else
|
|
void MR_complete_set(predDepth,tokensUsed,incomplete)
|
|
int predDepth;
|
|
set *tokensUsed;
|
|
set *incomplete;
|
|
#endif
|
|
{
|
|
int i;
|
|
RuleRefNode *ruleRef;
|
|
set rk2;
|
|
set b;
|
|
int k2;
|
|
Junction *save_MR_RuleBlkWithHalt;
|
|
|
|
if (set_int(*incomplete) > (unsigned) predDepth) {
|
|
return;
|
|
};
|
|
|
|
require(MR_PredRuleRefStack.count == MR_RuleBlkWithHaltStack.count,
|
|
"RuleRefStack and RuleBlkWithHaltStack not same size");
|
|
|
|
require(MR_RuleBlkWithHalt == NULL ||
|
|
(MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE),
|
|
"RuleBlkWithHalt has no halt set");
|
|
|
|
save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt;
|
|
|
|
if (MR_RuleBlkWithHalt != NULL) {
|
|
MR_RuleBlkWithHalt->end->halt=FALSE;
|
|
};
|
|
|
|
for (i=MR_PredRuleRefStack.count-1; i >= 0 ; i--) {
|
|
ruleRef=(RuleRefNode *)MR_PredRuleRefStack.data[i];
|
|
if (ruleRef == NULL) continue;
|
|
|
|
MR_RuleBlkWithHalt=(Junction *)MR_RuleBlkWithHaltStack.data[i];
|
|
if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=TRUE;
|
|
|
|
rk2=empty;
|
|
b=empty;
|
|
|
|
while ( !set_nil(*incomplete) ) {
|
|
k2=set_int(*incomplete);
|
|
if (k2 > predDepth) break; /* <=== another exit from loop */
|
|
set_rm(k2,*incomplete);
|
|
REACH(ruleRef->next,k2,&rk2,b);
|
|
set_orin(tokensUsed,b);
|
|
set_free(b);
|
|
};
|
|
|
|
if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=FALSE;
|
|
|
|
set_orin(incomplete,rk2); /* remember what we couldn't do */
|
|
set_free(rk2);
|
|
if (set_int(*incomplete) > (unsigned) predDepth) break; /* <=== another exit from loop */
|
|
};
|
|
|
|
MR_RuleBlkWithHalt=save_MR_RuleBlkWithHalt;
|
|
if (MR_RuleBlkWithHalt != NULL) {
|
|
MR_RuleBlkWithHalt->end->halt=TRUE;
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_complete_tree(int predDepth,Tree **t,set *incomplete)
|
|
#else
|
|
void MR_complete_tree(predDepth,t,incomplete)
|
|
int predDepth;
|
|
Tree **t;
|
|
set *incomplete;
|
|
#endif
|
|
{
|
|
int i;
|
|
RuleRefNode *ruleRef;
|
|
set rk2;
|
|
Tree *u;
|
|
unsigned k2;
|
|
Junction *save_MR_RuleBlkWithHalt;
|
|
int saveConstrainSearch;
|
|
|
|
if (set_int(*incomplete) > (unsigned) predDepth) {
|
|
return;
|
|
};
|
|
|
|
require(MR_PredRuleRefStack.count == MR_RuleBlkWithHaltStack.count,
|
|
"RuleRefStack and RuleBlkWithHaltStack not same size");
|
|
|
|
require(MR_RuleBlkWithHalt == NULL ||
|
|
(MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE),
|
|
"RuleBlkWithHalt has no halt set");
|
|
|
|
save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt;
|
|
saveConstrainSearch=ConstrainSearch;
|
|
ConstrainSearch=0;
|
|
|
|
if (MR_RuleBlkWithHalt != NULL) {
|
|
MR_RuleBlkWithHalt->end->halt=FALSE;
|
|
};
|
|
|
|
for (i=MR_PredRuleRefStack.count-1; i >= 0 ; i--) {
|
|
ruleRef=(RuleRefNode *)MR_PredRuleRefStack.data[i];
|
|
if (ruleRef == NULL) continue;
|
|
|
|
MR_RuleBlkWithHalt=(Junction *)MR_RuleBlkWithHaltStack.data[i];
|
|
|
|
if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=TRUE;
|
|
|
|
rk2=empty;
|
|
|
|
while ( !set_nil(*incomplete) ) {
|
|
k2 = set_int(*incomplete);
|
|
if (k2 > (unsigned) predDepth) break; /* <=== another exit from loop */
|
|
set_rm(k2,*incomplete);
|
|
u = NULL;
|
|
|
|
TRAV(ruleRef->next,k2,&rk2,u);
|
|
|
|
/* any subtrees missing k2 tokens, add u onto end */
|
|
|
|
*t=tlink(*t,u,k2);
|
|
Tfree(u);
|
|
}
|
|
|
|
set_orin(incomplete,rk2); /* remember what we couldn't do */
|
|
set_free(rk2);
|
|
|
|
if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=FALSE;
|
|
|
|
if (set_int(*incomplete) > (unsigned) predDepth) break; /* <=== another exit from loop */
|
|
};
|
|
|
|
MR_RuleBlkWithHalt=save_MR_RuleBlkWithHalt;
|
|
|
|
if (MR_RuleBlkWithHalt != NULL) {
|
|
MR_RuleBlkWithHalt->end->halt=TRUE;
|
|
};
|
|
ConstrainSearch=saveConstrainSearch;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_complete_predicates(int predDepth,Predicate *pred)
|
|
#else
|
|
void MR_complete_predicates(predDepth,pred)
|
|
int predDepth;
|
|
Predicate *pred;
|
|
#endif
|
|
{
|
|
if (pred == NULL) return;
|
|
if (pred->expr != PRED_AND_LIST &&
|
|
pred->expr != PRED_OR_LIST) {
|
|
MR_complete_set(predDepth,&(pred->scontext[1]),&(pred->completionSet));
|
|
MR_complete_tree(predDepth,&(pred->tcontext),&(pred->completionTree));
|
|
};
|
|
MR_complete_predicates(predDepth,pred->down);
|
|
MR_complete_predicates(predDepth,pred->right);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Junction * MR_junctionWithoutP2(Junction *j)
|
|
#else
|
|
Junction * MR_junctionWithoutP2(j)
|
|
Junction *j;
|
|
#endif
|
|
{
|
|
Junction *thisAlt;
|
|
|
|
/* don't want to follow p2 to the next alternative of this rule */
|
|
/* insert a generic node with null p2 if necessary */
|
|
/* however FIRST requires a junction */
|
|
|
|
thisAlt=j;
|
|
if (thisAlt->p2 != NULL) {
|
|
if (thisAlt->p1->ntype == nJunction) {
|
|
thisAlt=(Junction *) thisAlt->p1;
|
|
} else {
|
|
thisAlt=newJunction();
|
|
thisAlt->p1=j->p1;
|
|
thisAlt->rname=j->rname;
|
|
thisAlt->file=j->file;
|
|
thisAlt->line=j->line;
|
|
j->p1=(Node *)thisAlt;
|
|
};
|
|
};
|
|
return thisAlt;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_tree_equ(Tree *big, Tree *small) {
|
|
#else
|
|
int MR_tree_equ(big,small)
|
|
Tree *big;
|
|
Tree *small;
|
|
{
|
|
#endif
|
|
|
|
Tree *b;
|
|
Tree *s;
|
|
int bcount=0;
|
|
int scount=0;
|
|
|
|
if (small == NULL && big == NULL) return 1;
|
|
if (small == NULL) return 0;
|
|
if (big == NULL) return 0;
|
|
|
|
if (small->token == ALT) {
|
|
require(small->right == NULL,
|
|
"MR_tree_equ: small: ALT node has siblings");
|
|
return MR_tree_equ(big,small->down);
|
|
};
|
|
if (big->token == ALT) {
|
|
require(big->right == NULL,
|
|
"MR_tree_equ: big: ALT node has siblings");
|
|
return MR_tree_equ(big->down,small);
|
|
};
|
|
for (s=small; s != NULL; s=s->right) {
|
|
scount++;
|
|
require(s->token != EpToken,"MR_tree_equ: s->EpToken unexpected\n");
|
|
};
|
|
for (b=big; b != NULL; b=b->right) {
|
|
bcount++;
|
|
require(b->token != EpToken,"MR_tree_equ: b->EpToken unexpected\n");
|
|
};
|
|
|
|
if (bcount != scount) return 0;
|
|
|
|
for (s=small; s != NULL; s=s->right) {
|
|
for (b=big; b!= NULL; b=b->right) {
|
|
if (s->token == b->token) {
|
|
if (MR_tree_equ(b->down,s->down)) goto next_s;
|
|
};
|
|
};
|
|
return 0;
|
|
next_s:
|
|
continue;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
/* this does not compare sources - only contexts ! */
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_identicalContext(Predicate *p,Predicate *q)
|
|
#else
|
|
int MR_identicalContext(p,q)
|
|
Predicate *p;
|
|
Predicate *q;
|
|
#endif
|
|
{
|
|
if (p->k != q->k) return 0;
|
|
require ( (p->tcontext == NULL) == (q->tcontext == NULL),
|
|
"tcontext inconsistent");
|
|
if (p->k == 1) {
|
|
return set_equ(p->scontext[1],q->scontext[1]);
|
|
} else {
|
|
return MR_tree_equ(p->tcontext,q->tcontext);
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_reportSetSuppression(int predDepth,
|
|
set predSet,set plainSet,Junction *jPred,Junction *jPlain,Predicate *p)
|
|
#else
|
|
void MR_reportSetSuppression(predDepth,predSet,plainSet,jPred,jPlain,p)
|
|
int predDepth;
|
|
set predSet;
|
|
set plainSet;
|
|
Junction *jPred;
|
|
Junction *jPlain;
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
if (InfoP) {
|
|
fprintf(output,"\n#if 0\n\n");
|
|
fprintf(output,"Hoisting of predicate suppressed by alternative without predicate.\n");
|
|
fprintf(output,"The alt without the predicate includes all cases where the predicate is false.\n\n");
|
|
fprintf(output," WITH predicate: line %d %s\n",jPred->line,FileStr[jPred->file]);
|
|
if (jPlain != NULL) {
|
|
fprintf(output," WITHOUT predicate: line %d %s\n",jPlain->line,FileStr[jPlain->file]);
|
|
} else {
|
|
fprintf(output," WITHOUT predicate: all alternatives without predicates (combined)\n");
|
|
};
|
|
if (predDepth == 1) {
|
|
fprintf(output,"\nThe context set for the predicate:\n");
|
|
MR_dumpTokenSet(output,1,predSet);
|
|
};
|
|
fprintf(output,"\nThe lookahead set for the alt WITHOUT the semantic predicate:\n");
|
|
MR_dumpTokenSet(output,1,plainSet);
|
|
fprintf(output,"\nThe predicate:\n\n");
|
|
MR_dumpPred1(1,p,1);
|
|
fprintf(output,"Chain of referenced rules:\n\n");
|
|
MR_dumpPredRuleRefStack(output,4);
|
|
fprintf(output,"\n#endif\n");
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_reportSetRestriction(int predDepth,set predSet,set plainSet,
|
|
Junction *jPred,Junction *jPlain,Predicate *origPred,Predicate *newPred)
|
|
#else
|
|
void MR_reportSetRestriction(predDepth,predSet,plainSet,jPred,jPlain,origPred,newPred)
|
|
int predDepth;
|
|
set predSet;
|
|
set plainSet;
|
|
Junction *jPred;
|
|
Junction *jPlain;
|
|
Predicate *origPred;
|
|
Predicate *newPred;
|
|
#endif
|
|
{
|
|
set intersect;
|
|
|
|
intersect=empty;
|
|
|
|
if (! InfoP) return;
|
|
fprintf(output,"\n#if 0\n\n");
|
|
fprintf(output,"Restricting the context of a predicate because of overlap in the lookahead set\n");
|
|
fprintf(output," between the alternative with the semantic predicate and one without\n");
|
|
fprintf(output,"Without this restriction the alternative without the predicate could not\n");
|
|
fprintf(output," be reached when input matched the context of the predicate and the predicate\n");
|
|
fprintf(output," was false.\n\n");
|
|
|
|
fprintf(output," WITH predicate: line %d %s\n",jPred->line,FileStr[jPred->file]);
|
|
if (jPlain != NULL) {
|
|
fprintf(output," WITHOUT predicate: line %d %s\n",jPlain->line,FileStr[jPlain->file]);
|
|
} else {
|
|
fprintf(output," WITHOUT predicate: all alternatives without predicates (combined)\n");
|
|
};
|
|
if (predDepth == 1) {
|
|
fprintf(output,"\nThe original context set for the predicate:\n");
|
|
MR_dumpTokenSet(output,1,predSet);
|
|
};
|
|
fprintf(output,"\nThe lookahead set for the alt WITHOUT the semantic predicate:\n");
|
|
MR_dumpTokenSet(output,1,plainSet);
|
|
if (predDepth == 1) {
|
|
fprintf(output,"\nThe intersection of the two sets\n");
|
|
intersect=set_and(predSet,plainSet);
|
|
MR_dumpTokenSet(output,1,intersect);
|
|
set_free(intersect);
|
|
};
|
|
fprintf(output,"\nThe original predicate:\n\n");
|
|
MR_dumpPred1(1,origPred,1);
|
|
fprintf(output,"The new (modified) form of the predicate:\n\n");
|
|
MR_dumpPred1(1,newPred,1);
|
|
fprintf(output,"#endif\n");
|
|
}
|
|
|
|
/* don't use Pass3 by itself unless you know that inverted is not important */
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate * MR_removeRedundantPredPass3(Predicate *p)
|
|
#else
|
|
Predicate * MR_removeRedundantPredPass3(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
Predicate *q;
|
|
|
|
if (p == NULL) return NULL;
|
|
p->right=MR_removeRedundantPredPass3(p->right);
|
|
p->down=MR_removeRedundantPredPass3(p->down);
|
|
if (p->redundant) {
|
|
q=p->right;
|
|
p->right=NULL;
|
|
predicate_free(p);
|
|
return q;
|
|
};
|
|
if (p->expr == PRED_AND_LIST ||
|
|
p->expr == PRED_OR_LIST) {
|
|
if (p->down == NULL) {
|
|
q=p->right;
|
|
p->right=NULL;
|
|
predicate_free(p);
|
|
return q;
|
|
};
|
|
if (p->down != NULL && p->down->right == NULL) {
|
|
q=p->down;
|
|
q->right=p->right;
|
|
p->right=NULL;
|
|
p->down=NULL;
|
|
return q;
|
|
};
|
|
};
|
|
return p;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_removeRedundantPredPass2(Predicate *p)
|
|
#else
|
|
void MR_removeRedundantPredPass2(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
Predicate *q;
|
|
|
|
if (p == NULL) return;
|
|
|
|
if (p->expr == PRED_AND_LIST) {
|
|
for (q=p->down ; q != NULL ; q=q->right) {
|
|
MR_removeRedundantPredPass2(q);
|
|
if (q->isConst) {
|
|
if (q->constValue == 0) {
|
|
p->isConst=1;
|
|
p->constValue=0;
|
|
return;
|
|
} else {
|
|
q->redundant=1;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
if (p->expr == PRED_OR_LIST) {
|
|
for (q=p->down ; q != NULL ; q=q->right) {
|
|
MR_removeRedundantPredPass2(q);
|
|
if (q->isConst) {
|
|
if (q->constValue == 0) {
|
|
q->redundant=1;
|
|
} else {
|
|
p->isConst=1;
|
|
p->constValue=1;
|
|
return;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
this totally ignores the implications of guarded predicates
|
|
in which the part after the guard could possibly cover a predicate.
|
|
that would be much harder:
|
|
|
|
rule : (A)? => <<p>>? sub1; /* 1 */
|
|
| (B)? => <<r>>? sub2 /* 2 */
|
|
sub1 : (A)? => <<q>>? A B /* 3 */
|
|
| B /* 4 - suppresses line 2 */
|
|
;
|
|
#endif
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_apply_restriction1(Predicate *pred,set *plainSet,int *changed)
|
|
#else
|
|
void MR_apply_restriction1(pred,plainSet,changed)
|
|
Predicate *pred;
|
|
set *plainSet;
|
|
int *changed;
|
|
#endif
|
|
{
|
|
if (pred == NULL) return;
|
|
MR_apply_restriction1(pred->right,plainSet,changed);
|
|
if (pred->down != NULL) {
|
|
MR_apply_restriction1(pred->down,plainSet,changed);
|
|
} else {
|
|
set t;
|
|
if (pred->k == 1) {
|
|
t=set_dif(pred->scontext[1],*plainSet);
|
|
if (*changed == 0 &&
|
|
!set_equ(t,pred->scontext[1])) {
|
|
*changed=1;
|
|
};
|
|
if (set_nil(t)) {
|
|
pred->redundant=1;
|
|
};
|
|
set_free(pred->scontext[1]);
|
|
pred->scontext[1]=t;
|
|
};
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_orin_plainSet(Predicate *p,set plainSet)
|
|
#else
|
|
void MR_orin_plainSet(p,plainSet)
|
|
Predicate *p;
|
|
set plainSet;
|
|
#endif
|
|
{
|
|
if (p == NULL) return;
|
|
MR_orin_plainSet(p->down,plainSet);
|
|
MR_orin_plainSet(p->right,plainSet);
|
|
set_orin(&p->plainSet,plainSet);
|
|
}
|
|
|
|
Predicate *PRED_SUPPRESS;
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate * MR_find_in_aSubBlk(Junction *alt)
|
|
#else
|
|
Predicate * MR_find_in_aSubBlk(alt)
|
|
Junction *alt;
|
|
#endif
|
|
{
|
|
Predicate *root=NULL;
|
|
Predicate **tail=NULL;
|
|
|
|
Junction *p;
|
|
|
|
int nAlts=0;
|
|
Junction **jList;
|
|
Predicate **predList;
|
|
int *matchList;
|
|
set predSet;
|
|
int i;
|
|
int j;
|
|
int m;
|
|
int predDepth;
|
|
set incomplete;
|
|
set union_plainSet;
|
|
set setChange;
|
|
int changed;
|
|
Predicate *newPred;
|
|
set setDif;
|
|
Predicate *origPred;
|
|
int depth1=1; /* const int */
|
|
set *plainContext;
|
|
set plainSet;
|
|
|
|
predSet=empty;
|
|
incomplete=empty;
|
|
union_plainSet=empty;
|
|
setChange=empty;
|
|
setDif=empty;
|
|
plainSet=empty;
|
|
|
|
if (PRED_SUPPRESS == NULL) {
|
|
PRED_SUPPRESS=new_pred();
|
|
PRED_SUPPRESS->expr="Predicate Suppressed";
|
|
};
|
|
|
|
/* this section just counts the number of "interesting" alternatives */
|
|
/* in order to allocate arrays */
|
|
|
|
for (p=alt; p!=NULL; p=(Junction *)p->p2) {
|
|
/* ignore empty alts */
|
|
if ( p->p1->ntype != nJunction ||
|
|
((Junction *)p->p1)->jtype != EndBlk ) {
|
|
nAlts++;
|
|
};
|
|
};
|
|
|
|
/* if this is a (...)+ block then don't count the last alt because
|
|
it can't be taken until at least one time through the block.
|
|
In other words it isn't a real choice until the (...)+ is entered
|
|
at which point the hoisting issue is moot.
|
|
Maybe look at "ignore" instead ?
|
|
*/
|
|
|
|
if (alt->jtype == aPlusBlk) {
|
|
nAlts--;
|
|
};
|
|
|
|
jList=(Junction **)calloc(nAlts,sizeof(Junction *));
|
|
require(jList!=NULL,"cannot allocate MR_find_in_aSubBlk jList");
|
|
|
|
plainContext=(set *)calloc(nAlts,sizeof(set));
|
|
require(plainContext!=NULL,"cannot allocate MR_find_in_aSubBlk plainContext");
|
|
for (m=0; m < nAlts; m++) plainContext[m]=empty;
|
|
|
|
predList=(Predicate **)calloc(nAlts,sizeof(Predicate *));
|
|
require(predList!=NULL,"cannot allocate MR_find_in_aSubBlk predList");
|
|
|
|
matchList=(int *)calloc(nAlts,sizeof(int));
|
|
require(matchList!=NULL,"cannot allocate MR_find_in_aSubBlk matchList");
|
|
|
|
/* this section just fills in the arrays previously allocated */
|
|
/* the most interesting one is matchList[] */
|
|
/* */
|
|
/* bit 0 => this alt has a semantic pred which is "covered" */
|
|
/* by an alt without a semantic pred. Don't hoist. */
|
|
|
|
for (i=0,p=alt;
|
|
p!=NULL && i<nAlts;
|
|
i++,p=(Junction *)p->p2) {
|
|
|
|
/* ignore empty alts */
|
|
|
|
if ( p->p1->ntype != nJunction ||
|
|
((Junction *)p->p1)->jtype != EndBlk ) {
|
|
jList[i]=MR_junctionWithoutP2(p);
|
|
predList[i]=find_predicates(p->p1); /* should be jList ????? */
|
|
if (predList[i] != NULL) {
|
|
MR_cleanup_pred_trees(predList[i]); /* flatten & left factor */
|
|
plainContext[i]=MR_union_plain_sets(predList[i]);
|
|
} else {
|
|
MR_set_reuse(&plainSet);
|
|
MR_set_reuse(&incomplete);
|
|
plainSet=MR_First(depth1,jList[i],&incomplete);
|
|
MR_complete_set(depth1,&plainSet,&incomplete);
|
|
require(set_nil(incomplete),"couldn't complete k=1");
|
|
plainContext[i]=plainSet;
|
|
plainSet=empty;
|
|
};
|
|
set_orin(&union_plainSet,plainContext[i]);
|
|
};
|
|
};
|
|
|
|
if (nAlts == 1) {
|
|
goto EXIT_SIMPLE;
|
|
};
|
|
|
|
/*
|
|
* Looking for cases where alt i has a semantic pred and alt j does not.
|
|
* Don't care about cases where lookahead for semantic predicates overlap
|
|
* because normal predicate hoisting does the correct thing automatically.
|
|
* Don't care about cases where lookahead for alts without semantic predicates
|
|
* overlap because normal prediction does the correct thing automatically.
|
|
*
|
|
* When we find such a case check for one of three subcases:
|
|
*
|
|
* 1. if lookahead for alt i is contained in the lookahead for any
|
|
* alt j then ignore semantic predicate of alt i
|
|
* 2. if lookahead for alt i is not contained in the lookahead for
|
|
* any alt j then add add predicate i to the OR list to be hoisted
|
|
* 3. if lookahead for alt i overlaps the lookahead for some alt j then
|
|
* add a dummy semantic predicate for alt j
|
|
*
|
|
* There is an implicit assumption that the context of all alternatives following
|
|
* the rule being processed here are identical (but may vary from hoist to
|
|
* hoist depending on the place where the rule was invoked that led to hoisting
|
|
* these predicates. In othere words in the fragment:
|
|
*
|
|
* ( <<a>>? a1 a2 a3 | <<b>>? b1 b2 b3 )
|
|
*
|
|
* both a3 and b3 have the same follow sets because they are both at the end of
|
|
* alternatives in the same block.
|
|
*/
|
|
|
|
for (i=0; i < nAlts; i++) {
|
|
if (jList[i] == NULL) continue;
|
|
if (predList[i] == NULL) continue;
|
|
|
|
/* if the predicate depth turns out to be one token only */
|
|
/* then it is can be easily represented as a set and */
|
|
/* compared to the junction set create by MR_First() */
|
|
|
|
predDepth=0;
|
|
MR_pred_depth(predList[i],&predDepth);
|
|
require (predDepth >= 1,"MR_find_in_aSubBlk: pred depth < 1");
|
|
require (predDepth <= CLL_k,"MR_find_in_aSubBlk: predDepth > CLL_k");
|
|
|
|
/* complete predicates to predDepth
|
|
If completed to depth=1 then the context would be incomplete.
|
|
The context would be truncated and the predicate simplify routine
|
|
would have incomplete information. It would lead to
|
|
either false matches of failure to find true matches.
|
|
*/
|
|
|
|
MR_complete_predicates(predDepth,predList[i]);
|
|
|
|
if (predList[i] != NULL) {
|
|
MR_cleanup_pred_trees(predList[i]); /* flatten & left factor */
|
|
};
|
|
|
|
/* If the predicate depth is 1 then it is possible to suppress
|
|
a predicate completely using a single plain alt. Check for suppression
|
|
by a single plain alt first because it gives better messages. If that
|
|
fails try the union of all the plain alts.
|
|
*/
|
|
|
|
if (predDepth == 1) {
|
|
|
|
MR_set_reuse(&predSet);
|
|
predSet=MR_compute_pred_set(predList[i]); /* ignores k>1 predicates */
|
|
|
|
for (j=0; j < nAlts; j++) {
|
|
if (jList[j] == NULL) continue;
|
|
if (j == i) continue;
|
|
|
|
MR_set_reuse(&setDif);
|
|
setDif=set_dif(predSet,plainContext[j]);
|
|
if (set_nil(setDif)) {
|
|
matchList[i] |= 1;
|
|
MR_reportSetSuppression(predDepth,predSet,plainContext[j],jList[i],jList[j],predList[i]);
|
|
predicate_free(predList[i]);
|
|
predList[i]=PRED_SUPPRESS;
|
|
goto next_i;
|
|
};
|
|
|
|
}; /* end loop on j */
|
|
|
|
changed=0;
|
|
|
|
/* predicate_dup is only to give good error messages */
|
|
/* remember to do a predicate_free() */
|
|
|
|
origPred=predicate_dup(predList[i]);
|
|
MR_apply_restriction1(predList[i],&union_plainSet,&changed);
|
|
if (changed) {
|
|
|
|
/* don't use Pass3 by itself unless you know that inverted is not important */
|
|
|
|
newPred=MR_removeRedundantPredPass3(predList[i]);
|
|
newPred=MR_predSimplifyALL(newPred);
|
|
if (newPred == NULL) {
|
|
matchList[i] |= 1;
|
|
MR_reportSetSuppression(predDepth,predSet,union_plainSet,jList[i],
|
|
NULL,origPred);
|
|
predList[i]=PRED_SUPPRESS;
|
|
} else {
|
|
MR_reportSetRestriction(predDepth,predSet,union_plainSet,jList[i],
|
|
NULL,origPred,newPred);
|
|
predList[i]=newPred;
|
|
};
|
|
};
|
|
predicate_free(origPred);
|
|
origPred=NULL;
|
|
};
|
|
|
|
/*
|
|
If the predicate depth is > 1 then it can't be suppressed completely
|
|
because the code doesn't support inspection of such things. They're
|
|
much messier than k=1 sets.
|
|
*/
|
|
|
|
if (predDepth > 1 ) {
|
|
|
|
changed=0;
|
|
|
|
/* predicate_dup is only to give good error messages */
|
|
/* remember to do a predicate_free() */
|
|
|
|
origPred=predicate_dup(predList[i]);
|
|
MR_apply_restriction1(predList[i],&union_plainSet,&changed);
|
|
if (changed) {
|
|
newPred=MR_removeRedundantPredPass3(predList[i]);
|
|
newPred=MR_predSimplifyALL(newPred);
|
|
if (newPred == NULL) {
|
|
matchList[i] |= 1;
|
|
MR_reportSetSuppression(predDepth,predSet,union_plainSet,jList[i],
|
|
NULL,origPred);
|
|
predList[i]=PRED_SUPPRESS;
|
|
} else {
|
|
MR_reportSetRestriction(predDepth,predSet,union_plainSet,jList[i],
|
|
NULL,origPred,newPred);
|
|
predList[i]=newPred;
|
|
};
|
|
};
|
|
predicate_free(origPred);
|
|
origPred=NULL;
|
|
};
|
|
next_i:
|
|
continue;
|
|
};
|
|
|
|
EXIT_SIMPLE:
|
|
|
|
root = new_pred();
|
|
root->expr=PRED_OR_LIST;
|
|
tail = &(root->down);
|
|
|
|
for (i=0 ; i< nAlts ; i++) {
|
|
if (jList[i] == NULL) continue;
|
|
|
|
if (predList[i] == NULL) {
|
|
continue;
|
|
} else if ( (matchList[i] & 1) != 0) {
|
|
if (predList[i] != PRED_SUPPRESS) {
|
|
predicate_free(predList[i]);
|
|
};
|
|
continue;
|
|
};
|
|
|
|
/* make an OR list of predicates */
|
|
|
|
*tail=predList[i];
|
|
tail=&(predList[i]->right);
|
|
};
|
|
|
|
/* if just one pred, remove OR root */
|
|
|
|
if (root->down == NULL) {
|
|
predicate_free(root);
|
|
root=NULL;
|
|
} else if (root->down->right == NULL) {
|
|
Predicate *p=root->down;
|
|
root->down=NULL;
|
|
predicate_free(root);
|
|
root=p;
|
|
}
|
|
|
|
root=MR_predSimplifyALL(root);
|
|
|
|
MR_orin_plainSet(root,union_plainSet);
|
|
|
|
set_free(predSet);
|
|
set_free(union_plainSet);
|
|
set_free(incomplete);
|
|
set_free(setChange);
|
|
set_free(setDif);
|
|
|
|
for (m=0; m < nAlts; m++) set_free(plainContext[m]);
|
|
|
|
free ( (char *) jList);
|
|
free ( (char *) predList);
|
|
free ( (char *) matchList);
|
|
free ( (char *) plainContext);
|
|
|
|
return root;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_predContextPresent(Predicate *p,int *allHaveContext,int *noneHaveContext)
|
|
#else
|
|
void MR_predContextPresent(p,allHaveContext,noneHaveContext)
|
|
Predicate *p;
|
|
int *allHaveContext;
|
|
int *noneHaveContext;
|
|
#endif
|
|
{
|
|
if (p == NULL) return;
|
|
MR_predContextPresent(p->right,allHaveContext,noneHaveContext);
|
|
if (p->expr != PRED_AND_LIST &&
|
|
p->expr != PRED_OR_LIST) {
|
|
if (set_nil(p->scontext[1]) == 0 ||
|
|
(p->tcontext != NULL)) {
|
|
*noneHaveContext=0;
|
|
} else {
|
|
*allHaveContext=0;
|
|
};
|
|
};
|
|
MR_predContextPresent(p->down,allHaveContext,noneHaveContext);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_pointerStackPush(PointerStack *ps,void *dataPointer)
|
|
#else
|
|
int MR_pointerStackPush(ps,dataPointer)
|
|
PointerStack *ps;
|
|
void *dataPointer;
|
|
#endif
|
|
{
|
|
void **newStack;
|
|
int newSize;
|
|
int i;
|
|
|
|
if (ps->count == ps->size) {
|
|
newSize=20+ps->size*2;
|
|
newStack=(void **)calloc(newSize,sizeof(void *));
|
|
require (newStack != NULL,"cannot allocate PointerStack");
|
|
for (i=0; i < ps->size; i++) {
|
|
newStack[i]=ps->data[i];
|
|
};
|
|
if (ps->data != NULL) free( (char *) ps->data);
|
|
ps->data=newStack;
|
|
ps->size=newSize;
|
|
};
|
|
ps->data[ps->count]=dataPointer;
|
|
ps->count++;
|
|
return ps->count-1;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void * MR_pointerStackPop(PointerStack *ps)
|
|
#else
|
|
void * MR_pointerStackPop(ps)
|
|
PointerStack *ps;
|
|
#endif
|
|
{
|
|
void *dataPointer;
|
|
|
|
require(ps->count > 0,"MR_pointerStackPop underflow");
|
|
|
|
dataPointer=ps->data[ps->count-1];
|
|
ps->data[ps->count-1]=NULL;
|
|
(ps->count)--;
|
|
return dataPointer;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void * MR_pointerStackTop(PointerStack *ps)
|
|
#else
|
|
void * MR_pointerStackTop(ps)
|
|
PointerStack *ps;
|
|
#endif
|
|
{
|
|
require(ps->count > 0,"MR_pointerStackTop underflow");
|
|
return ps->data[ps->count-1];
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_pointerStackReset(PointerStack *ps)
|
|
#else
|
|
void MR_pointerStackReset(ps)
|
|
PointerStack *ps;
|
|
#endif
|
|
{
|
|
int i;
|
|
if (ps->data != NULL) {
|
|
for (i=0; i < ps->count ; i++) {
|
|
ps->data[i]=NULL;
|
|
};
|
|
};
|
|
ps->count=0;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Junction *MR_nameToRuleBlk(char *name)
|
|
#else
|
|
Junction *MR_nameToRuleBlk(name)
|
|
char *name;
|
|
#endif
|
|
{
|
|
RuleEntry *q;
|
|
|
|
require (RulePtr != NULL,"MR_nameToRule: RulePtr not initialized");
|
|
|
|
if (name == NULL) return NULL;
|
|
|
|
q = (RuleEntry *) hash_get(Rname,name);
|
|
|
|
if ( q == NULL ) {
|
|
return NULL;
|
|
} else {
|
|
return RulePtr[q->rulenum];
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Junction * MR_ruleReferenced(RuleRefNode *rrn)
|
|
#else
|
|
Junction * MR_ruleReferenced(rrn)
|
|
RuleRefNode *rrn;
|
|
#endif
|
|
{
|
|
return MR_nameToRuleBlk(rrn->text);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_comparePredLeaves(Predicate *me,Predicate *myParent,Predicate *him,Predicate *hisParent)
|
|
#else
|
|
void MR_comparePredLeaves(me,myParent,him,hisParent)
|
|
Predicate *me;
|
|
Predicate *myParent;
|
|
Predicate *him;
|
|
Predicate *hisParent;
|
|
#endif
|
|
{
|
|
if (me == NULL) return;
|
|
if (me == him) {
|
|
MR_comparePredLeaves(me->right,myParent,him,hisParent);
|
|
return;
|
|
} else if (me->expr == PRED_AND_LIST ||
|
|
me->expr == PRED_OR_LIST) {
|
|
MR_comparePredLeaves(me->down,me,him,hisParent);
|
|
MR_comparePredLeaves(me->right,myParent,him,hisParent);
|
|
return;
|
|
} else {
|
|
if (me->source != NULL) {
|
|
|
|
/* predicate->invert can be set only in the predEntry predicates */
|
|
/* thus they are only visible after the predEntry predicates have been "unfolded" */
|
|
|
|
int sameSource=(me->source == him->source);
|
|
int sameInvert=1 &
|
|
(1 + me->inverted + him->inverted + me->source->inverted + him->source->inverted);
|
|
int samePredEntry=(me->source->predEntry != NULL
|
|
&& him->source->predEntry != NULL
|
|
&& me->source->predEntry == him->source->predEntry);
|
|
if (sameInvert && (sameSource || samePredEntry)) {
|
|
if (MR_identicalContext(me,him)) {
|
|
|
|
/* identical predicates */
|
|
|
|
if (hisParent->expr == PRED_OR_LIST &&
|
|
myParent->expr == PRED_OR_LIST) {
|
|
me->redundant=1;
|
|
} else if (hisParent->expr == PRED_AND_LIST &&
|
|
myParent->expr == PRED_AND_LIST) {
|
|
me->redundant=1;
|
|
} else if ( (hisParent->expr == PRED_OR_LIST &&
|
|
myParent->expr == PRED_AND_LIST)
|
|
||
|
|
(hisParent->expr == PRED_AND_LIST &&
|
|
myParent->expr == PRED_OR_LIST)
|
|
) {
|
|
myParent->redundant=1;
|
|
} else {
|
|
require (0,"MR_comparePredLeaves: not both PRED_LIST");
|
|
};
|
|
};
|
|
}; /* end same source or same predEntrr with same invert sense */
|
|
|
|
/* same predEntry but opposite invert sense */
|
|
|
|
if (!sameInvert && (sameSource || samePredEntry)) {
|
|
if (MR_identicalContext(me,him)) {
|
|
if (hisParent->expr == PRED_OR_LIST &&
|
|
myParent->expr == PRED_OR_LIST) {
|
|
myParent->isConst=1;
|
|
myParent->constValue=1;
|
|
} else if (hisParent->expr == PRED_AND_LIST &&
|
|
myParent->expr == PRED_AND_LIST) {
|
|
myParent->isConst=1;
|
|
myParent->constValue=0;
|
|
} else if ( (hisParent->expr == PRED_OR_LIST &&
|
|
myParent->expr == PRED_AND_LIST)
|
|
||
|
|
(hisParent->expr == PRED_AND_LIST &&
|
|
myParent->expr == PRED_OR_LIST)
|
|
) {
|
|
me->redundant=1;
|
|
} else {
|
|
require (0,"MR_comparePredLeaves: not both PRED_LIST");
|
|
};
|
|
};
|
|
}; /* end same predEntry with opposite invert sense */
|
|
};
|
|
|
|
MR_comparePredLeaves(me->right,myParent,him,hisParent);
|
|
return;
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_removeRedundantPredPass1(Predicate *me,Predicate *myParent)
|
|
#else
|
|
void MR_removeRedundantPredPass1(me,myParent)
|
|
Predicate *me;
|
|
Predicate *myParent;
|
|
#endif
|
|
{
|
|
if (me == NULL) return;
|
|
if (me->redundant) {
|
|
MR_removeRedundantPredPass1(me->right,myParent);
|
|
return;
|
|
};
|
|
if (me->expr == PRED_AND_LIST ||
|
|
me->expr == PRED_OR_LIST) {
|
|
MR_removeRedundantPredPass1(me->down,me);
|
|
MR_removeRedundantPredPass1(me->right,myParent);
|
|
} else {
|
|
require (me->source != NULL,"me->source == NULL");
|
|
if (myParent != NULL) {
|
|
MR_comparePredLeaves(myParent->down,myParent,me,myParent);
|
|
};
|
|
MR_removeRedundantPredPass1(me->right,myParent);
|
|
};
|
|
}
|
|
|
|
/* pretty much ignores things with the inverted bit set */
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate *MR_predFlatten(Predicate *p)
|
|
#else
|
|
Predicate *MR_predFlatten(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
if (p == NULL) return NULL;
|
|
if (p->expr == PRED_OR_LIST
|
|
|| p->expr == PRED_AND_LIST) {
|
|
|
|
Predicate *child;
|
|
Predicate *gchild;
|
|
Predicate **tail;
|
|
Predicate *next;
|
|
char *PRED_XXX_LIST=p->expr;
|
|
|
|
require (p->down != NULL,"MR_predFlatten AND/OR no child");
|
|
|
|
|
|
p->down=MR_predFlatten(p->down);
|
|
p->right=MR_predFlatten(p->right);
|
|
child=p->down;
|
|
if (child->right == NULL) {
|
|
child->right=p->right;
|
|
p->right=NULL;
|
|
p->down=NULL;
|
|
if (p->inverted) child->inverted=!child->inverted;
|
|
predicate_free(p);
|
|
return child;
|
|
};
|
|
|
|
/* make a single list of all children and grandchildren */
|
|
|
|
tail=&(p->down);
|
|
for (child=p->down; child != NULL; child=next) {
|
|
if (child->expr != PRED_XXX_LIST
|
|
|| child->inverted
|
|
|| child->predEntry != NULL) {
|
|
*tail=child;
|
|
tail=&(child->right);
|
|
next=child->right;
|
|
} else {
|
|
for (gchild=child->down;
|
|
gchild != NULL;
|
|
gchild=gchild->right) {
|
|
*tail=gchild;
|
|
tail=&(gchild->right);
|
|
};
|
|
next=child->right;
|
|
child->right=NULL;
|
|
child->down=NULL;
|
|
predicate_free(child);
|
|
};
|
|
};
|
|
*tail=NULL;
|
|
return p;
|
|
} else {
|
|
p->right=MR_predFlatten(p->right);
|
|
return p;
|
|
};
|
|
}
|
|
|
|
static char *alwaysFalseWarning=NULL;
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate *checkPredicateConflict(Predicate *p)
|
|
#else
|
|
Predicate *checkPredicateConflict(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
if (p->isConst) {
|
|
if (p->constValue == 1) {
|
|
predicate_free(p);
|
|
return NULL;
|
|
} else {
|
|
if (InfoP && !p->conflictReported) {
|
|
p->conflictReported=1;
|
|
fprintf(output,"\n#if 0\n\n");
|
|
fprintf(output,"The following predicate expression will always be false:\n\n");
|
|
MR_dumpPred1(1,p,1);
|
|
fprintf(output,"\n#endif\n");
|
|
};
|
|
|
|
if (alwaysFalseWarning != CurRule) {
|
|
alwaysFalseWarning=CurRule;
|
|
if (InfoP) {
|
|
warnNoFL(eMsg1("one (or more) predicate expression hoisted into rule \"%s\" are always false \
|
|
- see output file for more information",CurRule));
|
|
} else {
|
|
warnNoFL(eMsg1("one (or more) predicate expressions hoisted into rule \"%s\" are always false \
|
|
- use \"-info p\" for more information",CurRule));
|
|
};
|
|
};
|
|
};
|
|
};
|
|
return p;
|
|
}
|
|
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_countPredNodes(Predicate *p)
|
|
#else
|
|
int MR_countPredNodes(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
if (p == NULL) return 0;
|
|
return 1 + MR_countPredNodes(p->down) + MR_countPredNodes(p->right);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate *MR_predSimplifyALLX(Predicate *p,int skipPass3)
|
|
#else
|
|
Predicate *MR_predSimplifyALLX(p,skipPass3)
|
|
Predicate *p;
|
|
int skipPass3;
|
|
#endif
|
|
{
|
|
int countBefore;
|
|
int countAfter;
|
|
|
|
countAfter=MR_countPredNodes(p);
|
|
|
|
do {
|
|
if (p == NULL) return NULL;
|
|
if (p->right == NULL && p->down == NULL) return p;
|
|
countBefore=countAfter;
|
|
MR_simplifyInverted(p,0);
|
|
p=MR_predFlatten(p);
|
|
MR_removeRedundantPredPass1(p,NULL);
|
|
MR_removeRedundantPredPass2(p);
|
|
if (! skipPass3) {
|
|
p=checkPredicateConflict(p);
|
|
p=MR_removeRedundantPredPass3(p);
|
|
};
|
|
countAfter=MR_countPredNodes(p);
|
|
} while (countBefore != countAfter);
|
|
|
|
return p;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate *MR_predSimplifyALL(Predicate *p)
|
|
#else
|
|
Predicate *MR_predSimplifyALL(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
return MR_predSimplifyALLX(p,0);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_releaseResourcesUsedInRule(Node *n)
|
|
#else
|
|
void MR_releaseResourcesUsedInRule(n)
|
|
Node *n;
|
|
#endif
|
|
{
|
|
Node *next;
|
|
Junction *j;
|
|
int i;
|
|
|
|
if (n == NULL) return;
|
|
if (n->ntype == nJunction) {
|
|
j=(Junction *) n;
|
|
|
|
if (j->predicate != NULL) {
|
|
predicate_free(j->predicate);
|
|
j->predicate=NULL;
|
|
};
|
|
for (i=0; i< CLL_k; i++) {
|
|
set_free(j->fset[i]);
|
|
j->fset[i]=empty;
|
|
};
|
|
if (j->ftree != NULL) {
|
|
Tfree(j->ftree);
|
|
j->ftree=NULL;
|
|
};
|
|
if (j->jtype == EndRule) return;
|
|
if (j->jtype != RuleBlk && j->jtype != EndBlk) {
|
|
if (j->p2 != NULL && !j->ignore) { /* MR11 */
|
|
MR_releaseResourcesUsedInRule(j->p2);
|
|
};
|
|
};
|
|
};
|
|
next=MR_advance(n);
|
|
MR_releaseResourcesUsedInRule(next);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_allPredLeaves(Predicate *p)
|
|
#else
|
|
int MR_allPredLeaves(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
Predicate *q;
|
|
|
|
if (p == NULL) return 1;
|
|
|
|
for (q=p; q != NULL; q=q->right) {
|
|
if (q->down != NULL) return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
/* make sure it works for the last rule in a file */
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_offsetFromRule(Node *n)
|
|
#else
|
|
int MR_offsetFromRule(n)
|
|
Node *n;
|
|
#endif
|
|
{
|
|
Junction *j;
|
|
int offset=(-1);
|
|
|
|
for (j=SynDiag; j != NULL; j=(Junction *)j->p2) {
|
|
|
|
require (j->ntype == nJunction && j->jtype == RuleBlk,"Not a rule block");
|
|
|
|
if (n->file < j->file) {
|
|
return offset;
|
|
};
|
|
if (n->file == j->file) {
|
|
if (n->line < j->line) {
|
|
return (offset < 0) ? 0 : offset;
|
|
} else {
|
|
offset=n->line - j->line;
|
|
if (offset == 0) return 0;
|
|
};
|
|
};
|
|
};
|
|
return offset;
|
|
}
|
|
|
|
#define ruleNameMax 50
|
|
|
|
static char ruleNameStatic1[ruleNameMax];
|
|
static char ruleNameStatic2[ruleNameMax+10];
|
|
|
|
#ifdef __USE_PROTOS
|
|
char * MR_ruleNamePlusOffset(Node *n)
|
|
#else
|
|
char * MR_ruleNamePlusOffset(n)
|
|
Node *n;
|
|
#endif
|
|
{
|
|
int offset=MR_offsetFromRule(n);
|
|
|
|
strncpy(ruleNameStatic1,n->rname,ruleNameMax);
|
|
if (offset < 0) {
|
|
sprintf(ruleNameStatic2,"%s/?",ruleNameStatic1);
|
|
} else {
|
|
sprintf(ruleNameStatic2,"%s/%d",ruleNameStatic1,offset+1);
|
|
};
|
|
return ruleNameStatic2;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_max_height_of_tree(Tree *t)
|
|
#else
|
|
int MR_max_height_of_tree(t)
|
|
Tree *t;
|
|
#endif
|
|
{
|
|
int h;
|
|
int height=0;
|
|
Tree *u;
|
|
|
|
if (t == NULL) return 0;
|
|
|
|
require (t->token != ALT && t->token != EpToken,"MR_max_height_of_tree ALT or EpToken");
|
|
|
|
for (u=t; u != NULL; u=u->right) {
|
|
h=MR_max_height_of_tree(u->down)+1;
|
|
if (h > height) height=h;
|
|
};
|
|
return height;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_all_leaves_same_height(Tree *t,int depth)
|
|
#else
|
|
int MR_all_leaves_same_height(t,depth)
|
|
Tree *t;
|
|
int depth;
|
|
#endif
|
|
{
|
|
if (t == NULL) {
|
|
return (depth==0);
|
|
};
|
|
|
|
require (t->token != ALT && t->token != EpToken,"MR_all_leaves_same_height ALT or EpToken");
|
|
|
|
if (depth == 0) {
|
|
return 0;
|
|
} else {
|
|
if ( ! MR_all_leaves_same_height(t->down,depth-1)) {
|
|
return 0;
|
|
};
|
|
if (t->right == NULL) {
|
|
return 1;
|
|
} else {
|
|
return MR_all_leaves_same_height(t->right,depth);
|
|
};
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_projectTreeOntoSet(Tree *tree,int ck,set *ckset)
|
|
#else
|
|
void MR_projectTreeOntoSet(tree,ck,ckset)
|
|
Tree *tree;
|
|
int ck;
|
|
set *ckset;
|
|
#endif
|
|
{
|
|
if (tree == NULL) return;
|
|
|
|
require(tree->token != EpToken,"MR_projectTreeOntoSet: EpToken unexpected\n");
|
|
|
|
MR_projectTreeOntoSet(tree->right,ck,ckset);
|
|
if (tree->token == ALT) {
|
|
MR_projectTreeOntoSet(tree->down,ck,ckset);
|
|
} else {
|
|
if (ck > 1) {
|
|
MR_projectTreeOntoSet(tree->down,ck-1,ckset);
|
|
} else {
|
|
set_orel(tree->token,ckset);
|
|
};
|
|
};
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_comparePredicates(Predicate *a,Predicate *b)
|
|
#else
|
|
int MR_comparePredicates(a,b)
|
|
Predicate *a;
|
|
Predicate *b;
|
|
#endif
|
|
{
|
|
Predicate *p;
|
|
Predicate *q;
|
|
|
|
if (a == b) return 1;
|
|
if (a == NULL || b == NULL ) return 0;
|
|
if (a->down == NULL && b->down == NULL) {
|
|
|
|
/* predicate->invert can be set only in the predEntry predicates */
|
|
/* thus they are only visible after the predEntry predicates have been "unfolded" */
|
|
|
|
int sameSource=(a->source == b->source);
|
|
int sameInvert= 1 & (1 +a->inverted + b->inverted +
|
|
a->source->inverted + b->source->inverted);
|
|
int samePredEntry=(a->source->predEntry != NULL
|
|
&& b->source->predEntry != NULL
|
|
&& a->source->predEntry == b->source->predEntry);
|
|
if (sameInvert && (sameSource || samePredEntry)) {
|
|
if (MR_identicalContext(a,b)) {
|
|
return 1;
|
|
};
|
|
};
|
|
return 0;
|
|
};
|
|
if (a->down == NULL || b->down == NULL) return 0;
|
|
if (a->expr != b->expr) return 0;
|
|
|
|
for (p=a->down; p != NULL; p=p->right) {
|
|
for (q=b->down; q != NULL; q=q->right) {
|
|
if (MR_comparePredicates(p,q)) goto NEXT_P;
|
|
};
|
|
return 0;
|
|
NEXT_P:
|
|
continue;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* action->inverted can be set only when a predicate symbol appears in
|
|
* a rule: "rule : <<!XXX>>? X". It cannot be set under any
|
|
* other circumstances. In particular it cannot be set by
|
|
* "#pred NotA !A" or by "#pred Nota <<!A>>?". The first case
|
|
* creates a predEntry and the predicate expression of that predEntry
|
|
* has inverted set. In the second case, the code for handling "!"
|
|
* is only present in buildAction, which is not called by the #pred
|
|
* semantic routines, only when a <<...>>? is recognized as part of
|
|
* a rule definition.
|
|
*
|
|
* predicate->inverted can only be set by a predicate created by a #pred
|
|
* expression, such as "#pred NotA !A" or "#pred NotXY ! (X && Y) or
|
|
* "#pred XbarY !(X && Y)". In particular, it cannot be set by any
|
|
* predicate expression occurring under any other circumstances.
|
|
* The #pred predicate expressions are stored with in predEntry->pred
|
|
* and do not normally appear anywhere else until the predicates are
|
|
* "unfolded" in order to recognize redundancies, conflicts, and
|
|
* tautologies.
|
|
*
|
|
* The unfold routine expands all references to #pred expressions.
|
|
*
|
|
* The simplifyInvert goes through and propagates the invert bit so that
|
|
* all OR and AND nodes are un-inverted.
|
|
*
|
|
* Note that !(A and B) => (!A or !B)
|
|
* !(A or B) => (!A and !B)
|
|
*
|
|
* MR_unfold() is called to expand predicate symbols by replacing predicates
|
|
* that reference predicate entries with the copies of the predicate entries.
|
|
* Each reference receives a duplicate of the original. This is necessary
|
|
* because the next phase involves simplification and removal of redundant
|
|
* predicate nodes. Anyway, the point I'm making is that predicate->invert
|
|
* should not be set in any predicate until it has been expanded.
|
|
*
|
|
* This is a recursive structure, but there is no need for "recursive expansion"
|
|
* by which I mean a predicate symbol refers to other predicate symbols which
|
|
* must also be expanded.
|
|
*
|
|
* Recursive expansion is *not* performed by this routine because it is not
|
|
* necessary. Expansion of references is performed by predPrimary when
|
|
* a new predicate symbol is created by referring to others in the pred expr.
|
|
*/
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate *MR_unfold(Predicate *pred)
|
|
#else
|
|
Predicate *MR_unfold(pred)
|
|
Predicate *pred;
|
|
#endif
|
|
{
|
|
Predicate *result;
|
|
|
|
if (pred == NULL) return NULL;
|
|
|
|
pred->right=MR_unfold(pred->right);
|
|
|
|
if (pred->down == NULL) {
|
|
if (pred->source->predEntry != NULL) {
|
|
if (pred->source->predEntry->pred == NULL) {
|
|
; /* do nothing */ /* a reference to a literal #pred (perhaps with "!" */
|
|
} else {
|
|
result=predicate_dup_without_context(pred->source->predEntry->pred);
|
|
if (pred->inverted) {
|
|
result->inverted=!result->inverted;
|
|
};
|
|
if (pred->source->inverted) {
|
|
result->inverted=!result->inverted;
|
|
};
|
|
result->right=pred->right;
|
|
pred->right=NULL;
|
|
predicate_free(pred);
|
|
/*** result=MR_unfold(result); *** not necessary */ /* recursive expansion */
|
|
return result;
|
|
};
|
|
} else {
|
|
; /* do nothing */ /* an inline literal predicate */
|
|
};
|
|
} else {
|
|
pred->down=MR_unfold(pred->down);
|
|
};
|
|
return pred;
|
|
}
|
|
|
|
/* this should be called immediately after MR_unfold() and
|
|
at no other times
|
|
*/
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_simplifyInverted(Predicate *pred,int inverted)
|
|
#else
|
|
void MR_simplifyInverted(pred,inverted)
|
|
Predicate *pred;
|
|
int inverted;
|
|
#endif
|
|
{
|
|
int newInverted;
|
|
|
|
if (pred == NULL) return;
|
|
|
|
MR_simplifyInverted(pred->right,inverted);
|
|
|
|
newInverted= 1 & (inverted + pred->inverted);
|
|
|
|
if (pred->down == NULL) {
|
|
pred->inverted=newInverted;
|
|
} else {
|
|
if (newInverted != 0) {
|
|
if (pred->expr == PRED_AND_LIST) {
|
|
pred->expr=PRED_OR_LIST;
|
|
} else {
|
|
pred->expr=PRED_AND_LIST;
|
|
};
|
|
};
|
|
pred->inverted=0;
|
|
MR_simplifyInverted(pred->down,newInverted);
|
|
};
|
|
}
|
|
|
|
/* only remove it from AND and OR nodes, not leaves */
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_clearPredEntry(Predicate *p)
|
|
#else
|
|
void MR_clearPredEntry(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
if (p == NULL) return;
|
|
MR_clearPredEntry(p->down);
|
|
MR_clearPredEntry(p->right);
|
|
if (p->down != NULL) p->predEntry=NULL;
|
|
}
|
|
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_orphanRules(FILE *f)
|
|
#else
|
|
void MR_orphanRules(f)
|
|
FILE *f;
|
|
#endif
|
|
{
|
|
set a;
|
|
Junction *p;
|
|
unsigned e;
|
|
RuleEntry *re;
|
|
|
|
a=empty;
|
|
|
|
if (! InfoO) return;
|
|
|
|
for (p=SynDiag; p!=NULL; p = (Junction *)p->p2) {
|
|
if ( (Junction *) (p->end)->p1 == NULL) {
|
|
re=(RuleEntry *) hash_get(Rname,p->rname);
|
|
require (re != NULL,"RuleEntry == NULL");
|
|
set_orel(re->rulenum, &a);
|
|
}
|
|
}
|
|
|
|
if (set_deg(a) > 1) {
|
|
fprintf(f,"note: Start rules: {");
|
|
for (; !set_nil(a); set_rm(e,a)) {
|
|
e=set_int(a);
|
|
fprintf(f," %s",RulePtr[e]->rname);
|
|
};
|
|
fprintf(f," }\n");
|
|
};
|
|
set_free( a );
|
|
}
|
|
|
|
/* merge (X Y) and (X) to create (X) */
|
|
|
|
static int *mergeChain;
|
|
static Tree *mergeTree;
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree *MR_merge_tree_contexts_client(Tree *t,int chain[])
|
|
#else
|
|
Tree *MR_merge_tree_contexts_client(t,chain)
|
|
Tree *t;
|
|
int chain[];
|
|
#endif
|
|
{
|
|
if (t == NULL) return NULL;
|
|
if (chain[0] == 0) {
|
|
Tree *u=t->right;
|
|
t->right=NULL;
|
|
Tfree(t);
|
|
return MR_merge_tree_contexts_client(u,&chain[0]);
|
|
}
|
|
if (chain[0] == t->token) {
|
|
t->down=MR_merge_tree_contexts_client(t->down,&chain[1]);
|
|
};
|
|
t->right=MR_merge_tree_contexts_client(t->right,&chain[0]);
|
|
return t;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_iterateOverTreeContexts(Tree *t,int chain[])
|
|
#else
|
|
void MR_iterateOverTreeContexts(t,chain)
|
|
Tree *t;
|
|
int chain[];
|
|
#endif
|
|
{
|
|
if (t == NULL) return;
|
|
chain[0]=t->token;
|
|
if (t->down != NULL) {
|
|
MR_iterateOverTreeContexts(t->down,&chain[1]);
|
|
} else {
|
|
MR_merge_tree_contexts_client(mergeTree,mergeChain);
|
|
};
|
|
MR_iterateOverTreeContexts(t->right,&chain[0]);
|
|
chain[0]=0;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree *MR_merge_tree_contexts(Tree *t)
|
|
#else
|
|
Tree *MR_merge_tree_contexts(t)
|
|
Tree *t;
|
|
#endif
|
|
{
|
|
int h=MR_max_height_of_tree(t);
|
|
|
|
mergeTree=t;
|
|
mergeChain=(int *) calloc(h+1,sizeof(int));
|
|
require (mergeChain != NULL,"MR_merge_tree_contexts: can't alloc chain");
|
|
MR_iterateOverTreeContexts(t,mergeChain);
|
|
t=tshrink(t);
|
|
t=tflatten(t);
|
|
t=tleft_factor(t);
|
|
free ( (char *) mergeChain);
|
|
mergeChain=NULL;
|
|
return t;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree *MR_compute_pred_tree_context(Predicate *p)
|
|
#else
|
|
Tree *MR_compute_pred_tree_context(p)
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
Tree *t;
|
|
|
|
t=MR_compute_pred_tree_ctxXX(p);
|
|
MR_merge_tree_contexts(t);
|
|
return t;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_guardPred_plainSet(ActionNode *anode,Predicate *pred)
|
|
#else
|
|
void MR_guardPred_plainSet(anode,pred)
|
|
ActionNode *anode;
|
|
Predicate *pred;
|
|
#endif
|
|
{
|
|
Junction *j;
|
|
Predicate *workPred;
|
|
set maskSet;
|
|
|
|
maskSet=empty;
|
|
|
|
if (!MRhoisting) return;
|
|
|
|
/* it doesn't really matter whether the predicate has
|
|
depth k=1 or k>1 because we're not really looking
|
|
at the predicate itself, just the stuff "behind"
|
|
the predicate.
|
|
*/
|
|
|
|
/* shouldn't have to worry about REACHing off the end
|
|
of the rule containing the predicate because the
|
|
Rule->end->halt should have been set already by the
|
|
the code which handles RuleRef nodes.
|
|
|
|
We don't want to REACH off the end of the rule because
|
|
this would give the "global" follow context rather than
|
|
the "local" context.
|
|
|
|
r1a : (A)? => <<p>>? r2 (A|B)
|
|
r1b : (A)? => <<p>>? r2 (A|C)
|
|
r2 : ();
|
|
|
|
For r1a we want follow of predicate = {A B}
|
|
we want plainSet = {B}
|
|
For r1b we want follow of predicate = {A C}
|
|
we want plainSet = {C}
|
|
*/
|
|
|
|
require (anode->next->ntype == nJunction,"MR_guardpred_plainSet not Junction");
|
|
j=(Junction *)(anode->next);
|
|
|
|
workPred=predicate_dup_without_context(pred);
|
|
workPred->k=1;
|
|
workPred->scontext[1]=MR_First(1,j, &(workPred->completionSet) );
|
|
MR_complete_predicates(1,workPred);
|
|
if (pred->k == 1) {
|
|
maskSet=pred->scontext[1];
|
|
} else {
|
|
MR_projectTreeOntoSet(pred->tcontext,1,&maskSet);
|
|
}
|
|
pred->plainSet=set_dif(workPred->scontext[1],maskSet);
|
|
predicate_free(workPred);
|
|
}
|
|
|
|
/*******************************************************************************/
|
|
|
|
static Tree * suppressTree;
|
|
static int * suppressChain; /* element 0 not used */
|
|
static set * suppressSets;
|
|
static Node * suppressNode;
|
|
static int suppressChainLength;
|
|
int MR_SuppressSearch=0;
|
|
static int suppressSucceeded;
|
|
static Predicate * suppressPredicate;
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_isChain(Tree *t)
|
|
#else
|
|
int MR_isChain(t)
|
|
Tree *t;
|
|
#endif
|
|
{
|
|
Tree *u;
|
|
|
|
for (u=t; u != NULL; u=u->down) {
|
|
if (u->right != NULL) return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
int MR_suppressK_client(Tree *tree,int tokensInChain[])
|
|
#else
|
|
int MR_suppressK_client(tree,tokensInChain)
|
|
Tree *tree;
|
|
int tokensInChain[];
|
|
#endif
|
|
{
|
|
int i;
|
|
set *save_fset;
|
|
int save_ConstrainSearch;
|
|
set incomplete;
|
|
Tree *t;
|
|
|
|
suppressSucceeded=0; /* volatile */
|
|
|
|
if (suppressSets == NULL) {
|
|
suppressSets=(set *) calloc (CLL_k+1,sizeof(set));
|
|
require (suppressSets != NULL,"MR_suppressK_client: suppressSets alloc");
|
|
};
|
|
|
|
for (suppressChainLength=1;
|
|
tokensInChain[suppressChainLength+1] != 0;
|
|
suppressChainLength++) {};
|
|
|
|
require (suppressChainLength != 0,"MR_suppressK_client: chain empty");
|
|
|
|
for (i=1 ; i <= suppressChainLength ; i++) {
|
|
set_clr(suppressSets[i]);
|
|
set_orel( (unsigned) tokensInChain[i],
|
|
&suppressSets[i]);
|
|
};
|
|
|
|
save_fset=fset;
|
|
save_ConstrainSearch=ConstrainSearch;
|
|
|
|
fset=suppressSets;
|
|
|
|
MR_SuppressSearch=1;
|
|
MR_AmbSourceSearch=1;
|
|
MR_MaintainBackTrace=1;
|
|
ConstrainSearch=1;
|
|
|
|
maxk = suppressChainLength;
|
|
|
|
incomplete=empty;
|
|
t=NULL;
|
|
|
|
/*** constrain = &(fset[1]); ***/
|
|
|
|
MR_setConstrainPointer(&(fset[1])); /* MR18 */
|
|
|
|
MR_pointerStackReset(&MR_BackTraceStack);
|
|
|
|
TRAV(suppressNode,maxk,&incomplete,t);
|
|
|
|
Tfree(t);
|
|
|
|
require (set_nil(incomplete),"MR_suppressK_client TRAV incomplete");
|
|
require (MR_BackTraceStack.count == 0,
|
|
"MR_suppressK_client: MR_BackTraceStack.count != 0");
|
|
set_free(incomplete);
|
|
|
|
ConstrainSearch=save_ConstrainSearch;
|
|
fset=save_fset;
|
|
|
|
MR_AmbSourceSearch=0;
|
|
MR_MaintainBackTrace=0;
|
|
MR_SuppressSearch=0;
|
|
return suppressSucceeded;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
Tree * MR_iterateOverTreeSuppressK(Tree *t,int chain[])
|
|
#else
|
|
Tree * MR_iterateOverTreeSuppressK(t,chain)
|
|
Tree *t;
|
|
int chain[];
|
|
#endif
|
|
{
|
|
if (t == NULL) return NULL;
|
|
t->right=MR_iterateOverTreeSuppressK(t->right,&chain[0]);
|
|
chain[0]=t->token;
|
|
if (t->down != NULL) {
|
|
t->down=MR_iterateOverTreeSuppressK(t->down,&chain[1]);
|
|
if (t->down == NULL) {
|
|
Tree *u=t->right;
|
|
t->right=NULL;
|
|
Tfree(t);
|
|
chain[0]=0;
|
|
return u;
|
|
};
|
|
} else {
|
|
MR_suppressK_client(suppressTree,suppressChain);
|
|
if (suppressSucceeded) {
|
|
Tree *u=t->right;
|
|
t->right=NULL;
|
|
Tfree(t);
|
|
chain[0]=0;
|
|
return u;
|
|
};
|
|
};
|
|
chain[0]=0;
|
|
return t;
|
|
}
|
|
|
|
/* @@@ */
|
|
|
|
#ifdef __USE_PROTOS
|
|
Predicate * MR_suppressK(Node *j,Predicate *p)
|
|
#else
|
|
Predicate * MR_suppressK(j,p)
|
|
Node *j;
|
|
Predicate *p;
|
|
#endif
|
|
{
|
|
Predicate *result;
|
|
int guardPred=0;
|
|
int ampersandPred=0;
|
|
Node *nodePrime;
|
|
|
|
if (! MRhoistingk) {
|
|
return p;
|
|
}
|
|
|
|
if (! MRhoisting) return p;
|
|
if (CLL_k == 1) return p;
|
|
|
|
if (suppressChain == NULL) {
|
|
suppressChain=(int *) calloc(CLL_k+2,sizeof(int));
|
|
require (suppressChain != NULL,"MR_suppressK: can't allocate chain");
|
|
}
|
|
|
|
if (p == NULL) return NULL;
|
|
|
|
if (j->ntype == nJunction) {
|
|
nodePrime=(Node *) MR_junctionWithoutP2( (Junction *) j);
|
|
} else {
|
|
nodePrime=j;
|
|
};
|
|
|
|
p->down=MR_suppressK(j,p->down);
|
|
p->right=MR_suppressK(j,p->right);
|
|
if (p->down != NULL) {
|
|
result=p;
|
|
goto EXIT;
|
|
};
|
|
if (p->k == 1) {
|
|
result=p;
|
|
goto EXIT;
|
|
};
|
|
|
|
if (p->source != NULL) {
|
|
if (p->source->guardpred != NULL) guardPred=1;
|
|
if (p->source->ampersandPred != NULL) ampersandPred=1;
|
|
}
|
|
|
|
suppressPredicate=p;
|
|
suppressNode=nodePrime; /* was j*/
|
|
|
|
suppressTree=p->tcontext;
|
|
|
|
if (guardPred || ampersandPred) {
|
|
p->tcontext=MR_iterateOverTreeSuppressK(suppressTree,&suppressChain[1]);
|
|
if (p->tcontext == NULL) {
|
|
predicate_free(p);
|
|
result=NULL;
|
|
goto EXIT;
|
|
};
|
|
} else {
|
|
if (MR_isChain(p->tcontext)) {
|
|
p->tcontext=MR_iterateOverTreeSuppressK(suppressTree,&suppressChain[1]);
|
|
if (p->tcontext == NULL) {
|
|
predicate_free(p);
|
|
result=NULL;
|
|
goto EXIT;
|
|
};
|
|
}
|
|
}
|
|
result=p;
|
|
EXIT:
|
|
return result;
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_suppressSearchReport(void)
|
|
#else
|
|
void MR_suppressSearchReport()
|
|
#endif
|
|
{
|
|
int i;
|
|
Node *p;
|
|
TokNode *tn;
|
|
int depth;
|
|
set setAnd;
|
|
|
|
/* number of tokens in back trace stack matches length of chain */
|
|
|
|
depth=0;
|
|
for (i=0; i < MR_BackTraceStack.count ; i++) {
|
|
p=(Node *) MR_BackTraceStack.data[i];
|
|
if (p->ntype == nToken) depth++;
|
|
};
|
|
|
|
require (depth == suppressChainLength,"depth > suppressChainLength");
|
|
|
|
/* token codes match chain */
|
|
|
|
depth=0;
|
|
for (i=0; i < MR_BackTraceStack.count ; i++) {
|
|
p=(Node *) MR_BackTraceStack.data[i];
|
|
if (p->ntype != nToken) continue;
|
|
tn=(TokNode *) p;
|
|
depth++;
|
|
if (set_nil(tn->tset)) {
|
|
require(set_el( (unsigned) tn->token,fset[depth]),
|
|
"MR_suppressSearchReport: no match to #token in chain");
|
|
} else {
|
|
setAnd=set_and(fset[depth],tn->tset);
|
|
require(!set_nil(setAnd),
|
|
"MR_suppressSearchReport: no match to #token set in chain");
|
|
set_free(setAnd);
|
|
};
|
|
};
|
|
|
|
/* have a match - now remove it from the predicate */
|
|
|
|
suppressSucceeded=1;
|
|
|
|
if (suppressSucceeded) {
|
|
fprintf(output,"\n");
|
|
fprintf(output,"#if 0\n");
|
|
fprintf(output,"\n");
|
|
fprintf(output,"Part (or all) of predicate with depth > 1 suppressed by ");
|
|
fprintf(output,"alternative without predicate\n\n");
|
|
MR_dumpPred(suppressPredicate,1);
|
|
fprintf(output,"The token sequence which is suppressed:");
|
|
fprintf(output," (");
|
|
for (i=1; i <= suppressChainLength; i++) {
|
|
fprintf(output," %s",TerminalString(suppressChain[i]));
|
|
};
|
|
fprintf(output," )\n");
|
|
fprintf(output,"The sequence of references which generate that sequence of tokens:\n\n");
|
|
|
|
MR_backTraceDumpItemReset();
|
|
|
|
for (i=0; i < MR_BackTraceStack.count ; i++) {
|
|
MR_backTraceDumpItem(output,0,(Node *) MR_BackTraceStack.data[i]);
|
|
};
|
|
fprintf(output,"\n");
|
|
fprintf(output,"#endif\n");
|
|
}
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_markCompromisedRule(Node *n)
|
|
#else
|
|
void MR_markCompromisedRule(n)
|
|
Node *n;
|
|
#endif
|
|
{
|
|
RuleEntry *q;
|
|
Node *mark=NULL;
|
|
Junction *j;
|
|
|
|
if (n->ntype == nRuleRef) {
|
|
mark=(Node *) MR_ruleReferenced( (RuleRefNode *) n);
|
|
} else if (n->ntype == nToken) {
|
|
mark=n;
|
|
} else if (n->ntype == nJunction) {
|
|
j=(Junction *)n;
|
|
switch (j->jtype) {
|
|
case aOptBlk:
|
|
case aLoopBlk:
|
|
case RuleBlk:
|
|
case EndRule:
|
|
case aPlusBlk:
|
|
case aLoopBegin:
|
|
mark=n;
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
}
|
|
|
|
if (mark == NULL) return;
|
|
|
|
require (RulePtr != NULL,"RulePtr not initialized");
|
|
|
|
q = (RuleEntry *) hash_get(Rname,mark->rname);
|
|
require (q != NULL,"RuleEntry not found");
|
|
set_orel(q->rulenum,&MR_CompromisedRules);
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_alphaBetaTraceReport(void)
|
|
#else
|
|
void MR_alphaBetaTraceReport()
|
|
#endif
|
|
{
|
|
int i;
|
|
|
|
if (! AlphaBetaTrace) return;
|
|
|
|
MR_AlphaBetaMessageCount++;
|
|
|
|
fprintf(output,"\n");
|
|
fprintf(output,"#if 0\n");
|
|
fprintf(output,"\n");
|
|
fprintf(output,"Trace of references leading to attempt to compute the follow set of\n");
|
|
fprintf(output,"alpha in an \"(alpha)? beta\" block. It is not possible for antlr to\n");
|
|
fprintf(output,"compute this follow set because it is not known what part of beta has\n");
|
|
fprintf(output,"already been matched by alpha and what part remains to be matched.\n");
|
|
fprintf(output,"\n");
|
|
fprintf(output,"Rules which make use of the incorrect follow set will also be incorrect\n");
|
|
fprintf(output,"\n");
|
|
|
|
MR_backTraceDumpItemReset();
|
|
|
|
for (i=0; i < MR_BackTraceStack.count ; i++) {
|
|
MR_backTraceDumpItem(output,0,(Node *) MR_BackTraceStack.data[i]);
|
|
if (i < MR_BackTraceStack.count-1) {
|
|
MR_markCompromisedRule( (Node *) MR_BackTraceStack.data[i]);
|
|
};
|
|
};
|
|
fprintf(output,"\n");
|
|
fprintf(output,"#endif\n");
|
|
}
|
|
|
|
#ifdef __USE_PROTOS
|
|
void MR_dumpRuleSet(set s)
|
|
#else
|
|
void MR_dumpRuleSet(s)
|
|
set s;
|
|
#endif
|
|
{
|
|
unsigned *cursor;
|
|
unsigned *origin=set_pdq(s);
|
|
|
|
require(origin != NULL,"set_pdq failed");
|
|
|
|
if (RulePtr == NULL) {
|
|
fprintf(stderr,"RulePtr[] not yet initialized");
|
|
} else {
|
|
for (cursor=origin; *cursor != nil ; cursor++) {
|
|
/**** if (cursor != origin) fprintf(stderr,","); ****/
|
|
fprintf(stderr," %s",RulePtr[*cursor]->rname);
|
|
fprintf(stderr,"\n");
|
|
};
|
|
free( (char *) origin);
|
|
};
|
|
}
|