diff --git a/solution/Lab2-修改记录.md b/solution/Lab2-修改记录.md index 3a56976..979b455 100644 --- a/solution/Lab2-修改记录.md +++ b/solution/Lab2-修改记录.md @@ -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` diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp index 0e3aadf..c14680f 100644 --- a/src/irgen/IRGenDecl.cpp +++ b/src/irgen/IRGenDecl.cpp @@ -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 const auto scalar_type = ScalarLeafType(type); std::vector 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 leaves(flat.size(), nullptr); size_t cursor = 0; FlattenInitValue(type, *init, leaves, cursor, 0); diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp index 856a4f1..01a7159 100644 --- a/src/sem/Sema.cpp +++ b/src/sem/Sema.cpp @@ -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; } diff --git a/test/test_case/functional/06_global_arr_scalar_init.out b/test/test_case/functional/06_global_arr_scalar_init.out new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/test/test_case/functional/06_global_arr_scalar_init.out @@ -0,0 +1 @@ +3 diff --git a/test/test_case/functional/06_global_arr_scalar_init.sy b/test/test_case/functional/06_global_arr_scalar_init.sy new file mode 100644 index 0000000..f7c322d --- /dev/null +++ b/test/test_case/functional/06_global_arr_scalar_init.sy @@ -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]; +} diff --git a/test/test_case/negative/lab2_const_mod_float.sy b/test/test_case/negative/lab2_const_mod_float.sy new file mode 100644 index 0000000..f0fc107 --- /dev/null +++ b/test/test_case/negative/lab2_const_mod_float.sy @@ -0,0 +1,5 @@ +const int a = 5 % 2.0; + +int main() { + return a; +}