// // 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())); }
/// <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' }
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) }