content: 
  package java_cup;
  
  import java.util.Hashtable;
  import java.util.Enumeration;
  
  /** This class represents a set of symbols and provides a series of 
   *  set operations to manipulate them.
   *
   * @see     java_cup.symbol
   * @version last updated: 11/25/95
   * @author  Scott Hudson
   */
  public class symbol_set {
  
    /*-----------------------------------------------------------*/
    /*--- Constructor(s) ----------------------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Constructor for an empty set. */
    public symbol_set() { }
  
    /** Constructor for cloning from another set. 
     * @param other the set we are cloning from.
     */
    public symbol_set(symbol_set other) throws internal_error
      {
        not_null(other);
        _all = (Hashtable)other._all.clone();
      }
  
    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/
  
    /** A hash table to hold the set. Symbols are keyed using their name string. 
     */
    protected Hashtable _all = new Hashtable(11);
  
    /** Access to all elements of the set. */
    public Enumeration all() {return _all.elements();}
  
    /** size of the set */
    public int size() {return _all.size();}
  
    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Helper function to test for a null object and throw an exception
     *  if one is found.
     * @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");
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Determine if the set contains a particular symbol. 
     * @param sym the symbol we are looking for.
     */
    public boolean contains(symbol sym) {return _all.containsKey(sym.name());}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Determine if this set is an (improper) subset of another. 
     * @param other the set we are testing against.
     */
    public boolean is_subset_of(symbol_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((symbol)e.nextElement()))
  	  return false;
  
        /* they were all there */
        return true;
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Determine if this set is an (improper) superset of another. 
     * @param other the set we are are testing against.
     */
    public boolean is_superset_of(symbol_set other) throws internal_error
      {
        not_null(other);
        return other.is_subset_of(this);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Add a single symbol to the set.  
     * @param sym the symbol we are adding.
     * @return true if this changes the set.
     */
    public boolean add(symbol sym) throws internal_error
      {
        Object previous;
  
        not_null(sym); 
  
        /* put the object in */
        previous = _all.put(sym.name(),sym);
  
        /* if we had a previous, this is no change */
        return previous == null;
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Remove a single symbol if it is in the set. 
     * @param sym the symbol we are removing.
     */
    public void remove(symbol sym) throws internal_error
      {
        not_null(sym); 
        _all.remove(sym.name());
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Add (union) in a complete set.  
     * @param other the set we are adding in.
     * @return true if this changes the set. 
     */
    public boolean add(symbol_set other) throws internal_error
      {
        boolean result = false;
  
        not_null(other);
  
        /* walk down the other set and do the adds individually */
        for (Enumeration e = other.all(); e.hasMoreElements(); )
  	result = add((symbol)e.nextElement()) || result;
  
        return result;
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Remove (set subtract) a complete set. 
     * @param other the set we are removing.
     */
    public void remove(symbol_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((symbol)e.nextElement());
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Equality comparison. */
    public boolean equals(symbol_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 the error (because super class doesn't), so we crash */
  	e.crash();
  	return false;
        }
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Generic equality comparison. */
    public boolean equals(Object other)
      {
        if (!(other instanceof symbol_set))
  	return false;
        else
  	return equals((symbol_set)other);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Compute a hash code. */
    public int hashCode()
      {
        int result = 0;
        int cnt;
        Enumeration e;
  
        /* hash together codes from at most first 5 elements */
        for (e = all(), cnt=0 ; e.hasMoreElements() && cnt<5; cnt++)
  	result ^= ((symbol)e.nextElement()).hashCode();
  
        return result;
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Convert to a string. */
    public String toString()
      {
        String result;
        boolean comma_flag;
  
        result = "{";
        comma_flag = false;
        for (Enumeration e = all(); e.hasMoreElements(); )
  	{
  	  if (comma_flag)
  	    result += ", ";
  	  else
  	    comma_flag = true;
  
  	  result += ((symbol)e.nextElement()).name();
  	}
        result += "}";
  
        return result;
      }
  
    /*-----------------------------------------------------------*/
  
  }
  
  
  