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