add: 这就是完全的Pascal (#11)

5!8!4!个状态堂堂登场!

Co-authored-by: Ichirinko <1621543655@qq.com>
Reviewed-on: PostGuard/Canon#11
This commit is contained in:
jackfiled 2024-03-13 23:58:06 +08:00
parent 184604940e
commit 99fdd6438b
7 changed files with 1088 additions and 45 deletions

View File

@ -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
} }

View File

@ -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
} }

View 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;
});
}
}

View 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)
]
]
}
};
}

View 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);
}
}

View File

@ -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;

View File

@ -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);
} }
}
} }