content: 
  package java_cup;
  
  import java.util.Hashtable;
  import java.util.Enumeration;
  
  /** This class represents a set of LALR items.  For purposes of building
   *  these sets, items are considered unique only if they have unique cores
   *  (i.e., ignoring differences in their lookahead sets).<p>
   *
   *  This class provides fairly conventional set oriented operations (union,
   *  sub/super-set tests, etc.), as well as an LALR "closure" operation (see 
   *  compute_closure()).
   *
   * @see     java_cup.lalr_item
   * @see     java_cup.lalr_state
   * @version last updated: 3/6/96
   * @author  Scott Hudson
   */
  
  public class lalr_item_set {
  
    /*-----------------------------------------------------------*/
    /*--- Constructor(s) ----------------------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Constructor for an empty set. */
    public lalr_item_set() { }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Constructor for cloning from another set. 
     * @param other indicates set we should copy from.
     */
    public lalr_item_set(lalr_item_set other) 
      throws internal_error
      {
        not_null(other);
        _all = (Hashtable)other._all.clone();
      }
  
    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/
  
    /** A hash table to implement the set.  We store the items using themselves
     *  as keys. 
     */
    protected Hashtable _all = new Hashtable(11);
  
    /** Access to all elements of the set. */
    public Enumeration all() {return _all.elements();}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Cached hashcode for this set. */
    protected Integer hashcode_cache = null;
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Size of the set */
    public int size() {return _all.size();}
  
    /*-----------------------------------------------------------*/
    /*--- Set Operation Methods ---------------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Does the set contain a particular item? 
     * @param itm the item in question.
     */
    public boolean contains(lalr_item itm) {return _all.containsKey(itm);}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Return the item in the set matching a particular item (or null if not 
     *  found) 
     *  @param itm the item we are looking for.
     */
    public lalr_item find(lalr_item itm) {return (lalr_item)_all.get(itm);}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Is this set an (improper) subset of another? 
     * @param other the other set in question.
     */
    public boolean is_subset_of(lalr_item_set other) throws internal_error
      {
        not_null(other);
  
        /* walk down our set and make sure every element is in the other */
        for (Enumeration e = all(); e.hasMoreElements(); )
  	if (!other.contains((lalr_item)e.nextElement()))
  	  return false;
  
        /* they were all there */
        return true;
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Is this set an (improper) superset of another? 
     * @param other the other set in question.
     */
    public boolean is_superset_of(lalr_item_set other) throws internal_error
      {
        not_null(other);
        return other.is_subset_of(this);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Add a singleton item, merging lookahead sets if the item is already 
     *  part of the set.  returns the element of the set that was added or 
     *  merged into.
     * @param itm the item being added.
     */
    public lalr_item add(lalr_item itm) throws internal_error
      {
        lalr_item other;
  
        not_null(itm); 
  
        /* see if an item with a matching core is already there */
        other = (lalr_item)_all.get(itm);
  
        /* if so, merge this lookahead into the original and leave it */
        if (other != null)
  	{
  	  other.lookahead().add(itm.lookahead());
  	  return other;
  	}
        /* otherwise we just go in the set */
        else
  	{
            /* invalidate cached hashcode */
            hashcode_cache = null;
  
            _all.put(itm,itm);
  	  return itm;
  	}
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Remove a single item if it is in the set. 
     * @param itm the item to remove.
     */
    public void remove(lalr_item itm) throws internal_error
      {
        not_null(itm); 
  
        /* invalidate cached hashcode */
        hashcode_cache = null;
  
        /* remove it from hash table implementing set */
        _all.remove(itm);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Add a complete set, merging lookaheads where items are already in 
     *  the set 
     * @param other the set to be added.
     */
    public void add(lalr_item_set other) throws internal_error
      {
        not_null(other);
  
        /* walk down the other set and do the adds individually */
        for (Enumeration e = other.all(); e.hasMoreElements(); )
  	add((lalr_item)e.nextElement());
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Remove (set subtract) a complete set. 
     * @param other the set to remove.
     */
    public void remove(lalr_item_set other) throws internal_error
      {
        not_null(other);
  
        /* walk down the other set and do the removes individually */
        for (Enumeration e = other.all(); e.hasMoreElements(); )
  	remove((lalr_item)e.nextElement());
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Remove and return one item from the set (done in hash order). */
    public lalr_item get_one() throws internal_error
      {
        Enumeration the_set;
        lalr_item result;
  
        the_set = all();
        if (the_set.hasMoreElements())
  	{
            result = (lalr_item)the_set.nextElement();
            remove(result);
  	  return result;
  	}
        else
  	return null;
      }
  
    /*-----------------------------------------------------------*/
    /*--- General Methods ---------------------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Helper function for null test.  Throws an interal_error exception if its
     *  parameter is null.
     *  @param obj the object we are testing.
     */
    protected void not_null(Object obj) throws internal_error
      {
        if (obj == null) 
  	throw new internal_error("Null object used in set operation");
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Compute the closure of the set using the LALR closure rules.  Basically
     *  for every item of the form: <pre>
     *    [L ::= a *N alpha, l] 
     *  </pre>
     *  (where N is a a non terminal and alpha is a string of symbols) make 
     *  sure there are also items of the form:  <pre>
     *    [N ::= *beta, first(alpha l)] 
     *  </pre>
     *  corresponding to each production of N.  Items with identical cores but 
     *  differing lookahead sets are merged by creating a new item with the same 
     *  core and the union of the lookahead sets (the LA in LALR stands for 
     *  "lookahead merged" and this is where the merger is).  This routine 
     *  assumes that nullability and first sets have been computed for all 
     *  productions before it is called.
     */
    public void compute_closure()
      throws internal_error
      {
        lalr_item_set consider;
        lalr_item     itm, new_itm, add_itm;
        non_terminal  nt;
        terminal_set  new_lookaheads;
        Enumeration   p;
        production    prod;
        boolean       need_prop;
  
  
  
        /* invalidate cached hashcode */
        hashcode_cache = null;
  
        /* each current element needs to be considered */
        consider = new lalr_item_set(this);
  
        /* repeat this until there is nothing else to consider */
        while (consider.size() > 0)
  	{
  	  /* get one item to consider */
  	  itm = consider.get_one(); 
  
  	  /* do we have a dot before a non terminal */
  	  nt = itm.dot_before_nt();
  	  if (nt != null)
  	    {
  	      /* create the lookahead set based on first after dot */
  	      new_lookaheads = itm.calc_lookahead(itm.lookahead());
  
  	      /* are we going to need to propagate our lookahead to new item */
  	      need_prop = itm.lookahead_visible();
  
  	      /* create items for each production of that non term */
  	      for (p = nt.productions(); p.hasMoreElements(); )
  		{
  		  prod = (production)p.nextElement();
  
  		  /* create new item with dot at start and that lookahead */
  		  new_itm = new lalr_item(prod, 
  					     new terminal_set(new_lookaheads));
  
  		  /* add/merge item into the set */
  		  add_itm = add(new_itm);
  		  /* if propagation is needed link to that item */
  		  if (need_prop)
  		    itm.add_propagate(add_itm);
  
  		  /* was this was a new item*/
  		  if (add_itm == new_itm)
  		    {
  		      /* that may need further closure, consider it also */ 
  		      consider.add(new_itm);
  		    } 
  		} 
  	    } 
  	} 
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Equality comparison. */
    public boolean equals(lalr_item_set other)
      {
        if (other == null || other.size() != size()) return false;
  
        /* once we know they are the same size, then improper subset does test */
        try {
          return is_subset_of(other);
        } catch (internal_error e) {
  	/* can't throw error from here (because superclass doesn't) so crash */
  	e.crash();
  	return false;
        }
  
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Generic equality comparison. */
    public boolean equals(Object other)
      {
        if (!(other instanceof lalr_item_set))
  	return false;
        else
  	return equals((lalr_item_set)other);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Return hash code. */
    public int hashCode()
      {
        int result = 0;
        Enumeration e;
        int cnt;
  
        /* only compute a new one if we don't have it cached */
        if (hashcode_cache == null)
  	{
            /* hash together codes from at most first 5 elements */
  	  //   CSA fix! we'd *like* to hash just a few elements, but
  	  //   that means equal sets will have inequal hashcodes, which
  	  //   we're not allowed (by contract) to do.  So hash them all.
            for (e = all(), cnt=0 ; e.hasMoreElements() /*&& cnt<5*/; cnt++)
  	    result ^= ((lalr_item)e.nextElement()).hashCode();
  
  	  hashcode_cache = new Integer(result);
  	}
  
        return hashcode_cache.intValue();
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Convert to string. */
    public String toString()
      {
        StringBuffer result = new StringBuffer();
  
        result.append("{\n");
        for (Enumeration e=all(); e.hasMoreElements(); ) 
   	{
   	  result.append("  " + (lalr_item)e.nextElement() + "\n");
   	}
         result.append("}");
  
         return result.toString();
      }
      /*-----------------------------------------------------------*/
  }
  
  