diff --git a/Canon.Tests/GrammarParserTests/SimpleGrammarWithEmptyTests.cs b/Canon.Tests/GrammarParserTests/SimpleGrammarWithEmptyTests.cs new file mode 100644 index 0000000..bbf58a1 --- /dev/null +++ b/Canon.Tests/GrammarParserTests/SimpleGrammarWithEmptyTests.cs @@ -0,0 +1,129 @@ +using Canon.Core.Enums; +using Canon.Core.GrammarParser; +using Xunit.Abstractions; + +namespace Canon.Tests.GrammarParserTests; + +public class SimpleGrammarWithEmptyTests(ITestOutputHelper testOutputHelper) +{ + /// + /// 带有空产生式的简单语法(课后题4.18) + /// S -> A + /// A -> BA | ε + /// B -> aB | b + /// 为了方便测试指定 + /// A ProgramStruct + /// B ProgramBody + /// a Identifier + /// b Identifier + /// + // private readonly ITestOutputHelper _testOutputHelper; + + private readonly ITestOutputHelper _testOutputHelper = testOutputHelper; + + private static readonly Dictionary>> s_simpleGrammar = new() + { + { + new NonTerminator(NonTerminatorType.StartNonTerminator), [ + [new NonTerminator(NonTerminatorType.ProgramStruct)] + ] + }, + { + new NonTerminator(NonTerminatorType.ProgramStruct), [ + [ + new NonTerminator(NonTerminatorType.ProgramBody), + new NonTerminator(NonTerminatorType.ProgramStruct) + ], + [] + ] + }, + { + new NonTerminator(NonTerminatorType.ProgramBody), [ + [ + Terminator.IdentifierTerminator, + new NonTerminator(NonTerminatorType.ProgramBody) + ], + [Terminator.IdentifierTerminator] + ] + } + }; + + [Fact] + public void FirstSetTest() + { + GrammarBuilder builder = new() + { + Generators = s_simpleGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator) + }; + + builder.Build(); + + Assert.Contains(builder.FirstSet, pair => + pair.Key == new NonTerminator(NonTerminatorType.StartNonTerminator)); + Assert.Contains(builder.FirstSet, pair => + pair.Key == new NonTerminator(NonTerminatorType.ProgramStruct)); + Assert.Contains(builder.FirstSet, pair => + pair.Key == new NonTerminator(NonTerminatorType.ProgramBody)); + + foreach (HashSet terminators in builder.FirstSet.Values) + { + Assert.Single(terminators); + Assert.Contains(Terminator.IdentifierTerminator, terminators); + } + } + + [Fact] + public void StatsTest() + { + GrammarBuilder builder = new() + { + Generators = s_simpleGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator) + }; + + Grammar grammar = builder.Build(); + + Assert.Equal(6, builder.Automation.Count); + + Assert.Contains(new NonTerminator(NonTerminatorType.ProgramStruct), grammar.BeginState.Transformer.Keys); + Assert.Contains(new NonTerminator(NonTerminatorType.ProgramBody), grammar.BeginState.Transformer.Keys); + Assert.Contains(Terminator.IdentifierTerminator, grammar.BeginState.Transformer.Keys); + Assert.Equal(7, grammar.BeginState.Expressions.Count); + _testOutputHelper.WriteLine("--- 0 ---"); + _testOutputHelper.WriteLine(grammar.BeginState.ToString()); + + LrState state1 = + grammar.BeginState.Transformer[new NonTerminator(NonTerminatorType.ProgramStruct)]; + Assert.Single(state1.Expressions); + _testOutputHelper.WriteLine("--- 1 ---"); + _testOutputHelper.WriteLine(state1.ToString()); + + LrState state2 = + grammar.BeginState.Transformer[new NonTerminator(NonTerminatorType.ProgramBody)]; + Assert.Contains(new NonTerminator(NonTerminatorType.ProgramStruct), state2.Transformer.Keys); + Assert.Contains(new NonTerminator(NonTerminatorType.ProgramBody), state2.Transformer.Keys); + Assert.Contains(Terminator.IdentifierTerminator, state2.Transformer.Keys); + Assert.Equal(7, state2.Expressions.Count); + _testOutputHelper.WriteLine("--- 2 ---"); + _testOutputHelper.WriteLine(state2.ToString()); + + LrState state3 = + grammar.BeginState.Transformer[Terminator.IdentifierTerminator]; + Assert.Contains(new NonTerminator(NonTerminatorType.ProgramBody), state3.Transformer.Keys); + Assert.Contains(Terminator.IdentifierTerminator, state3.Transformer.Keys); + Assert.Equal(8, state3.Expressions.Count); + _testOutputHelper.WriteLine("--- 3 ---"); + _testOutputHelper.WriteLine(state3.ToString()); + + LrState state4 = state2.Transformer[new NonTerminator(NonTerminatorType.ProgramStruct)]; + Assert.Empty(state4.Transformer); + Assert.Single(state4.Expressions); + _testOutputHelper.WriteLine("--- 4 ---"); + _testOutputHelper.WriteLine(state4.ToString()); + + LrState state5 = state3.Transformer[new NonTerminator(NonTerminatorType.ProgramBody)]; + Assert.Empty(state5.Transformer); + Assert.Equal(2, state5.Expressions.Count); + _testOutputHelper.WriteLine("--- 5 ---"); + _testOutputHelper.WriteLine(state5.ToString()); + } +}