diff --git a/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java index ed6ec2c..187b92b 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java @@ -3,11 +3,13 @@ package org.jcnc.snow.compiler.backend; import org.jcnc.snow.compiler.ir.core.IRFunction; import org.jcnc.snow.compiler.ir.core.IRInstruction; import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction; +import org.jcnc.snow.compiler.ir.instruction.CallInstruction; import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction; import org.jcnc.snow.compiler.ir.instruction.ReturnInstruction; import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction; import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; +import org.jcnc.snow.compiler.ir.core.IRValue; import java.lang.reflect.Field; import java.util.ArrayList; @@ -16,18 +18,17 @@ import java.util.Map; /** * VMCodeGenerator —— 虚拟机代码生成器。 - *

+ * * 该类负责将中间表示(IRFunction)翻译为 SVM 虚拟机可执行的文本指令。 * 当前支持: * - int32 类型的常量加载 * - 加减乘除(+ - * /)的二元表达式 * - 取负(一元 -) + * - 函数调用 * - 函数返回(含 main 函数终止) - *

- *

+ * * 每个虚拟寄存器通过 slotMap 分配一个槽位(int 索引),用于定位变量。 * 生成的代码是一系列字符串,格式为汇编式:OPCODE 参数... - *

*/ public final class VMCodeGenerator { @@ -58,6 +59,7 @@ public final class VMCodeGenerator { case LoadConstInstruction c -> genLoadConst(c); // 常量加载 case BinaryOperationInstruction b -> genBinOp(b); // 二元操作 case UnaryOperationInstruction u -> genUnary(u); // 一元操作 + case CallInstruction c -> genCall(c); // 函数调用 case ReturnInstruction r -> genRet(r); // 返回语句 default -> throw new IllegalStateException("不支持的 IR 指令类型: " + inst); } @@ -99,10 +101,31 @@ public final class VMCodeGenerator { emit(op("I_STORE"), slot(u.dest()) + ""); } + /** + * 生成函数调用指令: + * - 将所有实参从局部槽加载到栈; + * - 执行 CALL,使用函数全名; + * - 将返回值存回目标寄存器槽。 + */ + private void genCall(CallInstruction c) { + // 参数入栈 + for (IRValue arg : c.getArguments()) { + if (arg instanceof IRVirtualRegister reg) { + emit(op("I_LOAD"), slot(reg) + ""); + } else { + throw new IllegalStateException("不支持的调用参数类型: " + arg); + } + } + // 调用指令,函数名为全名(含模块前缀) + emit(op("CALL"), c.getFunctionName()); + // 返回值存储到目标寄存器 + emit(op("I_STORE"), slot(c.getDest()) + ""); + } + /** * 生成返回语句: - * - 对于 main 函数,使用 HALT 表示程序终止 - * - 其他函数使用 RET 指令返回调用者 + * - 对于 main 函数,使用 HALT 表示程序终止; + * - 其他函数使用 RET 指令返回调用者。 */ private void genRet(ReturnInstruction r) { if ("main".equals(currentFnName)) { @@ -157,4 +180,4 @@ public final class VMCodeGenerator { for (String a : args) sb.append(' ').append(a); code.add(sb.toString()); } -} +} \ No newline at end of file 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 c07aa83..37c0c72 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 @@ -1,116 +1,197 @@ package org.jcnc.snow.compiler.ir.builder; import org.jcnc.snow.compiler.ir.core.IROpCode; +import org.jcnc.snow.compiler.ir.core.IRValue; import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction; import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction; +import org.jcnc.snow.compiler.ir.instruction.CallInstruction; import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.parser.ast.BinaryExpressionNode; +import org.jcnc.snow.compiler.parser.ast.CallExpressionNode; +import org.jcnc.snow.compiler.parser.ast.MemberExpressionNode; import org.jcnc.snow.compiler.parser.ast.IdentifierNode; import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode; import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** - * ExpressionBuilder 将 AST 中的 ExpressionNode 转换为 IR 指令,并返回结果虚拟寄存器。 - * 支持: - *
    - *
  1. NumberLiteralNode:根据文本后缀(b/S/L/f/d)或内容自动区分 bytke/short/int/long/float/double,并生成常量加载指令
  2. - *
  3. IdentifierNode:从作用域获取已声明的虚拟寄存器
  4. - *
  5. BinaryExpressionNode:递归构建子表达式,根据数据宽度和符号生成对应的二元运算指令
  6. - *
+ * ExpressionBuilder 将 AST 中的 ExpressionNode 转换为 IR 指令,并返回结果的虚拟寄存器。 + * + * 支持以下表达式类型: + * */ public class ExpressionBuilder { - // 不同位宽整数和浮点的运算码映射 - private static final Map OP_I8 = Map.of("+", IROpCode.ADD_B8, "-", IROpCode.SUB_B8, "*", IROpCode.MUL_B8, "/", IROpCode.DIV_B8); - private static final Map OP_I16 = Map.of("+", IROpCode.ADD_S16, "-", IROpCode.SUB_S16, "*", IROpCode.MUL_S16, "/", IROpCode.DIV_S16); - private static final Map OP_I32 = Map.of("+", IROpCode.ADD_I32, "-", IROpCode.SUB_I32, "*", IROpCode.MUL_I32, "/", IROpCode.DIV_I32); - private static final Map OP_L64 = Map.of("+", IROpCode.ADD_L64, "-", IROpCode.SUB_L64, "*", IROpCode.MUL_L64, "/", IROpCode.DIV_L64); - private static final Map OP_F32 = Map.of("+", IROpCode.ADD_F32, "-", IROpCode.SUB_F32, "*", IROpCode.MUL_F32, "/", IROpCode.DIV_F32); - private static final Map OP_D64 = Map.of("+", IROpCode.ADD_D64, "-", IROpCode.SUB_D64, "*", IROpCode.MUL_D64, "/", IROpCode.DIV_D64); + private static final Map OP_I8 = Map.of( + "+", IROpCode.ADD_B8, "-", IROpCode.SUB_B8, + "*", IROpCode.MUL_B8, "/", IROpCode.DIV_B8 + ); + private static final Map OP_I16 = Map.of( + "+", IROpCode.ADD_S16, "-", IROpCode.SUB_S16, + "*", IROpCode.MUL_S16, "/", IROpCode.DIV_S16 + ); + private static final Map OP_I32 = Map.of( + "+", IROpCode.ADD_I32, "-", IROpCode.SUB_I32, + "*", IROpCode.MUL_I32, "/", IROpCode.DIV_I32 + ); + private static final Map OP_L64 = Map.of( + "+", IROpCode.ADD_L64, "-", IROpCode.SUB_L64, + "*", IROpCode.MUL_L64, "/", IROpCode.DIV_L64 + ); + private static final Map OP_F32 = Map.of( + "+", IROpCode.ADD_F32, "-", IROpCode.SUB_F32, + "*", IROpCode.MUL_F32, "/", IROpCode.DIV_F32 + ); + private static final Map OP_D64 = Map.of( + "+", IROpCode.ADD_D64, "-", IROpCode.SUB_D64, + "*", IROpCode.MUL_D64, "/", IROpCode.DIV_D64 + ); private final IRContext ctx; + /** + * 构造函数,传入 IRContext 用于生成寄存器和添加指令 + * @param ctx 构建上下文 + */ public ExpressionBuilder(IRContext ctx) { this.ctx = ctx; } + /** + * 将 AST 表达式节点转换为 IR 指令,并返回结果寄存器 + * @param expr 表达式节点 + * @return 存放计算结果的虚拟寄存器 + */ public IRVirtualRegister build(ExpressionNode expr) { - // 1. 常量字面量 - if (expr instanceof NumberLiteralNode(String value)) { - // 判断后缀 + // 1. 常量字面量处理 + if (expr instanceof NumberLiteralNode ln) { + String value = ln.value(); char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1)); - String digits = (suffix == 'b' || suffix == 's' || suffix == 'l' || suffix == 'f' || suffix == 'd') ? value.substring(0, value.length() - 1) : value; + String digits = (suffix == 'b' || suffix == 's' || suffix == 'l' || suffix == 'f' || suffix == 'd') + ? value.substring(0, value.length() - 1) + : value; IRVirtualRegister reg = ctx.newRegister(); switch (suffix) { - case 'b': // byte - byte bv = Byte.parseByte(digits); - ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(bv))); - break; - case 's': // short - short sv = Short.parseShort(digits); - ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(sv))); - break; - case 'l': // long - long lv = Long.parseLong(digits); - ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(lv))); - break; - case 'f': // float - float fv = Float.parseFloat(digits); - ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(fv))); - break; - case 'd': // double - double dv = Double.parseDouble(digits); - ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(dv))); - break; - default: // 无后缀,数字中有小数点或指数 => double,否则 int + case 'b' -> ctx.addInstruction( + new LoadConstInstruction(reg, new IRConstant(Byte.parseByte(digits))) + ); + case 's' -> ctx.addInstruction( + new LoadConstInstruction(reg, new IRConstant(Short.parseShort(digits))) + ); + case 'l' -> ctx.addInstruction( + new LoadConstInstruction(reg, new IRConstant(Long.parseLong(digits))) + ); + case 'f' -> ctx.addInstruction( + new LoadConstInstruction(reg, new IRConstant(Float.parseFloat(digits))) + ); + case 'd' -> ctx.addInstruction( + new LoadConstInstruction(reg, new IRConstant(Double.parseDouble(digits))) + ); + default -> { if (digits.contains(".") || digits.matches(".*[eE].*")) { - double dd = Double.parseDouble(digits); - ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(dd))); + ctx.addInstruction( + new LoadConstInstruction(reg, new IRConstant(Double.parseDouble(digits))) + ); } else { - int iv = Integer.parseInt(digits); - ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(iv))); + ctx.addInstruction( + new LoadConstInstruction(reg, new IRConstant(Integer.parseInt(digits))) + ); } + } } return reg; } - // 2. 标识符 => 作用域寄存器 - if (expr instanceof IdentifierNode(String name)) { - IRVirtualRegister reg = ctx.getScope().lookup(name); - if (reg == null) throw new IllegalStateException("未定义变量: " + name); + // 2. 变量标识符处理 + if (expr instanceof IdentifierNode id) { + IRVirtualRegister reg = ctx.getScope().lookup(id.name()); + if (reg == null) { + throw new IllegalStateException("未定义标识符: " + id.name()); + } return reg; } - // 3. 二元表达式 - if (expr instanceof BinaryExpressionNode(ExpressionNode left, String operator, ExpressionNode right)) { + // 3. 二元表达式处理 + if (expr instanceof BinaryExpressionNode bin) { + ExpressionNode left = bin.left(); + ExpressionNode right = bin.right(); + String op = bin.operator(); IRVirtualRegister lreg = build(left); IRVirtualRegister rreg = build(right); - // 判断计算类型:检查两侧是否为 NumberLiteralNode 并提取后缀 - char leftS = (left instanceof NumberLiteralNode( - String value - )) ? Character.toLowerCase(value.charAt(value.length() - 1)) : '\0'; - char rightS = (right instanceof NumberLiteralNode( - String value - )) ? Character.toLowerCase(value.charAt(value.length() - 1)) : '\0'; - // 选择优先级: byte < short < int < long < float < double - char suf = (leftS == 'd' || rightS == 'd') ? 'd' : (leftS == 'f' || rightS == 'f') ? 'f' : (leftS == 'l' || rightS == 'l') ? 'l' : (leftS == 's' || rightS == 's') ? 's' : (leftS == 'b' || rightS == 'b') ? 'b' : '\0'; + + char suf = resolveSuffix(left, right); IROpCode code = switch (suf) { - case 'b' -> OP_I8.get(operator); - case 's' -> OP_I16.get(operator); - case 'l' -> OP_L64.get(operator); - case 'f' -> OP_F32.get(operator); - case 'd' -> OP_D64.get(operator); - default -> OP_I32.get(operator); + case 'b' -> OP_I8.get(op); + case 's' -> OP_I16.get(op); + case 'l' -> OP_L64.get(op); + case 'f' -> OP_F32.get(op); + case 'd' -> OP_D64.get(op); + default -> OP_I32.get(op); }; - if (code == null) throw new IllegalStateException("不支持的运算符: " + operator); + if (code == null) { + throw new IllegalStateException("不支持的运算符: " + op); + } IRVirtualRegister dest = ctx.newRegister(); ctx.addInstruction(new BinaryOperationInstruction(code, dest, lreg, rreg)); return dest; } - throw new IllegalStateException("不支持的表达式类型: " + expr.getClass().getSimpleName()); + // 4. 函数调用表达式处理 + if (expr instanceof CallExpressionNode call) { + // 构造实参寄存器列表,使用 IRValue 类型 + List args = new ArrayList<>(); + for (ExpressionNode argNode : call.arguments()) { + args.add(build(argNode)); + } + // 解析 callee + String fullName; + ExpressionNode callee = call.callee(); + if (callee instanceof MemberExpressionNode men + && men.object() instanceof IdentifierNode objId) { + // 模块静态调用 + fullName = objId.name() + "." + men.member(); + } else if (callee instanceof IdentifierNode id2) { + // 同模块调用 + fullName = id2.name(); + } else { + throw new IllegalStateException( + "不支持的调用目标: " + callee.getClass().getSimpleName() + ); + } + IRVirtualRegister dest = ctx.newRegister(); + ctx.addInstruction(new CallInstruction(dest, fullName, args)); + return dest; + } + + throw new IllegalStateException( + "不支持的表达式类型: " + expr.getClass().getSimpleName() + ); + } + + /** + * 决定二元运算类型后缀,基于两侧 NumberLiteralNode 的后缀。 + */ + private char resolveSuffix(ExpressionNode left, ExpressionNode right) { + char l = (left instanceof NumberLiteralNode ln) + ? Character.toLowerCase(ln.value().charAt(ln.value().length() - 1)) + : '\0'; + char r = (right instanceof NumberLiteralNode rn) + ? Character.toLowerCase(rn.value().charAt(rn.value().length() - 1)) + : '\0'; + if (l == 'd' || r == 'd') return 'd'; + if (l == 'f' || r == 'f') return 'f'; + if (l == 'l' || r == 'l') return 'l'; + if (l == 's' || r == 's') return 's'; + if (l == 'b' || r == 'b') return 'b'; + return '\0'; } } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java b/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java index c400619..4000814 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/core/IRVisitor.java @@ -53,4 +53,7 @@ public interface IRVisitor { * 访问一元运算指令,如 NEG_I32。 */ void visit(UnaryOperationInstruction inst); + + void visit(CallInstruction instruction); + } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java new file mode 100644 index 0000000..9e6e944 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java @@ -0,0 +1,65 @@ +package org.jcnc.snow.compiler.ir.instruction; + +import org.jcnc.snow.compiler.ir.core.IRInstruction; +import org.jcnc.snow.compiler.ir.core.IROpCode; +import org.jcnc.snow.compiler.ir.core.IRVisitor; +import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; +import org.jcnc.snow.compiler.ir.core.IRValue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * CallInstruction —— 表示一次函数调用,格式:dest = CALL functionName, arg1, arg2, ... + */ +public class CallInstruction extends IRInstruction { + private final IRVirtualRegister dest; + private final String functionName; + private final List arguments; + + public CallInstruction(IRVirtualRegister dest, String functionName, List args) { + this.dest = dest; + this.functionName = functionName; + this.arguments = Collections.unmodifiableList(new ArrayList<>(args)); + } + + @Override + public IROpCode op() { + return IROpCode.CALL; + } + + @Override + public List operands() { + List ops = new ArrayList<>(); + ops.add(dest); + ops.addAll(arguments); + return ops; + } + + public IRVirtualRegister getDest() { + return dest; + } + + public String getFunctionName() { + return functionName; + } + + public List getArguments() { + return arguments; + } + + @Override + public void accept(IRVisitor visitor) { + visitor.visit(this); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(dest + " = CALL " + functionName); + for (IRValue arg : arguments) { + sb.append(", ").append(arg); + } + return sb.toString(); + } +}