本项目是一个面向 SysY2022 的分阶段编译器实现。这个目录收集了项目从词法分析、语法分析、语义分析与 LLVM IR 生成,到 RISC-V 目标代码生成和后端优化的核心版本,方便展示一个编译器从前端到后端逐步成型的过程。
整理时只保留核心源码、必要说明和本地演示脚本,未纳入测试输出、公开测试点数据、性能实验产物、依赖缓存和旧实验二进制文件。
本编译器主要参照课程给定的 SysY2022 语言定义和实验文法实现。SysY 是用于编译原理教学和编译系统竞赛的 C 语言子集,整体语义接近 C,但语法范围和运行时接口经过裁剪,适合按编译器阶段逐步实现。
本仓库已收录必要参考文档:
核心文法入口为:
CompUnit -> { Decl } { FuncDef } MainFuncDef
程序由全局声明、普通函数定义和 main 函数组成。支持的主要语法成分包括:
- 声明:常量声明
ConstDecl、变量声明VarDecl - 类型:以
int为基础,后续版本也保留了部分float处理能力 - 函数:
int/void函数、形参表、实参表和函数调用 - 语句:赋值、表达式语句、语句块、
if/else、while、break、continue、return - 输入输出:
getint()和printf(...) - 左值:普通变量、一维数组、二维数组
- 表达式:一元表达式、乘除模、加减、关系、相等、逻辑与、逻辑或、常量表达式
表达式优先级和结合性按类 C 规则组织,逻辑运算 &&、|| 需要满足短路求值语义。
词法分析阶段识别 SysY 源码中的 token,并过滤空白与注释。主要 token 类型包括:
- 关键字:
const、int、void、if、else、while、break、continue、return、printf - 标识符:由字母或下划线开头,后接字母、数字或下划线
- 整数常量:支持十进制、八进制和十六进制形式;课程语义约束中要求普通十进制整数不能含非法前导零
- 字符串常量:用于
printf,转义字符重点支持\n - 运算符:
+、-、*、/、%、=、!、<、>、<=、>=、==、!=、&&、|| - 分隔符:
()[]{};, - 注释:支持
//行注释和/* ... */块注释
早期词法版本使用 Flex 生成扫描器;后续完整编译器版本改为手写词法分析器,便于和递归下降语法分析、错误定位和后端生成逻辑集成。
语法分析阶段参照 SysY2022 EBNF 文法,将可选结构 [] 和重复结构 {} 改写为 Bison 或递归下降可处理的产生式。语法分析实验要求输出指定非终结符,例如 <CompUnit>、<FuncDef>、<Stmt>、<AddExp> 等,同时不输出 <BlockItem>、<Decl>、<BType> 等辅助节点。
重要语义约束包括:
- 常量表达式
ConstExp -> AddExp中引用的标识符必须是常量 - 常量数组不能作为函数实参传递
- 相邻的一元运算符不能相同,例如
--+4不符合语义约束 - 一元
!只用于条件表达式相关语义 printf字符串中的转义字符重点限制为\n- 有返回值函数的最后一条语句应为
return main函数返回值按课程约定处理
中间代码和目标代码阶段还需要维护作用域、符号表、常量值、数组维度、函数签名、控制流标签、循环上下文和运行时调用信息。
第三阶段生成 LLVM IR。LLVM IR 是一种与具体机器无关的中间表示,便于表达变量、临时值、控制流、函数调用和内存访问,也便于用 lli 进行本地解释执行验证。
第四、五阶段生成 64-bit RISC-V 汇编,接口遵循目标代码生成任务要求:
compiler -S -o testcase.s testcase.sy最终竞赛版额外支持:
compiler -S -o testcase.s testcase.sy -O1其中 -O1 用于开启保守优化。优化目标是在通过功能测试的前提下改进生成汇编的执行效率。
完整编译器的典型处理流程如下:
SysY 源码
-> 词法分析,生成 token 序列
-> 语法分析,构造语法结构或 AST
-> 语义分析,维护符号表、类型、作用域和常量信息
-> 中间代码生成,输出 LLVM IR
-> 目标代码生成,输出 RISC-V 汇编
-> 可选优化,改进常量、分支、循环、寄存器和局部代码质量
项目中的早期版本更强调单个实验阶段的输出格式;后期版本逐渐合并为单文件编译器,直接完成从 SysY 源文件到 LLVM IR 或 RISC-V 汇编的翻译。
-
01_Lexical_Analysis_Front_End- 阶段:词法分析前端
- 来源:
Lexical_analyzer/ - 作用:基于 Flex 实现 SysY 词法分析,识别关键字、标识符、常量、运算符和分隔符等词法单元,属于早期词法分析实验版本。
-
02_Syntax_Analysis_Front_End- 阶段:语法分析前端
- 来源:
Syntax_analyzer1/ - 作用:基于 Flex/Bison 实现 SysY 语法分析,并按实验要求输出指定的语法非终结符。
- 选择理由:相比
Syntax_analyzer/,该版本通过包装规约只输出一次<CompUnit>,更符合语法分析实验中“父节点标签只输出一次”的要求。
-
03_Semantic_Analysis_LLVM_IR_Generation- 阶段:语义分析与 LLVM IR 中间代码生成
- 来源:
Intermediate_code_generation/compiler.cpp - 作用:单文件 SysY 编译器,包含手写词法分析、递归下降语法分析、AST 构建、语义处理和 LLVM IR 生成,读取
testfile.txt并输出output.ll。
-
04_RISCV_Backend_Code_Generation- 阶段:RISC-V 后端目标代码生成
- 来源:
Target_code_generation/Compiler.cpp - 作用:将 SysY 源程序翻译为 64 位 RISC-V 汇编,满足
compiler -S -o testcase.s testcase.sy的目标代码生成接口;该版本保留为竞赛优化前的基础后端版本。
-
05_Optimizing_RISCV_Backend- 阶段:带优化的 RISC-V 后端
- 来源:
Competition/Compiler.cpp - 作用:最终竞赛版 SysY 编译器,支持 RISC-V 汇编生成,并提供
-O1优化模式。 - 选择理由:该文件与最新的可提交备份
Competition/backups/Compiler_submit_ready_random_state_cache_fix_20260601.cpp内容一致,因此将根目录下的Competition/Compiler.cpp作为最终优化版的标准版本。
可以运行统一演示脚本感受每个阶段的效果:
./run_stage_demos.sh只运行某个阶段:
./run_stage_demos.sh --stage 3保留临时输出文件:
./run_stage_demos.sh --keep脚本会展示词法 token、语法规约输出、LLVM IR、普通 RISC-V 汇编和 -O1 优化版 RISC-V 汇编。lli 是可选依赖;如果本机安装了 lli,第三阶段会额外执行生成的 LLVM IR。