refactor: 重构 FunctionBuilder
- 优化了 FunctionBuilder 类的文档注释,详细描述了其功能和处理流程 - 改进了 build 方法的内部逻辑,提高了代码可读性和可维护性 - 修复了返回类型为空时的处理逻辑,增加了鲁棒性 - 优化了默认字面量后缀的设置逻辑,提高了代码的灵活性
This commit is contained in:
parent
db720ea357
commit
cff45a9d17
@ -12,14 +12,15 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||
/**
|
||||
* IR 函数构建器。
|
||||
* <p>
|
||||
* 负责将语法树中的 FunctionNode 节点转化为可执行的 IRFunction,
|
||||
* 包含参数声明、返回类型推断、函数体语句转换等步骤。
|
||||
*
|
||||
* 将语法树中的 {@link FunctionNode} 转换为可执行的 {@link IRFunction},包含:
|
||||
* <ul>
|
||||
* <li>支持自动导入全局/跨模块常量,使跨模块常量引用(如 ModuleA.a)在 IR 阶段可用。</li>
|
||||
* <li>将函数形参声明为虚拟寄存器,并注册到作用域,便于后续指令生成。</li>
|
||||
* <li>根据返回类型设置表达式默认字面量类型,保证 IR 层类型一致性。</li>
|
||||
* <li>遍历并转换函数体语句为 IR 指令。</li>
|
||||
* <li>在全局函数表登记函数名与返回类型;</li>
|
||||
* <li>初始化 IR 容器与构建上下文(作用域、寄存器池等);</li>
|
||||
* <li>导入全局/跨模块常量,便于常量折叠与跨模块引用;</li>
|
||||
* <li>依据返回类型为表达式设置数字字面量默认后缀;</li>
|
||||
* <li>分配形参寄存器并注册到作用域与 IR 函数;</li>
|
||||
* <li>将函数体语句逐条转为 IR 指令;</li>
|
||||
* <li>在构建完成后清理默认字面量后缀,避免泄漏到其它函数。</li>
|
||||
* </ul>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user