fix: 变量的类型受右值类型影响而降级
This commit is contained in:
parent
e78cb09c0f
commit
ee9e56c479
@ -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;
|
||||
|
||||
@ -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); // 添加到函数参数列表
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,13 @@ final class IRBuilderScope {
|
||||
*/
|
||||
private final Map<String, IRVirtualRegister> vars = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 存储变量名到对应类型的映射。
|
||||
* <br>
|
||||
* 变量名为键,变量类型为值,用于变量类型提升。
|
||||
*/
|
||||
private final Map<String, String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String> 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<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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user