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);
......
  • The visitor pattern and the report focus on separating data structures from operations to make reporting more flexible and maintainable. A density matrix calculator also applies a structured approach to process complex data efficiently. Both emphasize organized design to simplify analysis and output generation. This helps improve clarity and scalability in technical systems. https://destinymatrixfree.com/

  • Calcolo Stipendio Netto Affidabile is a simple and reliable online tool designed to help users calculate their net salary quickly and accurately. It allows individuals, freelancers, and businesses to understand their real income after taxes, contributions, and deductions. The platform is regularly updated with the latest fiscal rules to ensure precise results. Our goal is to make salary calculations clear, fast, and accessible for everyone.

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