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 += "(" + 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 ;
}
/*-----------------------------------------------------------*/
}