diff --git a/README.md b/README.md index aae4b33..c094f57 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # PW6 实验文档 -本实验由黄庄湫、吴毓辰助教设计 - [PW6 实验文档](#pw6-实验文档) - [0. 前言](#0-前言) - [主要工作](#主要工作) @@ -95,12 +94,12 @@ * 实验要求、问题回答、实验设计、实验难点及解决方案、实验总结、实验反馈、组间交流(具体参考[report.md](./report.md)) * 本次实验报告**参与**评分标准. * 提交规范: - * 不破坏目录结构(`report.md`如果需要放图片,请新建`figs`文件夹放在`./report`下) + * 不破坏目录结构(`report.md`如果需要放图片,请新建`figs`文件夹放在`./report`下,并将图片放在`figs`文件夹内) * 不上传临时文件(凡是自动生成的文件和临时文件请不要上传) * **组队实验要求** * 由队长在 `./report/contribution.md` 中解释每位队员的贡献,并说明贡献比例 * 组队实验意味着合作,但是小组间的交流是受限的,且**严格禁止**代码的共享。除此之外,如果小组和其它组进行了交流,必须在 `./report/report.md` 中记录交流的小组和你们之间交流内容 -* 评分标准: 本次实验分为3部分, 为组队实验, 请合理安排分工, 我们会根据组长填写的贡献比进行分数分配,如果对贡献比有异议的组员可根据git的提交记录申请仲裁,建议利用好`git branch` +* 评分标准: 本次实验分为3部分, 为组队实验, 请合理安排分工, 我们会根据组长填写的贡献比进行分数分配,如果对贡献比有异议的组员可根据git的提交记录申请仲裁,建议利用好git的分支功能 * **禁止执行恶意代码,违者本次实验0分处理** * 第一部分10分: `.ll`运行结果正确(1个2分, 注释共2分) * 第二部分20分: `.cpp`运行结果正确(1个5分) diff --git a/doc/phase1.md b/doc/phase1.md index 9c8039f..936a44f 100644 --- a/doc/phase1.md +++ b/doc/phase1.md @@ -1,33 +1,68 @@ -# IR实验阶段一 -本实验由黄庄湫、吴毓辰助教设计 +[TOC] -## 0 前言 -本次实验的目的是让大家熟悉阶段三所需相关知识: -LLVM IR +--- -## 1 任务描述 -[了解LLVM IR](#llvm-ir介绍) -[通过clang生成的.ll,了解LLVM IR与c代码的对应关系](#例子-利用clang生成的ll) -[根据c程序手写.ll文件实现相同功能](#你需要做-手动编写ll) +### 任务描述 +本关任务:熟悉LLVM IR,并根据给出的4个sy程序手写ll文件以实现相同功能。 -## 2 实验内容 -### 2.1 LLVM IR介绍 +### 相关知识 +#### LLVM IR介绍 根据[维基百科](https://zh.wikipedia.org/zh-cn/LLVM)的介绍,LLVM是一个自由软件项目,它是一种编译器基础设施,以C++写成,包含一系列模块化的编译器组件和工具链,用来开发编译器前端和后端。IR的全称是Intermediate Representation,即中间表示。LLVM IR是一种类似于汇编的底层语言。 -LLVM IR的具体指令可以参考[Reference Manual](http://llvm.org/docs/LangRef.html)。但是你会发现其内容庞杂。虽然助教认为,高效地查阅官方文档及手册是非常必要的一项技能,但是由于其手册过于复杂,因此助教筛选了后续实验中将要用到的子集,总结为了[精简的IR Reference手册](./SysYIR.md)。 +LLVM IR的具体指令可以参考[Reference Manual](http://llvm.org/docs/LangRef.html)。但是你会发现其内容庞杂。虽然助教认为,高效地查阅官方文档及手册是非常必要的一项技能,但是由于其手册过于复杂,因此助教筛选了后续实验中将要用到的子集,总结为了**精简的IR Reference手册**`doc/SysYIR.md`。 作为一开始的参考,你可以先阅读其中`IR Features`和`IR Format`两节,后续有需要再反复参考。 -### 2.2 例子: 利用clang生成的.ll -阅读`SysYF_Student/SysYF_Task1/ta_demo/go_upstairs.c` -在对应文件夹内输入`clang -S -emit-llvm go_upstairs.c`指令,你可以得到对应的`go_upstairs.ll` -你需要结合`go_upstairs.c`阅读`go_upstairs.ll`,理解其中每条LLVM IR指令与c代码的对应情况。 +#### 样例学习 +
+ go_upstairs.c(点击展开) + +```c +int num[2] = {4, 8}; +int x[1]; +int n; +int tmp = 1; + +int climbStairs(int n) { + if(n < 4) + return n; + int dp[10]; + dp[0] = 0; + dp[1] = 1; + dp[2] = 2; + int i; + i = 3; + while(i + +阅读`SysYF_Student/SysYF_Task1/ta_demo/go_upstairs.c`。 +在`SysYF_Student/SysYF_Task1/ta_demo`文件夹内输入`clang -S -emit-llvm go_upstairs.c`指令,你可以得到对应的`go_upstairs.ll`。 +你需要结合`go_upstairs.c`阅读`go_upstairs.ll`,理解其中每条LLVM IR指令与C代码的对应情况。 通过`lli go_upstairs.ll; echo $?`指令,你可以测试`go_upstairs.ll`执行结果的正确性。 -### 2.3 你需要做: 手动编写.ll -助教在`SysYF_Student/SysYF_Task1/student_sy/`内提供了四个简单的sy程序:assign_test.sy,func_test.sy,if_test.sy,while_test.sy -你需要在`SysYF_Student/SysYF_Task1/student_ll/`内手工完成自己的assign_test.ll,func_test.ll,if_test.ll,while_test.ll文件,以实现与上述C程序相同的逻辑功能。你需要添加必要的注释,`.ll`文件的注释是以`;`开头的 -必要的情况下,你可以参考`clang -S -emit-llvm`的输出,但是你提交的结果必须避免同此输出一字不差 -注:`.sy`文件是我们定义的语言文件,`clang`无法直接识别 +### 本关具体任务 +1. 助教在`SysYF_Student/SysYF_Task1/student_sy/`内提供了四个简单的sy程序:`assign_test.sy`,`func_test.sy`,`if_test.sy`,`while_test.sy`。 +你需要在`SysYF_Student/SysYF_Task1/student_ll/`内手工完成自己的`assign_test.ll`,`func_test.ll`,`if_test.ll`,`while_test.ll`文件,以实现与上述C程序相同的逻辑功能。 +你需要在`ll`文件内添加必要的注释,`ll`文件的注释是以`;`开头的。 +必要的情况下,你可以参考`clang -S -emit-llvm`的输出,但是你提交的结果必须避免同此输出一字不差。 +2. 在`report.md`内回答[思考题](#思考题) -### 2.4 运行.ll文件 +### 运行说明 - `lli`会运行`*.ll`文件 -- `$?`的内容是上一条命令所返回的结果,而`echo $?`可以将其输出到终端中 \ No newline at end of file +- `$?`的内容是上一条命令所返回的结果,而`echo $?`可以将其输出到终端中 +- 使用`clang`时,注意`sy`文件是我们定义的语言文件,`clang`是无法直接识别的 + +### 思考题 +请在`report/report.md`中详细回答下述思考题。 \ No newline at end of file diff --git a/doc/phase2.md b/doc/phase2.md index db646d7..c0f140b 100644 --- a/doc/phase2.md +++ b/doc/phase2.md @@ -1,28 +1,110 @@ -# IR实验阶段二 -本实验由黄庄湫、吴毓辰助教设计 +[TOC] -## 0 前言 -本次实验的目的是让大家熟悉阶段三所需相关知识: -SysY IR(由助教编写的LLVM IR的轻量级C++接口)。 +--- -## 1 任务描述 -[了解SysY IR](#sysy-ir---llvm-ir的c接口) -[通过助教提供的C++例子,了解SysY IR的C++接口及实现](#例子-利用sysy-ir--cpp-生成ll) -[根据c程序手写C++文件调用SysY IR的API生成相同功能的.ll文件](#你需要做-利用sysy-ir--c编写生成ll的程序) +### 任务描述 +本关任务:熟悉SysY IR接口,并根据给出的4个C程序手写C++代码调用SysY IR接口生成与sy文件功能相同的ll文件。 -## 2 实验内容 -### 2.1 SysY IR - LLVM IR的C++接口 -由于LLVM IR官方的C++接口的文档同样过于冗长,助教提供了SysY IR这一C++接口库。你需要阅读[SysY IR核心类的介绍](./SysYIR.md)。 +### 相关知识 +#### SysY IR - LLVM IR的C++接口 +由于LLVM IR官方的C++接口的文档同样过于冗长,助教提供了SysY IR这一C++接口库。你需要阅读**SysY IR核心类的介绍**`doc/SysYIR.md`。 本关会要求大家通过SysY IR根据AST构建生成LLVM IR。所以你需要仔细阅读文档了解其接口的设计。 -### 2.2 例子: 利用SysY IR + C++ 生成.ll -为了让大家更直观地感受并学会LightIR接口的使用,助教提供了`SysYF_Student/SysYF_Task2/ta_demo/go_upstairs_gen.cpp`。 +#### 样例学习 +
+ go_upstairs_gen.cpp核心部分(点击展开) + +```cpp + // 全局数组,num,x + auto *arrayType_num = ArrayType::get(Int32Type, 2); + auto *arrayType_x = ArrayType::get(Int32Type, 1); + auto zero_initializer = ConstantZero::get(Int32Type, module); + std::vector init_val; + init_val.push_back(CONST_INT(4)); + init_val.push_back(CONST_INT(8)); + auto num_initializer = ConstantArray::get(arrayType_num, init_val); + auto num = GlobalVariable::create("num", module, arrayType_num, false, num_initializer);// 是否是常量定义,初始化常量(ConstantZero类) + auto x = GlobalVariable::create("x", module, arrayType_x, false, zero_initializer);// 参数解释: 名字name,所属module,全局变量类型type, + + auto n = GlobalVariable::create("n", module, Int32Type, false, zero_initializer); + auto tmp = GlobalVariable::create("tmp", module, Int32Type, false, CONST_INT(1)); + + // climbStairs函数 + // 函数参数类型的vector + std::vector Ints(1, Int32Type); + + //通过返回值类型与参数类型列表得到函数类型 + auto climbStairsFunTy = FunctionType::get(Int32Type, Ints); + + // 由函数类型得到函数 + auto climbStairsFun = Function::create(climbStairsFunTy, + "climbStairs", module); + + // BB的名字在生成中无所谓,但是可以方便阅读 + auto bb = BasicBlock::create(module, "entry", climbStairsFun); + + builder->set_insert_point(bb); // 一个BB的开始,将当前插入指令点的位置设在bb + + auto retAlloca = builder->create_alloca(Int32Type); // 在内存中分配返回值的位置 + auto nAlloca = builder->create_alloca(Int32Type); // 在内存中分配参数n的位置 + + std::vector args; // 获取climbStairs函数的形参,通过Function中的iterator + for (auto arg = climbStairsFun->arg_begin(); arg != climbStairsFun->arg_end(); arg++) { + args.push_back(*arg); // * 号运算符是从迭代器中取出迭代器当前指向的元素 + } + + builder->create_store(args[0], nAlloca); // store参数n + + auto retBB = BasicBlock::create( + module, "", climbStairsFun); // return分支,提前create,以便true分支可以br + + auto nLoad = builder->create_load(nAlloca); // 将参数n load上来 + auto icmp = builder->create_icmp_lt(nLoad, CONST_INT(4)); // n和4的比较,注意ICMPLT + + auto trueBB = BasicBlock::create(module, "trueBB_if", climbStairsFun); // true分支 + auto falseBB = BasicBlock::create(module, "falseBB_if", climbStairsFun); // false分支 + + builder->create_cond_br(icmp, trueBB, falseBB); // 条件BR + DEBUG_OUTPUT // 我调试的时候故意留下来的,以醒目地提醒你这个调试用的宏定义方法 + builder->set_insert_point(trueBB); // if true; 分支的开始需要SetInsertPoint设置 + nLoad = builder->create_load(nAlloca); + builder->create_store(nLoad, retAlloca); + builder->create_br(retBB); // br retBB + + builder->set_insert_point(falseBB); // if false + auto *arrayType_dp = ArrayType::get(Int32Type, 10); + auto dpAlloca = builder->create_alloca(arrayType_dp); + + auto dp0Gep = builder->create_gep(dpAlloca, {CONST_INT(0), CONST_INT(0)}); + builder->create_store(CONST_INT(0), dp0Gep); + + auto dp1Gep = builder->create_gep(dpAlloca, {CONST_INT(0), CONST_INT(1)}); + builder->create_store(CONST_INT(1), dp1Gep); + + auto dp2Gep = builder->create_gep(dpAlloca, {CONST_INT(0), CONST_INT(2)}); + builder->create_store(CONST_INT(2), dp2Gep); + + auto iAlloca = builder->create_alloca(Int32Type); + builder->create_store(CONST_INT(3), iAlloca); + + auto condBB = BasicBlock::create(module, "condBB_while", climbStairsFun); // 条件BB + trueBB = BasicBlock::create(module, "trueBB_while", climbStairsFun); // true分支 + falseBB = BasicBlock::create(module, "falseBB_while", climbStairsFun); // false分支 + + builder->create_br(condBB); + + builder->set_insert_point(condBB); + //后略, 详细见代码文件 +``` +
+为了让大家更直观地感受并学会SysY IR接口的使用,助教提供了`SysYF_Student/SysYF_Task2/ta_demo/go_upstairs_gen.cpp`。 该C++程序会生成与go_upstairs.c逻辑相同的LLVM IR文件。助教提供了详尽的注释,一定要好好利用! -### 2.3 你需要做: 利用SysY IR + C++编写生成.ll的程序 -你需要在`SysYF_Student/SysYF_Task2/student_cpp/`文件夹中,调用SysY IR接口,编写自己的assign_gen.cpp,func_gen.cpp,if_gen.cpp,while_gen.cpp程序,以生成与phase1的四个sy程序相同逻辑功能的`.ll`文件。 +### 本关具体任务 +1. 你需要在`SysYF_Student/SysYF_Task2/student_cpp/`文件夹中,调用SysY IR接口,编写自己的`assign_gen.cpp`,`func_gen.cpp`,`if_gen.cpp`,`while_gen.cpp`程序,以生成与phase1的四个sy程序相同逻辑功能的ll文件。 +2. 在`report.md`内回答[思考题](#思考题) -### 2.4 编译、运行和验证 +### 编译、运行和验证 在 `SysYF_Student/SysYF_Task2/build/` 下执行: ``` shell # 如果存在 CMakeCache.txt 要先删除 @@ -30,9 +112,16 @@ SysY IR(由助教编写的LLVM IR的轻量级C++接口)。 cmake .. make ``` -你可以得到对应`assign_gen.cpp`,`func_gen.cpp`,`if_gen.cpp`,`while_gen.cpp`,`go_upstairs_gen.cpp`的可执行文件`assign_generator`,`func_generator`,`if_generator`,`while_generator`,`go_upstairs_generator` -之后直接执行可执行文件即可得到对应`.ll`文件: +你可以得到对应`assign_gen.cpp`,`func_gen.cpp`,`if_gen.cpp`,`while_gen.cpp`,`go_upstairs_gen.cpp`的可执行文件`assign_generator`,`func_generator`,`if_generator`,`while_generator`,`go_upstairs_generator`。 +之后直接执行可执行文件即可得到对应ll文件: ``` shell # 在build文件夹内 ./go_upstairs_generator ``` + +### 思考题 +请在`report/report.md`中详细回答下述思考题。 + +1. 请给出`SysYIR.md`中提到的两种getelementptr用法的区别, 并解释原因: + - `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0` + - `%2 = getelementptr i32, i32* %1, i32 %0` \ No newline at end of file diff --git a/doc/phase3.md b/doc/phase3.md index 0f69f0a..fdab0cc 100644 --- a/doc/phase3.md +++ b/doc/phase3.md @@ -1,24 +1,15 @@ -# IR实验阶段三 -本实验由黄庄湫、吴毓辰助教设计 +[TOC] -## 0 前言 -本次实验我们要使用访问者模式来实现 IR 自动生成。 -对于产生的IR, 我们可以调用 clang 生成可执行文件,这样一个初级的 SysYF 编译器就完成啦! +--- -## 1 任务描述 - -阅读[SysYF 的语义规则](../SysYF语言定义.pdf),注意本次实验必做部分语言可能与前几次实验有不同 -阅读[SysY IR 核心类介绍](./SysYIR.md) -阅读[实验框架](#实验框架),理解如何使用框架以及注意事项 - -修改 `src/SysYBuilder/SysYBuilder.cpp` 来实现自动 IR 产生的算法,使得它能正确编译任何合法的 SysYF 程序 -注: 本次实验不需要实现多维数组 - -## 2 实验框架 +### 任务描述 +本关任务:编写`SysYBuilder.cpp`文件,以实现 IR 的自动生成 +### 相关知识 +#### 实验框架 本次实验使用了由 C++ 编写的 SysY IR 来生成 LLVM IR。为了便于大家进行实验,该框架自动完成了语法树到 C++ 上的抽象语法树的转换。 -在SysYBuilder.hpp中,我们还定义了一个用于存储作用域的类`Scope`。它的作用是辅助我们在遍历语法树时,管理不同作用域中的变量。它提供了以下接口: +在`SysYBuilder.hpp`中,我们还定义了一个用于存储作用域的类`Scope`。它的作用是辅助我们在遍历语法树时,管理不同作用域中的变量。它提供了以下接口: ```cpp // 进入一个新的作用域 void enter(); @@ -28,16 +19,19 @@ void exit(); bool push(std::string name, Value *val); // 根据名字,以及是否为函数的bool值寻找到对应值 // isfunc 为 true 时为寻找函数,否则为寻找其他变量对应的值 -// 思考:将函数单独处理的目的 Value* find(std::string name, bool isfunc); // 判断当前是否在全局作用域内 bool in_global(); ``` 你们需要根据语义合理调用`enter`与`exit`,并且在变量声明和使用时正确调用`push`与`find`。在类`SysYfBuilder`中,有一个`Scope`类型的成员变量`scope`,它在初始化时已经将特殊函数加入了作用域中。因此,你们在进行名字查找时不需要顾虑是否需要对特殊函数进行特殊操作。 -## 3 运行与调试 +### 本关具体任务 +1. 你需要在`src/SysYBuilder`文件夹中,调用SysY IR接口,填写`SysYBuilder.cpp`文件,以实现 IR 的自动生成。 +2. 在`report.md`内回答[思考题](#思考题) + +### 编译、运行与验证 -### 3.1 运行 SysYCompiler +#### 编译运行 SysYCompiler ```sh mkdir build @@ -46,29 +40,35 @@ cmake .. make ``` -编译后会产生 `SysYCompiler` 程序,它能将`.sy`文件输出为LLVM IR,可以利用clang将IR编译成二进制文件。 - -当需要对 `.sy` 文件测试时,可以这样使用: +编译后会产生 `SysYCompiler` 程序,它能将sy文件输出为LLVM IR。 +当需要对 sy 文件测试时,可以这样使用: ```sh SysYCompiler test.sy -emit-ir -o test.ll ``` +得到对应的ll文件。 -### 3.2 自动测试 +#### 自动测试 助教提供了自动评测脚本, 在`SysYF_Student/SysYF_Task3/Test_H/`目录下执行`python3 test_H.py`, 即可得到评测信息 -## 4 选做 +### 思考题 +请在`report/report.md`中详细回答下述思考题。 + +1. 在`scope`内单独处理`func`的好处有哪些。 +2. + +### 选做 对于学有余力的小组, 我们提供了选做环节, 若小组能完成选做部分, 将会有额外加分(仅针对本次实验的团队代码得分, 并且分数不能超过该部分得分上限) 选做部分验收方式为线下验收,你需要在线下检查时提供对应代码通过助教给出的选做部分测试样例,并且讲解你的代码 -选做部分说明如下: +选做部分说明如下: - 多维数组 -### 4.1 多维数组 +#### 多维数组 目前给出的SysY IR接口并不支持多维数组的实现,因此你需要修改接口,以实现多维数组的声明、初始化和使用,你可以修改的内容为文件夹`include/SysYIR`,`include/SysYBuilder`,`src/SysYIR`,`src/SysYBuilder`内的所有内容 @@ -80,8 +80,7 @@ SysYCompiler test.sy -emit-ir -o test.ll `int a[5][2] = {1,{2,3},{4},{5,6,7}}` `int a[5][2] = {{1,0},{2,3},{4,0},{5,6},{7,0}}` - -## 5 备注 +### 备注 测试样例并不止公开的20个样例, 助教准备了许多隐藏测例来考验大家:), 隐藏测例并不会放在平台上 diff --git a/report/report.md b/report/report.md index 64ff958..c43624a 100644 --- a/report/report.md +++ b/report/report.md @@ -4,10 +4,6 @@ ## 问题回答 -请给出`SysYIR.md`中提到的两种getelementptr用法的区别, 并解释原因: - - `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0` - - `%2 = getelementptr i32, i32* %1, i32 %0` - ## 实验设计 ## 实验难点及解决方案 diff --git a/src/SysYBuilder/SysYBuilder.cpp b/src/SysYBuilder/SysYBuilder.cpp index 8af141c..96b6944 100644 --- a/src/SysYBuilder/SysYBuilder.cpp +++ b/src/SysYBuilder/SysYBuilder.cpp @@ -3,7 +3,7 @@ #define CONST_INT(num) ConstantInt::get(num, module.get()) #define CONST_FLOAT(num) ConstantFloat::get(num, module.get()) -// You can define global variables here +// You can define global variables and functions here // to store state // store temporary value @@ -29,86 +29,46 @@ void SysYBuilder::visit(SyntaxTree::Assembly &node) { } } -void SysYBuilder::visit(SyntaxTree::InitVal &node) { - return; -} +// You need to fill them -void SysYBuilder::visit(SyntaxTree::FuncDef &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::InitVal &node) {} -void SysYBuilder::visit(SyntaxTree::FuncFParamList &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::FuncDef &node) {} -void SysYBuilder::visit(SyntaxTree::FuncParam &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::FuncFParamList &node) {} -void SysYBuilder::visit(SyntaxTree::VarDef &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::FuncParam &node) {} -void SysYBuilder::visit(SyntaxTree::AssignStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::VarDef &node) {} -void SysYBuilder::visit(SyntaxTree::LVal &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::LVal &node) {} -void SysYBuilder::visit(SyntaxTree::Literal &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::AssignStmt &node) {} -void SysYBuilder::visit(SyntaxTree::ReturnStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::Literal &node) {} -void SysYBuilder::visit(SyntaxTree::BlockStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::ReturnStmt &node) {} -void SysYBuilder::visit(SyntaxTree::EmptyStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::BlockStmt &node) {} -void SysYBuilder::visit(SyntaxTree::ExprStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::EmptyStmt &node) {} -void SysYBuilder::visit(SyntaxTree::UnaryCondExpr &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::ExprStmt &node) {} -void SysYBuilder::visit(SyntaxTree::BinaryCondExpr &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::UnaryCondExpr &node) {} -void SysYBuilder::visit(SyntaxTree::BinaryExpr &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::BinaryCondExpr &node) {} -void SysYBuilder::visit(SyntaxTree::UnaryExpr &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::BinaryExpr &node) {} -void SysYBuilder::visit(SyntaxTree::FuncCallStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::UnaryExpr &node) {} -void SysYBuilder::visit(SyntaxTree::IfStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::FuncCallStmt &node) {} -void SysYBuilder::visit(SyntaxTree::WhileStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::IfStmt &node) {} -void SysYBuilder::visit(SyntaxTree::BreakStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::WhileStmt &node) {} -void SysYBuilder::visit(SyntaxTree::ContinueStmt &node) { - return; -} +void SysYBuilder::visit(SyntaxTree::BreakStmt &node) {} + +void SysYBuilder::visit(SyntaxTree::ContinueStmt &node) {}