From e6bf9ecd1272dd7b2758c74566e58c8c531d4738 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 6 May 2025 22:03:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96ir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../snow/compiler/builder/BasicIRBuilder.java | 193 ------------------ .../jcnc/snow/compiler/cli/SnowCompiler.java | 5 +- .../compiler/ir/builder/FunctionBuilder.java | 145 +++++++++++++ .../compiler/ir/builder/ProgramBuilder.java | 82 ++++++++ .../jcnc/snow/compiler/ir/builder/Scope.java | 77 +++++++ 5 files changed, 307 insertions(+), 195 deletions(-) delete mode 100644 src/main/java/org/jcnc/snow/compiler/builder/BasicIRBuilder.java create mode 100644 src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java create mode 100644 src/main/java/org/jcnc/snow/compiler/ir/builder/ProgramBuilder.java create mode 100644 src/main/java/org/jcnc/snow/compiler/ir/builder/Scope.java diff --git a/src/main/java/org/jcnc/snow/compiler/builder/BasicIRBuilder.java b/src/main/java/org/jcnc/snow/compiler/builder/BasicIRBuilder.java deleted file mode 100644 index 88de9b8..0000000 --- a/src/main/java/org/jcnc/snow/compiler/builder/BasicIRBuilder.java +++ /dev/null @@ -1,193 +0,0 @@ -package org.jcnc.snow.compiler.builder; - -import org.jcnc.snow.compiler.ir.core.IRFunction; -import org.jcnc.snow.compiler.ir.core.IROp; -import org.jcnc.snow.compiler.ir.core.IRProgram; -import org.jcnc.snow.compiler.ir.instr.BinOpInstruction; -import org.jcnc.snow.compiler.ir.instr.LoadConstInstruction; -import org.jcnc.snow.compiler.ir.instr.ReturnInstruction; -import org.jcnc.snow.compiler.ir.value.Constant; -import org.jcnc.snow.compiler.ir.value.VirtualRegister; -import org.jcnc.snow.compiler.parser.ast.*; -import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; -import org.jcnc.snow.compiler.parser.ast.base.Node; -import org.jcnc.snow.compiler.parser.ast.base.StatementNode; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * BasicIRBuilder 类 —— 负责将 AST(抽象语法树)转换为 IR(中间表示)。 - *

- * 支持的功能包括: - *

- *

- * 注意: - * - 当前仅支持简单语言特性; - * - 变量采用虚拟寄存器(VirtualRegister)建模,未来可扩展 SSA。 - */ -public final class BasicIRBuilder { - - /* ───────────────── 顶层 API ───────────────── */ - - /** - * 当前作用域中,变量名 -> 虚拟寄存器(VirtualRegister)的映射 - */ - private final Map variables = new HashMap<>(); - - /* ───────────────── 内部实现 ───────────────── */ - /** - * 当前正在构建的 IRFunction 实例 - */ - private IRFunction currentFn; - - /** - * 将一组顶层 AST 节点(模块、函数、语句)编译为 IRProgram。 - * - * @param roots AST 根节点列表 - * @return 编译生成的 IRProgram 对象 - */ - public IRProgram buildProgram(List roots) { - IRProgram prog = new IRProgram(); // 创建新的 IRProgram - for (Node node : roots) dispatchTop(node, prog); // 依次处理所有顶层节点 - return prog; - } - - /* ─────────────── 函数体级别状态 ─────────────── */ - - /** - * 处理单个顶层节点。 - * 可能是:模块(ModuleNode)、函数(FunctionNode)、单条语句(StatementNode)。 - * - * @param node AST 顶层节点 - * @param irProgram 正在构建的 IRProgram - */ - private void dispatchTop(Node node, IRProgram irProgram) { - switch (node) { - case ModuleNode moduleNode -> - moduleNode.functions().forEach(functionNode -> dispatchTop(functionNode, irProgram)); // 递归处理模块内的函数 - case FunctionNode functionNode -> - irProgram.add(buildFunction(functionNode)); // 将函数编译成 IRFunction 并加入 IRProgram - case StatementNode _ -> { - //TODO 单条语句(如脚本式 main) - } - default -> throw new IllegalStateException("不支持的顶级节点: " + node); - } - } - - /** - * 将一个 FunctionNode 编译成 IRFunction。 - * - * @param functionNode AST 中的函数节点 - * @return 生成的 IRFunction - */ - private IRFunction buildFunction(FunctionNode functionNode) { - currentFn = new IRFunction(functionNode.name()); // 创建新 IRFunction - variables.clear(); // 清空变量表(每个函数独立) - - // 将函数参数映射为新的寄存器(未进一步使用参数,但保留未来拓展空间) - for (ParameterNode parameterNode : functionNode.parameters()) { - variables.put(parameterNode.name(), currentFn.newRegister()); - } - - // 编译函数体中的每条语句 - for (StatementNode statementNode : functionNode.body()) stmt(statementNode); - - return currentFn; - } - - /* ─── 处理语句 ─── */ - - /** - * 编译单个语句节点为 IR 指令。 - * - * @param statementNode 语句 AST 节点 - */ - private void stmt(StatementNode statementNode) { - switch (statementNode) { - case ExpressionStatementNode expressionStatementNode -> - expr(expressionStatementNode.expression()); // 表达式语句:只求值,无需保存 - case AssignmentNode assignmentNode -> { // 赋值语句 - VirtualRegister virtualRegister = expr(assignmentNode.value()); - variables.put(assignmentNode.variable(), virtualRegister); - } - case DeclarationNode declarationNode -> { // 变量声明 - if (declarationNode.getInitializer().isPresent()) { // 有初始化器 - VirtualRegister virtualRegister = expr(declarationNode.getInitializer().get()); - variables.put(declarationNode.getName(), virtualRegister); - } else { // 无初始化器,分配空寄存器 - variables.put(declarationNode.getName(), currentFn.newRegister()); - } - } - case ReturnNode returnNode -> { // 返回语句 - if (returnNode.getExpression().isPresent()) - currentFn.add(new ReturnInstruction(expr(returnNode.getExpression().get()))); - else currentFn.add(new ReturnInstruction(null)); - } - default -> throw new IllegalStateException("不支持的语句: " + statementNode); - } - } - - /* ─── 处理表达式 ─── */ - - /** - * 编译单个表达式节点,结果保存在一个新的寄存器中。 - * - * @param expressionNode 表达式 AST 节点 - * @return 保存结果的虚拟寄存器 - */ - private VirtualRegister expr(ExpressionNode expressionNode) { - return switch (expressionNode) { - case BinaryExpressionNode binaryExpressionNode -> bin(binaryExpressionNode); // 二元运算 - case NumberLiteralNode numberLiteralNode -> number(numberLiteralNode); // 数字字面量 - case IdentifierNode identifierNode -> { // 变量引用 - VirtualRegister virtualRegister = variables.get(identifierNode.name()); - if (virtualRegister == null) - throw new IllegalStateException("变量 " + identifierNode.name() + " 未定义"); - yield virtualRegister; - } - default -> throw new IllegalStateException("不支持的表达式: " + expressionNode); - }; - } - - /** - * 二元运算表达式(如加减乘除)。 - * - * @param b 二元表达式节点 - * @return 保存结果的寄存器 - */ - private VirtualRegister bin(BinaryExpressionNode b) { - VirtualRegister l = expr(b.left()); // 左操作数 - VirtualRegister r = expr(b.right()); // 右操作数 - VirtualRegister d = currentFn.newRegister(); // 结果寄存器 - - // 选择对应的 IR 操作符 - IROp op = switch (b.operator()) { - case "+" -> IROp.ADD_I32; - case "-" -> IROp.SUB_I32; - case "*" -> IROp.MUL_I32; - case "/" -> IROp.DIV_I32; - default -> throw new IllegalStateException("未知运算符 " + b.operator()); - }; - - currentFn.add(new BinOpInstruction(op, d, l, r)); // 添加二元运算指令 - return d; - } - - /** - * 编译一个整数字面量。 - * - * @param numberLiteralNode 数字字面量节点 - * @return 保存常量的寄存器 - */ - private VirtualRegister number(NumberLiteralNode numberLiteralNode) { - VirtualRegister virtualRegister = currentFn.newRegister(); // 分配一个新的寄存器 - currentFn.add(new LoadConstInstruction(virtualRegister, new Constant(Integer.parseInt(numberLiteralNode.value())))); // 加载常量指令 - return virtualRegister; - } -} diff --git a/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java b/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java index 3fec94c..a0b4bce 100644 --- a/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java +++ b/src/main/java/org/jcnc/snow/compiler/cli/SnowCompiler.java @@ -1,6 +1,6 @@ package org.jcnc.snow.compiler.cli; -import org.jcnc.snow.compiler.builder.BasicIRBuilder; +import org.jcnc.snow.compiler.ir.builder.ProgramBuilder; import org.jcnc.snow.compiler.ir.core.IRProgram; import org.jcnc.snow.compiler.lexer.core.LexerEngine; import org.jcnc.snow.compiler.lexer.token.Token; @@ -50,10 +50,11 @@ public class SnowCompiler { SemanticAnalyzerRunner.runSemanticAnalysis(ast, false); /* 4. AST → IRProgram */ - IRProgram program = new BasicIRBuilder().buildProgram(ast); + IRProgram program = new ProgramBuilder().buildProgram(ast); System.out.println("=== IR ==="); System.out.println(program); + /* 5. 后端:寄存器分配 & 代码生成 + VM 执行 */ // for (IRFunction fn : program.functions()) { // var alloc = new RegisterAllocator(); diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java new file mode 100644 index 0000000..2885bcd --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java @@ -0,0 +1,145 @@ +package org.jcnc.snow.compiler.ir.builder; + +import org.jcnc.snow.compiler.ir.core.IRFunction; +import org.jcnc.snow.compiler.ir.core.IROp; +import org.jcnc.snow.compiler.ir.instr.BinOpInstruction; +import org.jcnc.snow.compiler.ir.instr.LoadConstInstruction; +import org.jcnc.snow.compiler.ir.instr.ReturnInstruction; +import org.jcnc.snow.compiler.ir.value.Constant; +import org.jcnc.snow.compiler.ir.value.VirtualRegister; +import org.jcnc.snow.compiler.parser.ast.*; +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.StatementNode; + +/** + * FunctionBuilder 负责将 AST 中的 FunctionNode 构建为 IRFunction。 + * + *

构建流程: + *

    + *
  1. 创建 IRFunction 并绑定到作用域;
  2. + *
  3. 将函数参数声明为虚拟寄存器;
  4. + *
  5. 遍历函数体中的语句,生成对应的 IR 指令。
  6. + *
+ */ +final class FunctionBuilder { + + /** 当前正在构建的 IRFunction 实例 */ + private IRFunction fn; + + /** 管理变量名到虚拟寄存器的映射 */ + private final Scope scope = new Scope(); + + /** + * 将给定的 FunctionNode 转换为 IRFunction。 + * + * @param node 要转换的函数节点 + * @return 构建完成的 IRFunction + */ + IRFunction build(FunctionNode node) { + fn = new IRFunction(node.name()); + scope.attachFunction(fn); + for (ParameterNode p : node.parameters()) { + scope.declare(p.name()); + } + for (StatementNode s : node.body()) { + stmt(s); + } + return fn; + } + + /** + * 处理不同类型的语句节点,并生成相应的 IR 指令。 + * + * @param s 要处理的语句节点 + */ + private void stmt(StatementNode s) { + switch (s) { + case ExpressionStatementNode(ExpressionNode expression) -> + // 处理表达式语句,无需保存结果 + expr(expression); + case AssignmentNode(String variable, ExpressionNode value) -> { + // 处理赋值语句:计算右侧表达式并赋值 + VirtualRegister result = expr(value); + if (scope.lookup(variable) == null) { + scope.declare(variable, result); + } else { + scope.put(variable, result); + } + } + case DeclarationNode d -> { + // 处理声明语句,可能带初始化 + if (d.getInitializer().isPresent()) { + scope.declare(d.getName(), expr(d.getInitializer().get())); + } else { + scope.declare(d.getName()); + } + } + case ReturnNode r -> { + // 处理返回语句,区分是否带返回值 + if (r.getExpression().isPresent()) { + fn.add(new ReturnInstruction(expr(r.getExpression().get()))); + } else { + fn.add(new ReturnInstruction(null)); + } + } + case null, default -> throw new IllegalStateException("Unsupported statement: " + s); + } + } + + /** + * 根据表达式类型生成对应的 IR 值,并返回结果寄存器。 + * + * @param e 要处理的表达式节点 + * @return 存放表达式结果的虚拟寄存器 + */ + private VirtualRegister expr(ExpressionNode e) { + if (e instanceof NumberLiteralNode num) { + return number(num); + } else if (e instanceof IdentifierNode(String name)) { + // 处理变量引用,从作用域获取寄存器 + VirtualRegister vr = scope.lookup(name); + if (vr == null) { + throw new IllegalStateException("Undefined variable " + name); + } + return vr; + } else if (e instanceof BinaryExpressionNode bin) { + return bin(bin); + } + throw new IllegalStateException("Unsupported expression: " + e); + } + + /** + * 生成加载数值常量的指令。 + * + * @param n 数字字面量节点 + * @return 存放常量的虚拟寄存器 + */ + private VirtualRegister number(NumberLiteralNode n) { + VirtualRegister vr = fn.newRegister(); + fn.add(new LoadConstInstruction(vr, new Constant(Integer.parseInt(n.value())))); + return vr; + } + + /** + * 生成二元运算指令,并返回结果寄存器。 + * + * @param b 二元表达式节点 + * @return 存放运算结果的虚拟寄存器 + */ + private VirtualRegister bin(BinaryExpressionNode b) { + VirtualRegister l = expr(b.left()); + VirtualRegister r = expr(b.right()); + VirtualRegister d = fn.newRegister(); + + IROp op = switch (b.operator()) { + case "+" -> IROp.ADD_I32; + case "-" -> IROp.SUB_I32; + case "*" -> IROp.MUL_I32; + case "/" -> IROp.DIV_I32; + default -> throw new IllegalStateException("Unknown operator " + b.operator()); + }; + + fn.add(new BinOpInstruction(op, d, l, r)); + return d; + } +} \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ProgramBuilder.java new file mode 100644 index 0000000..6331d57 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ProgramBuilder.java @@ -0,0 +1,82 @@ +package org.jcnc.snow.compiler.ir.builder; + +import org.jcnc.snow.compiler.ir.core.IRFunction; +import org.jcnc.snow.compiler.ir.core.IRProgram; +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.ModuleNode; +import org.jcnc.snow.compiler.parser.ast.base.Node; +import org.jcnc.snow.compiler.parser.ast.base.StatementNode; + +import java.util.List; + +/** + * ProgramBuilder 用于将 AST 根节点列表构建为 IRProgram。 + * + *

功能: + *

+ */ +public final class ProgramBuilder { + + /** + * 构建一个完整的 IRProgram。 + * + * @param roots AST 根节点列表,可包含 ModuleNode、FunctionNode 或 StatementNode + * @return 构建好的 IRProgram 实例 + * @throws IllegalStateException 当遇到不支持的顶层节点时抛出 + */ + public IRProgram buildProgram(List roots) { + IRProgram prog = new IRProgram(); + for (Node n : roots) { + if (n instanceof ModuleNode m) { + // 模块节点:将模块内的所有函数加入程序 + m.functions().forEach(f -> prog.add(buildFunction(f))); + } else if (n instanceof FunctionNode f) { + // 顶层函数节点 + prog.add(buildFunction(f)); + } else if (n instanceof StatementNode s) { + // 顶层脚本语句,包装为 _start 函数 + prog.add(buildFunction(wrapTopLevel(s))); + } else { + throw new IllegalStateException("Unsupported top-level node: " + n); + } + } + return prog; + } + + /** + * 使用 FunctionBuilder 构建 IRFunction。 + * + * @param fn AST 中的 FunctionNode + * @return 构建完成的 IRFunction + */ + private IRFunction buildFunction(FunctionNode fn) { + return new FunctionBuilder().build(fn); + } + + /** + * 将顶层脚本式语句包装为名为 _start 的 FunctionNode。 + * + *

构造参数说明: + *

+ * + * @param stmt 要包装的顶层语句节点 + * @return 新建的 FunctionNode + */ + private FunctionNode wrapTopLevel(StatementNode stmt) { + return new FunctionNode( + "_start", + null, + String.valueOf(List.of()), + List.of(stmt) + ); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/Scope.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/Scope.java new file mode 100644 index 0000000..1d449aa --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/Scope.java @@ -0,0 +1,77 @@ +package org.jcnc.snow.compiler.ir.builder; + +import org.jcnc.snow.compiler.ir.core.IRFunction; +import org.jcnc.snow.compiler.ir.value.VirtualRegister; + +import java.util.HashMap; +import java.util.Map; + +/** + * Scope 用于管理单个函数的变量名与虚拟寄存器的映射。 + * + *

功能: + *

+ */ +final class Scope { + + /** 存储变量名到 VirtualRegister 的映射 */ + private final Map vars = new HashMap<>(); + + /** + * 当前作用域所属的 IRFunction,用于分配新的寄存器。 + */ + private IRFunction fn; + + /** + * 关联一个 IRFunction 到当前作用域,用于后续寄存器分配。 + * + * @param fn 要绑定的 IRFunction 实例 + */ + void attachFunction(IRFunction fn) { + this.fn = fn; + } + + /** + * 声明一个新变量,并为其分配一个新的虚拟寄存器。 + * + * @param name 变量名 + */ + void declare(String name) { + VirtualRegister reg = fn.newRegister(); + vars.put(name, reg); + } + + /** + * 声明或导入一个已有寄存器到当前作用域。 + * + * @param name 变量名 + * @param reg 对应的虚拟寄存器 + */ + void declare(String name, VirtualRegister reg) { + vars.put(name, reg); + } + + /** + * 更新已声明变量对应的虚拟寄存器。 + * + * @param name 变量名 + * @param reg 新的虚拟寄存器 + */ + void put(String name, VirtualRegister reg) { + vars.put(name, reg); + } + + /** + * 根据变量名查找其对应的虚拟寄存器。 + * + * @param name 变量名 + * @return 对应的 VirtualRegister,若未声明则返回 null + */ + VirtualRegister lookup(String name) { + return vars.get(name); + } +}