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 2fb428f..2aed3a5 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
@@ -12,14 +12,15 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
/**
* IR 函数构建器。
*
- * 负责将语法树中的 FunctionNode 节点转化为可执行的 IRFunction,
- * 包含参数声明、返回类型推断、函数体语句转换等步骤。
- *
+ * 将语法树中的 {@link FunctionNode} 转换为可执行的 {@link IRFunction},包含:
*
- * - 支持自动导入全局/跨模块常量,使跨模块常量引用(如 ModuleA.a)在 IR 阶段可用。
- * - 将函数形参声明为虚拟寄存器,并注册到作用域,便于后续指令生成。
- * - 根据返回类型设置表达式默认字面量类型,保证 IR 层类型一致性。
- * - 遍历并转换函数体语句为 IR 指令。
+ * - 在全局函数表登记函数名与返回类型;
+ * - 初始化 IR 容器与构建上下文(作用域、寄存器池等);
+ * - 导入全局/跨模块常量,便于常量折叠与跨模块引用;
+ * - 依据返回类型为表达式设置数字字面量默认后缀;
+ * - 分配形参寄存器并注册到作用域与 IR 函数;
+ * - 将函数体语句逐条转为 IR 指令;
+ * - 在构建完成后清理默认字面量后缀,避免泄漏到其它函数。
*
*/
public class FunctionBuilder {
@@ -44,57 +45,56 @@ public class FunctionBuilder {
* @return 构建得到的 IRFunction 对象
*/
public IRFunction build(FunctionNode functionNode) {
-
- // 1. 在全局函数表注册函数名与返回类型
- // 方便其他阶段/模块调用、类型检查。
+ // 1) 在全局函数表登记:名称 + 返回类型(返回类型可能为 null,例如构造函数 init)
GlobalFunctionTable.register(functionNode.name(), functionNode.returnType());
- // 2. 初始化 IRFunction 实例与上下文对象
- // IRFunction: 表示该函数的中间代码容器
- // IRContext: 负责作用域、寄存器分配等编译上下文管理
+ // 2) 初始化 IR 容器与上下文
IRFunction irFunction = new IRFunction(functionNode.name());
IRContext irContext = new IRContext(irFunction);
- // 3. 自动导入所有全局/跨模块常量到当前作用域
- // 支持如 ModuleA.a 这样的常量访问/折叠(参见 ExpressionBuilder)
+ // 3) 导入所有全局/跨模块常量到当前作用域(便于常量折叠和跨模块引用)
GlobalConstTable.all().forEach((k, v) ->
irContext.getScope().importExternalConst(k, v));
- // 4. 根据函数返回类型设置默认类型后缀
- // 例如返回类型为 double 时, 字面量表达式自动用 d 后缀。
- char _returnSuffix = switch (functionNode.returnType().toLowerCase()) {
+ // 4) 根据函数返回类型设置“数字字面量默认后缀”
+ // - 关键修复:对 returnType 进行空值/空白保护,缺省视为 "void"
+ String rt = functionNode.returnType();
+ String rtLower = (rt == null || rt.trim().isEmpty()) ? "void" : rt.trim().toLowerCase();
+
+ // 根据返回类型决定默认字面量后缀
+ // 仅在浮点/整型长短类型上设置;其它/void 情况不设置(使用 '\0' 表示不设置)
+ char defaultSuffix = switch (rtLower) {
case "double" -> 'd';
case "float" -> 'f';
case "long" -> 'l';
case "short" -> 's';
case "byte" -> 'b';
- default -> '\0'; // 其它类型不设默认后缀
+ default -> '\0';
};
- ExpressionUtils.setDefaultSuffix(_returnSuffix);
+ ExpressionUtils.setDefaultSuffix(defaultSuffix);
try {
- // 5. 遍历函数参数列表
- // - 为每个参数分配一个新的虚拟寄存器
- // - 注册参数名、类型、寄存器到当前作用域
- // - 添加参数寄存器到 IRFunction(用于后续调用与指令生成)
+ // 5) 处理形参:
+ // - 为每个形参分配一个新的虚拟寄存器(从 IRContext 统一分配,保证作用域一致)
+ // - 将 (参数名, 类型, 寄存器) 声明到当前作用域
+ // - 将寄存器加入 IRFunction 的参数列表,便于后续调用/生成
for (ParameterNode p : functionNode.parameters()) {
- IRVirtualRegister reg = irFunction.newRegister();
+ IRVirtualRegister reg = irContext.newRegister(); // 使用上下文统一分配
irContext.getScope().declare(p.name(), p.type(), reg);
irFunction.addParameter(reg);
}
- // 6. 遍历函数体语句节点,转换为 IR 指令
- // StatementBuilder 负责将每条语句递归转换为 IR
+ // 6) 构建函数体:将每条语句节点转换为 IR 指令序列
StatementBuilder stmtBuilder = new StatementBuilder(irContext);
for (StatementNode stmt : functionNode.body()) {
stmtBuilder.build(stmt);
}
} finally {
- // 7. 清理默认类型后缀,防止影响后续其他函数的类型推断
+ // 7) 清理默认后缀,防止影响后续函数的字面量推断
ExpressionUtils.clearDefaultSuffix();
}
- // 8. 返回构建完成的 IRFunction
+ // 8) 返回构建完成的 IRFunction
return irFunction;
}
}