X-Git-Url: https://pd.if.org/git/?p=pccts;a=blobdiff_plain;f=antlr%2Ffset.c;fp=antlr%2Ffset.c;h=71f85ca9cd8e0764e9595503939c4c6caf3d48c6;hp=0000000000000000000000000000000000000000;hb=129ce0f1c9d43c04ed8198ac184bce8d8be0042e;hpb=b5b3c41d4e99ca613b441d68458aa3cd873aa417 diff --git a/antlr/fset.c b/antlr/fset.c new file mode 100755 index 0000000..71f85ca --- /dev/null +++ b/antlr/fset.c @@ -0,0 +1,978 @@ +/* + * fset.c + * + * $Id: fset.c,v 1.6 95/06/15 18:07:09 parrt Exp $ + * $Revision: 1.6 $ + * + * Compute FIRST and FOLLOW sets. + * + * SOFTWARE RIGHTS + * + * We reserve no LEGAL rights to the Purdue Compiler Construction Tool + * Set (PCCTS) -- PCCTS is in the public domain. An individual or + * company may do whatever they wish with source code distributed with + * PCCTS or the code generated by PCCTS, including the incorporation of + * PCCTS, or its output, into commerical software. + * + * We encourage users to develop software with PCCTS. However, we do ask + * that credit is given to us for developing PCCTS. By "credit", + * we mean that if you incorporate our source code into one of your + * programs (commercial product, research project, or otherwise) that you + * acknowledge this fact somewhere in the documentation, research report, + * etc... If you like PCCTS and have developed a nice tool with the + * output, please mention that you developed it using PCCTS. In + * addition, we ask that this header remain intact in our source code. + * As long as these guidelines are kept, we expect to continue enhancing + * this system and expect to make other tools available as they are + * completed. + * + * ANTLR 1.33 + * Terence Parr + * Parr Research Corporation + * with Purdue University and AHPCRC, University of Minnesota + * 1989-1995 + */ +#include +#ifdef __cplusplus +#ifndef __STDC__ +#define __STDC__ +#endif +#endif +#include "set.h" +#include "syn.h" +#include "hash.h" +#include "generic.h" +#include "dlgdef.h" + +extern char *PRED_AND_LIST; +extern char *PRED_OR_LIST; + +#ifdef __STDC__ +static void ensure_predicates_cover_ambiguous_lookahead_sequences(Junction *, Junction *, char *, Tree *); +#else +static void ensure_predicates_cover_ambiguous_lookahead_sequences(); +#endif + +/* + * What tokens are k tokens away from junction q? + * + * Follow both p1 and p2 paths (unless RuleBlk) to collect the tokens k away from this + * node. + * We lock the junction according to k--the lookahead. If we have been at this + * junction before looking for the same, k, number of lookahead tokens, we will + * do it again and again...until we blow up the stack. Locks are only used on aLoopBlk, + * RuleBlk, aPlusBlk and EndRule junctions to remove/detect infinite recursion from + * FIRST and FOLLOW calcs. + * + * If p->jtype == EndRule we are going to attempt a FOLLOW. (FOLLOWs are really defined + * in terms of FIRST's, however). To proceed with the FOLLOW, p->halt cannot be + * set. p->halt is set to indicate that a reference to the current rule is in progress + * and the FOLLOW is not desirable. + * + * If we attempt a FOLLOW and find that there is no FOLLOW or REACHing beyond the EndRule + * junction yields an empty set, replace the empty set with EOF. No FOLLOW means that + * only EOF can follow the current rule. This normally occurs only on the start symbol + * since all other rules are referenced by another rule somewhere. + * + * Normally, both p1 and p2 are followed. However, checking p2 on a RuleBlk node is + * the same as checking the next rule which is clearly incorrect. + * + * Cycles in the FOLLOW sense are possible. e.g. Fo(c) requires Fo(b) which requires + * Fo(c). Both Fo(b) and Fo(c) are defined to be Fo(b) union Fo(c). Let's say + * Fo(c) is attempted first. It finds all of the FOLLOW symbols and then attempts + * to do Fo(b) which finds of its FOLLOW symbols. So, we have: + * + * Fo(c) + * / \ + * a set Fo(b) + * / \ + * a set Fo(c) .....Hmmmm..... Infinite recursion! + * + * The 2nd Fo(c) is not attempted and Fo(b) is left deficient, but Fo(c) is now + * correctly Fo(c) union Fo(b). We wish to pick up where we left off, so the fact + * that Fo(b) terminated early means that we lack Fo(c) in the Fo(b) set already + * laying around. SOOOOoooo, we track FOLLOW cycles. All FOLLOW computations are + * cached in a hash table. After the sequence of FOLLOWs finish, we reconcile all + * cycles --> correct all Fo(rule) sets in the cache. + * + * Confused? Good! Read my MS thesis [Purdue Technical Report TR90-30]. + * TJP 8/93 -- can now read PhD thesis from Purdue. + * + * Also, FIRST sets are cached in the hash table. Keys are (rulename,Fi/Fo,k). + * Only FIRST sets, for which the FOLLOW is not included, are stored. + * + * SPECIAL CASE of (...)+ blocks: + * I added an optional alt so that the alts could see what + * was behind the (...)+ block--thus using enough lookahead + * to branch out rather than just enough to distinguish + * between alts in the (...)+. However, when the FIRST("(...)+") is + * is needed, must not use this last "optional" alt. This routine + * turns off this path by setting a new 'ignore' flag for + * the alt and then resetting it afterwards. + */ +set +#ifdef __STDC__ +rJunc( Junction *p, int k, set *rk ) +#else +rJunc( p, k, rk ) +Junction *p; +int k; +set *rk; +#endif +{ + set a, b; + require(p!=NULL, "rJunc: NULL node"); + require(p->ntype==nJunction, "rJunc: not junction"); + +#ifdef DBG_LL1 + if ( p->jtype == RuleBlk ) fprintf(stderr, "FIRST(%s,%d) \n",((Junction *)p)->rname,k); + else fprintf(stderr, "rJunc: %s in rule %s\n", + decodeJType[p->jtype], ((Junction *)p)->rname); +#endif + /* if this is one of the added optional alts for (...)+ then return */ + if ( p->ignore ) return empty; + + /* locks are valid for aLoopBlk,aPlusBlk,RuleBlk,EndRule junctions only */ + if ( p->jtype==aLoopBlk || p->jtype==RuleBlk || + p->jtype==aPlusBlk || p->jtype==EndRule ) + { + require(p->lock!=NULL, "rJunc: lock array is NULL"); + if ( p->lock[k] ) + { + if ( p->jtype == EndRule ) /* FOLLOW cycle? */ + { +#ifdef DBG_LL1 + fprintf(stderr, "FOLLOW cycle to %s: panic!\n", p->rname); +#endif + RegisterCycle(p->rname, k); + } + return empty; + } + if ( p->jtype == RuleBlk && p->end->halt ) /* check for FIRST cache */ + { + CacheEntry *q = (CacheEntry *) hash_get(Fcache, Fkey(p->rname,'i',k)); + if ( q != NULL ) + { + set_orin(rk, q->rk); + return set_dup( q->fset ); + } + } + if ( p->jtype == EndRule ) /* FOLLOW set cached already? */ + { + CacheEntry *q = (CacheEntry *) hash_get(Fcache, Fkey(p->rname,'o',k)); + if ( q != NULL ) + { +#ifdef DBG_LL1 + fprintf(stderr, "cache for FOLLOW(%s,%d):", p->rname,k); + s_fprT(stderr, q->fset); + if ( q->incomplete ) fprintf(stderr, " (incomplete)"); + fprintf(stderr, "\n"); +#endif + if ( !q->incomplete ) + { + return set_dup( q->fset ); + } + } + } + p->lock[k] = TRUE; /* This rule is busy */ + } + + a = b = empty; + + if ( p->jtype == EndRule ) + { + if ( p->halt ) /* don't want FOLLOW here? */ + { + p->lock[k] = FALSE; + set_orel(k, rk); /* indicate this k value needed */ + return empty; + } + FoPush(p->rname, k); /* Attempting FOLLOW */ + if ( p->p1 == NULL ) set_orel((TokenInd!=NULL?TokenInd[EofToken]:EofToken), &a);/* if no FOLLOW assume EOF */ +#ifdef DBG_LL1 + fprintf(stderr, "-->FOLLOW(%s,%d)\n", p->rname,k); +#endif + } + + if ( p->p1 != NULL ) REACH(p->p1, k, rk, a); + + /* C a c h e R e s u l t s */ + if ( p->jtype == RuleBlk && p->end->halt ) /* can save FIRST set? */ + { + CacheEntry *q = newCacheEntry( Fkey(p->rname,'i',k) ); + /*fprintf(stderr, "Caching %s FIRST %d\n", p->rname, k);*/ + hash_add(Fcache, Fkey(p->rname,'i',k), (Entry *)q); + q->fset = set_dup( a ); + q->rk = set_dup( *rk ); + } + + if ( p->jtype == EndRule ) /* just completed FOLLOW? */ + { + /* Cache Follow set */ + CacheEntry *q = (CacheEntry *) hash_get(Fcache, Fkey(p->rname,'o',k)); + if ( q==NULL ) + { + q = newCacheEntry( Fkey(p->rname,'o',k) ); + hash_add(Fcache, Fkey(p->rname,'o',k), (Entry *)q); + } + /*fprintf(stderr, "Caching %s FOLLOW %d\n", p->rname, k);*/ + if ( set_nil(a) && !q->incomplete ) + { + /* Don't ever save a nil set as complete. + * Turn it into an eof set. + */ + set_orel(EofToken, &a); + } + set_orin(&(q->fset), a); + FoPop( k ); + if ( FoTOS[k] == NULL && Cycles[k] != NULL ) ResolveFoCycles(k); +#ifdef DBG_LL1 + fprintf(stderr, "saving FOLLOW(%s,%d):", p->rname, k); + s_fprT(stderr, q->fset); + if ( q->incomplete ) fprintf(stderr, " (incomplete)"); + fprintf(stderr, "\n"); +#endif + } + + if ( p->jtype != RuleBlk && p->p2 != NULL ) REACH(p->p2, k, rk, b); + if ( p->jtype==aLoopBlk || p->jtype==RuleBlk || + p->jtype==aPlusBlk || p->jtype==EndRule ) + p->lock[k] = FALSE; /* unlock node */ + + set_orin(&a, b); + set_free(b); + return a; +} + +set +#ifdef __STDC__ +rRuleRef( RuleRefNode *p, int k, set *rk_out ) +#else +rRuleRef( p, k, rk_out ) +RuleRefNode *p; +int k; +set *rk_out; +#endif +{ + set rk; + Junction *r; + int k2; + set a, rk2, b; + int save_halt; + RuleEntry *q = (RuleEntry *) hash_get(Rname, p->text); + require(p!=NULL, "rRuleRef: NULL node"); + require(p->ntype==nRuleRef, "rRuleRef: not rule ref"); + +#ifdef DBG_LL1 + fprintf(stderr, "rRuleRef: %s\n", p->text); +#endif + if ( q == NULL ) + { + warnFL( eMsg1("rule %s not defined",p->text), FileStr[p->file], p->line ); + REACH(p->next, k, rk_out, a); + return a; + } + rk2 = empty; + r = RulePtr[q->rulenum]; + if ( r->lock[k] ) + { + errNoFL( eMsg2("infinite left-recursion to rule %s from rule %s", + r->rname, p->rname) ); + return empty; + } + save_halt = r->end->halt; + r->end->halt = TRUE; /* don't let reach fall off end of rule here */ + rk = empty; + REACH(r, k, &rk, a); + r->end->halt = save_halt; + while ( !set_nil(rk) ) { + k2 = set_int(rk); + set_rm(k2, rk); + REACH(p->next, k2, &rk2, b); + set_orin(&a, b); + set_free(b); + } + set_free(rk); /* this has no members, but free it's memory */ + set_orin(rk_out, rk2); /* remember what we couldn't do */ + set_free(rk2); + return a; +} + +/* + * Return FIRST sub k ( token_node ) + * + * TJP 10/11/93 modified this so that token nodes that are actually + * ranges (T1..T2) work. + */ +set +#ifdef __STDC__ +rToken( TokNode *p, int k, set *rk ) +#else +rToken( p, k, rk ) +TokNode *p; +int k; +set *rk; +#endif +{ + set a; + require(p!=NULL, "rToken: NULL node"); + require(p->ntype==nToken, "rToken: not token node"); + +#ifdef DBG_LL1 + fprintf(stderr, "rToken: %s\n", (TokenString(p->token)!=NULL)?TokenString(p->token): + ExprString(p->token)); +#endif + if ( k-1 == 0 ) + { + if ( !set_nil(p->tset) ) return set_dup(p->tset); + return set_of(p->token); + } + REACH(p->next, k-1, rk, a); + + return a; +} + +set +#ifdef __STDC__ +rAction( ActionNode *p, int k, set *rk ) +#else +rAction( p, k, rk ) +ActionNode *p; +int k; +set *rk; +#endif +{ + set a; + require(p!=NULL, "rJunc: NULL node"); + require(p->ntype==nAction, "rJunc: not action"); + + REACH(p->next, k, rk, a); /* ignore actions */ + return a; +} + + /* A m b i g u i t y R e s o l u t i o n */ + + +void +#ifdef __STDC__ +dumpAmbigMsg( set *fset, FILE *f, int want_nls ) +#else +dumpAmbigMsg( fset, f, want_nls ) +set *fset; +FILE *f; +int want_nls; +#endif +{ + int i; + + if ( want_nls ) fprintf(f, "\n\t"); + else fprintf(f, " "); + for (i=1; i<=CLL_k; i++) + { + if ( i>1 ) + { + if ( !want_nls ) fprintf(f, ", "); + } + if ( set_deg(fset[i]) > 3 && elevel == 1 ) + { + int e,m; + fprintf(f, "{"); + for (m=1; m<=3; m++) + { + e=set_int(fset[i]); + fprintf(f, " %s", TerminalString(e)); + set_rm(e, fset[i]); + } + fprintf(f, " ... }"); + } + else s_fprT(f, fset[i]); + if ( want_nls ) fprintf(f, "\n\t"); + } + fprintf(f, "\n"); +} + +static void +#ifdef __USE_PROTOS +verify_context(Predicate *predicate) +#else +verify_context(predicate) +Predicate *predicate; +#endif +{ + if ( predicate == NULL ) return; + + if ( predicate->expr == PRED_OR_LIST || + predicate->expr == PRED_AND_LIST ) + { + verify_context(predicate->down); + return; + } + + if ( !predicate->source->ctxwarned && predicate->source->guardpred==NULL && + ((predicate->k > 1 && + !is_single_tuple(predicate->tcontext)) || + ( predicate->k == 1 && + set_deg(predicate->scontext[1])>1 )) ) + { + fprintf(stderr, ErrHdr, FileStr[predicate->source->file], + predicate->source->line); + fprintf(stderr, " warning: predicate applied for >1 lookahead %d-sequences\n", predicate->k); + fprintf(stderr, ErrHdr, FileStr[predicate->source->file], + predicate->source->line); + fprintf(stderr, " [you may only want one lookahead %d-sequence to apply.\n", predicate->k); + fprintf(stderr, ErrHdr, FileStr[predicate->source->file], + predicate->source->line); + fprintf(stderr, " Try using a context guard '(...)? =>'.]\n"); + predicate->source->ctxwarned = 1; + } +} + +/* + * If delta is the set of ambiguous lookahead sequences, then make sure that + * the predicate(s) for productions alt1,alt2 cover the sequences in delta. + * + * For example, + * a : <>? (A B|A C) + * | b + * ; + * b : <>? A B + * | A C + * ; + * + * This should give a warning that (A C) predicts both productions and alt2 + * does not have a predicate in the production that generates (A C). + * + * The warning detection is simple. Let delta = LOOK(alt1) intersection LOOK(alt2). + * Now, if ( delta set-difference context(predicates-for-alt1) != empty then + * alt1 does not "cover" all ambiguous sequences. + * + * If ambig is nonempty, then ambig in LL(k) sense -> use tree info; else use fset + * info. Actually, sets are used only if k=1 for this grammar. + */ +static void +#ifdef __USE_PROTOS +ensure_predicates_cover_ambiguous_lookahead_sequences( Junction *alt1, Junction *alt2, char *sub, Tree *ambig ) +#else +ensure_predicates_cover_ambiguous_lookahead_sequences( alt1, alt2, sub, ambig ) +Junction *alt1; +Junction *alt2; +char *sub; +Tree *ambig; +#endif +{ + if ( !ParseWithPredicates ) return; + + if ( ambig!=NULL ) + { + Tree *non_covered = NULL; + if ( alt1->predicate!=NULL ) + non_covered = tdif(ambig, alt1->predicate, alt1->fset, alt2->fset); + if ( (non_covered!=NULL || alt1->predicate==NULL) && WarningLevel>1 ) + { + fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); + fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", + alt1->altnum, sub); + if ( alt1->predicate!=NULL && non_covered!=NULL ) + { + fprintf(stderr, " upon"); + preorder(non_covered); + } + else if ( alt1->predicate==NULL ) + { + fprintf(stderr, " upon"); + preorder(ambig->down); + } + fprintf(stderr, "\n"); + } + Tfree(non_covered); + non_covered = NULL; + if ( alt2->predicate!=NULL ) + non_covered = tdif(ambig, alt2->predicate, alt1->fset, alt2->fset); + if ( (non_covered!=NULL || alt2->predicate==NULL) && WarningLevel>1 ) + { + fprintf(stderr, ErrHdr, FileStr[alt2->file], alt2->line); + fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", + alt2->altnum, sub); + if ( alt2->predicate!=NULL && non_covered!=NULL ) + { + fprintf(stderr, " upon"); + preorder(non_covered); + } + else if ( alt2->predicate==NULL ) + { + fprintf(stderr, " upon"); + preorder(ambig->down); + } + fprintf(stderr, "\n"); + } + Tfree(non_covered); + } + else if ( !set_nil(alt1->fset[1]) ) + { + set delta, non_covered; + delta = set_and(alt1->fset[1], alt2->fset[1]); + non_covered = set_dif(delta, covered_set(alt1->predicate)); + if ( set_deg(non_covered)>0 && WarningLevel>1 ) + { + fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); + fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", + alt1->altnum, sub); + if ( alt1->predicate!=NULL ) + { + fprintf(stderr, " upon "); + s_fprT(stderr, non_covered); + } + fprintf(stderr, "\n"); + } + set_free( non_covered ); + non_covered = set_dif(delta, covered_set(alt2->predicate)); + if ( set_deg(non_covered)>0 && WarningLevel>1 ) + { + fprintf(stderr, ErrHdr, FileStr[alt2->file], alt2->line); + fprintf(stderr, " warning: alt %d %shas no predicate to resolve ambiguity", + alt2->altnum, sub); + if ( alt2->predicate!=NULL ) + { + fprintf(stderr, " upon "); + s_fprT(stderr, non_covered); + } + fprintf(stderr, "\n"); + } + set_free( non_covered ); + set_free( delta ); + } + else fatal_internal("productions have no lookahead in predicate checking routine"); +} + +void +#ifdef __STDC__ +HandleAmbiguity( Junction *block, Junction *alt1, Junction *alt2, int jtype ) +#else +HandleAmbiguity( block, alt1, alt2, jtype ) +Junction *block; +Junction *alt1; +Junction *alt2; +int jtype; +#endif +{ + unsigned **ftbl; + set *fset, b; + int i, numAmbig, n, n2; + Tree *ambig=NULL, *t, *u; + char *sub = ""; + require(block!=NULL, "NULL block"); + require(block->ntype==nJunction, "invalid block"); + + /* These sets are used to constrain LL_k set, but are made CLL_k long anyway */ + fset = (set *) calloc(CLL_k+1, sizeof(set)); + require(fset!=NULL, "cannot allocate fset"); + ftbl = (unsigned **) calloc(CLL_k+1, sizeof(unsigned *)); + require(ftbl!=NULL, "cannot allocate ftbl"); + /* create constraint table and count number of possible ambiguities (use<=LL_k) */ + for (n=1,i=1; i<=CLL_k; i++) + { + b = set_and(alt1->fset[i], alt2->fset[i]); + n *= set_deg(b); + fset[i] = set_dup(b); + ftbl[i] = set_pdq(b); + set_free(b); + } + + switch ( jtype ) + { + case aSubBlk: sub = "of (..) "; break; + case aOptBlk: sub = "of {..} "; break; + case aLoopBegin: sub = "of (..)* "; break; + case aLoopBlk: sub = "of (..)* "; break; + case aPlusBlk: sub = "of (..)+ "; break; + case RuleBlk: sub = "of the rule itself "; break; + default : sub = ""; break; + } + + /* If the block is marked as a compressed lookahead only block, then + * simply return; ambiguity warning is given only at warning level 2. + */ + if ( block->approx>0 ) + { + if ( ParseWithPredicates ) + { + alt1->predicate = find_predicates((Node *)alt1->p1); + alt2->predicate = find_predicates((Node *)alt2->p1); + if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) + { + verify_context(alt1->predicate); + verify_context(alt2->predicate); + } + + if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1 ) + ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); + } + + if ( WarningLevel>1 ) + { + fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); + if ( jtype == aLoopBegin || jtype == aPlusBlk ) + fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); + else + fprintf(stderr, " warning(approx): alts %d and %d %sambiguous upon", + alt1->altnum, alt2->altnum, sub); + dumpAmbigMsg(fset, stderr, 0); + } + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); + for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); + free((char *)ftbl); + return; + } + + /* if all sets have degree 1 for k=1 permutation; + * don't bother doing full LL(k) analysis. + * (This "if" block handles the LL(1) case) + */ + n2 = 0; + for (i=1; ifset[i])+set_deg(alt2->fset[i]); + if ( n2==2*(LL_k-1) ) + { +/* TJP: added to fix the case where LL(1) and syntactic predicates didn't + * work. It now recognizes syntactic predicates, but does not like combo: + * LL(1)/syn/sem predicates. (10/24/93) + */ + if ( first_item_is_guess_block((Junction *)alt1->p1)!=NULL ) + { + if ( WarningLevel==1 ) + { + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); + for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); + free((char *)ftbl); + return; + } + + fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); + if ( jtype == aLoopBegin || jtype == aPlusBlk ) + fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); + else + fprintf(stderr, " warning: alts %d and %d %sambiguous upon", + alt1->altnum, alt2->altnum, sub); + dumpAmbigMsg(fset, stderr, 0); + } + + ambig = NULL; + if ( LL_k>1 ) ambig = make_tree_from_sets(alt1->fset, alt2->fset); + if ( ParseWithPredicates ) + { + alt1->predicate = find_predicates((Node *)alt1->p1); + alt2->predicate = find_predicates((Node *)alt2->p1); + if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) + { + verify_context(alt1->predicate); + verify_context(alt2->predicate); + } + if (HoistPredicateContext&&(alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1) + ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); + if ( WarningLevel == 1 && + (alt1->predicate!=NULL||alt2->predicate!=NULL)) + { + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); + for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); + free((char *)ftbl); + Tfree(ambig); + return; + } + } +/* end TJP (10/24/93) */ + + fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); + if ( jtype == aLoopBegin || jtype == aPlusBlk ) + fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); + else + fprintf(stderr, " warning: alts %d and %d %sambiguous upon", + alt1->altnum, alt2->altnum, sub); + if ( elevel == 3 && LL_k>1 ) + { + preorder(ambig); + fprintf(stderr, "\n"); + Tfree(ambig); + return; + } + Tfree(ambig); + dumpAmbigMsg(fset, stderr, 0); + + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); + for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); + free((char *)ftbl); + return; + } + + /* in case tree construction runs out of memory, set info to make good err msg */ + CurAmbigAlt1 = alt1->altnum; + CurAmbigAlt2 = alt2->altnum; + CurAmbigbtype = sub; + CurAmbigfile = alt1->file; + CurAmbigline = alt1->line; + + /* Don't do full LL(n) analysis if (...)? block because the block, + by definition, defies LL(n) analysis. + If guess (...)? block and ambiguous then don't remove anything from + 2nd alt to resolve ambig. + Want to predict with LL sup 1 ( n ) decision not LL(n) if guess block + since it is much cheaper than LL(n). LL sup 1 ( n ) "covers" the LL(n) + lookahead information. + + Note: LL(n) context cannot be computed for semantic predicates when + followed by (..)?. + + If (..)? then we scream "AAAHHHH! No LL(n) analysis will help" + + Is 'ambig' always defined if we enter this if? I hope so + because the 'ensure...()' func references it. TJP Nov 1993. + */ + if ( first_item_is_guess_block((Junction *)alt1->p1)!=NULL ) + { + if ( ParseWithPredicates ) + { + alt1->predicate = find_predicates((Node *)alt1->p1); + alt2->predicate = find_predicates((Node *)alt2->p1); + if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) + { + verify_context(alt1->predicate); + verify_context(alt2->predicate); + } + if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1 ) + ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); + if ( WarningLevel==1 && + (alt1->predicate!=NULL||alt2->predicate!=NULL)) + { + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); + for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); + free((char *)ftbl); + return; + } + } + + if ( WarningLevel>1 ) + { + fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); + if ( jtype == aLoopBegin || jtype == aPlusBlk ) + fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); + else + fprintf(stderr, " warning: alts %d and %d %sambiguous upon", + alt1->altnum, alt2->altnum, sub); + dumpAmbigMsg(fset, stderr, 0); + } + + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); + for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); + free((char *)ftbl); + return; + } + + /* Not resolved with (..)? block. Do full LL(n) analysis */ + + /* ambig is the set of k-tuples truly in common between alt 1 and alt 2 */ + ambig = VerifyAmbig(alt1, alt2, ftbl, fset, &t, &u, &numAmbig); + for (i=1; i<=CLL_k; i++) free( (char *)ftbl[i] ); + free((char *)ftbl); + + /* are all things in intersection really ambigs? */ + if ( numAmbig < n ) + { + Tree *v; + + /* remove ambig permutation from 2nd alternative to resolve ambig; + * We want to compute the set of artificial tuples, arising from + * LL sup 1 (n) compression, that collide with real tuples from the + * 2nd alternative. This is the set of "special case" tuples that + * the LL sup 1 (n) decision template maps incorrectly. + */ + if ( ambig!=NULL ) + { + for (v=ambig->down; v!=NULL; v=v->right) + { + u = trm_perm(u, v); + } +/* fprintf(stderr, "after rm alt2:"); preorder(u); fprintf(stderr, "\n");*/ + } + Tfree( t ); + alt1->ftree = tappend(alt1->ftree, u); + alt1->ftree = tleft_factor(alt1->ftree); + } + + if ( ambig==NULL ) + { + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); + return; + } + + ambig = tleft_factor(ambig); + +/* TJP: + * At this point, we surely have an LL(k) ambiguity. Check for predicates + */ + if ( ParseWithPredicates ) + { + alt1->predicate = find_predicates((Node *)alt1->p1); + alt2->predicate = find_predicates((Node *)alt2->p1); + if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) ) + { + verify_context(alt1->predicate); + verify_context(alt2->predicate); + } + if ( HoistPredicateContext && (alt1->predicate!=NULL||alt2->predicate!=NULL) && WarningLevel>1 ) + ensure_predicates_cover_ambiguous_lookahead_sequences(alt1, alt2, sub, ambig); + if ( WarningLevel==1 && + (alt1->predicate!=NULL||alt2->predicate!=NULL)) + { + /* We found at least one pred for at least one of the alts; + * If warnings are low, just return. + */ + Tfree(ambig); + return; + } + /* else we're gonna give a warning */ + } +/* end TJP addition */ + + fprintf(stderr, ErrHdr, FileStr[alt1->file], alt1->line); + if ( jtype == aLoopBegin || jtype == aPlusBlk ) + fprintf(stderr, " warning: optional/exit path and alt(s) %sambiguous upon", sub); + else + fprintf(stderr, " warning: alts %d and %d %sambiguous upon", + alt1->altnum, alt2->altnum, sub); + if ( elevel == 3 ) + { + preorder(ambig->down); + fprintf(stderr, "\n"); + Tfree(ambig); + return; + } + Tfree(ambig); + dumpAmbigMsg(fset, stderr, 0); + for (i=1; i<=CLL_k; i++) set_free( fset[i] ); + free((char *)fset); +} + +/* Don't analyze alpha block of (alpha)?beta; if (alpha)? then analyze + * Return the 1st node of the beta block if present else return j. + */ +Junction * +#ifdef __STDC__ +analysis_point( Junction *j ) +#else +analysis_point( j ) +Junction *j; +#endif +{ + Junction *gblock; + + if ( j->ntype!=nJunction ) return j; + gblock = first_item_is_guess_block((Junction *)j); + + if ( gblock!=NULL ) + { + Junction *past = gblock->end; + Junction *p; + require(past!=NULL, "analysis_point: no end block on (...)? block"); + + for (p=(Junction *)past->p1; p!=NULL; ) + { + if ( p->ntype==nAction ) + { + p=(Junction *)((ActionNode *)p)->next; + continue; + } + if ( p->ntype!=nJunction ) + { + return (Junction *)past->p1; + } + if ( p->jtype==EndBlk || p->jtype==EndRule ) + { + return j; + } + p=(Junction *)p->p1; + } + } + return j; +} + +set +#ifdef __STDC__ +First( Junction *j, int k, int jtype, int *max_k ) +#else +First( j, k, jtype, max_k ) +Junction *j; +int k; +int jtype; +int *max_k; +#endif +{ + Junction *alt1, *alt2; + set a, rk, fCurBlk; + int savek; + int p1, p2; + require(j->ntype==nJunction, "First: non junction passed"); + + /* C o m p u t e F I R S T s e t w i t h k l o o k a h e a d */ + fCurBlk = rk = empty; + for (alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2) + { + Junction *p = analysis_point((Junction *)alt1->p1); + REACH(p, k, &rk, alt1->fset[k]); + require(set_nil(rk), "rk != nil"); + set_free(rk); + set_orin(&fCurBlk, alt1->fset[k]); + } + + /* D e t e c t A m b i g u i t i e s */ + *max_k = 1; + for (p1=1,alt1=j; alt1!=NULL; alt1 = (Junction *)alt1->p2, p1++) + { + for (p2=1,alt2=(Junction *)alt1->p2; alt2!=NULL; alt2 = (Junction *)alt2->p2, p2++) + { + savek = k; + a = set_and(alt1->fset[k], alt2->fset[k]); + while ( !set_nil(a) ) + { + /* if we have hit the max k requested, just give warning */ + if ( j->approx==k ) { + } + + if ( k==CLL_k ) + { +#ifdef NOT_USED + int save_LL_k = LL_k; + int save_CLL_k = CLL_k; + /* Get new LL_k from interactive feature if enabled */ + if ( AImode ) + AmbiguityDialog(j, jtype, alt1, alt2, &CLL_k, &LL_k); +#endif + *max_k = CLL_k; + HandleAmbiguity(j, alt1, alt2, jtype); + break; + } + else + { + Junction *p = analysis_point((Junction *)alt1->p1); + Junction *q = analysis_point((Junction *)alt2->p1); + k++; /* attempt ambig alts again with more lookahead */ + REACH(p, k, &rk, alt1->fset[k]); + require(set_nil(rk), "rk != nil"); + REACH(q, k, &rk, alt2->fset[k]); + require(set_nil(rk), "rk != nil"); + set_free(a); + a = set_and(alt1->fset[k], alt2->fset[k]); + if ( k > *max_k ) *max_k = k; + } + } + set_free(a); + k = savek; + } + } + + return fCurBlk; +}