⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lalr_state.java

📁 我开发的一个用java语言实现的编译器,内含词法分析器,语法分析器,而且可以实现中间代码生成.用到了SLR算法和LR(1)算法
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package java_cup;import java.util.Hashtable;import java.util.Enumeration;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 *   */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();}  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/  /** 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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -