コード例 #1
0
        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));
        }