fix: 变量的类型受右值类型影响而降级

This commit is contained in:
zhangxun 2025-06-17 21:28:19 +08:00 committed by Luke
parent e78cb09c0f
commit ee9e56c479
7 changed files with 104 additions and 14 deletions

View File

@ -109,7 +109,7 @@ public record ExpressionBuilder(IRContext ctx) {
switch (node) { switch (node) {
// 数字字面量直接加载到目标寄存器 // 数字字面量直接加载到目标寄存器
case NumberLiteralNode n -> case NumberLiteralNode n ->
InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.parseIntSafely(n.value())); InstructionFactory.loadConstInto(ctx, dest, ExpressionUtils.buildNumberConstant(ctx, n.value()));
// 标识符查找并move到目标寄存器 // 标识符查找并move到目标寄存器
case IdentifierNode id -> { case IdentifierNode id -> {
IRVirtualRegister src = ctx.getScope().lookup(id.name()); IRVirtualRegister src = ctx.getScope().lookup(id.name());
@ -207,7 +207,7 @@ public record ExpressionBuilder(IRContext ctx) {
* @return 存放该常量的寄存器 * @return 存放该常量的寄存器
*/ */
private IRVirtualRegister buildNumberLiteral(String value) { private IRVirtualRegister buildNumberLiteral(String value) {
IRConstant constant = ExpressionUtils.buildNumberConstant(value); IRConstant constant = ExpressionUtils.buildNumberConstant(ctx, value);
IRVirtualRegister reg = ctx.newRegister(); IRVirtualRegister reg = ctx.newRegister();
ctx.addInstruction(new LoadConstInstruction(reg, constant)); ctx.addInstruction(new LoadConstInstruction(reg, constant));
return reg; return reg;

View File

@ -51,7 +51,7 @@ public class FunctionBuilder {
// 2) 声明形参为每个参数分配虚拟寄存器并声明到作用域 // 2) 声明形参为每个参数分配虚拟寄存器并声明到作用域
for (ParameterNode p : functionNode.parameters()) { for (ParameterNode p : functionNode.parameters()) {
IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器 IRVirtualRegister reg = irFunction.newRegister(); // 新寄存器
irContext.getScope().declare(p.name(), reg); // 变量名寄存器绑定 irContext.getScope().declare(p.name(), p.type(), reg); // 变量名寄存器绑定
irFunction.addParameter(reg); // 添加到函数参数列表 irFunction.addParameter(reg); // 添加到函数参数列表
} }

View File

@ -24,6 +24,13 @@ final class IRBuilderScope {
*/ */
private final Map<String, IRVirtualRegister> vars = new HashMap<>(); private final Map<String, IRVirtualRegister> vars = new HashMap<>();
/**
* 存储变量名到对应类型的映射
* <br>
* 变量名为键变量类型为值用于变量类型提升
*/
private final Map<String, String> varTypes = new HashMap<>();
/** /**
* 当前作用域所绑定的 IRFunction 对象用于申请新的虚拟寄存器 * 当前作用域所绑定的 IRFunction 对象用于申请新的虚拟寄存器
*/ */
@ -44,10 +51,12 @@ final class IRBuilderScope {
* 调用绑定的 IRFunction.newRegister() 生成寄存器后保存到映射表中 * 调用绑定的 IRFunction.newRegister() 生成寄存器后保存到映射表中
* *
* @param name 变量名称作为映射键使用 * @param name 变量名称作为映射键使用
* @param type 变量类型
*/ */
void declare(String name) { void declare(String name, String type) {
IRVirtualRegister reg = fn.newRegister(); IRVirtualRegister reg = fn.newRegister();
vars.put(name, reg); vars.put(name, reg);
varTypes.put(name, type);
} }
/** /**
@ -55,10 +64,12 @@ final class IRBuilderScope {
* 该方法可用于将外部或前一作用域的寄存器导入到本作用域 * 该方法可用于将外部或前一作用域的寄存器导入到本作用域
* *
* @param name 变量名称作为映射键使用 * @param name 变量名称作为映射键使用
* @param type 变量类型
* @param reg 要绑定到该名称的 IRVirtualRegister 实例 * @param reg 要绑定到该名称的 IRVirtualRegister 实例
*/ */
void declare(String name, IRVirtualRegister reg) { void declare(String name, String type, IRVirtualRegister reg) {
vars.put(name, reg); vars.put(name, reg);
varTypes.put(name, type);
} }
/** /**
@ -82,4 +93,15 @@ final class IRBuilderScope {
IRVirtualRegister lookup(String name) { IRVirtualRegister lookup(String name) {
return vars.get(name); return vars.get(name);
} }
/**
* 根据变量名称在当前作用域中查找对应的类型
*
* @param name 需要查询的变量名称
* @return 如果该名称已声明则返回对应的类型
* 如果未声明则返回 null
*/
String lookupType(String name) {
return varTypes.get(name);
}
} }

View File

@ -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.core.IRInstruction;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import java.util.Optional;
/** /**
* IRContext 类负责封装当前正在构建的 IRFunction 实例 * IRContext 类负责封装当前正在构建的 IRFunction 实例
* 以及与之配套的作用域管理IRBuilderScope * 以及与之配套的作用域管理IRBuilderScope
@ -31,6 +33,11 @@ public class IRContext {
*/ */
private final IRBuilderScope scope; private final IRBuilderScope scope;
/**
* 当前声明变量的类型不在声明变量时为空
*/
private Optional<String> var_type;
/** /**
* 构造一个新的 IRContext并将指定的 IRFunction 与作用域关联 * 构造一个新的 IRContext并将指定的 IRFunction 与作用域关联
* *
@ -41,6 +48,7 @@ public class IRContext {
this.scope = new IRBuilderScope(); this.scope = new IRBuilderScope();
// 关联作用域与 IRFunction以便在声明变量时申请寄存器 // 关联作用域与 IRFunction以便在声明变量时申请寄存器
this.scope.attachFunction(function); this.scope.attachFunction(function);
this.var_type = Optional.empty();
} }
/** /**
@ -85,4 +93,29 @@ public class IRContext {
public String newLabel() { public String newLabel() {
return "L" + (labelCounter++); return "L" + (labelCounter++);
} }
/**
* 获取当前 declare 编译阶段变量类型
*
* @return 当前 declare 的变量类型
*/
public Optional<String> 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();
}
} }

View File

@ -58,8 +58,8 @@ public class InstructionFactory {
* @param dest 目标寄存器 * @param dest 目标寄存器
* @param value 要加载的整数常量 * @param value 要加载的整数常量
*/ */
public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, int value) { public static void loadConstInto(IRContext ctx, IRVirtualRegister dest, IRConstant value) {
ctx.addInstruction(new LoadConstInstruction(dest, new IRConstant(value))); ctx.addInstruction(new LoadConstInstruction(dest, value));
} }
/** /**

View File

@ -55,19 +55,37 @@ public class StatementBuilder {
} }
if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) { if (stmt instanceof AssignmentNode(String var, ExpressionNode rhs)) {
// 赋值语句 a = b + 1; // 赋值语句 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); expr.buildInto(rhs, target);
// 2. 清除变量声明
ctx.clearVarType();
return; return;
} }
if (stmt instanceof DeclarationNode decl) { if (stmt instanceof DeclarationNode decl) {
// 变量声明 int a = 1; // 变量声明 int a = 1;
if (decl.getInitializer().isPresent()) { if (decl.getInitializer().isPresent()) {
// 声明同时有初值 // 声明同时有初值
// 1. 设置声明变量的类型
ctx.setVarType(decl.getType());
IRVirtualRegister r = expr.build(decl.getInitializer().get()); 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 { } else {
// 仅声明无初值 // 仅声明无初值
ctx.getScope().declare(decl.getName()); ctx.getScope().declare(decl.getName(), decl.getType());
} }
return; return;
} }
@ -92,11 +110,12 @@ public class StatementBuilder {
* @param name 变量名 * @param name 变量名
* @return 变量对应的虚拟寄存器 * @return 变量对应的虚拟寄存器
*/ */
private IRVirtualRegister getOrDeclareRegister(String name) { private IRVirtualRegister getOrDeclareRegister(String name, String type) {
IRVirtualRegister reg = ctx.getScope().lookup(name); IRVirtualRegister reg = ctx.getScope().lookup(name);
if (reg == null) { if (reg == null) {
reg = ctx.newRegister(); reg = ctx.newRegister();
ctx.getScope().declare(name, reg); ctx.getScope().declare(name, type, reg);
throw new IllegalStateException("这里是怎么到达?");
} }
return reg; return reg;
} }

View File

@ -1,5 +1,6 @@
package org.jcnc.snow.compiler.ir.utils; 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.IROpCode;
import org.jcnc.snow.compiler.ir.core.IROpCodeMappings; import org.jcnc.snow.compiler.ir.core.IROpCodeMappings;
import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRConstant;
@ -56,14 +57,29 @@ public class ExpressionUtils {
* 根据数字字面量字符串自动判断类型生成对应类型的 IRConstant * 根据数字字面量字符串自动判断类型生成对应类型的 IRConstant
* 支持 b/s/l/f/d 类型后缀与浮点格式自动分配合适类型 * 支持 b/s/l/f/d 类型后缀与浮点格式自动分配合适类型
* *
* @param ctx IR 编译上下文环境
* @param value 字面量字符串 "1", "2l", "3.14f", "5D" * @param value 字面量字符串 "1", "2l", "3.14f", "5D"
* @return 生成的 IRConstant 对象包含正确类型 * @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)); char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1));
String digits = switch (suffix) { String digits = switch (suffix) {
case 'b','s','l','f','d' -> value.substring(0, value.length() - 1); 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) { return switch (suffix) {