From ee9e56c4798ea7203252eb98ce6fcf1ae73916eb Mon Sep 17 00:00:00 2001 From: zhangxun <1958638841@qq.com> Date: Tue, 17 Jun 2025 21:28:19 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8F=98=E9=87=8F=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=8F=97=E5=8F=B3=E5=80=BC=E7=B1=BB=E5=9E=8B=E5=BD=B1?= =?UTF-8?q?=E5=93=8D=E8=80=8C=E9=99=8D=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ir/builder/ExpressionBuilder.java | 4 +-- .../compiler/ir/builder/FunctionBuilder.java | 2 +- .../compiler/ir/builder/IRBuilderScope.java | 26 +++++++++++++-- .../snow/compiler/ir/builder/IRContext.java | 33 +++++++++++++++++++ .../ir/builder/InstructionFactory.java | 4 +-- .../compiler/ir/builder/StatementBuilder.java | 29 +++++++++++++--- .../compiler/ir/utils/ExpressionUtils.java | 20 +++++++++-- 7 files changed, 104 insertions(+), 14 deletions(-) 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 11288ba..1b5afaf 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 @@ -109,7 +109,7 @@ public record ExpressionBuilder(IRContext ctx) { switch (node) { // 数字字面量,直接加载到目标寄存器 case NumberLiteralNode n -> - InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.parseIntSafely(n.value())); + InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value())); // 标识符,查找并move到目标寄存器 case IdentifierNode id -> { IRVirtualRegister src = ctx.getScope().lookup(id.name()); @@ -207,7 +207,7 @@ public record ExpressionBuilder(IRContext ctx) { * @return 存放该常量的寄存器 */ private IRVirtualRegister buildNumberLiteral(String value) { - IRConstant constant = ExpressionUtils.buildNumberConstant(value); + IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value); IRVirtualRegister reg = ctx.newRegister(); ctx.addInstruction(new LoadConstInstruction(reg, constant)); return reg; 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 cc14557..48b10e7 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 @@ -51,7 +51,7 @@ public class FunctionBuilder { // 2) 声明形参:为每个参数分配虚拟寄存器并声明到作用域 for (ParameterNode p : functionNode.parameters()) { IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器 - irContext.getScope().declare(p.name(), reg); // 变量名→寄存器绑定 + irContext.getScope().declare(p.name(), p.type(), reg); // 变量名→寄存器绑定 irFunction.addParameter(reg); // 添加到函数参数列表 } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java index 168eac2..e0fd4cf 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRBuilderScope.java @@ -24,6 +24,13 @@ final class IRBuilderScope { */ private final Map vars = new HashMap<>(); + /** + * 存储变量名到对应类型的映射。 + *
+ * 变量名为键,变量类型为值,用于变量类型提升。 + */ + private final Map varTypes = new HashMap<>(); + /** * 当前作用域所绑定的 IRFunction 对象,用于申请新的虚拟寄存器。 */ @@ -44,10 +51,12 @@ final class IRBuilderScope { * 调用绑定的 IRFunction.newRegister() 生成寄存器后保存到映射表中。 * * @param name 变量名称,作为映射键使用 + * @param type 变量类型 */ - void declare(String name) { + void declare(String name, String type) { IRVirtualRegister reg = fn.newRegister(); vars.put(name, reg); + varTypes.put(name, type); } /** @@ -55,10 +64,12 @@ final class IRBuilderScope { * 该方法可用于将外部或前一作用域的寄存器导入到本作用域。 * * @param name 变量名称,作为映射键使用 + * @param type 变量类型 * @param reg 要绑定到该名称的 IRVirtualRegister 实例 */ - void declare(String name, IRVirtualRegister reg) { + void declare(String name, String type, IRVirtualRegister reg) { vars.put(name, reg); + varTypes.put(name, type); } /** @@ -82,4 +93,15 @@ final class IRBuilderScope { IRVirtualRegister lookup(String name) { return vars.get(name); } + + /** + * 根据变量名称在当前作用域中查找对应的类型。 + * + * @param name 需要查询的变量名称 + * @return 如果该名称已声明,则返回对应的类型 + * 如果未声明,则返回 null + */ + String lookupType(String name) { + return varTypes.get(name); + } } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java index 4c5078d..2407bf5 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRContext.java @@ -4,6 +4,8 @@ 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.Optional; + /** * IRContext 类负责封装当前正在构建的 IRFunction 实例 * 以及与之配套的作用域管理(IRBuilderScope), @@ -31,6 +33,11 @@ public class IRContext { */ private final IRBuilderScope scope; + /** + * 当前声明变量的类型,不在声明变量时为空 + */ + private Optional var_type; + /** * 构造一个新的 IRContext,并将指定的 IRFunction 与作用域关联。 * @@ -41,6 +48,7 @@ public class IRContext { this.scope = new IRBuilderScope(); // 关联作用域与 IRFunction,以便在声明变量时申请寄存器 this.scope.attachFunction(function); + this.var_type = Optional.empty(); } /** @@ -85,4 +93,29 @@ public class IRContext { public String newLabel() { return "L" + (labelCounter++); } + + /** + * 获取当前 declare 编译阶段变量类型 + * + * @return 当前 declare 的变量类型 + */ + public Optional getVarType() { + return var_type; + } + + /** + * 设置当前 declare 编译阶段变量类型 + * + */ + public void setVarType(String type) { + this.var_type = Optional.of(type); + } + + /** + * 清除当前 declare 编译阶段变量类型 + * + */ + public void clearVarType() { + this.var_type = Optional.empty(); + } } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java index 9b7a467..6c5881a 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/InstructionFactory.java @@ -58,8 +58,8 @@ public class InstructionFactory { * @param dest 目标寄存器 * @param value 要加载的整数常量 */ - public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, int value) { - ctx.addInstruction(new LoadConstInstruction(dest, new IRConstant(value))); + public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, IRConstant value) { + ctx.addInstruction(new LoadConstInstruction(dest, value)); } /** diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java index 8a95ca5..9661650 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/StatementBuilder.java @@ -55,19 +55,37 @@ public class StatementBuilder { } if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) { // 赋值语句,如 a = b + 1; - IRVirtualRegister target = getOrDeclareRegister(var); + + final String type = ctx.getScope().lookupType(var); + + // 1. 设置声明变量的类型 + ctx.setVarType(type); + + IRVirtualRegister target = getOrDeclareRegister(var, type); expr.buildInto(rhs, target); + + // 2. 清除变量声明 + ctx.clearVarType(); + return; } if (stmt instanceof DeclarationNode decl) { // 变量声明,如 int a = 1; if (decl.getInitializer().isPresent()) { // 声明同时有初值 + + // 1. 设置声明变量的类型 + ctx.setVarType(decl.getType()); + IRVirtualRegister r = expr.build(decl.getInitializer().get()); - ctx.getScope().declare(decl.getName(), r); + + // 2. 清除变量声明 + ctx.clearVarType(); + + ctx.getScope().declare(decl.getName(), decl.getType(), r); } else { // 仅声明,无初值 - ctx.getScope().declare(decl.getName()); + ctx.getScope().declare(decl.getName(), decl.getType()); } return; } @@ -92,11 +110,12 @@ public class StatementBuilder { * @param name 变量名 * @return 变量对应的虚拟寄存器 */ - private IRVirtualRegister getOrDeclareRegister(String name) { + private IRVirtualRegister getOrDeclareRegister(String name, String type) { IRVirtualRegister reg = ctx.getScope().lookup(name); if (reg == null) { reg = ctx.newRegister(); - ctx.getScope().declare(name, reg); + ctx.getScope().declare(name, type, reg); + throw new IllegalStateException("这里是怎么到达?"); } return reg; } diff --git a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java index 91155df..15a7407 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/utils/ExpressionUtils.java @@ -1,5 +1,6 @@ package org.jcnc.snow.compiler.ir.utils; +import org.jcnc.snow.compiler.ir.builder.IRContext; import org.jcnc.snow.compiler.ir.core.IROpCode; import org.jcnc.snow.compiler.ir.core.IROpCodeMappings; import org.jcnc.snow.compiler.ir.value.IRConstant; @@ -56,14 +57,29 @@ public class ExpressionUtils { * 根据数字字面量字符串自动判断类型,生成对应类型的 IRConstant。 * 支持 b/s/l/f/d 类型后缀与浮点格式,自动分配合适类型。 * + * @param ctx IR 编译上下文环境 * @param value 字面量字符串(如 "1", "2l", "3.14f", "5D") * @return 生成的 IRConstant 对象,包含正确类型 */ - public static IRConstant buildNumberConstant(String value) { + public static IRConstant buildNumberConstant(IRContext ctx, String value) { char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1)); String digits = switch (suffix) { case 'b','s','l','f','d' -> value.substring(0, value.length() - 1); - default -> value; + default -> { + if (ctx.getVarType().isPresent()) { + final var receiverType = ctx.getVarType().get(); + switch (receiverType) { + case "byte" -> suffix = 'b'; + case "short" -> suffix = 's'; + case "int" -> suffix = 'i'; + case "long" -> suffix = 'l'; + case "float" -> suffix = 'f'; + case "double" -> suffix = 'd'; + } + } + + yield value; + } }; // 根据类型后缀或数值格式创建常量 return switch (suffix) {