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 */ @SuppressWarnings ( { "all" } ) 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; } /*-----------------------------------------------------------*/ }