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},包含: *

*/ 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; } }