fix(irgen): 修复 Lab2 全局数组初始化与常量取模语义

dev
brkstar 10 hours ago
parent 3a49f8e131
commit f32ebef74c

@ -270,3 +270,64 @@ done
## 7. 结论
本次修改后Lab2 已完成从 SysY 语法树到 LLVM 风格 IR 的主链路扩展,支持函数、控制流、数组、初始化、浮点与运行库调用,并且通过了当前仓库 `functional``performance` 正例全集的运行验证。
## 附录2026-04-08 增量修复
本次增量修复补齐了两处会影响 Lab2 语义一致性的缺陷。
### A. 全局数组标量初始化补齐
问题:
1. `Sema` 已允许数组初始化器直接写单个表达式。
2. 局部数组初始化路径也能把该表达式落到首元素,其他元素补零。
3. 但全局数组在 `BuildGlobalInitializer` 中只处理花括号初始化,导致 `int a[3] = 1;` 被错误生成为全零数组。
修复:
1. 在 `src/irgen/IRGenDecl.cpp` 中为数组类型增加 `init->exp()` 分支。
2. 将该表达式求值后写入扁平化初始化列表第 0 个元素,其余元素继续保持零初始化。
结果:
1. `int a[3] = 1;` 现在会生成 `@a = global [3 x i32] [i32 1, i32 0, i32 0]`
2. `float b[2] = 2.5;` 现在会生成首元素为 `2.5`、其余元素为 `0.0`
### B. 常量表达式 `%` 类型约束对齐
问题:
1. 运行时表达式路径已经限制 `%` 仅支持 `int`
2. 但常量求值路径会直接执行 `AsInt() % AsInt()`,从而把 `float` 静默截断后继续通过。
修复:
1. 在 `src/sem/Sema.cpp` 的常量求值路径中加入 `%``int` 类型检查。
2. 在 `src/irgen/IRGenDecl.cpp` 的全局常量初始化求值路径中加入同样的检查。
结果:
1. 普通表达式和常量表达式对 `%` 的语义约束保持一致。
2. `const int a = 5 % 2.0;` 现在会在 `sema` 阶段直接报错,而不是被静默接受。
### C. 本次新增回归样例
1. `test/test_case/functional/06_global_arr_scalar_init.sy`
2. `test/test_case/functional/06_global_arr_scalar_init.out`
3. `test/test_case/negative/lab2_const_mod_float.sy`
### D. 本次定向验证
执行命令:
```bash
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCOMPILER_PARSE_ONLY=OFF
cmake --build build -j 4
./scripts/verify_ir.sh test/test_case/functional/06_global_arr_scalar_init.sy test/test_result/lab2_ir --run
./build/bin/compiler --emit-ir test/test_case/negative/lab2_const_mod_float.sy
```
结果:
1. 正例 `06_global_arr_scalar_init.sy` 成功生成 IR、链接运行并匹配期望退出码 `3`
2. 负例 `lab2_const_mod_float.sy` 按预期报错:`[error] [sema] % 只支持 int`

@ -96,6 +96,9 @@ ConstantData EvalGlobalConstMulExp(
ConstantData rhs = EvalGlobalConstUnaryExp(*mul.unaryExp(i), const_values);
const std::string op = mul.children[2 * i - 1]->getText();
if (op == "%") {
if (!acc.GetType()->IsInt32() || !rhs.GetType()->IsInt32()) {
throw std::runtime_error(FormatError("irgen", "% 只支持 int"));
}
acc = ConstantData::FromInt(acc.AsInt() % rhs.AsInt());
continue;
}
@ -386,7 +389,11 @@ ir::ConstantValue* IRGenImpl::BuildGlobalInitializer(const std::shared_ptr<Type>
const auto scalar_type = ScalarLeafType(type);
std::vector<ConstantData> flat(CountScalars(type), ZeroForType(scalar_type));
if (init->L_BRACE()) {
if (init->exp()) {
flat[0] =
EvalGlobalConstAddExp(*init->exp()->addExp(), global_const_values_)
.CastTo(scalar_type);
} else if (init->L_BRACE()) {
std::vector<SysYParser::InitValContext*> leaves(flat.size(), nullptr);
size_t cursor = 0;
FlattenInitValue(type, *init, leaves, cursor, 0);

@ -183,6 +183,9 @@ class SemaAnalyzer {
ConstantData rhs = EvalConstUnaryExp(*terms[i]);
const std::string op = mul.children[2 * i - 1]->getText();
if (op == "%") {
if (!acc.GetType()->IsInt32() || !rhs.GetType()->IsInt32()) {
throw std::runtime_error(FormatError("sema", "% 只支持 int"));
}
acc = ConstantData::FromInt(acc.AsInt() % rhs.AsInt());
continue;
}

@ -0,0 +1,6 @@
int a[3] = 1;
float b[2] = 2.5;
int main() {
return a[0] + a[1] + a[2] + b[0] + b[1];
}

@ -0,0 +1,5 @@
const int a = 5 % 2.0;
int main() {
return a;
}
Loading…
Cancel
Save