支持多参数
This commit is contained in:
parent
50fbc40039
commit
fda5e5b3ac
@ -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(
|
default -> throw new IllegalStateException("Unsupported IR: "+inst);
|
||||||
"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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 <addr> <nArgs>”.
|
||||||
* 2. 生成指令并维护全局 pc 计数
|
|
||||||
* 3. 支持前向调用:CALL 时目标函数尚未出现也能写占位并在后续回填
|
|
||||||
* 4. 允许模块前缀(CommonTasks.test)与简名(test)互相解析
|
|
||||||
*/
|
*/
|
||||||
public final class VMProgramBuilder {
|
public final class VMProgramBuilder {
|
||||||
|
|
||||||
|
private record Fix(int index, String target, int nArgs) {}
|
||||||
|
|
||||||
private static final String PLACEHOLDER = "-1";
|
private static final String PLACEHOLDER = "-1";
|
||||||
private record Fixup(int index, String target) {}
|
|
||||||
|
|
||||||
private final List<String> code = new ArrayList<>();
|
private final List<String> code = new ArrayList<>();
|
||||||
private final Map<String, Integer> labelMap = new HashMap<>();
|
private final Map<String,Integer> labelAddr = new HashMap<>();
|
||||||
private final List<Fixup> unresolved = new ArrayList<>();
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 callee’s local slots
|
||||||
|
* 0‥n-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 */
|
||||||
|
for (int slot = nArgs - 1; slot >= 0; slot--) {
|
||||||
if (operandStack.isEmpty())
|
if (operandStack.isEmpty())
|
||||||
throw new IllegalStateException("CALL: operand stack empty, missing argument");
|
throw new IllegalStateException("CALL: operand stack underflow");
|
||||||
Object arg0 = operandStack.pop(); // 弹出栈顶实参
|
calleeLVS.setVariable(slot, operandStack.pop());
|
||||||
calleeLVS.setVariable(0, arg0); // 写入槽 0
|
|
||||||
|
|
||||||
/* 若将来有多个参数,可用:
|
|
||||||
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,
|
||||||
StackFrame newFrame = new StackFrame(currentPC + 1, calleeLVS, ctx);
|
new MethodContext("subroutine@" + targetAddr, null));
|
||||||
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
7
test
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user