feat: 添加语法分析基类抽象 (#8)
增加语法分析基类和状态转换接口抽象,为直接生成语法分析器做准备,同时也提前释放一些大对象,降低内存消耗。 Reviewed-on: PostGuard/Canon#8
This commit is contained in:
70
Canon.Core/Abstractions/GrammarParseBase.cs
Normal file
70
Canon.Core/Abstractions/GrammarParseBase.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using Canon.Core.GrammarParser;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 语法分析器接口
|
||||
/// </summary>
|
||||
public abstract class GrammarParserBase
|
||||
{
|
||||
public abstract ITransformer BeginTransformer { get; }
|
||||
|
||||
public abstract NonTerminator Begin { get; }
|
||||
|
||||
public SyntaxNode Analyse(IEnumerable<SemanticToken> tokens)
|
||||
{
|
||||
Stack<AnalyseState> stack = [];
|
||||
stack.Push(new AnalyseState(BeginTransformer, new SyntaxNode(SemanticToken.End)));
|
||||
|
||||
using IEnumerator<SemanticToken> enumerator = tokens.GetEnumerator();
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
throw new InvalidOperationException("Input token list is empty");
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
AnalyseState top = stack.Peek();
|
||||
|
||||
// 首先尝试进行归约
|
||||
if (top.State.ReduceTable.TryGetValue(enumerator.Current, out ReduceInformation? information))
|
||||
{
|
||||
if (information.Left == Begin)
|
||||
{
|
||||
// 如果是归约到起始符
|
||||
// 那么就直接返回不继续进行归约
|
||||
return top.Node;
|
||||
}
|
||||
|
||||
SyntaxNode newNode = new(information.Left.Type);
|
||||
for (int i = 0; i < information.Length; i++)
|
||||
{
|
||||
newNode.Children.Add(stack.Pop().Node);
|
||||
}
|
||||
|
||||
stack.Push(new AnalyseState(stack.Peek().State.ShiftTable[information.Left],
|
||||
newNode));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 如果没有成功归约就进行移进
|
||||
if (top.State.ShiftTable.TryGetValue(enumerator.Current, out ITransformer? next))
|
||||
{
|
||||
stack.Push(new AnalyseState(next, new SyntaxNode(enumerator.Current)));
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Run out of token but not accept");
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Failed to analyse input grammar");
|
||||
}
|
||||
}
|
||||
|
||||
private record AnalyseState(ITransformer State, SyntaxNode Node);
|
||||
}
|
26
Canon.Core/Abstractions/ITransformer.cs
Normal file
26
Canon.Core/Abstractions/ITransformer.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Canon.Core.GrammarParser;
|
||||
|
||||
namespace Canon.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 进行归约需要的信息
|
||||
/// </summary>
|
||||
/// <param name="Length">归约的长度</param>
|
||||
/// <param name="Left">归约得到的左部符号</param>
|
||||
public record ReduceInformation(int Length, NonTerminator Left);
|
||||
|
||||
/// <summary>
|
||||
/// 状态的各种迁移信息
|
||||
/// </summary>
|
||||
public interface ITransformer
|
||||
{
|
||||
/// <summary>
|
||||
/// 进行移进的信息
|
||||
/// </summary>
|
||||
public IDictionary<TerminatorBase, ITransformer> ShiftTable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 进行归约的信息
|
||||
/// </summary>
|
||||
public IDictionary<Terminator, ReduceInformation> ReduceTable { get; }
|
||||
}
|
Reference in New Issue
Block a user