Compare commits

..

No commits in common. 'lab2' and 'master' have entirely different histories.
lab2 ... master

@ -20,7 +20,100 @@
如果希望进一步参考编译相关项目和往届优秀实现,可以查看编译比赛官网的技术支持栏目:<https://compiler.educg.net/#/index?TYPE=26COM>。其中的“备赛推荐”整理了一些编译相关项目,也能看到往届优秀作品的开源实现,这些内容都很值得参考。 如果希望进一步参考编译相关项目和往届优秀实现,可以查看编译比赛官网的技术支持栏目:<https://compiler.educg.net/#/index?TYPE=26COM>。其中的“备赛推荐”整理了一些编译相关项目,也能看到往届优秀作品的开源实现,这些内容都很值得参考。
## 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 教程,例如:<https://liaoxuefeng.com/books/git/introduction/index.html>
当然也没有必要一开始学得特别深入,只需要记住常见操作即可,例如 `clone`、`status`、`add`、`commit`、`pull`、`push`、分支切换与合并。遇到具体报错或不会处理的冲突时,可以把现象和命令发给大模型帮你分析。
Git Commit 提交的信息建议尽量写清楚,推荐使用下面的格式:
```text
<type>(<scope>): <subject>
```
常见的 `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. 实验环境配置 ## 4. 实验环境配置

@ -48,13 +48,10 @@ class IRGenImpl final : public SysYBaseVisitor {
ir::Module& module_; ir::Module& module_;
const SemanticContext& sema_; const SemanticContext& sema_;
ir::Function* func_ = nullptr; ir::Function* func_;
ir::IRBuilder builder_; ir::IRBuilder builder_;
// 名称绑定由 Sema 负责IRGen 只维护“声明 -> 存储槽位”的代码生成状态。 // 名称绑定由 Sema 负责IRGen 只维护“声明 -> 存储槽位”的代码生成状态。
std::unordered_map<SysYParser::VarDefContext*, ir::Value*> storage_map_; std::unordered_map<SysYParser::VarDefContext*, ir::Value*> storage_map_;
// 修复点:添加缺失的函数返回类型标记
bool current_func_void_ = false;
}; };
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree, std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,

@ -1,17 +0,0 @@
#!/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 "恭喜通关"

@ -1,5 +1,15 @@
// SysY 子集语法:支持形如
// int main() { int a = 1; int b = 2; return a + b; }
// 的最小返回表达式编译。
// 后续需要自行添加
grammar SysY; grammar SysY;
/*===-------------------------------------------===*/
/* Lexer rules */
/*===-------------------------------------------===*/
INT: 'int'; INT: 'int';
RETURN: 'return'; RETURN: 'return';
@ -19,25 +29,70 @@ WS: [ \t\r\n] -> skip;
LINECOMMENT: '//' ~[\r\n]* -> skip; LINECOMMENT: '//' ~[\r\n]* -> skip;
BLOCKCOMMENT: '/*' .*? '*/' -> skip; BLOCKCOMMENT: '/*' .*? '*/' -> skip;
compUnit : funcDef EOF ; /*===-------------------------------------------===*/
decl : btype varDef SEMICOLON ; /* Syntax rules */
btype : INT ; /*===-------------------------------------------===*/
varDef : lValue (ASSIGN initValue)? ;
initValue : exp ; compUnit
funcDef : funcType ID LPAREN RPAREN blockStmt ; : funcDef EOF
funcType : INT ; ;
blockStmt : LBRACE blockItem* RBRACE ;
blockItem : decl | stmt ; decl
: btype varDef SEMICOLON
;
stmt : returnStmt ; btype
returnStmt : RETURN exp SEMICOLON ; : INT
;
exp : LPAREN exp RPAREN # parenExp 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
| var # varExp | var # varExp
| number # numberExp | number # numberExp
| exp ADD exp # additiveExp | exp ADD exp # additiveExp
; ;
var : ID ; var
lValue : ID ; : ID
number : ILITERAL ; ;
lValue
: ID
;
number
: ILITERAL
;

@ -15,7 +15,3 @@ file(GLOB_RECURSE ANTLR4_GENERATED_SOURCES CONFIGURE_DEPENDS
if(ANTLR4_GENERATED_SOURCES) if(ANTLR4_GENERATED_SOURCES)
target_sources(frontend PRIVATE ${ANTLR4_GENERATED_SOURCES}) target_sources(frontend PRIVATE ${ANTLR4_GENERATED_SOURCES})
endif() endif()
if(TARGET antlr4_generate)
add_dependencies(frontend antlr4_generate)
endif()

@ -1,50 +1,39 @@
#include "irgen/IRGen.h" #include "irgen/IRGen.h"
#include <any>
#include <stdexcept> #include <stdexcept>
#include "RuleContext.h"
#include "SysYParser.h" #include "SysYParser.h"
#include "ir/IR.h" #include "ir/IR.h"
#include "utils/Log.h" #include "utils/Log.h"
// 语句生成当前只实现了最小子集。
// 目前支持:
// - return <exp>;
//
// 还未支持:
// - 赋值语句
// - if / while 等控制流
// - 空语句、块语句嵌套分发之外的更多语句形态
std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) { std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
if (!ctx) { if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句")); throw std::runtime_error(FormatError("irgen", "缺少语句"));
} }
if (ctx->returnStmt()) {
if (auto* r = dynamic_cast<SysYParser::ReturnStmtContext*>(ctx->returnStmt())) { return ctx->returnStmt()->accept(this);
return visitReturnStmt(r);
}
// 兼容不同 ANTLR 版本的遍历兜底
for (auto* ch : ctx->children) {
if (auto* rs = dynamic_cast<SysYParser::ReturnStmtContext*>(
dynamic_cast<antlr4::RuleContext*>(ch))) {
return visitReturnStmt(rs);
} }
throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
} }
throw std::runtime_error(FormatError("irgen", "暂不支持的语句"));
return {};
}
std::any IRGenImpl::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) { std::any IRGenImpl::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) {
if (!ctx) { if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少 return")); 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()) { if (!ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "return 缺表达式")); throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
} }
ir::Value* v = EvalExpr(*ctx->exp()); ir::Value* v = EvalExpr(*ctx->exp());
builder_.CreateRet(v); builder_.CreateRet(v);
} return BlockFlow::Terminated;
return std::any(BlockFlow::Terminated);
} }

@ -1,11 +0,0 @@
实验步骤:
1.使用 Git 同步功能,从团队 Fork 的项目仓库中,拉取当前关卡对应分支的代码。
2.根据任务要求,完成相关代码文件的编写与完善。
3.编写测试脚本对代码qw逻辑进行充分验证。
4.确认自测通过后,点击“评测”按钮提交检验。
注意:评测输出内容可在 /data/workspace/myshixun/result/result1.txt 文件内查看。
Loading…
Cancel
Save