From cadace165ab9c5e0e9c1f84b1781a01e0788998f Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:43:17 +0800 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=E6=94=B9=E8=BF=9B=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E8=B0=83=E7=94=A8=E5=92=8C=E6=A8=A1=E5=9D=97=E5=A4=84?= =?UTF-8?q?=E7=90=86=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 补充模块名以生成全限定函数名,增强模块间调用的准确性 - 重构 IRProgramBuilder 以更清晰地处理模块和函数 - 优化 VMCodeGenerator 和 VMProgramBuilder 以支持新的全限定名机制 --- .../backend/builder/VMCodeGenerator.java | 67 ++++---- .../backend/builder/VMProgramBuilder.java | 159 +++++++++--------- .../ir/builder/ExpressionBuilder.java | 16 +- .../compiler/ir/builder/IRProgramBuilder.java | 90 ++++++---- 4 files changed, 176 insertions(+), 156 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java index 2458b9e..98c490d 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java @@ -5,96 +5,89 @@ import org.jcnc.snow.compiler.backend.utils.OpHelper; import org.jcnc.snow.compiler.ir.core.IRFunction; import org.jcnc.snow.compiler.ir.core.IRInstruction; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; - import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** - * 虚拟机代码生成器(VMCodeGenerator) + * VMCodeGenerator 负责将中间表示(IR)函数转换为目标虚拟机(VM)的指令序列。 *

- * 本类作为指令生成器调度中心,不负责任何具体 IR 指令到 VM 指令的转换实现, - * 仅负责根据指令类型分发到对应的 {@link InstructionGenerator} 子类完成实际生成。 - *

- *

- * 工作流程简述: - *

    - *
  1. 接收一组已注册的 IR 指令生成器,并建立类型到生成器的映射表。
  2. - *
  3. 遍历 IR 函数体的每条指令,根据类型找到对应的生成器,调用其 generate 方法生成 VM 指令。
  4. - *
  5. 生成流程以函数为单位(beginFunction/endFunction)。
  6. - *
+ * 每个 IR 指令根据类型由对应的 InstructionGenerator 处理,并将结果输出到 VMProgramBuilder。 + * 该类通过注册表(registry)实现 IR 到 VM 指令生成器的快速分发。 */ public final class VMCodeGenerator { /** - * 指令类型到生成器的注册表(调度表)。 - *

- * 键: IR 指令类型(Class对象), - * 值: 对应的指令生成器实例。 - *

+ * IR 指令类型到指令生成器的映射。 + * 每种 IRInstruction 都有对应的 InstructionGenerator 处理。 */ private final Map, InstructionGenerator> registry; /** - * 虚拟寄存器到槽号的映射表,由 RegisterAllocator 负责生成。 + * 虚拟寄存器到 VM 局部槽位的映射表。 + * 用于寄存器分配与指令生成。 */ private final Map slotMap; /** - * 虚拟机程序构建器,用于输出 VM 指令。 + * 输出目标 VM 程序的构建器。 + * 提供 emit、beginFunction、endFunction 等接口。 */ private final VMProgramBuilder out; /** - * 当前处理的函数名,用于部分指令生成逻辑(如主函数判断等)。 + * 当前正在处理的函数名。 + * 用于区分是否为 main 函数等用途。 */ private String currentFn; /** - * 构造方法 + * 构造 VMCodeGenerator。 * - * @param slotMap 虚拟寄存器到槽号的映射 - * @param out 虚拟机程序构建器 - * @param generators 各类 IR 指令生成器集合,需预先构建 + * @param slotMap 虚拟寄存器到 VM 局部槽位的分配表 + * @param out 输出 VM 程序的 builder + * @param generators 可用的 IR 指令生成器列表,每个类型只应有一个 */ public VMCodeGenerator(Map slotMap, VMProgramBuilder out, List> generators) { this.slotMap = slotMap; this.out = out; - // 按类型注册各 IR 指令生成器,建立不可变类型-生成器映射表 + // 构建不可变的类型到生成器的注册表 this.registry = generators.stream() .collect(Collectors.toUnmodifiableMap(InstructionGenerator::supportedClass, g -> g)); } /** - * 为一个 IR 函数生成虚拟机指令 + * 将 IRFunction 生成对应 VM 代码,并写入输出。 * - * @param fn 待生成的 IR 函数对象 - * @throws IllegalStateException 若遇到不支持的 IR 指令类型 + *
    + *
  1. 调用 {@code out.beginFunction} 标记函数起始。
  2. + *
  3. 遍历函数体的每条 IR 指令,查找对应 InstructionGenerator 并生成目标代码。
  4. + *
  5. 对 main/main.xxx 函数追加 HALT 指令,其它函数追加 RET。
  6. + *
  7. 调用 {@code out.endFunction} 结束函数。
  8. + *
+ * + * @param fn 需要生成 VM 代码的 IRFunction + * @throws IllegalStateException 如果遇到不支持的 IR 指令类型 */ public void generate(IRFunction fn) { this.currentFn = fn.name(); - - /* 登记函数入口地址 —— 解决 CALL 未解析符号问题 */ out.beginFunction(currentFn); - - /* 逐条分发 IR 指令给对应的生成器 */ for (IRInstruction ins : fn.body()) { @SuppressWarnings("unchecked") + // 查找合适的指令生成器 InstructionGenerator gen = (InstructionGenerator) registry.get(ins.getClass()); if (gen == null) { throw new IllegalStateException("Unsupported IR: " + ins); } + // 调用生成器生成对应的 VM 指令 gen.generate(ins, out, slotMap, currentFn); } - - /* 强制补上函数结尾的返回/终止指令 */ - String retOpcode = "main".equals(currentFn) ? "HALT" : "RET"; + // 结尾指令:main 函数统一用 HALT,其他函数用 RET + String retOpcode = ("main".equals(currentFn) || currentFn.endsWith(".main")) ? "HALT" : "RET"; out.emit(OpHelper.opcode(retOpcode)); - - /* 结束函数 */ out.endFunction(); } } diff --git a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java index 7ded37b..fab891c 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMProgramBuilder.java @@ -1,109 +1,109 @@ package org.jcnc.snow.compiler.backend.builder; import org.jcnc.snow.vm.engine.VMOpCode; - import java.util.*; /** - * VMProgramBuilder: 构建线性 VM 程序(即按顺序存放所有 VM 指令)。 + * VMProgramBuilder 用于构建虚拟机(VM)的最终指令列表。 *

- * 本类用于编译器后端,将所有生成的 VM 指令(包括分支和调用指令)统一存储、管理。 - * 支持符号(如函数入口、标签地址)的延迟解析与回填(fix-up)机制, - * 可在目标尚未定义时提前生成分支或调用指令,定义后自动修正。 - *

- *

- * 常用于处理跨函数、跨标签的 CALL/JUMP 等复杂控制流,确保最终生成的 VM 指令地址一致正确。 - *

+ * 主要职责: + *
    + *
  • 维护代码指令序列和符号地址表
  • + *
  • 支持跨函数、标签跳转的延后修补(Call/Branch Fixup)
  • + *
  • 支持虚拟机本地槽位类型的管理(如 I/F...)
  • + *
*/ public final class VMProgramBuilder { - /** 未解析目标的 CALL 指令信息(待修补) */ + + /** + * 未知目标的 CALL 指令修补记录(待目标地址确定后修正)。 + * @param index CALL 指令在 code 列表中的位置 + * @param target 目标函数的全名 + * @param nArgs 参数个数 + */ private record CallFix(int index, String target, int nArgs) {} - /** 未解析目标的分支指令(JUMP/IC_* 等待修补) */ + /** + * 未知目标的分支指令修补记录(待目标标签确定后修正)。 + * @param index 分支指令在 code 列表中的位置 + * @param label 跳转目标标签名 + */ private record BranchFix(int index, String label) {} - /** 占位符: 用于表示尚未确定的符号地址 */ + /** 未解析地址的占位符,便于后期批量修补 */ private static final String PLACEHOLDER = "-1"; - /** 按顺序存放的 VM 指令文本 */ + /** VM 指令列表 */ private final List code = new ArrayList<>(); - - // 虚拟机槽位编号到数据类型前缀的映射(如 0 -> 'I', 1 -> 'D' 等) + /** 槽位(寄存器)类型映射表(如 I/F...,用于类型检查或代码生成优化) */ private final Map slotType = new HashMap<>(); - - /** 符号(如函数名、标签名)到其首地址(即指令序号/偏移量)的映射表 - * 主要用于跳转和调用,定位具体的代码位置 */ + /** 符号(函数名/标签)到指令序号的映射表 */ private final Map addr = new HashMap<>(); - - /** 所有待回填(fix-up)的 CALL 调用指令记录 - * 由于被调用目标地址在编译时可能尚未确定,需要先记录,最终统一回填 */ + /** 所有待修补的 CALL 指令集合 */ private final List callFixes = new ArrayList<>(); - - /** 所有待回填(fix-up)的分支跳转指令记录 - * 与 CALL 类似,分支指令的目标地址也可能需要编译后期再补充 */ + /** 所有待修补的分支指令集合 */ private final List branchFixes = new ArrayList<>(); - - /** 程序计数器(Program Counter),表示下一个生成指令将插入的位置 */ + /** 当前代码指针(已生成指令的数量/下一个指令的位置) */ private int pc = 0; /** - * 设置某个槽位对应的数据类型前缀 + * 设置槽位(局部变量/虚拟寄存器)的类型前缀。 + * * @param slot 槽位编号 - * @param prefix 类型前缀(如 'I' 表示 int,'D' 表示 double 等) + * @param prefix 类型前缀(如 'I', 'F') */ public void setSlotType(int slot, char prefix) { slotType.put(slot, prefix); } /** - * 获取某个槽位对应的数据类型前缀 - * 若未指定则返回默认类型 'I'(int) + * 获取槽位的类型前缀,默认为 'I'(整数类型)。 + * * @param slot 槽位编号 - * @return 类型前缀(如 'I', 'D' 等) + * @return 类型前缀字符 */ public char getSlotType(int slot) { return slotType.getOrDefault(slot, 'I'); } - /** - * 标记函数入口或标签,并尝试修补所有等候该符号的指令。 - * @param name 符号名(函数名/标签名) + * 标记一个函数或标签的起始位置。 + *

+ * 1. 记录符号到当前 pc 的映射; + * 2. 立即尝试修补之前所有针对该符号的延后调用和分支。 + * + * @param name 函数名或标签名(全限定名) */ public void beginFunction(String name) { - addr.put(name, pc); // 记录当前地址为入口 - patchCallFixes(name); // 修补所有待该符号的 CALL - patchBranchFixes(name); // 修补所有待该符号的分支 + addr.put(name, pc); + patchCallFixes(name); + patchBranchFixes(name); } - /** - * 结束函数(当前实现为空,方便 API 统一)。 - */ - public void endFunction() { /* no-op */ } + /** 函数结尾的处理(占位,无需特殊处理)。 */ + public void endFunction() {} /** - * 写入一条 VM 指令或标签。 - *

    - *
  • 如果以冒号结尾,视为标签,仅登记其地址,不写入指令流,也不递增 pc。
  • - *
  • 否则写入实际指令,并自增 pc。
  • - *
- * @param line 一行 VM 指令文本或标签名(结尾有冒号) + * 添加一条指令或标签到代码列表。 + * + * @param line 指令字符串或标签字符串(若以冒号结尾为标签) */ public void emit(String line) { - if (line.endsWith(":")) { // 是标签定义行 + if (line.endsWith(":")) { + // 标签定义 String label = line.substring(0, line.length() - 1); - addr.put(label, pc); // 记录标签地址 - patchBranchFixes(label); // 修补所有以该标签为目标的分支指令 - return; // 标签行不写入 code,不递增 pc + addr.put(label, pc); + patchBranchFixes(label); + return; } - code.add(line); // 普通指令写入 code + code.add(line); pc++; } /** - * 生成 CALL 指令。 - * 支持延迟修补: 若目标已知,直接写入地址;否则写入占位并登记 fix-up。 - * @param target 目标函数名 + * 添加一条 CALL 指令,若目标未定义则延后修补。 + * + * @param target 目标函数全名 * @param nArgs 参数个数 */ public void emitCall(String target, int nArgs) { @@ -117,10 +117,10 @@ public final class VMProgramBuilder { } /** - * 生成分支(JUMP 或 IC_*)指令。 - * 支持延迟修补机制。 - * @param opcode 指令名 - * @param label 目标标签名 + * 添加一条分支指令(如 JMP/BR/BEQ),若目标未定义则延后修补。 + * + * @param opcode 指令操作码 + * @param label 跳转目标标签名 */ public void emitBranch(String opcode, String label) { Integer a = resolve(label); @@ -133,13 +133,12 @@ public final class VMProgramBuilder { } /** - * 构建最终 VM 代码文本列表。 - *
    - *
  • 若存在未解析符号(CALL 或分支),则抛出异常。
  • - *
  • 否则返回不可变指令流。
  • - *
- * @return 完整 VM 指令流 - * @throws IllegalStateException 若有未修补的符号引用 + * 完成代码生成,输出最终 VM 指令序列。 + *

+ * 如果存在未修补的调用或分支,将抛出异常。 + * + * @return 指令序列(不可变) + * @throws IllegalStateException 如果存在未修补符号 */ public List build() { if (!callFixes.isEmpty() || !branchFixes.isEmpty()) { @@ -151,27 +150,26 @@ public final class VMProgramBuilder { } /** - * 解析符号地址。若全限定名找不到则降级尝试简单名。 - * @param sym 符号名 - * @return 地址或 null(未定义) + * 解析符号地址,仅支持全名精准匹配。 + * + * @param sym 符号全名 + * @return 地址(指令序号),未找到返回 null */ private Integer resolve(String sym) { - Integer a = addr.get(sym); - if (a == null && sym.contains(".")) { - a = addr.get(sym.substring(sym.lastIndexOf('.') + 1)); - } - return a; + return addr.get(sym); } /** - * 修补所有以 name 为目标的 CALL 占位符。 - * @param name 新定义的函数名 + * 修补所有等待目标函数 name 的 CALL 指令。 + *

+ * 只支持全名精确修补,不做模糊查找或短名回退。 + * + * @param name 目标函数全名 */ private void patchCallFixes(String name) { for (Iterator it = callFixes.iterator(); it.hasNext();) { CallFix f = it.next(); - // 目标函数名完全匹配或后缀匹配(兼容全限定名) - if (f.target.equals(name) || f.target.endsWith("." + name)) { + if (f.target.equals(name)) { code.set(f.index, VMOpCode.CALL + " " + addr.get(name) + " " + f.nArgs); it.remove(); } @@ -179,8 +177,9 @@ public final class VMProgramBuilder { } /** - * 修补所有以 label 为目标的分支占位符。 - * @param label 新定义的标签名 + * 修补所有等待目标 label 的分支指令。 + * + * @param label 目标标签 */ private void patchBranchFixes(String label) { for (Iterator it = branchFixes.iterator(); it.hasNext();) { diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java index 58eccfc..eab2d75 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java @@ -157,7 +157,7 @@ public record ExpressionBuilder(IRContext ctx) { } /** - * 构建函数或方法调用表达式。 + * 构建函数或方法调用表达式。模块内未限定调用会自动补全当前模块名。 * * @param call AST 调用表达式节点 * @return 存储调用结果的虚拟寄存器 @@ -171,8 +171,18 @@ public record ExpressionBuilder(IRContext ctx) { // 成员方法调用,例如 obj.foo() case MemberExpressionNode m when m.object() instanceof IdentifierNode id -> id.name() + "." + m.member(); - // 普通函数调用 - case IdentifierNode id -> id.name(); + // 普通函数调用,如果未指定模块,自动补全当前模块名 + case IdentifierNode id -> { + String current = ctx.getFunction().name(); + int dot = current.lastIndexOf('.'); + if (dot > 0) { + // 当前处于模块内函数(Module.func),补全为同模块下的全限定名 + yield current.substring(0, dot) + "." + id.name(); + } else { + // 顶层/脚本函数等不含模块前缀,保持原样 + yield id.name(); + } + } // 其它情况暂不支持 default -> throw new IllegalStateException("不支持的调用目标: " + call.callee().getClass().getSimpleName()); }; diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java index dbde250..28e89c2 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java @@ -12,21 +12,19 @@ import java.util.ArrayList; import java.util.List; /** - * 本类负责将解析生成的 AST 根节点列表转换为可执行的 IRProgram。 - * - *

主要职责: + * IRProgramBuilder 负责将 AST 根节点(如模块、函数、顶层语句)转换为可执行的 IRProgram 实例。 + *

+ * 主要职责: *

    - *
  • 遍历输入的顶层节点,识别 ModuleNode、FunctionNode 及脚本式顶层 StatementNode;
  • - *
  • 对 ModuleNode 中的所有函数节点调用 FunctionBuilder 构建 IRFunction 并添加至 IRProgram;
  • - *
  • 对单独的 FunctionNode 节点直接构建并纳入 IRProgram;
  • - *
  • 对顶层脚本式 StatementNode 自动封装为名称固定的“_start”函数,再行构建并纳入 IRProgram;
  • - *
  • 对不支持的节点类型抛出 IllegalStateException,以确保编译流程严谨。
  • + *
  • 遍历 AST 根节点,根据类型分别处理(模块、函数、顶层语句)。
  • + *
  • 对模块内的函数添加全限定名,并在函数体前注入全局变量声明。
  • + *
  • 将单独的顶层语句封装为特殊的 "_start" 函数。
  • *
*/ public final class IRProgramBuilder { /** - * 构建完整的 IRProgram 实例。 + * 将解析生成的 AST 根节点列表转换为 IRProgram。 * * @param roots 含 ModuleNode、FunctionNode 或 StatementNode 的顶层 AST 根节点列表 * @return 包含所有转换后 IRFunction 的 IRProgram 对象 @@ -36,17 +34,20 @@ public final class IRProgramBuilder { IRProgram irProgram = new IRProgram(); for (Node node : roots) { switch (node) { - case ModuleNode moduleNode -> - // 对每个模块,所有函数均自动注入 globals - moduleNode.functions().forEach(f -> irProgram.add(buildFunctionWithGlobals(moduleNode, f))); + case ModuleNode moduleNode -> { + // 处理模块节点:遍历其中所有函数,统一用“模块名.函数名”作为全限定名 + for (FunctionNode f : moduleNode.functions()) { + irProgram.add(buildFunctionWithGlobals(moduleNode, f)); + } + } case FunctionNode functionNode -> - // 顶层函数节点: 直接构建并添加 + // 处理顶层函数节点:直接构建为 IRFunction 并加入 irProgram.add(buildFunction(functionNode)); case StatementNode statementNode -> - // 脚本式顶层语句: 封装为“_start”函数后构建并添加 + // 处理脚本式顶层语句:封装成 "_start" 函数后构建并添加 irProgram.add(buildFunction(wrapTopLevel(statementNode))); default -> - // 严格校验节点类型,遇不支持者立即失败 + // 遇到未知类型节点,抛出异常 throw new IllegalStateException("Unsupported top-level node: " + node); } } @@ -54,21 +55,27 @@ public final class IRProgramBuilder { } /** - * 构建带有模块全局声明“注入”的函数。 - * 为了在当前 IR 设计下能访问全局变量,将模块的 globals 作为前置声明 - * 追加到函数体最前面,使其在函数内被注册到 IR 作用域中。 + * 构建带有模块全局声明“注入”的函数,并将函数名加上模块前缀,保证模块内函数名唯一。 + *

+ * 如果模块有全局声明,则这些声明会被插入到函数体前部。 + * + * @param moduleNode 当前模块节点 + * @param functionNode 模块中的函数节点 + * @return 包含全局声明、已加前缀函数名的 IRFunction */ private IRFunction buildFunctionWithGlobals(ModuleNode moduleNode, FunctionNode functionNode) { + // 拼接模块名和函数名,生成全限定名 + String qualifiedName = moduleNode.name() + "." + functionNode.name(); + // 若无全局声明,仅重命名后直接构建 if (moduleNode.globals() == null || moduleNode.globals().isEmpty()) { - return buildFunction(functionNode); + return buildFunction(renameFunction(functionNode, qualifiedName)); } - // 重建函数体:先放 globals 的声明,再放原来的语句 + // 若有全局声明,插入到函数体最前面 List newBody = new ArrayList<>(moduleNode.globals().size() + functionNode.body().size()); newBody.addAll(moduleNode.globals()); newBody.addAll(functionNode.body()); - FunctionNode wrapped = new FunctionNode( - functionNode.name(), + qualifiedName, functionNode.parameters(), functionNode.returnType(), newBody, @@ -78,28 +85,39 @@ public final class IRProgramBuilder { } /** - * 利用 FunctionBuilder 将 FunctionNode 转换为 IRFunction。 + * 生成一个重命名的 FunctionNode(只修改函数名,其他属性保持不变)。 * - * @param functionNode 待构建的 AST FunctionNode - * @return 构建完成的 IRFunction 实例 + * @param fn 原始函数节点 + * @param newName 新的函数名(通常为全限定名) + * @return 重命名后的 FunctionNode + */ + private FunctionNode renameFunction(FunctionNode fn, String newName) { + return new FunctionNode( + newName, + fn.parameters(), + fn.returnType(), + fn.body(), + fn.context() + ); + } + + /** + * 构建 IRFunction。 + * + * @param functionNode 要转换的函数节点 + * @return 转换结果 IRFunction */ private IRFunction buildFunction(FunctionNode functionNode) { return new FunctionBuilder().build(functionNode); } /** - * 将单个脚本式顶层 StatementNode 封装为名称固定的“_start”函数节点。 + * 将顶层语句节点封装成特殊的 "_start" 函数。 + *

+ * 这对于脚本式文件支持至关重要(即文件最外层直接写语句)。 * - *

封装规则: - *

    - *
  • 函数名固定为“_start”;
  • - *
  • 返回类型设为 null,由后续流程处理;
  • - *
  • 参数列表为空;
  • - *
  • 函数主体仅包含传入的单条语句。
  • - *
- * - * @param stmt 待封装的顶层脚本语句节点 - * @return 生成的 FunctionNode,用于后续 IRFunction 构建 + * @param stmt 要封装的顶层语句 + * @return 包装成 FunctionNode 的 "_start" 函数 */ private FunctionNode wrapTopLevel(StatementNode stmt) { return new FunctionNode( From 2c3c4089f8aded9e1f66143910a8f05b1c222140 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:43:48 +0800 Subject: [PATCH 02/11] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=20Demo17=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=89=93=E5=8D=B0=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/Demo/Demo17/Main.snow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/Demo/Demo17/Main.snow b/playground/Demo/Demo17/Main.snow index 6171781..8c15d75 100644 --- a/playground/Demo/Demo17/Main.snow +++ b/playground/Demo/Demo17/Main.snow @@ -12,7 +12,7 @@ module: Main i = i + 1 body: if i % 2 == 0 then - print(i) + os.print(i) break end if end body From be8e57ef607a584708326e670878ca3852fe277a Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:43:55 +0800 Subject: [PATCH 03/11] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=20Demo16=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=89=93=E5=8D=B0=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/Demo/Demo16/Main.snow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/Demo/Demo16/Main.snow b/playground/Demo/Demo16/Main.snow index 0211f2d..4aa7b8d 100644 --- a/playground/Demo/Demo16/Main.snow +++ b/playground/Demo/Demo16/Main.snow @@ -12,7 +12,7 @@ module: Main i = i + 1 body: if i % 2 == 0 then - print(i) + os.print(i) end if end body end loop From 8e26b57cde3f23ed51f8ac4ef0071da2c9b5d031 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:44:01 +0800 Subject: [PATCH 04/11] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=20Demo15=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=89=93=E5=8D=B0=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/Demo/Demo15/Main.snow | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/playground/Demo/Demo15/Main.snow b/playground/Demo/Demo15/Main.snow index df8dc63..65533fe 100644 --- a/playground/Demo/Demo15/Main.snow +++ b/playground/Demo/Demo15/Main.snow @@ -1,13 +1,20 @@ module: Main import: os globals: - declare num1:int=10 declare num2:int=10 function: main return_type: void body: declare num1:int=11 - print(num1+num2) + os.print(num1+num2+abc()) end body end function + + function: abc + return_type: int + body: + return 1 + end body + end function + end module \ No newline at end of file From 156f2b76c40a3b805edb5843bd9ad8e177b3becf Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:44:05 +0800 Subject: [PATCH 05/11] =?UTF-8?q?test:=20=E4=BF=AE=E6=94=B9=20Demo14=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E6=89=93=E5=8D=B0=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/Demo/Demo14/Main.snow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/Demo/Demo14/Main.snow b/playground/Demo/Demo14/Main.snow index 7ef2b05..7bb005a 100644 --- a/playground/Demo/Demo14/Main.snow +++ b/playground/Demo/Demo14/Main.snow @@ -3,7 +3,7 @@ module: Main function: main return_type: void body: - print(222) + os.print(222) end body end function end module \ No newline at end of file From 1d73fc298e49d92760074da70b050dcbd3fda3f7 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:44:33 +0800 Subject: [PATCH 06/11] =?UTF-8?q?test:=20=E6=B7=BB=E5=8A=A0=20Bug4=20?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/BugFarm/Bug4/Main.snow | 9 +++++++++ playground/BugFarm/Bug4/a.snow | 8 ++++++++ playground/BugFarm/Bug4/b.snow | 9 +++++++++ 3 files changed, 26 insertions(+) create mode 100644 playground/BugFarm/Bug4/Main.snow create mode 100644 playground/BugFarm/Bug4/a.snow create mode 100644 playground/BugFarm/Bug4/b.snow diff --git a/playground/BugFarm/Bug4/Main.snow b/playground/BugFarm/Bug4/Main.snow new file mode 100644 index 0000000..0efa4b1 --- /dev/null +++ b/playground/BugFarm/Bug4/Main.snow @@ -0,0 +1,9 @@ +module: Main + import: ModuleB + function: main + return_type: int + body: + return ModuleB.fun() + end body + end function +end module diff --git a/playground/BugFarm/Bug4/a.snow b/playground/BugFarm/Bug4/a.snow new file mode 100644 index 0000000..d717032 --- /dev/null +++ b/playground/BugFarm/Bug4/a.snow @@ -0,0 +1,8 @@ +module: ModuleA + function: fun + return_type: int + body: + return 123 + end body + end function +end module \ No newline at end of file diff --git a/playground/BugFarm/Bug4/b.snow b/playground/BugFarm/Bug4/b.snow new file mode 100644 index 0000000..4db51a0 --- /dev/null +++ b/playground/BugFarm/Bug4/b.snow @@ -0,0 +1,9 @@ +module: ModuleB + import: ModuleA + function: fun + return_type: int + body: + return ModuleA.fun() + ModuleA.fun() + end body + end function +end module \ No newline at end of file From 1cb5951e6893ebfb0a7cdccce6cfc523d39c9105 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:45:49 +0800 Subject: [PATCH 07/11] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=20Bug4=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .run/Bug4.run.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .run/Bug4.run.xml diff --git a/.run/Bug4.run.xml b/.run/Bug4.run.xml new file mode 100644 index 0000000..d10e3f5 --- /dev/null +++ b/.run/Bug4.run.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file From 466b6ca2bec63c90798b878c7700237759e5223a Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 12:48:10 +0800 Subject: [PATCH 08/11] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=20VMCodeGe?= =?UTF-8?q?nerator=20=E4=B8=AD=E7=9A=84=E5=86=97=E4=BD=99=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除了 VMCodeGenerator 类中不再使用的 currentFn 字段- 将 currentFn 作为局部变量在 generate 方法中使用 - 这个改动简化了类的结构,减少了冗余代码 --- .../snow/compiler/backend/builder/VMCodeGenerator.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java index 98c490d..e764e41 100644 --- a/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java +++ b/src/main/java/org/jcnc/snow/compiler/backend/builder/VMCodeGenerator.java @@ -35,12 +35,6 @@ public final class VMCodeGenerator { */ private final VMProgramBuilder out; - /** - * 当前正在处理的函数名。 - * 用于区分是否为 main 函数等用途。 - */ - private String currentFn; - /** * 构造 VMCodeGenerator。 * @@ -72,7 +66,7 @@ public final class VMCodeGenerator { * @throws IllegalStateException 如果遇到不支持的 IR 指令类型 */ public void generate(IRFunction fn) { - this.currentFn = fn.name(); + String currentFn = fn.name(); out.beginFunction(currentFn); for (IRInstruction ins : fn.body()) { @SuppressWarnings("unchecked") From b7e9c8121ec025222196bd805d1356c011abc1b1 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 14:11:09 +0800 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20RetComma?= =?UTF-8?q?nd=20=E5=B9=B6=E6=B7=BB=E5=8A=A0=E6=97=A5=E5=BF=97=E8=AE=B0?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新导入语句,明确导入模块 - 使用 LoggingUtils 替代 System.out.println 输出日志 - 添加换行符改善日志可读性 --- .../jcnc/snow/vm/commands/flow/control/RetCommand.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java index c31ec96..90cd8ae 100644 --- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java +++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java @@ -1,7 +1,11 @@ package org.jcnc.snow.vm.commands.flow.control; import org.jcnc.snow.vm.interfaces.Command; -import org.jcnc.snow.vm.module.*; +import org.jcnc.snow.vm.module.CallStack; +import org.jcnc.snow.vm.module.LocalVariableStore; +import org.jcnc.snow.vm.module.OperandStack; +import org.jcnc.snow.vm.module.StackFrame; +import org.jcnc.snow.vm.utils.LoggingUtils; import static org.jcnc.snow.common.SnowConfig.print; @@ -37,7 +41,7 @@ public class RetCommand implements Command { /* ----- Root frame: do NOT pop, just end program ----- */ if (topFrame.getReturnAddress() == PROGRAM_END) { - System.out.println("Return "); + LoggingUtils.logInfo("", "\nReturn "); return PROGRAM_END; // VM main loop should break } From e1a7f3310cc84555260ba4e4d68e8e92f87d5590 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 14:17:28 +0800 Subject: [PATCH 10/11] =?UTF-8?q?test:=20=E6=B7=BB=E5=8A=A0=20Bug5=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E8=BF=9B=E8=A1=8C=E6=93=8D=E4=BD=9C=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E4=BA=A4=E4=BA=92=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/BugFarm/Bug5/Main.snow | 16 ++++++++++++++++ playground/BugFarm/Bug5/OS.snow | 11 +++++++++++ 2 files changed, 27 insertions(+) create mode 100644 playground/BugFarm/Bug5/Main.snow create mode 100644 playground/BugFarm/Bug5/OS.snow diff --git a/playground/BugFarm/Bug5/Main.snow b/playground/BugFarm/Bug5/Main.snow new file mode 100644 index 0000000..89c6c84 --- /dev/null +++ b/playground/BugFarm/Bug5/Main.snow @@ -0,0 +1,16 @@ +module: Main + import: os + globals: + declare sum: int = 0 + function: main + parameter: + return_type: int + body: + sum = 20 + + os.print(sum) + + return 0 + end body + end function +end module \ No newline at end of file diff --git a/playground/BugFarm/Bug5/OS.snow b/playground/BugFarm/Bug5/OS.snow new file mode 100644 index 0000000..6026d43 --- /dev/null +++ b/playground/BugFarm/Bug5/OS.snow @@ -0,0 +1,11 @@ +module: os + import: os + function: print + parameter: + declare i1: int + return_type: void + body: + syscall("PRINT",i1) + end body + end function +end module \ No newline at end of file From d77368bb13fdd195a6ad72b90b4d123f86803ea0 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 31 Jul 2025 14:17:46 +0800 Subject: [PATCH 11/11] =?UTF-8?q?chore:=20=E6=B7=BB=E5=8A=A0=20Bug5=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .run/Bug5.run.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .run/Bug5.run.xml diff --git a/.run/Bug5.run.xml b/.run/Bug5.run.xml new file mode 100644 index 0000000..054f0b9 --- /dev/null +++ b/.run/Bug5.run.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file