--- /dev/null
+
+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;
+ }
+
+ /*-----------------------------------------------------------*/
+
+}
+
+