package java_cup ; import java.util.Enumeration ; import java.util.Hashtable ; /** * 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 ; } /*-----------------------------------------------------------*/ }