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