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