From 3aef7cd9065fdaf4123a4ff0e9cbe3baca029491 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 21 Jul 2025 17:06:40 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20ExpressionBuil?= =?UTF-8?q?der=20=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 优化了代码结构,提高了代码的可读性和可维护性 - 添加了详细的注释,解释了各个方法的功能和实现细节 - 改进了对不同表达式类型的处理逻辑,增强了表达式构建的能力 - 优化了寄存器的使用和管理,提高了 IR 指令生成的效率 --- .../ir/builder/ExpressionBuilder.java | 319 ++++++++++-------- 1 file changed, 171 insertions(+), 148 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java index 31e2973..58eccfc 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java @@ -5,130 +5,117 @@ import org.jcnc.snow.compiler.ir.instruction.CallInstruction; import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction; import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction; import org.jcnc.snow.compiler.ir.utils.ComparisonUtils; +import org.jcnc.snow.compiler.ir.utils.ExpressionUtils; import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; -import org.jcnc.snow.compiler.ir.utils.ExpressionUtils; import org.jcnc.snow.compiler.parser.ast.*; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; import java.util.*; /** - * 表达式构建器 + * ExpressionBuilder - 表达式 → IR 构建器 + * *

- * 该类负责将抽象语法树(AST)的表达式节点转换为中间表示(IR)指令和虚拟寄存器, - * 是编译器IR生成阶段的核心工具。 - *
- * 主要职责包括: + * 负责将 AST 表达式节点递归转换为 IR 虚拟寄存器操作,并生成对应的 IR 指令序列。 + * 支持字面量、标识符、二元表达式、一元表达式、函数调用等多种类型表达式。 + *

+ * + *

+ * 主要功能: *

- *

+ *

*/ public record ExpressionBuilder(IRContext ctx) { + /* ───────────────── 顶层入口 ───────────────── */ + /** - * 构建并返回某个表达式节点对应的虚拟寄存器。 + * 构建任意 AST 表达式节点,自动为其分配一个新的虚拟寄存器,并返回该寄存器。 * - *

会根据节点的实际类型分别处理: - *

+ *

+ * 这是表达式 IR 生成的核心入口。它会根据不同的表达式类型进行分派,递归构建 IR 指令。 + *

* - * @param expr 要转换的表达式AST节点 - * @return 该表达式的计算结果寄存器 - * @throws IllegalStateException 如果遇到未定义的标识符或不支持的表达式类型 + * @param expr 任意 AST 表达式节点 + * @return 存储该表达式结果的虚拟寄存器 + * @throws IllegalStateException 遇到不支持的表达式类型或未定义标识符 */ public IRVirtualRegister build(ExpressionNode expr) { return switch (expr) { - // 数字字面量 + // 数字字面量,例如 123、3.14 case NumberLiteralNode n -> buildNumberLiteral(n.value()); - // 字符串字面量 + // 字符串字面量,例如 "abc" case StringLiteralNode s -> buildStringLiteral(s.value()); - // 布尔字面量 + // 布尔字面量,例如 true / false case BoolLiteralNode b -> buildBoolLiteral(b.getValue()); - // 标识符 + // 标识符(变量名),如 a、b case IdentifierNode id -> { + // 查找当前作用域中的变量寄存器 IRVirtualRegister reg = ctx.getScope().lookup(id.name()); if (reg == null) throw new IllegalStateException("未定义标识符: " + id.name()); yield reg; } - // 二元表达式 + // 二元表达式(如 a+b, x==y) case BinaryExpressionNode bin -> buildBinary(bin); - // 函数调用 - case CallExpressionNode call -> buildCall(call); - // 一元表达式 - case UnaryExpressionNode u -> buildUnary(u); + // 函数/方法调用表达式 + case CallExpressionNode call -> buildCall(call); + // 一元表达式(如 -a, !a) + case UnaryExpressionNode un -> buildUnary(un); + + // 默认分支:遇到未知表达式类型则直接抛异常 default -> throw new IllegalStateException( "不支持的表达式类型: " + expr.getClass().getSimpleName()); }; } - /** 处理一元表达式 */ - private IRVirtualRegister buildUnary(UnaryExpressionNode un) { - String op = un.operator(); - IRVirtualRegister val = build(un.operand()); - - // -x → NEG_*(根据类型自动选择位宽) - if (op.equals("-")) { - IRVirtualRegister dest = ctx.newRegister(); - IROpCode code = ExpressionUtils.negOp(un.operand()); - ctx.addInstruction(new UnaryOperationInstruction(code, dest, val)); - return dest; - } - - // !x → (x == 0) - if (op.equals("!")) { - IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0); - return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, val, zero); - } - - throw new IllegalStateException("未知一元运算符: " + op); - } + /* ───────────────── 写入指定寄存器 ───────────────── */ /** - * 直接将表达式计算结果写入指定的目标寄存器(dest)。 - *

- * 与{@link #build(ExpressionNode)}类似,但支持目标寄存器复用(避免不必要的move)。 + * 生成表达式,并将其结果直接写入目标寄存器,避免冗余的 move 操作。 * - * @param node 表达式AST节点 - * @param dest 目标寄存器 - * @throws IllegalStateException 未定义标识符/不支持的表达式类型时报错 + *

+ * 某些简单表达式(如字面量、变量名)可以直接写入目标寄存器;复杂表达式则会先 build 到新寄存器,再 move 到目标寄存器。 + *

+ * + * @param node 要生成的表达式节点 + * @param dest 目标虚拟寄存器(用于存储结果) */ public void buildInto(ExpressionNode node, IRVirtualRegister dest) { switch (node) { - // 数字字面量,直接加载到目标寄存器 + // 数字字面量:生成 loadConst 指令写入目标寄存器 case NumberLiteralNode n -> - InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value())); - // 字符串字面量,直接加载到目标寄存器 + InstructionFactory.loadConstInto( + ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value())); + + // 字符串字面量:生成 loadConst 指令写入目标寄存器 case StringLiteralNode s -> - InstructionFactory.loadConstInto(ctx, dest, new IRConstant(s.value())); - // 布尔字面量,直接加载到目标寄存器 + InstructionFactory.loadConstInto( + ctx, dest, new IRConstant(s.value())); + + // 布尔字面量:转换为 int 1/0,生成 loadConst case BoolLiteralNode b -> - InstructionFactory.loadConstInto(ctx, dest, new IRConstant(b.getValue() ? 1 : 0)); - // 标识符,查找并move到目标寄存器 + InstructionFactory.loadConstInto( + ctx, dest, new IRConstant(b.getValue() ? 1 : 0)); + + // 标识符:查表获取原寄存器,然后 move 到目标寄存器 case IdentifierNode id -> { IRVirtualRegister src = ctx.getScope().lookup(id.name()); - if (src == null) throw new IllegalStateException("未定义标识符: " + id.name()); + if (src == null) + throw new IllegalStateException("未定义标识符: " + id.name()); InstructionFactory.move(ctx, src, dest); } - // 二元表达式,直接写入目标寄存器 + + // 二元表达式:递归生成并写入目标寄存器 case BinaryExpressionNode bin -> buildBinaryInto(bin, dest); - // 其他表达式,先递归生成寄存器,再move到目标寄存器 + + // 其它复杂情况:先 build 到新寄存器,再 move 到目标寄存器 default -> { IRVirtualRegister tmp = build(node); InstructionFactory.move(ctx, tmp, dest); @@ -136,41 +123,100 @@ public record ExpressionBuilder(IRContext ctx) { } } + /* ───────────────── 具体表达式类型 ───────────────── */ + /** - * 构建二元表达式的IR,生成新寄存器存储结果。 - *

- * 先递归构建左右操作数,之后根据操作符类别(算术或比较)决定生成的IR操作码, - * 并生成对应的二元运算指令。 + * 一元表达式构建 * - * @param bin 二元表达式节点 - * @return 存放结果的虚拟寄存器 + *

+ * 支持算术取负(-a)、逻辑非(!a)等一元运算符。 + *

+ * + * @param un 一元表达式节点 + * @return 结果存储的新分配虚拟寄存器 */ - private IRVirtualRegister buildBinary(BinaryExpressionNode bin) { - String op = bin.operator(); - IRVirtualRegister left = build(bin.left()); - IRVirtualRegister right = build(bin.right()); + private IRVirtualRegister buildUnary(UnaryExpressionNode un) { + // 递归生成操作数的寄存器 + IRVirtualRegister src = build(un.operand()); + // 分配目标寄存器 + IRVirtualRegister dest = ctx.newRegister(); - // 1. 比较运算 - if (ComparisonUtils.isComparisonOperator(op)) { - return InstructionFactory.binOp( - ctx, - ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()), - left, right); + switch (un.operator()) { + // 算术负号:生成取负指令 + case "-" -> ctx.addInstruction( + new UnaryOperationInstruction(ExpressionUtils.negOp(un.operand()), dest, src)); + // 逻辑非:等价于 a == 0,生成比较指令 + case "!" -> { + IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0); + return InstructionFactory.binOp(ctx, IROpCode.CMP_IEQ, src, zero); + } + // 其它一元运算符不支持,抛异常 + default -> throw new IllegalStateException("未知一元运算符: " + un.operator()); } - - // 2. 其他算术 / 逻辑运算 - IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right()); - if (code == null) throw new IllegalStateException("不支持的运算符: " + op); - return InstructionFactory.binOp(ctx, code, left, right); + return dest; } /** - * 将二元表达式的结果直接写入指定寄存器dest。 - *

- * 结构与{@link #buildBinary(BinaryExpressionNode)}类似,但不会新分配寄存器。 + * 构建函数或方法调用表达式。 + * + * @param call AST 调用表达式节点 + * @return 存储调用结果的虚拟寄存器 + */ + private IRVirtualRegister buildCall(CallExpressionNode call) { + // 递归生成所有参数(实参)对应的寄存器 + List argv = call.arguments().stream().map(this::build).toList(); + + // 解析被调用目标名,支持普通函数/成员方法 + String callee = switch (call.callee()) { + // 成员方法调用,例如 obj.foo() + case MemberExpressionNode m when m.object() instanceof IdentifierNode id + -> id.name() + "." + m.member(); + // 普通函数调用 + case IdentifierNode id -> id.name(); + // 其它情况暂不支持 + default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName()); + }; + + // 为返回值分配新寄存器,生成 Call 指令 + IRVirtualRegister dest = ctx.newRegister(); + ctx.addInstruction(new CallInstruction(dest, callee, new ArrayList<>(argv))); + return dest; + } + + /** + * 二元表达式构建,结果存储到新寄存器。 + *
+ * 支持算术、位运算与比较(==, !=, >, <, ...)。 * * @param bin 二元表达式节点 - * @param dest 目标寄存器 + * @return 存储表达式结果的虚拟寄存器 + */ + private IRVirtualRegister buildBinary(BinaryExpressionNode bin) { + // 递归生成左、右子表达式的寄存器 + IRVirtualRegister a = build(bin.left()); + IRVirtualRegister b = build(bin.right()); + String op = bin.operator(); + + // 比较运算符(==、!=、>、< 等),需要生成条件跳转或布尔值寄存器 + if (ComparisonUtils.isComparisonOperator(op)) { + return InstructionFactory.binOp( + ctx, + // 通过比较工具获得合适的 IR 操作码 + ComparisonUtils.cmpOp(ctx.getScope().getVarTypes(), op, bin.left(), bin.right()), + a, b); + } + + // 其它算术/位运算 + IROpCode code = ExpressionUtils.resolveOpCode(op, bin.left(), bin.right()); + if (code == null) throw new IllegalStateException("不支持的运算符: " + op); + return InstructionFactory.binOp(ctx, code, a, b); + } + + /** + * 二元表达式构建,结果直接写入目标寄存器(用于赋值左值等优化场景)。 + * + * @param bin 二元表达式节点 + * @param dest 目标虚拟寄存器 */ private void buildBinaryInto(BinaryExpressionNode bin, IRVirtualRegister dest) { IRVirtualRegister a = build(bin.left()); @@ -189,67 +235,44 @@ public record ExpressionBuilder(IRContext ctx) { } } - /** - * 处理函数调用表达式,生成对应的Call指令和目标寄存器。 - *

- * 支持普通标识符调用和成员调用(如 mod.func),会为每个参数依次生成子表达式的寄存器。 - * - * @param call 调用表达式AST节点 - * @return 返回结果存放的寄存器 - */ - private IRVirtualRegister buildCall(CallExpressionNode call) { - // 递归构建所有参数的寄存器 - List argv = call.arguments().stream() - .map(this::build) - .toList(); - // 获取完整调用目标名称(支持成员/模块调用和普通调用) - String fullName = switch (call.callee()) { - case MemberExpressionNode member when member.object() instanceof IdentifierNode _ -> - ((IdentifierNode)member.object()).name() + "." + member.member(); - case IdentifierNode id -> id.name(); - default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName()); - }; - // 申请目标寄存器 - IRVirtualRegister dest = ctx.newRegister(); - // 添加Call指令到IR上下文 - ctx.addInstruction(new CallInstruction(dest, fullName, new ArrayList<>(argv))); - return dest; - } + /* ───────────────── 字面量辅助方法 ───────────────── */ /** - * 处理数字字面量,生成常量寄存器和加载指令。 - *

- * 会将字符串型字面量(如 "123", "1.0f")解析为具体的IRConstant, - * 并分配一个新的虚拟寄存器来存放该常量。 + * 构建数字字面量表达式(如 123),分配新寄存器并生成 LoadConst 指令。 * - * @param value 字面量字符串 - * @return 存放该常量的寄存器 + * @param value 字面量文本(字符串格式) + * @return 存储该字面量的寄存器 */ private IRVirtualRegister buildNumberLiteral(String value) { - IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value); - IRVirtualRegister reg = ctx.newRegister(); - ctx.addInstruction(new LoadConstInstruction(reg, constant)); - return reg; + IRConstant c = ExpressionUtils.buildNumberConstant(ctx, value); + IRVirtualRegister r = ctx.newRegister(); + ctx.addInstruction(new LoadConstInstruction(r, c)); + return r; } /** - * 处理字符串字面量,生成常量寄存器和加载指令。 + * 构建字符串字面量表达式,分配新寄存器并生成 LoadConst 指令。 * * @param value 字符串内容 - * @return 存放该字符串常量的寄存器 + * @return 存储该字符串的寄存器 */ private IRVirtualRegister buildStringLiteral(String value) { - IRConstant constant = new IRConstant(value); - IRVirtualRegister reg = ctx.newRegister(); - ctx.addInstruction(new LoadConstInstruction(reg, constant)); - return reg; + IRConstant c = new IRConstant(value); + IRVirtualRegister r = ctx.newRegister(); + ctx.addInstruction(new LoadConstInstruction(r, c)); + return r; } - /** 布尔字面量 → CONST (true=1,false=0)*/ - private IRVirtualRegister buildBoolLiteral(boolean value) { - IRConstant constant = new IRConstant(value ? 1 : 0); - IRVirtualRegister reg = ctx.newRegister(); - ctx.addInstruction(new LoadConstInstruction(reg, constant)); - return reg; + /** + * 构建布尔字面量表达式(true/false),分配新寄存器并生成 LoadConst 指令(1 表示 true,0 表示 false)。 + * + * @param v 布尔值 + * @return 存储 1/0 的寄存器 + */ + private IRVirtualRegister buildBoolLiteral(boolean v) { + IRConstant c = new IRConstant(v ? 1 : 0); + IRVirtualRegister r = ctx.newRegister(); + ctx.addInstruction(new LoadConstInstruction(r, c)); + return r; } }