//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // PLEASE DO NOT EDIT WITHOUT THE EXPLICIT CONSENT OF THE AUTHOR! \\ //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ using System.Collections; using Ilog.Language.Util; using Ilog.Language.Tools; namespace Ilog.Language.Syntax { /** * This is the class of nonterminal symbols used by the grammar * at parser construction time. * * @see GrammarSymbol * * @version Last modified on Sat May 21 20:07:26 2005 by hak * @author Hassan Aït-Kaci * @copyright © 2000 ILOG, S.A. */ internal class NonTerminal : GrammarSymbol { /** * Constructs a nonterminal symbol with the specified name. */ internal NonTerminal (string name) : base(name,grammar.Nonterminals,grammar.NCount++) { } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ /** * The rules for this non-terminal */ private ArrayList rules = new ArrayList(); internal ArrayList Rules { get { return rules; } } /** * The class name of a parse stack node for this symbol * (if != null, the name of a subclass of ParseNode). */ private string nodeType = null; internal string NodeType { get { return nodeType; } set { nodeType = value; } } /** * Set of nonterminals N such that this L* N. */ private SetOf lset; internal SetOf LSet { get { return lset; } set { lset = value; } } /** * Table of nonterminals and rules N, N -> this ... * such that N L this. */ private Hashtable ltable; internal Hashtable LTable { get { return ltable; } } /** * Returns the appropriate set of rules from LTable * for the given nonterminal, or null if none exists. */ internal SetOf GetLRules (NonTerminal n) { return (SetOf)ltable[n]; } /** * Adds the given rule for the given nonterminal in this * symbol's LTable. */ internal void AddLRule (NonTerminal n, Rule r) { if (ltable == null) ltable = new Hashtable(); SetOf ruleset = GetLRules(n); if (ruleset == null) { ruleset = new SetOf(grammar.Rules); ltable[n] = ruleset; } ruleset.Add(r.Index); } /** * This table is similar to the LTable, but the entry keys * are nonterminals that are L*-related to this one. Also, * unlike in LTable, the links for pathTable are * kept in the right direction. A key in N.pathTable is a * nonterminal P such that N L* P and its entry is an * ArrayList of RulePath objects. Namely, let N be this * node and P be a node such that N L* P. Each path * between N and P is characterized by the sequence * of rules leading from N to P. Since there may be * several differents paths between N and P, each * such path must be recorded in an ArrayList which the stored as * N.pathTable(P). */ private Hashtable pathTable; internal Hashtable PathTable { get { return pathTable; } } /** * For convenient iteration over all paths starting at this nonterminal * we also maintain this ArrayList. */ private ArrayList paths; internal ArrayList Paths { get { return paths; } } /** * This initializes the path structures, creates an empty path * from this nonterminal to itself, and records it where appropriate. */ internal void InitPaths () { paths = new ArrayList(); pathTable = new Hashtable(); pathTable[this] = new RulePaths(new RulePath(this)); } /** * Adds the given path to the paths starting at this nonterminal if * it is not already there. Returns true if the given path * contributes to the FIRST set of the paths between this nonterminal * and the end of the path. */ internal bool AddPath (RulePath path) { RulePaths paths = (RulePaths)pathTable[path.End]; if (paths == null) { pathTable[path.End] = new RulePaths(path); return true; } return paths.Add(path); } /** * Returns the FIRST set of terminals in PATH(this,n). * NB: By construction this will always be well-defined * by the time it is called because all nonterminals * have their paths initialized when the grammar builds * its L-graph. This cannot be done in the constructor * because then the grammar may not have read all its * data yet. */ internal SetOf Path (NonTerminal n) { return ((RulePaths)pathTable[n]).First; } /** * Returns true iff this.path(n) derives EMPTY. */ internal bool PathIsNullable (NonTerminal n) { return ((RulePaths)pathTable[n]).IsNullable; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ /** * Indicates whether this nonterminal is a user-defined start symbol. */ private bool isStart = false; internal bool IsStart { get { return isStart; } } /** * Makes this nonterminal a user-defined start symbol. */ internal void MakeStart () { isStart = true; } /** * Indicates whether this nonterminal is a user-defined root symbol. */ private bool isRoot = false; internal bool IsRoot { get { return isRoot; } } /** * Makes this nonterminal a user-defined root symbol. */ internal void MakeRoot () { isRoot = true; } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ /** * An HTML-coded label for this symbol (used when generating a grammar * documentation) */ internal override string Label { get { string label = ""+Misc.HtmlString(name)+""; return isStart ? ""+label+"" : label; } } /** * An HTML-coded label for this symbol's specified rule (used when * generating a grammar documentation) */ internal string RuleLabel (Rule r) { int index = 1; string head = Misc.HtmlString(name); foreach (Rule rl in rules) { if (r == rl) return ""+head+"_"+index+""; index++; } return head; } /** * Establishes a link between this symbol and the specified rule. */ internal override void Link (Rule rule) { if (IsSpecial || rule.Sequence[0].IsSpecial || this == rule.Sequence[0]) return; if (ruleOccurrences == null) ruleOccurrences = new SetOf(grammar.Rules); ruleOccurrences.Add(rule); } /** * A coded reference name for this symbol (used when generating * a grammar documentation). */ internal override string RefName { get { if (refName == null) refName = Options.GrammarPrefix + "_NT_"+Misc.ZeroPaddedString(Index, Misc.NumWidth(grammar.NCount)); return refName; } } /** * Returns true iff this symbol precedes the specified one. */ public override bool LessThan (Comparable other) { if (grammar.RULE_ORDER_MODE) { if (!(other is NonTerminal)) return false; NonTerminal n = (NonTerminal)other; if (rules.Count == 0 || n.rules.Count == 0) return false; return ((Rule)rules[0]).Index < ((Rule)n.rules[0]).Index; } return base.LessThan(other); } } }