public ContextFreeGrammar(string[] nonterminals, string[] terminals, ProductionInfo[] rules, string starting) { if (HasDuplicates(nonterminals)) { throw new ArgumentException("Nonterminal symbols cannot contain duplicates."); } if (HasDuplicates(terminals)) { throw new ArgumentException("Terminal symbols cannot contain duplicates."); } if (HasDuplicates(rules)) { throw new ArgumentException("Rules cannot contain duplicates."); } bool overlap = terminals.Intersect(nonterminals).Any(); if (overlap) { throw new ArgumentException("Terminal symbols and nonterminal symbols are not disjoint."); } var symbolByString = new Dictionary <string, GrammarSymbol>(nonterminals.Length + terminals.Length); this.nonterminals = new GrammarSymbol[nonterminals.Length]; for (int i = 0; i < nonterminals.Length; i++) { this.nonterminals[i] = new GrammarSymbol(nonterminals[i], false); symbolByString.Add(nonterminals[i], this.nonterminals[i]); } this.terminals = new GrammarSymbol[terminals.Length]; for (int i = 0; i < terminals.Length; i++) { this.terminals[i] = new GrammarSymbol(terminals[i], true); symbolByString.Add(terminals[i], this.terminals[i]); } this.alphabet = (this.nonterminals).Concat(this.terminals).ToArray(); int startingIndex = Array.IndexOf(nonterminals, starting); if (startingIndex < 0) { throw new ArgumentException("Start symbol must be a nonterminal symbol."); } this.starting = this.nonterminals[startingIndex]; var ruleList = new List <Production>(rules.Length); foreach (var rule in rules) { if (!IsValid(rule)) { throw new ArgumentException("Production rule is invalid."); } GrammarSymbol original = symbolByString[rule.Original]; var sentenceSymbols = new List <GrammarSymbol>(); foreach (string s in rule.DirectDerivative) { sentenceSymbols.Add(symbolByString[s]); } Sentence sentence = new Sentence(sentenceSymbols.ToArray()); ruleList.Add(new Production(original, sentence)); } this.rules = ruleList.ToArray(); }