From 965b1a1addee31bd7a2c9a0570a18fad7df63478 Mon Sep 17 00:00:00 2001 From: Luke Date: Sun, 11 May 2025 23:05:51 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compiler/backend/VMCodeGenerator.java | 2 +- .../compiler/backend/VMProgramBuilder.java | 99 +++++++++++++++---- 2 files changed, 81 insertions(+), 20 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 d03ba84..09f933f 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/VMCodeGenerator.java @@ -16,7 +16,7 @@ import java.lang.reflect.Field; import java.util.Map; /** - * 为单个 {@link IRFunction} 生成对应的虚拟机指令序列。 + * VMCodeGenerator为单个 {@link IRFunction} 生成对应的虚拟机指令序列。 *

* 本类依据中间表示函数的指令列表,调用 {@link VMProgramBuilder} 输出相应的 VM 操作码, * 包括常量加载、算术运算、函数调用和返回等指令生成逻辑。 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 b1d6fb0..11d83d4 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/VMProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/VMProgramBuilder.java @@ -5,64 +5,125 @@ import org.jcnc.snow.vm.engine.VMOpCode; import java.util.*; /** - * Builds a linear VM program, resolving CALL addresses even if the - * target function appears later. Now emits “CALL <addr> <nArgs>”. + * 构建线性 VM 程序,支持对函数调用地址的延迟解析与修补。 + *

+ * 本类在生成程序时按顺序追加指令,并在定义函数入口时修补之前遇到的对该函数的调用。 + * 最终可产出完整的指令列表,用于 VM 执行。 + *

*/ public final class VMProgramBuilder { + /** + * 记录待修补的调用信息,包括指令索引、目标函数名称及参数个数。 + */ private record Fix(int index, String target, int nArgs) {} + /** + * 用于在目标地址未知时的占位符。 + */ private static final String PLACEHOLDER = "-1"; + /** + * 存储生成的指令行,按追加顺序对应程序计数器地址。 + */ private final List code = new ArrayList<>(); - private final Map labelAddr = new HashMap<>(); + + /** + * 已知函数名称到其入口地址(程序计数)的映射表。 + */ + private final Map labelAddr = new HashMap<>(); + + /** + * 存放所有尚未解析目标地址的调用信息,待函数定义时进行修补。 + */ private final List unresolved = new ArrayList<>(); + + /** + * 当前程序计数器,表示下一条指令的地址。 + */ private int pc = 0; - /* ---------- public API ---------- */ - + /** + * 标记函数入口位置,并即时修补之前对该函数的所有延迟调用。 + * + * @param name 函数名称 + */ public void beginFunction(String name) { labelAddr.put(name, pc); patchFixesFor(name); } + /** + * 追加一条原始指令到程序,并将程序计数器递增。 + * + * @param line 完整的指令文本 + */ public void emit(String line) { code.add(line); pc++; } - /** Emits CALL addr nArgs (addr may be unknown yet). */ + /** + * 生成函数调用指令 "CALL <addr> <nArgs>"。 + *
    + *
  • 若目标函数已定义,则直接使用其地址;
  • + *
  • 否则使用占位符并记录调用信息,待后续修补。
  • + *
+ * + * @param targetFn 目标函数名称 + * @param nArgs 调用参数数量 + */ public void emitCall(String targetFn, int nArgs) { Integer addr = resolve(targetFn); if (addr != null) { emit(VMOpCode.CALL + " " + addr + " " + nArgs); } else { emit(VMOpCode.CALL + " " + PLACEHOLDER + " " + nArgs); - unresolved.add(new Fix(pc-1, targetFn, nArgs)); + unresolved.add(new Fix(pc - 1, targetFn, nArgs)); } } + /** + * 完成指令生成并返回不可变的指令列表。 + * + * @return 按执行顺序排列的完整指令列表 + * @throws IllegalStateException 若仍存在未修补的调用目标 + */ public List build() { - if (!unresolved.isEmpty()) - throw new IllegalStateException("Unresolved CALL targets: "+unresolved); + if (!unresolved.isEmpty()) { + throw new IllegalStateException("Unresolved CALL targets: " + unresolved); + } return List.copyOf(code); } - /* ---------- internal helpers ---------- */ - + /** + * 尝试解析给定标签对应的地址。 + *

+ * 若标签包含包名(以 '.' 分隔),则尝试匹配简单名称后缀。 + *

+ * + * @param label 函数标签或全限定名称 + * @return 已知地址,或 {@code null} 表示尚未定义 + */ private Integer resolve(String label) { - Integer a = labelAddr.get(label); - if (a == null && label.contains(".")) { - a = labelAddr.get(label.substring(label.lastIndexOf('.')+1)); + Integer addr = labelAddr.get(label); + if (addr == null && label.contains(".")) { + String simpleName = label.substring(label.lastIndexOf('.') + 1); + addr = labelAddr.get(simpleName); } - return a; + return addr; } + /** + * 修补指定函数名称对应的所有延迟调用,将占位符替换为实际地址。 + * + * @param name 函数名称 + */ 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); + for (Iterator it = unresolved.iterator(); it.hasNext(); ) { + Fix fix = it.next(); + if (fix.target.equals(name) || fix.target.endsWith("." + name)) { + code.set(fix.index, VMOpCode.CALL + " " + pc + " " + fix.nArgs); it.remove(); } }