package java_cup; import java.util.Enumeration; import java.util.Hashtable; import java.util.Stack; /** * This class represents a state in the LALR viable prefix recognition machine. * A state consists of an LALR item set and a set of transitions to other states * under terminal and non-terminal symbols. Each state represents a potential * configuration of the parser. If the item set of a state includes an item such * as: * * <pre> * [A ::= B * C d E , {a,b,c}] * </pre> * * this indicates that when the parser is in this state it is currently looking * for an A of the given form, has already seen the B, and would expect to see * an a, b, or c after this sequence is complete. Note that the parser is * normally looking for several things at once (represented by several items). * In our example above, the state would also include items such as: * * <pre> * [C ::= * X e Z, {d}] * [X ::= * f, {e}] * </pre> * * to indicate that it was currently looking for a C followed by a d (which * would be reduced into a C, matching the first symbol in our production * above), and the terminal f followed by e. * <p> * At runtime, the parser uses a viable prefix recognition machine made up of * these states to parse. The parser has two operations, shift and reduce. In a * shift, it consumes one Symbol and makes a transition to a new state. This * corresponds to "moving the dot past" a terminal in one or more items in the * state (these new shifted items will then be found in the state at the end of * the transition). For a reduce operation, the parser is signifying that it is * recognizing the RHS of some production. To do this it first "backs up" by * popping a stack of previously saved states. It pops off the same number of * states as are found in the RHS of the production. This leaves the machine in * the same state is was in when the parser first attempted to find the RHS. * From this state it makes a transition based on the non-terminal on the LHS of * the production. This corresponds to placing the parse in a configuration * equivalent to having replaced all the symbols from the the input * corresponding to the RHS with the symbol on the LHS. * * @see java_cup.lalr_item * @see java_cup.lalr_item_set * @see java_cup.lalr_transition * @version last updated: 7/3/96 * @author Frank Flannery */ @SuppressWarnings ( { "all", "unchecked" } ) public class lalr_state { /*-----------------------------------------------------------*/ /*--- Constructor(s) ----------------------------------------*/ /*-----------------------------------------------------------*/ /** * Constructor for building a state from a set of items. * * @param itms the set of items that makes up this state. */ public lalr_state ( lalr_item_set itms ) throws internal_error { /* don't allow null or duplicate item sets */ if ( itms == null ) throw new internal_error ( "Attempt to construct an LALR state from a null item set" ); if ( find_state ( itms ) != null ) throw new internal_error ( "Attempt to construct a duplicate LALR state" ); /* assign a unique index */ _index = next_index++ ; /* store the items */ _items = itms; /* add to the global collection, keyed with its item set */ _all.put ( _items, this ); } /*-----------------------------------------------------------*/ /*--- (Access to) Static (Class) Variables ------------------*/ /*-----------------------------------------------------------*/ /** Collection of all states. */ protected static Hashtable _all = new Hashtable (); /** Collection of all states. */ public static Enumeration all () { return _all.elements (); } // Hm Added clear to clear all static fields public static void clear () { _all.clear (); _all_kernels.clear (); next_index = 0; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Indicate total number of states there are. */ public static int number () { return _all.size (); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Hash table to find states by their kernels (i.e, the original, unclosed, * set of items -- which uniquely define the state). This table stores state * objects using (a copy of) their kernel item sets as keys. */ protected static Hashtable _all_kernels = new Hashtable (); /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Find and return state with a given a kernel item set (or null if not * found). The kernel item set is the subset of items that were used to * originally create the state. These items are formed by "shifting the dot" * within items of other states that have a transition to this one. The * remaining elements of this state's item set are added during closure. * * @param itms the kernel set of the state we are looking for. */ public static lalr_state find_state ( lalr_item_set itms ) { if ( itms == null ) return null; else return ( lalr_state ) _all.get ( itms ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Static counter for assigning unique state indexes. */ protected static int next_index = 0; /*-----------------------------------------------------------*/ /*--- (Access to) Instance Variables ------------------------*/ /*-----------------------------------------------------------*/ /** The item set for this state. */ protected lalr_item_set _items; /** The item set for this state. */ public lalr_item_set items () { return _items; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** List of transitions out of this state. */ protected lalr_transition _transitions = null; /** List of transitions out of this state. */ public lalr_transition transitions () { return _transitions; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Index of this state in the parse tables */ protected int _index; /** Index of this state in the parse tables */ public int index () { return _index; } /*-----------------------------------------------------------*/ /*--- Static Methods ----------------------------------------*/ /*-----------------------------------------------------------*/ /** * Helper routine for debugging -- produces a dump of the given state onto * System.out. */ protected static void dump_state ( lalr_state st ) throws internal_error { lalr_item_set itms; lalr_item itm; production_part part; if ( st == null ) { System.out.println ( "NULL lalr_state" ); return; } System.out.println ( "lalr_state [" + st.index () + "] {" ); itms = st.items (); for ( Enumeration e = itms.all () ; e.hasMoreElements () ; ) { itm = ( lalr_item ) e.nextElement (); System.out.print ( " [" ); System.out.print ( itm.the_production ().lhs ().the_symbol ().name () ); System.out.print ( " ::= " ); for ( int i = 0 ; i < itm.the_production ().rhs_length () ; i++ ) { if ( i == itm.dot_pos () ) System.out.print ( "(*) " ); part = itm.the_production ().rhs ( i ); if ( part.is_action () ) System.out.print ( "{action} " ); else System.out.print ( ( ( symbol_part ) part ).the_symbol ().name () + " " ); } if ( itm.dot_at_end () ) System.out.print ( "(*) " ); System.out.println ( "]" ); } System.out.println ( "}" ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Propagate lookahead sets through the constructed viable prefix recognizer. * When the machine is constructed, each item that results in the creation of * another such that its lookahead is included in the other's will have a * propagate link set up for it. This allows additions to the lookahead of one * item to be included in other items that it was used to directly or * indirectly create. */ protected static void propagate_all_lookaheads () throws internal_error { /* iterate across all states */ for ( Enumeration st = all () ; st.hasMoreElements () ; ) { /* propagate lookaheads out of that state */ ( ( lalr_state ) st.nextElement () ).propagate_lookaheads (); } } /*-----------------------------------------------------------*/ /*--- General Methods ---------------------------------------*/ /*-----------------------------------------------------------*/ /** * Add a transition out of this state to another. * * @param on_sym the symbol the transition is under. * @param to_st the state the transition goes to. */ public void add_transition ( symbol on_sym, lalr_state to_st ) throws internal_error { lalr_transition trans; /* create a new transition object and put it in our list */ trans = new lalr_transition ( on_sym, to_st, _transitions ); _transitions = trans; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Build an LALR viable prefix recognition machine given a start production. * This method operates by first building a start state from the start * production (based on a single item with the dot at the beginning and EOF as * expected lookahead). Then for each state it attempts to extend the machine * by creating transitions out of the state to new or existing states. When * considering extension from a state we make a transition on each symbol that * appears before the dot in some item. For example, if we have the items: * * <pre> * [A ::= a b * X c, {d,e}] * [B ::= a b * X d, {a,b}] * </pre> * * in some state, then we would be making a transition under X to a new state. * This new state would be formed by a "kernel" of items corresponding to * moving the dot past the X. In this case: * * <pre> * [A ::= a b X * c, {d,e}] * [B ::= a b X * Y, {a,b}] * </pre> * * The full state would then be formed by "closing" this kernel set of items * so that it included items that represented productions of things the parser * was now looking for. In this case we would items corresponding to * productions of Y, since various forms of Y are expected next when in this * state (see lalr_item_set.compute_closure() for details on closure). * <p> * The process of building the viable prefix recognizer terminates when no new * states can be added. However, in order to build a smaller number of states * (i.e., corresponding to LALR rather than canonical LR) the state building * process does not maintain full loookaheads in all items. Consequently, * after the machine is built, we go back and propagate lookaheads through the * constructed machine using a call to propagate_all_lookaheads(). This makes * use of propagation links constructed during the closure and transition * process. * * @param start_prod the start production of the grammar * @see java_cup.lalr_item_set#compute_closure * @see java_cup.lalr_state#propagate_all_lookaheads */ public static lalr_state build_machine ( production start_prod ) throws internal_error { lalr_state start_state; lalr_item_set start_items; lalr_item_set new_items; lalr_item_set linked_items; lalr_item_set kernel; Stack work_stack = new Stack (); lalr_state st, new_st; symbol_set outgoing; lalr_item itm, new_itm, existing, fix_itm; symbol sym, sym2; Enumeration i, s, fix; /* sanity check */ if ( start_prod == null ) throw new internal_error ( "Attempt to build viable prefix recognizer using a null production" ); /* build item with dot at front of start production and EOF lookahead */ start_items = new lalr_item_set (); itm = new lalr_item ( start_prod ); itm.lookahead ().add ( terminal.EOF ); start_items.add ( itm ); /* create copy the item set to form the kernel */ kernel = new lalr_item_set ( start_items ); /* create the closure from that item set */ start_items.compute_closure (); /* build a state out of that item set and put it in our work set */ start_state = new lalr_state ( start_items ); work_stack.push ( start_state ); /* enter the state using the kernel as the key */ _all_kernels.put ( kernel, start_state ); /* continue looking at new states until we have no more work to do */ while ( !work_stack.empty () ) { /* remove a state from the work set */ st = ( lalr_state ) work_stack.pop (); /* gather up all the symbols that appear before dots */ outgoing = new symbol_set (); for ( i = st.items ().all () ; i.hasMoreElements () ; ) { itm = ( lalr_item ) i.nextElement (); /* add the symbol before the dot (if any) to our collection */ sym = itm.symbol_after_dot (); if ( sym != null ) outgoing.add ( sym ); } /* now create a transition out for each individual symbol */ for ( s = outgoing.all () ; s.hasMoreElements () ; ) { sym = ( symbol ) s.nextElement (); /* will be keeping the set of items with propagate links */ linked_items = new lalr_item_set (); /* * gather up shifted versions of all the items that have this symbol * before the dot */ new_items = new lalr_item_set (); for ( i = st.items ().all () ; i.hasMoreElements () ; ) { itm = ( lalr_item ) i.nextElement (); /* if this is the symbol we are working on now, add to set */ sym2 = itm.symbol_after_dot (); if ( sym.equals ( sym2 ) ) { /* add to the kernel of the new state */ new_items.add ( itm.shift () ); /* remember that itm has propagate link to it */ linked_items.add ( itm ); } } /* use new items as state kernel */ kernel = new lalr_item_set ( new_items ); /* have we seen this one already? */ new_st = ( lalr_state ) _all_kernels.get ( kernel ); /* if we haven't, build a new state out of the item set */ if ( new_st == null ) { /* compute closure of the kernel for the full item set */ new_items.compute_closure (); /* build the new state */ new_st = new lalr_state ( new_items ); /* add the new state to our work set */ work_stack.push ( new_st ); /* put it in our kernel table */ _all_kernels.put ( kernel, new_st ); } /* otherwise relink propagation to items in existing state */ else { /* walk through the items that have links to the new state */ for ( fix = linked_items.all () ; fix.hasMoreElements () ; ) { fix_itm = ( lalr_item ) fix.nextElement (); /* look at each propagate link out of that item */ for ( int l = 0 ; l < fix_itm.propagate_items ().size () ; l++ ) { /* pull out item linked to in the new state */ new_itm = ( lalr_item ) fix_itm.propagate_items ().elementAt ( l ); /* find corresponding item in the existing state */ existing = new_st.items ().find ( new_itm ); /* fix up the item so it points to the existing set */ if ( existing != null ) fix_itm.propagate_items ().setElementAt ( existing, l ); } } } /* add a transition from current state to that state */ st.add_transition ( sym, new_st ); } } /* all done building states */ /* propagate complete lookahead sets throughout the states */ propagate_all_lookaheads (); return start_state; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Propagate lookahead sets out of this state. This recursively propagates to * all items that have propagation links from some item in this state. */ protected void propagate_lookaheads () throws internal_error { /* recursively propagate out from each item in the state */ for ( Enumeration itm = items ().all () ; itm.hasMoreElements () ; ) ( ( lalr_item ) itm.nextElement () ).propagate_lookaheads ( null ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Fill in the parse table entries for this state. There are two parse tables * that encode the viable prefix recognition machine, an action table and a * reduce-goto table. The rows in each table correspond to states of the * machine. The columns of the action table are indexed by terminal symbols * and correspond to either transitions out of the state (shift entries) or * reductions from the state to some previous state saved on the stack (reduce * entries). All entries in the action table that are not shifts or reduces, * represent errors. The reduce-goto table is indexed by non terminals and * represents transitions out of a state on that non-terminal. * <p> * Conflicts occur if more than one action needs to go in one entry of the * action table (this cannot happen with the reduce-goto table). Conflicts are * resolved by always shifting for shift/reduce conflicts and choosing the * lowest numbered production (hence the one that appeared first in the * specification) in reduce/reduce conflicts. All conflicts are reported and * if more conflicts are detected than were declared by the user, code * generation is aborted. * * @param act_table the action table to put entries in. * @param reduce_table the reduce-goto table to put entries in. */ public void build_table_entries ( parse_action_table act_table, parse_reduce_table reduce_table ) throws internal_error { parse_action_row our_act_row; parse_reduce_row our_red_row; lalr_item itm; parse_action act, other_act; symbol sym; terminal_set conflict_set = new terminal_set (); /* pull out our rows from the tables */ our_act_row = act_table.under_state [ index () ]; our_red_row = reduce_table.under_state [ index () ]; /* consider each item in our state */ for ( Enumeration i = items ().all () ; i.hasMoreElements () ; ) { itm = ( lalr_item ) i.nextElement (); /* if its completed (dot at end) then reduce under the lookahead */ if ( itm.dot_at_end () ) { act = new reduce_action ( itm.the_production () ); /* consider each lookahead symbol */ for ( int t = 0 ; t < terminal.number () ; t++ ) { /* skip over the ones not in the lookahead */ if ( !itm.lookahead ().contains ( t ) ) continue; /* if we don't already have an action put this one in */ if ( our_act_row.under_term [ t ].kind () == parse_action.ERROR ) { our_act_row.under_term [ t ] = act; } else { /* we now have at least one conflict */ terminal term = terminal.find ( t ); other_act = our_act_row.under_term [ t ]; /* if the other act was not a shift */ if ( ( other_act.kind () != parse_action.SHIFT ) && ( other_act.kind () != parse_action.NONASSOC ) ) { /* if we have lower index hence priority, replace it */ if ( itm.the_production ().index () < ( ( reduce_action ) other_act ) .reduce_with ().index () ) { /* replace the action */ our_act_row.under_term [ t ] = act; } } else { /* Check precedences,see if problem is correctable */ if ( fix_with_precedence ( itm.the_production (), t, our_act_row, act ) ) { term = null; } } if ( term != null ) { conflict_set.add ( term ); } } } } } /* consider each outgoing transition */ for ( lalr_transition trans = transitions () ; trans != null ; trans = trans .next () ) { /* if its on an terminal add a shift entry */ sym = trans.on_symbol (); if ( !sym.is_non_term () ) { act = new shift_action ( trans.to_state () ); /* if we don't already have an action put this one in */ if ( our_act_row.under_term [ sym.index () ].kind () == parse_action.ERROR ) { our_act_row.under_term [ sym.index () ] = act; } else { /* we now have at least one conflict */ production p = ( ( reduce_action ) our_act_row.under_term [ sym .index () ] ).reduce_with (); /* shift always wins */ if ( !fix_with_precedence ( p, sym.index (), our_act_row, act ) ) { our_act_row.under_term [ sym.index () ] = act; conflict_set.add ( terminal.find ( sym.index () ) ); } } } else { /* for non terminals add an entry to the reduce-goto table */ our_red_row.under_non_term [ sym.index () ] = trans.to_state (); } } /* if we end up with conflict(s), report them */ if ( !conflict_set.empty () ) report_conflicts ( conflict_set ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Procedure that attempts to fix a shift/reduce error by using precedences. * --frankf 6/26/96 if a production (also called rule) or the lookahead * terminal has a precedence, then the table can be fixed. if the rule has * greater precedence than the terminal, a reduce by that rule in inserted in * the table. If the terminal has a higher precedence, it is shifted. if they * have equal precedence, then the associativity of the precedence is used to * determine what to put in the table: if the precedence is left associative, * the action is to reduce. if the precedence is right associative, the action * is to shift. if the precedence is non associative, then it is a syntax * error. * * @param p the production * @param term_index the index of the lokahead terminal * @param table_row a row of the action table * @param act the rule in conflict with the table entry */ protected boolean fix_with_precedence ( production p, int term_index, parse_action_row table_row, parse_action act ) throws internal_error { terminal term = terminal.find ( term_index ); /* if the production has a precedence number, it can be fixed */ if ( p.precedence_num () > assoc.no_prec ) { /* if production precedes terminal, put reduce in table */ if ( p.precedence_num () > term.precedence_num () ) { table_row.under_term [ term_index ] = insert_reduce ( table_row.under_term [ term_index ], act ); return true; } /* if terminal precedes rule, put shift in table */ else if ( p.precedence_num () < term.precedence_num () ) { table_row.under_term [ term_index ] = insert_shift ( table_row.under_term [ term_index ], act ); return true; } else { /* they are == precedence */ /* * equal precedences have equal sides, so only need to look at one: if * it is right, put shift in table */ if ( term.precedence_side () == assoc.right ) { table_row.under_term [ term_index ] = insert_shift ( table_row.under_term [ term_index ], act ); return true; } /* if it is left, put reduce in table */ else if ( term.precedence_side () == assoc.left ) { table_row.under_term [ term_index ] = insert_reduce ( table_row.under_term [ term_index ], act ); return true; } /* * if it is nonassoc, we're not allowed to have two nonassocs of equal * precedence in a row, so put in NONASSOC */ else if ( term.precedence_side () == assoc.nonassoc ) { table_row.under_term [ term_index ] = new nonassoc_action (); return true; } else { /* something really went wrong */ throw new internal_error ( "Unable to resolve conflict correctly" ); } } } /* * check if terminal has precedence, if so, shift, since rule does not have * precedence */ else if ( term.precedence_num () > assoc.no_prec ) { table_row.under_term [ term_index ] = insert_shift ( table_row.under_term [ term_index ], act ); return true; } /* * otherwise, neither the rule nor the terminal has a precedence, so it * can't be fixed. */ return false; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /* * given two actions, and an action type, return the action of that action * type. give an error if they are of the same action, because that should * never have tried to be fixed */ protected parse_action insert_action ( parse_action a1, parse_action a2, int act_type ) throws internal_error { if ( ( a1.kind () == act_type ) && ( a2.kind () == act_type ) ) { throw new internal_error ( "Conflict resolution of bogus actions" ); } else if ( a1.kind () == act_type ) { return a1; } else if ( a2.kind () == act_type ) { return a2; } else { throw new internal_error ( "Conflict resolution of bogus actions" ); } } /* find the shift in the two actions */ protected parse_action insert_shift ( parse_action a1, parse_action a2 ) throws internal_error { return insert_action ( a1, a2, parse_action.SHIFT ); } /* find the reduce in the two actions */ protected parse_action insert_reduce ( parse_action a1, parse_action a2 ) throws internal_error { return insert_action ( a1, a2, parse_action.REDUCE ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Produce warning messages for all conflicts found in this state. */ protected void report_conflicts ( terminal_set conflict_set ) throws internal_error { lalr_item itm, compare; symbol shift_sym; boolean after_itm; /* consider each element */ for ( Enumeration itms = items ().all () ; itms.hasMoreElements () ; ) { itm = ( lalr_item ) itms.nextElement (); /* clear the S/R conflict set for this item */ /* if it results in a reduce, it could be a conflict */ if ( itm.dot_at_end () ) { /* not yet after itm */ after_itm = false; /* compare this item against all others looking for conflicts */ for ( Enumeration comps = items ().all () ; comps.hasMoreElements () ; ) { compare = ( lalr_item ) comps.nextElement (); /* if this is the item, next one is after it */ if ( itm == compare ) after_itm = true; /* only look at it if its not the same item */ if ( itm != compare ) { /* is it a reduce */ if ( compare.dot_at_end () ) { /* only look at reduces after itm */ if ( after_itm ) /* does the comparison item conflict? */ if ( compare.lookahead ().intersects ( itm.lookahead () ) ) /* report a reduce/reduce conflict */ report_reduce_reduce ( itm, compare ); } } } /* report S/R conflicts under all the symbols we conflict under */ for ( int t = 0 ; t < terminal.number () ; t++ ) if ( conflict_set.contains ( t ) ) report_shift_reduce ( itm, t ); } } } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Produce a warning message for one reduce/reduce conflict. * * @param itm1 first item in conflict. * @param itm2 second item in conflict. */ protected void report_reduce_reduce ( lalr_item itm1, lalr_item itm2 ) throws internal_error { boolean comma_flag = false; String message = "*** Reduce/Reduce conflict found in state #" + index () + "\n" + " between " + itm1.to_simple_string () + "\n" + " and " + itm2.to_simple_string () + "\n" + " under symbols: {"; for ( int t = 0 ; t < terminal.number () ; t++ ) { if ( itm1.lookahead ().contains ( t ) && itm2.lookahead ().contains ( t ) ) { if ( comma_flag ) message += ( ", " ); else comma_flag = true; message += ( terminal.find ( t ).name () ); } } message += "}\n Resolved in favor of "; if ( itm1.the_production ().index () < itm2.the_production ().index () ) message += "the first production.\n"; else message += "the second production.\n"; /* count the conflict */ emit.num_conflicts++ ; ErrorManager.getManager ().emit_warning ( message ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Produce a warning message for one shift/reduce conflict. * * @param red_itm the item with the reduce. * @param conflict_sym the index of the symbol conflict occurs under. */ protected void report_shift_reduce ( lalr_item red_itm, int conflict_sym ) throws internal_error { lalr_item itm; symbol shift_sym; /* emit top part of message including the reduce item */ String message = "*** Shift/Reduce conflict found in state #" + index () + "\n" + " between " + red_itm.to_simple_string () + "\n"; /* find and report on all items that shift under our conflict symbol */ for ( Enumeration itms = items ().all () ; itms.hasMoreElements () ; ) { itm = ( lalr_item ) itms.nextElement (); /* only look if its not the same item and not a reduce */ if ( itm != red_itm && !itm.dot_at_end () ) { /* is it a shift on our conflicting terminal */ shift_sym = itm.symbol_after_dot (); if ( !shift_sym.is_non_term () && shift_sym.index () == conflict_sym ) { /* yes, report on it */ message += " and " + itm.to_simple_string () + "\n"; } } } message += " under symbol " + terminal.find ( conflict_sym ).name () + "\n" + " Resolved in favor of shifting.\n"; /* count the conflict */ emit.num_conflicts++ ; ErrorManager.getManager ().emit_warning ( message ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Equality comparison. */ public boolean equals ( lalr_state other ) { /* we are equal if our item sets are equal */ return other != null && items ().equals ( other.items () ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Generic equality comparison. */ public boolean equals ( Object other ) { if ( ! ( other instanceof lalr_state ) ) return false; else return equals ( ( lalr_state ) other ); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Produce a hash code. */ public int hashCode () { /* just use the item set hash code */ return items ().hashCode (); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Convert to a string. */ public String toString () { String result; lalr_transition tr; /* dump the item set */ result = "lalr_state [" + index () + "]: " + _items + "\n"; /* do the transitions */ for ( tr = transitions () ; tr != null ; tr = tr.next () ) { result += tr; result += "\n"; } return result; } /*-----------------------------------------------------------*/ }