refactor: 重构 ExpressionBuilder 类

- 优化了代码结构,提高了代码的可读性和可维护性
- 添加了详细的注释,解释了各个方法的功能和实现细节
- 改进了对不同表达式类型的处理逻辑,增强了表达式构建的能力
- 优化了寄存器的使用和管理,提高了 IR 指令生成的效率
This commit is contained in:
Luke 2025-07-21 17:06:40 +08:00
parent 970976ecc5
commit 3aef7cd906

View File

@ -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.*;
/**
* <b>表达式构建器</b>
* <b>ExpressionBuilder - 表达式 IR 构建器</b>
*
* <p>
* 该类负责将抽象语法树AST的表达式节点转换为中间表示IR指令和虚拟寄存器
* 是编译器IR生成阶段的核心工具
* <br/>
* 主要职责包括:
* 负责将 AST 表达式节点递归转换为 IR 虚拟寄存器操作并生成对应的 IR 指令序列
* 支持字面量标识符二元表达式一元表达式函数调用等多种类型表达式
* </p>
*
* <p>
* 主要功能
* <ul>
* <li>将数字字面量标识符二元表达式函数调用等AST表达式节点翻译为对应的IR指令序列</li>
* <li>管理并分配虚拟寄存器保证IR操作的数据流正确</li>
* <li>将表达式节点映射为虚拟寄存器</li>
* <li>为每种表达式类型生成对应 IR 指令</li>
* <li>支持表达式嵌套的递归构建</li>
* <li>支持写入指定目标寄存器避免冗余的 move 指令</li>
* </ul>
* <p>
* </p>
*/
public record ExpressionBuilder(IRContext ctx) {
/* ───────────────── 顶层入口 ───────────────── */
/**
* 构建并返回某个表达式节点对应的虚拟寄存器
* 构建任意 AST 表达式节点自动为其分配一个新的虚拟寄存器并返回该寄存器
*
* <p>会根据节点的实际类型分别处理:
* <ul>
* <li>数字字面量: 新建常量寄存器</li>
* <li>字符串字面量: 新建常量寄存器字符串类型</li>
* <li>布尔字面量: 生成值为 0 1 的常量寄存器</li>
* <li>标识符: 查找当前作用域中的寄存器</li>
* <li>二元表达式: 递归处理子表达式并进行相应运算</li>
* <li>一元运算符:
* <ul>
* <li><code>-x</code>取负生成 <code>NEG_I32</code> 指令</li>
* <li><code>!x</code>逻辑非转换为 <code>x == 0</code> 比较指令</li>
* </ul>
* </li>
* <li>函数调用: 生成对应的Call指令</li>
* <li>其它类型不支持抛出异常</li>
* </ul>
* <p>
* 这是表达式 IR 生成的核心入口它会根据不同的表达式类型进行分派递归构建 IR 指令
* </p>
*
* @param expr 要转换的表达式AST节点
* @return 该表达式的计算结果寄存器
* @throws IllegalStateException 如果遇到未定义的标识符或不支持的表达式类型
* @param expr 任意 AST 表达式节点
* @return 存储该表达式结果的虚拟寄存器
* @throws IllegalStateException 遇到不支持的表达式类型或未定义标识符
*/
public IRVirtualRegister build(ExpressionNode expr) {
return switch (expr) {
// 数字字面量
// 数字字面量例如 1233.14
case NumberLiteralNode n -> buildNumberLiteral(n.value());
// 字符串字面量
// 字符串字面量例如 "abc"
case StringLiteralNode s -> buildStringLiteral(s.value());
// 布尔字面量
// 布尔字面量例如 true / false
case BoolLiteralNode b -> buildBoolLiteral(b.getValue());
// 标识符
// 标识符变量名 ab
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
* <p>
* {@link #build(ExpressionNode)}类似但支持目标寄存器复用避免不必要的move
* 生成表达式并将其结果直接写入目标寄存器避免冗余的 move 操作
*
* @param node 表达式AST节点
* @param dest 目标寄存器
* @throws IllegalStateException 未定义标识符/不支持的表达式类型时报错
* <p>
* 某些简单表达式如字面量变量名可以直接写入目标寄存器复杂表达式则会先 build 到新寄存器 move 到目标寄存器
* </p>
*
* @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生成新寄存器存储结果
* <p>
* 先递归构建左右操作数之后根据操作符类别算术或比较决定生成的IR操作码
* 并生成对应的二元运算指令
* 一元表达式构建
*
* @param bin 二元表达式节点
* @return 存放结果的虚拟寄存器
* <p>
* 支持算术取负-a逻辑非!a等一元运算符
* </p>
*
* @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
* <p>
* 结构与{@link #buildBinary(BinaryExpressionNode)}类似但不会新分配寄存器
* 构建函数或方法调用表达式
*
* @param call AST 调用表达式节点
* @return 存储调用结果的虚拟寄存器
*/
private IRVirtualRegister buildCall(CallExpressionNode call) {
// 递归生成所有参数实参对应的寄存器
List<IRVirtualRegister> 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;
}
/**
* 二元表达式构建结果存储到新寄存器
* <br>
* 支持算术位运算与比较==, !=, >, <, ...
*
* @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指令和目标寄存器
* <p>
* 支持普通标识符调用和成员调用 mod.func会为每个参数依次生成子表达式的寄存器
*
* @param call 调用表达式AST节点
* @return 返回结果存放的寄存器
*/
private IRVirtualRegister buildCall(CallExpressionNode call) {
// 递归构建所有参数的寄存器
List<IRVirtualRegister> 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;
}
/* ───────────────── 字面量辅助方法 ───────────────── */
/**
* 处理数字字面量生成常量寄存器和加载指令
* <p>
* 会将字符串型字面量 "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=1false=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 表示 true0 表示 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;
}
}