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