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

finish part3: visitor pattern and the report.

parent 4b7accb1
1-parser/*.pdf
2-ir-gen-warmup/*.pdf
# lab2 实验报告
学号 姓名
PB20111654 李晓奇
## 问题1: 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 的对应
请说明你的 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
分析 `calc` 程序在输入为 `4 * (8 + 4 - 1) / 2` 时的行为:
分析 `calc` 程序在输入为 `4 * (8 + 4 - 1) / 2` 时的行为:
1. 请画出该表达式对应的抽象语法树(使用 `calc_ast.hpp` 中的 `CalcAST*` 类型和在该类型中存储的值来表示),并给节点使用数字编号。
2. 请指出示例代码在用访问者模式遍历该语法树时的遍历顺序。
AST如下,略去了CalcAST中的root:
![](figures/CALC_AST.png)
序列请按如下格式指明(序号为问题 2.1 中的编号):
3->2->5->1
2. 请指出示例代码在用访问者模式遍历该语法树时的遍历顺序。
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" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char*);
#include "syntax_tree.h"
extern syntax_tree *parse(const char *);
}
#include <cstdio>
#include <fstream>
......@@ -10,8 +10,8 @@ using namespace std::literals::string_literals;
int main(int argc, char *argv[])
{
syntax_tree *tree = NULL;
const char *input = NULL;
syntax_tree *tree = NULL;
const char *input = NULL;
if (argc >= 3) {
printf("usage: %s\n", argv[0]);
......@@ -22,22 +22,24 @@ int main(int argc, char *argv[])
if (argc == 2) {
input = argv[1];
} 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);
CalcAST ast(tree);
CalcAST ast(tree);
CalcBuilder builder;
auto module = builder.build(ast);
auto IR = module->print();
auto module = builder.build(ast);
auto IR = module->print();
std::ofstream output_stream;
auto output_file = "result.ll";
auto output_file = "result.ll";
output_stream.open(output_file, std::ios::out);
output_stream << "; ModuleID = 'calculator'\n";
output_stream << IR;
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());
if (ret) {
printf("something went wrong!\n");
......
#ifndef _CALC_AST_HPP_
#define _CALC_AST_HPP_
extern "C" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char *input);
#include "syntax_tree.h"
extern syntax_tree *parse(const char *input);
}
#include <vector>
#include <memory>
......@@ -32,59 +32,68 @@ struct CalcASTFactor;
class CalcASTVisitor;
class CalcAST {
public:
class CalcAST
{
public:
CalcAST() = delete;
CalcAST(syntax_tree *);
CalcAST(CalcAST &&tree) {
root = tree.root;
CalcAST(CalcAST &&tree)
{
root = tree.root;
tree.root = nullptr;
};
CalcASTInput* get_root() { return root.get(); }
void run_visitor(CalcASTVisitor& visitor);
private:
CalcASTNode* transform_node_iter(syntax_tree_node *);
CalcASTInput *get_root() { return root.get(); }
void run_visitor(CalcASTVisitor &visitor);
private:
CalcASTNode *transform_node_iter(syntax_tree_node *);
std::shared_ptr<CalcASTInput> root = nullptr;
};
struct CalcASTNode {
struct CalcASTNode
{
virtual void accept(CalcASTVisitor &) = 0;
};
struct CalcASTInput: CalcASTNode {
virtual void accept(CalcASTVisitor &) override final;
struct CalcASTInput : CalcASTNode
{
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression;
};
struct CalcASTFactor: CalcASTNode {
struct CalcASTFactor : CalcASTNode
{
virtual void accept(CalcASTVisitor &) override;
};
struct CalcASTNum: CalcASTFactor {
struct CalcASTNum : CalcASTFactor
{
virtual void accept(CalcASTVisitor &) override final;
int val;
int val;
};
struct CalcASTExpression: CalcASTFactor {
virtual void accept(CalcASTVisitor &) override final;
struct CalcASTExpression : CalcASTFactor
{
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression;
AddOp op;
std::shared_ptr<CalcASTTerm> term;
AddOp op;
std::shared_ptr<CalcASTTerm> term;
};
struct CalcASTTerm : CalcASTNode {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTTerm> term;
MulOp op;
struct CalcASTTerm : CalcASTNode
{
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTTerm> term;
MulOp op;
std::shared_ptr<CalcASTFactor> factor;
};
class CalcASTVisitor {
public:
virtual void visit(CalcASTInput &) = 0;
virtual void visit(CalcASTNum &) = 0;
class CalcASTVisitor
{
public:
virtual void visit(CalcASTInput &) = 0;
virtual void visit(CalcASTNum &) = 0;
virtual void visit(CalcASTExpression &) = 0;
virtual void visit(CalcASTTerm &) = 0;
virtual void visit(CalcASTTerm &) = 0;
};
#endif
#include "calc_builder.hpp"
std::unique_ptr<Module>
CalcBuilder::build(CalcAST &ast) {
module = std::unique_ptr<Module>(new Module("Cminus code"));
builder = new IRBuilder(nullptr, module.get());
std::unique_ptr<Module> CalcBuilder::build(CalcAST &ast)
{
module = std::unique_ptr<Module>(new Module("Cminus code"));
builder = new IRBuilder(nullptr, 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;
output_params.push_back(TyInt32);
auto output_type = FunctionType::get(TyVoid, output_params);
auto output_fun =
Function::create(
output_type,
"output",
module.get());
auto main = Function::create(FunctionType::get(TyInt32, {}),
"main", module.get());
auto output_fun = Function::create(output_type, "output", module.get());
auto main =
Function::create(FunctionType::get(TyInt32, {}), "main", module.get());
auto bb = BasicBlock::create(module.get(), "entry", main);
builder->set_insert_point(bb);
ast.run_visitor(*this);
......@@ -23,10 +19,9 @@ CalcBuilder::build(CalcAST &ast) {
builder->create_ret(ConstantInt::get(0, module.get()));
return std::move(module);
}
void CalcBuilder::visit(CalcASTInput &node) {
node.expression->accept(*this);
}
void CalcBuilder::visit(CalcASTExpression &node) {
void CalcBuilder::visit(CalcASTInput &node) { node.expression->accept(*this); }
void CalcBuilder::visit(CalcASTExpression &node)
{
if (node.expression == nullptr) {
node.term->accept(*this);
} else {
......@@ -35,17 +30,18 @@ void CalcBuilder::visit(CalcASTExpression &node) {
node.term->accept(*this);
auto r_val = val;
switch (node.op) {
case OP_PLUS:
val = builder->create_iadd(l_val, r_val);
break;
case OP_MINUS:
val = builder->create_isub(l_val, r_val);
break;
case OP_PLUS:
val = builder->create_iadd(l_val, r_val);
break;
case OP_MINUS:
val = builder->create_isub(l_val, r_val);
break;
}
}
}
void CalcBuilder::visit(CalcASTTerm &node) {
void CalcBuilder::visit(CalcASTTerm &node)
{
if (node.term == nullptr) {
node.factor->accept(*this);
} else {
......@@ -54,16 +50,17 @@ void CalcBuilder::visit(CalcASTTerm &node) {
node.factor->accept(*this);
auto r_val = val;
switch (node.op) {
case OP_MUL:
val = builder->create_imul(l_val, r_val);
break;
case OP_DIV:
val = builder->create_isdiv(l_val, r_val);
break;
case OP_MUL:
val = builder->create_imul(l_val, r_val);
break;
case OP_DIV:
val = builder->create_isdiv(l_val, r_val);
break;
}
}
}
void CalcBuilder::visit(CalcASTNum &node) {
void CalcBuilder::visit(CalcASTNum &node)
{
val = ConstantInt::get(node.val, module.get());
}
......@@ -7,18 +7,20 @@
#include "Module.h"
#include "Type.h"
#include "calc_ast.hpp"
class CalcBuilder: public CalcASTVisitor {
public:
class CalcBuilder : public CalcASTVisitor
{
public:
std::unique_ptr<Module> build(CalcAST &ast);
private:
private:
virtual void visit(CalcASTInput &) override final;
virtual void visit(CalcASTNum &) override final;
virtual void visit(CalcASTExpression &) override final;
virtual void visit(CalcASTTerm &) override final;
IRBuilder *builder;
Value *val;
Type *TyInt32;
IRBuilder *builder;
Value *val;
Type *TyInt32;
std::unique_ptr<Module> module;
};
#endif
......@@ -10,7 +10,7 @@
int main()
{
auto mod = new Module("Cminus code"); // module name是什么无关紧要
auto mod = new Module("fun.cpp");
auto bud = new IRBuilder(nullptr, mod);
Type *I32Type = Type::get_int32_type(mod);
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