From fda5e5b3ac5bccc2dc07bbd5b5f042f9135ca9d8 Mon Sep 17 00:00:00 2001 From: Luke Date: Sun, 11 May 2025 00:21:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compiler/backend/VMCodeGenerator.java | 50 +++++-------- .../compiler/backend/VMProgramBuilder.java | 73 ++++++++----------- .../vm/commands/function/CallCommand.java | 41 +++++------ test | 7 +- 4 files changed, 72 insertions(+), 99 deletions(-) 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 5b20d55..0fb8c7f 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java @@ -9,39 +9,35 @@ import java.lang.reflect.Field; import java.util.Map; /** - * 将单个 IRFunction 转换成 VM 指令并写入 VMProgramBuilder。 + * Generates VM code for a single IRFunction. */ public final class VMCodeGenerator { - private final Map slotMap; + private final Map slotMap; private final VMProgramBuilder out; private String currentFn; - public VMCodeGenerator(Map slotMap, + public VMCodeGenerator(Map slotMap, VMProgramBuilder out) { this.slotMap = slotMap; this.out = out; } - /** 主入口:生成当前函数全部指令(无返回值,直接写入 builder) */ public void generate(IRFunction fn) { currentFn = fn.name(); - out.beginFunction(currentFn); // 记录入口 + out.beginFunction(currentFn); - for (IRInstruction inst : fn.body()) { - switch (inst) { - 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( - "Unsupported IR: " + inst); - } + for (IRInstruction inst : fn.body()) switch (inst) { + 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("Unsupported IR: "+inst); } } - /* ---------- 指令生成 ---------- */ + /* ---------- helpers ---------- */ private void genLoadConst(LoadConstInstruction c) { IRConstant k = (IRConstant) c.operands().getFirst(); @@ -62,17 +58,14 @@ public final class VMCodeGenerator { emit(op("I_STORE"), slot(u.dest())); } + /** Generates CALL addr nArgs */ private void genCall(CallInstruction c) { - // 实参入栈 + /* push arguments in IR order (already left-to-right) */ for (IRValue arg : c.getArguments()) { - if (arg instanceof IRVirtualRegister reg) - emit(op("I_LOAD"), slot(reg)); - else - throw new IllegalStateException("Unsupported arg: " + arg); + emit(op("I_LOAD"), slot((IRVirtualRegister) arg)); } - // 生成 CALL(由 builder 解析地址/回填) - out.emitCall(c.getFunctionName()); - // 存放返回值 + int nArgs = c.getArguments().size(); + out.emitCall(c.getFunctionName(), nArgs); emit(op("I_STORE"), slot(c.getDest())); } @@ -82,8 +75,6 @@ public final class VMCodeGenerator { emit("main".equals(currentFn) ? op("HALT") : op("RET")); } - /* ---------- 工具 ---------- */ - private void emit(String opcode, String... args) { StringBuilder sb = new StringBuilder(opcode); for (String a : args) sb.append(' ').append(a); @@ -91,10 +82,7 @@ public final class VMCodeGenerator { } private String slot(IRVirtualRegister r) { - Integer s = slotMap.get(r); - if (s == null) - throw new IllegalStateException("Unmapped register: " + r); - return s.toString(); + return slotMap.get(r).toString(); } private String op(String name) { @@ -102,7 +90,7 @@ public final class VMCodeGenerator { Field f = VMOpCode.class.getField(name); return f.get(null).toString(); } catch (Exception e) { - throw new RuntimeException("Unknown opcode: " + name, e); + throw new RuntimeException("Unknown opcode: "+name, e); } } } diff --git a/src/main/java/org/jcnc/snow/compiler/backend/VMProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/backend/VMProgramBuilder.java index 0b6514f..b1d6fb0 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/VMProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/VMProgramBuilder.java @@ -5,75 +5,64 @@ import org.jcnc.snow.vm.engine.VMOpCode; import java.util.*; /** - * 负责生成整段 VM 指令: - * 1. 为每个函数登记入口地址(label → pc) - * 2. 生成指令并维护全局 pc 计数 - * 3. 支持前向调用:CALL 时目标函数尚未出现也能写占位并在后续回填 - * 4. 允许模块前缀(CommonTasks.test)与简名(test)互相解析 + * Builds a linear VM program, resolving CALL addresses even if the + * target function appears later. Now emits “CALL <addr> <nArgs>”. */ public final class VMProgramBuilder { - private static final String PLACEHOLDER = "-1"; - private record Fixup(int index, String target) {} + private record Fix(int index, String target, int nArgs) {} - private final List code = new ArrayList<>(); - private final Map labelMap = new HashMap<>(); - private final List unresolved = new ArrayList<>(); + private static final String PLACEHOLDER = "-1"; + + private final List code = new ArrayList<>(); + private final Map labelAddr = new HashMap<>(); + private final List unresolved = new ArrayList<>(); private int pc = 0; - /* 在写入函数体指令之前调用 —— 记录入口地址并回填之前的前向 CALL */ + /* ---------- public API ---------- */ + public void beginFunction(String name) { - labelMap.put(name, pc); - patchFixupsFor(name); + labelAddr.put(name, pc); + patchFixesFor(name); } - /* 普通指令 */ public void emit(String line) { code.add(line); pc++; } - /* 生成 CALL,自动解析前缀 / 回填 */ - public void emitCall(String target) { - Integer addr = resolveAddr(target); + /** Emits CALL addr nArgs (addr may be unknown yet). */ + public void emitCall(String targetFn, int nArgs) { + Integer addr = resolve(targetFn); if (addr != null) { - emit(VMOpCode.CALL + " " + addr); + emit(VMOpCode.CALL + " " + addr + " " + nArgs); } else { - emit(VMOpCode.CALL + " " + PLACEHOLDER); // 写占位 - unresolved.add(new Fixup(pc - 1, target)); + emit(VMOpCode.CALL + " " + PLACEHOLDER + " " + nArgs); + unresolved.add(new Fix(pc-1, targetFn, nArgs)); } } - /* 构建最终代码,若还有悬而未决的前向调用则报错 */ public List build() { - if (!unresolved.isEmpty()) { - String msg = "Unresolved CALL targets: " + - unresolved.stream().map(f -> f.target).toList(); - throw new IllegalStateException(msg); - } + if (!unresolved.isEmpty()) + throw new IllegalStateException("Unresolved CALL targets: "+unresolved); return List.copyOf(code); } - /* ---------- 私有辅助 ---------- */ + /* ---------- internal helpers ---------- */ - /** 解析 label:先查原样,再查去掉模块前缀后的简名 */ - private Integer resolveAddr(String label) { - Integer addr = labelMap.get(label); - if (addr == null && label.contains(".")) { - String simple = label.substring(label.lastIndexOf('.') + 1); - addr = labelMap.get(simple); + private Integer resolve(String label) { + Integer a = labelAddr.get(label); + if (a == null && label.contains(".")) { + a = labelAddr.get(label.substring(label.lastIndexOf('.')+1)); } - return addr; + return a; } - /** 当某个函数登记入口后,回填此前针对它的占位 CALL */ - private void patchFixupsFor(String name) { - for (Iterator it = unresolved.iterator(); it.hasNext(); ) { - Fixup f = it.next(); - boolean match = f.target.equals(name) || - f.target.endsWith("." + name); - if (match) { - code.set(f.index, VMOpCode.CALL + " " + pc); + private void patchFixesFor(String name) { + for (Iterator it = unresolved.iterator(); it.hasNext();) { + Fix f = it.next(); + if (f.target.equals(name) || f.target.endsWith("."+name)) { + code.set(f.index, VMOpCode.CALL + " " + pc + " " + f.nArgs); it.remove(); } } diff --git a/src/main/java/org/jcnc/snow/vm/commands/function/CallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/function/CallCommand.java index e466bc0..a384570 100644 --- a/src/main/java/org/jcnc/snow/vm/commands/function/CallCommand.java +++ b/src/main/java/org/jcnc/snow/vm/commands/function/CallCommand.java @@ -5,8 +5,9 @@ import org.jcnc.snow.vm.interfaces.Command; import org.jcnc.snow.vm.module.*; /** - * CALL 指令 —— 创建新栈帧并跳转到目标地址,同时把实参从操作数栈 - * 写入被调函数的局部变量表(目前只处理 1 个参数)。 + * CALL addr nArgs — pushes a new stack-frame, transfers the specified + * argument count from the operand stack into the callee’s local slots + * 0‥n-1 (left-to-right), then jumps to {@code addr}. */ public class CallCommand implements Command { @@ -17,39 +18,33 @@ public class CallCommand implements Command { LocalVariableStore callerLVS, CallStack callStack) { - /* ---------- 解析地址 ---------- */ - if (parts.length < 2) - throw new IllegalArgumentException("CALL: missing target address"); + if (parts.length < 3) + throw new IllegalArgumentException("CALL: need "); int targetAddr; + int nArgs; try { targetAddr = Integer.parseInt(parts[1]); + nArgs = Integer.parseInt(parts[2]); } catch (NumberFormatException e) { - throw new IllegalArgumentException("CALL: invalid address " + parts[1], e); + throw new IllegalArgumentException("CALL: malformed operands", e); } - /* ---------- 创建新栈帧 ---------- */ + /* build new frame & local table for callee */ LocalVariableStore calleeLVS = new LocalVariableStore(VMMode.RUN); - /* ---------- 处理 1 个实参 ---------- */ - if (operandStack.isEmpty()) - throw new IllegalStateException("CALL: operand stack empty, missing argument"); - Object arg0 = operandStack.pop(); // 弹出栈顶实参 - calleeLVS.setVariable(0, arg0); // 写入槽 0 + /* transfer arguments: operand stack top is last arg */ + for (int slot = nArgs - 1; slot >= 0; slot--) { + if (operandStack.isEmpty()) + throw new IllegalStateException("CALL: operand stack underflow"); + calleeLVS.setVariable(slot, operandStack.pop()); + } - /* 若将来有多个参数,可用: - for (int i = nArgs - 1; i >= 0; i--) { - calleeLVS.setVariable(i, operandStack.pop()); - } - */ - - MethodContext ctx = new MethodContext("subroutine@" + targetAddr, null); - StackFrame newFrame = new StackFrame(currentPC + 1, calleeLVS, ctx); + StackFrame newFrame = new StackFrame(currentPC + 1, calleeLVS, + new MethodContext("subroutine@" + targetAddr, null)); callStack.pushFrame(newFrame); System.out.println("Calling function at address: " + targetAddr); - - /* ---------- 跳转 ---------- */ - return targetAddr; + return targetAddr; // jump } } diff --git a/test b/test index 85222e7..783b83e 100644 --- a/test +++ b/test @@ -8,18 +8,19 @@ module: CommonTasks body: num1 = 1 num2=2 - return num1 + CommonTasks.test(3) + return num1 + CommonTasks.test(3,4) end body end function function:test parameter: declare num1:int + declare num2:int return_type:int body: declare result : int - declare num2: int =4 - result = num2 + num1 + declare num3: int =4 + result = num1 + num2 +num3 return result end body end function