Commit 24af41cc authored by 李晓奇's avatar 李晓奇

finish part3: visitor pattern and the report.

parent 4b7accb1
1-parser/*.pdf 1-parser/*.pdf
2-ir-gen-warmup/*.pdf
# lab2 实验报告 # lab2 实验报告
学号 姓名
PB20111654 李晓奇
## 问题1: getelementptr ## 问题1: getelementptr
请给出 `IR.md` 中提到的两种 getelementptr 用法的区别,并稍加解释: 请给出 `IR.md` 中提到的两种 getelementptr 用法的区别,并稍加解释:
- `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0`
- `%2 = getelementptr i32, i32* %1 i32 %0` - `%2 = getelementptr [10 x i32], [10 x i32]* %1, i32 0, i32 %0`
%2是`i32*`类型。
我的理解是,这条指令相当于`%2=&%1[0][%0]`,其中将`%1`看成指向至少有两层结构的指针,GEP指令最后边的两个数字一是用来指定进入的层数,一是用来指定每层的偏移量。
第一个`i32 0`表示指向第一个`[10 x i32]`
第二个`i32 %0`表示在第一个`[10 x i32]`块中指向第`%0`个元素
GEP指令返回这个元素的指针,赋值给%2
- `%2 = getelementptr i32, i32* %1 i32 %0`
%2同样是`i32*`类型。
%1是指针,不同于上式(%1指向数组),本式%1指向`i32`类型,所以填入一个偏移数字,即GEP指令返回`%1[%0]`的指针,赋值给%2。
## 问题2: cpp 与 .ll 的对应 ## 问题2: cpp 与 .ll 的对应
请说明你的 cpp 代码片段和 .ll 的每个 BasicBlock 的对应关系。 请说明你的 cpp 代码片段和 .ll 的每个 BasicBlock 的对应关系。
### assign.c
![](figures/assign.png)
### fun.c
![](figures/fun.png)
### if.c
![](figures/if.png)
### while.c
![](figures/while.png)
## 问题3: Visitor Pattern ## 问题3: Visitor Pattern
分析 `calc` 程序在输入为 `4 * (8 + 4 - 1) / 2` 时的行为:
分析 `calc` 程序在输入为 `4 * (8 + 4 - 1) / 2` 时的行为:
1. 请画出该表达式对应的抽象语法树(使用 `calc_ast.hpp` 中的 `CalcAST*` 类型和在该类型中存储的值来表示),并给节点使用数字编号。 1. 请画出该表达式对应的抽象语法树(使用 `calc_ast.hpp` 中的 `CalcAST*` 类型和在该类型中存储的值来表示),并给节点使用数字编号。
2. 请指出示例代码在用访问者模式遍历该语法树时的遍历顺序。
AST如下,略去了CalcAST中的root:
![](figures/CALC_AST.png)
序列请按如下格式指明(序号为问题 2.1 中的编号): 2. 请指出示例代码在用访问者模式遍历该语法树时的遍历顺序。
3->2->5->1
CalcBuilder类从AST的树根开始,访问每个节点,具体行为如下:
- 如果节点是中间节点,则visit会触发该节点内部的每一个子节点的accept函数,经过一次或多次调用又触发CalcBuilder的visit,所以进行递归。
- 如果节点是叶子节点,即CalcASTNum类型,则可以直接读出这个节点的数值,保存在CalcBuilder类中的val中,回溯时会使用到。
所以CalcBuilder访问AST是个深度优先递归遍历的过程。
遍历顺序是:
1->2->3->4->5->7->8->9->11->14->16->12->15->10->13->6
> 个人感觉这个过程像是根据分析树构建语法树。过程中通过val保存一次visit调用的结果,只有在涉及到翻译的节点,即加减乘除运算时才做输出。
## 实验难点 ## 实验难点
描述在实验中遇到的问题、分析和解决方案。 描述在实验中遇到的问题、分析和解决方案。
- 理解GEP指令和指针的关系:阅读[资料](https://llvm.org/docs/GetElementPtr.html#what-effect-do-address-spaces-have-on-geps)
- lightIR API的使用方法:相比[代码](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/tree/master/include/lightir)[文档](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/blob/master/Documentations/common/LightIR.md#c-apis)中有更多有助于理解的信息。所以先扫一遍文档获得宏观上的理解,再读[示例](http://202.38.79.174/compiler_staff/2022fall-compiler_cminus/-/blob/master/tests/2-ir-gen-warmup/ta_gcd/gcd_array_generator.cpp)。对于API中的每个类,文档和代码配合着看,大致就能理解了。
- 理解CalcAST和CalcBuilder的行为:读一遍代码就能懂了。
## 实验反馈 ## 实验反馈
吐槽?建议?
暂无~
extern "C" { extern "C" {
#include "syntax_tree.h" #include "syntax_tree.h"
extern syntax_tree *parse(const char*); extern syntax_tree *parse(const char *);
} }
#include <cstdio> #include <cstdio>
#include <fstream> #include <fstream>
...@@ -10,8 +10,8 @@ using namespace std::literals::string_literals; ...@@ -10,8 +10,8 @@ using namespace std::literals::string_literals;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
syntax_tree *tree = NULL; syntax_tree *tree = NULL;
const char *input = NULL; const char *input = NULL;
if (argc >= 3) { if (argc >= 3) {
printf("usage: %s\n", argv[0]); printf("usage: %s\n", argv[0]);
...@@ -22,22 +22,24 @@ int main(int argc, char *argv[]) ...@@ -22,22 +22,24 @@ int main(int argc, char *argv[])
if (argc == 2) { if (argc == 2) {
input = argv[1]; input = argv[1];
} else { } else {
printf("Input an arithmatic expression (press Ctrl+D in a new line after you finish the expression):\n"); printf("Input an arithmatic expression (press Ctrl+D in a new line "
"after you finish the expression):\n");
} }
tree = parse(input); tree = parse(input);
CalcAST ast(tree); CalcAST ast(tree);
CalcBuilder builder; CalcBuilder builder;
auto module = builder.build(ast); auto module = builder.build(ast);
auto IR = module->print(); auto IR = module->print();
std::ofstream output_stream; std::ofstream output_stream;
auto output_file = "result.ll"; auto output_file = "result.ll";
output_stream.open(output_file, std::ios::out); output_stream.open(output_file, std::ios::out);
output_stream << "; ModuleID = 'calculator'\n"; output_stream << "; ModuleID = 'calculator'\n";
output_stream << IR; output_stream << IR;
output_stream.close(); output_stream.close();
auto command_string = "clang -O0 -w "s + "result.ll -o result -L. -lcminus_io"; auto command_string =
"clang -O0 -w "s + "result.ll -o result -L. -lcminus_io";
auto ret = std::system(command_string.c_str()); auto ret = std::system(command_string.c_str());
if (ret) { if (ret) {
printf("something went wrong!\n"); printf("something went wrong!\n");
......
#ifndef _CALC_AST_HPP_ #ifndef _CALC_AST_HPP_
#define _CALC_AST_HPP_ #define _CALC_AST_HPP_
extern "C" { extern "C" {
#include "syntax_tree.h" #include "syntax_tree.h"
extern syntax_tree *parse(const char *input); extern syntax_tree *parse(const char *input);
} }
#include <vector> #include <vector>
#include <memory> #include <memory>
...@@ -32,59 +32,68 @@ struct CalcASTFactor; ...@@ -32,59 +32,68 @@ struct CalcASTFactor;
class CalcASTVisitor; class CalcASTVisitor;
class CalcAST { class CalcAST
public: {
public:
CalcAST() = delete; CalcAST() = delete;
CalcAST(syntax_tree *); CalcAST(syntax_tree *);
CalcAST(CalcAST &&tree) { CalcAST(CalcAST &&tree)
root = tree.root; {
root = tree.root;
tree.root = nullptr; tree.root = nullptr;
}; };
CalcASTInput* get_root() { return root.get(); } CalcASTInput *get_root() { return root.get(); }
void run_visitor(CalcASTVisitor& visitor); void run_visitor(CalcASTVisitor &visitor);
private:
CalcASTNode* transform_node_iter(syntax_tree_node *); private:
CalcASTNode *transform_node_iter(syntax_tree_node *);
std::shared_ptr<CalcASTInput> root = nullptr; std::shared_ptr<CalcASTInput> root = nullptr;
}; };
struct CalcASTNode { struct CalcASTNode
{
virtual void accept(CalcASTVisitor &) = 0; virtual void accept(CalcASTVisitor &) = 0;
}; };
struct CalcASTInput: CalcASTNode { struct CalcASTInput : CalcASTNode
virtual void accept(CalcASTVisitor &) override final; {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression; std::shared_ptr<CalcASTExpression> expression;
}; };
struct CalcASTFactor: CalcASTNode { struct CalcASTFactor : CalcASTNode
{
virtual void accept(CalcASTVisitor &) override; virtual void accept(CalcASTVisitor &) override;
}; };
struct CalcASTNum: CalcASTFactor { struct CalcASTNum : CalcASTFactor
{
virtual void accept(CalcASTVisitor &) override final; virtual void accept(CalcASTVisitor &) override final;
int val; int val;
}; };
struct CalcASTExpression: CalcASTFactor { struct CalcASTExpression : CalcASTFactor
virtual void accept(CalcASTVisitor &) override final; {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression; std::shared_ptr<CalcASTExpression> expression;
AddOp op; AddOp op;
std::shared_ptr<CalcASTTerm> term; std::shared_ptr<CalcASTTerm> term;
}; };
struct CalcASTTerm : CalcASTNode { struct CalcASTTerm : CalcASTNode
virtual void accept(CalcASTVisitor &) override final; {
std::shared_ptr<CalcASTTerm> term; virtual void accept(CalcASTVisitor &) override final;
MulOp op; std::shared_ptr<CalcASTTerm> term;
MulOp op;
std::shared_ptr<CalcASTFactor> factor; std::shared_ptr<CalcASTFactor> factor;
}; };
class CalcASTVisitor
class CalcASTVisitor { {
public: public:
virtual void visit(CalcASTInput &) = 0; virtual void visit(CalcASTInput &) = 0;
virtual void visit(CalcASTNum &) = 0; virtual void visit(CalcASTNum &) = 0;
virtual void visit(CalcASTExpression &) = 0; virtual void visit(CalcASTExpression &) = 0;
virtual void visit(CalcASTTerm &) = 0; virtual void visit(CalcASTTerm &) = 0;
}; };
#endif #endif
#include "calc_builder.hpp" #include "calc_builder.hpp"
std::unique_ptr<Module> std::unique_ptr<Module> CalcBuilder::build(CalcAST &ast)
CalcBuilder::build(CalcAST &ast) { {
module = std::unique_ptr<Module>(new Module("Cminus code")); module = std::unique_ptr<Module>(new Module("Cminus code"));
builder = new IRBuilder(nullptr, module.get()); builder = new IRBuilder(nullptr, module.get());
auto TyVoid = Type::get_void_type(module.get()); auto TyVoid = Type::get_void_type(module.get());
TyInt32 = Type::get_int32_type(module.get()); TyInt32 = Type::get_int32_type(module.get());
std::vector<Type *> output_params; std::vector<Type *> output_params;
output_params.push_back(TyInt32); output_params.push_back(TyInt32);
auto output_type = FunctionType::get(TyVoid, output_params); auto output_type = FunctionType::get(TyVoid, output_params);
auto output_fun = auto output_fun = Function::create(output_type, "output", module.get());
Function::create( auto main =
output_type, Function::create(FunctionType::get(TyInt32, {}), "main", module.get());
"output",
module.get());
auto main = Function::create(FunctionType::get(TyInt32, {}),
"main", module.get());
auto bb = BasicBlock::create(module.get(), "entry", main); auto bb = BasicBlock::create(module.get(), "entry", main);
builder->set_insert_point(bb); builder->set_insert_point(bb);
ast.run_visitor(*this); ast.run_visitor(*this);
...@@ -23,10 +19,9 @@ CalcBuilder::build(CalcAST &ast) { ...@@ -23,10 +19,9 @@ CalcBuilder::build(CalcAST &ast) {
builder->create_ret(ConstantInt::get(0, module.get())); builder->create_ret(ConstantInt::get(0, module.get()));
return std::move(module); return std::move(module);
} }
void CalcBuilder::visit(CalcASTInput &node) { void CalcBuilder::visit(CalcASTInput &node) { node.expression->accept(*this); }
node.expression->accept(*this); void CalcBuilder::visit(CalcASTExpression &node)
} {
void CalcBuilder::visit(CalcASTExpression &node) {
if (node.expression == nullptr) { if (node.expression == nullptr) {
node.term->accept(*this); node.term->accept(*this);
} else { } else {
...@@ -35,17 +30,18 @@ void CalcBuilder::visit(CalcASTExpression &node) { ...@@ -35,17 +30,18 @@ void CalcBuilder::visit(CalcASTExpression &node) {
node.term->accept(*this); node.term->accept(*this);
auto r_val = val; auto r_val = val;
switch (node.op) { switch (node.op) {
case OP_PLUS: case OP_PLUS:
val = builder->create_iadd(l_val, r_val); val = builder->create_iadd(l_val, r_val);
break; break;
case OP_MINUS: case OP_MINUS:
val = builder->create_isub(l_val, r_val); val = builder->create_isub(l_val, r_val);
break; break;
} }
} }
} }
void CalcBuilder::visit(CalcASTTerm &node) { void CalcBuilder::visit(CalcASTTerm &node)
{
if (node.term == nullptr) { if (node.term == nullptr) {
node.factor->accept(*this); node.factor->accept(*this);
} else { } else {
...@@ -54,16 +50,17 @@ void CalcBuilder::visit(CalcASTTerm &node) { ...@@ -54,16 +50,17 @@ void CalcBuilder::visit(CalcASTTerm &node) {
node.factor->accept(*this); node.factor->accept(*this);
auto r_val = val; auto r_val = val;
switch (node.op) { switch (node.op) {
case OP_MUL: case OP_MUL:
val = builder->create_imul(l_val, r_val); val = builder->create_imul(l_val, r_val);
break; break;
case OP_DIV: case OP_DIV:
val = builder->create_isdiv(l_val, r_val); val = builder->create_isdiv(l_val, r_val);
break; break;
} }
} }
} }
void CalcBuilder::visit(CalcASTNum &node) { void CalcBuilder::visit(CalcASTNum &node)
{
val = ConstantInt::get(node.val, module.get()); val = ConstantInt::get(node.val, module.get());
} }
...@@ -7,18 +7,20 @@ ...@@ -7,18 +7,20 @@
#include "Module.h" #include "Module.h"
#include "Type.h" #include "Type.h"
#include "calc_ast.hpp" #include "calc_ast.hpp"
class CalcBuilder: public CalcASTVisitor { class CalcBuilder : public CalcASTVisitor
public: {
public:
std::unique_ptr<Module> build(CalcAST &ast); std::unique_ptr<Module> build(CalcAST &ast);
private:
private:
virtual void visit(CalcASTInput &) override final; virtual void visit(CalcASTInput &) override final;
virtual void visit(CalcASTNum &) override final; virtual void visit(CalcASTNum &) override final;
virtual void visit(CalcASTExpression &) override final; virtual void visit(CalcASTExpression &) override final;
virtual void visit(CalcASTTerm &) override final; virtual void visit(CalcASTTerm &) override final;
IRBuilder *builder; IRBuilder *builder;
Value *val; Value *val;
Type *TyInt32; Type *TyInt32;
std::unique_ptr<Module> module; std::unique_ptr<Module> module;
}; };
#endif #endif
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
int main() int main()
{ {
auto mod = new Module("Cminus code"); // module name是什么无关紧要 auto mod = new Module("fun.cpp");
auto bud = new IRBuilder(nullptr, mod); auto bud = new IRBuilder(nullptr, mod);
Type *I32Type = Type::get_int32_type(mod); Type *I32Type = Type::get_int32_type(mod);
std::vector<Type *> OneIntArg(1, I32Type); std::vector<Type *> OneIntArg(1, I32Type);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment