diff --git a/playground/BugFarm/Bug1/Main.snow b/playground/BugFarm/Bug1/Main.snow
index 134096c..cc9117d 100644
--- a/playground/BugFarm/Bug1/Main.snow
+++ b/playground/BugFarm/Bug1/Main.snow
@@ -9,13 +9,9 @@ module: Main
end function
function: foo
- return_type: int
+ return_type: void
body:
- if false then
- return 1
- end if
- return 0
end body
end function
end module
\ No newline at end of file
diff --git a/playground/BugFarm/Bug1/README.md b/playground/BugFarm/Bug1/README.md
deleted file mode 100644
index b34d14d..0000000
--- a/playground/BugFarm/Bug1/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-## 编译器输出
-### Snow 源代码
-#### Main.snow
-```snow
-function: main
- return_type: int
- body:
- 3 L
- return 65537
- end body
-end function
-```
\ No newline at end of file
diff --git a/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java b/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java
index d3a7b80..84fe8cf 100644
--- a/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java
+++ b/src/main/java/org/jcnc/snow/compiler/backend/generator/CallGenerator.java
@@ -3,74 +3,56 @@ package org.jcnc.snow.compiler.backend.generator;
import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder;
import org.jcnc.snow.compiler.backend.core.InstructionGenerator;
import org.jcnc.snow.compiler.backend.utils.OpHelper;
+import org.jcnc.snow.compiler.ir.common.GlobalFunctionTable;
import org.jcnc.snow.compiler.ir.instruction.CallInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Map;
/**
- * 函数调用指令生成器。
- *
- * 该类实现了函数调用(CallInstruction)的指令翻译逻辑,
- * 负责将 IR 层的函数调用转换为虚拟机可执行的低级指令。
+ * 将 IR CallInstruction 生成 VM 指令
*/
public class CallGenerator implements InstructionGenerator {
- /**
- * 返回本指令生成器支持的 IR 指令类型(CallInstruction)。
- *
- * @return 指令类型的 Class 对象
- */
@Override
public Class supportedClass() {
return CallInstruction.class;
}
- /**
- * 生成函数调用相关的虚拟机指令。
- *
- * 步骤如下:
- *
- * - 预测返回值类型(采用首个实参槽的类型作为近似)
- * - 为每个参数根据实际类型发出加载指令
- * - 生成 CALL 调用指令
- * - 将返回值存储到目标槽,并记录类型信息
- *
- *
- * @param ins 待翻译的 CallInstruction 指令对象
- * @param out 指令输出与类型槽管理器
- * @param slotMap IR 寄存器到槽号的映射
- * @param currentFn 当前函数名(未用,可用于递归/闭包等复杂场景)
- */
@Override
public void generate(CallInstruction ins,
VMProgramBuilder out,
Map slotMap,
String currentFn) {
- // —— 1. 预测返回值类型(用首个实参槽类型作为近似推断) ——
- char retType = 'I'; // 默认整型
+ /* 1. 推断返回值类型(用于非 void 情况下的 I/F/D/L_STORE) */
+ char retType = 'I';
if (!ins.getArguments().isEmpty()) {
int firstSlot = slotMap.get((IRVirtualRegister) ins.getArguments().getFirst());
- retType = out.getSlotType(firstSlot); // 获取槽位实际类型
- if (retType == '\0') retType = 'I'; // 默认整型
+ retType = out.getSlotType(firstSlot);
+ if (retType == '\0') retType = 'I';
}
- // —— 2. 按真实类型加载每个参数到虚拟机操作栈 ——
+ /* 2. 依次加载实参 */
for (var arg : ins.getArguments()) {
- int slotId = slotMap.get((IRVirtualRegister) arg); // 获取参数槽号
- char t = out.getSlotType(slotId); // 获取参数类型
- if (t == '\0') t = 'I'; // 类型未知时默认整型
- // 生成类型相关的加载指令,如 I_LOAD、F_LOAD 等
+ int slotId = slotMap.get((IRVirtualRegister) arg);
+ char t = out.getSlotType(slotId);
+ if (t == '\0') t = 'I';
out.emit(OpHelper.opcode(t + "_LOAD") + " " + slotId);
}
- // —— 3. 生成 CALL 调用指令 ——
+ /* 3. 发出 CALL 指令 */
out.emitCall(ins.getFunctionName(), ins.getArguments().size());
- // —— 4. 将返回值存入目标槽,并记录槽的类型 ——
- int destSlot = slotMap.get(ins.getDest()); // 目标寄存器槽
+ /* 3.5 若被调用函数返回 void,则无需保存返回值 */
+ String rt = GlobalFunctionTable.getReturnType(ins.getFunctionName());
+ if ("void".equals(rt)) {
+ return; // 直接结束,无 _STORE
+ }
+
+ /* 4. 保存返回值到目标槽 */
+ int destSlot = slotMap.get(ins.getDest());
out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot);
- out.setSlotType(destSlot, retType); // 标记返回值类型
+ out.setSlotType(destSlot, retType);
}
}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java
index 48b10e7..c9f4fd5 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/FunctionBuilder.java
@@ -1,5 +1,6 @@
package org.jcnc.snow.compiler.ir.builder;
+import org.jcnc.snow.compiler.ir.common.GlobalFunctionTable;
import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.ir.utils.ExpressionUtils;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
@@ -32,6 +33,10 @@ public class FunctionBuilder {
*/
public IRFunction build(FunctionNode functionNode) {
+ // 在全局函数表中注册函数信息
+ GlobalFunctionTable.register(functionNode.name(), functionNode.returnType());
+
+
// 0) 基本初始化:创建 IRFunction 实例与对应上下文
IRFunction irFunction = new IRFunction(functionNode.name());
IRContext irContext = new IRContext(irFunction);
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/common/GlobalFunctionTable.java b/src/main/java/org/jcnc/snow/compiler/ir/common/GlobalFunctionTable.java
new file mode 100644
index 0000000..db6502c
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/compiler/ir/common/GlobalFunctionTable.java
@@ -0,0 +1,76 @@
+package org.jcnc.snow.compiler.ir.common;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 全局函数返回类型表。
+ *
+ * 此工具类用于在编译前端构建每个函数 IR(中间表示)时登记函数的返回类型,
+ * 以便后端在生成 {@code CALL} 指令时判断是否需要保存返回值。
+ *
+ *
+ * 使用说明
+ *
+ * - 在函数 IR 构建阶段,调用 {@link #register(String, String)} 方法登记函数名与返回类型。
+ * - 在生成调用指令阶段,通过 {@link #getReturnType(String)} 查询函数的返回类型。
+ * - 返回类型统一为小写;若调用 {@code register} 时传入的返回类型为 {@code null},则登记为 {@code "void"}。
+ *
+ */
+public final class GlobalFunctionTable {
+
+ /**
+ * 存储全局函数返回类型映射表。
+ *
+ * - Key:函数名(不含模块限定)
+ * - Value:返回类型,统一转换为小写字符串;若无返回值则为 {@code "void"}
+ *
+ */
+ private static final Map RETURN_TYPES = new ConcurrentHashMap<>();
+
+ /**
+ * 私有构造函数,防止实例化。
+ */
+ private GlobalFunctionTable() {
+ // 工具类,禁止实例化
+ }
+
+ /**
+ * 登记或更新指定函数的返回类型。
+ *
+ * 若传入的 {@code returnType} 为 {@code null},则登记为 {@code "void"}。
+ * 否则将去除前后空白并转换为小写后登记。
+ *
+ * @param name 函数名(不含模块限定)
+ * @param returnType 函数返回类型字符串,如 {@code "int"}、{@code "String"}。
+ * 如果为 {@code null},则登记类型为 {@code "void"}。
+ * @throws IllegalArgumentException 如果 {@code name} 为空或 {@code null}
+ */
+ public static void register(String name, String returnType) {
+ if (name == null || name.trim().isEmpty()) {
+ throw new IllegalArgumentException("函数名不能为空或 null");
+ }
+ RETURN_TYPES.put(
+ name,
+ returnType == null
+ ? "void"
+ : returnType.trim().toLowerCase()
+ );
+ }
+
+ /**
+ * 查询指定函数的返回类型。
+ *
+ * 返回类型为登记时的值(小写),如果函数未登记过,则返回 {@code null}。
+ *
+ * @param name 函数名(不含模块限定)
+ * @return 已登记的返回类型(小写),或 {@code null} 表示未知
+ * @throws IllegalArgumentException 如果 {@code name} 为空或 {@code null}
+ */
+ public static String getReturnType(String name) {
+ if (name == null || name.trim().isEmpty()) {
+ throw new IllegalArgumentException("函数名不能为空或 null");
+ }
+ return RETURN_TYPES.get(name);
+ }
+}
diff --git a/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
index 7e9f152..13db658 100644
--- a/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
+++ b/src/main/java/org/jcnc/snow/compiler/ir/instruction/CallInstruction.java
@@ -1,41 +1,63 @@
package org.jcnc.snow.compiler.ir.instruction;
+import org.jcnc.snow.compiler.ir.common.GlobalFunctionTable;
import org.jcnc.snow.compiler.ir.core.IRInstruction;
import org.jcnc.snow.compiler.ir.core.IROpCode;
+import org.jcnc.snow.compiler.ir.core.IRValue;
import org.jcnc.snow.compiler.ir.core.IRVisitor;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
-import org.jcnc.snow.compiler.ir.core.IRValue;
import java.util.ArrayList;
import java.util.List;
/**
- * CallInstruction —— 表示一次函数调用,格式:dest = CALL functionName, arg1, arg2, ...
+ * CallInstruction —— 表示一次函数调用的中间代码指令
+ *
+ * dest = CALL foo, arg1, arg2, ...
+ *
+ * 若被调函数返回 void,则 {@code dest} 可以为 {@code null},
+ * 并且不会参与寄存器分配。
*/
public class CallInstruction extends IRInstruction {
+ /** 调用结果目标寄存器;void 返回时可为 null */
private final IRVirtualRegister dest;
+ /** 被调用的函数名(含模块限定) */
private final String functionName;
+ /** 实参列表 */
private final List arguments;
- public CallInstruction(IRVirtualRegister dest, String functionName, List args) {
+ public CallInstruction(IRVirtualRegister dest,
+ String functionName,
+ List args) {
this.dest = dest;
this.functionName = functionName;
this.arguments = List.copyOf(args);
}
+ // === 基本信息 ===
@Override
public IROpCode op() {
return IROpCode.CALL;
}
+ /** 仅在函数有返回值时才暴露目标寄存器 */
+ @Override
+ public IRVirtualRegister dest() {
+ return isVoidReturn() ? null : dest;
+ }
+
+ /** 操作数列表:void 调用不包含 dest */
@Override
public List operands() {
List ops = new ArrayList<>();
- ops.add(dest);
+ if (!isVoidReturn() && dest != null) {
+ ops.add(dest);
+ }
ops.addAll(arguments);
return ops;
}
+ // === Getter ===
public IRVirtualRegister getDest() {
return dest;
}
@@ -48,14 +70,26 @@ public class CallInstruction extends IRInstruction {
return arguments;
}
+ // === 帮助方法 ===
+ /** 判断被调函数是否返回 void */
+ private boolean isVoidReturn() {
+ return "void".equals(GlobalFunctionTable.getReturnType(functionName));
+ }
+
+ // === 访客模式 ===
@Override
public void accept(IRVisitor visitor) {
visitor.visit(this);
}
+ // === 字符串表示 ===
@Override
public String toString() {
- StringBuilder sb = new StringBuilder(dest + " = CALL " + functionName);
+ StringBuilder sb = new StringBuilder();
+ if (!isVoidReturn() && dest != null) {
+ sb.append(dest).append(" = ");
+ }
+ sb.append("CALL ").append(functionName);
for (IRValue arg : arguments) {
sb.append(", ").append(arg);
}