]> pd.if.org Git - pccts/blobdiff - antlr/fset.c
auto commit for import
[pccts] / antlr / fset.c
diff --git a/antlr/fset.c b/antlr/fset.c
new file mode 100755 (executable)
index 0000000..71f85ca
--- /dev/null
@@ -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 <stdio.h>
+#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 : <<PRED1>>? (A B|A C)
+ *       | b
+ *    ;
+ *     b : <<PRED2>>? 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<LL_k, then must be ambig upon >=1 permutation;
+        * don't bother doing full LL(k) analysis.
+        * (This "if" block handles the LL(1) case)
+        */
+       n2 = 0;
+       for (i=1; i<LL_k; i++) n2 += set_deg(alt1->fset[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;
+}