| package java_cup; |
| |
| import java.util.Stack; |
| |
| /** This class represents an LALR item. Each LALR item consists of |
| * a production, a "dot" at a position within that production, and |
| * a set of lookahead symbols (terminal). (The first two of these parts |
| * are provide by the super class). An item is designed to represent a |
| * configuration that the parser may be in. For example, an item of the |
| * form: <pre> |
| * [A ::= B * C d E , {a,b,c}] |
| * </pre> |
| * indicates that the parser is in the middle of parsing the production <pre> |
| * A ::= B C d E |
| * </pre> |
| * that B has already been parsed, and that we will expect to see a lookahead |
| * of either a, b, or c once the complete RHS of this production has been |
| * found.<p> |
| * |
| * Items may initially be missing some items from their lookahead sets. |
| * Links are maintained from each item to the set of items that would need |
| * to be updated if symbols are added to its lookahead set. During |
| * "lookahead propagation", we add symbols to various lookahead sets and |
| * propagate these changes across these dependency links as needed. |
| * |
| * @see java_cup.lalr_item_set |
| * @see java_cup.lalr_state |
| * @version last updated: 11/25/95 |
| * @author Scott Hudson |
| */ |
| public class lalr_item extends lr_item_core { |
| |
| /*-----------------------------------------------------------*/ |
| /*--- Constructor(s) ----------------------------------------*/ |
| /*-----------------------------------------------------------*/ |
| |
| /** Full constructor. |
| * @param prod the production for the item. |
| * @param pos the position of the "dot" within the production. |
| * @param look the set of lookahead symbols. |
| */ |
| public lalr_item(production prod, int pos, terminal_set look) |
| throws internal_error |
| { |
| super(prod, pos); |
| _lookahead = look; |
| _propagate_items = new Stack(); |
| needs_propagation = true; |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Constructor with default position (dot at start). |
| * @param prod the production for the item. |
| * @param look the set of lookahead symbols. |
| */ |
| public lalr_item(production prod, terminal_set look) throws internal_error |
| { |
| this(prod,0,look); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Constructor with default position and empty lookahead set. |
| * @param prod the production for the item. |
| */ |
| public lalr_item(production prod) throws internal_error |
| { |
| this(prod,0,new terminal_set()); |
| } |
| |
| /*-----------------------------------------------------------*/ |
| /*--- (Access to) Instance Variables ------------------------*/ |
| /*-----------------------------------------------------------*/ |
| |
| /** The lookahead symbols of the item. */ |
| protected terminal_set _lookahead; |
| |
| /** The lookahead symbols of the item. */ |
| public terminal_set lookahead() {return _lookahead;}; |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Links to items that the lookahead needs to be propagated to. */ |
| protected Stack _propagate_items; |
| |
| /** Links to items that the lookahead needs to be propagated to */ |
| public Stack propagate_items() {return _propagate_items;} |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Flag to indicate that this item needs to propagate its lookahead |
| * (whether it has changed or not). |
| */ |
| protected boolean needs_propagation; |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Add a new item to the set of items we propagate to. */ |
| public void add_propagate(lalr_item prop_to) |
| { |
| _propagate_items.push(prop_to); |
| needs_propagation = true; |
| } |
| |
| /*-----------------------------------------------------------*/ |
| /*--- General Methods ---------------------------------------*/ |
| /*-----------------------------------------------------------*/ |
| |
| /** Propagate incoming lookaheads through this item to others need to |
| * be changed. |
| * @params incoming symbols to potentially be added to lookahead of this item. |
| */ |
| public void propagate_lookaheads(terminal_set incoming) throws internal_error |
| { |
| boolean change = false; |
| |
| /* if we don't need to propagate, then bail out now */ |
| if (!needs_propagation && (incoming == null || incoming.empty())) |
| return; |
| |
| /* if we have null incoming, treat as an empty set */ |
| if (incoming != null) |
| { |
| /* add the incoming to the lookahead of this item */ |
| change = lookahead().add(incoming); |
| } |
| |
| /* if we changed or need it anyway, propagate across our links */ |
| if (change || needs_propagation) |
| { |
| /* don't need to propagate again */ |
| needs_propagation = false; |
| |
| /* propagate our lookahead into each item we are linked to */ |
| for (int i = 0; i < propagate_items().size(); i++) |
| ((lalr_item)propagate_items().elementAt(i)) |
| .propagate_lookaheads(lookahead()); |
| } |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Produce the new lalr_item that results from shifting the dot one position |
| * to the right. |
| */ |
| public lalr_item shift() throws internal_error |
| { |
| lalr_item result; |
| |
| /* can't shift if we have dot already at the end */ |
| if (dot_at_end()) |
| throw new internal_error("Attempt to shift past end of an lalr_item"); |
| |
| /* create the new item w/ the dot shifted by one */ |
| result = new lalr_item(the_production(), dot_pos()+1, |
| new terminal_set(lookahead())); |
| |
| /* change in our lookahead needs to be propagated to this item */ |
| add_propagate(result); |
| |
| return result; |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Calculate lookahead representing symbols that could appear after the |
| * symbol that the dot is currently in front of. Note: this routine must |
| * not be invoked before first sets and nullability has been calculated |
| * for all non terminals. |
| */ |
| public terminal_set calc_lookahead(terminal_set lookahead_after) |
| throws internal_error |
| { |
| terminal_set result; |
| int pos; |
| production_part part; |
| symbol sym; |
| |
| /* sanity check */ |
| if (dot_at_end()) |
| throw new internal_error( |
| "Attempt to calculate a lookahead set with a completed item"); |
| |
| /* start with an empty result */ |
| result = new terminal_set(); |
| |
| /* consider all nullable symbols after the one to the right of the dot */ |
| for (pos = dot_pos()+1; pos < the_production().rhs_length(); pos++) |
| { |
| part = the_production().rhs(pos); |
| |
| /* consider what kind of production part it is -- skip actions */ |
| if (!part.is_action()) |
| { |
| sym = ((symbol_part)part).the_symbol(); |
| |
| /* if its a terminal add it in and we are done */ |
| if (!sym.is_non_term()) |
| { |
| result.add((terminal)sym); |
| return result; |
| } |
| else |
| { |
| /* otherwise add in first set of the non terminal */ |
| result.add(((non_terminal)sym).first_set()); |
| |
| /* if its nullable we continue adding, if not, we are done */ |
| if (!((non_terminal)sym).nullable()) |
| return result; |
| } |
| } |
| } |
| |
| /* if we get here everything past the dot was nullable |
| we add in the lookahead for after the production and we are done */ |
| result.add(lookahead_after); |
| return result; |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Determine if everything from the symbol one beyond the dot all the |
| * way to the end of the right hand side is nullable. This would indicate |
| * that the lookahead of this item must be included in the lookaheads of |
| * all items produced as a closure of this item. Note: this routine should |
| * not be invoked until after first sets and nullability have been |
| * calculated for all non terminals. |
| */ |
| public boolean lookahead_visible() throws internal_error |
| { |
| production_part part; |
| symbol sym; |
| |
| /* if the dot is at the end, we have a problem, but the cleanest thing |
| to do is just return true. */ |
| if (dot_at_end()) return true; |
| |
| /* walk down the rhs and bail if we get a non-nullable symbol */ |
| for (int pos = dot_pos() + 1; pos < the_production().rhs_length(); pos++) |
| { |
| part = the_production().rhs(pos); |
| |
| /* skip actions */ |
| if (!part.is_action()) |
| { |
| sym = ((symbol_part)part).the_symbol(); |
| |
| /* if its a terminal we fail */ |
| if (!sym.is_non_term()) return false; |
| |
| /* if its not nullable we fail */ |
| if (!((non_terminal)sym).nullable()) return false; |
| } |
| } |
| |
| /* if we get here its all nullable */ |
| return true; |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Equality comparison -- here we only require the cores to be equal since |
| * we need to do sets of items based only on core equality (ignoring |
| * lookahead sets). |
| */ |
| public boolean equals(lalr_item other) |
| { |
| if (other == null) return false; |
| return super.equals(other); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Generic equality comparison. */ |
| public boolean equals(Object other) |
| { |
| if (!(other instanceof lalr_item)) |
| return false; |
| else |
| return equals((lalr_item)other); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Return a hash code -- here we only hash the core since we only test core |
| * matching in LALR items. |
| */ |
| public int hashCode() |
| { |
| return super.hashCode(); |
| } |
| |
| /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/ |
| |
| /** Convert to string. */ |
| public String toString() |
| { |
| String result = ""; |
| |
| // additional output for debugging: |
| // result += "(" + hashCode() + ")"; |
| result += "["; |
| result += super.toString(); |
| result += ", "; |
| if (lookahead() != null) |
| { |
| result += "{"; |
| for (int t = 0; t < terminal.number(); t++) |
| if (lookahead().contains(t)) |
| result += terminal.find(t).name() + " "; |
| result += "}"; |
| } |
| else |
| result += "NULL LOOKAHEAD!!"; |
| result += "]"; |
| |
| // additional output for debugging: |
| // result += " -> "; |
| // for (int i = 0; i<propagate_items().size(); i++) |
| // result += propagate_items().elementAt(i).hashCode() + " "; |
| // |
| // if (needs_propagation) result += " NP"; |
| |
| return result; |
| } |
| /*-----------------------------------------------------------*/ |
| }; |