| /* | |
| * 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 expresssions 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); | |
| }; | |
| } |