diff options
Diffstat (limited to 'src/syntaxParser/java_cup/non_terminal.java')
| -rw-r--r-- | src/syntaxParser/java_cup/non_terminal.java | 301 |
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() ? "*" : ""); + } + + /*-----------------------------------------------------------*/ +} |
