content: package java_cup;
  
  import java.util.Hashtable;
  import java.util.Enumeration;
  
  /** This class represents a non-terminal symbol in the grammar.  Each
   *  non terminal has a textual name, an index, and a string which indicates
   *  the type of object it will be implemented with at runtime (i.e. the class
   *  of object that will be pushed on the parse stack to represent it). 
   *
   * @version last updated: 11/25/95
   * @author  Scott Hudson
   */
  
  public class non_terminal extends symbol {
  
    /*-----------------------------------------------------------*/
    /*--- Constructor(s) ----------------------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Full constructor.
     * @param nm  the name of the non terminal.
     * @param tp  the type string for the non terminal.
     */
    public non_terminal(String nm, String tp) 
      {
        /* super class does most of the work */
        super(nm, tp);
  
        /* add to set of all non terminals and check for duplicates */
        Object conflict = _all.put(nm,this);
        if (conflict != null)
  	// can't throw an exception here because these are used in static
  	// initializers, so we crash instead
  	// was: 
  	// throw new internal_error("Duplicate non-terminal ("+nm+") created");
  	(new internal_error("Duplicate non-terminal ("+nm+") created")).crash();
  
        /* assign a unique index */
        _index = next_index++;
  
        /* add to by_index set */
        _all_by_index.put(new Integer(_index), this);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Constructor with default type. 
     * @param nm  the name of the non terminal.
     */
    public non_terminal(String nm) 
      {
        this(nm, null);
      }
  
    /*-----------------------------------------------------------*/
    /*--- (Access to) Static (Class) Variables ------------------*/
    /*-----------------------------------------------------------*/
  
    /** Table of all non-terminals -- elements are stored using name strings 
     *  as the key 
     */
    protected static Hashtable _all = new Hashtable();
  
    //Hm Added clear  to clear all static fields
    public static void clear() {
        _all.clear();
        _all_by_index.clear();
        next_index=0;
        next_nt=0;
    }
  
    /** Access to all non-terminals. */
    public static Enumeration all() {return _all.elements();}
  
    /** lookup a non terminal by name string */ 
    public static non_terminal find(String with_name)
      {
        if (with_name == null)
          return null;
        else 
          return (non_terminal)_all.get(with_name);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Table of all non terminals indexed by their index number. */
    protected static Hashtable _all_by_index = new Hashtable();
  
    /** Lookup a non terminal by index. */
    public static non_terminal find(int indx)
      {
        Integer the_indx = new Integer(indx);
  
        return (non_terminal)_all_by_index.get(the_indx);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Total number of non-terminals. */
    public static int number() {return _all.size();}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Static counter to assign unique indexes. */
    protected static int next_index = 0;
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Static counter for creating unique non-terminal names */
    static protected int next_nt = 0;
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** special non-terminal for start symbol */
    public static final non_terminal START_nt = new non_terminal("$START");
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** flag non-terminals created to embed action productions */
    public boolean is_embedded_action = false; /* added 24-Mar-1998, CSA */
  
    /*-----------------------------------------------------------*/
    /*--- Static Methods ----------------------------------------*/
    /*-----------------------------------------------------------*/
  	 
    /** Method for creating a new uniquely named hidden non-terminal using 
     *  the given string as a base for the name (or "NT$" if null is passed).
     * @param prefix base name to construct unique name from. 
     */
    static non_terminal create_new(String prefix) throws internal_error
      {
        return create_new(prefix,null); // TUM 20060608 embedded actions patch
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** static routine for creating a new uniquely named hidden non-terminal */
    static non_terminal create_new() throws internal_error
      { 
        return create_new(null); 
      }
      /**
       * TUM 20060608 bugfix for embedded action codes
       */
      static non_terminal create_new(String prefix, String type) throws internal_error{
          if (prefix==null) prefix = "NT$";
          return new non_terminal(prefix + next_nt++,type);
      }
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Compute nullability of all non-terminals. */
    public static void compute_nullability() throws internal_error
      {
        boolean      change = true;
        non_terminal nt;
        Enumeration  e;
        production   prod;
  
        /* repeat this process until there is no change */
        while (change)
  	{
  	  /* look for a new change */
  	  change = false;
  
  	  /* consider each non-terminal */
  	  for (e=all(); e.hasMoreElements(); )
  	    {
  	      nt = (non_terminal)e.nextElement();
  
  	      /* only look at things that aren't already marked nullable */
  	      if (!nt.nullable())
  		{
  		  if (nt.looks_nullable())
  		    {
  		      nt._nullable = true;
  		      change = true;
  		    }
  		}
  	    }
  	}
        
        /* do one last pass over the productions to finalize all of them */
        for (e=production.all(); e.hasMoreElements(); )
  	{
  	  prod = (production)e.nextElement();
  	  prod.set_nullable(prod.check_nullable());
  	}
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Compute first sets for all non-terminals.  This assumes nullability has
     *  already computed.
     */
    public static void compute_first_sets() throws internal_error
      {
        boolean      change = true;
        Enumeration  n;
        Enumeration  p;
        non_terminal nt;
        production   prod;
        terminal_set prod_first;
  
        /* repeat this process until we have no change */
        while (change)
  	{
  	  /* look for a new change */
  	  change = false;
  
  	  /* consider each non-terminal */
  	  for (n = all(); n.hasMoreElements(); )
  	    {
  	      nt = (non_terminal)n.nextElement();
  
  	      /* consider every production of that non terminal */
  	      for (p = nt.productions(); p.hasMoreElements(); )
  		{
  		  prod = (production)p.nextElement();
  
  		  /* get the updated first of that production */
  		  prod_first = prod.check_first_set();
  
  		  /* if this going to add anything, add it */
  		  if (!prod_first.is_subset_of(nt._first_set))
  		    {
  		      change = true;
  		      nt._first_set.add(prod_first);
  		    }
  		}
  	    }
  	}
      }
  
    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Table of all productions with this non terminal on the LHS. */
    protected Hashtable _productions = new Hashtable(11);
  
    /** Access to productions with this non terminal on the LHS. */
    public Enumeration productions() {return _productions.elements();}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Total number of productions with this non terminal on the LHS. */
    public int num_productions() {return _productions.size();}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Add a production to our set of productions. */
    public void add_production(production prod) throws internal_error
      {
        /* catch improper productions */
        if (prod == null || prod.lhs() == null || prod.lhs().the_symbol() != this)
  	throw new internal_error(
  	  "Attempt to add invalid production to non terminal production table");
  
        /* add it to the table, keyed with itself */
        _productions.put(prod,prod);
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Nullability of this non terminal. */
    protected boolean _nullable;
  
    /** Nullability of this non terminal. */
    public boolean nullable() {return _nullable;}
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** First set for this non-terminal. */
    protected terminal_set _first_set = new terminal_set();
  
    /** First set for this non-terminal. */
    public terminal_set first_set() {return _first_set;}
  
    /*-----------------------------------------------------------*/
    /*--- General Methods ---------------------------------------*/
    /*-----------------------------------------------------------*/
  
    /** Indicate that this symbol is a non-terminal. */
    public boolean is_non_term() 
      {
        return true;
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** Test to see if this non terminal currently looks nullable. */
    protected boolean looks_nullable() throws internal_error
      {
        /* look and see if any of the productions now look nullable */
        for (Enumeration e = productions(); e.hasMoreElements(); )
  	/* if the production can go to empty, we are nullable */
  	if (((production)e.nextElement()).check_nullable())
  	  return true;
  
        /* none of the productions can go to empty, so we are not nullable */
        return false;
      }
  
    /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
  
    /** convert to string */
    public String toString()
      {
        return super.toString() + "[" + index() + "]" + (nullable() ? "*" : "");
      }
  
    /*-----------------------------------------------------------*/
  }
  