using Canon.Core.Enums; using Canon.Core.GrammarParser; using Canon.Core.LexicalParser; namespace Canon.Tests.GrammarParserTests; public class SimpleGrammarTests { /// /// 用于测试的简单语法 /// S -> E /// E -> E+T | E-T | T /// T -> T*F | T/F | F /// F -> (E) | n /// 为了方便测试指定 /// E ProgramStruct /// T ProgramBody /// F StatementList /// n Identifier /// private static readonly Dictionary>> s_simpleGrammar = new() { { new NonTerminator(NonTerminatorType.StartNonTerminator), [ [new NonTerminator(NonTerminatorType.ProgramStruct)] ] }, { new NonTerminator(NonTerminatorType.ProgramStruct), [ [ new NonTerminator(NonTerminatorType.ProgramStruct), new Terminator(OperatorType.Plus), new NonTerminator(NonTerminatorType.ProgramBody) ], [ new NonTerminator(NonTerminatorType.ProgramStruct), new Terminator(OperatorType.Minus), new NonTerminator(NonTerminatorType.ProgramBody) ], [new NonTerminator(NonTerminatorType.ProgramBody)] ] }, { new NonTerminator(NonTerminatorType.ProgramBody), [ [ new NonTerminator(NonTerminatorType.ProgramBody), new Terminator(OperatorType.Multiply), new NonTerminator(NonTerminatorType.StatementList) ], [ new NonTerminator(NonTerminatorType.ProgramBody), new Terminator(OperatorType.Divide), new NonTerminator(NonTerminatorType.StatementList) ], [new NonTerminator(NonTerminatorType.StatementList)] ] }, { new NonTerminator(NonTerminatorType.StatementList), [ [ new Terminator(DelimiterType.LeftParenthesis), new NonTerminator(NonTerminatorType.ProgramStruct), new Terminator(DelimiterType.RightParenthesis) ], [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)); Assert.Contains(builder.FirstSet, pair => pair.Key == new NonTerminator(NonTerminatorType.StatementList)); foreach (HashSet terminators in builder.FirstSet.Values) { Assert.Contains(Terminator.IdentifierTerminator, terminators); Assert.Contains(new Terminator(DelimiterType.LeftParenthesis), terminators); } } [Fact] public void StatsTest() { GrammarBuilder builder = new() { Generators = s_simpleGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator) }; Grammar grammar = builder.Build(); Assert.Equal(30, builder.Automation.Count); // 来自Ichirinko不辞辛劳的手算 Assert.Contains(new NonTerminator(NonTerminatorType.ProgramStruct), grammar.BeginState.Transformer.Keys); Assert.Contains(new NonTerminator(NonTerminatorType.ProgramBody), grammar.BeginState.Transformer.Keys); Assert.Contains(new NonTerminator(NonTerminatorType.StatementList), grammar.BeginState.Transformer.Keys); Assert.Contains(new Terminator(DelimiterType.LeftParenthesis), grammar.BeginState.Transformer.Keys); Assert.Contains(Terminator.IdentifierTerminator, grammar.BeginState.Transformer.Keys); } [Fact] public void AnalyseSingleSentenceTest() { GrammarBuilder builder = new() { Generators = s_simpleGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator) }; Grammar grammar = builder.Build(); List tokens = [ new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "n" }, new OperatorSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "+", OperatorType = OperatorType.Plus }, new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "n" }, SemanticToken.End ]; // 验证分析语句不会抛出错误 grammar.Analyse(tokens); } }