支持多参数

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;
/**
* 将单个 IRFunction 转换成 VM 指令并写入 VMProgramBuilder
* Generates VM code for a single IRFunction.
*/
public final class VMCodeGenerator {
private final Map<IRVirtualRegister, Integer> slotMap;
private final Map<IRVirtualRegister,Integer> slotMap;
private final VMProgramBuilder out;
private String currentFn;
public VMCodeGenerator(Map<IRVirtualRegister, Integer> slotMap,
public VMCodeGenerator(Map<IRVirtualRegister,Integer> 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);
}
}
}

View File

@ -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 &lt;addr&gt; &lt;nArgs&gt;.
*/
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<String> code = new ArrayList<>();
private final Map<String, Integer> labelMap = new HashMap<>();
private final List<Fixup> unresolved = new ArrayList<>();
private static final String PLACEHOLDER = "-1";
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;
/* 在写入函数体指令之前调用 —— 记录入口地址并回填之前的前向 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<String> 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<Fixup> 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<Fix> 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();
}
}

View File

@ -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 callees local slots
* 0n-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 <addr> <nArgs>");
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
}
}

7
test
View File

@ -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