001: package java_cup;
002:
003: /** The "core" of an LR item. This includes a production and the position
004: * of a marker (the "dot") within the production. Typically item cores
005: * are written using a production with an embedded "dot" to indicate their
006: * position. For example: <pre>
007: * A ::= B * C d E
008: * </pre>
009: * This represents a point in a parse where the parser is trying to match
010: * the given production, and has succeeded in matching everything before the
011: * "dot" (and hence is expecting to see the symbols after the dot next). See
012: * lalr_item, lalr_item_set, and lalr_start for full details on the meaning
013: * and use of items.
014: *
015: * @see java_cup.lalr_item
016: * @see java_cup.lalr_item_set
017: * @see java_cup.lalr_state
018: * @version last updated: 11/25/95
019: * @author Scott Hudson
020: */
021:
022: public class lr_item_core {
023:
024: /*-----------------------------------------------------------*/
025: /*--- Constructor(s) ----------------------------------------*/
026: /*-----------------------------------------------------------*/
027:
028: /** Full constructor.
029: * @param prod production this item uses.
030: * @param pos position of the "dot" within the item.
031: */
032: public lr_item_core(production prod, int pos) throws internal_error {
033: symbol after_dot = null;
034: production_part part;
035:
036: if (prod == null)
037: throw new internal_error(
038: "Attempt to create an lr_item_core with a null production");
039:
040: _the_production = prod;
041:
042: if (pos < 0 || pos > _the_production.rhs_length())
043: throw new internal_error(
044: "Attempt to create an lr_item_core with a bad dot position");
045:
046: _dot_pos = pos;
047:
048: /* compute and cache hash code now */
049: _core_hash_cache = 13 * _the_production.hashCode() + pos;
050:
051: /* cache the symbol after the dot */
052: if (_dot_pos < _the_production.rhs_length()) {
053: part = _the_production.rhs(_dot_pos);
054: if (!part.is_action())
055: _symbol_after_dot = ((symbol_part) part).the_symbol();
056: }
057: }
058:
059: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
060:
061: /** Constructor for dot at start of right hand side.
062: * @param prod production this item uses.
063: */
064: public lr_item_core(production prod) throws internal_error {
065: this (prod, 0);
066: }
067:
068: /*-----------------------------------------------------------*/
069: /*--- (Access to) Instance Variables ------------------------*/
070: /*-----------------------------------------------------------*/
071:
072: /** The production for the item. */
073: protected production _the_production;
074:
075: /** The production for the item. */
076: public production the_production() {
077: return _the_production;
078: }
079:
080: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
081:
082: /** The position of the "dot" -- this indicates the part of the production
083: * that the marker is before, so 0 indicates a dot at the beginning of
084: * the RHS.
085: */
086: protected int _dot_pos;
087:
088: /** The position of the "dot" -- this indicates the part of the production
089: * that the marker is before, so 0 indicates a dot at the beginning of
090: * the RHS.
091: */
092: public int dot_pos() {
093: return _dot_pos;
094: }
095:
096: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
097:
098: /** Cache of the hash code. */
099: protected int _core_hash_cache;
100:
101: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
102:
103: /** Cache of symbol after the dot. */
104: protected symbol _symbol_after_dot = null;
105:
106: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
107:
108: /** Is the dot at the end of the production? */
109: public boolean dot_at_end() {
110: return _dot_pos >= _the_production.rhs_length();
111: }
112:
113: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
114:
115: /** Return the symbol after the dot. If there is no symbol after the dot
116: * we return null. */
117: public symbol symbol_after_dot() {
118: /* use the cached symbol */
119: return _symbol_after_dot;
120: }
121:
122: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
123:
124: /** Determine if we have a dot before a non terminal, and if so which one
125: * (return null or the non terminal).
126: */
127: public non_terminal dot_before_nt() {
128: symbol sym;
129:
130: /* get the symbol after the dot */
131: sym = symbol_after_dot();
132:
133: /* if it exists and is a non terminal, return it */
134: if (sym != null && sym.is_non_term())
135: return (non_terminal) sym;
136: else
137: return null;
138: }
139:
140: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
141:
142: /** Produce a new lr_item_core that results from shifting the dot one
143: * position to the right.
144: */
145: public lr_item_core shift_core() throws internal_error {
146: if (dot_at_end())
147: throw new internal_error(
148: "Attempt to shift past end of an lr_item_core");
149:
150: return new lr_item_core(_the_production, _dot_pos + 1);
151: }
152:
153: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
154:
155: /** Equality comparison for the core only. This is separate out because we
156: * need separate access in a super class.
157: */
158: public boolean core_equals(lr_item_core other) {
159: return other != null
160: && _the_production.equals(other._the_production)
161: && _dot_pos == other._dot_pos;
162: }
163:
164: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
165:
166: /** Equality comparison. */
167: public boolean equals(lr_item_core other) {
168: return core_equals(other);
169: }
170:
171: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
172:
173: /** Generic equality comparison. */
174: public boolean equals(Object other) {
175: if (!(other instanceof lr_item_core))
176: return false;
177: else
178: return equals((lr_item_core) other);
179: }
180:
181: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
182:
183: /** Hash code for the core (separated so we keep non overridden version). */
184: public int core_hashCode() {
185: return _core_hash_cache;
186: }
187:
188: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
189:
190: /** Hash code for the item. */
191: public int hashCode() {
192: return _core_hash_cache;
193: }
194:
195: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
196:
197: /** Return the hash code that object would have provided for us so we have
198: * a (nearly) unique id for debugging.
199: */
200: protected int obj_hash() {
201: return super .hashCode();
202: }
203:
204: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
205:
206: /** Convert to a string (separated out from toString() so we can call it
207: * from subclass that overrides toString()).
208: */
209: public String to_simple_string() throws internal_error {
210: String result;
211: production_part part;
212:
213: if (_the_production.lhs() != null
214: && _the_production.lhs().the_symbol() != null
215: && _the_production.lhs().the_symbol().name() != null)
216: result = _the_production.lhs().the_symbol().name();
217: else
218: result = "$$NULL$$";
219:
220: result += " ::= ";
221:
222: for (int i = 0; i < _the_production.rhs_length(); i++) {
223: /* do we need the dot before this one? */
224: if (i == _dot_pos)
225: result += "(*) ";
226:
227: /* print the name of the part */
228: if (_the_production.rhs(i) == null) {
229: result += "$$NULL$$ ";
230: } else {
231: part = _the_production.rhs(i);
232: if (part == null)
233: result += "$$NULL$$ ";
234: else if (part.is_action())
235: result += "{ACTION} ";
236: else if (((symbol_part) part).the_symbol() != null
237: && ((symbol_part) part).the_symbol().name() != null)
238: result += ((symbol_part) part).the_symbol().name()
239: + " ";
240: else
241: result += "$$NULL$$ ";
242: }
243: }
244:
245: /* put the dot after if needed */
246: if (_dot_pos == _the_production.rhs_length())
247: result += "(*) ";
248:
249: return result;
250: }
251:
252: /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
253:
254: /** Convert to a string */
255: public String toString() {
256: /* can't throw here since super class doesn't, so we crash instead */
257: try {
258: return to_simple_string();
259: } catch (internal_error e) {
260: e.crash();
261: return null;
262: }
263: }
264:
265: /*-----------------------------------------------------------*/
266:
267: }
|