2024-03-11 19:33:02 +08:00
|
|
|
|
using Canon.Core.LexicalParser;
|
|
|
|
|
|
|
|
|
|
namespace Canon.Core.GrammarParser;
|
2024-03-10 15:37:18 +08:00
|
|
|
|
|
|
|
|
|
public class Grammar
|
|
|
|
|
{
|
|
|
|
|
public required NonTerminator Begin { get; init; }
|
|
|
|
|
|
|
|
|
|
public required LrState BeginState { get; init; }
|
2024-03-11 19:33:02 +08:00
|
|
|
|
|
2024-03-11 21:57:47 +08:00
|
|
|
|
public SyntaxNode Analyse(IEnumerable<SemanticToken> tokens)
|
2024-03-11 19:33:02 +08:00
|
|
|
|
{
|
2024-03-11 21:57:47 +08:00
|
|
|
|
Stack<AnalyseState> stack = [];
|
|
|
|
|
stack.Push(new AnalyseState(BeginState, new SyntaxNode(SemanticToken.End)));
|
2024-03-11 19:33:02 +08:00
|
|
|
|
|
|
|
|
|
using IEnumerator<SemanticToken> enumerator = tokens.GetEnumerator();
|
|
|
|
|
if (!enumerator.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Input token list is empty");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
2024-03-11 21:57:47 +08:00
|
|
|
|
AnalyseState top = stack.Peek();
|
2024-03-11 19:33:02 +08:00
|
|
|
|
|
|
|
|
|
// 尝试进行移进
|
|
|
|
|
bool acceptFlag = false, reduceFlag = false;
|
2024-03-11 21:57:47 +08:00
|
|
|
|
foreach (Expression e in top.State.Expressions)
|
2024-03-11 19:33:02 +08:00
|
|
|
|
{
|
|
|
|
|
if (e.Pos == e.Right.Count && e.LookAhead == enumerator.Current)
|
|
|
|
|
{
|
|
|
|
|
if (e.Left == Begin)
|
|
|
|
|
{
|
|
|
|
|
acceptFlag = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
reduceFlag = true;
|
2024-03-11 21:57:47 +08:00
|
|
|
|
SyntaxNode newNode = new(e.Left.Type);
|
2024-03-11 19:33:02 +08:00
|
|
|
|
|
|
|
|
|
for (int i = 0; i < e.Right.Count; i++)
|
|
|
|
|
{
|
2024-03-11 21:57:47 +08:00
|
|
|
|
newNode.Children.Add(stack.Pop().Node);
|
2024-03-11 19:33:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-11 21:57:47 +08:00
|
|
|
|
stack.Push(new AnalyseState(stack.Peek().State.Transformer[e.Left],
|
|
|
|
|
newNode));
|
2024-03-11 19:33:02 +08:00
|
|
|
|
}
|
2024-03-11 21:57:47 +08:00
|
|
|
|
break;
|
2024-03-11 19:33:02 +08:00
|
|
|
|
}
|
2024-03-12 14:52:42 +08:00
|
|
|
|
|
|
|
|
|
if (e.Right.Count == 0 && e.LookAhead == enumerator.Current)
|
|
|
|
|
{
|
|
|
|
|
// 考虑空产生式的归约
|
|
|
|
|
// 显然空产生式是不能accept的
|
|
|
|
|
reduceFlag = true;
|
|
|
|
|
SyntaxNode newNode = new(e.Left.Type);
|
|
|
|
|
|
|
|
|
|
stack.Push(new AnalyseState(stack.Peek().State.Transformer[e.Left],
|
|
|
|
|
newNode));
|
|
|
|
|
}
|
2024-03-11 19:33:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (acceptFlag)
|
|
|
|
|
{
|
|
|
|
|
// 接受文法 退出循环
|
2024-03-11 21:57:47 +08:00
|
|
|
|
return top.Node;
|
2024-03-11 19:33:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reduceFlag)
|
|
|
|
|
{
|
|
|
|
|
// 归约
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 尝试进行移进
|
2024-03-11 21:57:47 +08:00
|
|
|
|
if (top.State.Transformer.TryGetValue(enumerator.Current, out LrState? next))
|
2024-03-11 19:33:02 +08:00
|
|
|
|
{
|
2024-03-11 21:57:47 +08:00
|
|
|
|
stack.Push(new AnalyseState(next, new SyntaxNode(enumerator.Current)));
|
2024-03-11 19:33:02 +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-03-11 21:57:47 +08:00
|
|
|
|
|
|
|
|
|
private record AnalyseState(LrState State, SyntaxNode Node);
|
2024-03-10 15:37:18 +08:00
|
|
|
|
}
|