All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java_cup.non_terminal Maven / Gradle / Ivy

Go to download

A fork of the Java Cup parser generator with some bug fixes and enhancements. (Forked at version 11b)

The newest version!
package java_cup;

import java.util.Enumeration;
import java.util.Hashtable;

/**
 * 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).
 *
 * @author Scott Hudson
 * @version last updated: 11/25/95
 */

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() ? "*" : "");
    }

  /*-----------------------------------------------------------*/
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy