支持多参数

This commit is contained in:
Luke 2025-05-11 00:21:53 +08:00
parent 50fbc40039
commit fda5e5b3ac
4 changed files with 72 additions and 99 deletions

View File

@ -9,39 +9,35 @@ import java.lang.reflect.Field;
import java.util.Map; import java.util.Map;
/** /**
* 将单个 IRFunction 转换成 VM 指令并写入 VMProgramBuilder * Generates VM code for a single IRFunction.
*/ */
public final class VMCodeGenerator { public final class VMCodeGenerator {
private final Map<IRVirtualRegister, Integer> slotMap; private final Map<IRVirtualRegister,Integer> slotMap;
private final VMProgramBuilder out; private final VMProgramBuilder out;
private String currentFn; private String currentFn;
public VMCodeGenerator(Map<IRVirtualRegister, Integer> slotMap, public VMCodeGenerator(Map<IRVirtualRegister,Integer> slotMap,
VMProgramBuilder out) { VMProgramBuilder out) {
this.slotMap = slotMap; this.slotMap = slotMap;
this.out = out; this.out = out;
} }
/** 主入口:生成当前函数全部指令(无返回值,直接写入 builder */
public void generate(IRFunction fn) { public void generate(IRFunction fn) {
currentFn = fn.name(); currentFn = fn.name();
out.beginFunction(currentFn); // 记录入口 out.beginFunction(currentFn);
for (IRInstruction inst : fn.body()) { for (IRInstruction inst : fn.body()) switch (inst) {
switch (inst) { case LoadConstInstruction c -> genLoadConst(c);
case LoadConstInstruction c -> genLoadConst(c); case BinaryOperationInstruction b -> genBinOp(b);
case BinaryOperationInstruction b -> genBinOp(b); case UnaryOperationInstruction u -> genUnary(u);
case UnaryOperationInstruction u -> genUnary(u); case CallInstruction c -> genCall(c);
case CallInstruction c -> genCall(c); case ReturnInstruction r -> genRet(r);
case ReturnInstruction r -> genRet(r); default -> throw new IllegalStateException("Unsupported IR: "+inst);
default -> throw new IllegalStateException(
"Unsupported IR: " + inst);
}
} }
} }
/* ---------- 指令生成 ---------- */ /* ---------- helpers ---------- */
private void genLoadConst(LoadConstInstruction c) { private void genLoadConst(LoadConstInstruction c) {
IRConstant k = (IRConstant) c.operands().getFirst(); IRConstant k = (IRConstant) c.operands().getFirst();
@ -62,17 +58,14 @@ public final class VMCodeGenerator {
emit(op("I_STORE"), slot(u.dest())); emit(op("I_STORE"), slot(u.dest()));
} }
/** Generates CALL addr nArgs */
private void genCall(CallInstruction c) { private void genCall(CallInstruction c) {
// 实参入栈 /* push arguments in IR order (already left-to-right) */
for (IRValue arg : c.getArguments()) { for (IRValue arg : c.getArguments()) {
if (arg instanceof IRVirtualRegister reg) emit(op("I_LOAD"), slot((IRVirtualRegister) arg));
emit(op("I_LOAD"), slot(reg));
else
throw new IllegalStateException("Unsupported arg: " + arg);
} }
// 生成 CALL builder 解析地址/回填 int nArgs = c.getArguments().size();
out.emitCall(c.getFunctionName()); out.emitCall(c.getFunctionName(), nArgs);
// 存放返回值
emit(op("I_STORE"), slot(c.getDest())); emit(op("I_STORE"), slot(c.getDest()));
} }
@ -82,8 +75,6 @@ public final class VMCodeGenerator {
emit("main".equals(currentFn) ? op("HALT") : op("RET")); emit("main".equals(currentFn) ? op("HALT") : op("RET"));
} }
/* ---------- 工具 ---------- */
private void emit(String opcode, String... args) { private void emit(String opcode, String... args) {
StringBuilder sb = new StringBuilder(opcode); StringBuilder sb = new StringBuilder(opcode);
for (String a : args) sb.append(' ').append(a); for (String a : args) sb.append(' ').append(a);
@ -91,10 +82,7 @@ public final class VMCodeGenerator {
} }
private String slot(IRVirtualRegister r) { private String slot(IRVirtualRegister r) {
Integer s = slotMap.get(r); return slotMap.get(r).toString();
if (s == null)
throw new IllegalStateException("Unmapped register: " + r);
return s.toString();
} }
private String op(String name) { private String op(String name) {
@ -102,7 +90,7 @@ public final class VMCodeGenerator {
Field f = VMOpCode.class.getField(name); Field f = VMOpCode.class.getField(name);
return f.get(null).toString(); return f.get(null).toString();
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Unknown opcode: " + name, e); throw new RuntimeException("Unknown opcode: "+name, e);
} }
} }
} }

View File

@ -5,75 +5,64 @@ import org.jcnc.snow.vm.engine.VMOpCode;
import java.util.*; import java.util.*;
/** /**
* 负责生成整段 VM 指令 * Builds a linear VM program, resolving CALL addresses even if the
* 1. 为每个函数登记入口地址label pc * target function appears later. Now emits CALL &lt;addr&gt; &lt;nArgs&gt;.
* 2. 生成指令并维护全局 pc 计数
* 3. 支持前向调用CALL 时目标函数尚未出现也能写占位并在后续回填
* 4. 允许模块前缀CommonTasks.test与简名test互相解析
*/ */
public final class VMProgramBuilder { public final class VMProgramBuilder {
private static final String PLACEHOLDER = "-1"; private record Fix(int index, String target, int nArgs) {}
private record Fixup(int index, String target) {}
private final List<String> code = new ArrayList<>(); private static final String PLACEHOLDER = "-1";
private final Map<String, Integer> labelMap = new HashMap<>();
private final List<Fixup> unresolved = new ArrayList<>(); private final List<String> code = new ArrayList<>();
private final Map<String,Integer> labelAddr = new HashMap<>();
private final List<Fix> unresolved = new ArrayList<>();
private int pc = 0; private int pc = 0;
/* 在写入函数体指令之前调用 —— 记录入口地址并回填之前的前向 CALL */ /* ---------- public API ---------- */
public void beginFunction(String name) { public void beginFunction(String name) {
labelMap.put(name, pc); labelAddr.put(name, pc);
patchFixupsFor(name); patchFixesFor(name);
} }
/* 普通指令 */
public void emit(String line) { public void emit(String line) {
code.add(line); code.add(line);
pc++; pc++;
} }
/* 生成 CALL自动解析前缀 / 回填 */ /** Emits CALL addr nArgs (addr may be unknown yet). */
public void emitCall(String target) { public void emitCall(String targetFn, int nArgs) {
Integer addr = resolveAddr(target); Integer addr = resolve(targetFn);
if (addr != null) { if (addr != null) {
emit(VMOpCode.CALL + " " + addr); emit(VMOpCode.CALL + " " + addr + " " + nArgs);
} else { } else {
emit(VMOpCode.CALL + " " + PLACEHOLDER); // 写占位 emit(VMOpCode.CALL + " " + PLACEHOLDER + " " + nArgs);
unresolved.add(new Fixup(pc - 1, target)); unresolved.add(new Fix(pc-1, targetFn, nArgs));
} }
} }
/* 构建最终代码,若还有悬而未决的前向调用则报错 */
public List<String> build() { public List<String> build() {
if (!unresolved.isEmpty()) { if (!unresolved.isEmpty())
String msg = "Unresolved CALL targets: " + throw new IllegalStateException("Unresolved CALL targets: "+unresolved);
unresolved.stream().map(f -> f.target).toList();
throw new IllegalStateException(msg);
}
return List.copyOf(code); return List.copyOf(code);
} }
/* ---------- 私有辅助 ---------- */ /* ---------- internal helpers ---------- */
/** 解析 label先查原样再查去掉模块前缀后的简名 */ private Integer resolve(String label) {
private Integer resolveAddr(String label) { Integer a = labelAddr.get(label);
Integer addr = labelMap.get(label); if (a == null && label.contains(".")) {
if (addr == null && label.contains(".")) { a = labelAddr.get(label.substring(label.lastIndexOf('.')+1));
String simple = label.substring(label.lastIndexOf('.') + 1);
addr = labelMap.get(simple);
} }
return addr; return a;
} }
/** 当某个函数登记入口后,回填此前针对它的占位 CALL */ private void patchFixesFor(String name) {
private void patchFixupsFor(String name) { for (Iterator<Fix> it = unresolved.iterator(); it.hasNext();) {
for (Iterator<Fixup> it = unresolved.iterator(); it.hasNext(); ) { Fix f = it.next();
Fixup f = it.next(); if (f.target.equals(name) || f.target.endsWith("."+name)) {
boolean match = f.target.equals(name) || code.set(f.index, VMOpCode.CALL + " " + pc + " " + f.nArgs);
f.target.endsWith("." + name);
if (match) {
code.set(f.index, VMOpCode.CALL + " " + pc);
it.remove(); it.remove();
} }
} }

View File

@ -5,8 +5,9 @@ import org.jcnc.snow.vm.interfaces.Command;
import org.jcnc.snow.vm.module.*; import org.jcnc.snow.vm.module.*;
/** /**
* CALL 指令 创建新栈帧并跳转到目标地址同时把实参从操作数栈 * CALL addr nArgs pushes a new stack-frame, transfers the specified
* 写入被调函数的局部变量表目前只处理 1 个参数 * argument count from the operand stack into the callees local slots
* 0n-1 (left-to-right), then jumps to {@code addr}.
*/ */
public class CallCommand implements Command { public class CallCommand implements Command {
@ -17,39 +18,33 @@ public class CallCommand implements Command {
LocalVariableStore callerLVS, LocalVariableStore callerLVS,
CallStack callStack) { CallStack callStack) {
/* ---------- 解析地址 ---------- */ if (parts.length < 3)
if (parts.length < 2) throw new IllegalArgumentException("CALL: need <addr> <nArgs>");
throw new IllegalArgumentException("CALL: missing target address");
int targetAddr; int targetAddr;
int nArgs;
try { try {
targetAddr = Integer.parseInt(parts[1]); targetAddr = Integer.parseInt(parts[1]);
nArgs = Integer.parseInt(parts[2]);
} catch (NumberFormatException e) { } 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); LocalVariableStore calleeLVS = new LocalVariableStore(VMMode.RUN);
/* ---------- 处理 1 个实参 ---------- */ /* transfer arguments: operand stack top is last arg */
if (operandStack.isEmpty()) for (int slot = nArgs - 1; slot >= 0; slot--) {
throw new IllegalStateException("CALL: operand stack empty, missing argument"); if (operandStack.isEmpty())
Object arg0 = operandStack.pop(); // 弹出栈顶实参 throw new IllegalStateException("CALL: operand stack underflow");
calleeLVS.setVariable(0, arg0); // 写入槽 0 calleeLVS.setVariable(slot, operandStack.pop());
}
/* 若将来有多个参数可用 StackFrame newFrame = new StackFrame(currentPC + 1, calleeLVS,
for (int i = nArgs - 1; i >= 0; i--) { new MethodContext("subroutine@" + targetAddr, null));
calleeLVS.setVariable(i, operandStack.pop());
}
*/
MethodContext ctx = new MethodContext("subroutine@" + targetAddr, null);
StackFrame newFrame = new StackFrame(currentPC + 1, calleeLVS, ctx);
callStack.pushFrame(newFrame); callStack.pushFrame(newFrame);
System.out.println("Calling function at address: " + targetAddr); System.out.println("Calling function at address: " + targetAddr);
return targetAddr; // jump
/* ---------- 跳转 ---------- */
return targetAddr;
} }
} }

7
test
View File

@ -8,18 +8,19 @@ module: CommonTasks
body: body:
num1 = 1 num1 = 1
num2=2 num2=2
return num1 + CommonTasks.test(3) return num1 + CommonTasks.test(3,4)
end body end body
end function end function
function:test function:test
parameter: parameter:
declare num1:int declare num1:int
declare num2:int
return_type:int return_type:int
body: body:
declare result : int declare result : int
declare num2: int =4 declare num3: int =4
result = num2 + num1 result = num1 + num2 +num3
return result return result
end body end body
end function end function