summaryrefslogtreecommitdiffstats
path: root/src/syntaxParser/java_cup/non_terminal.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/syntaxParser/java_cup/non_terminal.java')
-rw-r--r--src/syntaxParser/java_cup/non_terminal.java301
1 files changed, 301 insertions, 0 deletions
diff --git a/src/syntaxParser/java_cup/non_terminal.java b/src/syntaxParser/java_cup/non_terminal.java
new file mode 100644
index 0000000..9354a7f
--- /dev/null
+++ b/src/syntaxParser/java_cup/non_terminal.java
@@ -0,0 +1,301 @@
+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();
+
+ /** 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
+ {
+ if (prefix == null) prefix = "NT$";
+ return new non_terminal(prefix + next_nt++);
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** static routine for creating a new uniquely named hidden non-terminal */
+ static non_terminal create_new() throws internal_error
+ {
+ return create_new(null);
+ }
+
+ /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
+
+ /** 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() ? "*" : "");
+ }
+
+ /*-----------------------------------------------------------*/
+}