支持多参数
This commit is contained in:
parent
50fbc40039
commit
fda5e5b3ac
@ -9,7 +9,7 @@ import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 将单个 IRFunction 转换成 VM 指令并写入 VMProgramBuilder。
|
||||
* Generates VM code for a single IRFunction.
|
||||
*/
|
||||
public final class VMCodeGenerator {
|
||||
|
||||
@ -23,25 +23,21 @@ public final class VMCodeGenerator {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
|
||||
@ -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 record Fix(int index, String target, int nArgs) {}
|
||||
|
||||
private static final String PLACEHOLDER = "-1";
|
||||
private record Fixup(int index, String target) {}
|
||||
|
||||
private final List<String> code = new ArrayList<>();
|
||||
private final Map<String, Integer> labelMap = new HashMap<>();
|
||||
private final List<Fixup> unresolved = 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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 <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 个实参 ---------- */
|
||||
/* 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 empty, missing argument");
|
||||
Object arg0 = operandStack.pop(); // 弹出栈顶实参
|
||||
calleeLVS.setVariable(0, arg0); // 写入槽 0
|
||||
|
||||
/* 若将来有多个参数,可用:
|
||||
for (int i = nArgs - 1; i >= 0; i--) {
|
||||
calleeLVS.setVariable(i, operandStack.pop());
|
||||
throw new IllegalStateException("CALL: operand stack underflow");
|
||||
calleeLVS.setVariable(slot, 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
7
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user