parent
f1c569ee0e
commit
67deb0aa2c
11
Canon.Core/Abstractions/ICCodeGenerator.cs
Normal file
11
Canon.Core/Abstractions/ICCodeGenerator.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using Canon.Core.CodeGenerators;
|
||||
|
||||
namespace Canon.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 支持生成C语言代码的接口
|
||||
/// </summary>
|
||||
public interface ICCodeGenerator
|
||||
{
|
||||
public void GenerateCCode(CCodeBuilder builder);
|
||||
}
|
|
@ -8,13 +8,19 @@ namespace Canon.Core.Abstractions;
|
|||
/// <summary>
|
||||
/// 语法分析器接口
|
||||
/// </summary>
|
||||
public abstract class GrammarParserBase
|
||||
public interface IGrammarParser
|
||||
{
|
||||
public abstract ITransformer BeginTransformer { get; }
|
||||
public ITransformer BeginTransformer { get; }
|
||||
|
||||
public abstract NonTerminator Begin { get; }
|
||||
public NonTerminator Begin { get; }
|
||||
|
||||
public SyntaxNodeBase Analyse(IEnumerable<SemanticToken> tokens)
|
||||
/// <summary>
|
||||
/// 分析指定的词法记号流并构建对应的语法树
|
||||
/// </summary>
|
||||
/// <param name="tokens">输入的词法记号流</param>
|
||||
/// <returns>语法树的根节点</returns>
|
||||
/// <exception cref="InvalidOperationException">语法分析错误</exception>
|
||||
public ProgramStruct Analyse(IEnumerable<SemanticToken> tokens)
|
||||
{
|
||||
Stack<AnalyseState> stack = [];
|
||||
stack.Push(new AnalyseState(BeginTransformer, SyntaxNodeBase.Create(SemanticToken.End)));
|
||||
|
@ -36,7 +42,7 @@ public abstract class GrammarParserBase
|
|||
{
|
||||
// 如果是归约到起始符
|
||||
// 那么就直接返回不继续进行归约
|
||||
return top.Node;
|
||||
return top.Node.Convert<ProgramStruct>();
|
||||
}
|
||||
|
||||
List<SyntaxNodeBase> children = [];
|
11
Canon.Core/Abstractions/ILexer.cs
Normal file
11
Canon.Core/Abstractions/ILexer.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 词法分析器接口
|
||||
/// </summary>
|
||||
public interface ILexer
|
||||
{
|
||||
public IEnumerable<SemanticToken> Tokenize(ISourceReader reader);
|
||||
}
|
31
Canon.Core/Abstractions/ISourceReader.cs
Normal file
31
Canon.Core/Abstractions/ISourceReader.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Canon.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// 读取源代码的接口
|
||||
/// </summary>
|
||||
public interface ISourceReader
|
||||
{
|
||||
/// <summary>
|
||||
/// 尝试读取下一个字符
|
||||
/// </summary>
|
||||
/// <param name="c">读取到的字符</param>
|
||||
/// <returns>是否成功读取</returns>
|
||||
public bool TryReadChar([NotNullWhen(true)] out char? c);
|
||||
|
||||
/// <summary>
|
||||
/// 源文件名称
|
||||
/// </summary>
|
||||
public string FileName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前读取字符的行号
|
||||
/// </summary>
|
||||
public uint Line { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前读取字符的列号
|
||||
/// </summary>
|
||||
public uint Pos { get; }
|
||||
}
|
22
Canon.Core/CodeGenerators/CCodeBuilder.cs
Normal file
22
Canon.Core/CodeGenerators/CCodeBuilder.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Text;
|
||||
|
||||
namespace Canon.Core.CodeGenerators;
|
||||
|
||||
/// <summary>
|
||||
/// 构建C语言代码
|
||||
/// </summary>
|
||||
public class CCodeBuilder
|
||||
{
|
||||
private readonly StringBuilder _builder = new();
|
||||
|
||||
public void AddString(string code)
|
||||
{
|
||||
_builder.Append(code);
|
||||
}
|
||||
|
||||
|
||||
public string Build()
|
||||
{
|
||||
return _builder.ToString();
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ public class Grammar
|
|||
/// </summary>
|
||||
public required LrState BeginState { get; init; }
|
||||
|
||||
public GrammarParserBase ToGrammarParser()
|
||||
public IGrammarParser ToGrammarParser()
|
||||
{
|
||||
Dictionary<LrState, Transformer> transformers = [];
|
||||
|
||||
|
@ -71,10 +71,10 @@ public class Grammar
|
|||
return new GrammarParser(transformers[BeginState], Begin);
|
||||
}
|
||||
|
||||
private class GrammarParser(ITransformer beginTransformer, NonTerminator begin) : GrammarParserBase
|
||||
private class GrammarParser(ITransformer beginTransformer, NonTerminator begin) : IGrammarParser
|
||||
{
|
||||
public override ITransformer BeginTransformer { get; } = beginTransformer;
|
||||
public override NonTerminator Begin { get; } = begin;
|
||||
public ITransformer BeginTransformer { get; } = beginTransformer;
|
||||
public NonTerminator Begin { get; } = begin;
|
||||
}
|
||||
|
||||
private class Transformer : ITransformer
|
||||
|
|
|
@ -21,7 +21,8 @@ public abstract class NonTerminatedSyntaxNode : SyntaxNodeBase, IEnumerable<Synt
|
|||
{
|
||||
yield return child;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
NonTerminatedSyntaxNode nonTerminatedNode = child.Convert<NonTerminatedSyntaxNode>();
|
||||
|
||||
foreach (SyntaxNodeBase node in nonTerminatedNode)
|
||||
|
@ -30,6 +31,7 @@ public abstract class NonTerminatedSyntaxNode : SyntaxNodeBase, IEnumerable<Synt
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
|
@ -20,4 +21,9 @@ public class ProgramStruct : NonTerminatedSyntaxNode
|
|||
{
|
||||
return new ProgramStruct { Children = children };
|
||||
}
|
||||
|
||||
public override void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
builder.AddString("#include <PascalCoreLib.h>");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using Canon.Core.Enums;
|
||||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.Enums;
|
||||
using Canon.Core.LexicalParser;
|
||||
|
||||
namespace Canon.Core.SyntaxNodes;
|
||||
|
||||
public abstract class SyntaxNodeBase
|
||||
public abstract class SyntaxNodeBase : ICCodeGenerator
|
||||
{
|
||||
public abstract bool IsTerminated { get; }
|
||||
|
||||
|
@ -19,6 +21,14 @@ public abstract class SyntaxNodeBase
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 语法树节点基类对于生成C代码的默认实现
|
||||
/// </summary>
|
||||
public virtual void GenerateCCode(CCodeBuilder builder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static SyntaxNodeBase Create(SemanticToken token)
|
||||
{
|
||||
return new TerminatedSyntaxNode { Token = token };
|
||||
|
|
|
@ -7,11 +7,11 @@ namespace Canon.Generator.GrammarGenerator;
|
|||
public class GeneratedGrammarParser(
|
||||
Dictionary<string, GeneratedTransformer> transformers,
|
||||
string beginState,
|
||||
NonTerminator begin) : GrammarParserBase
|
||||
NonTerminator begin) : IGrammarParser
|
||||
{
|
||||
public override ITransformer BeginTransformer => transformers[beginState];
|
||||
public ITransformer BeginTransformer => transformers[beginState];
|
||||
|
||||
public override NonTerminator Begin => begin;
|
||||
public NonTerminator Begin => begin;
|
||||
|
||||
public string GenerateCode(string namespaceValue)
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ public class GeneratedGrammarParser(
|
|||
""");
|
||||
builder.Append('\n');
|
||||
|
||||
builder.Append("public class GeneratedGrammarParser : GrammarParserBase\n")
|
||||
builder.Append("public class GeneratedGrammarParser : IGrammarParser\n")
|
||||
.Append("{\n");
|
||||
|
||||
builder.Append("\tprivate static readonly Dictionary<string, GeneratedTransformer> s_transformers = new()\n")
|
||||
|
@ -104,10 +104,10 @@ public class GeneratedGrammarParser(
|
|||
""");
|
||||
builder.Append("\n");
|
||||
|
||||
builder.Append('\t').Append("public override ITransformer BeginTransformer => ")
|
||||
builder.Append('\t').Append("public ITransformer BeginTransformer => ")
|
||||
.Append($"s_transformers[\"{beginState}\"];\n");
|
||||
|
||||
builder.Append('\t').Append("public override NonTerminator Begin => ")
|
||||
builder.Append('\t').Append("public NonTerminator Begin => ")
|
||||
.Append(begin.GenerateCode()).Append(";\n");
|
||||
|
||||
builder.Append("}\n");
|
||||
|
|
33
Canon.Tests/CCodeGeneratorTests/BasicTests.cs
Normal file
33
Canon.Tests/CCodeGeneratorTests/BasicTests.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using Canon.Core.Abstractions;
|
||||
using Canon.Core.CodeGenerators;
|
||||
using Canon.Core.LexicalParser;
|
||||
using Canon.Core.SyntaxNodes;
|
||||
using Canon.Tests.GeneratedParserTests;
|
||||
|
||||
namespace Canon.Tests.CCodeGeneratorTests;
|
||||
|
||||
public class BasicTests
|
||||
{
|
||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||
|
||||
[Fact]
|
||||
public void ProgramStructTest()
|
||||
{
|
||||
CCodeBuilder builder = new();
|
||||
|
||||
const string program = """
|
||||
program DoNothing;
|
||||
begin
|
||||
end.
|
||||
""";
|
||||
|
||||
Lexer lexer = new(program);
|
||||
List<SemanticToken> tokens = lexer.Tokenize();
|
||||
tokens.Add(SemanticToken.End);
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
root.GenerateCCode(builder);
|
||||
|
||||
Assert.Equal("#include <PascalCoreLib.h>", builder.Build());
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ public class GenerateParserTests
|
|||
Generators = PascalGrammar.Grammar, Begin = new NonTerminator(NonTerminatorType.StartNonTerminator)
|
||||
};
|
||||
|
||||
private readonly GrammarParserBase _parser;
|
||||
private readonly IGrammarParser _parser;
|
||||
|
||||
public GenerateParserTests()
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,7 @@ namespace Canon.Tests.GrammarParserTests;
|
|||
|
||||
public class PascalGrammarTests
|
||||
{
|
||||
private readonly GrammarParserBase _parser = GeneratedGrammarParser.Instance;
|
||||
private readonly IGrammarParser _parser = GeneratedGrammarParser.Instance;
|
||||
|
||||
[Fact]
|
||||
public void DoNothingTest()
|
||||
|
@ -24,8 +24,9 @@ public class PascalGrammarTests
|
|||
List<SemanticToken> tokens = lexer.Tokenize();
|
||||
tokens.Add(SemanticToken.End);
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens).Convert<ProgramStruct>();
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
Assert.Equal("DoNothing", root.Head.ProgramName.LiteralValue);
|
||||
Assert.Equal(15, root.Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -43,7 +44,7 @@ public class PascalGrammarTests
|
|||
List<SemanticToken> tokens = lexer.Tokenize();
|
||||
tokens.Add(SemanticToken.End);
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens).Convert<ProgramStruct>();
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
Assert.Equal("Add", root.Head.ProgramName.LiteralValue);
|
||||
}
|
||||
|
||||
|
@ -63,11 +64,11 @@ public class PascalGrammarTests
|
|||
List<SemanticToken> tokens = lexer.Tokenize();
|
||||
tokens.Add(SemanticToken.End);
|
||||
|
||||
ProgramStruct root = _parser.Analyse(tokens).Convert<ProgramStruct>();
|
||||
ProgramStruct root = _parser.Analyse(tokens);
|
||||
Assert.Equal("exFunction", root.Head.ProgramName.LiteralValue);
|
||||
}
|
||||
|
||||
private static GrammarParserBase GenerateGrammarParser()
|
||||
private static IGrammarParser GenerateGrammarParser()
|
||||
{
|
||||
GrammarBuilder builder = new()
|
||||
{
|
||||
|
|
|
@ -159,7 +159,7 @@ public class SimpleGrammarWithEmptyTests(ITestOutputHelper testOutputHelper)
|
|||
};
|
||||
|
||||
Grammar grammar = builder.Build();
|
||||
GrammarParserBase parser = grammar.ToGrammarParser();
|
||||
IGrammarParser parser = grammar.ToGrammarParser();
|
||||
|
||||
ITransformer transformer1 = parser.BeginTransformer;
|
||||
Assert.Equal(3, transformer1.ShiftTable.Count);
|
||||
|
|
Loading…
Reference in New Issue
Block a user