public static LrItemNfa <TTokenKind> GetLr0AutomatonNfa <TTokenKind, TNonterminal>(Grammar <TTokenKind, TNonterminal> grammar) where TTokenKind : struct, Enum where TNonterminal : struct, Enum { // NOTE: These are all synonyms for what machine we are building here // - 'characteristic strings' recognizer // - 'viable prefix' recognizer (αβ is the viable prefix on top of the the stack) // - 'handle' recognizer (β is the handle on top of the stack) // - LR(0) automaton if (!grammar.IsAugmented) { throw new InvalidOperationException("The grammar should be augmented with canonical S' → S production."); } if (!grammar.IsReduced) { throw new InvalidOperationException("The grammar contains useless symbols."); } var startItem = new ProductionItem <TTokenKind>(grammar.Productions[0], 0, 0); var transitions = new List <Transition <Symbol, ProductionItem <TTokenKind> > >(); var acceptItems = new List <ProductionItem <TTokenKind> >(); // (a) For every terminal a ∈ T, if A → α•aβ is a marked production, then // there is a transition on input a from state A → α•aβ to state A → αa•β // obtained by "shifting the dot" // (b) For every variable B ∈ V, if A → α•Bβ is a marked production, then // there is a transition on input B from state A → α•Bβ to state A → αB•β // obtained by "shifting the dot", and transitions on input ε (the empty string) // to all states B → •γ(i), for all productions B → γ(i) ∈ P with left-hand side B. int productionIndex = 0; foreach (var production in grammar.Productions) { for (int dotPosition = 0; dotPosition <= production.Tail.Count; dotPosition += 1) { // (productionIndex, dotPosition) is identifier var item = new ProductionItem <TTokenKind>(production, productionIndex, dotPosition); // (a) A → α•aβ if (item.IsShiftItem) { Symbol a = item.GetDotSymbol <Terminal <TTokenKind> >(); var shiftToItem = item.WithShiftedDot(); transitions.Add(Transition.Move(item, a, shiftToItem)); } // (b) A → α•Bβ if (item.IsGotoItem) { var B = item.GetDotSymbol <Nonterminal>(); var gotoItem = item.WithShiftedDot(); transitions.Add(Transition.Move(item, (Symbol)B, gotoItem)); // closure items foreach (var(index, productionOfB) in grammar.ProductionsFor[B]) { var closureItem = new ProductionItem <TTokenKind>(productionOfB, index, 0); // Expecting to see a nonterminal 'B' (of Bβ) is the same as expecting to see // RHS grammar symbols 'γ(i)', where B → γ(i) is a production ∈ P transitions.Add(Transition.Move(item, Symbol.Epsilon, closureItem)); } } // (c) A → β• (Accepting states has dot shifted all the way to the end) if (item.IsReduceItem) { acceptItems.Add(item); } } productionIndex += 1; } return(new LrItemNfa <TTokenKind>(transitions, startItem, acceptItems)); }