Logo Search packages:      
Sourcecode: pccts version File versions  Download package

fset2.c

/*
 * fset2.c
 *
 * Compute FIRST sets for full LL(k)
 *
 * SOFTWARE RIGHTS
 *
 * We reserve no LEGAL rights to the Purdue Compiler Construction Tool
 * Set (PCCTS) -- PCCTS is in the public domain.  An individual or
 * company may do whatever they wish with source code distributed with
 * PCCTS or the code generated by PCCTS, including the incorporation of
 * PCCTS, or its output, into commerical software.
 *
 * We encourage users to develop software with PCCTS.  However, we do ask
 * that credit is given to us for developing PCCTS.  By "credit",
 * we mean that if you incorporate our source code into one of your
 * programs (commercial product, research project, or otherwise) that you
 * acknowledge this fact somewhere in the documentation, research report,
 * etc...  If you like PCCTS and have developed a nice tool with the
 * output, please mention that you developed it using PCCTS.  In
 * addition, we ask that this header remain intact in our source code.
 * As long as these guidelines are kept, we expect to continue enhancing
 * this system and expect to make other tools available as they are
 * completed.
 *
 * ANTLR 1.33
 * Terence Parr
 * Parr Research Corporation
 * with Purdue University and AHPCRC, University of Minnesota
 * 1989-2001
 */

#include <stdio.h>
#include "pcctscfg.h"
#include <stdlib.h>

#ifdef PCCTS_USE_STDARG
#include <stdarg.h>
#else
#include <varargs.h>
#endif

#include "set.h"
#include "syn.h"
#include "hash.h"
#include "generic.h"
#include "dlgdef.h"

/* ick! globals.  Used by permute() to track which elements of a set have been used */

static int *findex;
set *fset;              /* MR11 make global */
static unsigned **ftbl;
static set *constrain; /* pts into fset. constrains tToken() to 'constrain' */
int ConstrainSearch;
int maxk;               /* set to initial k upon tree construction request */
                        /* MR11 make global */
static Tree *FreeList = NULL;

#ifdef __USE_PROTOS
static int tmember_of_context(Tree *, Predicate *);
#else
static int tmember_of_context();
#endif

#if TREE_DEBUG
set     set_of_tnodes_in_use;
int     stop_on_tnode_seq_number=(-1);     /* (-1) to disable */
#endif

/* Do root
 * Then each sibling
 */

void
#ifdef __USE_PROTOS
preorder( Tree *tree )
#else
preorder( tree )
Tree *tree;
#endif
{
      if ( tree == NULL ) return;
      if ( tree->down != NULL ) fprintf(stderr, " (");
      if ( tree->token == ALT ) fprintf(stderr, " ALT");
      else fprintf(stderr, " %s", TerminalString(tree->token));
      if ( tree->token==EpToken ) fprintf(stderr, "(%d)", tree->v.rk);
      preorder(tree->down);
      if ( tree->down != NULL ) fprintf(stderr, " )");
      preorder(tree->right);
}

#ifdef __USE_PROTOS
int MR_tree_matches_constraints(int k,set * constrain,Tree *t)
#else
int MR_tree_matches_constraints(k,constrain,t)
  int       k;
  set *     constrain;
  Tree *    t;
#endif
{
  int       i;
  Tree      *u;

  if (k == 0) return 1;

  /* for testing guard predicates: if the guard tree is shorter
     than the constraint then it is a match.  The reason is that
     a guard of (A B) should be equivalent to a guard of (A B . . .)
     where "." matches every token.  Thus a match which runs out
     of tree before constraint is a match.
  */

  if (t == NULL) return 1;
  require (set_deg(constrain[0]) == 1,
            "MR_tree_matches_constraints: set_deg != 1");
  i=set_int(constrain[0]);
  if (t->token != i) return 0;
  if (k-1 == 0) return 1;
  for (u=t->down; u != NULL; u=u->right) {
    if (MR_tree_matches_constraints(k-1,&constrain[1],u)) {
       return 1;
    };
  };
  return 0;
}

/* check the depth of each primary sibling to see that it is exactly
 * k deep. e.g.;
 *
 *    ALT
 *   |
 *   A ------- B
 *   |         |
 *   C -- D    E
 *
 * Remove all branches <= k deep.
 *
 * Added by TJP 9-23-92 to make the LL(k) constraint mechanism to work.
 */

static int pruneCount=0;
static int prunePeak=200;

Tree *
#ifdef __USE_PROTOS
prune( Tree *t, int k )
#else
prune( t, k )
Tree *t;
int k;
#endif
{
    pruneCount++;
    if (pruneCount > prunePeak+100) {
      prunePeak=pruneCount;
#if 0
***   fprintf(stderr,"pruneCount=%d\n",pruneCount);
/***  preorder(t);   ***/
***   fprintf(stderr,"\n",pruneCount);
#endif
    };
    if ( t == NULL ) {
        pruneCount--;
        return NULL;
    };
    if ( t->token == ALT ) fatal_internal("prune: ALT node in FIRST tree");
    if ( t->right!=NULL ) t->right = prune(t->right, k);
    if ( k>1 )
      {
            if ( t->down!=NULL ) t->down = prune(t->down, k-1);
            if ( t->down == NULL )
            {
                  Tree *r = t->right;
                  t->right = NULL;
                  Tfree(t);
            pruneCount--;
                  return r;
            }
      }
    pruneCount--;
    return t;
}

/* build a tree (root child1 child2 ... NULL) */
#ifdef PCCTS_USE_STDARG
Tree *tmake(Tree *root, ...)
#else
Tree *tmake(va_alist)
va_dcl
#endif
{
      Tree *w;
      va_list ap;
      Tree *child, *sibling=NULL, *tail=NULL;
#ifndef PCCTS_USE_STDARG
      Tree *root;
#endif

#ifdef PCCTS_USE_STDARG
      va_start(ap, root);
#else
      va_start(ap);
      root = va_arg(ap, Tree *);
#endif
      child = va_arg(ap, Tree *);
      while ( child != NULL )
      {
#ifdef DUM
            /* added "find end of child" thing TJP March 1994 */
            for (w=child; w->right!=NULL; w=w->right) {;} /* find end of child */
#else
            w = child;
#endif

            if ( sibling == NULL ) {sibling = child; tail = w;}
            else {tail->right = child; tail = w;}
            child = va_arg(ap, Tree *);
      }

      /* was "root->down = sibling;" */
      if ( root==NULL ) root = sibling;
      else root->down = sibling;

      va_end(ap);
      return root;
}

Tree *
#ifdef __USE_PROTOS
tnode( int tok )
#else
tnode( tok )
int tok;
#endif
{
      Tree *p, *newblk;
      static int n=0;
      
      if ( FreeList == NULL )
      {
            /*fprintf(stderr, "tnode: %d more nodes\n", TreeBlockAllocSize);*/
            if ( TreeResourceLimit > 0 )
            {
                  if ( (n+TreeBlockAllocSize) >= TreeResourceLimit )
                  {
                        fprintf(stderr, ErrHdr, FileStr[CurAmbigfile], CurAmbigline);
                        fprintf(stderr, " hit analysis resource limit while analyzing alts %d and %d %s\n",
                                                CurAmbigAlt1,
                                                CurAmbigAlt2,
                                                CurAmbigbtype);
                        exit(PCCTS_EXIT_FAILURE);
                  }
            }
            newblk = (Tree *)calloc(TreeBlockAllocSize, sizeof(Tree));
            if ( newblk == NULL )
            {
                  fprintf(stderr, ErrHdr, FileStr[CurAmbigfile], CurAmbigline);
                  fprintf(stderr, " out of memory while analyzing alts %d and %d %s\n",
                                          CurAmbigAlt1,
                                          CurAmbigAlt2,
                                          CurAmbigbtype);
                  exit(PCCTS_EXIT_FAILURE);
            }
            n += TreeBlockAllocSize;
            for (p=newblk; p<&(newblk[TreeBlockAllocSize]); p++)
            {
                  p->right = FreeList;    /* add all new Tree nodes to Free List */
                  FreeList = p;
            }
      }
      p = FreeList;
      FreeList = FreeList->right;         /* remove a tree node */
      p->right = NULL;                    /* zero out ptrs */
      p->down = NULL;
      p->token = tok;

    TnodesAllocated++;                                      /* MR10 */
    TnodesInUse++;                                          /* MR10 */
    if (TnodesInUse > TnodesPeak) TnodesPeak=TnodesInUse;   /* MR10 */

#ifdef TREE_DEBUG
      require(!p->in_use, "tnode: node in use!");
      p->in_use = 1;
    p->seq=TnodesAllocated;
    set_orel( (unsigned) TnodesAllocated,&set_of_tnodes_in_use);
    if (stop_on_tnode_seq_number == p->seq) {
      fprintf(stderr,"\n*** just allocated tnode #%d ***\n",
            stop_on_tnode_seq_number);
    };
#endif
      return p;
}

static Tree *
#ifdef __USE_PROTOS
eofnode( int k )
#else
eofnode( k )
int k;
#endif
{
      Tree *t=NULL;
      int i;

      for (i=1; i<=k; i++)
      {
            t = tmake(tnode((TokenInd!=NULL?TokenInd[EofToken]:EofToken)), t, NULL);
      }
      return t;
}



void
#ifdef __USE_PROTOS
_Tfree( Tree *t )
#else
_Tfree( t )
Tree *t;
#endif
{
      if ( t!=NULL )
      {
#ifdef TREE_DEBUG
        if (t->seq == stop_on_tnode_seq_number) {
           fprintf(stderr,"\n*** just freed tnode #%d ***\n",t->seq);
        };
            require(t->in_use, "_Tfree: node not in use!");
            t->in_use = 0;
        set_rm( (unsigned) t->seq,set_of_tnodes_in_use);
#endif
            t->right = FreeList;
            FreeList = t;
        TnodesInUse--;                   /* MR10 */
      }
}

/* tree duplicate */
Tree *
#ifdef __USE_PROTOS
tdup( Tree *t )
#else
tdup( t )
Tree *t;
#endif
{
      Tree *u;
      
      if ( t == NULL ) return NULL;
      u = tnode(t->token);
      u->v.rk = t->v.rk;
      u->right = tdup(t->right);
      u->down = tdup(t->down);
      return u;
}

/* tree duplicate (assume tree is a chain downwards) */
Tree *
#ifdef __USE_PROTOS
tdup_chain( Tree *t )
#else
tdup_chain( t )
Tree *t;
#endif
{
      Tree *u;
      
      if ( t == NULL ) return NULL;
      u = tnode(t->token);
      u->v.rk = t->v.rk;
      u->down = tdup(t->down);
      return u;
}

Tree *
#ifdef __USE_PROTOS
tappend( Tree *t, Tree *u )
#else
tappend( t, u )
Tree *t;
Tree *u;
#endif
{
      Tree *w;

/*** fprintf(stderr, "tappend(");
 *** preorder(t); fprintf(stderr, ",");
 *** preorder(u); fprintf(stderr, " )\n");
*/
      if ( t == NULL ) return u;
      if ( t->token == ALT && t->right == NULL ) return tappend(t->down, u);
      for (w=t; w->right!=NULL; w=w->right) {;}
      w->right = u;
      return t;
}

/* dealloc all nodes in a tree */
void
#ifdef __USE_PROTOS
Tfree( Tree *t )
#else
Tfree( t )
Tree *t;
#endif
{
      if ( t == NULL ) return;
      Tfree( t->down );
      Tfree( t->right );
      _Tfree( t );
}

/* find all children (alts) of t that require remaining_k nodes to be LL_k
 * tokens long.
 *
 * t-->o
 *     |
 *     a1--a2--...--an        <-- LL(1) tokens
 *     |   |        |
 *     b1  b2  ...  bn        <-- LL(2) tokens
 *     |   |        |
 *     .   .        .
 *     .   .        .
 *     z1  z2  ...  zn        <-- LL(LL_k) tokens
 *
 * We look for all [Ep] needing remaining_k nodes and replace with u.
 * u is not destroyed or actually used by the tree (a copy is made).
 */
Tree *
#ifdef __USE_PROTOS
tlink( Tree *t, Tree *u, int remaining_k )
#else
tlink( t, u, remaining_k )
Tree *t;
Tree *u;
int remaining_k;
#endif
{
      Tree *p;
      require(remaining_k!=0, "tlink: bad tree");

      if ( t==NULL ) return NULL;
      /*fprintf(stderr, "tlink: u is:"); preorder(u); fprintf(stderr, "\n");*/
      if ( t->token == EpToken && t->v.rk == remaining_k )
      {
            require(t->down==NULL, "tlink: invalid tree");
            if ( u == NULL ) {
/* MR10 */  Tree  *tt=t->right;
/* MR10 */  _Tfree(t);
/* MR10 */  return tt;
        };
            p = tdup( u );
            p->right = t->right;
            _Tfree( t );
            return p;
      }
      t->down = tlink(t->down, u, remaining_k);
      t->right = tlink(t->right, u, remaining_k);
      return t;
}

/* remove as many ALT nodes as possible while still maintaining semantics */
Tree *
#ifdef __USE_PROTOS
tshrink( Tree *t )
#else
tshrink( t )
Tree *t;
#endif
{
      if ( t == NULL ) return NULL;
      t->down = tshrink( t->down );
      t->right = tshrink( t->right );
      if ( t->down == NULL )
      {
            if ( t->token == ALT )
            {
                  Tree *u = t->right;
                  _Tfree(t);
                  return u;               /* remove useless alts */
            }
            return t;
      }

      /* (? (ALT (? ...)) s) ==> (? (? ...) s) where s = sibling, ? = match any */
      if ( t->token == ALT && t->down->right == NULL)
      {
            Tree *u = t->down;
            u->right = t->right;
            _Tfree( t );
            return u;
      }
      /* (? (A (ALT t)) s) ==> (? (A t) s) where A is a token; s,t siblings */
      if ( t->token != ALT && t->down->token == ALT && t->down->right == NULL )
      {
            Tree *u = t->down->down;
            _Tfree( t->down );
            t->down = u;
            return t;
      }
      return t;
}

Tree *
#ifdef __USE_PROTOS
tflatten( Tree *t )
#else
tflatten( t )
Tree *t;
#endif
{
      if ( t == NULL ) return NULL;
      t->down = tflatten( t->down );
      t->right = tflatten( t->right );
      if ( t->down == NULL ) return t;
      
      if ( t->token == ALT )
      {
            Tree *u;
            /* find tail of children */
            for (u=t->down; u->right!=NULL; u=u->right) {;}
            u->right = t->right;
            u = t->down;
            _Tfree( t );
            return u;
      }
      return t;
}

Tree *
#ifdef __USE_PROTOS
tJunc( Junction *p, int k, set *rk )
#else
tJunc( p, k, rk )
Junction *p;
int k;
set *rk;
#endif
{
      Tree *t=NULL, *u=NULL;
      Junction *alt;
      Tree *tail=NULL, *r;

#ifdef DBG_TRAV
      fprintf(stderr, "tJunc(%d): %s in rule %s\n", k,
                  decodeJType[p->jtype], ((Junction *)p)->rname);
#endif

/* MR14 */    if (AlphaBetaTrace && p->alpha_beta_guess_end) {
/* MR14 */         warnFL(
/* MR14 */           "not possible to compute follow set for alpha in an \"(alpha)? beta\" block.  ",
/* MR14 */                 FileStr[p->file],p->line);
/* MR14 */         MR_alphaBetaTraceReport();
/* MR14 */    };

/* MR14 */    if (p->alpha_beta_guess_end) {
/* MR14 */      return NULL;
/* MR14 */    }

      if ( p->jtype==aLoopBlk || p->jtype==RuleBlk ||
             p->jtype==aPlusBlk || p->jtype==aSubBlk || p->jtype==aOptBlk )
      {
            if ( p->jtype!=aSubBlk && p->jtype!=aOptBlk ) {
                  require(p->lock!=NULL, "rJunc: lock array is NULL");
                  if ( p->lock[k] ) return NULL;
                  p->lock[k] = TRUE;
            }

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p);
/* MR10 */    };

            TRAV(p->p1, k, rk, tail);

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack);
/* MR10 */    };

            if ( p->jtype==RuleBlk ) {p->lock[k] = FALSE; return tail;}
            r = tmake(tnode(ALT), tail, NULL);
            for (alt=(Junction *)p->p2; alt!=NULL; alt = (Junction *)alt->p2)
            {
                  /* if this is one of the added optional alts for (...)+ then break */
                  if ( alt->ignore ) break;

                  if ( tail==NULL ) {TRAV(alt->p1, k, rk, tail); r->down = tail;}
                  else
                  {
/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p);
/* MR10 */    };

                        TRAV(alt->p1, k, rk, tail->right);

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack);
/* MR10 */    };
                        if ( tail->right != NULL ) tail = tail->right;
                  }
            }
            if ( p->jtype!=aSubBlk && p->jtype!=aOptBlk ) p->lock[k] = FALSE;
#ifdef DBG_TREES
            fprintf(stderr, "blk(%s) returns:",((Junction *)p)->rname); preorder(r); fprintf(stderr, "\n");
#endif
            if ( r->down == NULL ) {_Tfree(r); return NULL;}
            return r;
      }

      if ( p->jtype==EndRule )
      {
            if ( p->halt )                                  /* don't want FOLLOW here? */
            {
/****       if ( ContextGuardTRAV ) return NULL; ****/
                  set_orel( (unsigned) k, rk);  /* indicate this k value needed */ /* MR10 cast */
                  t = tnode(EpToken);
                  t->v.rk = k;
                  return t;
            }
            require(p->lock!=NULL, "rJunc: lock array is NULL");
            if ( p->lock[k] ) return NULL;
            /* if no FOLLOW assume k EOF's */
            if ( p->p1 == NULL ) return eofnode(k);
            p->lock[k] = TRUE;
      }

/* MR14 */  if (p->p1 != NULL && p->guess &&  p->guess_analysis_point == NULL) {
/* MR14 */    Node * guess_point;
/* MR14 */    guess_point=(Node *)analysis_point(p);
/* MR14 */    if (guess_point == (Node *)p) {
/* MR14 */      guess_point=p->p1;
/* MR14 */    }
/* MR14 */    p->guess_analysis_point=guess_point;
/* MR14 */  }     

      if ( p->p2 == NULL )
      {

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p);
/* MR10 */    };

/* M14 */        if (p->guess_analysis_point != NULL) {
/* M14 */            TRAV(p->guess_analysis_point, k, rk,t);
/* M14 */        } else {
                     TRAV(p->p1, k, rk,t);
/* M14 */        }

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack);
/* MR10 */    };

            if ( p->jtype==EndRule ) p->lock[k]=FALSE;
            return t;
      }

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPush(&MR_BackTraceStack,p);
/* MR10 */    };

/* M14 */        if (p->guess_analysis_point != NULL) {
/* M14 */            TRAV(p->guess_analysis_point, k, rk,t);
/* M14 */        } else {
                     TRAV(p->p1, k, rk,t);
/* M14 */        }

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (p->jtype != Generic) MR_pointerStackPop(&MR_BackTraceStack);
/* MR10 */    };

      if ( p->jtype!=RuleBlk && /* MR14 */ !p->guess) TRAV(p->p2, k, rk, u);

      if ( p->jtype==EndRule ) p->lock[k] = FALSE;/* unlock node */

      if ( t==NULL ) return tmake(tnode(ALT), u, NULL);
      return tmake(tnode(ALT), t, u, NULL);
}

Tree *
#ifdef __USE_PROTOS
tRuleRef( RuleRefNode *p, int k, set *rk_out )
#else
tRuleRef( p, k, rk_out )
RuleRefNode *p;
int k;
set *rk_out;
#endif
{
      int k2;
      Tree *t=NULL, *u=NULL;
      Junction *r;
      set rk, rk2;
      int save_halt;
      RuleEntry *q = (RuleEntry *) hash_get(Rname, p->text);
      
#ifdef DBG_TRAV
      fprintf(stderr, "tRuleRef: %s\n", p->text);
#endif
      if ( q == NULL )
      {
            TRAV(p->next, k, rk_out, t);/* ignore undefined rules */
            return t;
      }
      rk = rk2 = empty;
    if (RulePtr == NULL) fatal("RulePtr==NULL");
      r = RulePtr[q->rulenum];
      if ( r->lock[k] ) return NULL;
      save_halt = r->end->halt;
      r->end->halt = TRUE;          /* don't let reach fall off end of rule here */

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      MR_pointerStackPush(&MR_BackTraceStack,p);
/* MR10 */    };

      TRAV(r, k, &rk, t);

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      MR_pointerStackPop(&MR_BackTraceStack);
/* MR10 */    };

      r->end->halt = save_halt;
#ifdef DBG_TREES
      fprintf(stderr, "after ruleref, t is:"); preorder(t); fprintf(stderr, "\n");
#endif
      t = tshrink( t );
      while ( !set_nil(rk) ) {      /* any k left to do? if so, link onto tree */
            k2 = set_int(rk);
            set_rm(k2, rk);

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      MR_pointerStackPush(&MR_BackTraceStack,p);
/* MR10 */    };

            TRAV(p->next, k2, &rk2, u);

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      MR_pointerStackPop(&MR_BackTraceStack);
/* MR10 */    };

            t = tlink(t, u, k2);    /* any alts missing k2 toks, add u onto end */
        Tfree(u);               /* MR10 */
      }
      set_free(rk);                       /* rk is empty, but free it's memory */
      set_orin(rk_out, rk2);        /* remember what we couldn't do */
      set_free(rk2);
      return t;
}

Tree *
#ifdef __USE_PROTOS
tToken( TokNode *p, int k, set *rk )
#else
tToken( p, k, rk )
TokNode *p;
int k;
set *rk;
#endif
{
      Tree *t=NULL, *tset=NULL, *u;

      if (ConstrainSearch) {
      if (MR_AmbSourceSearch) {
            require(constrain>=fset&&constrain<=&(fset[CLL_k]),"tToken: constrain is not a valid set");
      } else {
            require(constrain>=fset&&constrain<=&(fset[LL_k]),"tToken: constrain is not a valid set");
      };
      constrain = &fset[maxk-k+1];
      }

#ifdef DBG_TRAV
            fprintf(stderr, "tToken(%d): %s\n", k, TerminalString(p->token));
            if ( ConstrainSearch ) {
                  fprintf(stderr, "constrain is:"); s_fprT(stderr, *constrain); fprintf(stderr, "\n");
            }
#endif

      /* is it a meta token (set of tokens)? */

      if ( !set_nil(p->tset) )
      {
            unsigned e=0;
            set a;
            Tree *n, *tail = NULL;

            if ( ConstrainSearch ) {
          a = set_and(p->tset, *constrain);
          if (set_nil(a)) {         /* MR10 */
            set_free(a);            /* MR11 */
            return NULL;            /* MR10 */
          };                        /* MR10 */
            } else {
          a = set_dup(p->tset);
        };

            for (; !set_nil(a); set_rm(e, a))
            {
                  e = set_int(a);
                  n = tnode(e);
                  if ( tset==NULL ) { tset = n; tail = n; }
                  else { tail->right = n; tail = n; }
            }
            set_free( a );
      }
      else if ( ConstrainSearch && !set_el(p->token, *constrain) )
    {
/*      fprintf(stderr, "ignoring token %s(%d)\n", TerminalString(p->token),
                k);*/
        return NULL;
    }
      else {
        tset = tnode( p->token );
    };

/* MR10 */    if (MR_MaintainBackTrace) {
/* MR10 */      if (k == 1) {
/* MR10 */        MR_pointerStackPush(&MR_BackTraceStack,p);
/* MR13 */        if (MR_SuppressSearch) {
/* MR13 */          MR_suppressSearchReport();
/* MR13 */        } else {
/* MR10 */          MR_backTraceReport();
/* MR13 */        };
/* MR10 */        MR_pointerStackPop(&MR_BackTraceStack);
/* MR11 */        Tfree(tset);
/* MR11 */        return NULL;
/* MR10 */      };
/* MR10 */    };

      if ( k == 1 ) return tset;

    if (MR_MaintainBackTrace) {
      MR_pointerStackPush(&MR_BackTraceStack,p);
    };

      TRAV(p->next, k-1, rk, t);

    if (MR_MaintainBackTrace) {
      Tfree(t);
      Tfree(tset);
      MR_pointerStackPop(&MR_BackTraceStack);
      return NULL;
    };

      /* here, we are positive that, at least, this tree will not contribute
       * to the LL(2) tree since it will be too shallow, IF t==NULL.
       * If doing a context guard walk, then don't prune.
       */
      if ( t == NULL && !ContextGuardTRAV )     /* tree will be too shallow */
      {
            if ( tset!=NULL ) Tfree( tset );
            return NULL;
      }
#ifdef DBG_TREES
      fprintf(stderr, "tToken(%d)->next:",k); preorder(t); fprintf(stderr, "\n");
#endif

      /* if single token root, then just make new tree and return */
    /* MR10 - set_nil(p->tset) isn't a good test because of ConstraintSearch */

      if (tset->right == NULL) return tmake(tset, t, NULL);    /* MR10 */

      /* here we must make a copy of t as a child of each element of the tset;
       * e.g., "T1..T3 A" would yield ( nil ( T1 A ) ( T2 A ) ( T3 A ) )
       */
      for (u=tset; u!=NULL; u=u->right)
      {
            /* make a copy of t and hook it onto bottom of u */
            u->down = tdup(t);
      }
      Tfree( t );
#ifdef DBG_TREES
      fprintf(stderr, "range is:"); preorder(tset); fprintf(stderr, "\n");
#endif
      return tset;
}

Tree *
#ifdef __USE_PROTOS
tAction( ActionNode *p, int k, set *rk )
#else
tAction( p, k, rk )
ActionNode *p;
int k;
set *rk;
#endif
{
      Tree        *t=NULL;
    set         *save_fset=NULL;
    int         i;

      /* fprintf(stderr, "tAction\n"); */

/*  An MR_SuppressSearch is looking for things that can be
      reached even when the predicate is false.

    There are three kinds of predicates:
        plain:              r1: <<p>>? r2
        guarded:            r1: (A)? => <<p>>? r2
        ampersand style:    r1: (A)? && <<p>>? r2

    Of the three kinds of predicates, only a guard predicate
      has things which are reachable even when the predicate
      is false.  To be reachable the constraint must *not*
      match the guard.

*/

    if (p->is_predicate && MR_SuppressSearch) {

      Predicate     *pred=p->guardpred;

      if (pred == NULL) {
        t=NULL;
        goto EXIT;
      };
      constrain = &fset[maxk-k+1];
      if (pred->k == 1) {
        set     dif;
        dif=set_dif(*constrain,pred->scontext[1]);
        if (set_nil(dif)) {
          set_free(dif);
          t=NULL;
          goto EXIT;
        };
        set_free(dif);
      } else {
        if (MR_tree_matches_constraints(k,constrain,pred->tcontext)) {
          t=NULL;
          goto EXIT;
        };
      }
    };

    /* The ampersand predicate differs from the
         other predicates because its first set
         is a subset of the first set behind the predicate

            r1: (A)? && <<p>>? r2 ;
            r2: A | B;

       In this case first[1] of r1 is A, even
         though first[1] of r2 is {A B}.
    */

    if (p->is_predicate && p->ampersandPred != NULL) {

      Predicate     *pred=p->ampersandPred;
      Tree          *tAND;
      Tree          *tset;

      if (k <= pred->k) {
        if (MR_MaintainBackTrace) MR_pointerStackPush(&MR_BackTraceStack,p);
        TRAV(p->guardNodes,k,rk,t);
        if (MR_MaintainBackTrace) MR_pointerStackPop(&MR_BackTraceStack);
        return t;
      } else {
        require (k>1,"tAction for ampersandpred: k <= 1");
        if (ConstrainSearch) {
          if (MR_AmbSourceSearch) {
            require(constrain>=fset&&constrain<=&(fset[CLL_k]),
                                "tToken: constrain is not a valid set");
          } else {
            require(constrain>=fset&&constrain<=&(fset[LL_k]),
                                "tToken: constrain is not a valid set");
          };
          save_fset=(set *) calloc (CLL_k+1,sizeof(set));
          require (save_fset != NULL,"tAction save_fset alloc");
          for (i=1; i <= CLL_k ; i++) {
            save_fset[i]=set_dup(fset[i]);
          };
          if (pred->k == 1) {
            constrain = &fset[maxk-k+1];
            set_andin(constrain,pred->scontext[1]);
            if (set_nil(*constrain)) {
              t=NULL;
              goto EXIT;
            };
          } else {
            constrain = &fset[maxk-k+1];
            if (! MR_tree_matches_constraints(pred->k,constrain,pred->tcontext)) {
               t=NULL;
               goto EXIT;
            };  /* end loop on i          */
          }; /* end loop on pred scontext/tcontext */
        }; /* end if on k > pred->k     */
      }; /* end if on constrain search  */

      TRAV(p->next,k,rk,t);

      if (t != NULL) {
        t=tshrink(t);
        t=tflatten(t);
        t=tleft_factor(t);
        if (pred->tcontext != NULL) {
          tAND=MR_computeTreeAND(t,pred->tcontext);
        } else {
          tset=MR_make_tree_from_set(pred->scontext[1]);
          tAND=MR_computeTreeAND(t,tset);
          Tfree(tset);
        };
        Tfree(t);
        t=tAND;
      };
      goto EXIT;

    }; /* end if on ampersand predicate */

    TRAV(p->next,k,rk,t);

EXIT:
    if (save_fset != NULL) {
      for (i=1 ; i <= CLL_k ; i++) {
        set_free(fset[i]);
        fset[i]=save_fset[i];
      };
      free ( (char *) save_fset);
    };
      return t;
}

/* see if e exists in s as a possible input permutation (e is always a chain) */

int
#ifdef __USE_PROTOS
tmember( Tree *e, Tree *s )
#else
tmember( e, s )
Tree *e;
Tree *s;
#endif
{
      if ( e==NULL||s==NULL ) return 0;
/** fprintf(stderr, "tmember(");
***   preorder(e); fprintf(stderr, ",");
***   preorder(s); fprintf(stderr, " )\n");
*/
      if ( s->token == ALT && s->right == NULL ) return tmember(e, s->down);
      if ( e->token!=s->token )
      {
            if ( s->right==NULL ) return 0;
            return tmember(e, s->right);
      }
      if ( e->down==NULL && s->down == NULL ) return 1;
      if ( tmember(e->down, s->down) ) return 1;
      if ( s->right==NULL ) return 0;
      return tmember(e, s->right);
}

/* see if e exists in s as a possible input permutation (e is always a chain);
 * Only check s to the depth of e.  In other words, 'e' can be a shorter
 * sequence than s.
 */
int
#ifdef __USE_PROTOS
tmember_constrained( Tree *e, Tree *s)
#else
tmember_constrained( e, s )
Tree *e;
Tree *s;
#endif
{
      if ( e==NULL||s==NULL ) return 0;
/**   fprintf(stderr, "tmember_constrained(");
***   preorder(e); fprintf(stderr, ",");
***   preorder(s); fprintf(stderr, " )\n");
**/
      if ( s->token == ALT && s->right == NULL )
            return tmember_constrained(e, s->down);
      if ( e->token!=s->token )
      {
            if ( s->right==NULL ) return 0;
            return tmember_constrained(e, s->right);
      }
      if ( e->down == NULL ) return 1; /* if s is matched to depth of e return */
      if ( tmember_constrained(e->down, s->down) ) return 1;
      if ( s->right==NULL ) return 0;
      return tmember_constrained(e, s->right);
}

/* combine (? (A t) ... (A u) ...) into (? (A t u)) */
Tree *
#ifdef __USE_PROTOS
tleft_factor( Tree *t )
#else
tleft_factor( t )
Tree *t;
#endif
{
      Tree *u, *v, *trail, *w;

      /* left-factor what is at this level */
      if ( t == NULL ) return NULL;
      for (u=t; u!=NULL; u=u->right)
      {
            trail = u;
            v=u->right;
            while ( v!=NULL )
            {
                  if ( u->token == v->token )
                  {
                        if ( u->down!=NULL )
                        {
                              for (w=u->down; w->right!=NULL; w=w->right) {;}
                              w->right = v->down;     /* link children together */
                        }
                        else u->down = v->down;
                        trail->right = v->right;            /* unlink factored node */
                        _Tfree( v );
                        v = trail->right;
                  }
                  else {trail = v; v=v->right;}
            }
      }
      /* left-factor what is below */
      for (u=t; u!=NULL; u=u->right) u->down = tleft_factor( u->down );
      return t;
}

/* remove the permutation p from t if present */
Tree *
#ifdef __USE_PROTOS
trm_perm( Tree *t, Tree *p )
#else
trm_perm( t, p )
Tree *t;
Tree *p;
#endif
{
      /*
      fprintf(stderr, "trm_perm(");
      preorder(t); fprintf(stderr, ",");
      preorder(p); fprintf(stderr, " )\n");
      */
      if ( t == NULL || p == NULL ) return NULL;
      if ( t->token == ALT )
      {
            t->down = trm_perm(t->down, p);
            if ( t->down == NULL )                    /* nothing left below, rm cur node */
            {
                  Tree *u = t->right;
                  _Tfree( t );
                  return trm_perm(u, p);
            }
            t->right = trm_perm(t->right, p);   /* look for more instances of p */
            return t;
      }
      if ( p->token != t->token )                     /* not found, try a sibling */
      {
            t->right = trm_perm(t->right, p);
            return t;
      }
      t->down = trm_perm(t->down, p->down);
      if ( t->down == NULL )                          /* nothing left below, rm cur node */
      {
            Tree *u = t->right;
            _Tfree( t );
            return trm_perm(u, p);
      }
      t->right = trm_perm(t->right, p);         /* look for more instances of p */
      return t;
}

/* add the permutation 'perm' to the LL_k sets in 'fset' */
void
#ifdef __USE_PROTOS
tcvt( set *fset, Tree *perm )
#else
tcvt( fset, perm )
set *fset;
Tree *perm;
#endif
{
      if ( perm==NULL ) return;
      set_orel(perm->token, fset);
      tcvt(fset+1, perm->down);
}

/* for each element of ftbl[k], make it the root of a tree with permute(ftbl[k+1])
 * as a child.
 */
Tree *
#ifdef __USE_PROTOS
permute( int k, int max_k )
#else
permute( k, max_k )
int k, max_k;
#endif
{
      Tree *t, *u;
      
      if ( k>max_k ) return NULL;
      if ( ftbl[k][findex[k]] == nil ) return NULL;
      t = permute(k+1, max_k);
      if ( t==NULL&&k<max_k )       /* no permutation left below for k+1 tokens? */
      {
            findex[k+1] = 0;
            (findex[k])++;                /* try next token at this k */
            return permute(k, max_k);
      }
      
      u = tmake(tnode(ftbl[k][findex[k]]), t, NULL);
      if ( k == max_k ) (findex[k])++;
      return u;
}

/* Compute LL(k) trees for alts alt1 and alt2 of p.
 * function result is tree of ambiguous input permutations
 *
 * ALGORITHM may change to look for something other than LL_k size
 * trees ==> maxk will have to change.
 */
Tree *
#ifdef __USE_PROTOS
VerifyAmbig( Junction *alt1, Junction *alt2, unsigned **ft, set *fs, Tree **t, Tree **u, int *numAmbig )
#else
VerifyAmbig( alt1, alt2, ft, fs, t, u, numAmbig )
Junction *alt1;
Junction *alt2;
unsigned **ft;
set *fs;
Tree **t;
Tree **u;
int *numAmbig;
#endif
{
      set rk;
      Tree *perm, *ambig=NULL;
      Junction *p;
      int k;
    int    tnodes_at_start=TnodesAllocated;
    int    tnodes_at_end;
    int    tnodes_used;
    set    *save_fs;
    int    j;

    save_fs=(set *) calloc(CLL_k+1,sizeof(set));
    require(save_fs != NULL,"save_fs calloc");

    for (j=0; j <= CLL_k ; j++) save_fs[j]=set_dup(fs[j]);

      maxk = LL_k;                        /* NOTE: for now, we look for LL_k */
      ftbl = ft;
      fset = fs;
      constrain = &(fset[1]);
      findex = (int *) calloc(LL_k+1, sizeof(int));
      if ( findex == NULL )
      {
            fprintf(stderr, ErrHdr, FileStr[CurAmbigfile], CurAmbigline);
            fprintf(stderr, " out of memory while analyzing alts %d and %d of %s\n",
                                    CurAmbigAlt1,
                                    CurAmbigAlt2,
                                    CurAmbigbtype);
            exit(PCCTS_EXIT_FAILURE);
      }
      for (k=1; k<=LL_k; k++) findex[k] = 0;

      rk = empty;
      ConstrainSearch = 1;    /* consider only tokens in ambig sets */

      p = analysis_point((Junction *)alt1->p1);
      TRAV(p, LL_k, &rk, *t);
      *t = tshrink( *t );
      *t = tflatten( *t );
      *t = tleft_factor( *t );    /* MR10 */
      *t = prune(*t, LL_k);
      *t = tleft_factor( *t );

/***  fprintf(stderr, "after shrink&flatten&prune&left_factor:"); preorder(*t); fprintf(stderr, "\n");*/
      if ( *t == NULL )
      {
/***  fprintf(stderr, "TreeIncomplete --> no LL(%d) ambiguity\n", LL_k);*/
            Tfree( *t );      /* kill if impossible to have ambig */
            *t = NULL;
      }

      p = analysis_point((Junction *)alt2->p1);

      TRAV(p, LL_k, &rk, *u);
      *u = tshrink( *u );
      *u = tflatten( *u );
      *t = tleft_factor( *t );    /* MR10 */
      *u = prune(*u, LL_k);
      *u = tleft_factor( *u );
/*    fprintf(stderr, "after shrink&flatten&prune&lfactor:"); preorder(*u); fprintf(stderr, "\n");*/
      if ( *u == NULL )
      {
/*          fprintf(stderr, "TreeIncomplete --> no LL(%d) ambiguity\n", LL_k);*/
            Tfree( *u );
            *u = NULL;
      }

      for (k=1; k<=LL_k; k++) set_clr( fs[k] );

      ambig = tnode(ALT);
      k = 0;
      if ( *t!=NULL && *u!=NULL )
      {
            while ( (perm=permute(1,LL_k))!=NULL )
            {
/*                fprintf(stderr, "chk perm:"); preorder(perm); fprintf(stderr, "\n");*/
                  if ( tmember(perm, *t) && tmember(perm, *u) )
                  {
/*                      fprintf(stderr, "ambig upon"); preorder(perm); fprintf(stderr, "\n");*/

                        k++;
                        perm->right = ambig->down;
                        ambig->down = perm;
                        tcvt(&(fs[1]), perm);
                  }
                  else Tfree( perm );
            }
      }

    for (j=0; j <= CLL_k ; j++) fs[j]=save_fs[j];
    free( (char *) save_fs);

    tnodes_at_end=TnodesAllocated;
    tnodes_used=tnodes_at_end - tnodes_at_start;

    if (TnodesReportThreshold > 0 && tnodes_used > TnodesReportThreshold) {
      fprintf(stdout,"There were %d tuples whose ambiguity could not be resolved by full lookahead\n",k);
      fprintf(stdout,"There were %d tnodes created to resolve ambiguity between:\n\n",tnodes_used);
      fprintf(stdout,"  Choice 1: %s  line %d  file %s\n",
                                 MR_ruleNamePlusOffset( (Node *) alt1),alt1->line,FileStr[alt1->file]);
      fprintf(stdout,"  Choice 2: %s  line %d  file %s\n",
                                 MR_ruleNamePlusOffset( (Node *) alt2),alt2->line,FileStr[alt2->file]);
      for (j=1; j <= CLL_k ; j++) {
        fprintf(stdout,"\n    Intersection of lookahead[%d] sets:\n",j);
        MR_dumpTokenSet(stdout,2,fs[j]);
      };
      fprintf(stdout,"\n");
    };

      *numAmbig = k;
      if ( ambig->down == NULL ) {_Tfree(ambig); ambig = NULL;}
      free( (char *)findex );
/*    fprintf(stderr, "final ambig:"); preorder(ambig); fprintf(stderr, "\n");*/
      return ambig;
}

static Tree *
#ifdef __USE_PROTOS
bottom_of_chain( Tree *t )
#else
bottom_of_chain( t )
Tree *t;
#endif
{
    if ( t==NULL ) return NULL;
    for (; t->down != NULL; t=t->down) {;}
    return t;
}

/*
 * Make a tree from k sets where the degree of the first k-1 sets is 1.
 */
Tree *
#ifdef __USE_PROTOS
make_tree_from_sets( set *fset1, set *fset2 )
#else
make_tree_from_sets( fset1, fset2 )
set *fset1;
set *fset2;
#endif
{
      set inter;
      int i;
      Tree *t=NULL, *n, *u;
      unsigned *p,*q;
      require(LL_k>1, "make_tree_from_sets: LL_k must be > 1");

      /* do the degree 1 sets first */
      for (i=1; i<=LL_k-1; i++)
      {
            inter = set_and(fset1[i], fset2[i]);
            require(set_deg(inter)==1, "invalid set to tree conversion");
            n = tnode(set_int(inter));
            if (t==NULL) t=n; else tmake(t, n, NULL);
            set_free(inter);
      }

      /* now add the chain of tokens at depth k */
      u = bottom_of_chain(t);
      inter = set_and(fset1[LL_k], fset2[LL_k]);
      if ( (q=p=set_pdq(inter)) == NULL ) fatal_internal("Can't alloc space for set_pdq");
      /* first one is linked to bottom, then others are sibling linked */
      n = tnode(*p++);
      u->down = n;
      u = u->down;
      while ( *p != nil )
      {
            n = tnode(*p);
            u->right = n;
            u = u->right;
            p++;
      }
      free((char *)q);

      return t;
}

/* create and return the tree of lookahead k-sequences that are in t, but not
 * in the context of predicates in predicate list p.
 */
Tree *
#ifdef __USE_PROTOS
tdif( Tree *ambig_tuples, Predicate *p, set *fset1, set *fset2 )
#else
tdif( ambig_tuples, p, fset1, fset2 )
Tree *ambig_tuples;
Predicate *p;
set *fset1;
set *fset2;
#endif
{
      unsigned **ft;
      Tree *dif=NULL;
      Tree *perm;
      set b;
      int i,k;

      if ( p == NULL ) return tdup(ambig_tuples);

      ft = (unsigned **) calloc(CLL_k+1, sizeof(unsigned *));
      require(ft!=NULL, "cannot allocate ft");
      for (i=1; i<=CLL_k; i++)
      {
            b = set_and(fset1[i], fset2[i]);
            ft[i] = set_pdq(b);
            set_free(b);
      }
      findex = (int *) calloc(LL_k+1, sizeof(int));
      if ( findex == NULL )
      {
            fatal_internal("out of memory in tdif while checking predicates");
      }
      for (k=1; k<=LL_k; k++) findex[k] = 0;

#ifdef DBG_TRAV
      fprintf(stderr, "tdif_%d[", p->k);
      preorder(ambig_tuples);
      fprintf(stderr, ",");
      preorder(p->tcontext);
      fprintf(stderr, "] =");
#endif

      ftbl = ft;
      while ( (perm=permute(1,p->k))!=NULL )
      {
#ifdef DBG_TRAV
            fprintf(stderr, "test perm:"); preorder(perm); fprintf(stderr, "\n");
#endif
            if ( tmember_constrained(perm, ambig_tuples) &&
                   !tmember_of_context(perm, p) )
            {
#ifdef DBG_TRAV
                  fprintf(stderr, "satisfied upon"); preorder(perm); fprintf(stderr, "\n");
#endif
                  k++;
                  if ( dif==NULL ) dif = perm;
                  else
                  {
                        perm->right = dif;
                        dif = perm;
                  }
            }
            else Tfree( perm );
      }

#ifdef DBG_TRAV
      preorder(dif);
      fprintf(stderr, "\n");
#endif

      for (i=1; i<=CLL_k; i++) free( (char *)ft[i] );
      free((char *)ft);
      free((char *)findex);

      return dif;
}

/* is lookahead sequence t a member of any context tree for any
 * predicate in p?
 */
static int
#ifdef __USE_PROTOS
tmember_of_context( Tree *t, Predicate *p )
#else
tmember_of_context( t, p )
Tree *t;
Predicate *p;
#endif
{
      for (; p!=NULL; p=p->right)
      {
            if ( p->expr==PRED_AND_LIST || p->expr==PRED_OR_LIST )
                  return tmember_of_context(t, p->down);
            if ( tmember_constrained(t, p->tcontext) ) return 1;
            if ( tmember_of_context(t, p->down) ) return 1;
      }
      return 0;
}

int
#ifdef __USE_PROTOS
is_single_tuple( Tree *t )
#else
is_single_tuple( t )
Tree *t;
#endif
{
      if ( t == NULL ) return 0;
      if ( t->right != NULL ) return 0;
      if ( t->down == NULL ) return 1;
      return is_single_tuple(t->down);
}


/* MR10 Check that a context guard contains only allowed things */
/* MR10   (mainly token references).                            */

#ifdef __USE_PROTOS
int contextGuardOK(Node *p,int h,int *hmax)
#else
int contextGuardOK(p,h,hmax)
  Node  *p;
  int   h;
  int   *hmax;
#endif
{
    Junction     *j;
    TokNode      *tn;

    if (p == NULL) return 1;
    if (p->ntype == nToken) {
      h++;
      if (h > *hmax) *hmax=h;
      tn=(TokNode *)p;
      if (tn->el_label != NULL) {
        warnFL(eMsg1("a label (\"%s\") for a context guard element is meaningless",tn->el_label),
                             FileStr[p->file],p->line);
      };
      return contextGuardOK( ( (TokNode *) p)->next,h,hmax);
    } else if (p->ntype == nAction) {
      goto Fail;
    } else if (p->ntype == nRuleRef) {
      goto Fail;
    } else {
      require (p->ntype == nJunction,"Unexpected ntype");
      j=(Junction *) p;
      if (j->jtype != Generic &&
          j->jtype != aSubBlk &&        /* pretty sure this one is allowed */
/****     j->jtype != aOptBlk && ****/  /* pretty sure this one is allowed */ /* MR11 not any more ! */
          j->jtype != EndBlk) {
        errFL("A context guard may not contain an option block: {...} or looping block: (...)* or (...)+",
                  FileStr[p->file],p->line);
        contextGuardOK(j->p1,h,hmax);
        return 0;
      };
      /* do both p1 and p2 so use | rather than ||  */
      return contextGuardOK(j->p2,h,hmax) | contextGuardOK(j->p1,h,hmax);
    };
Fail:
    errFL("A context guard may contain only Token references - guard will be ignored",
                             FileStr[p->file],p->line);
    contextGuardOK( ( (ActionNode *) p)->next,h,hmax);
    return 0;
}

/*
 * Look at a (...)? generalized-predicate context-guard and compute
 * either a lookahead set (k==1) or a lookahead tree for k>1.  The
 * k level is determined by the guard itself rather than the LL_k
 * variable.  For example, ( A B )? is an LL(2) guard and ( ID )?
 * is an LL(1) guard.  For the moment, you can only have a single
 * tuple in the guard.  Physically, the block must look like this
 *   --o-->TOKEN-->o-->o-->TOKEN-->o-- ... -->o-->TOKEN-->o--
 * An error is printed for any other type.
 */
Predicate *
#ifdef __USE_PROTOS
computePredFromContextGuard(Graph blk,int *msgDone)    /* MR10 */
#else
computePredFromContextGuard(blk,msgDone)               /* MR10 */
  Graph     blk;
  int       *msgDone;                                       /* MR10 */
#endif
{
    Junction *junc = (Junction *)blk.left, *p;
    Tree        *t=NULL;
      Predicate   *pred = NULL;
      set         scontext, rk;
    int         ok;
    int         hmax=0;

    require(junc!=NULL && junc->ntype == nJunction, "bad context guard");

/* MR10 Check for anything other than Tokens and generic junctions */

    *msgDone=0;                                             /* MR10 */
    ok=contextGuardOK( (Node *)junc,0,&hmax);               /* MR10 */
    if (! ok) {                                             /* MR10 */
      *msgDone=1;                                           /* MR10 */
      return NULL;                                          /* MR10 */
    };                                                      /* MR10 */
    if (hmax == 0) {
errFL("guard is 0 tokens long",FileStr[junc->file],junc->line);          /* MR11 */
      *msgDone=1;
      return NULL;
    };
    if (hmax > CLL_k) {                                     /* MR10 */
errFL(eMsgd2("guard is %d tokens long - lookahead is limited to max(k,ck)==%d", /* MR10 */
        hmax,CLL_k),                                        /* MR10 */
        FileStr[junc->file],junc->line);                    /* MR10 */
      *msgDone=1;                                           /* MR10 */
      return NULL;                                          /* MR10 */
    };                                                      /* MR10 */

      rk = empty;
      p = junc;
      pred = new_pred();
      pred->k = hmax;     /* MR10 should be CLL_k, not LLK ? */
      if (hmax > 1 )      /* MR10 was LL_k                   */
      {
            ConstrainSearch = 0;
            ContextGuardTRAV = 1;
            TRAV(p, hmax, &rk, t);  /* MR10 was LL_k */
            ContextGuardTRAV = 0;
            set_free(rk);
            t = tshrink( t );
            t = tflatten( t );
            t = tleft_factor( t );
/*
            fprintf(stderr, "ctx guard:");
            preorder(t);
            fprintf(stderr, "\n");
*/
            pred->tcontext = t;
      }
      else
      {
            REACH(p, 1, &rk, scontext);
            require(set_nil(rk), "rk != nil");
            set_free(rk);
/*
            fprintf(stderr, "LL(1) ctx guard is:");
            s_fprT(stderr, scontext);
            fprintf(stderr, "\n");
*/
            pred->scontext[1] = scontext;
      }

    list_add(&ContextGuardPredicateList,pred);     /* MR13 */

      return pred;
}

/* MR13
   When the context guard is originally computed the
   meta-tokens are not known.
*/

#ifdef __USE_PROTOS
void recomputeContextGuard(Predicate *pred)
#else
void recomputeContextGuard(pred)
    Predicate   *pred;
#endif
{
    Tree *          t=NULL;
      set             scontext;
    set             rk;
    ActionNode *    actionNode;
    Junction *      p;

    actionNode=pred->source;
    require (actionNode != NULL,"context predicate's source == NULL");

    p=actionNode->guardNodes;
    require (p != NULL,"context predicate's guardNodes == NULL");

      rk = empty;
      if (pred->k > 1 )
      {
            ConstrainSearch = 0;
            ContextGuardTRAV = 1;
            TRAV(p, pred->k, &rk, t);
            ContextGuardTRAV = 0;
            set_free(rk);
            t = tshrink( t );
            t = tflatten( t );
            t = tleft_factor( t );
        Tfree(pred->tcontext);
            pred->tcontext = t;
      }
      else
      {
            REACH(p, 1, &rk, scontext);
            require(set_nil(rk), "rk != nil");
            set_free(rk);
        set_free(pred->scontext[1]);
            pred->scontext[1] = scontext;
      }
}

/* MR11 - had enough of flags yet ? */

int     MR_AmbSourceSearch=0;
int     MR_AmbSourceSearchGroup=0;
int     MR_AmbSourceSearchChoice=0;
int     MR_AmbSourceSearchLimit=0;
int     MR_matched_AmbAidRule=0;

static    set         *matchSets[2]={NULL,NULL};
static    int         *tokensInChain=NULL;
static    Junction    *MR_AmbSourceSearchJ[2];

void MR_traceAmbSourceKclient()
{
  int       i;
  set       *save_fset;
  int       save_ConstrainSearch;
  set       incomplete;
  Tree      *t;

  if (matchSets[0] == NULL) {
    matchSets[0]=(set *) calloc (CLL_k+1,sizeof(set));
    require (matchSets[0] != NULL,"matchSets[0] alloc");
    matchSets[1]=(set *) calloc (CLL_k+1,sizeof(set));
    require (matchSets[1] != NULL,"matchSets[1] alloc");
  };

  for (i=1 ; i <= MR_AmbSourceSearchLimit ; i++) {
    set_clr(matchSets[0][i]);
    set_orel( (unsigned) tokensInChain[i],
                              &matchSets[0][i]);
    set_clr(matchSets[1][i]);
    set_orel( (unsigned) tokensInChain[i],
                              &matchSets[1][i]);
  };

  save_fset=fset;
  save_ConstrainSearch=ConstrainSearch;



  for (i=0 ; i < 2 ; i++) {

#if 0
**    fprintf(stdout,"  Choice:%d  Depth:%d  ",i+1,MR_AmbSourceSearchLimit);
**    fprintf(stdout,"(");
**    for (j=1 ; j <= MR_AmbSourceSearchLimit ; j++) {
**      if (j != 1) fprintf(stdout," ");
**      fprintf(stdout,"%s",TerminalString(tokensInChain[j]));
**    };
**    fprintf(stdout,")\n\n");
#endif

    fset=matchSets[i];

    MR_AmbSourceSearch=1;
    MR_MaintainBackTrace=1;
    MR_AmbSourceSearchChoice=i;
    ConstrainSearch=1;

    maxk = MR_AmbSourceSearchLimit;

    incomplete=empty;
    t=NULL;

    constrain = &(fset[1]);
    MR_pointerStackReset(&MR_BackTraceStack);

    TRAV(MR_AmbSourceSearchJ[i],maxk,&incomplete,t);

    Tfree(t);

    require (set_nil(incomplete),"MR_traceAmbSourceK TRAV incomplete");
    require (MR_BackTraceStack.count == 0,"K: MR_BackTraceStack.count != 0");

    set_free(incomplete);
  };

  ConstrainSearch=save_ConstrainSearch;
  fset=save_fset;
  MR_AmbSourceSearch=0;
  MR_MaintainBackTrace=0;
  MR_AmbSourceSearchChoice=0;
}

#ifdef __USE_PROTOS
Tree *tTrunc(Tree *t,int depth)
#else
Tree *tTrunc(t,depth)
  Tree  *t;
#endif
{
    Tree    *u;

    require ( ! (t == NULL && depth > 0),"tree too short");

    if (depth == 0) return NULL;

    if (t->token == ALT) {
      u=tTrunc(t->down,depth);
    } else {
      u=tnode(t->token);
      u->down=tTrunc(t->down,depth-1);
    };
    if (t->right != NULL) u->right=tTrunc(t->right,depth);
    return u;
}

#ifdef __USE_PROTOS
void MR_iterateOverTree(Tree *t,int chain[])
#else
void MR_iterateOverTree(t,chain)
  Tree          *t;
  int           chain[];
#endif
{
  if (t == NULL) return;
  chain[0]=t->token;
  if (t->down != NULL) {
    MR_iterateOverTree(t->down,&chain[1]);
  } else {
    MR_traceAmbSourceKclient();
  };
  MR_iterateOverTree(t->right,&chain[0]);
  chain[0]=0;
}

#ifdef __USE_PROTOS
void MR_traceAmbSourceK(Tree *t,Junction *alt1,Junction *alt2)
#else
void MR_traceAmbSourceK(t,alt1,alt2)
  Tree      *t;
  Junction  *alt1;
  Junction  *alt2;
#endif
{
    int         i;
    int         depth;
    int         maxDepth;
    Tree        *truncatedTree;

    if (MR_AmbAidRule == NULL) return;

    if ( ! (
            strcmp(MR_AmbAidRule,alt1->rname) == 0 ||
            strcmp(MR_AmbAidRule,alt2->rname) == 0 ||
            MR_AmbAidLine==alt1->line ||
            MR_AmbAidLine==alt2->line
           )
       ) return;

    MR_matched_AmbAidRule++;

    /* there are no token sets in trees, only in TokNodes */

    MR_AmbSourceSearchJ[0]=analysis_point( (Junction *) alt1->p1);
    MR_AmbSourceSearchJ[1]=analysis_point( (Junction *) alt2->p1);

    if (tokensInChain == NULL) {
      tokensInChain=(int *) calloc (CLL_k+1,sizeof(int));
      require (tokensInChain != NULL,"tokensInChain alloc");
    };

    MR_AmbSourceSearchGroup=0;

    fprintf(stdout,"\n");
    fprintf(stdout,"  Ambiguity Aid                 ");
    fprintf(stdout,
                (MR_AmbAidDepth <= LL_k ?
                    "(-k %d  -aa %s  %s  -aad %d)\n\n" :
                        "(-k %d  -aa %s  %s  [-k value limits -aad %d])\n\n"),
                LL_k,
                MR_AmbAidRule,
                (MR_AmbAidMultiple ? "-aam" : ""),
                MR_AmbAidDepth);

    for (i=0 ; i < 2 ; i++) {
      fprintf(stdout,"    Choice %d: %-25s  line %d  file %s\n",
                  (i+1),
                  MR_ruleNamePlusOffset( (Node *) MR_AmbSourceSearchJ[i]),
                  MR_AmbSourceSearchJ[i]->line,
                  FileStr[MR_AmbSourceSearchJ[i]->file]);
    };

    fprintf(stdout,"\n");

    if (MR_AmbAidDepth < LL_k) {
      maxDepth=MR_AmbAidDepth;
    } else {
      maxDepth=LL_k;
    };

    for (depth=1 ; depth <= maxDepth; depth++) {
      MR_AmbSourceSearchLimit=depth;
      if (depth < LL_k) {
        truncatedTree=tTrunc(t,depth);
        truncatedTree=tleft_factor(truncatedTree);
        MR_iterateOverTree(truncatedTree,&tokensInChain[1]);    /* <===== */
        Tfree(truncatedTree);
      } else {
        MR_iterateOverTree(t,tokensInChain);                /* <===== */
      };
      fflush(stdout);
      fflush(stderr);
    };

    fprintf(stdout,"\n");
    MR_AmbSourceSearch=0;
    MR_MaintainBackTrace=0;
    MR_AmbSourceSearchGroup=0;
    MR_AmbSourceSearchChoice=0;
    MR_AmbSourceSearchLimit=0;

}


/* this if for k=1 grammars only

   this is approximate only because of the limitations of linear
   approximation lookahead.  Don't want to do a k=3 search when
   the user only specified a ck=3 grammar
*/

#ifdef __USE_PROTOS
void MR_traceAmbSource(set *matchSets,Junction *alt1, Junction *alt2)
#else
void MR_traceAmbSource(matchSets,alt1,alt2)
  set       *matchSets;
  Junction  *alt1;
  Junction  *alt2;
#endif
{
    set         *save_fset;
    Junction    *p[2];
    int         i;
    int         j;
    set         *dup_matchSets;
    set         intersection;
    set         incomplete;
    set         tokensUsed;
    int         depth;

    if (MR_AmbAidRule == NULL) return;
    if ( ! (
            strcmp(MR_AmbAidRule,alt1->rname) == 0 ||
            strcmp(MR_AmbAidRule,alt2->rname) == 0 ||
            MR_AmbAidLine==alt1->line ||
            MR_AmbAidLine==alt2->line
           )
       ) return;

    MR_matched_AmbAidRule++;

    save_fset=fset;

    dup_matchSets=(set *) calloc(CLL_k+1,sizeof(set));
    require (dup_matchSets != NULL,"Can't allocate dup_matchSets");

    p[0]=analysis_point( (Junction *) alt1->p1);
    p[1]=analysis_point( (Junction *) alt2->p1);

    fprintf(stdout,"\n");

    fprintf(stdout,"  Ambiguity Aid                 ");
    fprintf(stdout,
                (MR_AmbAidDepth <= CLL_k ?
                    "(-ck %d  -aa %s  %s  -aad %d)\n\n" :
                        "(-ck %d  -aa %s  %s  [-ck value limits -aad %d])\n\n"),
                CLL_k,
                MR_AmbAidRule,
                (MR_AmbAidMultiple ? "-aam" : ""),
                MR_AmbAidDepth);

    for (i=0 ; i < 2 ; i++) {
      fprintf(stdout,"    Choice %d: %-25s  line %d  file %s\n",
                            (i+1),
                            MR_ruleNamePlusOffset( (Node *) p[i]),
                            p[i]->line,FileStr[p[i]->file]);
    };

    for (j=1; j <= CLL_k ; j++) {
      fprintf(stdout,"\n    Intersection of lookahead[%d] sets:\n",j);
      intersection=set_and(alt1->fset[j],alt2->fset[j]);
      MR_dumpTokenSet(stdout,2,intersection);
      set_free(intersection);
    };

    fprintf(stdout,"\n");

    require (1 <= MR_AmbAidDepth && MR_AmbAidDepth <= CLL_k,
                "illegal MR_AmbAidDepth");

    MR_AmbSourceSearchGroup=0;
    for (depth=1; depth <= MR_AmbAidDepth; depth++) {
        MR_AmbSourceSearchLimit=depth;
        for (i=0 ; i < 2 ; i++) {

/***        fprintf(stdout,"  Choice:%d  Depth:%d\n\n",i+1,depth);  ***/

            for (j=0 ; j <= CLL_k ; j++) { dup_matchSets[j]=set_dup(matchSets[j]); };
            fset=dup_matchSets;

            fflush(output);
            fflush(stdout);

            MR_AmbSourceSearch=1;
            MR_MaintainBackTrace=1;
            MR_AmbSourceSearchChoice=i;

            maxk = depth;
            tokensUsed=empty;
            incomplete=empty;

            constrain = &(fset[1]);
            MR_pointerStackReset(&MR_BackTraceStack);

            REACH(p[i],depth,&incomplete,tokensUsed);

            fflush(output);
            fflush(stdout);

            require (set_nil(incomplete),"MR_traceAmbSource REACH incomplete");
            require (MR_BackTraceStack.count == 0,"1: MR_BackTraceStack.count != 0");

            set_free(incomplete);
            set_free(tokensUsed);

            for (j=0 ; j <= CLL_k ; j++) { set_free(dup_matchSets[j]); };
        };
    };

    fprintf(stdout,"\n");

    MR_AmbSourceSearch=0;
    MR_MaintainBackTrace=0;
    MR_AmbSourceSearchGroup=0;
    MR_AmbSourceSearchChoice=0;
    MR_AmbSourceSearchLimit=0;

    fset=save_fset;
    free ( (char *) dup_matchSets);
}

static int itemCount;

void MR_backTraceDumpItemReset() {
  itemCount=0;
}

#ifdef __USE_PROTOS
void MR_backTraceDumpItem(FILE *f,int skip,Node *n)
#else
void MR_backTraceDumpItem(f,skip,n)
  FILE      *f;
  int       skip;
  Node      *n;
#endif
{
  TokNode       *tn;
  RuleRefNode   *rrn;
  Junction      *j;
  ActionNode    *a;

  switch (n->ntype) {
    case nToken:
        itemCount++; if (skip) goto EXIT;
        tn=(TokNode *)n;
        if (set_nil(tn->tset)) {
          fprintf(f,"  %2d #token %-23s",itemCount,TerminalString(tn->token));
        } else {
          fprintf(f,"  %2d #tokclass %-20s",itemCount,TerminalString(tn->token));
        };
        break;
    case nRuleRef:
        itemCount++; if (skip) goto EXIT;
        rrn=(RuleRefNode *)n;
        fprintf(f,"  %2d to %-27s",itemCount,rrn->text);
        break;
    case nAction:
        a=(ActionNode *)n;
        goto EXIT;
    case nJunction:

      j=(Junction *)n;

      switch (j->jtype) {
        case aSubBlk:
            if (j->guess) {
              itemCount++; if (skip) goto EXIT;
              fprintf(f,"  %2d %-30s",itemCount,"in (...)? block at");
              break;
            };
/******     fprintf(f,"  %2d %-32s",itemCount,"in (...) block at");  *******/
/******     break;                                                          *******/
            goto EXIT;
        case aOptBlk:
            itemCount++; if (skip) goto EXIT;
            fprintf(f,"  %2d %-30s",itemCount,"in {...} block");
            break;
        case aLoopBlk:
            itemCount++; if (skip) goto EXIT;
            fprintf(f,"  %2d %-30s",itemCount,"in (...)* block");
            break;
        case EndBlk:
            if (j->alpha_beta_guess_end) {
              itemCount++; if (skip) goto EXIT;
              fprintf(f,"  %2d %-30s",itemCount,"end (...)? block at");
              break;
            };
            goto EXIT;
/******     fprintf(f,"  %2d %-32s",itemCount,"end of a block at");     *****/
/******     break;                                                             *****/
        case RuleBlk:
            itemCount++; if (skip) goto EXIT;
            fprintf(f,"  %2d %-30s",itemCount,j->rname);
            break;
        case Generic:
            goto EXIT;
        case EndRule:
            itemCount++; if (skip) goto EXIT;
            fprintf (f,"  %2d end %-26s",itemCount,j->rname);
            break;
        case aPlusBlk:
            itemCount++; if (skip) goto EXIT;
            fprintf(f,"  %2d %-30s",itemCount,"in (...)+ block");
            break;
        case aLoopBegin:
            goto EXIT;
      };
      break;
  };
  fprintf(f," %-23s line %-4d  %s\n",MR_ruleNamePlusOffset(n),n->line,FileStr[n->file]);
EXIT:
  return;
}


static PointerStack     previousBackTrace={0,0,NULL};

#ifdef __USE_PROTOS
void MR_backTraceReport(void)
#else
void MR_backTraceReport()
#endif
{
  int       i;
  int       match = 0;
  int       limitMatch;

  Node      *p;
  TokNode   *tn;
  set       remainder;
  int       depth;

  /* Even when doing a k=2 search this routine can get
       called when there is only 1 token on the stack.
     This is because something like rRuleRef can change
       the search value of k from 2 to 1 temporarily.
     It does this because the it wants to know the k=1
       first set before it does a k=2 search
  */

  depth=0;
  for (i=0; i < MR_BackTraceStack.count ; i++) {
    p=(Node *) MR_BackTraceStack.data[i];
    if (p->ntype == nToken) depth++;
  };

/* MR14 */  if (MR_AmbSourceSearch) {
/* MR14 */     require (depth <= MR_AmbSourceSearchLimit,"depth > MR_AmbSourceSearchLimit");
/* MR14 */  }

  /* MR23 THM - Traceback report was being called at the wrong time for -alpha reports */
  /*            Reported by Arpad Beszedes (beszedes@inf.u-szeged.hu)                  */

  if (MR_AmbSourceSearchLimit == 0 || depth < MR_AmbSourceSearchLimit) {
    return;
  };

  MR_backTraceDumpItemReset();

  limitMatch=MR_BackTraceStack.count;
  if (limitMatch > previousBackTrace.count) {
    limitMatch=previousBackTrace.count;
  };

  for (match=0; match < limitMatch; match++) {
    if (MR_BackTraceStack.data[match] !=
        previousBackTrace.data[match]) {
      break;
    };
  };

  /* not sure at the moment why there would be duplicates */

  if (match != MR_BackTraceStack.count) {

    fprintf(stdout,"     Choice:%d  Depth:%d  Group:%d",
        (MR_AmbSourceSearchChoice+1),
        MR_AmbSourceSearchLimit,
        ++MR_AmbSourceSearchGroup);

    depth=0;
    fprintf(stdout,"  (");
    for (i=0; i < MR_BackTraceStack.count ; i++) {
      p=(Node *) MR_BackTraceStack.data[i];
      if (p->ntype != nToken) continue;
      tn=(TokNode *)p;
      if (depth != 0) fprintf(stdout," ");
      fprintf(stdout,TerminalString(tn->token));
      depth++;
      if (! MR_AmbAidMultiple) {
        if (set_nil(tn->tset)) {
          set_rm( (unsigned) tn->token,fset[depth]);
        } else {
          remainder=set_dif(fset[depth],tn->tset);
          set_free(fset[depth]);
          fset[depth]=remainder;
        };
      };
    };
    fprintf(stdout,")\n");

    for (i=0; i < MR_BackTraceStack.count ; i++) {
      MR_backTraceDumpItem(stdout, (i<match) ,(Node *) MR_BackTraceStack.data[i]);
    };
    fprintf(stdout,"\n");
    fflush(stdout);

    MR_pointerStackReset(&previousBackTrace);

    for (i=0; i < MR_BackTraceStack.count ; i++) {
      MR_pointerStackPush(&previousBackTrace,MR_BackTraceStack.data[i]);
    };

  };
}

#ifdef __USE_PROTOS
void MR_setConstrainPointer(set * newConstrainValue)
#else
void MR_setConstrainPointer(newConstrainValue)
  set * newConstrainValue;
#endif
{
      constrain=newConstrainValue;
}

Generated by  Doxygen 1.6.0   Back to index