package java_cup; import java.util.BitSet; /** A set of terminals implemented as a bitset. * @version last updated: 11/25/95 * @author Scott Hudson */ public class terminal_set { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** Constructor for an empty set. */ public terminal_set() { /* allocate the bitset at what is probably the right size */ _elements = new BitSet(terminal.number()); }; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Constructor for cloning from another set. * @param other the set we are cloning from. */ public terminal_set(terminal_set other) throws internal_error { not_null(other); _elements = (BitSet)other._elements.clone(); }; /*-----------------------------------------------------------*/ /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ /** Constant for the empty set. */ public static final terminal_set EMPTY = new terminal_set(); /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** Bitset to implement the actual set. */ protected BitSet _elements; /*-----------------------------------------------------------*/ /*--- General Methods ----------------------------------------*/ /*-----------------------------------------------------------*/ /** 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 is empty. */ public boolean empty() { return equals(EMPTY); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if the set contains a particular terminal. * @param sym the terminal symbol we are looking for. */ public boolean contains(terminal sym) throws internal_error { not_null(sym); return _elements.get(sym.index()); }; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Given its index determine if the set contains a particular terminal. * @param indx the index of the terminal in question. */ public boolean contains(int indx) { return _elements.get(indx); }; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this set is an (improper) subset of another. * @param other the set we are testing against. */ public boolean is_subset_of(terminal_set other) throws internal_error { not_null(other); /* make a copy of the other set */ BitSet copy_other = (BitSet)other._elements.clone(); /* and or in */ copy_other.or(_elements); /* if it hasn't changed, we were a subset */ return copy_other.equals(other._elements); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this set is an (improper) superset of another. * @param other the set we are testing against. */ public boolean is_superset_of(terminal_set other) throws internal_error { not_null(other); return other.is_subset_of(this); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add a single terminal to the set. * @param sym the terminal being added. * @return true if this changes the set. */ public boolean add(terminal sym) throws internal_error { boolean result; not_null(sym); /* see if we already have this */ result = _elements.get(sym.index()); /* if not we add it */ if (!result) _elements.set(sym.index()); return result; }; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Remove a terminal if it is in the set. * @param sym the terminal being removed. */ public void remove(terminal sym) throws internal_error { not_null(sym); _elements.clear(sym.index()); }; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Add (union) in a complete set. * @param other the set being added. * @return true if this changes the set. */ public boolean add(terminal_set other) throws internal_error { not_null(other); /* make a copy */ BitSet copy = (BitSet)_elements.clone(); /* or in the other set */ _elements.or(other._elements); /* changed if we are not the same as the copy */ return !_elements.equals(copy); }; /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Determine if this set intersects another. * @param other the other set in question. */ public boolean intersects(terminal_set other) throws internal_error { not_null(other); /* make a copy of the other set */ BitSet copy = (BitSet)other._elements.clone(); /* xor out our values */ copy.xor(this._elements); /* see if its different */ return !copy.equals(other._elements); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Equality comparison. */ public boolean equals(terminal_set other) { if (other == null) return false; else return _elements.equals(other._elements); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Generic equality comparison. */ public boolean equals(Object other) { if (!(other instanceof terminal_set)) return false; else return equals((terminal_set)other); } /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ /** Convert to string. */ public String toString() { String result; boolean comma_flag; result = "{"; comma_flag = false; for (int t = 0; t < terminal.number(); t++) { if (_elements.get(t)) { if (comma_flag) result += ", "; else comma_flag = true; result += terminal.find(t).name(); } } result += "}"; return result; } /*-----------------------------------------------------------*/ };