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

#include <stdio.h>

#include "pcctscfg.h"

#include "set.h"
#include "syn.h"
#include "hash.h"
#include "generic.h"
#include "dlgdef.h"
#include <ctype.h>

#ifdef __USE_PROTOS
void dumppred(Predicate *);
#else
void dumppred();
#endif

/*
  Try to determine whether predicate "first" is true for
    all cases where "second" is true.  Comparison takes place
    without regard to context.
  Assumes that predicate symbols have been expanded.
  Assumes that there are no NAND or NOR nodes

*/

#ifdef __USE_PROTOS
int MR_secondPredicateUnreachable(Predicate *first,Predicate *second)
#else
int MR_secondPredicateUnreachable(first,second)
  Predicate     *first;
  Predicate     *second;
#endif
{
  Predicate     *f;
  Predicate     *s;

  if (first == NULL) {
    return 1;
  } else if (second == NULL) {
    return 0;
  } else if (first->down == NULL && second->down == NULL) {
    if (first->source == second->source &&
        first->inverted == second->inverted) {
      return 1; /* look identical - will never reach alt2 */
    } else {
      return 0; /* look different */
    };
  } else if (first->down == NULL && second->down != NULL) {

    if (second->expr == PRED_AND_LIST) {

      /* unreachable if first covers any child of second */

      for (s=second->down; s != NULL; s=s->right) {
        if (MR_secondPredicateUnreachable(first,s)) {
          return 1;
        };
      };
      return 0;
    } else if (second->expr == PRED_OR_LIST) {

      /* unreachable if first covers every child of second */

      for (s=second->down; s != NULL; s=s->right) {
        if (!MR_secondPredicateUnreachable(first,s)) {
          return 0;
        };
      };
      return 1;
    } else {
      require (0,"Illegal pred->expr");
      return 0; /* MR20 Make compiler happy */
    };
  } else if (first->down != NULL && second->down == NULL) {
    if (first->expr == PRED_AND_LIST) {

      /* unreachable if every child of first covers second */

      for (f=first->down; f != NULL; f=f->right) {
        if (!MR_secondPredicateUnreachable(f,second)) {
          return 0;
        };
      };
      return 1;
    } else if (first->expr == PRED_OR_LIST) {

      /* unreachable if any child of first covers second */

      for (f=first->down; f != NULL; f=f->right) {
        if (MR_secondPredicateUnreachable(f,second)) {
          return 1;
        };
      };
      return 0;
    } else {
      require (0,"Illegal predicate->expr");
      return 0; /* MR20 Make compiler happy */
    };
  } else {

    if (first->expr == PRED_AND_LIST && second->expr == PRED_AND_LIST) {

      /* unreachable if each child of first covers at least one child of second */

      for (f=first->down; f != NULL ; f=f->right) {
        for (s=second->down; s != NULL ; s=s->right) {
          if (MR_secondPredicateUnreachable(f,s)) goto A_next_f;
        };
        return 0;
A_next_f:
        continue;
      };
      return 1;

    } else if (first->expr == PRED_AND_LIST && second->expr == PRED_OR_LIST) {

      /* unreachable if each child of first covers ALL of second's children */

      for (f=first->down; f != NULL ; f=f->right) {
        for (s=second->down; s != NULL ; s=s->right) {
          if (!MR_secondPredicateUnreachable(f,s)) return 0;
        };
      };
      return 1;

    } else if (first->expr == PRED_OR_LIST && second->expr == PRED_AND_LIST) {

      /* unreachable if any child of second is covered by any child of first */

      for (f=first->down; f != NULL ; f=f->right) {
        for (s=second->down; s != NULL ; s=s->right) {
          if (MR_secondPredicateUnreachable(f,s)) return 1;
        };
      };
      return 0;

    } else if (first->expr == PRED_OR_LIST && second->expr == PRED_OR_LIST) {

      /* unreachable if every child of second is covered by some child of first */

      for (f=first->down; f != NULL ; f=f->right) {
        for (s=second->down; s != NULL ; s=s->right) {
          if (MR_secondPredicateUnreachable(f,s)) goto B_next_f;
        };
        return 0;
B_next_f:
       continue;
      };
      return 1;

    } else {
      require (0,"Illegal predicate->expr");
      return 0; /* MR20 Make compiler happy */
    };
  };
  return 0; /* MR20 MSVC 5.0 complains about missing return statement */
}

#ifdef __USE_PROTOS
void MR_xxxIndent(FILE *f,int depth)
#else
void MR_xxxIndent(f,depth)
  FILE  *f;
  int   depth;
#endif
{
  int   i;

  for (i=0; i<depth ; i++) {
    fprintf(f,"  ");
  };
}

#ifdef __USE_PROTOS
void MR_stderrIndent(int depth)
#else
void MR_stderrIndent(depth)
  int   depth;
#endif
{
  MR_xxxIndent(stderr,depth);
}

#ifdef __USE_PROTOS
void MR_outputIndent(int depth)
#else
void MR_outputIndent(depth)
  int   depth;
#endif
{
  MR_xxxIndent(output,depth);
}

#ifdef __USE_PROTOS
void MR_set_reuse(set *s)
#else
void MR_set_reuse(s)
  set   *s;
#endif
{
  set_free(*s);
  *s=empty;
}

#ifdef __USE_PROTOS
void MR_dumpPredRuleRefStack(FILE *iounit,int indent)
#else
void MR_dumpPredRuleRefStack(iounit,indent)
  FILE  *iounit;
  int   indent;
#endif
{
    int             i;
    int             j;
    int             count=MR_PredRuleRefStack.count;
    RuleRefNode     *rrn=NULL;
    Junction        *lastOne;

    if (count == 0) {
      fprintf(iounit,"empty\n");
      return;
    };
    for (i=0; i < count; i++) {
      rrn=(RuleRefNode *) MR_PredRuleRefStack.data[i];
      for (j=0; j<indent; j++) fprintf(iounit," ");
      fprintf(iounit,"#%-2d in rule %s (line %d %s) to rule %s\n",
            i,rrn->rname,rrn->line,FileStr[rrn->file],rrn->text);
    };
    lastOne=MR_ruleReferenced(rrn);
    if (lastOne != NULL) {
      for (j=0; j<indent; j++) fprintf(iounit," ");
      fprintf(iounit,"#%-2d in rule %s (line %d %s)\n",
        count,lastOne->rname,lastOne->line,FileStr[lastOne->file]);
    };
}

#ifdef __USE_PROTOS
void MR_dumpTreeF(FILE *f,int depth,Tree *tree,int across)
#else
void MR_dumpTreeF(f,depth,tree,across)
  FILE  *f;
  Tree  *tree;
  int   depth;
  int   across;
#endif
{
    int     newAcross=across;

	if (tree == NULL ) return;
	if (tree->down != NULL ) {
      fprintf(output,"\n");
      MR_outputIndent(depth);
      fprintf(output, "(root =");
    };
	if (tree->token == ALT ) {
      fprintf(output," %-16s","Alt");
	} else if (tree->token==EpToken ) {
      fprintf(output,"(%d)%13s",tree->v.rk," ");
	} else {
      fprintf(output," %-16s",TerminalString(tree->token));
    };
    if (tree->down != NULL) {
      fprintf(output,"\n");
      MR_outputIndent(depth+1);
      MR_dumpTreeF(f,depth+1,tree->down,1);
      newAcross=0;
      fprintf(output,"\n");
      MR_outputIndent(depth);
      fprintf(output,")");
    };
    if (newAcross > 3) {
      fprintf(output,"\n");
      MR_outputIndent(depth);
      newAcross=0;
    };
    MR_dumpTreeF(f,depth,tree->right,newAcross+1);
}

#ifdef __USE_PROTOS
void MR_dumpTreeX(int depth,Tree *tree,int across)
#else
void MR_dumpTreeX(depth,tree,across)
  Tree  *tree;
  int   depth;
  int   across;
#endif
{
  MR_dumpTreeF(output,depth,tree,across);
}

#ifdef __USE_PROTOS
void MR_dumpTokenSet(FILE *f,int depth,set s)
#else
void MR_dumpTokenSet(f,depth,s)
  FILE  *f;
  int   depth;
  set   s;
#endif
{
    int     i;
    int     j;

    unsigned  *pdq;

    if (set_nil(s)) {
      fprintf(f,"\n");
      MR_xxxIndent(f,depth+1);
      fprintf(f,"nil\n");
      return;
    };

    pdq=set_pdq(s);
    require(pdq != NULL,"set_pdq failed");
    i=0;
    for (i=0 ; ; i=i+4) {
      fprintf(f,"\n");
      MR_xxxIndent(f,depth+1);
      for (j=0; j < 4 ; j++) {
        if (pdq[i+j] == nil) break;
        fprintf(f," %-16s",TerminalString(pdq[i+j]));
      };
      if (pdq[i+j] == nil) break;
    };
    fprintf(f,"\n");
    free( (char *) pdq);
}

#ifdef __USE_PROTOS
void MR_dumpPred1(int depth,Predicate *p,int withContext)
#else
void MR_dumpPred1(depth,p,withContext)
  int           depth;
  Predicate     *p;
  int           withContext;
#endif
{
  unsigned      k;

  if (p == NULL) {
    MR_outputIndent(depth);
    fprintf(output,"The predicate is empty (or always true)\n\n");
    return;
  };
  if (p->down != NULL) {
    MR_outputIndent(depth);
    if (p->inverted) {

        /* MR14a Left out print expression in fprintf
                 Reported by Manuel Kessler (mlkessle@cip.physik.uni-wuerzburg.de)
        */

      if (p->expr == PRED_AND_LIST) fprintf(output,"%s NAND (not AND) expr\n\n",p->expr);
      if (p->expr == PRED_OR_LIST) fprintf(output,"%s NOR (not OR) expr\n\n",p->expr);
    } else {
      fprintf(output,"%s expr\n\n",p->expr);
    };
  } else {
    MR_outputIndent(depth);
    fprintf(output,"pred %s <<%s>>?\n",
            (p->inverted ? " *not*" : ""),
            (p->expr == NULL ? "null expr" : p->expr));
    MR_outputIndent(depth+1);
    fprintf(output,"              ");
    fprintf(output,"  depth=k=%d",p->k);
    if (p->source != NULL && p->source->guardpred) {
      fprintf(output,"  (\"=>\" guard)");
    }
    if (p->source != NULL && p->source->ampersandPred != NULL) {
      fprintf(output,"  (\"&&\" guard)");
    };
    k=set_int(p->completionSet);
    if (k != nil) {
      fprintf(output," Incomplete Set at k=%d !",k);
    };
    k=set_int(p->completionTree);
    if (k != nil) {
      fprintf(output," Incomplete Tree at k=%d !",k);
    };
    if (p->source != NULL) {
      fprintf(output,"  rule %s  line %d  %s",
                    p->source->rname,p->source->line,FileStr[p->source->file]);
    };
    fprintf(output,"\n");
    if (withContext &&
            (HoistPredicateContext ||
             ! set_nil(p->scontext[1]) ||
             p->tcontext != NULL)) {
      if (p->k == 1) {
        MR_outputIndent(depth+1);
        fprintf(output,"set context: ");
        MR_dumpTokenSet(output,depth+1,p->scontext[1]);
      }
      if (p->k != 1) {
        MR_outputIndent(depth+1);
        fprintf(output,"tree context:");
        if (p->tcontext == NULL) {
          fprintf(output," null");
        } else {
          MR_dumpTreeX(depth+2,p->tcontext,0);
        };
        fprintf(output,"\n");
      };
    };
    fprintf(output,"\n");
  };
  if (p->down != NULL) {
    MR_dumpPred1(depth+1,p->down,withContext);
  };
  if (p->right != NULL) {
    MR_dumpPred1(depth,p->right,withContext);
  };
}

#ifdef __USE_PROTOS
void MR_dumpPred(Predicate *p,int withContext)
#else
void MR_dumpPred(p,withContext)
  Predicate     *p;
  int           withContext;
#endif
{
  MR_dumpPred1(0,p,withContext);
}

#ifdef __USE_PROTOS
Tree * MR_make_tree_from_set(set s)
#else
Tree * MR_make_tree_from_set(s)
  set   s;
#endif
{
  Tree  *t=NULL;
  Tree  *node;
  Tree  **tp=&t;
  int   i;

  unsigned *pdq=set_pdq(s);

  if (pdq != NULL) {
    for (i=0 ; pdq[i] != nil ; i++) {
      node=tnode( (int) pdq[i]);
      *tp=node;
      tp=&(node->right);
    };
    *tp=NULL;
    free ( (char *) pdq);
  };
  return t;
}

#ifdef __USE_PROTOS
void MR_check_pred_too_long(Predicate *p,set completion)
#else
void MR_check_pred_too_long(p,completion)
  Predicate     *p;
  set           completion;
#endif
{
  if (p != NULL &&
      p->source != NULL &&
      ! p->source->predTooLong) {
    if ( !set_nil(completion)) {
      p->source->predTooLong=1;
warnFL("It is unusual (but ok) for a semantic predicate to test context past the end of its own rule",
                                FileStr[p->source->file],p->source->line);
    };
  };
}

#ifdef __USE_PROTOS
int MR_predicate_context_completed(Predicate *p)
#else
int MR_predicate_context_completed(p)
  Predicate     *p;
#endif
{
  if (p == NULL) return 1;
  if (p->expr != PRED_AND_LIST &&
      p->expr != PRED_OR_LIST) {
    if ( ! set_nil(p->completionSet)) return 0;
    if ( ! set_nil(p->completionTree)) return 0;
  };
  return MR_predicate_context_completed(p->down) &
         MR_predicate_context_completed(p->right);
}

#ifdef __USE_PROTOS
Node * MR_advance(Node *n)
#else
Node * MR_advance(n)
  Node  *n;
#endif
{
    if (n == NULL) return NULL;
    switch (n->ntype) {
      case nJunction:   return ((Junction *)n)->p1;
      case nToken:      return ((TokNode *)n)->next;
      case nRuleRef:    return ((RuleRefNode *)n)->next;
      case nAction:     return ((ActionNode *)n)->next;
      default:          return NULL;
    };
  return NULL; /* MSVC 5.0 complains about missing return statement */
}

#ifdef __USE_PROTOS
Junction * MR_find_endRule(Node *n)
#else
Junction * MR_find_endRule(n)
  Node  *n;
#endif
{
    Node    *next;
    if (n == NULL) return NULL;
    for (next=n; next != NULL; next=MR_advance(next)) {
      if (next->ntype == nJunction &&
            ( (Junction *) next)->jtype == EndRule) {
        break;
      };
    };
    return (Junction *)next;
}

/*
   Intersection:  a branch which is shorter is chosen
   over one which is longer: (A B C) intersect (A B) yields (A B).

   AND: a branch which is longer is chosen over the one
   which is shorter: (A B C) AND (A B) yields (A B C)

*/

#ifdef __USE_PROTOS
Tree *MR_computeTreeIntersection(Tree *l,Tree *r)
#else
Tree *MR_computeTreeIntersection(l,r)
    Tree    *l;
    Tree    *r;
#endif
{
    Tree    *result=NULL;
    Tree    **tail;
    Tree    *p;
    Tree    *q;
    Tree    *match;

    if (l == NULL || r == NULL) return NULL;
    for (p=l; p != NULL; p=p->right) {
      require(p->token != EpToken,"MR_computeTreeIntersection: p->EpToken unexpected\n");
      require (p->token != ALT,"MR_computeTreeIntersection: p->ALT unexpected\n");
    };
    for (q=r; q != NULL; q=q->right) {
      require(q->token != EpToken,"MR_computeTreeIntersection: q->EpToken unexpected\n");
      require(q->token != ALT,"MR_computeTreeIntersection: q->ALT unexpected\n");
    };

    result=tnode(ALT);
    tail=&(result->down);

    for (p=l; p != NULL ; p=p->right) {
      for (q=r; q != NULL ; q=q->right) {
        if (p->token == q->token) {
          match=tnode(p->token);
          match->down=MR_computeTreeIntersection(p->down,q->down);
          *tail=match;
          tail=&(match->right);
        };
      };
    };

    *tail=NULL;
    result=tshrink(result);
    result=tflatten( result );
    result=tleft_factor( result );
    return result;
}

/* the predicates which are ANDed together have a common
   context:  they must all have common roots.  Thus the
   AND operation is more like an OR operation because
   branches which are longer are grafted onto shorter
   branches of the AND tree.  For instance combining
   (A B C) with (A B C D) gives (A B C D).  There
   should never be a case of (A B C) and (A B D) because
   they have the same context.

   Actually, this may not be true once one throws in
   guard predicates which are defined by the user, not
   the context.
*/

/* requires input trees to be in "canonical" format */

#ifdef __USE_PROTOS
Tree *MR_computeTreeAND(Tree *l,Tree *r)
#else
Tree *MR_computeTreeAND(l,r)
    Tree    *l;
    Tree    *r;
#endif
{
    Tree    *result=NULL;
    Tree    **tail;
    Tree    *p;
    Tree    *q;
    Tree    *match;

    if (l == NULL) return tdup(r);
    if (r == NULL) return tdup(l);

    for (p=l; p != NULL; p=p->right) {
/**** require(p->token != EpToken,"MR_computeTreeAND: p->EpToken unexpected\n"); ****/
      require (p->token != ALT,"MR_computeTreeAND: p->ALT unexpected\n");
    };
    for (q=r; q != NULL; q=q->right) {
/**** require(q->token != EpToken,"MR_computeTreeAND: q->EpToken unexpected\n"); ****/
      require(q->token != ALT,"MR_computeTreeAND: q->ALT unexpected\n");
    };

    result=tnode(ALT);
    tail=&(result->down);

    for (p=l; p != NULL ; p=p->right) {
      for (q=r; q != NULL ; q=q->right) {
        if (p->token == q->token) {
          match=tnode(p->token);
          match->down=MR_computeTreeAND(p->down,q->down);
          *tail=match;
          tail=&(match->right);
        };
      };
    };

    *tail=NULL;
    result=tshrink(result);
    result=tflatten( result );
    result=tleft_factor( result );
    return result;
}

#ifdef __USE_PROTOS
void MR_union_plain_sets1(Predicate *p,set *theUnion)
#else
void MR_union_plain_sets1(p,theUnion)
  Predicate     *p;
  set           *theUnion;
#endif
{
  if (p == NULL) return;
  MR_union_plain_sets1(p->down,theUnion);
  MR_union_plain_sets1(p->right,theUnion);
  set_orin(theUnion,p->plainSet);
  return;
}

#ifdef __USE_PROTOS
set MR_union_plain_sets(Predicate *p)
#else
set MR_union_plain_sets(p)
  Predicate     *p;
#endif
{
  set   theUnion;

  theUnion=empty;

  MR_union_plain_sets1(p,&theUnion);
  return theUnion;
}

/* does NOT left factor: do not want to merge
     (A B) with (A) to get (A B)
   in fact the opposite: (A B) with (A) gives (A)
*/

#ifdef __USE_PROTOS
Tree *MR_compute_pred_tree_ctxXX(Predicate *p)
#else
Tree *MR_compute_pred_tree_ctxXX(p)
  Predicate     *p;
#endif
{
    Tree        *result=NULL;
    Predicate   *q;
    Tree        *t;

    if (p == NULL) return NULL;

/* this appears strange: why do we OR the context
   of and AND predicate ?  It is because of the way
   that predicates are evaluated: if the context is
   wrong then it's the same as if the predicate was
   true.  That means that even when one leg of an
   AND has unmatched context, if the other leg has
   matched context and is true then the predicate
   succeeds.  It's only when all the legs have unmatched
   context that this one can skip evaluation of the
   predicates.
*/
    if (p->expr == PRED_OR_LIST ||
        p->expr == PRED_AND_LIST) {
      for (q=p->down; q != NULL ; q=q->right) {
        t=MR_compute_pred_tree_ctxXX(q);
        result=tappend(result,t);
        t=NULL;
      };

      result=tshrink(result);
      result=tflatten( result );

/* does NOT left factor: do not want to merge
     (A B) with (A) to get (A B)
   in fact the opposite: (A B) with (A) gives (A)
*/

/**** result=tleft_factor( result ); ****/
      return result;
    };

#if 0
**    if (p->expr == PRED_AND_LIST) {
**
**      Predicate     *l;
**      Predicate     *r;
**      Tree          *l1;
**      Tree          *r1;
**      Tree          *prevl1;
**
**      l=p->down;
**      require (l->right != NULL,"MR_compute_pred_tree - AND has only one child");
**
**/* l1 and r1 should already be in "canonical" format */
**
**      l1=MR_compute_pred_tree(l);
**      for (r=l->right; r != NULL; r=r->right) {
**        r1=MR_compute_pred_tree(r);
**        prevl1=l1;
**        l1=MR_computeTreeAND(l1,r1);
**        Tfree(r1);
**        Tfree(prevl1);
**      };
**
**/* result from computeTreeAND should be in "canonical" format */
**
**      result=l1;
**
**/* result of MR_computeTreeAND should be in "canonical" format */
**
**      return result;
**    };
#endif

    if (p->k == 1) {
      result=MR_make_tree_from_set(p->scontext[1]);
    } else {
      result=tdup(p->tcontext);
      result=MR_remove_epsilon_from_tree(result);
      result=tshrink(result);
      result=tflatten(result);
      result=tleft_factor(result);
    };
    return result;
}

#ifdef __USE_PROTOS
void MR_pred_depth(Predicate *p,int *maxDepth)
#else
void MR_pred_depth(p,maxDepth)
  Predicate     *p;
  int           *maxDepth;
#endif
{
  if (p == NULL) return;
  if (p->expr != PRED_OR_LIST &&
      p->expr != PRED_AND_LIST) {
    if (p->k > *maxDepth) *maxDepth=p->k;
  };
  MR_pred_depth(p->down,maxDepth);
  MR_pred_depth(p->right,maxDepth);
}

/* this computes the OR of all the contexts */

#ifdef __USE_PROTOS
set MR_compute_pred_set(Predicate *p)
#else
set MR_compute_pred_set(p)
  Predicate     *p;
#endif
{
    set         result;
    Predicate   *q;

    result=empty;

    if (p == NULL) return empty;

    if (p->expr == PRED_OR_LIST ||
        p->expr == PRED_AND_LIST) {         /* yes, I do mean PRED_AND_LIST !   */
                                            /* remember: r1: (A)? => <<p>>? r2; */
                                            /*           r2: (B)? => <<q>>? r3; */
      set   t;

      t=empty;
      result=empty;

      for (q=p->down; q != NULL; q=q->right) {
        t=MR_compute_pred_set(q);
        set_orin(&result,t);
        set_free(t);
      };
      return result;
    } else if (p->k > 1) {
      return empty;
    } else {
      return set_dup(p->scontext[1]);
    };
}

#ifdef __USE_PROTOS
set MR_First(int ck,Junction *j,set *incomplete)
#else
set MR_First(ck,j,incomplete)
  int       ck;
  Junction  *j;
  set       *incomplete;
#endif
{
    Junction    *p;
    set         tokensUsed;

    tokensUsed=empty;

	require(j->ntype==nJunction, "MR_First: non junction passed");

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

	REACH(p,ck,incomplete,tokensUsed);

    return tokensUsed;
}

#ifdef __USE_PROTOS
void MR_cleanup_pred_trees(Predicate *p)
#else
void MR_cleanup_pred_trees(p)
  Predicate     *p;
#endif
{
  Tree      *t;

  if (p == NULL) return;
  if (p->expr != PRED_OR_LIST &&
      p->expr != PRED_AND_LIST) {
    t=p->tcontext;
    t=tshrink(t);
    t=tflatten(t);
    t=tleft_factor(t);
    p->tcontext=t;
  };
  MR_cleanup_pred_trees(p->down);
  MR_cleanup_pred_trees(p->right);
}

/* does NOT return canonical tree */

#ifdef __USE_PROTOS
Tree * MR_remove_epsilon_from_tree(Tree *t)
#else
Tree * MR_remove_epsilon_from_tree(t)
  Tree  *t;
#endif
{
  if (t == NULL) return NULL;

  /* I think ALT can be ignored as a special case */

  if (t->token != EpToken) {
    t->down=MR_remove_epsilon_from_tree(t->down);
    t->right=MR_remove_epsilon_from_tree(t->right);
    return t;
  } else {
    Tree    *u;
    u=MR_remove_epsilon_from_tree(t->right);
    t->right=NULL;
    Tfree(t);
    return u;
  };
}

#ifdef __USE_PROTOS
void MR_complete_set(int predDepth,set *tokensUsed,set *incomplete)
#else
void MR_complete_set(predDepth,tokensUsed,incomplete)
  int       predDepth;
  set       *tokensUsed;
  set       *incomplete;
#endif
{
    int             i;
    RuleRefNode     *ruleRef;
	set             rk2;
    set             b;
	int             k2;
    Junction        *save_MR_RuleBlkWithHalt;

    if (set_int(*incomplete) > (unsigned) predDepth) {
      return;
    };

    require(MR_PredRuleRefStack.count == MR_RuleBlkWithHaltStack.count,
                "RuleRefStack and RuleBlkWithHaltStack not same size");

    require(MR_RuleBlkWithHalt == NULL ||
         (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE),
                     "RuleBlkWithHalt has no halt set");

    save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt;

    if (MR_RuleBlkWithHalt != NULL) {
      MR_RuleBlkWithHalt->end->halt=FALSE;
    };

    for (i=MR_PredRuleRefStack.count-1; i >= 0 ; i--) {
      ruleRef=(RuleRefNode *)MR_PredRuleRefStack.data[i];
      if (ruleRef == NULL) continue;

      MR_RuleBlkWithHalt=(Junction *)MR_RuleBlkWithHaltStack.data[i];
      if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=TRUE;

      rk2=empty;
      b=empty;

      while ( !set_nil(*incomplete) ) {
		k2=set_int(*incomplete);
        if (k2 > predDepth) break;                    /* <=== another exit from loop */
		set_rm(k2,*incomplete);
        REACH(ruleRef->next,k2,&rk2,b);
		set_orin(tokensUsed,b);
		set_free(b);
      };

      if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=FALSE;

	  set_orin(incomplete,rk2);                       /* remember what we couldn't do */
      set_free(rk2);
	  if (set_int(*incomplete) > (unsigned) predDepth) break;    /* <=== another exit from loop */
    };

    MR_RuleBlkWithHalt=save_MR_RuleBlkWithHalt;
    if (MR_RuleBlkWithHalt != NULL) {
      MR_RuleBlkWithHalt->end->halt=TRUE;
    };
}

#ifdef __USE_PROTOS
void MR_complete_tree(int predDepth,Tree **t,set *incomplete)
#else
void MR_complete_tree(predDepth,t,incomplete)
  int       predDepth;
  Tree      **t;
  set       *incomplete;
#endif
{
    int             i;
    RuleRefNode     *ruleRef;
	set             rk2;
    Tree            *u;
	unsigned        k2;
    Junction        *save_MR_RuleBlkWithHalt;
    int             saveConstrainSearch;

    if (set_int(*incomplete) > (unsigned) predDepth) {
      return;
    };

    require(MR_PredRuleRefStack.count == MR_RuleBlkWithHaltStack.count,
                "RuleRefStack and RuleBlkWithHaltStack not same size");

    require(MR_RuleBlkWithHalt == NULL ||
         (MR_RuleBlkWithHalt->jtype == RuleBlk && MR_RuleBlkWithHalt->end->halt == TRUE),
                     "RuleBlkWithHalt has no halt set");

    save_MR_RuleBlkWithHalt=MR_RuleBlkWithHalt;
    saveConstrainSearch=ConstrainSearch;
    ConstrainSearch=0;

    if (MR_RuleBlkWithHalt != NULL) {
      MR_RuleBlkWithHalt->end->halt=FALSE;
    };

    for (i=MR_PredRuleRefStack.count-1; i >= 0 ; i--) {
      ruleRef=(RuleRefNode *)MR_PredRuleRefStack.data[i];
      if (ruleRef == NULL) continue;

      MR_RuleBlkWithHalt=(Junction *)MR_RuleBlkWithHaltStack.data[i];

      if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=TRUE;

      rk2=empty;

      while ( !set_nil(*incomplete) ) {	
		k2 = set_int(*incomplete);
        if (k2 > (unsigned) predDepth) break;       /* <=== another exit from loop */
		set_rm(k2,*incomplete);
		u = NULL;

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

			/* any subtrees missing k2 tokens, add u onto end */

		*t=tlink(*t,u,k2);
        Tfree(u);
      }

	  set_orin(incomplete,rk2);         /* remember what we couldn't do */
      set_free(rk2);

      if (MR_RuleBlkWithHalt != NULL) MR_RuleBlkWithHalt->end->halt=FALSE;

	  if (set_int(*incomplete) > (unsigned) predDepth) break;    /* <=== another exit from loop */
    };

    MR_RuleBlkWithHalt=save_MR_RuleBlkWithHalt;

    if (MR_RuleBlkWithHalt != NULL) {
      MR_RuleBlkWithHalt->end->halt=TRUE;
    };
    ConstrainSearch=saveConstrainSearch;
}

#ifdef __USE_PROTOS
void MR_complete_predicates(int predDepth,Predicate *pred)
#else
void MR_complete_predicates(predDepth,pred)
  int           predDepth;
  Predicate     *pred;
#endif
{
  if (pred == NULL) return;
  if (pred->expr != PRED_AND_LIST &&
      pred->expr != PRED_OR_LIST) {
    MR_complete_set(predDepth,&(pred->scontext[1]),&(pred->completionSet));
    MR_complete_tree(predDepth,&(pred->tcontext),&(pred->completionTree));
  };
  MR_complete_predicates(predDepth,pred->down);
  MR_complete_predicates(predDepth,pred->right);
}

#ifdef __USE_PROTOS
Junction * MR_junctionWithoutP2(Junction *j)
#else
Junction * MR_junctionWithoutP2(j)
  Junction  *j;
#endif
{
  Junction  *thisAlt;

/* don't want to follow p2 to the next alternative of this rule */
/* insert a generic node with null p2 if necessary              */
/* however FIRST requires a junction                            */

  thisAlt=j;
  if (thisAlt->p2 != NULL) {
    if (thisAlt->p1->ntype == nJunction) {
      thisAlt=(Junction *) thisAlt->p1;
    } else {
      thisAlt=newJunction();
      thisAlt->p1=j->p1;
      thisAlt->rname=j->rname;
      thisAlt->file=j->file;
      thisAlt->line=j->line;
      j->p1=(Node *)thisAlt;
    };
  };
  return thisAlt;
}

#ifdef __USE_PROTOS
int MR_tree_equ(Tree *big, Tree *small) {
#else
int MR_tree_equ(big,small)
  Tree  *big;
  Tree  *small;
{
#endif

  Tree      *b;
  Tree      *s;
  int       bcount=0;
  int       scount=0;

  if (small == NULL && big == NULL) return 1;
  if (small == NULL) return 0;
  if (big == NULL) return 0;

  if (small->token == ALT) {
    require(small->right == NULL,
                "MR_tree_equ: small: ALT node has siblings");
    return MR_tree_equ(big,small->down);
  };
  if (big->token == ALT) {
    require(big->right == NULL,
                "MR_tree_equ: big: ALT node has siblings");
    return MR_tree_equ(big->down,small);
  };
  for (s=small; s != NULL; s=s->right) {
    scount++;
    require(s->token != EpToken,"MR_tree_equ: s->EpToken unexpected\n");
  };
  for (b=big; b != NULL; b=b->right) {
    bcount++;
    require(b->token != EpToken,"MR_tree_equ: b->EpToken unexpected\n");
  };

  if (bcount != scount) return 0;

  for (s=small; s != NULL; s=s->right) {
    for (b=big; b!= NULL; b=b->right) {
      if (s->token == b->token) {
        if (MR_tree_equ(b->down,s->down)) goto next_s;
      };
    };
    return 0;
next_s:
    continue;
  };
  return 1;
}

/* this does not compare sources - only contexts ! */

#ifdef __USE_PROTOS
int MR_identicalContext(Predicate *p,Predicate *q)
#else
int MR_identicalContext(p,q)
  Predicate     *p;
  Predicate     *q;
#endif
{
  if (p->k != q->k) return 0;
  require ( (p->tcontext == NULL) == (q->tcontext == NULL),
        "tcontext inconsistent");
  if (p->k == 1) {
    return set_equ(p->scontext[1],q->scontext[1]);
  } else {
    return MR_tree_equ(p->tcontext,q->tcontext);
  };
}

#ifdef __USE_PROTOS
void MR_reportSetSuppression(int predDepth,
            set predSet,set plainSet,Junction *jPred,Junction *jPlain,Predicate *p)
#else
void MR_reportSetSuppression(predDepth,predSet,plainSet,jPred,jPlain,p)
  int       predDepth;
  set       predSet;
  set       plainSet;
  Junction  *jPred;
  Junction  *jPlain;
  Predicate *p;
#endif
{
  if (InfoP) {
    fprintf(output,"\n#if 0\n\n");
    fprintf(output,"Hoisting of predicate suppressed by alternative without predicate.\n");
    fprintf(output,"The alt without the predicate includes all cases where the predicate is false.\n\n");
    fprintf(output,"   WITH predicate: line %d  %s\n",jPred->line,FileStr[jPred->file]);
    if (jPlain != NULL) {
      fprintf(output,"   WITHOUT predicate: line %d  %s\n",jPlain->line,FileStr[jPlain->file]);
    } else {
      fprintf(output,"   WITHOUT predicate: all alternatives without predicates (combined)\n");
    };
    if (predDepth == 1) {
      fprintf(output,"\nThe context set for the predicate:\n");
      MR_dumpTokenSet(output,1,predSet);
    };
    fprintf(output,"\nThe lookahead set for the alt WITHOUT the semantic predicate:\n");
    MR_dumpTokenSet(output,1,plainSet);
    fprintf(output,"\nThe predicate:\n\n");
    MR_dumpPred1(1,p,1);
    fprintf(output,"Chain of referenced rules:\n\n");
    MR_dumpPredRuleRefStack(output,4);
    fprintf(output,"\n#endif\n");
  };
}

#ifdef __USE_PROTOS
void MR_reportSetRestriction(int predDepth,set predSet,set plainSet,
            Junction *jPred,Junction *jPlain,Predicate *origPred,Predicate *newPred)
#else
void MR_reportSetRestriction(predDepth,predSet,plainSet,jPred,jPlain,origPred,newPred)
  int       predDepth;
  set       predSet;
  set       plainSet;
  Junction  *jPred;
  Junction  *jPlain;
  Predicate *origPred;
  Predicate *newPred;
#endif
{
  set       intersect;

  intersect=empty;

  if (! InfoP) return;
  fprintf(output,"\n#if 0\n\n");
  fprintf(output,"Restricting the context of a predicate because of overlap in the lookahead set\n");
  fprintf(output,"  between the alternative with the semantic predicate and one without\n");
  fprintf(output,"Without this restriction the alternative without the predicate could not\n");
  fprintf(output,"  be reached when input matched the context of the predicate and the predicate\n");
  fprintf(output,"  was false.\n\n");

  fprintf(output,"   WITH predicate: line %d  %s\n",jPred->line,FileStr[jPred->file]);
  if (jPlain != NULL) {
    fprintf(output,"   WITHOUT predicate: line %d  %s\n",jPlain->line,FileStr[jPlain->file]);
  } else {
    fprintf(output,"   WITHOUT predicate: all alternatives without predicates (combined)\n");
  };
  if (predDepth == 1) {
    fprintf(output,"\nThe original context set for the predicate:\n");
    MR_dumpTokenSet(output,1,predSet);
  };
  fprintf(output,"\nThe lookahead set for the alt WITHOUT the semantic predicate:\n");
  MR_dumpTokenSet(output,1,plainSet);
  if (predDepth == 1) {
    fprintf(output,"\nThe intersection of the two sets\n");
    intersect=set_and(predSet,plainSet);
    MR_dumpTokenSet(output,1,intersect);
    set_free(intersect);
  };
  fprintf(output,"\nThe original predicate:\n\n");
  MR_dumpPred1(1,origPred,1);
  fprintf(output,"The new (modified) form of the predicate:\n\n");
  MR_dumpPred1(1,newPred,1);
  fprintf(output,"#endif\n");
}

/* don't use Pass3 by itself unless you know that inverted is not important */

#ifdef __USE_PROTOS
Predicate * MR_removeRedundantPredPass3(Predicate *p)
#else
Predicate * MR_removeRedundantPredPass3(p)
  Predicate *p;
#endif
{
  Predicate     *q;

  if (p == NULL) return NULL;
  p->right=MR_removeRedundantPredPass3(p->right);
  p->down=MR_removeRedundantPredPass3(p->down);
  if (p->redundant) {
    q=p->right;
    p->right=NULL;
    predicate_free(p);
    return q;
  };
  if (p->expr == PRED_AND_LIST ||
      p->expr == PRED_OR_LIST) {
    if (p->down == NULL) {
      q=p->right;
      p->right=NULL;
      predicate_free(p);
      return q;
    };
    if (p->down != NULL && p->down->right == NULL) {
      q=p->down;
      q->right=p->right;
      p->right=NULL;
      p->down=NULL;
      return q;
    };
  };
  return p;
}

#ifdef __USE_PROTOS
void MR_removeRedundantPredPass2(Predicate *p)
#else
void MR_removeRedundantPredPass2(p)
  Predicate *p;
#endif
{
  Predicate     *q;

  if (p == NULL) return;

  if (p->expr == PRED_AND_LIST) {
    for (q=p->down ; q != NULL ; q=q->right) {
      MR_removeRedundantPredPass2(q);
      if (q->isConst) {
        if (q->constValue == 0) {
          p->isConst=1;
          p->constValue=0;
          return;
        } else {
          q->redundant=1;
        };
      };
    };
  };

  if (p->expr == PRED_OR_LIST) {
    for (q=p->down ; q != NULL ; q=q->right) {
      MR_removeRedundantPredPass2(q);
      if (q->isConst) {
        if (q->constValue == 0) {
          q->redundant=1;
        } else {
          p->isConst=1;
          p->constValue=1;
          return;
        };
      };
    };
  };

  return;
}

#if 0
   this totally ignores the implications of guarded predicates
     in which the part after the guard could possibly cover a predicate.
   that would be much harder:

        rule : (A)? => <<p>>? sub1;     /* 1 */
             | (B)? => <<r>>? sub2      /* 2 */
        sub1 : (A)? => <<q>>? A B       /* 3 */
             | B                        /* 4 - suppresses line 2 */
             ;
#endif

#ifdef __USE_PROTOS
void MR_apply_restriction1(Predicate *pred,set *plainSet,int *changed)
#else
void MR_apply_restriction1(pred,plainSet,changed)
  Predicate     *pred;
  set           *plainSet;
  int           *changed;
#endif
{
  if (pred == NULL) return;
  MR_apply_restriction1(pred->right,plainSet,changed);
  if (pred->down != NULL) {
    MR_apply_restriction1(pred->down,plainSet,changed);
  } else {
    set     t;
    if (pred->k == 1) {
      t=set_dif(pred->scontext[1],*plainSet);
      if (*changed == 0 &&
          !set_equ(t,pred->scontext[1])) {
        *changed=1;
      };
      if (set_nil(t)) {
        pred->redundant=1;
      };
      set_free(pred->scontext[1]);
      pred->scontext[1]=t;
    };
  };
}

#ifdef __USE_PROTOS
void MR_orin_plainSet(Predicate *p,set plainSet)
#else
void MR_orin_plainSet(p,plainSet)
  Predicate     *p;
  set           plainSet;
#endif
{
  if (p == NULL) return;
  MR_orin_plainSet(p->down,plainSet);
  MR_orin_plainSet(p->right,plainSet);
  set_orin(&p->plainSet,plainSet);
}

Predicate   *PRED_SUPPRESS;

#ifdef __USE_PROTOS
Predicate * MR_find_in_aSubBlk(Junction *alt)
#else
Predicate * MR_find_in_aSubBlk(alt)
  Junction  *alt;
#endif
{
    Predicate       *root=NULL;
    Predicate       **tail=NULL;

	Junction        *p;

    int             nAlts=0;
    Junction        **jList;
    Predicate       **predList;
    int             *matchList;
    set             predSet;
    int             i;
    int             j;
    int             m;
    int             predDepth;
    set             incomplete;
    set             union_plainSet;
    set             setChange;
    int             changed;
    Predicate       *newPred;
    set             setDif;
    Predicate       *origPred;
    int             depth1=1;             /* const int */
    set             *plainContext;
    set             plainSet;

    predSet=empty;
    incomplete=empty;
    union_plainSet=empty;
    setChange=empty;
    setDif=empty;
    plainSet=empty;

    if (PRED_SUPPRESS == NULL) {
      PRED_SUPPRESS=new_pred();
      PRED_SUPPRESS->expr="Predicate Suppressed";
    };

    /* this section just counts the number of "interesting" alternatives  */
    /*   in order to allocate arrays                                      */

	for (p=alt; p!=NULL; p=(Junction *)p->p2) {
	  /* ignore empty alts */
	  if ( p->p1->ntype != nJunction ||
	        ((Junction *)p->p1)->jtype != EndBlk )	{
        nAlts++;
      };
    };

    /* if this is a (...)+ block then don't count the last alt because
       it can't be taken until at least one time through the block.
       In other words it isn't a real choice until the (...)+ is entered
         at which point the hoisting issue is moot.
       Maybe look at "ignore" instead ?
    */

    if (alt->jtype == aPlusBlk) {
      nAlts--;
    };

    jList=(Junction **)calloc(nAlts,sizeof(Junction *));
    require(jList!=NULL,"cannot allocate MR_find_in_aSubBlk jList");

    plainContext=(set *)calloc(nAlts,sizeof(set));
    require(plainContext!=NULL,"cannot allocate MR_find_in_aSubBlk plainContext");
    for (m=0; m < nAlts; m++) plainContext[m]=empty;

    predList=(Predicate **)calloc(nAlts,sizeof(Predicate *));
    require(predList!=NULL,"cannot allocate MR_find_in_aSubBlk predList");

    matchList=(int *)calloc(nAlts,sizeof(int));
    require(matchList!=NULL,"cannot allocate MR_find_in_aSubBlk matchList");

    /* this section just fills in the arrays previously allocated       */
    /* the most interesting one is matchList[]                          */
    /*                                                                  */
    /*   bit 0 => this alt has a semantic pred which is "covered"       */
    /*              by an alt without a semantic pred.  Don't hoist.    */

	for (i=0,p=alt;
         p!=NULL && i<nAlts;
         i++,p=(Junction *)p->p2) {

	  /* ignore empty alts */

	  if ( p->p1->ntype != nJunction ||
	        ((Junction *)p->p1)->jtype != EndBlk )	{
        jList[i]=MR_junctionWithoutP2(p);
        predList[i]=find_predicates(p->p1);      /* should be jList ????? */
        if (predList[i] != NULL) {
          MR_cleanup_pred_trees(predList[i]);    /* flatten & left factor */
          plainContext[i]=MR_union_plain_sets(predList[i]);
        } else {
          MR_set_reuse(&plainSet);
          MR_set_reuse(&incomplete);
          plainSet=MR_First(depth1,jList[i],&incomplete);
          MR_complete_set(depth1,&plainSet,&incomplete);
          require(set_nil(incomplete),"couldn't complete k=1");
          plainContext[i]=plainSet;
          plainSet=empty;
        };
        set_orin(&union_plainSet,plainContext[i]);
      };
    };

    if (nAlts == 1) {
      goto EXIT_SIMPLE;
    };

/*
 *  Looking for cases where alt i has a semantic pred and alt j does not.
 *  Don't care about cases where lookahead for semantic predicates overlap
 *    because normal predicate hoisting does the correct thing automatically.
 *  Don't care about cases where lookahead for alts without semantic predicates
 *    overlap because normal prediction does the correct thing automatically.
 *
 *  When we find such a case check for one of three subcases:
 *
 *      1.  if lookahead for alt i is contained in the lookahead for any
 *          alt j then ignore semantic predicate of alt i
 *      2.  if lookahead for alt i is not contained in the lookahead for
 *          any alt j then add add predicate i to the OR list to be hoisted
 *      3.  if lookahead for alt i overlaps the lookahead for some alt j then
 *          add a dummy semantic predicate for alt j
 *
 *  There is an implicit assumption that the context of all alternatives following
 *  the rule being processed here are identical (but may vary from hoist to
 *  hoist depending on the place where the rule was invoked that led to hoisting
 *  these predicates.  In othere words in the fragment:
 *
 *            ( <<a>>? a1 a2 a3 | <<b>>? b1 b2 b3 )
 *
 *  both a3 and b3 have the same follow sets  because they are both at the end of
 *  alternatives in the same block.
 */

    for (i=0; i < nAlts; i++) {
      if (jList[i] == NULL) continue;
      if (predList[i] == NULL) continue;

        /* if the predicate depth turns out to be one token only */
        /*   then it is can be easily represented as a set and   */
        /*   compared to the junction set create by MR_First()   */

      predDepth=0;
      MR_pred_depth(predList[i],&predDepth);
      require (predDepth >= 1,"MR_find_in_aSubBlk: pred depth < 1");
      require (predDepth <= CLL_k,"MR_find_in_aSubBlk: predDepth > CLL_k");

        /* complete predicates to predDepth
           If completed to depth=1 then the context would be incomplete.
           The context would be truncated and the predicate simplify routine
             would have incomplete information.  It would lead to
             either false matches of failure to find true matches.
        */

      MR_complete_predicates(predDepth,predList[i]);

      if (predList[i] != NULL) {
        MR_cleanup_pred_trees(predList[i]);    /* flatten & left factor */
      };

      /* If the predicate depth is 1 then it is possible to suppress
           a predicate completely using a single plain alt.  Check for suppression
           by a single plain alt first because it gives better messages.  If that
           fails try the union of all the plain alts.
      */

      if (predDepth == 1) {

        MR_set_reuse(&predSet);
        predSet=MR_compute_pred_set(predList[i]);   /* ignores k>1 predicates */

        for (j=0; j < nAlts; j++) {
          if (jList[j] == NULL) continue;
          if (j == i) continue;

          MR_set_reuse(&setDif);
          setDif=set_dif(predSet,plainContext[j]);
          if (set_nil(setDif)) {
            matchList[i] |= 1;
            MR_reportSetSuppression(predDepth,predSet,plainContext[j],jList[i],jList[j],predList[i]);
            predicate_free(predList[i]);
            predList[i]=PRED_SUPPRESS;
            goto next_i;
          };

        }; /* end loop on j */

        changed=0;

        /* predicate_dup is only to give good error messages */
        /* remember to do a predicate_free()                 */

        origPred=predicate_dup(predList[i]);
        MR_apply_restriction1(predList[i],&union_plainSet,&changed);
        if (changed) {

          /* don't use Pass3 by itself unless you know that inverted is not important */

          newPred=MR_removeRedundantPredPass3(predList[i]);
          newPred=MR_predSimplifyALL(newPred);
          if (newPred == NULL) {
            matchList[i] |= 1;
            MR_reportSetSuppression(predDepth,predSet,union_plainSet,jList[i],
                                                            NULL,origPred);
            predList[i]=PRED_SUPPRESS;
          } else {
            MR_reportSetRestriction(predDepth,predSet,union_plainSet,jList[i],
                                                    NULL,origPred,newPred);
            predList[i]=newPred;
          };
        };
        predicate_free(origPred);
        origPred=NULL;
      };

      /*
         If the predicate depth is > 1 then it can't be suppressed completely
           because the code doesn't support inspection of such things.  They're
           much messier than k=1 sets.
      */

      if (predDepth > 1 ) {

        changed=0;

        /* predicate_dup is only to give good error messages */
        /* remember to do a predicate_free()                 */

        origPred=predicate_dup(predList[i]);
        MR_apply_restriction1(predList[i],&union_plainSet,&changed);
        if (changed) {
          newPred=MR_removeRedundantPredPass3(predList[i]);
          newPred=MR_predSimplifyALL(newPred);
          if (newPred == NULL) {
            matchList[i] |= 1;
            MR_reportSetSuppression(predDepth,predSet,union_plainSet,jList[i],
                                                            NULL,origPred);
            predList[i]=PRED_SUPPRESS;
          } else {
            MR_reportSetRestriction(predDepth,predSet,union_plainSet,jList[i],
                                                    NULL,origPred,newPred);
            predList[i]=newPred;
          };
        };
        predicate_free(origPred);
        origPred=NULL;
      };
next_i:
      continue;
    };

EXIT_SIMPLE:

    root = new_pred();
    root->expr=PRED_OR_LIST;
    tail = &(root->down);

    for (i=0 ; i< nAlts ; i++) {
      if (jList[i] == NULL) continue;

      if (predList[i] == NULL) {
        continue;
      } else if ( (matchList[i] & 1) != 0) {
        if (predList[i] != PRED_SUPPRESS) {
          predicate_free(predList[i]);
        };
        continue;
      };

      /* make an OR list of predicates */

      *tail=predList[i];
      tail=&(predList[i]->right);
    };

	/* if just one pred, remove OR root */

	if (root->down == NULL) {
      predicate_free(root);
      root=NULL;
    } else if (root->down->right == NULL) {
      Predicate     *p=root->down;
      root->down=NULL;
      predicate_free(root);
      root=p;
	}

    root=MR_predSimplifyALL(root);

    MR_orin_plainSet(root,union_plainSet);

    set_free(predSet);
    set_free(union_plainSet);
    set_free(incomplete);
    set_free(setChange);
    set_free(setDif);

    for (m=0; m < nAlts; m++) set_free(plainContext[m]);

    free ( (char *) jList);
    free ( (char *) predList);
    free ( (char *) matchList);
    free ( (char *) plainContext);

	return root;
}

#ifdef __USE_PROTOS
void MR_predContextPresent(Predicate *p,int *allHaveContext,int *noneHaveContext)
#else
void MR_predContextPresent(p,allHaveContext,noneHaveContext)
  Predicate     *p;
  int           *allHaveContext;
  int           *noneHaveContext;
#endif
{
  if (p == NULL) return;
  MR_predContextPresent(p->right,allHaveContext,noneHaveContext);
  if (p->expr != PRED_AND_LIST &&
      p->expr != PRED_OR_LIST) {
    if (set_nil(p->scontext[1]) == 0 ||
            (p->tcontext != NULL)) {
      *noneHaveContext=0;
    } else {
      *allHaveContext=0;
    };
  };
  MR_predContextPresent(p->down,allHaveContext,noneHaveContext);
}

#ifdef __USE_PROTOS
int MR_pointerStackPush(PointerStack *ps,void *dataPointer)
#else
int MR_pointerStackPush(ps,dataPointer)
  PointerStack  *ps;
  void          *dataPointer;
#endif
{
  void             **newStack;
  int              newSize;
  int              i;

  if (ps->count == ps->size) {
    newSize=20+ps->size*2;
    newStack=(void **)calloc(newSize,sizeof(void *));
    require (newStack != NULL,"cannot allocate PointerStack");
    for (i=0; i < ps->size; i++) {
      newStack[i]=ps->data[i];
    };
    if (ps->data != NULL) free( (char *) ps->data);
    ps->data=newStack;
    ps->size=newSize;
  };
  ps->data[ps->count]=dataPointer;
  ps->count++;
  return ps->count-1;
}

#ifdef __USE_PROTOS
void * MR_pointerStackPop(PointerStack *ps)
#else
void * MR_pointerStackPop(ps)
  PointerStack  *ps;
#endif
{
  void  *dataPointer;

  require(ps->count > 0,"MR_pointerStackPop underflow");

  dataPointer=ps->data[ps->count-1];
  ps->data[ps->count-1]=NULL;
  (ps->count)--;
  return dataPointer;
}

#ifdef __USE_PROTOS
void * MR_pointerStackTop(PointerStack *ps)
#else
void * MR_pointerStackTop(ps)
  PointerStack  *ps;
#endif
{
  require(ps->count > 0,"MR_pointerStackTop underflow");
  return ps->data[ps->count-1];
}

#ifdef __USE_PROTOS
void MR_pointerStackReset(PointerStack *ps)
#else
void MR_pointerStackReset(ps)
  PointerStack  *ps;
#endif
{
  int i;
  if (ps->data != NULL) {
    for (i=0; i < ps->count ; i++) {
       ps->data[i]=NULL;
    };
  };
  ps->count=0;
}

#ifdef __USE_PROTOS
Junction *MR_nameToRuleBlk(char *name)
#else
Junction *MR_nameToRuleBlk(name)
  char  *name;
#endif
{
    RuleEntry *q;

    require (RulePtr != NULL,"MR_nameToRule: RulePtr not initialized");

    if (name == NULL) return NULL;

    q = (RuleEntry *) hash_get(Rname,name);

	if ( q == NULL ) {
      return NULL;
    } else {
      return RulePtr[q->rulenum];
    };
}

#ifdef __USE_PROTOS
Junction * MR_ruleReferenced(RuleRefNode *rrn)
#else
Junction * MR_ruleReferenced(rrn)
  RuleRefNode   *rrn;
#endif
{
    return MR_nameToRuleBlk(rrn->text);
}

#ifdef __USE_PROTOS
void MR_comparePredLeaves(Predicate *me,Predicate *myParent,Predicate *him,Predicate *hisParent)
#else
void MR_comparePredLeaves(me,myParent,him,hisParent)
    Predicate *me;
    Predicate *myParent;
    Predicate *him;
    Predicate *hisParent;
#endif
{
    if (me == NULL) return;
    if (me == him) {
      MR_comparePredLeaves(me->right,myParent,him,hisParent);
      return;
    } else if (me->expr == PRED_AND_LIST ||
               me->expr == PRED_OR_LIST) {
      MR_comparePredLeaves(me->down,me,him,hisParent);
      MR_comparePredLeaves(me->right,myParent,him,hisParent);
      return;
    } else {
      if (me->source != NULL) {

        /* predicate->invert can be set only in the predEntry predicates        */
        /* thus they are only visible after the predEntry predicates have been "unfolded" */

        int     sameSource=(me->source == him->source);
        int     sameInvert=1 &
                 (1 + me->inverted + him->inverted + me->source->inverted + him->source->inverted);
        int     samePredEntry=(me->source->predEntry != NULL
                                 && him->source->predEntry != NULL
                                    && me->source->predEntry == him->source->predEntry);
        if (sameInvert && (sameSource || samePredEntry)) {
          if (MR_identicalContext(me,him)) {

            /* identical predicates */

            if (hisParent->expr == PRED_OR_LIST &&
                myParent->expr == PRED_OR_LIST) {
              me->redundant=1;
            } else if (hisParent->expr == PRED_AND_LIST &&
                       myParent->expr == PRED_AND_LIST) {
              me->redundant=1;
            } else if (  (hisParent->expr == PRED_OR_LIST &&
                          myParent->expr == PRED_AND_LIST)
                       ||
                         (hisParent->expr == PRED_AND_LIST &&
                          myParent->expr == PRED_OR_LIST)
                      ) {
              myParent->redundant=1;
            } else {
              require (0,"MR_comparePredLeaves: not both PRED_LIST");
            };
          };
        };  /* end same source or same predEntrr with same invert sense */

        /* same predEntry but opposite invert sense */

        if (!sameInvert && (sameSource || samePredEntry)) {
          if (MR_identicalContext(me,him)) {
            if (hisParent->expr == PRED_OR_LIST &&
                myParent->expr == PRED_OR_LIST) {
              myParent->isConst=1;
              myParent->constValue=1;
            } else if (hisParent->expr == PRED_AND_LIST &&
                       myParent->expr == PRED_AND_LIST) {
              myParent->isConst=1;
              myParent->constValue=0;
            } else if (  (hisParent->expr == PRED_OR_LIST &&
                          myParent->expr == PRED_AND_LIST)
                       ||
                         (hisParent->expr == PRED_AND_LIST &&
                          myParent->expr == PRED_OR_LIST)
                      ) {
              me->redundant=1;
            } else {
              require (0,"MR_comparePredLeaves: not both PRED_LIST");
            };
          };
        };  /* end same predEntry with opposite invert sense */
      };

      MR_comparePredLeaves(me->right,myParent,him,hisParent);
      return;
    };
}

#ifdef __USE_PROTOS
void MR_removeRedundantPredPass1(Predicate *me,Predicate *myParent)
#else
void MR_removeRedundantPredPass1(me,myParent)
  Predicate     *me;
  Predicate     *myParent;
#endif
{
    if (me == NULL) return;
    if (me->redundant) {
      MR_removeRedundantPredPass1(me->right,myParent);
      return;
    };
    if (me->expr == PRED_AND_LIST ||
        me->expr == PRED_OR_LIST) {
      MR_removeRedundantPredPass1(me->down,me);
      MR_removeRedundantPredPass1(me->right,myParent);
    } else {
      require (me->source != NULL,"me->source == NULL");
      if (myParent != NULL) {
        MR_comparePredLeaves(myParent->down,myParent,me,myParent);
      };
      MR_removeRedundantPredPass1(me->right,myParent);
    };
}

/* pretty much ignores things with the inverted bit set */

#ifdef __USE_PROTOS
Predicate *MR_predFlatten(Predicate *p)
#else
Predicate *MR_predFlatten(p)
  Predicate     *p;
#endif
{
    if (p == NULL) return NULL;
    if (p->expr == PRED_OR_LIST
        || p->expr == PRED_AND_LIST) {

      Predicate     *child;
      Predicate     *gchild;
      Predicate     **tail;
      Predicate     *next;
      char          *PRED_XXX_LIST=p->expr;

      require (p->down != NULL,"MR_predFlatten AND/OR no child");


      p->down=MR_predFlatten(p->down);
      p->right=MR_predFlatten(p->right);
      child=p->down;
      if (child->right == NULL) {
        child->right=p->right;
        p->right=NULL;
        p->down=NULL;
        if (p->inverted) child->inverted=!child->inverted;
        predicate_free(p);
        return child;
      };

      /* make a single list of all children and grandchildren */

      tail=&(p->down);
      for (child=p->down; child != NULL; child=next) {
        if (child->expr != PRED_XXX_LIST
              || child->inverted
                || child->predEntry != NULL) {
          *tail=child;
          tail=&(child->right);
          next=child->right;
        } else {
          for (gchild=child->down;
               gchild != NULL;
               gchild=gchild->right) {
            *tail=gchild;
            tail=&(gchild->right);
          };
          next=child->right;
          child->right=NULL;
          child->down=NULL;
          predicate_free(child);
        };
      };
      *tail=NULL;
      return p;
    } else {
      p->right=MR_predFlatten(p->right);
      return p;
    };
}

static char *alwaysFalseWarning=NULL;

#ifdef __USE_PROTOS
Predicate *checkPredicateConflict(Predicate *p)
#else
Predicate *checkPredicateConflict(p)
  Predicate     *p;
#endif
{
  if (p->isConst) {
    if (p->constValue == 1) {
      predicate_free(p);
      return NULL;
    } else {
      if (InfoP && !p->conflictReported) {
        p->conflictReported=1;
        fprintf(output,"\n#if 0\n\n");
        fprintf(output,"The following predicate expression will always be false:\n\n");
        MR_dumpPred1(1,p,1);
        fprintf(output,"\n#endif\n");
      };

      if (alwaysFalseWarning != CurRule) {
        alwaysFalseWarning=CurRule;
        if (InfoP) {
          warnNoFL(eMsg1("one (or more) predicate expression hoisted into rule \"%s\" are always false \
- see output file for more information",CurRule));
        } else {
          warnNoFL(eMsg1("one (or more) predicate expressions hoisted into rule \"%s\" are always false \
- use \"-info p\" for more information",CurRule));
        };
      };
    };
  };
  return p;
}


#ifdef __USE_PROTOS
int MR_countPredNodes(Predicate *p)
#else
int MR_countPredNodes(p)
  Predicate     *p;
#endif
{
  if (p == NULL) return 0;
  return 1 + MR_countPredNodes(p->down) + MR_countPredNodes(p->right);
}

#ifdef __USE_PROTOS
Predicate *MR_predSimplifyALLX(Predicate *p,int skipPass3)
#else
Predicate *MR_predSimplifyALLX(p,skipPass3)
  Predicate     *p;
  int           skipPass3;
#endif
{
  int       countBefore;
  int       countAfter;

  countAfter=MR_countPredNodes(p);

  do {
      if (p == NULL) return NULL;
      if (p->right == NULL && p->down == NULL) return p;
      countBefore=countAfter;
      MR_simplifyInverted(p,0);
      p=MR_predFlatten(p);
      MR_removeRedundantPredPass1(p,NULL);
      MR_removeRedundantPredPass2(p);
      if (! skipPass3) {
        p=checkPredicateConflict(p);
        p=MR_removeRedundantPredPass3(p);
      };
      countAfter=MR_countPredNodes(p);
  } while (countBefore != countAfter);

  return p;
}

#ifdef __USE_PROTOS
Predicate *MR_predSimplifyALL(Predicate *p)
#else
Predicate *MR_predSimplifyALL(p)
  Predicate     *p;
#endif
{
  return MR_predSimplifyALLX(p,0);
}

#ifdef __USE_PROTOS
void MR_releaseResourcesUsedInRule(Node *n)
#else
void MR_releaseResourcesUsedInRule(n)
  Node  *n;
#endif
{
   Node         *next;
   Junction     *j;
   int          i;

   if (n == NULL) return;
   if (n->ntype == nJunction) {
     j=(Junction *) n;

     if (j->predicate != NULL) {
       predicate_free(j->predicate);
       j->predicate=NULL;
     };
     for (i=0; i< CLL_k; i++) {
       set_free(j->fset[i]);
       j->fset[i]=empty;
     };
     if (j->ftree != NULL) {
       Tfree(j->ftree);
       j->ftree=NULL;
     };
     if (j->jtype == EndRule) return;
     if (j->jtype != RuleBlk && j->jtype != EndBlk) {
       if (j->p2 != NULL && !j->ignore) {   /* MR11 */
          MR_releaseResourcesUsedInRule(j->p2);
       };
     };
   };
   next=MR_advance(n);
   MR_releaseResourcesUsedInRule(next);
}

#ifdef __USE_PROTOS
int MR_allPredLeaves(Predicate *p)
#else
int MR_allPredLeaves(p)
  Predicate *p;
#endif
{
  Predicate     *q;

  if (p == NULL) return 1;

  for (q=p; q != NULL; q=q->right) {
   if (q->down != NULL) return 0;
  };
  return 1;
}

/* make sure it works for the last rule in a file */

#ifdef __USE_PROTOS
int MR_offsetFromRule(Node *n)
#else
int MR_offsetFromRule(n)
  Node      *n;
#endif
{
  Junction  *j;
  int       offset=(-1);

  for (j=SynDiag; j != NULL; j=(Junction *)j->p2) {

    require (j->ntype == nJunction && j->jtype == RuleBlk,"Not a rule block");

    if (n->file < j->file) {
      return offset;
    };
    if (n->file == j->file) {
      if (n->line < j->line) {
        return (offset < 0) ? 0 : offset;
      } else {
        offset=n->line - j->line;
        if (offset == 0) return 0;
      };
    };
  };
  return offset;
}

#define ruleNameMax 50

static char ruleNameStatic1[ruleNameMax];
static char ruleNameStatic2[ruleNameMax+10];

#ifdef __USE_PROTOS
char * MR_ruleNamePlusOffset(Node *n)
#else
char * MR_ruleNamePlusOffset(n)
  Node      *n;
#endif
{
    int     offset=MR_offsetFromRule(n);

    strncpy(ruleNameStatic1,n->rname,ruleNameMax);
    if (offset < 0) {
      sprintf(ruleNameStatic2,"%s/?",ruleNameStatic1);
    } else {
      sprintf(ruleNameStatic2,"%s/%d",ruleNameStatic1,offset+1);
    };
    return ruleNameStatic2;
}

#ifdef __USE_PROTOS
int MR_max_height_of_tree(Tree *t)
#else
int MR_max_height_of_tree(t)
  Tree  *t;
#endif
{
  int       h;
  int       height=0;
  Tree      *u;

  if (t == NULL) return 0;

  require (t->token != ALT && t->token != EpToken,"MR_max_height_of_tree ALT or EpToken");

  for (u=t; u != NULL; u=u->right) {
    h=MR_max_height_of_tree(u->down)+1;
    if (h > height) height=h;
  };
  return height;
}

#ifdef __USE_PROTOS
int MR_all_leaves_same_height(Tree *t,int depth)
#else
int MR_all_leaves_same_height(t,depth)
  Tree  *t;
  int   depth;
#endif
{
  if (t == NULL) {
    return (depth==0);
  };

  require (t->token != ALT && t->token != EpToken,"MR_all_leaves_same_height ALT or EpToken");

  if (depth == 0) {
    return 0;
  } else {
    if ( ! MR_all_leaves_same_height(t->down,depth-1)) {
      return 0;
    };
    if (t->right == NULL) {
      return 1;
    } else {
      return MR_all_leaves_same_height(t->right,depth);
    };
  };
}

#ifdef __USE_PROTOS
void MR_projectTreeOntoSet(Tree *tree,int ck,set *ckset)
#else
void MR_projectTreeOntoSet(tree,ck,ckset)
  Tree  *tree;
  int   ck;
  set   *ckset;
#endif
{
    if (tree == NULL) return;

    require(tree->token != EpToken,"MR_projectTreeOntoSet: EpToken unexpected\n");

    MR_projectTreeOntoSet(tree->right,ck,ckset);
    if (tree->token == ALT) {
      MR_projectTreeOntoSet(tree->down,ck,ckset);
    } else {
      if (ck > 1) {
        MR_projectTreeOntoSet(tree->down,ck-1,ckset);
      } else {
        set_orel(tree->token,ckset);
      };
    };
}

#ifdef __USE_PROTOS
int MR_comparePredicates(Predicate *a,Predicate *b)
#else
int MR_comparePredicates(a,b)
  Predicate     *a;
  Predicate     *b;
#endif
{
  Predicate     *p;
  Predicate     *q;

  if (a == b) return 1;
  if (a == NULL || b == NULL ) return 0;
  if (a->down == NULL && b->down == NULL) {

    /* predicate->invert can be set only in the predEntry predicates                  */
    /* thus they are only visible after the predEntry predicates have been "unfolded" */

    int     sameSource=(a->source == b->source);
    int     sameInvert= 1 & (1 +a->inverted + b->inverted +
                                a->source->inverted + b->source->inverted);
    int     samePredEntry=(a->source->predEntry != NULL
                                 && b->source->predEntry != NULL
                                    && a->source->predEntry == b->source->predEntry);
    if (sameInvert && (sameSource || samePredEntry)) {
      if (MR_identicalContext(a,b)) {
         return 1;
      };
    };
    return 0;
  };
  if (a->down == NULL || b->down == NULL) return 0;
  if (a->expr != b->expr) return 0;

  for (p=a->down; p != NULL; p=p->right) {
    for (q=b->down; q != NULL; q=q->right) {
      if (MR_comparePredicates(p,q)) goto NEXT_P;
    };
    return 0;
NEXT_P:
    continue;
  };
  return 1;
}

/*
 *  action->inverted can be set only when a predicate symbol appears in
 *      a rule:  "rule : <<!XXX>>? X".  It cannot be set under any
 *      other circumstances.  In particular it cannot be set by
 *      "#pred NotA !A" or by "#pred Nota <<!A>>?".  The first case
 *      creates a predEntry and the predicate expression of that predEntry
 *      has inverted set.  In the second case, the code for handling "!"
 *      is only present in buildAction, which is not called by the #pred
 *      semantic routines, only when a <<...>>? is recognized as part of
 *      a rule definition.
 *
 *  predicate->inverted can only be set by a predicate created by a #pred
 *      expression, such as "#pred NotA !A" or "#pred NotXY ! (X && Y) or
 *      "#pred XbarY !(X && Y)".  In particular, it cannot be set by any
 *      predicate expression occurring under any other circumstances.
 *      The #pred predicate expressions are stored with in predEntry->pred
 *      and do not normally appear anywhere else until the predicates are
 *      "unfolded" in order to recognize redundancies, conflicts, and
 *      tautologies.
 *
 *  The unfold routine expands all references to #pred expressions.
 *
 *  The simplifyInvert goes through and propagates the invert bit so that
 *      all OR and AND nodes are un-inverted.
 *
 *  Note that !(A and B) => (!A or !B)
 *            !(A or B)  => (!A and !B)
 *
 *  MR_unfold() is called to expand predicate symbols by replacing predicates
 *    that reference predicate entries with the copies of the predicate entries.
 *    Each reference receives a duplicate of the original.  This is necessary
 *    because the next phase involves simplification and removal of redundant
 *    predicate nodes.  Anyway, the point I'm making is that predicate->invert
 *    should not be set in any predicate until it has been expanded.
 *
 *    This is a recursive structure, but there is no need for "recursive expansion"
 *    by which I mean a predicate symbol refers to other predicate symbols which
 *    must also be expanded.
 *
 *    Recursive expansion is *not* performed by this routine because it is not
 *    necessary.  Expansion of references is performed by predPrimary when
 *    a new predicate symbol is created by referring to others in the pred expr.
 */

#ifdef __USE_PROTOS
Predicate *MR_unfold(Predicate *pred)
#else
Predicate *MR_unfold(pred)
  Predicate     *pred;
#endif
{
  Predicate     *result;

  if (pred == NULL) return NULL;

  pred->right=MR_unfold(pred->right);

  if (pred->down == NULL) {
    if (pred->source->predEntry != NULL) {
      if (pred->source->predEntry->pred == NULL) {
        ; /* do nothing */ /* a reference to a literal #pred (perhaps with "!" */
      } else {
        result=predicate_dup_without_context(pred->source->predEntry->pred);
        if (pred->inverted) {
          result->inverted=!result->inverted;
        };
        if (pred->source->inverted) {
          result->inverted=!result->inverted;
        };
        result->right=pred->right;
        pred->right=NULL;
        predicate_free(pred);
/***    result=MR_unfold(result); *** not necessary */    /* recursive expansion */
        return result;
      };
    } else {
      ; /* do nothing */ /* an inline literal predicate */
    };
  } else {
    pred->down=MR_unfold(pred->down);
  };
  return pred;
}

/* this should be called immediately after MR_unfold() and
   at no other times
*/

#ifdef __USE_PROTOS
void MR_simplifyInverted(Predicate *pred,int inverted)
#else
void MR_simplifyInverted(pred,inverted)
  Predicate     *pred;
  int           inverted;
#endif
{
  int       newInverted;

  if (pred == NULL) return;

  MR_simplifyInverted(pred->right,inverted);

  newInverted= 1 & (inverted + pred->inverted);

  if (pred->down == NULL) {
    pred->inverted=newInverted;
  } else {
    if (newInverted != 0) {
      if (pred->expr == PRED_AND_LIST) {
        pred->expr=PRED_OR_LIST;
      } else {
        pred->expr=PRED_AND_LIST;
      };
    };
    pred->inverted=0;
    MR_simplifyInverted(pred->down,newInverted);
  };
}

/* only remove it from AND and OR nodes, not leaves */

#ifdef __USE_PROTOS
void MR_clearPredEntry(Predicate *p)
#else
void MR_clearPredEntry(p)
  Predicate     *p;
#endif
{
   if (p == NULL) return;
   MR_clearPredEntry(p->down);
   MR_clearPredEntry(p->right);
   if (p->down != NULL) p->predEntry=NULL;
}


#ifdef __USE_PROTOS
void MR_orphanRules(FILE *f)
#else
void MR_orphanRules(f)
  FILE      *f;
#endif
{
	set         a;
    Junction    *p;
    unsigned    e;
    RuleEntry   *re;

	a=empty;

    if (! InfoO) return;

	for (p=SynDiag; p!=NULL; p = (Junction *)p->p2)	{
      if ( (Junction *) (p->end)->p1 == NULL) {
        re=(RuleEntry *) hash_get(Rname,p->rname);
        require (re != NULL,"RuleEntry == NULL");
		set_orel(re->rulenum, &a);
      }
  	}

    if (set_deg(a) > 1) {
      fprintf(f,"note: Start rules: {");
      for (; !set_nil(a); set_rm(e,a)) {
        e=set_int(a);
        fprintf(f," %s",RulePtr[e]->rname);
      };
      fprintf(f," }\n");
    };
	set_free( a );
}

/*  merge (X Y) and (X) to create (X)  */

static int      *mergeChain;
static Tree     *mergeTree;

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

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

#ifdef __USE_PROTOS
Tree *MR_merge_tree_contexts(Tree *t)
#else
Tree *MR_merge_tree_contexts(t)
  Tree  *t;
#endif
{
    int     h=MR_max_height_of_tree(t);

    mergeTree=t;
    mergeChain=(int *) calloc(h+1,sizeof(int));
    require (mergeChain != NULL,"MR_merge_tree_contexts: can't alloc chain");
    MR_iterateOverTreeContexts(t,mergeChain);
    t=tshrink(t);
    t=tflatten(t);
    t=tleft_factor(t);
    free ( (char *) mergeChain);
    mergeChain=NULL;
    return t;
}

#ifdef __USE_PROTOS
Tree *MR_compute_pred_tree_context(Predicate *p)
#else
Tree *MR_compute_pred_tree_context(p)
  Predicate *p;
#endif
{
  Tree  *t;

  t=MR_compute_pred_tree_ctxXX(p);
  MR_merge_tree_contexts(t);
  return t;
}

#ifdef __USE_PROTOS
void MR_guardPred_plainSet(ActionNode *anode,Predicate *pred)
#else
void MR_guardPred_plainSet(anode,pred)
  ActionNode    *anode;
  Predicate     *pred;
#endif
{
  Junction      *j;
  Predicate     *workPred;
  set           maskSet;

  maskSet=empty;

  if (!MRhoisting) return;

  /* it doesn't really matter whether the predicate has
     depth k=1 or k>1 because we're not really looking
     at the predicate itself, just the stuff "behind"
     the predicate.
  */

  /* shouldn't have to worry about REACHing off the end
     of the rule containing the predicate because the
     Rule->end->halt should have been set already by the
     the code which handles RuleRef nodes.

     We don't want to REACH off the end of the rule because
     this would give the "global" follow context rather than
     the "local" context.

         r1a : (A)? => <<p>>? r2 (A|B)
         r1b : (A)? => <<p>>? r2 (A|C)
         r2  : ();

     For r1a we want follow of predicate = {A B}
             we want plainSet = {B}
     For r1b we want follow of predicate = {A C}
             we want plainSet = {C}
  */

  require (anode->next->ntype == nJunction,"MR_guardpred_plainSet not Junction");
  j=(Junction *)(anode->next);

  workPred=predicate_dup_without_context(pred);
  workPred->k=1;
  workPred->scontext[1]=MR_First(1,j, &(workPred->completionSet) );
  MR_complete_predicates(1,workPred);
  if (pred->k == 1) {
    maskSet=pred->scontext[1];
  } else {
    MR_projectTreeOntoSet(pred->tcontext,1,&maskSet);
  }
  pred->plainSet=set_dif(workPred->scontext[1],maskSet);
  predicate_free(workPred);
}

/*******************************************************************************/

static Tree *       suppressTree;
static int *        suppressChain;  /* element 0 not used */
static set *        suppressSets;
static Node *       suppressNode;
static int          suppressChainLength;
int                 MR_SuppressSearch=0;
static int          suppressSucceeded;
static Predicate *  suppressPredicate;

#ifdef __USE_PROTOS
int MR_isChain(Tree *t)
#else
int MR_isChain(t)
  Tree  *t;
#endif
{
  Tree  *u;

  for (u=t; u != NULL; u=u->down) {
    if (u->right != NULL) return 0;
  }
  return 1;
}

#ifdef __USE_PROTOS
int MR_suppressK_client(Tree *tree,int tokensInChain[])
#else
int MR_suppressK_client(tree,tokensInChain)
  Tree      *tree;
  int       tokensInChain[];
#endif
{
  int       i;
  set       *save_fset;
  int       save_ConstrainSearch;
  set       incomplete;
  Tree      *t;

  suppressSucceeded=0;  /* volatile */

  if (suppressSets == NULL) {
    suppressSets=(set *) calloc (CLL_k+1,sizeof(set));
    require (suppressSets != NULL,"MR_suppressK_client: suppressSets alloc");
  };

  for (suppressChainLength=1;
       tokensInChain[suppressChainLength+1] != 0;
       suppressChainLength++) {};

  require (suppressChainLength != 0,"MR_suppressK_client: chain empty");

  for (i=1 ; i <= suppressChainLength ; i++) {
    set_clr(suppressSets[i]);
    set_orel( (unsigned) tokensInChain[i],
                              &suppressSets[i]);
  };

  save_fset=fset;
  save_ConstrainSearch=ConstrainSearch;

  fset=suppressSets;

  MR_SuppressSearch=1;
  MR_AmbSourceSearch=1;
  MR_MaintainBackTrace=1;
  ConstrainSearch=1;

  maxk = suppressChainLength;

  incomplete=empty;
  t=NULL;

/***  constrain = &(fset[1]); ***/

  MR_setConstrainPointer(&(fset[1]));	/* MR18 */
  
  MR_pointerStackReset(&MR_BackTraceStack);

  TRAV(suppressNode,maxk,&incomplete,t);

  Tfree(t);

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

  ConstrainSearch=save_ConstrainSearch;
  fset=save_fset;

  MR_AmbSourceSearch=0;
  MR_MaintainBackTrace=0;
  MR_SuppressSearch=0;
  return suppressSucceeded;
}

#ifdef __USE_PROTOS
Tree * MR_iterateOverTreeSuppressK(Tree *t,int chain[])
#else
Tree * MR_iterateOverTreeSuppressK(t,chain)
  Tree          *t;
  int           chain[];
#endif
{
  if (t == NULL) return NULL;
  t->right=MR_iterateOverTreeSuppressK(t->right,&chain[0]);
  chain[0]=t->token;
  if (t->down != NULL) {
    t->down=MR_iterateOverTreeSuppressK(t->down,&chain[1]);
    if (t->down == NULL) {
      Tree *u=t->right;
      t->right=NULL;
      Tfree(t);
      chain[0]=0;
      return u;
    };
  } else {
    MR_suppressK_client(suppressTree,suppressChain);
    if (suppressSucceeded) {
      Tree  *u=t->right;
      t->right=NULL;
      Tfree(t);
      chain[0]=0;
      return u;
    };
  };
  chain[0]=0;
  return t;
}

/* @@@ */

#ifdef __USE_PROTOS
Predicate * MR_suppressK(Node *j,Predicate *p)
#else
Predicate * MR_suppressK(j,p)
  Node          *j;
  Predicate     *p;
#endif
{
  Predicate     *result;
  int           guardPred=0;
  int           ampersandPred=0;
  Node          *nodePrime;

  if (! MRhoistingk) {
     return p;
  }

  if (! MRhoisting) return p;
  if (CLL_k == 1) return p;

  if (suppressChain == NULL) {
    suppressChain=(int *) calloc(CLL_k+2,sizeof(int));
    require (suppressChain != NULL,"MR_suppressK: can't allocate chain");
  }

  if (p == NULL) return NULL;

  if (j->ntype == nJunction) {
    nodePrime=(Node *) MR_junctionWithoutP2( (Junction *) j);
  } else {
    nodePrime=j;
  };

  p->down=MR_suppressK(j,p->down);
  p->right=MR_suppressK(j,p->right);
  if (p->down != NULL) {
    result=p;
    goto EXIT;
  };
  if (p->k == 1) {
    result=p;
    goto EXIT;
  };

  if (p->source != NULL) {
    if (p->source->guardpred != NULL) guardPred=1;
    if (p->source->ampersandPred != NULL) ampersandPred=1;
  }

  suppressPredicate=p;
  suppressNode=nodePrime;   /* was j*/

  suppressTree=p->tcontext;

  if (guardPred || ampersandPred) {
    p->tcontext=MR_iterateOverTreeSuppressK(suppressTree,&suppressChain[1]);
    if (p->tcontext == NULL) {
      predicate_free(p);
      result=NULL;
      goto EXIT;
    };
  } else {
    if (MR_isChain(p->tcontext)) {
      p->tcontext=MR_iterateOverTreeSuppressK(suppressTree,&suppressChain[1]);
      if (p->tcontext == NULL) {
        predicate_free(p);
        result=NULL;
        goto EXIT;
      };
    }
  }
  result=p;
EXIT:
  return result;
}

#ifdef __USE_PROTOS
void MR_suppressSearchReport(void)
#else
void MR_suppressSearchReport()
#endif
{
  int       i;
  Node      *p;
  TokNode   *tn;
  int       depth;
  set       setAnd;

  /* number of tokens in back trace stack matches length of chain */

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

  require (depth == suppressChainLength,"depth > suppressChainLength");

  /* token codes match chain */

  depth=0;
  for (i=0; i < MR_BackTraceStack.count ; i++) {
    p=(Node *) MR_BackTraceStack.data[i];
    if (p->ntype != nToken) continue;
    tn=(TokNode *) p;
    depth++;
    if (set_nil(tn->tset)) {
      require(set_el( (unsigned) tn->token,fset[depth]),
        "MR_suppressSearchReport: no match to #token in chain");
    } else {
      setAnd=set_and(fset[depth],tn->tset);
      require(!set_nil(setAnd),
        "MR_suppressSearchReport: no match to #token set in chain");
      set_free(setAnd);
    };
  };

  /* have a match - now remove it from the predicate */

  suppressSucceeded=1;

  if (suppressSucceeded) {
    fprintf(output,"\n");
    fprintf(output,"#if 0\n");
    fprintf(output,"\n");
    fprintf(output,"Part (or all) of predicate with depth > 1 suppressed by ");
        fprintf(output,"alternative without predicate\n\n");
    MR_dumpPred(suppressPredicate,1);
    fprintf(output,"The token sequence which is suppressed:");
    fprintf(output," (");
    for (i=1; i <= suppressChainLength; i++) {
      fprintf(output," %s",TerminalString(suppressChain[i]));
    };
    fprintf(output," )\n");
    fprintf(output,"The sequence of references which generate that sequence of tokens:\n\n");

    MR_backTraceDumpItemReset();

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

#ifdef __USE_PROTOS
void MR_markCompromisedRule(Node *n)
#else
void MR_markCompromisedRule(n)
  Node *n;
#endif
{
  RuleEntry     *q;
  Node          *mark=NULL;
  Junction      *j;

  if (n->ntype == nRuleRef) {
    mark=(Node *) MR_ruleReferenced( (RuleRefNode *) n);
  } else if (n->ntype == nToken) {
    mark=n;
  } else if (n->ntype == nJunction) {
    j=(Junction *)n;
    switch (j->jtype) {
      case aOptBlk:
      case aLoopBlk:
      case RuleBlk:
      case EndRule:
      case aPlusBlk:
      case aLoopBegin:
        mark=n;
        break;
      default:
        break;
    };
  }

  if (mark == NULL) return;

  require (RulePtr != NULL,"RulePtr not initialized");

  q = (RuleEntry *) hash_get(Rname,mark->rname);
  require (q != NULL,"RuleEntry not found");
  set_orel(q->rulenum,&MR_CompromisedRules);
}

#ifdef __USE_PROTOS
void MR_alphaBetaTraceReport(void)
#else
void MR_alphaBetaTraceReport()
#endif
{
  int       i;

  if (! AlphaBetaTrace) return;

  MR_AlphaBetaMessageCount++;

  fprintf(output,"\n");
  fprintf(output,"#if 0\n");
  fprintf(output,"\n");
  fprintf(output,"Trace of references leading to attempt to compute the follow set of\n");
  fprintf(output,"alpha in an \"(alpha)? beta\" block. It is not possible for antlr to\n");
  fprintf(output,"compute this follow set because it is not known what part of beta has\n");
  fprintf(output,"already been matched by alpha and what part remains to be matched.\n");
  fprintf(output,"\n");
  fprintf(output,"Rules which make use of the incorrect follow set will also be incorrect\n");
  fprintf(output,"\n");

  MR_backTraceDumpItemReset();

  for (i=0; i < MR_BackTraceStack.count ; i++) {
     MR_backTraceDumpItem(output,0,(Node *) MR_BackTraceStack.data[i]);
     if (i < MR_BackTraceStack.count-1) {
        MR_markCompromisedRule( (Node *) MR_BackTraceStack.data[i]);
     };
  };
  fprintf(output,"\n");
  fprintf(output,"#endif\n");
}

#ifdef __USE_PROTOS
void MR_dumpRuleSet(set s)
#else
void MR_dumpRuleSet(s)
  set   s;
#endif
{
    unsigned    *cursor;
    unsigned    *origin=set_pdq(s);

    require(origin != NULL,"set_pdq failed");

    if (RulePtr == NULL) {
      fprintf(stderr,"RulePtr[] not yet initialized");
    } else {
      for (cursor=origin; *cursor != nil ; cursor++) {
/****   if (cursor != origin) fprintf(stderr,","); ****/
        fprintf(stderr,"    %s",RulePtr[*cursor]->rname);
        fprintf(stderr,"\n");
      };
      free( (char *) origin);
    };
}
