Roslyn 的語法樹只是第一步,真正的編譯需要進行語意分析,建立符號表和語意模型。
using System;
using System.Collections.Generic;
using System.Linq;
namespace MiniRoslyn.Symbols
{
// 符號基類 - 代表程式中的實體(類別、方法、變數等)
public abstract record Symbol(string Name, SymbolKind Kind);
public enum SymbolKind
{
Type, Method, Field, Property, Parameter, Local
}
public record TypeSymbol(string Name, TypeKind TypeKind, List<Symbol> Members)
: Symbol(Name, SymbolKind.Type);
public record MethodSymbol(string Name, TypeSymbol ReturnType, List<ParameterSymbol> Parameters)
: Symbol(Name, SymbolKind.Method);
public record ParameterSymbol(string Name, TypeSymbol Type)
: Symbol(Name, SymbolKind.Parameter);
public enum TypeKind
{
Class, Struct, Interface, Enum, Delegate
}
// 語意模型 - 提供語法節點的語意資訊查詢
public class SemanticModel
{
private readonly Dictionary<SyntaxNode, Symbol> _nodeToSymbol = new();
private readonly Dictionary<SyntaxNode, TypeSymbol> _nodeToType = new();
private readonly SymbolTable _symbolTable;
public SemanticModel(SymbolTable symbolTable)
{
_symbolTable = symbolTable;
}
public Symbol? GetSymbolInfo(SyntaxNode node)
{
return _nodeToSymbol.GetValueOrDefault(node);
}
public TypeSymbol? GetTypeInfo(SyntaxNode node)
{
return _nodeToType.GetValueOrDefault(node);
}
internal void BindSymbol(SyntaxNode node, Symbol symbol)
{
_nodeToSymbol[node] = symbol;
}
internal void BindType(SyntaxNode node, TypeSymbol type)
{
_nodeToType[node] = type;
}
}
// 符號表 - 管理作用域與符號解析
public class SymbolTable
{
private readonly Stack<Dictionary<string, Symbol>> _scopes = new();
public SymbolTable()
{
PushScope(); // 全域作用域
}
public void PushScope()
{
_scopes.Push(new Dictionary<string, Symbol>());
}
public void PopScope()
{
if (_scopes.Count > 1) // 保留全域作用域
_scopes.Pop();
}
public void DeclareSymbol(string name, Symbol symbol)
{
_scopes.Peek()[name] = symbol;
}
public Symbol? LookupSymbol(string name)
{
foreach (var scope in _scopes)
{
if (scope.TryGetValue(name, out var symbol))
return symbol;
}
return null;
}
}
}
Binding 是將語法節點與符號系統連結的過程:
namespace MiniRoslyn.Binding
{
using MiniRoslyn.Syntax;
using MiniRoslyn.Symbols;
// 綁定器 - 執行語意分析
public class Binder
{
private readonly SymbolTable _symbolTable;
private readonly SemanticModel _semanticModel;
private readonly Dictionary<string, TypeSymbol> _builtinTypes;
public Binder()
{
_symbolTable = new SymbolTable();
_semanticModel = new SemanticModel(_symbolTable);
// 內建類型
_builtinTypes = new Dictionary<string, TypeSymbol>
{
["int"] = new TypeSymbol("int", TypeKind.Struct, new List<Symbol>()),
["string"] = new TypeSymbol("string", TypeKind.Class, new List<Symbol>()),
["void"] = new TypeSymbol("void", TypeKind.Struct, new List<Symbol>())
};
foreach (var (name, type) in _builtinTypes)
{
_symbolTable.DeclareSymbol(name, type);
}
}
public SemanticModel Analyze(SyntaxNode root)
{
BindNode(root);
return _semanticModel;
}
private void BindNode(SyntaxNode node)
{
switch (node)
{
case NumberNode number:
_semanticModel.BindType(number, _builtinTypes["int"]);
break;
case BinaryNode binary:
BindNode(binary.Left);
BindNode(binary.Right);
var leftType = _semanticModel.GetTypeInfo(binary.Left);
var rightType = _semanticModel.GetTypeInfo(binary.Right);
// 簡化:假設都是 int 運算
if (leftType?.Name == "int" && rightType?.Name == "int")
{
_semanticModel.BindType(binary, _builtinTypes["int"]);
}
break;
}
}
}
}
Roslyn 的最終階段是將語意分析後的程式碼轉換為 IL:
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Text;
namespace MiniRoslyn.CodeGen
{
using MiniRoslyn.Syntax;
using MiniRoslyn.Symbols;
// IL 生成器
public class ILGenerator
{
private readonly StringBuilder _il = new();
private int _labelCounter = 0;
public string Generate(SyntaxNode node, SemanticModel semanticModel)
{
_il.Clear();
EmitPreamble();
EmitNode(node);
EmitPostamble();
return _il.ToString();
}
private void EmitPreamble()
{
_il.AppendLine(".assembly extern mscorlib {}");
_il.AppendLine(".assembly Sample {}");
_il.AppendLine(".class public Program extends [mscorlib]System.Object");
_il.AppendLine("{");
_il.AppendLine(" .method public static void Main() cil managed");
_il.AppendLine(" {");
_il.AppendLine(" .entrypoint");
}
private void EmitPostamble()
{
_il.AppendLine(" call void [mscorlib]System.Console::WriteLine(int32)");
_il.AppendLine(" ret");
_il.AppendLine(" }");
_il.AppendLine("}");
}
private void EmitNode(SyntaxNode node)
{
switch (node)
{
case NumberNode number:
EmitLoadConstant(number.Value);
break;
case BinaryNode binary:
EmitNode(binary.Left);
EmitNode(binary.Right);
EmitBinaryOperation(binary.Op);
break;
}
}
private void EmitLoadConstant(int value)
{
_il.AppendLine($" ldc.i4 {value}");
}
private void EmitBinaryOperation(string op)
{
switch (op)
{
case "+":
_il.AppendLine(" add");
break;
case "-":
_il.AppendLine(" sub");
break;
case "*":
_il.AppendLine(" mul");
break;
default:
throw new NotSupportedException($"Operator {op} not supported");
}
}
private string NewLabel()
{
return $"L{_labelCounter++}";
}
}
}