add: 这就是完全的Pascal (#11)
5!8!4!个状态堂堂登场! Co-authored-by: Ichirinko <1621543655@qq.com> Reviewed-on: PostGuard/Canon#11
This commit is contained in:
parent
184604940e
commit
99fdd6438b
|
@ -19,7 +19,7 @@ public enum NonTerminatorType
|
||||||
VarDeclaration,
|
VarDeclaration,
|
||||||
Type,
|
Type,
|
||||||
BasicType,
|
BasicType,
|
||||||
Range,
|
Period,
|
||||||
Subprogram,
|
Subprogram,
|
||||||
SubprogramHead,
|
SubprogramHead,
|
||||||
SubprogramBody,
|
SubprogramBody,
|
||||||
|
@ -37,5 +37,9 @@ public enum NonTerminatorType
|
||||||
ExpressionList,
|
ExpressionList,
|
||||||
SimpleExpression,
|
SimpleExpression,
|
||||||
Term,
|
Term,
|
||||||
Factor
|
Factor,
|
||||||
|
AddOperator,
|
||||||
|
MultiplyOperator,
|
||||||
|
RelationOperator,
|
||||||
|
IdVarPart
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,15 @@ public enum DelimiterType
|
||||||
LeftSquareBracket,
|
LeftSquareBracket,
|
||||||
RightSquareBracket,
|
RightSquareBracket,
|
||||||
SingleQuotation,
|
SingleQuotation,
|
||||||
DoubleQuotation
|
DoubleQuotation,
|
||||||
|
/// <summary>
|
||||||
|
/// 访问记录字段用的点 x.a
|
||||||
|
/// </summary>
|
||||||
|
Dot,
|
||||||
|
/// <summary>
|
||||||
|
/// 数组声明上下界之间的分隔符 1..50
|
||||||
|
/// </summary>
|
||||||
|
DoubleDots
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum KeywordType
|
public enum KeywordType
|
||||||
|
@ -49,6 +57,15 @@ public enum KeywordType
|
||||||
For,
|
For,
|
||||||
To,
|
To,
|
||||||
Do,
|
Do,
|
||||||
|
Integer,
|
||||||
|
Real,
|
||||||
|
Boolean,
|
||||||
|
Character,
|
||||||
|
Divide,
|
||||||
|
Not,
|
||||||
|
Mod,
|
||||||
|
And,
|
||||||
|
Or
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OperatorType
|
public enum OperatorType
|
||||||
|
@ -63,9 +80,6 @@ public enum OperatorType
|
||||||
Minus,
|
Minus,
|
||||||
Multiply,
|
Multiply,
|
||||||
Divide,
|
Divide,
|
||||||
Mod,
|
|
||||||
And,
|
|
||||||
Or,
|
|
||||||
Assign
|
Assign
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
413
Canon.Tests/GrammarParserTests/PascalGrammarConstPart.cs
Normal file
413
Canon.Tests/GrammarParserTests/PascalGrammarConstPart.cs
Normal file
|
@ -0,0 +1,413 @@
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.GrammarParser;
|
||||||
|
using Canon.Core.LexicalParser;
|
||||||
|
|
||||||
|
namespace Canon.Tests.GrammarParserTests;
|
||||||
|
|
||||||
|
public class PascalGrammarConstPart
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<NonTerminator, List<List<TerminatorBase>>> s_pascalGrammar = new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// ProgramStart -> ProgramBody
|
||||||
|
new NonTerminator(NonTerminatorType.StartNonTerminator), [
|
||||||
|
[new NonTerminator(NonTerminatorType.ProgramBody)]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ProgramBody -> ConstDeclarations
|
||||||
|
new NonTerminator(NonTerminatorType.ProgramBody), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclarations),
|
||||||
|
// new NonTerminator(NonTerminatorType.VarDeclarations),
|
||||||
|
// new NonTerminator(NonTerminatorType.SubprogramDeclarations),
|
||||||
|
// new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ConstDeclarations -> ε | const ConstDeclaration ;
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclarations), [
|
||||||
|
[
|
||||||
|
Terminator.EmptyTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Const),
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||||
|
new Terminator(DelimiterType.Semicolon)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ConstDeclaration -> id = ConstValue | ConstDeclaration ; id = ConstValue
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclaration), [
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(OperatorType.Equal),
|
||||||
|
new NonTerminator(NonTerminatorType.ConstValue)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||||
|
new Terminator(DelimiterType.Semicolon),
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(OperatorType.Equal),
|
||||||
|
new NonTerminator(NonTerminatorType.ConstValue)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ConstValue -> +num | -num | num | 'letter'
|
||||||
|
new NonTerminator(NonTerminatorType.ConstValue), [
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Plus), Terminator.NumberTerminator
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Minus), Terminator.NumberTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Terminator.NumberTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(DelimiterType.SingleQuotation),
|
||||||
|
Terminator.CharacterTerminator,
|
||||||
|
new Terminator(DelimiterType.SingleQuotation),
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AstTestFirst()
|
||||||
|
{
|
||||||
|
GrammarBuilder builder = new()
|
||||||
|
{
|
||||||
|
Generators = s_pascalGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
||||||
|
};
|
||||||
|
|
||||||
|
GrammarParserBase grammar = builder.Build().ToGrammarParser();
|
||||||
|
|
||||||
|
// const a = +5;
|
||||||
|
List<SemanticToken> tokens =
|
||||||
|
[
|
||||||
|
new KeywordSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, KeywordType = KeywordType.Const, LinePos = 0, LiteralValue = "const"
|
||||||
|
},
|
||||||
|
new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "a" },
|
||||||
|
new OperatorSemanticToken
|
||||||
|
{
|
||||||
|
LinePos = 0, CharacterPos = 0, LiteralValue = "=", OperatorType = OperatorType.Equal
|
||||||
|
},
|
||||||
|
new OperatorSemanticToken
|
||||||
|
{
|
||||||
|
LinePos = 0, CharacterPos = 0, LiteralValue = "+", OperatorType = OperatorType.Plus
|
||||||
|
},
|
||||||
|
new NumberSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, LinePos = 0, LiteralValue = "5", NumberType = NumberType.Integer
|
||||||
|
},
|
||||||
|
new DelimiterSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, DelimiterType = DelimiterType.Semicolon, LinePos = 0, LiteralValue = ";"
|
||||||
|
},
|
||||||
|
SemanticToken.End
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// ProgramBody
|
||||||
|
SyntaxNode root = grammar.Analyse(tokens);
|
||||||
|
Assert.Equal(NonTerminatorType.ProgramBody, root.GetNonTerminatorType());
|
||||||
|
Assert.Single(root.Children);
|
||||||
|
Assert.Equal(10, root.Count());
|
||||||
|
|
||||||
|
// ConstDeclarations
|
||||||
|
root = root.Children[0];
|
||||||
|
Assert.Equal(NonTerminatorType.ConstDeclarations, root.GetNonTerminatorType());
|
||||||
|
Assert.Equal(3, root.Children.Count);
|
||||||
|
|
||||||
|
Assert.Contains(root.Children, node =>
|
||||||
|
{
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Keyword)
|
||||||
|
{
|
||||||
|
KeywordSemanticToken token = (KeywordSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.KeywordType == KeywordType.Const;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||||
|
{
|
||||||
|
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.DelimiterType == DelimiterType.Semicolon;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ConstDeclaration
|
||||||
|
root = root.Children.Where(child =>
|
||||||
|
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration
|
||||||
|
).ElementAt(0);
|
||||||
|
|
||||||
|
Assert.Equal(NonTerminatorType.ConstDeclaration, root.GetNonTerminatorType());
|
||||||
|
Assert.Equal(3, root.Children.Count);
|
||||||
|
Assert.Contains(root.Children, node =>
|
||||||
|
{
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Identifier)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstValue)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||||
|
{
|
||||||
|
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.OperatorType == OperatorType.Equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ConstValue
|
||||||
|
root = root.Children.Where(child =>
|
||||||
|
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstValue
|
||||||
|
).ElementAt(0);
|
||||||
|
Assert.Equal(NonTerminatorType.ConstValue, root.GetNonTerminatorType());
|
||||||
|
Assert.Equal(2, root.Children.Count);
|
||||||
|
Assert.Contains(root.Children, node =>
|
||||||
|
{
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||||
|
{
|
||||||
|
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.OperatorType == OperatorType.Plus;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Number)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AstTestSecond()
|
||||||
|
{
|
||||||
|
GrammarBuilder builder = new()
|
||||||
|
{
|
||||||
|
Generators = s_pascalGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
||||||
|
};
|
||||||
|
|
||||||
|
GrammarParserBase grammar = builder.Build().ToGrammarParser();
|
||||||
|
|
||||||
|
// const a = 5; McCafe = 'Under Pressure (Queen & D. Bowie)' ;
|
||||||
|
List<SemanticToken> tokens =
|
||||||
|
[
|
||||||
|
new KeywordSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, KeywordType = KeywordType.Const, LinePos = 0, LiteralValue = "const"
|
||||||
|
},
|
||||||
|
new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "a" },
|
||||||
|
new OperatorSemanticToken
|
||||||
|
{
|
||||||
|
LinePos = 0, CharacterPos = 0, LiteralValue = "=", OperatorType = OperatorType.Equal
|
||||||
|
},
|
||||||
|
new NumberSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, LinePos = 0, LiteralValue = "5", NumberType = NumberType.Integer
|
||||||
|
},
|
||||||
|
new DelimiterSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, DelimiterType = DelimiterType.Semicolon, LinePos = 0, LiteralValue = ";"
|
||||||
|
},
|
||||||
|
new IdentifierSemanticToken { LinePos = 0, CharacterPos = 0, LiteralValue = "McCafe" },
|
||||||
|
new OperatorSemanticToken
|
||||||
|
{
|
||||||
|
LinePos = 0, CharacterPos = 0, LiteralValue = "=", OperatorType = OperatorType.Equal
|
||||||
|
},
|
||||||
|
new DelimiterSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, DelimiterType = DelimiterType.SingleQuotation, LinePos = 0, LiteralValue = "'"
|
||||||
|
},
|
||||||
|
new CharacterSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, LinePos = 0, LiteralValue = "Under Pressure (Queen & D. Bowie)"
|
||||||
|
},
|
||||||
|
new DelimiterSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, DelimiterType = DelimiterType.SingleQuotation, LinePos = 0, LiteralValue = "'"
|
||||||
|
},
|
||||||
|
new DelimiterSemanticToken
|
||||||
|
{
|
||||||
|
CharacterPos = 0, DelimiterType = DelimiterType.Semicolon, LinePos = 0, LiteralValue = ";"
|
||||||
|
},
|
||||||
|
SemanticToken.End
|
||||||
|
];
|
||||||
|
|
||||||
|
// 分析树见文档
|
||||||
|
|
||||||
|
// ProgramBody
|
||||||
|
SyntaxNode root = grammar.Analyse(tokens);
|
||||||
|
Assert.Equal(NonTerminatorType.ProgramBody, root.GetNonTerminatorType());
|
||||||
|
Assert.Single(root.Children);
|
||||||
|
Assert.Equal(17, root.Count());
|
||||||
|
|
||||||
|
// ConstDeclarations
|
||||||
|
root = root.Children[0];
|
||||||
|
Assert.Equal(NonTerminatorType.ConstDeclarations, root.GetNonTerminatorType());
|
||||||
|
Assert.Equal(3, root.Children.Count);
|
||||||
|
|
||||||
|
Assert.Contains(root.Children, node =>
|
||||||
|
{
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Keyword)
|
||||||
|
{
|
||||||
|
KeywordSemanticToken token = (KeywordSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.KeywordType == KeywordType.Const;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||||
|
{
|
||||||
|
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.DelimiterType == DelimiterType.Semicolon;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ConstDeclaration layer3
|
||||||
|
root = root.Children.Where(child =>
|
||||||
|
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration
|
||||||
|
).ElementAt(0);
|
||||||
|
|
||||||
|
Assert.Equal(NonTerminatorType.ConstDeclaration, root.GetNonTerminatorType());
|
||||||
|
Assert.Equal(5, root.Children.Count);
|
||||||
|
Assert.Contains(root.Children, node =>
|
||||||
|
{
|
||||||
|
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||||
|
{
|
||||||
|
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.DelimiterType == DelimiterType.Semicolon;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Identifier)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstValue)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||||
|
{
|
||||||
|
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.OperatorType == OperatorType.Equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ConstDeclaration layer4
|
||||||
|
SyntaxNode constDeclarationLayer4 = root.Children.Where(child =>
|
||||||
|
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstDeclaration
|
||||||
|
).ElementAt(0);
|
||||||
|
Assert.Equal(NonTerminatorType.ConstDeclaration, constDeclarationLayer4.GetNonTerminatorType());
|
||||||
|
Assert.Equal(3, constDeclarationLayer4.Children.Count);
|
||||||
|
Assert.Contains(constDeclarationLayer4.Children, node =>
|
||||||
|
{
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Identifier)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Operator)
|
||||||
|
{
|
||||||
|
OperatorSemanticToken token = (OperatorSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.OperatorType == OperatorType.Equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.IsTerminated && node.GetNonTerminatorType() == NonTerminatorType.ConstValue)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// ConstValue layer4
|
||||||
|
SyntaxNode constValueLayer4 = root.Children.Where(child =>
|
||||||
|
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstValue
|
||||||
|
).ElementAt(0);
|
||||||
|
Assert.Equal(NonTerminatorType.ConstValue, constValueLayer4.GetNonTerminatorType());
|
||||||
|
Assert.Equal(3, constValueLayer4.Children.Count);
|
||||||
|
Assert.Contains(constValueLayer4.Children, node =>
|
||||||
|
{
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||||
|
{
|
||||||
|
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.DelimiterType == DelimiterType.SingleQuotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Character)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Delimiter)
|
||||||
|
{
|
||||||
|
DelimiterSemanticToken token = (DelimiterSemanticToken)node.GetSemanticToken();
|
||||||
|
|
||||||
|
return token.DelimiterType == DelimiterType.SingleQuotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ConstValue layer5
|
||||||
|
SyntaxNode constValueLayer5 = constDeclarationLayer4.Children.Where(child =>
|
||||||
|
!child.IsTerminated && child.GetNonTerminatorType() == NonTerminatorType.ConstValue
|
||||||
|
).ElementAt(0);
|
||||||
|
Assert.Equal(NonTerminatorType.ConstValue, constValueLayer5.GetNonTerminatorType());
|
||||||
|
Assert.Single(constValueLayer5.Children);
|
||||||
|
Assert.Contains(constValueLayer5.Children, node =>
|
||||||
|
{
|
||||||
|
if (node.IsTerminated && node.GetSemanticToken().TokenType == SemanticTokenType.Number)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
595
Canon.Tests/GrammarParserTests/PascalGrammarTests.Grammar.cs
Normal file
595
Canon.Tests/GrammarParserTests/PascalGrammarTests.Grammar.cs
Normal file
|
@ -0,0 +1,595 @@
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.GrammarParser;
|
||||||
|
|
||||||
|
namespace Canon.Tests.GrammarParserTests;
|
||||||
|
|
||||||
|
public partial class PascalGrammarTests
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<NonTerminator, List<List<TerminatorBase>>> s_pascalGrammar = new()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// ProgramStart -> ProgramStruct
|
||||||
|
new NonTerminator(NonTerminatorType.StartNonTerminator), [
|
||||||
|
[new NonTerminator(NonTerminatorType.ProgramStruct)]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ProgramStruct -> ProgramHead ; ProgramBody .
|
||||||
|
new NonTerminator(NonTerminatorType.ProgramStruct), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ProgramHead),
|
||||||
|
new Terminator(DelimiterType.Semicolon),
|
||||||
|
new NonTerminator(NonTerminatorType.ProgramBody),
|
||||||
|
new Terminator(DelimiterType.Period)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ProgramHead -> program id (IdList) | program id
|
||||||
|
new NonTerminator(NonTerminatorType.ProgramHead), [
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Program),
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Program),
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ProgramBody -> ConstDeclarations
|
||||||
|
// VarDeclarations
|
||||||
|
// SubprogramDeclarations
|
||||||
|
// CompoundStatement
|
||||||
|
new NonTerminator(NonTerminatorType.ProgramBody), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclarations),
|
||||||
|
new NonTerminator(NonTerminatorType.VarDeclarations),
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramDeclarations),
|
||||||
|
new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// IdList -> id | IdList , id
|
||||||
|
new NonTerminator(NonTerminatorType.IdentifierList), [
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||||
|
new Terminator(DelimiterType.Comma),
|
||||||
|
Terminator.IdentifierTerminator
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ConstDeclarations -> ε | const ConstDeclaration ;
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclarations), [
|
||||||
|
[
|
||||||
|
Terminator.EmptyTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Const),
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||||
|
new Terminator(DelimiterType.Semicolon)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ConstDeclaration -> id = ConstValue | ConstDeclaration ; id = ConstValue
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclaration), [
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(OperatorType.Equal),
|
||||||
|
new NonTerminator(NonTerminatorType.ConstValue)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclaration),
|
||||||
|
new Terminator(DelimiterType.Semicolon),
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(OperatorType.Equal),
|
||||||
|
new NonTerminator(NonTerminatorType.ConstValue)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ConstValue -> +num | -num | num | 'letter'
|
||||||
|
new NonTerminator(NonTerminatorType.ConstValue), [
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Plus), Terminator.NumberTerminator
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Minus), Terminator.NumberTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Terminator.NumberTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(DelimiterType.SingleQuotation),
|
||||||
|
Terminator.CharacterTerminator,
|
||||||
|
new Terminator(DelimiterType.SingleQuotation),
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// VarDeclarations -> ε | var VarDeclaration ;
|
||||||
|
new NonTerminator(NonTerminatorType.VarDeclarations), [
|
||||||
|
[
|
||||||
|
Terminator.EmptyTerminator
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Var),
|
||||||
|
new NonTerminator(NonTerminatorType.VarDeclaration),
|
||||||
|
new Terminator(DelimiterType.Semicolon)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// VarDeclaration -> IdList : Type | VarDeclaration ; IdList : Type
|
||||||
|
new NonTerminator(NonTerminatorType.VarDeclaration), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||||
|
new Terminator(DelimiterType.Colon),
|
||||||
|
new NonTerminator(NonTerminatorType.Type)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.VarDeclaration),
|
||||||
|
new Terminator(DelimiterType.Semicolon),
|
||||||
|
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||||
|
new Terminator(DelimiterType.Colon),
|
||||||
|
new NonTerminator(NonTerminatorType.Type)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Type -> BasicType | Array [ Period ] of BasicType
|
||||||
|
new NonTerminator(NonTerminatorType.Type), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.BasicType)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Array),
|
||||||
|
new Terminator(DelimiterType.LeftSquareBracket),
|
||||||
|
new NonTerminator(NonTerminatorType.Period),
|
||||||
|
new Terminator(DelimiterType.RightSquareBracket),
|
||||||
|
new Terminator(KeywordType.Of),
|
||||||
|
new NonTerminator(NonTerminatorType.BasicType)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// BasicType -> Integer | Real | Boolean | char
|
||||||
|
new NonTerminator(NonTerminatorType.BasicType), [
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Integer)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Real)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Boolean)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Character)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Period -> digits .. digits | Period , digits .. digits
|
||||||
|
new NonTerminator(NonTerminatorType.Period), [
|
||||||
|
[
|
||||||
|
Terminator.NumberTerminator,
|
||||||
|
new Terminator(DelimiterType.DoubleDots),
|
||||||
|
Terminator.NumberTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Period),
|
||||||
|
new Terminator(DelimiterType.Comma),
|
||||||
|
Terminator.NumberTerminator,
|
||||||
|
new Terminator(DelimiterType.DoubleDots),
|
||||||
|
Terminator.NumberTerminator,
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SubprogramDeclarations -> ε | SubprogramDeclarations Subprogram ;
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramDeclarations), [
|
||||||
|
[
|
||||||
|
Terminator.EmptyTerminator
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramDeclarations),
|
||||||
|
new NonTerminator(NonTerminatorType.Subprogram),
|
||||||
|
new Terminator(DelimiterType.Semicolon)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Subprogram -> SubprogramHead ; SubprogramBody
|
||||||
|
new NonTerminator(NonTerminatorType.Subprogram), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramHead),
|
||||||
|
new Terminator(DelimiterType.Semicolon),
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramBody)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SubprogramHead -> procedure id FormalParameter
|
||||||
|
// | function id FormalParameter : BasicType
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramHead), [
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Procedure),
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new NonTerminator(NonTerminatorType.FormalParameter)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Function),
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new NonTerminator(NonTerminatorType.FormalParameter),
|
||||||
|
new Terminator(DelimiterType.Colon),
|
||||||
|
new NonTerminator(NonTerminatorType.BasicType)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// FormalParameter -> ε | ( ParameterList )
|
||||||
|
new NonTerminator(NonTerminatorType.FormalParameter), [
|
||||||
|
[
|
||||||
|
Terminator.EmptyTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new NonTerminator(NonTerminatorType.ParameterList),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ParameterList -> Parameter | ParameterList ; Parameter
|
||||||
|
new NonTerminator(NonTerminatorType.ParameterList), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Parameter)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ParameterList),
|
||||||
|
new Terminator(DelimiterType.Semicolon),
|
||||||
|
new NonTerminator(NonTerminatorType.Parameter)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Parameter -> VarParameter | ValueParameter
|
||||||
|
new NonTerminator(NonTerminatorType.Parameter), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.VarParameter)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ValueParameter)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// VarParameter -> var ValueParameter
|
||||||
|
new NonTerminator(NonTerminatorType.VarParameter), [
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Var),
|
||||||
|
new NonTerminator(NonTerminatorType.ValueParameter)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ValueParameter -> IdList : BasicType
|
||||||
|
new NonTerminator(NonTerminatorType.ValueParameter), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.IdentifierList),
|
||||||
|
new Terminator(DelimiterType.Colon),
|
||||||
|
new NonTerminator(NonTerminatorType.BasicType)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SubprogramBody -> ConstDeclarations
|
||||||
|
// VarDeclarations
|
||||||
|
// CompoundStatement
|
||||||
|
new NonTerminator(NonTerminatorType.SubprogramBody), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ConstDeclarations),
|
||||||
|
new NonTerminator(NonTerminatorType.VarDeclarations),
|
||||||
|
new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// CompoundStatement -> begin StatementList end
|
||||||
|
new NonTerminator(NonTerminatorType.CompoundStatement), [
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Begin),
|
||||||
|
new NonTerminator(NonTerminatorType.StatementList),
|
||||||
|
new Terminator(KeywordType.End)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// StatementList -> Statement | StatementList ; Statement
|
||||||
|
new NonTerminator(NonTerminatorType.StatementList), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Statement)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.StatementList),
|
||||||
|
new Terminator(DelimiterType.Semicolon),
|
||||||
|
new NonTerminator(NonTerminatorType.Statement)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Statement -> ε
|
||||||
|
// | Variable AssignOp Expression
|
||||||
|
// | FuncId AssignOp Expression
|
||||||
|
// | ProcedureCall
|
||||||
|
// | CompoundStatement
|
||||||
|
// | if Expression then Statement ElsePart
|
||||||
|
// | for id AssignOp Expression to Expression do Statement
|
||||||
|
// | read ( VariableList )
|
||||||
|
// | write( ExpressionList )
|
||||||
|
// 注意这里 read 和 write 作为普通的函数调用处理了
|
||||||
|
// 因此下面并没有单独声明
|
||||||
|
new NonTerminator(NonTerminatorType.Statement), [
|
||||||
|
[
|
||||||
|
// ε
|
||||||
|
Terminator.EmptyTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// Variable AssignOp Expression
|
||||||
|
new NonTerminator(NonTerminatorType.Variable),
|
||||||
|
new Terminator(OperatorType.Assign),
|
||||||
|
new NonTerminator(NonTerminatorType.Expression)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// FuncId AssignOp Expression
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(OperatorType.Assign),
|
||||||
|
new NonTerminator(NonTerminatorType.Expression)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// ProcedureCall
|
||||||
|
new NonTerminator(NonTerminatorType.ProcedureCall)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// CompoundStatement
|
||||||
|
new NonTerminator(NonTerminatorType.CompoundStatement)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// if Expression then Statement ElsePart
|
||||||
|
new Terminator(KeywordType.If),
|
||||||
|
new NonTerminator(NonTerminatorType.Expression),
|
||||||
|
new Terminator(KeywordType.Then),
|
||||||
|
new NonTerminator(NonTerminatorType.Statement),
|
||||||
|
new NonTerminator(NonTerminatorType.ElsePart)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// for id AssignOp Expression to Expression do Statement
|
||||||
|
new Terminator(KeywordType.For),
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(OperatorType.Assign),
|
||||||
|
new NonTerminator(NonTerminatorType.Expression),
|
||||||
|
new Terminator(KeywordType.To),
|
||||||
|
new NonTerminator(NonTerminatorType.Expression),
|
||||||
|
new Terminator(KeywordType.Do),
|
||||||
|
new NonTerminator(NonTerminatorType.Statement)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// // VariableList -> Variable | VariableList , Variable
|
||||||
|
// // 这里用expressionList代替VariableList
|
||||||
|
// new NonTerminator(NonTerminatorType.ExpressionList), [
|
||||||
|
// [
|
||||||
|
// new NonTerminator(NonTerminatorType.Variable)
|
||||||
|
// ],
|
||||||
|
// [
|
||||||
|
// new NonTerminator(NonTerminatorType.ExpressionList),
|
||||||
|
// new Terminator(DelimiterType.Comma),
|
||||||
|
// new NonTerminator(NonTerminatorType.Variable)
|
||||||
|
// ]
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
// Variable -> id IdVarPart
|
||||||
|
new NonTerminator(NonTerminatorType.Variable), [
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new NonTerminator(NonTerminatorType.IdVarPart)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// IdVarPart -> ε | [ ExpressionList ]
|
||||||
|
new NonTerminator(NonTerminatorType.IdVarPart), [
|
||||||
|
[
|
||||||
|
Terminator.EmptyTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(DelimiterType.LeftSquareBracket),
|
||||||
|
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||||
|
new Terminator(DelimiterType.RightSquareBracket)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ProcedureCall -> id | id ( ExpressionList )
|
||||||
|
new NonTerminator(NonTerminatorType.ProcedureCall), [
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ElsePart -> ε | else statement
|
||||||
|
new NonTerminator(NonTerminatorType.ElsePart), [
|
||||||
|
[
|
||||||
|
Terminator.EmptyTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Else),
|
||||||
|
new NonTerminator(NonTerminatorType.Statement)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// ExpressionList -> Expression | ExpressionList , Expression
|
||||||
|
new NonTerminator(NonTerminatorType.ExpressionList), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Expression)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||||
|
new Terminator(DelimiterType.Comma),
|
||||||
|
new NonTerminator(NonTerminatorType.Expression)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Expression -> SimpleExpression | SimpleExpression RelationOperator SimpleExpression
|
||||||
|
new NonTerminator(NonTerminatorType.Expression), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.SimpleExpression)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.SimpleExpression),
|
||||||
|
new NonTerminator(NonTerminatorType.RelationOperator),
|
||||||
|
new NonTerminator(NonTerminatorType.SimpleExpression)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// SimpleExpression -> Term | SimpleExpression AddOperator Term
|
||||||
|
new NonTerminator(NonTerminatorType.SimpleExpression), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Term)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.SimpleExpression),
|
||||||
|
new NonTerminator(NonTerminatorType.AddOperator),
|
||||||
|
new NonTerminator(NonTerminatorType.Term)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Term -> Factor | Term MultiplyOperator Factor
|
||||||
|
new NonTerminator(NonTerminatorType.Term), [
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Factor)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Term),
|
||||||
|
new NonTerminator(NonTerminatorType.MultiplyOperator),
|
||||||
|
new NonTerminator(NonTerminatorType.Factor)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Factor -> num | Variable
|
||||||
|
// | ( Expression )
|
||||||
|
// | id ( ExpressionList )
|
||||||
|
// | not Factor
|
||||||
|
// | minus Factor
|
||||||
|
new NonTerminator(NonTerminatorType.Factor), [
|
||||||
|
[
|
||||||
|
Terminator.NumberTerminator,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new NonTerminator(NonTerminatorType.Variable)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new NonTerminator(NonTerminatorType.Expression),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Terminator.IdentifierTerminator,
|
||||||
|
new Terminator(DelimiterType.LeftParenthesis),
|
||||||
|
new NonTerminator(NonTerminatorType.ExpressionList),
|
||||||
|
new Terminator(DelimiterType.RightParenthesis)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Not),
|
||||||
|
new NonTerminator(NonTerminatorType.Factor)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Minus),
|
||||||
|
new NonTerminator(NonTerminatorType.Factor)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// AddOperator -> + | - | or
|
||||||
|
new NonTerminator(NonTerminatorType.AddOperator), [
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Plus)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Minus)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Or)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// MultiplyOperator -> * | / | div | mod | and
|
||||||
|
new NonTerminator(NonTerminatorType.MultiplyOperator), [
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Multiply),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Divide),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Divide)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.Mod)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(KeywordType.And)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// RelationOperator -> = | <> | < | <= | > | >=
|
||||||
|
new NonTerminator(NonTerminatorType.RelationOperator), [
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Equal)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.NotEqual)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Less)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.LessEqual)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.Greater)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
new Terminator(OperatorType.GreaterEqual)
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
27
Canon.Tests/GrammarParserTests/PascalGrammarTests.cs
Normal file
27
Canon.Tests/GrammarParserTests/PascalGrammarTests.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using Canon.Core.Abstractions;
|
||||||
|
using Canon.Core.Enums;
|
||||||
|
using Canon.Core.GrammarParser;
|
||||||
|
|
||||||
|
namespace Canon.Tests.GrammarParserTests;
|
||||||
|
|
||||||
|
public partial class PascalGrammarTests
|
||||||
|
{
|
||||||
|
private readonly GrammarBuilder _builder = new()
|
||||||
|
{
|
||||||
|
Generators = s_pascalGrammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly GrammarParserBase _parser;
|
||||||
|
|
||||||
|
public PascalGrammarTests()
|
||||||
|
{
|
||||||
|
Grammar grammar = _builder.Build();
|
||||||
|
_parser = grammar.ToGrammarParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GrammarTest()
|
||||||
|
{
|
||||||
|
Assert.NotNull(_parser);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ public class SimpleGrammarWithEmptyTests(ITestOutputHelper testOutputHelper)
|
||||||
/// B ProgramBody
|
/// B ProgramBody
|
||||||
/// a Identifier
|
/// a Identifier
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// private readonly ITestOutputHelper _testOutputHelper;
|
|
||||||
|
|
||||||
private readonly ITestOutputHelper _testOutputHelper = testOutputHelper;
|
private readonly ITestOutputHelper _testOutputHelper = testOutputHelper;
|
||||||
|
|
||||||
|
|
|
@ -6,45 +6,36 @@ namespace Canon.Tests.LexicalParserTests;
|
||||||
public class OperatorTypeTests
|
public class OperatorTypeTests
|
||||||
{
|
{
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("+ 123", OperatorType.Plus, 0u, 0u, true)]
|
[InlineData("+ 123", OperatorType.Plus)]
|
||||||
[InlineData("1 + 123", OperatorType.Plus, 0u, 2u, true)]
|
[InlineData("1 + 123", OperatorType.Plus)]
|
||||||
[InlineData("+123", OperatorType.Plus, 0u, 0u, true)]
|
[InlineData("+123", OperatorType.Plus)]
|
||||||
[InlineData("m +123", OperatorType.Plus, 0u, 2u, true)]
|
[InlineData("m +123", OperatorType.Plus)]
|
||||||
[InlineData("-123", OperatorType.Minus, 0u, 0u, true)]
|
[InlineData("-123", OperatorType.Minus)]
|
||||||
[InlineData("*123", OperatorType.Multiply, 0u, 0u, true)]
|
[InlineData("*123", OperatorType.Multiply)]
|
||||||
[InlineData("/123", OperatorType.Divide, 0u, 0u, true)]
|
[InlineData("/123", OperatorType.Divide)]
|
||||||
[InlineData("=123", OperatorType.Equal, 0u, 0u, true)]
|
[InlineData("=123", OperatorType.Equal)]
|
||||||
[InlineData("<123", OperatorType.Less, 0u, 0u, true)]
|
[InlineData("<123", OperatorType.Less)]
|
||||||
[InlineData(">123", OperatorType.Greater, 0u, 0u, true)]
|
[InlineData(">123", OperatorType.Greater)]
|
||||||
[InlineData("<=123", OperatorType.LessEqual, 0u, 0u, true)]
|
[InlineData("<=123", OperatorType.LessEqual)]
|
||||||
[InlineData(">=123", OperatorType.GreaterEqual, 0u, 0u, true)]
|
[InlineData(">=123", OperatorType.GreaterEqual)]
|
||||||
[InlineData("<>123", OperatorType.NotEqual, 0u, 0u, true)]
|
[InlineData("<>123", OperatorType.NotEqual)]
|
||||||
[InlineData(":=123", OperatorType.Assign, 0u, 0u, true)]
|
[InlineData(":=123", OperatorType.Assign)]
|
||||||
[InlineData("and 123", OperatorType.And, 0u, 0u, true)]
|
public void ParseTest(string input, OperatorType result)
|
||||||
[InlineData("or123", OperatorType.Or, 0u, 0u, true)]
|
|
||||||
[InlineData("mod123", OperatorType.Mod, 0u, 0u, true)]
|
|
||||||
|
|
||||||
[InlineData("and123", OperatorType.And, 0u, 0u, false)]
|
|
||||||
[InlineData("andasd", OperatorType.And, 0u, 0u, false)]
|
|
||||||
[InlineData("andand", OperatorType.And, 0u, 0u, false)]
|
|
||||||
[InlineData("<><123", OperatorType.NotEqual, 0u, 0u, false)]
|
|
||||||
[InlineData("<><123", OperatorType.Less, 0u, 0u, false)]
|
|
||||||
[InlineData("<=<123", OperatorType.LessEqual, 0u, 0u, false)]
|
|
||||||
public void SmokeTest(string input, OperatorType type, uint expectedLinePos, uint expectedCharacterPos, bool expectedResult)
|
|
||||||
{
|
{
|
||||||
LinkedList<char> content = Utils.GetLinkedList(input);
|
LinkedList<char> content = Utils.GetLinkedList(input);
|
||||||
Assert.Equal(expectedResult, OperatorSemanticToken.TryParse(expectedLinePos, expectedCharacterPos, content.First!,
|
Assert.True(OperatorSemanticToken.TryParse(0, 0,
|
||||||
out OperatorSemanticToken? token));
|
content.First!, out OperatorSemanticToken? token));
|
||||||
if (expectedResult)
|
Assert.Equal(result, token?.OperatorType);
|
||||||
{
|
|
||||||
Assert.NotNull(token);
|
|
||||||
Assert.Equal(type, token.OperatorType);
|
|
||||||
Assert.Equal(expectedLinePos, token.LinePos);
|
|
||||||
Assert.Equal(expectedCharacterPos, token.CharacterPos);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("<><123")]
|
||||||
|
[InlineData("<=<123")]
|
||||||
|
public void ParseFailedTest(string input)
|
||||||
{
|
{
|
||||||
|
LinkedList<char> content = Utils.GetLinkedList(input);
|
||||||
|
Assert.False(OperatorSemanticToken.TryParse(0, 0,
|
||||||
|
content.First!, out OperatorSemanticToken? token));
|
||||||
Assert.Null(token);
|
Assert.Null(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user