예제 #1
0
        //
        // Context-Free languages, CFG and LR Parsing
        //

        /// <summary>
        /// G3 in "A Survey of LR-Parsing Methods", Gallier.
        /// </summary>
        public static void GallierLookaheadLR_Example3()
        {
            var grammar = DragonBookExample4_48.GetGrammar();

            // characteristic automaton (LR(0) automaton)
            var dfaLr0 = grammar.GetLr0AutomatonDfa();

            SaveFile("GallierEx3_LR0Automaton.dot", DotLanguagePrinter.ToDotLanguage(dfaLr0, DotRankDirection.LeftRight, skipStateLabeling: true));

            var analyzer = Analyzers.CreateErasableSymbolsAnalyzer(grammar);

            //(ImmutableArray<IReadOnlySet<Terminal>> initfirstSets, IGraph graphFirst) = DigraphAlgorithm.GetFirstGraph(grammar, analyzer);
            (var initfirstSets, IGraph graphFirst) = DigraphAlgorithm.GetFirstGraph(grammar, analyzer);

            SaveFile("GallierEx3_FirstGraph.dot",
                     DigraphDotLanguagePrinter.PrintGraph("INITFIRST", initfirstSets, graphFirst, v => grammar.Nonterminals[v].Name));

            var firstSymbolsAnalyzer = Analyzers.CreateFirstSymbolsAnalyzer(grammar);

            (var initFollowSets, IGraph graphFollow) = DigraphAlgorithm.GetFollowGraph(grammar, firstSymbolsAnalyzer);

            SaveFile("GallierEx3_FollowGraph.dot",
                     DigraphDotLanguagePrinter.PrintGraph("INITFOLLOW", initFollowSets, graphFollow, v => grammar.Nonterminals[v].Name));

            var stringWriter = new StringWriter();

            grammar.PrintFirstAndFollowSets(stringWriter);
            SaveFile("GallierEx3_FirstAndFollowSets.txt", stringWriter.ToString());

            // Grammar is LR(0)
            var lr0Parser = grammar.ComputeLr0ParsingTable();
            var writer    = new StringWriter();

            lr0Parser.PrintParsingTable(writer);

            foreach (var conflict in lr0Parser.Conflicts)
            {
                writer.WriteLine(conflict);
                writer.WriteLine($"In state {conflict.State}: {lr0Parser.GetItems(conflict.State).KernelItems.ToVectorString()} (kernel items)");
            }
            writer.WriteLine();

            SaveFile("GallierEx3_Lr0ParsingTable.txt", writer.ToString());

            ////

            var vertices = LalrLookaheadSetsAlgorithm.GetGotoTransitionPairs(grammar, dfaLr0);

            // Read (INITFOLLOW) sets
            var(directReads, graphRead) = LalrLookaheadSetsAlgorithm.GetGraphReads(grammar, dfaLr0, vertices, analyzer);

            SaveFile("GallierEx3_ReadGraph.dot",
                     DigraphDotLanguagePrinter.PrintGraph("DR", directReads, graphRead, v => vertices[v].ToString()));

            var graphLaFollow = LalrLookaheadSetsAlgorithm.GetGraphLaFollow(grammar, dfaLr0, vertices, analyzer);

            SaveFile("GallierEx3_LaFollowGraph.dot",
                     DigraphDotLanguagePrinter.PrintGraph("INITFOLLOW", directReads, graphLaFollow, v => vertices[v].ToString()));
        }
예제 #2
0
        /// <summary>
        /// Example 4.48 in Dragon book p. 255, 2nd ed
        /// </summary>
        public static void DragonBookEx4_48()
        {
            var grammar = DragonBookExample4_48.GetGrammar();

            //
            // LR(0) automaton
            //

            var nfa0 = grammar.GetLr0AutomatonNfa();

            SaveFile("DragonBookEx4_48_NCG0.dot", DotLanguagePrinter.ToDotLanguage(nfa0, DotRankDirection.TopBottom));

            var dfa0 = nfa0.ToDfa();

            SaveFile("DragonBookEx4_48_DCG0.dot", DotLanguagePrinter.ToDotLanguage(dfa0, DotRankDirection.LeftRight, skipStateLabeling: true));

            var dfaLr0 = grammar.GetLr0AutomatonDfa();

            SaveFile("DragonBookEx4_48_DCG0Lr.dot", DotLanguagePrinter.ToDotLanguage(dfaLr0, DotRankDirection.LeftRight, skipStateLabeling: true));

            // We will augment every LR(0) item with information about what portion of the follow set is appropriate given
            // the path we have taken to that state. We can be in state 2 {S → L•=R, R → L•} for one of two reasons
            //     (i)  We are trying to build from S => L=R    (shift =)
            //     (ii) We are trying to build from S => R => L (reduce by R → L•)

            //
            // LR(1) automaton
            //

            var nfa1 = grammar.GetLr1AutomatonNfa();

            SaveFile("DragonBookEx4_48_NCG1.dot", DotLanguagePrinter.ToDotLanguage(nfa1, DotRankDirection.TopBottom));

            var dfa1 = nfa1.ToDfa();

            SaveFile("DragonBookEx4_48_DCG1.dot", DotLanguagePrinter.ToDotLanguage(dfa1, DotRankDirection.LeftRight, skipStateLabeling: true));

            var dfaLr1 = grammar.GetLr1AutomatonDfa();

            SaveFile("DragonBookEx4_48_DCG1Lr.dot", DotLanguagePrinter.ToDotLanguage(dfaLr1, DotRankDirection.LeftRight, skipStateLabeling: true));

            // TODO: Parse 'a=a'
        }
예제 #3
0
        public LookaheadTests()
        {
            // 0: S' → S     (the digraph algorithms will augment the unit production with eof marker)
            // 1: S  → L = R
            // 2: S  → R
            // 3: R  → *R
            // 4: R  → a     ('id' in Gallier notes)
            // 5: R  → L
            Grammar = DragonBookExample4_48.GetGrammar();

            DfaLr0 = Grammar.GetLr0AutomatonDfa();

            // 0: S' → S$    (the digraph algorithms will augment the unit production with eof marker)
            // 1: S  → L = R
            // 2: S  → R
            // 3: R  → *R
            // 4: R  → a     ('id' in Gallier notes)
            // 5: R  → L
            GrammarEof = DragonBookExample4_48.GetExtendedGrammar();

            DfaLr0Eof = GrammarEof.GetLr0AutomatonDfa();
        }
        public void DragonBookEx4_48()
        {
            // NOTE: We are using nonterminal L for l-value (a location), nonterminal R for r-value (value
            //       that can be stored in a location), and terminal * for 'content-of' prefix operator.
            // 0: S' → S
            // 1: S → L = R
            // 2: S → R
            // 3: L → *R
            // 4: L → ID
            // 5: R → L
            Grammar <Sym, Var> grammar = DragonBookExample4_48.GetGrammar();

            var writer = new TestWriter();


            var lr0Dfa = grammar.GetLr0AutomatonDfa();

            lr0Dfa.PrintKernelItems(writer);

            grammar.PrintFirstAndFollowSets(writer);
            // ╔═══════════════════════════════════════════════════════════╗
            // ║                   First and Follow sets                   ║
            // ╠════════════╤════════════╤════════════════╤════════════════╣
            // ║  Variable  │  Nullable  │     First      │     Follow     ║
            // ╠════════════╪════════════╪════════════════╪════════════════╣
            // ║     S'     │   false    │ {ASTERISK, ID} │       {}       ║
            // ║     S      │   false    │ {ASTERISK, ID} │     {EOF}      ║
            // ║     R      │   false    │ {ASTERISK, ID} │  {EOF, EQUAL}  ║
            // ║     L      │   false    │ {ASTERISK, ID} │  {EQUAL, EOF}  ║
            // ╚════════════╧════════════╧════════════════╧════════════════╝

            grammar.Follow(grammar.V(Var.Start)).ShouldBeEmpty();
            grammar.Follow(grammar.V(Var.S)).ShouldSetEqual(grammar.Eof());
            grammar.Follow(grammar.V(Var.R)).ShouldSetEqual(grammar.T(Sym.EQUAL), grammar.Eof());
            grammar.Follow(grammar.V(Var.L)).ShouldSetEqual(grammar.T(Sym.EQUAL), grammar.Eof());

            WriteLine("SLR(1) Parsing Table");
            var slrParser = grammar.ComputeSlrParsingTable();

            // SLR(1) Parsing Table
            // ╔════════════════════════════════╗╔══════════════════════════╗
            // ║             ACTION             ║║           GOTO           ║
            // ╠════════╤═════╤═════╤═════╤═════╣╠════════╤═════╤═════╤═════╣
            // ║ State  │EQUAL│ ID  │ASTER│ EOF ║║ State  │  S  │  R  │  L  ║
            // ╠════════╪═════╪═════╪═════╪═════╣╠════════╪═════╪═════╪═════╣
            // ║   0    │     │ s5  │ s4  │     ║║   0    │  1  │  3  │  2  ║
            // ║   1    │     │     │     │ acc ║║   1    │     │     │     ║
            // ║   2    │ s6  │     │     │ r5  ║║   2    │     │     │     ║
            // ║   3    │     │     │     │ r2  ║║   3    │     │     │     ║
            // ║   4    │     │ s5  │ s4  │     ║║   4    │     │  7  │  8  ║
            // ║   5    │ r4  │     │     │ r4  ║║   5    │     │     │     ║
            // ║   6    │     │ s5  │ s4  │     ║║   6    │     │  9  │  8  ║
            // ║   7    │ r3  │     │     │ r3  ║║   7    │     │     │     ║
            // ║   8    │ r5  │     │     │ r5  ║║   8    │     │     │     ║
            // ║   9    │     │     │     │ r1  ║║   9    │     │     │     ║
            // ╚════════╧═════╧═════╧═════╧═════╝╚════════╧═════╧═════╧═════╝
            slrParser.PrintParsingTable(writer);

            // Grammar is not SLR(1)
            slrParser.AnyConflicts.ShouldBeTrue();
            slrParser.Conflicts.Count().ShouldBe(1);

            // This will print
            //      State 2: { shift 6, reduce 5} on 'EQUAL'
            //      State 2: { S → L•EQUAL R, R → L•} (kernel items)
            // The correct choice of the parser is to shift, because no right sentential form begins with....TODO
            // Therefore....TODO
            var conflict = slrParser.Conflicts.Single();

            writer.WriteLine(conflict);
            writer.WriteLine($"State {conflict.State}: {slrParser.GetItems(conflict.State).KernelItems.ToVectorString()} (kernel items)");

            // a=a$
            var lexer = new FakeLexer <Sym>((Sym.ID, "a"), (Sym.EQUAL, "="), (Sym.ID, "a"));

            slrParser.Parse(lexer, writer);
            //  ╔════════╤══════════════╤══════════════╤══════════╤══════════════════════════════════╗
            //  ║ SeqNo  │    Stack     │   Symbols    │  Input   │              Action              ║
            //  ╠════════╪══════════════╪══════════════╪══════════╪══════════════════════════════════╣
            //  ║  (1)   │ 0            │              │   a = a$ │ shift 5                          ║
            //  ║  (2)   │ 0 5          │ ID           │     = a$ │ reduce by L → ID, goto 2         ║
            //  ║  (3)   │ 0 2          │ L            │     = a$ │ shift 6                          ║<--- shift/reduce conflict here (shift wins)
            //  ║  (4)   │ 0 2 6        │ L EQUAL      │       a$ │ shift 5                          ║
            //  ║  (5)   │ 0 2 6 5      │ L EQUAL ID   │        $ │ reduce by L → ID, goto 8         ║
            //  ║  (6)   │ 0 2 6 8      │ L EQUAL L    │        $ │ reduce by R → L, goto 9          ║
            //  ║  (7)   │ 0 2 6 9      │ L EQUAL R    │        $ │ reduce by S → L EQUAL R, goto 1  ║
            //  ║  (8)   │ 0 1          │ S            │        $ │ accept                           ║
            //  ╚════════╧══════════════╧══════════════╧══════════╧══════════════════════════════════╝


            var lr1Parser = grammar.ComputeLr1ParsingTable();

            WriteLine("LR(1) Parsing Table");
            lr1Parser.PrintParsingTable(writer);

            // LR(1) Parsing Table
            // ╔════════════════════════════════╗╔══════════════════════════╗
            // ║             ACTION             ║║           GOTO           ║
            // ╠════════╤═════╤═════╤═════╤═════╣╠════════╤═════╤═════╤═════╣
            // ║ State  │EQUAL│ ID  │ASTER│ EOF ║║ State  │  S  │  R  │  L  ║
            // ╠════════╪═════╪═════╪═════╪═════╣╠════════╪═════╪═════╪═════╣
            // ║   0    │     │ s5  │ s4  │     ║║   0    │  1  │  3  │  2  ║
            // ║   1    │     │     │     │ acc ║║   1    │     │     │     ║
            // ║   2    │ s6  │     │     │ r5  ║║   2    │     │     │     ║
            // ║   3    │     │     │     │ r2  ║║   3    │     │     │     ║
            // ║   4    │     │ s5  │ s4  │     ║║   4    │     │  7  │  8  ║
            // ║   5    │ r4  │     │     │ r4  ║║   5    │     │     │     ║
            // ║   6    │     │ s12 │ s11 │     ║║   6    │     │  9  │ 10  ║
            // ║   7    │ r3  │     │     │ r3  ║║   7    │     │     │     ║
            // ║   8    │ r5  │     │     │ r5  ║║   8    │     │     │     ║
            // ║   9    │     │     │     │ r1  ║║   9    │     │     │     ║
            // ║   10   │     │     │     │ r5  ║║   10   │     │     │     ║
            // ║   11   │     │ s12 │ s11 │     ║║   11   │     │ 13  │ 10  ║
            // ║   12   │     │     │     │ r4  ║║   12   │     │     │     ║
            // ║   13   │     │     │     │ r3  ║║   13   │     │     │     ║
            // ╚════════╧═════╧═════╧═════╧═════╝╚════════╧═════╧═════╧═════╝

            // Grammar is LR(1)
            lr1Parser.AnyConflicts.ShouldBeFalse();

            // a=a$
            var lexer2 = new FakeLexer <Sym>((Sym.ID, "a"), (Sym.EQUAL, "="), (Sym.ID, "a"));

            lr1Parser.Parse(lexer2, writer);
            //  ╔════════╤══════════════╤══════════════╤══════════╤══════════════════════════════════╗
            //  ║ SeqNo  │    Stack     │   Symbols    │  Input   │              Action              ║
            //  ╠════════╪══════════════╪══════════════╪══════════╪══════════════════════════════════╣
            //  ║  (1)   │ 0            │              │     a=a$ │ shift 5                          ║
            //  ║  (2)   │ 0 5          │ ID           │      =a$ │ reduce by L → ID, goto 2         ║
            //  ║  (3)   │ 0 2          │ L            │      =a$ │ shift 6                          ║<--- no reduce, '=' is not a valid lookahead
            //  ║  (4)   │ 0 2 6        │ L EQUAL      │       a$ │ shift 12                         ║
            //  ║  (5)   │ 0 2 6 12     │ L EQUAL ID   │        $ │ reduce by L → ID, goto 10        ║
            //  ║  (6)   │ 0 2 6 10     │ L EQUAL L    │        $ │ reduce by R → L, goto 9          ║
            //  ║  (7)   │ 0 2 6 9      │ L EQUAL R    │        $ │ reduce by S → L EQUAL R, goto 1  ║
            //  ║  (8)   │ 0 1          │ S            │        $ │ accept                           ║
            //  ╚════════╧══════════════╧══════════════╧══════════╧══════════════════════════════════╝


            // TODO: Compute LALR(1) parser
            //      - brute force merging: LR(1) -> LALR(1)
            //      - fixed-point algorithm of propagated lookaheads: LR(0) -> SLR(1) extended follow sets --> LALR(1)
        }