//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// 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);
}
}
}