2024-04-07 16:47:28 +08:00
|
|
|
|
using Canon.Core.Enums;
|
|
|
|
|
using Canon.Core.GrammarParser;
|
2024-03-13 16:41:44 +08:00
|
|
|
|
using Canon.Core.LexicalParser;
|
2024-04-07 16:47:28 +08:00
|
|
|
|
using Canon.Core.SyntaxNodes;
|
2024-03-13 16:41:44 +08:00
|
|
|
|
|
|
|
|
|
namespace Canon.Core.Abstractions;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 语法分析器接口
|
|
|
|
|
/// </summary>
|
|
|
|
|
public abstract class GrammarParserBase
|
|
|
|
|
{
|
|
|
|
|
public abstract ITransformer BeginTransformer { get; }
|
|
|
|
|
|
|
|
|
|
public abstract NonTerminator Begin { get; }
|
|
|
|
|
|
2024-04-07 16:47:28 +08:00
|
|
|
|
public SyntaxNodeBase Analyse(IEnumerable<SemanticToken> tokens)
|
2024-03-13 16:41:44 +08:00
|
|
|
|
{
|
|
|
|
|
Stack<AnalyseState> stack = [];
|
2024-04-07 16:47:28 +08:00
|
|
|
|
stack.Push(new AnalyseState(BeginTransformer, SyntaxNodeBase.Create(SemanticToken.End)));
|
2024-03-13 16:41:44 +08:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-07 16:47:28 +08:00
|
|
|
|
List<SyntaxNodeBase> children = [];
|
|
|
|
|
NonTerminatorType leftType = information.Left.Type;
|
2024-03-13 16:41:44 +08:00
|
|
|
|
for (int i = 0; i < information.Length; i++)
|
|
|
|
|
{
|
2024-04-07 16:47:28 +08:00
|
|
|
|
children.Add(stack.Pop().Node);
|
2024-03-13 16:41:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-04-07 16:47:28 +08:00
|
|
|
|
// 为了符合生成式的顺序而倒序
|
|
|
|
|
children.Reverse();
|
2024-03-13 16:41:44 +08:00
|
|
|
|
stack.Push(new AnalyseState(stack.Peek().State.ShiftTable[information.Left],
|
2024-04-07 16:47:28 +08:00
|
|
|
|
SyntaxNodeBase.Create(leftType, children)));
|
2024-03-13 16:41:44 +08:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果没有成功归约就进行移进
|
|
|
|
|
if (top.State.ShiftTable.TryGetValue(enumerator.Current, out ITransformer? next))
|
|
|
|
|
{
|
2024-04-07 16:47:28 +08:00
|
|
|
|
stack.Push(new AnalyseState(next, SyntaxNodeBase.Create(enumerator.Current)));
|
2024-03-13 16:41:44 +08:00
|
|
|
|
if (enumerator.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Run out of token but not accept");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new InvalidOperationException("Failed to analyse input grammar");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-07 16:47:28 +08:00
|
|
|
|
private record AnalyseState(ITransformer State, SyntaxNodeBase Node);
|
2024-03-13 16:41:44 +08:00
|
|
|
|
}
|