refact: syntax-node (#23)

重构语法树的部分,使用单独的类来抽象不同的非终结符节点。
**同时**,将`Pascal`语法的定义从测试项目中移动到核心项目中,在项目中只维护一份对于`Pascal`语法的定义。

Reviewed-on: PostGuard/Canon#23
This commit is contained in:
2024-04-07 16:47:28 +08:00
parent c0a8e25d45
commit 5e3ea6303e
48 changed files with 1273 additions and 708 deletions

View File

@@ -1,5 +1,4 @@
using Canon.Core.Abstractions;
using Canon.Core.LexicalParser;
namespace Canon.Core.GrammarParser;
@@ -86,6 +85,4 @@ public class Grammar
public IDictionary<Terminator, ReduceInformation> ReduceTable { get; }
= new Dictionary<Terminator, ReduceInformation>();
}
private record AnalyseState(LrState State, SyntaxNode Node);
}

View File

@@ -0,0 +1,594 @@
using Canon.Core.Enums;
namespace Canon.Core.GrammarParser;
public static class PascalGrammar
{
public static readonly Dictionary<NonTerminator, List<List<TerminatorBase>>> Grammar = 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

@@ -1,130 +0,0 @@
using System.Collections;
using Canon.Core.Enums;
using Canon.Core.LexicalParser;
namespace Canon.Core.GrammarParser;
/// <summary>
/// 抽象语法树上的节点
/// </summary>
public class SyntaxNode : IEquatable<SyntaxNode>, IEnumerable<SyntaxNode>
{
private readonly SemanticToken? _semanticToken;
private readonly NonTerminatorType _nonTerminatorType;
public bool IsTerminated { get; }
public List<SyntaxNode> Children { get; } = [];
public SyntaxNode(SemanticToken token)
{
IsTerminated = true;
_semanticToken = token;
}
public SyntaxNode(NonTerminatorType nonTerminatorType)
{
IsTerminated = false;
_nonTerminatorType = nonTerminatorType;
}
/// <summary>
/// 获得终结节点包含的记号对象
/// </summary>
/// <returns>词法分析得到的记号对象</returns>
/// <exception cref="InvalidOperationException">在非终结节点上调用该方法</exception>
public SemanticToken GetSemanticToken()
{
if (!IsTerminated)
{
throw new InvalidOperationException("Can not get semantic token from a not terminated node");
}
return _semanticToken!;
}
/// <summary>
/// 获得非终结节点的类型
/// </summary>
/// <returns>非终结节点类型</returns>
/// <exception cref="InvalidOperationException">在终结节点上调用该方法</exception>
public NonTerminatorType GetNonTerminatorType()
{
if (IsTerminated)
{
throw new InvalidOperationException("Can not get non terminated type from a terminated node");
}
return _nonTerminatorType;
}
public IEnumerator<SyntaxNode> GetEnumerator()
{
yield return this;
foreach (SyntaxNode child in Children)
{
foreach (SyntaxNode node in child)
{
yield return node;
}
}
}
public bool Equals(SyntaxNode? other)
{
if (other is null)
{
return false;
}
if (IsTerminated != other.IsTerminated)
{
return false;
}
if (IsTerminated)
{
return GetSemanticToken() == other.GetSemanticToken();
}
else
{
// TODO: 在判等时是否需要判断子节点也相等
return GetNonTerminatorType() == other.GetNonTerminatorType();
}
}
public override bool Equals(object? obj)
{
if (obj is not SyntaxNode other)
{
return false;
}
return Equals(other);
}
public override int GetHashCode()
{
if (IsTerminated)
{
return GetSemanticToken().GetHashCode();
}
else
{
return GetNonTerminatorType().GetHashCode();
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public static bool operator ==(SyntaxNode a, SyntaxNode b)
{
return a.Equals(b);
}
public static bool operator !=(SyntaxNode a, SyntaxNode b)
{
return !a.Equals(b);
}
}