package java_cup; import java.util.BitSet; /** * A set of terminals implemented as a bitset. * * @version last updated: 11/25/95 * @author Scott Hudson */ @SuppressWarnings ( { "all" } ) 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; } /*-----------------------------------------------------------*/ }