[lab2]IR-Gen implementation using given code by xxy

Merge pull request !4 from Downright/master
This commit is contained in:
LixuanWang
2025-03-26 11:42:19 +00:00
committed by Gitee
10 changed files with 1694 additions and 114 deletions

5
.gitignore vendored
View File

@@ -37,5 +37,6 @@ doxygen
!/testdata/functional/*.out
!/testdata/performance/*.out
build
.antlr
build/
.antlr
.vscode/

View File

@@ -29,7 +29,8 @@ sudo apt install -y uuid-dev libutfcpp-dev pkg-config make git cmake openjdk-11-
git clone https://gitee.com/xsu1989/sysy.git
cd sysy
cmake -S . -B build
cmake --build build
cmake --build build --target all -- -j $(nproc)
cmake --build build --target all -- -j $(nproc) -DCMAKE_BUILD_TYPE=Debug
```
构建完成后,可以运行一个小的测试用例。该测试将逗号分隔的整数或字符串列表进行格式化后重新输出,即将相邻参数之间的分隔统一调整为逗号外加一个空格。
@@ -81,7 +82,7 @@ cmake_install.cmake SysYBaseVisitor.h SysYLexer.cpp SysYLexer.interp SysYP
完成格式化器进阶内容后,可以通过执行`sysyc`观察格式化器的执行效果。
```bash
./build/sysyc -f test/format-test.sy
./build/bin/sysyc -f test/format-test.sy
```
## 实验2从AST生成中间表示
@@ -100,7 +101,7 @@ cmake_install.cmake SysYBaseVisitor.h SysYLexer.cpp SysYLexer.interp SysYP
完成实验2后可以通过执行`sysyc`观察生成的IR。
```bash
./build/sysyc -s ir 01_add.sy
./build/bin/sysyc -s ir test/01_add.sy
```
请同学们仔细阅读代码学习IR的定义。可以使用doxygen工具自动生成HTML文档
@@ -112,6 +113,8 @@ doxygen doc/Doxyfile
上述命令执行完毕后将在doxygen/html下找到生成的代码文档。
该版本还未实现数组初始化定义等功能
## 实验3从SysY IR 生成ARMv7汇编代码
### 后端相关源码

169
doc/markdowns/IR.md Normal file
View File

@@ -0,0 +1,169 @@
这个头文件定义了一个用于生成中间表示IR的数据结构主要用于编译器前端将抽象语法树AST转换为中间代码。以下是文件中定义的主要类和功能的整理和解释
---
### **1. 类型系统Type System**
#### **1.1 `Type` 类**
- **作用**:表示所有基本标量类型(如 `int``float``void` 等)以及指针类型和函数类型。
- **成员**
- `Kind` 枚举:表示类型的种类(如 `kInt``kFloat``kPointer` 等)。
- `kind`:当前类型的种类。
- 构造函数:`Type(Kind kind)`,用于初始化类型。
- 静态方法:如 `getIntType()``getFloatType()` 等,用于获取特定类型的单例对象。
- 类型检查方法:如 `isInt()``isFloat()` 等,用于检查当前类型是否为某种类型。
- `getSize()`:获取类型的大小。
- `as<T>()`:将当前类型动态转换为派生类(如 `PointerType``FunctionType`)。
#### **1.2 `PointerType` 类**
- **作用**:表示指针类型,派生自 `Type`
- **成员**
- `baseType`:指针指向的基础类型。
- 静态方法:`get(Type *baseType)`,用于获取指向 `baseType` 的指针类型。
- `getBaseType()`:获取指针指向的基础类型。
#### **1.3 `FunctionType` 类**
- **作用**:表示函数类型,派生自 `Type`
- **成员**
- `returnType`:函数的返回类型。
- `paramTypes`:函数的参数类型列表。
- 静态方法:`get(Type *returnType, const std::vector<Type *> &paramTypes)`,用于获取函数类型。
- `getReturnType()`:获取函数的返回类型。
- `getParamTypes()`:获取函数的参数类型列表。
---
### **2. 中间表示IR**
#### **2.1 `Value` 类**
- **作用**:表示 IR 中的所有值(如指令、常量、参数等)。
- **成员**
- `Kind` 枚举:表示值的种类(如 `kAdd``kSub``kConstant` 等)。
- `kind`:当前值的种类。
- `type`:值的类型。
- `name`:值的名称。
- `uses`:值的用途列表(表示哪些指令使用了该值)。
- 构造函数:`Value(Kind kind, Type *type, const std::string &name)`
- 类型检查方法:如 `isInt()``isFloat()` 等。
- `getUses()`:获取值的用途列表。
- `replaceAllUsesWith(Value *value)`:将该值的所有用途替换为另一个值。
- `print(std::ostream &os)`:打印值的表示。
#### **2.2 `ConstantValue` 类**
- **作用**:表示编译时常量(如整数常量、浮点数常量)。
- **成员**
- `iScalar``fScalar`:分别存储整数和浮点数常量的值。
- 静态方法:`get(int value)``get(float value)`,用于获取常量值。
- `getInt()``getFloat()`:获取常量的值。
#### **2.3 `Argument` 类**
- **作用**:表示函数或基本块的参数。
- **成员**
- `block`:参数所属的基本块。
- `index`:参数的索引。
- 构造函数:`Argument(Type *type, BasicBlock *block, int index, const std::string &name)`
- `getParent()`:获取参数所属的基本块。
- `getIndex()`:获取参数的索引。
#### **2.4 `BasicBlock` 类**
- **作用**:表示基本块,包含一系列指令。
- **成员**
- `parent`:基本块所属的函数。
- `instructions`:基本块中的指令列表。
- `arguments`:基本块的参数列表。
- `successors``predecessors`:基本块的后继和前驱列表。
- 构造函数:`BasicBlock(Function *parent, const std::string &name)`
- `getParent()`:获取基本块所属的函数。
- `getInstructions()`:获取基本块中的指令列表。
- `createArgument()`:为基本块创建一个参数。
#### **2.5 `Instruction` 类**
- **作用**:表示 IR 中的指令,派生自 `User`
- **成员**
- `Kind` 枚举:表示指令的种类(如 `kAdd``kSub``kLoad` 等)。
- `kind`:当前指令的种类。
- `parent`:指令所属的基本块。
- 构造函数:`Instruction(Kind kind, Type *type, BasicBlock *parent, const std::string &name)`
- `getParent()`:获取指令所属的基本块。
- `getFunction()`:获取指令所属的函数。
- 指令分类方法:如 `isBinary()``isUnary()``isMemory()` 等。
#### **2.6 `User` 类**
- **作用**:表示使用其他值的指令或全局值,派生自 `Value`
- **成员**
- `operands`:指令的操作数列表。
- 构造函数:`User(Kind kind, Type *type, const std::string &name)`
- `getOperand(int index)`:获取指定索引的操作数。
- `addOperand(Value *value)`:添加一个操作数。
- `replaceOperand(int index, Value *value)`:替换指定索引的操作数。
#### **2.7 具体指令类**
- **`CallInst`**:表示函数调用指令。
- **`UnaryInst`**:表示一元操作指令(如取反、类型转换)。
- **`BinaryInst`**:表示二元操作指令(如加法、减法)。
- **`ReturnInst`**:表示返回指令。
- **`UncondBrInst`**:表示无条件跳转指令。
- **`CondBrInst`**:表示条件跳转指令。
- **`AllocaInst`**:表示栈内存分配指令。
- **`LoadInst`**:表示从内存加载值的指令。
- **`StoreInst`**:表示将值存储到内存的指令。
---
### **3. 模块和函数**
#### **3.1 `Function` 类**
- **作用**:表示函数,包含多个基本块。
- **成员**
- `parent`:函数所属的模块。
- `blocks`:函数中的基本块列表。
- 构造函数:`Function(Module *parent, Type *type, const std::string &name)`
- `getReturnType()`:获取函数的返回类型。
- `getParamTypes()`:获取函数的参数类型列表。
- `addBasicBlock()`:为函数添加一个基本块。
#### **3.2 `GlobalValue` 类**
- **作用**:表示全局变量或常量。
- **成员**
- `parent`:全局值所属的模块。
- `hasInit`:是否有初始化值。
- `isConst`:是否是常量。
- 构造函数:`GlobalValue(Module *parent, Type *type, const std::string &name, const std::vector<Value *> &dims, Value *init)`
- `init()`:获取全局值的初始化值。
#### **3.3 `Module` 类**
- **作用**:表示整个编译单元(如一个源文件)。
- **成员**
- `children`:模块中的所有值(如函数、全局变量)。
- `functions`:模块中的函数列表。
- `globals`:模块中的全局变量列表。
- `createFunction()`:创建一个函数。
- `createGlobalValue()`:创建一个全局变量。
- `getFunction()`:获取指定名称的函数。
- `getGlobalValue()`:获取指定名称的全局变量。
---
### **4. 工具类**
#### **4.1 `Use` 类**
- **作用**:表示值与其使用者之间的关系。
- **成员**
- `index`:值在使用者操作数列表中的索引。
- `user`:使用者。
- `value`:被使用的值。
- 构造函数:`Use(int index, User *user, Value *value)`
- `getValue()`:获取被使用的值。
#### **4.2 `range` 类**
- **作用**:封装迭代器对 `[begin, end)`,用于遍历容器。
- **成员**
- `begin()``end()`:返回范围的起始和结束迭代器。
- `size()`:返回范围的大小。
- `empty()`:判断范围是否为空。
---
### **5. 总结**
- **类型系统**`Type``PointerType``FunctionType` 用于表示 IR 中的类型。
- **中间表示**`Value``ConstantValue``Instruction` 等用于表示 IR 中的值和指令。
- **模块和函数**`Module``Function``GlobalValue` 用于组织 IR 的结构。
- **工具类**`Use``range` 用于辅助实现 IR 的数据结构和遍历。
这个头文件定义了一个完整的 IR 数据结构,适用于编译器前端将 AST 转换为中间代码,并支持后续的优化和目标代码生成。

156
doc/markdowns/IRbuilder.md Normal file
View File

@@ -0,0 +1,156 @@
`IRBuilder.h` 文件定义了一个 `IRBuilder`用于简化中间表示IR的构建过程。`IRBuilder` 提供了创建各种 IR 指令的便捷方法,并将这些指令插入到指定的基本块中。以下是对文件中主要内容的整理和解释:
---
### **1. `IRBuilder` 类的作用**
`IRBuilder` 是一个工具类用于在生成中间表示IR时简化指令的创建和插入操作。它的主要功能包括
- 提供创建各种 IR 指令的工厂方法。
- 将创建的指令插入到指定的基本块中。
- 支持在基本块的任意位置插入指令。
---
### **2. 主要成员**
#### **2.1 成员变量**
- **`block`**:当前操作的基本块。
- **`position`**:当前操作的插入位置(基本块中的迭代器)。
#### **2.2 构造函数**
- **默认构造函数**`IRBuilder()`
- **带参数的构造函数**
- `IRBuilder(BasicBlock *block)`:初始化 `IRBuilder`,并设置当前基本块和插入位置(默认在基本块末尾)。
- `IRBuilder(BasicBlock *block, BasicBlock::iterator position)`:初始化 `IRBuilder`,并设置当前基本块和插入位置。
#### **2.3 设置方法**
- **`setPosition(BasicBlock *block, BasicBlock::iterator position)`**:设置当前基本块和插入位置。
- **`setPosition(BasicBlock::iterator position)`**:设置当前插入位置。
#### **2.4 获取方法**
- **`getBasicBlock()`**:获取当前基本块。
- **`getPosition()`**:获取当前插入位置。
---
### **3. 指令创建方法**
`IRBuilder` 提供了多种工厂方法,用于创建不同类型的 IR 指令。这些方法会将创建的指令插入到当前基本块的指定位置。
#### **3.1 函数调用指令**
- **`createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name)`**
- 创建一个函数调用指令。
- 参数:
- `callee`:被调用的函数。
- `args`:函数参数列表。
- `name`:指令的名称(可选)。
- 返回:`CallInst*`
#### **3.2 一元操作指令**
- **`createUnaryInst(Instruction::Kind kind, Type *type, Value *operand, const std::string &name)`**
- 创建一个一元操作指令(如取反、类型转换)。
- 参数:
- `kind`:指令的类型(如 `kNeg``kFtoI` 等)。
- `type`:指令的结果类型。
- `operand`:操作数。
- `name`:指令的名称(可选)。
- 返回:`UnaryInst*`
- **具体一元操作指令**
- `createNegInst(Value *operand, const std::string &name)`:创建整数取反指令。
- `createNotInst(Value *operand, const std::string &name)`:创建逻辑取反指令。
- `createFtoIInst(Value *operand, const std::string &name)`:创建浮点数转整数指令。
- `createFNegInst(Value *operand, const std::string &name)`:创建浮点数取反指令。
- `createIToFInst(Value *operand, const std::string &name)`:创建整数转浮点数指令。
#### **3.3 二元操作指令**
- **`createBinaryInst(Instruction::Kind kind, Type *type, Value *lhs, Value *rhs, const std::string &name)`**
- 创建一个二元操作指令(如加法、减法)。
- 参数:
- `kind`:指令的类型(如 `kAdd``kSub` 等)。
- `type`:指令的结果类型。
- `lhs``rhs`:左操作数和右操作数。
- `name`:指令的名称(可选)。
- 返回:`BinaryInst*`
- **具体二元操作指令**
- 整数运算:
- `createAddInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数加法指令。
- `createSubInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数减法指令。
- `createMulInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数乘法指令。
- `createDivInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数除法指令。
- `createRemInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数取余指令。
- 整数比较:
- `createICmpEQInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数相等比较指令。
- `createICmpNEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数不等比较指令。
- `createICmpLTInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数小于比较指令。
- `createICmpLEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数小于等于比较指令。
- `createICmpGTInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数大于比较指令。
- `createICmpGEInst(Value *lhs, Value *rhs, const std::string &name)`:创建整数大于等于比较指令。
- 浮点数运算:
- `createFAddInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数加法指令。
- `createFSubInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数减法指令。
- `createFMulInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数乘法指令。
- `createFDivInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数除法指令。
- `createFRemInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数取余指令。
- 浮点数比较:
- `createFCmpEQInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数相等比较指令。
- `createFCmpNEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数不等比较指令。
- `createFCmpLTInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数小于比较指令。
- `createFCmpLEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数小于等于比较指令。
- `createFCmpGTInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数大于比较指令。
- `createFCmpGEInst(Value *lhs, Value *rhs, const std::string &name)`:创建浮点数大于等于比较指令。
#### **3.4 控制流指令**
- **`createReturnInst(Value *value)`**
- 创建返回指令。
- 参数:
- `value`:返回值(可选)。
- 返回:`ReturnInst*`
- **`createUncondBrInst(BasicBlock *block, std::vector<Value *> args)`**
- 创建无条件跳转指令。
- 参数:
- `block`:目标基本块。
- `args`:跳转参数(可选)。
- 返回:`UncondBrInst*`
- **`createCondBrInst(Value *condition, BasicBlock *thenBlock, BasicBlock *elseBlock, const std::vector<Value *> &thenArgs, const std::vector<Value *> &elseArgs)`**
- 创建条件跳转指令。
- 参数:
- `condition`:跳转条件。
- `thenBlock`:条件为真时的目标基本块。
- `elseBlock`:条件为假时的目标基本块。
- `thenArgs``elseArgs`:跳转参数(可选)。
- 返回:`CondBrInst*`
#### **3.5 内存操作指令**
- **`createAllocaInst(Type *type, const std::vector<Value *> &dims, const std::string &name)`**
- 创建栈内存分配指令。
- 参数:
- `type`:分配的类型。
- `dims`:数组维度(可选)。
- `name`:指令的名称(可选)。
- 返回:`AllocaInst*`
- **`createLoadInst(Value *pointer, const std::vector<Value *> &indices, const std::string &name)`**
- 创建加载指令。
- 参数:
- `pointer`:指针值。
- `indices`:数组索引(可选)。
- `name`:指令的名称(可选)。
- 返回:`LoadInst*`
- **`createStoreInst(Value *value, Value *pointer, const std::vector<Value *> &indices, const std::string &name)`**
- 创建存储指令。
- 参数:
- `value`:要存储的值。
- `pointer`:指针值。
- `indices`:数组索引(可选)。
- `name`:指令的名称(可选)。
- 返回:`StoreInst*`
---
### **4. 总结**
- `IRBuilder` 是一个用于简化 IR 构建的工具类,提供了创建各种 IR 指令的工厂方法。
- 通过 `IRBuilder`,可以方便地在指定基本块的任意位置插入指令。
- 该类的设计使得 IR 的生成更加模块化和易于维护。

121
doc/markdowns/IRcpp.md Normal file
View File

@@ -0,0 +1,121 @@
这个 `IR.cpp` 文件实现了 `IR.h` 中定义的中间表示IR数据结构的功能。它包含了类型系统、值、指令、基本块、函数和模块的具体实现以及一些辅助函数用于打印 IR 的内容。以下是对文件中主要内容的整理和解释:
---
### **1. 辅助函数**
#### **1.1 `interleave` 函数**
- **作用**:用于在输出流中插入分隔符(如逗号)来打印容器中的元素。
- **示例**
```cpp
interleave(os, container, ", ");
```
#### **1.2 打印函数**
- **`printVarName`**:打印变量名,全局变量以 `@` 开头,局部变量以 `%` 开头。
- **`printBlockName`**:打印基本块名,以 `^` 开头。
- **`printFunctionName`**:打印函数名,以 `@` 开头。
- **`printOperand`**:打印操作数,如果是常量则直接打印值,否则打印变量名。
---
### **2. 类型系统**
#### **2.1 `Type` 类的实现**
- **静态方法**
- `getIntType()`、`getFloatType()`、`getVoidType()`、`getLabelType()`:返回对应类型的单例对象。
- `getPointerType(Type *baseType)`:返回指向 `baseType` 的指针类型。
- `getFunctionType(Type *returnType, const vector<Type *> &paramTypes)`:返回函数类型。
- **`getSize()`**:返回类型的大小(如 `int` 和 `float` 为 4 字节,指针为 8 字节)。
- **`print()`**:打印类型的表示。
#### **2.2 `PointerType` 类的实现**
- **静态方法**
- `get(Type *baseType)`:返回指向 `baseType` 的指针类型,使用 `std::map` 缓存已创建的指针类型。
- **`getBaseType()`**:返回指针指向的基础类型。
#### **2.3 `FunctionType` 类的实现**
- **静态方法**
- `get(Type *returnType, const vector<Type *> &paramTypes)`:返回函数类型,使用 `std::set` 缓存已创建的函数类型。
- **`getReturnType()`** 和 `getParamTypes()`:分别返回函数的返回类型和参数类型列表。
---
### **3. 值Value**
#### **3.1 `Value` 类的实现**
- **`replaceAllUsesWith(Value *value)`**:将该值的所有用途替换为另一个值。
- **`isConstant()`**:判断值是否为常量(包括常量值、全局值和函数)。
#### **3.2 `ConstantValue` 类的实现**
- **静态方法**
- `get(int value)``get(float value)`:返回整数或浮点数常量,使用 `std::map` 缓存已创建的常量。
- **`getInt()``getFloat()`**:返回常量的值。
- **`print()`**:打印常量的值。
#### **3.3 `Argument` 类的实现**
- **构造函数**:初始化参数的类型、所属基本块和索引。
- **`print()`**:打印参数的表示。
---
### **4. 基本块BasicBlock**
#### **4.1 `BasicBlock` 类的实现**
- **构造函数**:初始化基本块的名称和所属函数。
- **`print()`**:打印基本块的表示,包括参数和指令。
---
### **5. 指令Instruction**
#### **5.1 `Instruction` 类的实现**
- **构造函数**:初始化指令的类型、所属基本块和名称。
- **`print()`**:由具体指令类实现。
#### **5.2 具体指令类的实现**
- **`CallInst`**:表示函数调用指令。
- **`print()`**:打印函数调用的表示。
- **`UnaryInst`**:表示一元操作指令(如取反、类型转换)。
- **`print()`**:打印一元操作的表示。
- **`BinaryInst`**:表示二元操作指令(如加法、减法)。
- **`print()`**:打印二元操作的表示。
- **`ReturnInst`**:表示返回指令。
- **`print()`**:打印返回指令的表示。
- **`UncondBrInst`**:表示无条件跳转指令。
- **`print()`**:打印无条件跳转的表示。
- **`CondBrInst`**:表示条件跳转指令。
- **`print()`**:打印条件跳转的表示。
- **`AllocaInst`**:表示栈内存分配指令。
- **`print()`**:打印内存分配的表示。
- **`LoadInst`**:表示从内存加载值的指令。
- **`print()`**:打印加载指令的表示。
- **`StoreInst`**:表示将值存储到内存的指令。
- **`print()`**:打印存储指令的表示。
---
### **6. 函数Function**
#### **6.1 `Function` 类的实现**
- **构造函数**:初始化函数的名称、返回类型和参数类型。
- **`print()`**:打印函数的表示,包括基本块和指令。
---
### **7. 模块Module**
#### **7.1 `Module` 类的实现**
- **`print()`**:打印模块的表示,包括所有函数和全局变量。
---
### **8. 用户User**
#### **8.1 `User` 类的实现**
- **`setOperand(int index, Value *value)`**:设置指定索引的操作数。
- **`replaceOperand(int index, Value *value)`**:替换指定索引的操作数,并更新用途列表。
---
### **9. 总结**
- **类型系统**:实现了 `Type``PointerType``FunctionType`,用于表示 IR 中的类型。
- **值**:实现了 `Value``ConstantValue``Argument`,用于表示 IR 中的值和参数。
- **基本块**:实现了 `BasicBlock`,用于组织指令。
- **指令**:实现了多种具体指令类(如 `CallInst``BinaryInst` 等),用于表示 IR 中的操作。
- **函数和模块**:实现了 `Function``Module`,用于组织 IR 的结构。
- **打印功能**:通过 `print()` 方法,可以将 IR 的内容输出为可读的文本格式。
这个文件是编译器中间表示的核心实现能够将抽象语法树AST转换为中间代码并支持后续的优化和目标代码生成。

View File

@@ -124,7 +124,7 @@ std::any ASTPrinter::visitFuncFParam(SysYParser::FuncFParamContext *ctx){
}
std::any ASTPrinter::visitBlockStmt(SysYParser::BlockStmtContext *ctx){
cout << ' ' << ctx->LBRACE()->getText() << endl;
cout << ctx->LBRACE()->getText() << endl;
indentLevel++;
for (auto item : ctx->blockItem()) item->accept(this);
indentLevel--;
@@ -133,69 +133,70 @@ std::any ASTPrinter::visitBlockStmt(SysYParser::BlockStmtContext *ctx){
}
// std::any ASTPrinter::visitBlockItem(SysYParser::BlockItemContext *ctx);
std::any ASTPrinter::visitStmt(SysYParser::StmtContext *ctx){
if(ctx->lValue()&& ctx->exp()) {
cout << getIndent();
ctx->lValue()->accept(this);
cout << ' ' << ctx->ASSIGN()->getText() <<' ';
std::any ASTPrinter::visitAssignStmt(SysYParser::AssignStmtContext *ctx){
cout << getIndent();
ctx->lValue()->accept(this);
cout << ' ' << ctx->ASSIGN()->getText() << ' ';
ctx->exp()->accept(this);
cout << ctx->SEMICOLON()->getText() << '\n';
return nullptr;
}
std::any ASTPrinter::visitExpStmt(SysYParser::ExpStmtContext *ctx){
cout << getIndent();
if (ctx->exp()) {
ctx->exp()->accept(this);
cout << ctx->SEMICOLON()->getText() << endl;
}
else if(ctx->blockStmt()){
ctx->blockStmt()->accept(this);
cout << ctx->SEMICOLON()->getText() << '\n';
return nullptr;
}
std::any ASTPrinter::visitIfStmt(SysYParser::IfStmtContext *ctx){
cout << getIndent() << ctx->IF()->getText() << ' ' << ctx->LPAREN()->getText();
ctx->cond()->accept(this);
cout << ctx->RPAREN()->getText() << ' ';
//格式化有问题
if(ctx->stmt(0)) {
ctx->stmt(0)->accept(this);
}
else if(ctx->IF()){
cout << getIndent() << "if (";
ctx->cond()->accept(this);
cout << ")";
// visit ctx->stmt(0) to judge if it is a blockStmt or a Lvale=exp
if(ctx->stmt(0)->blockStmt())ctx->stmt(0)->accept(this);
else{
cout << " {"<< endl;
indentLevel++;
ctx->stmt(0)->accept(this);
indentLevel--;
cout << getIndent() << "}" << endl;
}
if (ctx->stmt().size() > 1) {
cout << getIndent() << "else";
if(ctx->stmt(1)->blockStmt())ctx->stmt(1)->accept(this);
else{
cout << " {"<< endl;
indentLevel++;
ctx->stmt(1)->accept(this);
indentLevel--;
cout << getIndent() << "}" << endl;
}
}
else {
cout << '{' << endl;
indentLevel++;
ctx->stmt(0)->accept(this);
indentLevel--;
cout << getIndent() << '}' << endl;
}
else if(ctx->WHILE()){
cout << getIndent() << "while (";
ctx->cond()->accept(this);
cout << ")";
if(ctx->stmt(0)->blockStmt())ctx->stmt(0)->accept(this);
else{
cout << " {"<< endl;
indentLevel++;
ctx->stmt(0)->accept(this);
indentLevel--;
cout << getIndent() << "}" << endl;
}
if (ctx->ELSE()) {
cout << getIndent() << ctx->ELSE()->getText() << ' ';
ctx->stmt(1)->accept(this);
}
else if(ctx->BREAK()){
cout << getIndent() << "break;" << endl;
}
else if(ctx->CONTINUE()){
cout << getIndent() << "continue;" << endl;
}
else if(ctx->RETURN()){
cout << getIndent() << "return";
if(ctx->exp()){
cout << ' ';
ctx->exp()->accept(this);
}
cout << ctx->SEMICOLON()->getText() << endl;
return nullptr;
}
std::any ASTPrinter::visitWhileStmt(SysYParser::WhileStmtContext *ctx){
cout << getIndent() << ctx->WHILE()->getText() << ' ' << ctx->LPAREN()->getText();
ctx->cond()->accept(this);
cout << ctx->RPAREN()->getText() << ' ';
ctx->stmt()->accept(this);
return nullptr;
}
std::any ASTPrinter::visitBreakStmt(SysYParser::BreakStmtContext *ctx){
cout << getIndent() << ctx->BREAK()->getText() << ctx->SEMICOLON()->getText() << '\n';
return nullptr;
}
std::any ASTPrinter::visitContinueStmt(SysYParser::ContinueStmtContext *ctx){
cout << getIndent() << ctx->CONTINUE()->getText() << ctx->SEMICOLON()->getText() << '\n';
return nullptr;
}
std::any ASTPrinter::visitReturnStmt(SysYParser::ReturnStmtContext *ctx){
cout << getIndent() << ctx->RETURN()->getText() << ' ';
if (ctx->exp()) {
ctx->exp()->accept(this);
}
cout << ctx->SEMICOLON()->getText() << '\n';
return nullptr;
}
@@ -211,6 +212,12 @@ std::any ASTPrinter::visitLValue(SysYParser::LValueContext *ctx){
return nullptr;
}
// std::any ASTPrinter::visitPrimaryExp(SysYParser::PrimaryExpContext *ctx);
std::any ASTPrinter::visitParenExp(SysYParser::ParenExpContext *ctx){
cout << ctx->LPAREN()->getText();
ctx->exp()->accept(this);
cout << ctx->RPAREN()->getText();
return nullptr;
}
std::any ASTPrinter::visitNumber(SysYParser::NumberContext *ctx) {
if(ctx->ILITERAL())cout << ctx->ILITERAL()->getText();
@@ -222,28 +229,15 @@ std::any ASTPrinter::visitString(SysYParser::StringContext *ctx) {
cout << ctx->STRING()->getText();
return nullptr;
}
std::any ASTPrinter::visitUnaryExp(SysYParser::UnaryExpContext *ctx){
if(ctx->primaryExp())
ctx->primaryExp()->accept(this);
else if(ctx->Ident()){
cout << ctx->Ident()->getText() << ctx->LPAREN()->getText();
if(ctx->funcRParams())
ctx->funcRParams()->accept(this);
if (ctx->RPAREN())
cout << ctx->RPAREN()->getText();
else
cout << "<missing \')\'?>";
}
else if(ctx->unaryExp()){
cout << ctx->unaryOp()->getText();
ctx->unaryExp()->accept(this);
}
else
ctx->accept(this);
// std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx);
// std::any ASTPrinter::visitUnaryOp(SysYParser::UnaryOpContext *ctx);
std::any ASTPrinter::visitCall(SysYParser::CallContext *ctx){
cout << ctx->Ident()->getText() << ctx->LPAREN()->getText();
if(ctx->funcRParams())
ctx->funcRParams()->accept(this);
cout << ctx->RPAREN()->getText();
return nullptr;
}
// std::any ASTPrinter::visitUnaryOp(SysYParser::UnaryOpContext *ctx);
any ASTPrinter::visitFuncRParams(SysYParser::FuncRParamsContext *ctx) {
if (ctx->exp().empty())

View File

@@ -25,15 +25,28 @@ public:
std::any visitFuncFParams(SysYParser::FuncFParamsContext *ctx) override;
std::any visitFuncFParam(SysYParser::FuncFParamContext *ctx) override;
std::any visitBlockStmt(SysYParser::BlockStmtContext *ctx) override;
// std::any visitBlockItem(SysYParser::BlockItemContext *ctx) override;
std::any visitStmt(SysYParser::StmtContext *ctx) override;
// std::any visitStmt(SysYParser::StmtContext *ctx) override;
std::any visitAssignStmt(SysYParser::AssignStmtContext *ctx) override;
std::any visitExpStmt(SysYParser::ExpStmtContext *ctx) override;
std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override;
std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override;
std::any visitBreakStmt(SysYParser::BreakStmtContext *ctx) override;
std::any visitContinueStmt(SysYParser::ContinueStmtContext *ctx) override;
std::any visitReturnStmt(SysYParser::ReturnStmtContext *ctx) override;
// std::any visitExp(SysYParser::ExpContext *ctx) override;
// std::any visitCond(SysYParser::CondContext *ctx) override;
std::any visitLValue(SysYParser::LValueContext *ctx) override;
// std::any visitPrimaryExp(SysYParser::PrimaryExpContext *ctx) override;
std::any visitParenExp(SysYParser::ParenExpContext *ctx) override;
std::any visitNumber(SysYParser::NumberContext *ctx) override;
std::any visitString(SysYParser::StringContext *ctx) override;
std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override;
// std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override;
std::any visitCall(SysYParser::CallContext *ctx) override;
// std::any visitUnExpOp(SysYParser::UnExpContext *ctx) override;
// std::any visitUnaryOp(SysYParser::UnaryOpContext *ctx) override;
std::any visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override;
std::any visitMulExp(SysYParser::MulExpContext *ctx) override;

View File

@@ -136,29 +136,29 @@ blockStmt: LBRACE blockItem* RBRACE;
blockItem: decl | stmt;
stmt: lValue ASSIGN exp SEMICOLON
| exp? SEMICOLON
| blockStmt
| IF LPAREN cond RPAREN stmt (ELSE stmt)?
| WHILE LPAREN cond RPAREN stmt
| BREAK SEMICOLON
| CONTINUE SEMICOLON
| RETURN exp? SEMICOLON;
stmt: lValue ASSIGN exp SEMICOLON #assignStmt
| exp? SEMICOLON #expStmt
| blockStmt #blkStmt
| IF LPAREN cond RPAREN stmt (ELSE stmt)? #ifStmt
| WHILE LPAREN cond RPAREN stmt #whileStmt
| BREAK SEMICOLON #breakStmt
| CONTINUE SEMICOLON #continueStmt
| RETURN exp? SEMICOLON #returnStmt;
exp: addExp;
cond: lOrExp;
lValue: Ident (LBRACK exp RBRACK)*;
// 为了方便测试 primaryExp 可以是一个string
primaryExp: LPAREN exp RPAREN
| lValue
| number
| string;
primaryExp: LPAREN exp RPAREN #parenExp
| lValue #lVal
| number #num
| string #str;
number: ILITERAL | FLITERAL;
unaryExp: primaryExp
| Ident LPAREN (funcRParams)? RPAREN
| unaryOp unaryExp;
unaryExp: primaryExp #primExp
| Ident LPAREN (funcRParams)? RPAREN #call
| unaryOp unaryExp #unExp;
unaryOp: ADD|SUB|NOT;
funcRParams: exp (COMMA exp)*;

File diff suppressed because it is too large Load Diff

View File

@@ -5,13 +5,88 @@
#include "SysYBaseVisitor.h"
#include "SysYParser.h"
#include <memory>
#include <unordered_map>
#include <forward_list>
namespace sysy {
class SymbolTable{
private:
enum Kind
{
kModule,
kFunction,
kBlock,
};
std::forward_list<std::pair<Kind, std::unordered_map<std::string, Value*>>> Scopes;
public:
struct ModuleScope {
SymbolTable& tables_ref;
ModuleScope(SymbolTable& tables) : tables_ref(tables) {
tables.enter(kModule);
}
~ModuleScope() { tables_ref.exit(); }
};
struct FunctionScope {
SymbolTable& tables_ref;
FunctionScope(SymbolTable& tables) : tables_ref(tables) {
tables.enter(kFunction);
}
~FunctionScope() { tables_ref.exit(); }
};
struct BlockScope {
SymbolTable& tables_ref;
BlockScope(SymbolTable& tables) : tables_ref(tables) {
tables.enter(kBlock);
}
~BlockScope() { tables_ref.exit(); }
};
SymbolTable() = default;
bool isModuleScope() const { return Scopes.front().first == kModule; }
bool isFunctionScope() const { return Scopes.front().first == kFunction; }
bool isBlockScope() const { return Scopes.front().first == kBlock; }
Value *lookup(const std::string &name) const {
for (auto &scope : Scopes) {
auto iter = scope.second.find(name);
if (iter != scope.second.end())
return iter->second;
}
return nullptr;
}
auto insert(const std::string &name, Value *value) {
assert(not Scopes.empty());
return Scopes.front().second.emplace(name, value);
}
private:
void enter(Kind kind) {
Scopes.emplace_front();
Scopes.front().first = kind;
}
void exit() {
Scopes.pop_front();
}
};
class SysYIRGenerator : public SysYBaseVisitor {
private:
std::unique_ptr<Module> module;
IRBuilder builder;
SymbolTable symbols_table;
int trueBlockNum = 0, falseBlockNum = 0;
int d = 0, n = 0;
vector<int> path;
bool isalloca;
AllocaInst *current_alloca;
GlobalValue *current_global;
Type* current_type;
int numdims = 0;
public:
SysYIRGenerator() = default;
@@ -21,9 +96,55 @@ public:
public:
std::any visitCompUnit(SysYParser::CompUnitContext *ctx) override;
std::any visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override;
std::any visitDecl(SysYParser::DeclContext *ctx) override;
std::any visitConstDecl(SysYParser::ConstDeclContext *ctx) override;
std::any visitBType(SysYParser::BTypeContext *ctx) override;
std::any visitConstDef(SysYParser::ConstDefContext *ctx) override;
std::any visitConstInitVal(SysYParser::ConstInitValContext *ctx) override;
std::any visitFuncType(SysYParser::FuncTypeContext* ctx) override;
std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override;
std::any visitVarDecl(SysYParser::VarDeclContext *ctx) override;
std::any visitVarDef(SysYParser::VarDefContext *ctx) override;
std::any visitInitVal(SysYParser::InitValContext *ctx) override;
// std::any visitFuncFParam(SysYParser::FuncFParamContext *ctx) override;
// std::any visitFuncFParams(SysYParser::FuncFParamsContext *ctx) override;
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override;
// std::any visitStmt(SysYParser::StmtContext *ctx) override;
std::any visitAssignStmt(SysYParser::AssignStmtContext *ctx) override;
std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override;
std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override;
std::any visitBreakStmt(SysYParser::BreakStmtContext *ctx) override;
std::any visitContinueStmt(SysYParser::ContinueStmtContext *ctx) override;
std::any visitReturnStmt(SysYParser::ReturnStmtContext *ctx) override;
// std::any visitExp(SysYParser::ExpContext *ctx) override;
std::any visitLValue(SysYParser::LValueContext *ctx) override;
std::any visitPrimExp(SysYParser::PrimExpContext *ctx) override;
// std::any visitParenExp(SysYParser::ParenExpContext *ctx) override;
std::any visitNumber(SysYParser::NumberContext *ctx) override;
std::any visitString(SysYParser::StringContext *ctx) override;
// std::any visitString(SysYParser::StringContext *ctx) override;
std::any visitCall(SysYParser::CallContext *ctx) override;
// std::any visitUnaryExp(SysYParser::UnaryExpContext *ctx) override;
// std::any visitUnaryOp(SysYParser::UnaryOpContext *ctx) override;
std::any visitUnExp(SysYParser::UnExpContext *ctx) override;
// std::any visitFuncRParams(SysYParser::FuncRParamsContext *ctx) override;
std::any visitMulExp(SysYParser::MulExpContext *ctx) override;
std::any visitAddExp(SysYParser::AddExpContext *ctx) override;
std::any visitRelExp(SysYParser::RelExpContext *ctx) override;
std::any visitEqExp(SysYParser::EqExpContext *ctx) override;
std::any visitLAndExp(SysYParser::LAndExpContext *ctx) override;
std::any visitLOrExp(SysYParser::LOrExpContext *ctx) override;
std::any visitConstExp(SysYParser::ConstExpContext *ctx) override;
private:
std::any visitConstGlobalDecl(SysYParser::ConstDeclContext *ctx, Type* type);
std::any visitVarGlobalDecl(SysYParser::VarDeclContext *ctx, Type* type);
std::any visitConstLocalDecl(SysYParser::ConstDeclContext *ctx, Type* type);
std::any visitVarLocalDecl(SysYParser::VarDeclContext *ctx, Type* type);
Type *getArithmeticResultType(Type *lhs, Type *rhs) {
assert(lhs->isIntOrFloat() and rhs->isIntOrFloat());
return lhs == rhs ? lhs : Type::getFloatType();
}
}; // class SysYIRGenerator
} // namespace sysy