|
package java_cup;
|
|
/** The "core" of an LR item. This includes a production and the position
|
* of a marker (the "dot") within the production. Typically item cores
|
* are written using a production with an embedded "dot" to indicate their
|
* position. For example: <pre>
|
* A ::= B * C d E
|
* </pre>
|
* This represents a point in a parse where the parser is trying to match
|
* the given production, and has succeeded in matching everything before the
|
* "dot" (and hence is expecting to see the symbols after the dot next). See
|
* lalr_item, lalr_item_set, and lalr_start for full details on the meaning
|
* and use of items.
|
*
|
* @see java_cup.lalr_item
|
* @see java_cup.lalr_item_set
|
* @see java_cup.lalr_state
|
* @version last updated: 11/25/95
|
* @author Scott Hudson
|
*/
|
|
public class lr_item_core {
|
|
/*-----------------------------------------------------------*/
|
/*--- Constructor(s) ----------------------------------------*/
|
/*-----------------------------------------------------------*/
|
|
/** Full constructor.
|
* @param prod production this item uses.
|
* @param pos position of the "dot" within the item.
|
*/
|
public lr_item_core(production prod, int pos) throws internal_error
|
{
|
symbol after_dot = null;
|
production_part part;
|
|
if (prod == null)
|
throw new internal_error(
|
"Attempt to create an lr_item_core with a null production");
|
|
_the_production = prod;
|
|
if (pos < 0 || pos > _the_production.rhs_length())
|
throw new internal_error(
|
"Attempt to create an lr_item_core with a bad dot position");
|
|
_dot_pos = pos;
|
|
/* compute and cache hash code now */
|
_core_hash_cache = 13*_the_production.hashCode() + pos;
|
|
/* cache the symbol after the dot */
|
if (_dot_pos < _the_production.rhs_length())
|
{
|
part = _the_production.rhs(_dot_pos);
|
if (!part.is_action())
|
_symbol_after_dot = ((symbol_part)part).the_symbol();
|
}
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Constructor for dot at start of right hand side.
|
* @param prod production this item uses.
|
*/
|
public lr_item_core(production prod) throws internal_error
|
{
|
this(prod,0);
|
}
|
|
/*-----------------------------------------------------------*/
|
/*--- (Access to) Instance Variables ------------------------*/
|
/*-----------------------------------------------------------*/
|
|
/** The production for the item. */
|
protected production _the_production;
|
|
/** The production for the item. */
|
public production the_production() {return _the_production;}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** The position of the "dot" -- this indicates the part of the production
|
* that the marker is before, so 0 indicates a dot at the beginning of
|
* the RHS.
|
*/
|
protected int _dot_pos;
|
|
/** The position of the "dot" -- this indicates the part of the production
|
* that the marker is before, so 0 indicates a dot at the beginning of
|
* the RHS.
|
*/
|
public int dot_pos() {return _dot_pos;}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Cache of the hash code. */
|
protected int _core_hash_cache;
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Cache of symbol after the dot. */
|
protected symbol _symbol_after_dot = null;
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Is the dot at the end of the production? */
|
public boolean dot_at_end()
|
{
|
return _dot_pos >= _the_production.rhs_length();
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Return the symbol after the dot. If there is no symbol after the dot
|
* we return null. */
|
public symbol symbol_after_dot()
|
{
|
/* use the cached symbol */
|
return _symbol_after_dot;
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Determine if we have a dot before a non terminal, and if so which one
|
* (return null or the non terminal).
|
*/
|
public non_terminal dot_before_nt()
|
{
|
symbol sym;
|
|
/* get the symbol after the dot */
|
sym = symbol_after_dot();
|
|
/* if it exists and is a non terminal, return it */
|
if (sym != null && sym.is_non_term())
|
return (non_terminal)sym;
|
else
|
return null;
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Produce a new lr_item_core that results from shifting the dot one
|
* position to the right.
|
*/
|
public lr_item_core shift_core() throws internal_error
|
{
|
if (dot_at_end())
|
throw new internal_error(
|
"Attempt to shift past end of an lr_item_core");
|
|
return new lr_item_core(_the_production, _dot_pos+1);
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Equality comparison for the core only. This is separate out because we
|
* need separate access in a super class.
|
*/
|
public boolean core_equals(lr_item_core other)
|
{
|
return other != null &&
|
_the_production.equals(other._the_production) &&
|
_dot_pos == other._dot_pos;
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Equality comparison. */
|
public boolean equals(lr_item_core other) {return core_equals(other);}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Generic equality comparison. */
|
public boolean equals(Object other)
|
{
|
if (!(other instanceof lr_item_core))
|
return false;
|
else
|
return equals((lr_item_core)other);
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Hash code for the core (separated so we keep non overridden version). */
|
public int core_hashCode()
|
{
|
return _core_hash_cache;
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Hash code for the item. */
|
public int hashCode()
|
{
|
return _core_hash_cache;
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Convert to a string (separated out from toString() so we can call it
|
* from subclass that overrides toString()).
|
*/
|
public String to_simple_string() throws internal_error
|
{
|
String result;
|
production_part part;
|
|
if (_the_production.lhs() != null &&
|
_the_production.lhs().the_symbol() != null &&
|
_the_production.lhs().the_symbol().name() != null)
|
result = _the_production.lhs().the_symbol().name();
|
else
|
result = "$$NULL$$";
|
|
result += " ::= ";
|
|
for (int i = 0; i<_the_production.rhs_length(); i++)
|
{
|
/* do we need the dot before this one? */
|
if (i == _dot_pos)
|
result += "(*) ";
|
|
/* print the name of the part */
|
if (_the_production.rhs(i) == null)
|
{
|
result += "$$NULL$$ ";
|
}
|
else
|
{
|
part = _the_production.rhs(i);
|
if (part == null)
|
result += "$$NULL$$ ";
|
else if (part.is_action())
|
result += "{ACTION} ";
|
else if (((symbol_part)part).the_symbol() != null &&
|
((symbol_part)part).the_symbol().name() != null)
|
result += ((symbol_part)part).the_symbol().name() + " ";
|
else
|
result += "$$NULL$$ ";
|
}
|
}
|
|
/* put the dot after if needed */
|
if (_dot_pos == _the_production.rhs_length())
|
result += "(*) ";
|
|
return result;
|
}
|
|
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
|
|
/** Convert to a string */
|
public String toString()
|
{
|
/* can't throw here since super class doesn't, so we crash instead */
|
try {
|
return to_simple_string();
|
} catch(internal_error e) {
|
e.crash();
|
return null;
|
}
|
}
|
|
/*-----------------------------------------------------------*/
|
|
};
|
|