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
*/
@SuppressWarnings (
{ "all", "unchecked" } )
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.
*
* @param 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 += "(" + obj_hash() + ")";
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+=((lalr_item)(propagate_items().elementAt(i))).obj_hash()+" ";
//
// if (needs_propagation) result += " NP";
return result;
}
/*-----------------------------------------------------------*/
}