public Production(Nonterminal head, IEnumerable <Symbol> tail) { Head = head ?? throw new ArgumentNullException(nameof(head)); var rhs = (tail ?? Enumerable.Empty <Symbol>()).ToArray(); if (rhs.Length > 1 && rhs.Any(symbol => symbol.IsEpsilon)) { throw new ArgumentException($"{Symbol.Epsilon}-productions cannot have more than one symbol."); } if (rhs.Length == 0 || rhs.Length == 1 && rhs[0].IsEpsilon) { Tail = Array.Empty <Symbol>(); } else { Tail = rhs; } }
public Grammar( SymbolCache <TTokenKind, Terminal <TTokenKind> > terminals, SymbolCache <TNonterminal, Nonterminal> nonterminals, Nonterminal startSymbol, IEnumerable <Production> productions, Func <Grammar <TTokenKind, TNonterminal>, IFollowSymbolsAnalyzer <TTokenKind> > analyzerFactory) { if (productions == null) { throw new ArgumentNullException(nameof(productions)); } StartSymbol = startSymbol ?? throw new ArgumentNullException(nameof(startSymbol)); Nonterminals = nonterminals ?? throw new ArgumentNullException(nameof(nonterminals)); Terminals = terminals ?? throw new ArgumentNullException(nameof(terminals)); // Productions are numbered 0,1,2,...,^Productions.Count var prods = new List <Production>(); // Variables (productions on the shorter form (A -> α | β | ...) are numbered 0,1,...,^Variables.Count var productionMap = Nonterminals.ToDictionary(symbol => symbol, _ => new List <(int, Production)>()); int index = 0; foreach (var production in productions) { prods.Add(production); productionMap[production.Head].Add((index, production)); index += 1; } ProductionsFor = productionMap.ToImmutableDictionary(kvp => kvp.Key, kvp => (IReadOnlyList <(int, Production)>)kvp.Value); if (prods.Count == 0) { throw new ArgumentException("The productions are empty.", nameof(productions)); } Productions = prods; // Calculate lookahead sets (Erasable, First, Follow) using strategy provided by the caller _analyzer = analyzerFactory(this); }
internal LrGotoEntry(int sourceState, Nonterminal nonterminalSymbol, int targetState) { SourceState = sourceState; NonterminalSymbol = nonterminalSymbol; TargetState = targetState; }