diff --git a/README.md b/README.md index c24a2fa..f5424d5 100644 --- a/README.md +++ b/README.md @@ -20,100 +20,7 @@ 如果希望进一步参考编译相关项目和往届优秀实现,可以查看编译比赛官网的技术支持栏目:。其中的“备赛推荐”整理了一些编译相关项目,也能看到往届优秀作品的开源实现,这些内容都很值得参考。 -## 3. 头歌平台协作流程 -头歌平台的代码托管方式与 GitHub/Gitee 类似。如果你希望基于当前仓库快速开始协作,可以参考下面这套流程。 - -### 3.1 组长 fork 课程仓库 - -组长打开课程仓库页面,点击右上角的 `Fork`,创建你们小组自己的仓库副本。后续组内开发统一基于这个 fork 后的仓库进行。 - -![组长 fork 课程仓库](doc/images/01.png) - -### 3.2 组长邀请组员加入仓库 - -fork 完成后,组长进入自己的仓库页面,在右侧可以看到邀请码。把邀请码发给组员即可,组员不需要再 fork 课程仓库。 - -![组长查看邀请码](doc/images/02.png) - -### 3.3 组员申请加入,组长审批通过 - -组员拿到邀请码后,可以在页面右上角的 `+` 菜单里选择 `加入项目`,然后提交加入申请。 - -![组员加入项目入口](doc/images/03.png) - -申请发出后,组长到个人主页的待办事项中审批成员申请,同意后组员就可以正常参与仓库协作。 - -![组长审批组员申请](doc/images/04.png) - -### 3.4 在本地克隆小组仓库并配置远端 - -组长和组员在成功加入小组仓库后,就可以从仓库页面复制 HTTPS 地址,在本地克隆代码: - -![复制仓库 HTTPS 地址](doc/images/05.png) - -下面示例使用 HTTPS 方式: - -```bash -git clone <仓库 HTTPS 地址> -cd nudt-compiler-cpp -``` - -如果希望后续同步课程仓库更新,可以额外把课程主仓库配置为 `upstream`: - -```bash -git remote add upstream https://bdgit.educoder.net/NUDT-compiler/nudt-compiler-cpp.git -git remote -v -``` - -配置完成后,常见的远端分工如下: - -- `origin`:你们小组 fork 后的仓库,日常提交代码、推送分支都使用这个远端。 -- `upstream`:课程主仓库,通常用于查看或同步课程团队发布的更新。 - -如果后续需要同步主仓库更新,可以先抓取远端信息: - -```bash -git fetch upstream -``` - -### 3.5 提交与协作建议 - -借助 Git 进行协作开发,是当前软件开发中非常常见的一种工作方式,也是这门课程里需要大家掌握的基本能力。如果你对 Git 还不太熟悉,可以先看一下网络上的 Git 教程,例如:。 - -当然也没有必要一开始学得特别深入,只需要记住常见操作即可,例如 `clone`、`status`、`add`、`commit`、`pull`、`push`、分支切换与合并。遇到具体报错或不会处理的冲突时,可以把现象和命令发给大模型帮你分析。 - -Git Commit 提交的信息建议尽量写清楚,推荐使用下面的格式: - -```text -(): -``` - -常见的 `type` 有: - -- `feat`:新增功能 -- `fix`:修复 bug -- `refactor`:重构但不改变外部行为 -- `docs`:文档修改 -- `test`:测试相关 -- `chore`:杂项维护 - -`scope` 用来说明改动的大致范围,例如 `frontend`、`irgen`、`backend`、`test`、`doc`。 - -`subject` 用一句简短的话说明“这次改了什么”。 - -例如: - -```text -feat(irgen): 支持一元表达式生成 -fix(frontend): 修复空语句解析错误 -docs(doc): 补充实验环境配置说明 -``` - -除了提交代码本身,也推荐大家把头歌平台上的协作功能真正用起来: - -- `Issue` 适合用来拆分任务、记录 bug、整理讨论结果和跟踪待办。 -- `PR` / `Merge Request` 适合用来做分支合并和代码评审。比较推荐的流程是:每个人在自己的分支上开发,完成一个相对独立的小功能后提交 PR,再由组内其他同学帮忙检查实现思路、代码质量和测试结果。 ## 4. 实验环境配置 diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h index 231ba90..beb55ed 100644 --- a/include/irgen/IRGen.h +++ b/include/irgen/IRGen.h @@ -48,11 +48,14 @@ class IRGenImpl final : public SysYBaseVisitor { ir::Module& module_; const SemanticContext& sema_; - ir::Function* func_; + ir::Function* func_ = nullptr; ir::IRBuilder builder_; // 名称绑定由 Sema 负责;IRGen 只维护“声明 -> 存储槽位”的代码生成状态。 std::unordered_map storage_map_; + + // 修复点:添加缺失的函数返回类型标记 + bool current_func_void_ = false; }; std::unique_ptr GenerateIR(SysYParser::CompUnitContext& tree, - const SemanticContext& sema); + const SemanticContext& sema); \ No newline at end of file diff --git a/result/result b/result/result new file mode 100644 index 0000000..e69de29 diff --git a/result/result1.txt b/result/result1.txt new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/result/result1.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/build_lab2.sh b/scripts/build_lab2.sh new file mode 100644 index 0000000..79deaf0 --- /dev/null +++ b/scripts/build_lab2.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$ROOT" + +# 生成ANTLR解析器代码 +echo "生成ANTLR解析器代码..." +java -jar "$ROOT/third_party/antlr-4.13.2-complete.jar" -Dlanguage=Cpp -visitor -o "$ROOT/build/generated/antlr4" "$ROOT/src/antlr4/SysY.g4" + + +# 构建项目 +echo "构建项目..." +cmake -S . -B build -DCMAKE_BUILD_TYPE=Release +cmake --build build --parallel + +echo "恭喜通关" \ No newline at end of file diff --git a/src/antlr4/SysY.g4 b/src/antlr4/SysY.g4 index 263aeef..b8d5fd2 100644 --- a/src/antlr4/SysY.g4 +++ b/src/antlr4/SysY.g4 @@ -1,15 +1,5 @@ -// SysY 子集语法:支持形如 -// int main() { int a = 1; int b = 2; return a + b; } -// 的最小返回表达式编译。 - -// 后续需要自行添加 - grammar SysY; -/*===-------------------------------------------===*/ -/* Lexer rules */ -/*===-------------------------------------------===*/ - INT: 'int'; RETURN: 'return'; @@ -29,70 +19,25 @@ WS: [ \t\r\n] -> skip; LINECOMMENT: '//' ~[\r\n]* -> skip; BLOCKCOMMENT: '/*' .*? '*/' -> skip; -/*===-------------------------------------------===*/ -/* Syntax rules */ -/*===-------------------------------------------===*/ - -compUnit - : funcDef EOF - ; - -decl - : btype varDef SEMICOLON - ; +compUnit : funcDef EOF ; +decl : btype varDef SEMICOLON ; +btype : INT ; +varDef : lValue (ASSIGN initValue)? ; +initValue : exp ; +funcDef : funcType ID LPAREN RPAREN blockStmt ; +funcType : INT ; +blockStmt : LBRACE blockItem* RBRACE ; +blockItem : decl | stmt ; -btype - : INT - ; +stmt : returnStmt ; +returnStmt : RETURN exp SEMICOLON ; -varDef - : lValue (ASSIGN initValue)? - ; - -initValue - : exp - ; - -funcDef - : funcType ID LPAREN RPAREN blockStmt - ; - -funcType - : INT - ; - -blockStmt - : LBRACE blockItem* RBRACE - ; - -blockItem - : decl - | stmt - ; - -stmt - : returnStmt - ; - -returnStmt - : RETURN exp SEMICOLON - ; - -exp - : LPAREN exp RPAREN # parenExp +exp : LPAREN exp RPAREN # parenExp | var # varExp | number # numberExp | exp ADD exp # additiveExp ; -var - : ID - ; - -lValue - : ID - ; - -number - : ILITERAL - ; +var : ID ; +lValue : ID ; +number : ILITERAL ; \ No newline at end of file diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt index 524fcd6..7023c1c 100644 --- a/src/frontend/CMakeLists.txt +++ b/src/frontend/CMakeLists.txt @@ -15,3 +15,7 @@ file(GLOB_RECURSE ANTLR4_GENERATED_SOURCES CONFIGURE_DEPENDS if(ANTLR4_GENERATED_SOURCES) target_sources(frontend PRIVATE ${ANTLR4_GENERATED_SOURCES}) endif() + +if(TARGET antlr4_generate) + add_dependencies(frontend antlr4_generate) +endif() diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp index 751550c..fc6b102 100644 --- a/src/irgen/IRGenStmt.cpp +++ b/src/irgen/IRGenStmt.cpp @@ -1,39 +1,50 @@ #include "irgen/IRGen.h" +#include #include +#include "RuleContext.h" #include "SysYParser.h" #include "ir/IR.h" #include "utils/Log.h" -// 语句生成当前只实现了最小子集。 -// 目前支持: -// - return ; -// -// 还未支持: -// - 赋值语句 -// - if / while 等控制流 -// - 空语句、块语句嵌套分发之外的更多语句形态 - std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) { if (!ctx) { throw std::runtime_error(FormatError("irgen", "缺少语句")); } - if (ctx->returnStmt()) { - return ctx->returnStmt()->accept(this); + + if (auto* r = dynamic_cast(ctx->returnStmt())) { + return visitReturnStmt(r); + } + + // 兼容不同 ANTLR 版本的遍历兜底 + for (auto* ch : ctx->children) { + if (auto* rs = dynamic_cast( + dynamic_cast(ch))) { + return visitReturnStmt(rs); + } } - throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型")); -} + throw std::runtime_error(FormatError("irgen", "暂不支持的语句")); + return {}; +} std::any IRGenImpl::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) { if (!ctx) { - throw std::runtime_error(FormatError("irgen", "缺少 return 语句")); + throw std::runtime_error(FormatError("irgen", "缺少 return")); } - if (!ctx->exp()) { - throw std::runtime_error(FormatError("irgen", "return 缺少表达式")); + if (current_func_void_) { + if (ctx->exp()) { + throw std::runtime_error(FormatError("irgen", "void return 带值")); + } + // 修复点:原版的 CreateRetVoid() 名字错了,正确的 API 是 CreateRet() + builder_.CreateRet(nullptr); + } else { + if (!ctx->exp()) { + throw std::runtime_error(FormatError("irgen", "return 缺表达式")); + } + ir::Value* v = EvalExpr(*ctx->exp()); + builder_.CreateRet(v); } - ir::Value* v = EvalExpr(*ctx->exp()); - builder_.CreateRet(v); - return BlockFlow::Terminated; -} + return std::any(BlockFlow::Terminated); +} \ No newline at end of file diff --git a/test/test_case/performance/2025-MYO-20.sy b/test/test_case/performance/2025-MYO-20.sy index 0812089..a888e38 100644 --- a/test/test_case/performance/2025-MYO-20.sy +++ b/test/test_case/performance/2025-MYO-20.sy @@ -1,110 +1,110 @@ -int A[1024][1024]; -int B[1024][1024]; -int C[1024][1024]; - -int main() { - int T = getint(); // 矩阵规模 - int R = getint(); // 重复次数 - - int i = 0; - while (i < T) { - if (i < T / 2) { - getarray(A[i]); - } - i = i + 1; - } - - i = 0; - while (i < T) { - if (i >= T / 2) { - getarray(B[i]); - } - i = i + 1; - } - - starttime(); - - i = 0; - while (i < T) { - if (i >= T / 2) { - int j = 0; - while (j < T) { - A[i][j] = -1; - j = j + 1; - } - } - i = i + 1; - } - - i = 0; - while (i < T) { - if (i < T / 2) { - int j = 0; - while (j < T) { - B[i][j] = -1; - j = j + 1; - } - } - i = i + 1; - } - - i = 0; - while (i < T) { - int j = 0; - while (j < T) { - C[i][j] = A[i][j] * 2 + B[i][j] * 3; - j = j + 1; - } - i = i + 1; - } - - i = 0; - while (i < T) { - int j = 0; - while (j < T) { - int val = C[i][j]; - val = val * val + 7; - val = val / 3; - C[i][j] = val; - j = j + 1; - } - i = i + 1; - } - - i = 0; - while (i < T) { - int j = 0; - while (j < T) { - int k = 0; - int sum = 0; - while (k < T) { - sum = sum + C[i][k] * A[k][j]; - k = k + 1; - } - A[i][j] = sum; - j = j + 1; - } - i = i + 1; - } - - int total = 0; - int r = 0; - while (r < R) { - i = 0; - while (i < T) { - int j = 0; - while (j < T) { - total = total + A[i][j] * A[i][j]; - j = j + 1; - } - i = i + 1; - } - r = r + 1; - } - - stoptime(); - - putint(total); - putch(10); - return 0; -} +int A[1024][1024]; +int B[1024][1024]; +int C[1024][1024]; + +int main() { + int T = getint(); // 矩阵规模 + int R = getint(); // 重复次数 + + int i = 0; + while (i < T) { + if (i < T / 2) { + getarray(A[i]); + } + i = i + 1; + } + + i = 0; + while (i < T) { + if (i >= T / 2) { + getarray(B[i]); + } + i = i + 1; + } + + starttime(); + + i = 0; + while (i < T) { + if (i >= T / 2) { + int j = 0; + while (j < T) { + A[i][j] = -1; + j = j + 1; + } + } + i = i + 1; + } + + i = 0; + while (i < T) { + if (i < T / 2) { + int j = 0; + while (j < T) { + B[i][j] = -1; + j = j + 1; + } + } + i = i + 1; + } + + i = 0; + while (i < T) { + int j = 0; + while (j < T) { + C[i][j] = A[i][j] * 2 + B[i][j] * 3; + j = j + 1; + } + i = i + 1; + } + + i = 0; + while (i < T) { + int j = 0; + while (j < T) { + int val = C[i][j]; + val = val * val + 7; + val = val / 3; + C[i][j] = val; + j = j + 1; + } + i = i + 1; + } + + i = 0; + while (i < T) { + int j = 0; + while (j < T) { + int k = 0; + int sum = 0; + while (k < T) { + sum = sum + C[i][k] * A[k][j]; + k = k + 1; + } + A[i][j] = sum; + j = j + 1; + } + i = i + 1; + } + + int total = 0; + int r = 0; + while (r < R) { + i = 0; + while (i < T) { + int j = 0; + while (j < T) { + total = total + A[i][j] * A[i][j]; + j = j + 1; + } + i = i + 1; + } + r = r + 1; + } + + stoptime(); + + putint(total); + putch(10); + return 0; +} diff --git a/test/test_case/performance/vector_mul3.out b/test/test_case/performance/vector_mul3.out index 8fc524f..166c057 100644 --- a/test/test_case/performance/vector_mul3.out +++ b/test/test_case/performance/vector_mul3.out @@ -1,2 +1,2 @@ -1 +1 0 \ No newline at end of file diff --git a/实验说明.txt b/实验说明.txt new file mode 100644 index 0000000..a4f6b20 --- /dev/null +++ b/实验说明.txt @@ -0,0 +1,11 @@ +实验步骤: + +1.使用 Git 同步功能,从团队 Fork 的项目仓库中,拉取当前关卡对应分支的代码。 + +2.根据任务要求,完成相关代码文件的编写与完善。 + +3.编写测试脚本,对代码qw逻辑进行充分验证。 + +4.确认自测通过后,点击“评测”按钮提交检验。 + +注意:评测输出内容可在 /data/workspace/myshixun/result/result1.txt 文件内查看。 \ No newline at end of file