001: package java_cup;
002:
003: import java.util.Hashtable;
004: import java.util.Enumeration;
005:
006: /** This class represents a set of symbols and provides a series of
007: * set operations to manipulate them.
008: *
009: * @see java_cup.symbol
010: * @version last updated: 11/25/95
011: * @author Scott Hudson
012: */
013: public class symbol_set {
014:
015: /*-----------------------------------------------------------*/
016: /*--- Constructor(s) ----------------------------------------*/
017: /*-----------------------------------------------------------*/
018:
019: /** Constructor for an empty set. */
020: public symbol_set() {
021: }
022:
023: /** Constructor for cloning from another set.
024: * @param other the set we are cloning from.
025: */
026: public symbol_set(symbol_set other) throws internal_error {
027: not_null(other);
028: _all = (Hashtable) other._all.clone();
029: }
030:
031: /*-----------------------------------------------------------*/
032: /*--- (Access to) Instance Variables ------------------------*/
033: /*-----------------------------------------------------------*/
034:
035: /** A hash table to hold the set. Symbols are keyed using their name string.
036: */
037: protected Hashtable _all = new Hashtable(11);
038:
039: /** Access to all elements of the set. */
040: public Enumeration all() {
041: return _all.elements();
042: }
043:
044: /** size of the set */
045: public int size() {
046: return _all.size();
047: }
048:
049: /*-----------------------------------------------------------*/
050: /*--- (Access to) Instance Variables ------------------------*/
051: /*-----------------------------------------------------------*/
052:
053: /** Helper function to test for a null object and throw an exception
054: * if one is found.
055: * @param obj the object we are testing.
056: */
057: protected void not_null(Object obj) throws internal_error {
058: if (obj == null)
059: throw new internal_error(
060: "Null object used in set operation");
061: }
062:
063: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
064:
065: /** Determine if the set contains a particular symbol.
066: * @param sym the symbol we are looking for.
067: */
068: public boolean contains(symbol sym) {
069: return _all.containsKey(sym.name());
070: }
071:
072: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
073:
074: /** Determine if this set is an (improper) subset of another.
075: * @param other the set we are testing against.
076: */
077: public boolean is_subset_of(symbol_set other) throws internal_error {
078: not_null(other);
079:
080: /* walk down our set and make sure every element is in the other */
081: for (Enumeration e = all(); e.hasMoreElements();)
082: if (!other.contains((symbol) e.nextElement()))
083: return false;
084:
085: /* they were all there */
086: return true;
087: }
088:
089: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
090:
091: /** Determine if this set is an (improper) superset of another.
092: * @param other the set we are are testing against.
093: */
094: public boolean is_super set_of(symbol_set other)
095: throws internal_error {
096: not_null(other);
097: return other.is_subset_of(this );
098: }
099:
100: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
101:
102: /** Add a single symbol to the set.
103: * @param sym the symbol we are adding.
104: * @return true if this changes the set.
105: */
106: public boolean add(symbol sym) throws internal_error {
107: Object previous;
108:
109: not_null(sym);
110:
111: /* put the object in */
112: previous = _all.put(sym.name(), sym);
113:
114: /* if we had a previous, this is no change */
115: return previous == null;
116: }
117:
118: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
119:
120: /** Remove a single symbol if it is in the set.
121: * @param sym the symbol we are removing.
122: */
123: public void remove(symbol sym) throws internal_error {
124: not_null(sym);
125: _all.remove(sym.name());
126: }
127:
128: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
129:
130: /** Add (union) in a complete set.
131: * @param other the set we are adding in.
132: * @return true if this changes the set.
133: */
134: public boolean add(symbol_set other) throws internal_error {
135: boolean result = false;
136:
137: not_null(other);
138:
139: /* walk down the other set and do the adds individually */
140: for (Enumeration e = other.all(); e.hasMoreElements();)
141: result = add((symbol) e.nextElement()) || result;
142:
143: return result;
144: }
145:
146: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
147:
148: /** Remove (set subtract) a complete set.
149: * @param other the set we are removing.
150: */
151: public void remove(symbol_set other) throws internal_error {
152: not_null(other);
153:
154: /* walk down the other set and do the removes individually */
155: for (Enumeration e = other.all(); e.hasMoreElements();)
156: remove((symbol) e.nextElement());
157: }
158:
159: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
160:
161: /** Equality comparison. */
162: public boolean equals(symbol_set other) {
163: if (other == null || other.size() != size())
164: return false;
165:
166: /* once we know they are the same size, then improper subset does test */
167: try {
168: return is_subset_of(other);
169: } catch (internal_error e) {
170: /* can't throw the error (because super class doesn't), so we crash */
171: e.crash();
172: return false;
173: }
174: }
175:
176: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
177:
178: /** Generic equality comparison. */
179: public boolean equals(Object other) {
180: if (!(other instanceof symbol_set))
181: return false;
182: else
183: return equals((symbol_set) other);
184: }
185:
186: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
187:
188: /** Compute a hash code. */
189: public int hashCode() {
190: int result = 0;
191: int cnt;
192: Enumeration e;
193:
194: /* hash together codes from at most first 5 elements */
195: for (e = all(), cnt = 0; e.hasMoreElements() && cnt < 5; cnt++)
196: result ^= ((symbol) e.nextElement()).hashCode();
197:
198: return result;
199: }
200:
201: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
202:
203: /** Convert to a string. */
204: public String toString() {
205: String result;
206: boolean comma_flag;
207:
208: result = "{";
209: comma_flag = false;
210: for (Enumeration e = all(); e.hasMoreElements();) {
211: if (comma_flag)
212: result += ", ";
213: else
214: comma_flag = true;
215:
216: result += ((symbol) e.nextElement()).name();
217: }
218: result += "}";
219:
220: return result;
221: }
222:
223: /*-----------------------------------------------------------*/
224:
225: }
|