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