/* * STANDARD ML OF NEW JERSEY COPYRIGHT NOTICE, LICENSE AND DISCLAIMER. * * Copyright (c) 1989-1998 by Lucent Technologies * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice and warranty disclaimer appear * in supporting documentation, and that the name of Lucent Technologies, Bell * Labs or any Lucent entity not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior permission. * * Lucent disclaims all warranties with regard to this software, including all * implied warranties of merchantability and fitness. In no event shall Lucent * be liable for any special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether in an action * of contract, negligence or other tortious action, arising out of or in * connection with the use or performance of this software. * * Taken from this URL: * http://www.smlnj.org/license.html * * This license is compatible with the GNU GPL (see section "Standard ML of New * Jersey Copyright License"): * http://www.gnu.org/licenses/license-list.html#StandardMLofNJ */ /* * Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian */ package weka.core.parser.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() ? "*" : ""); } /*-----------------------------------------------------------*/ }