Commit 2dd8c34b authored by 李晓奇's avatar 李晓奇

Fetch lab3

parents 4dfb6145 a27f5a5e
---
Language: Cpp
BasedOnStyle: LLVM
AllowAllParametersOfDeclarationOnNextLine: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BreakConstructorInitializers: BeforeComma
ColumnLimit: 120
CommentPragmas: '^(!|NOLINT)'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 1
IndentCaseLabels: false
AllowShortCaseLabelsOnASingleLine: true
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
PenaltyReturnTypeOnItsOwnLine: 200
SpacesBeforeTrailingComments: 1
TabWidth: 4
UseTab: Never
...
...@@ -22,22 +22,22 @@ ...@@ -22,22 +22,22 @@
本次实验的目的是让大家熟悉 Lab3 所需要的相关知识: LLVM IR、 LightIR(LLVM IR 的轻量级 C++ 接口)和 Visitor Pattern(访问者模式)。 本次实验的目的是让大家熟悉 Lab3 所需要的相关知识: LLVM IR、 LightIR(LLVM IR 的轻量级 C++ 接口)和 Visitor Pattern(访问者模式)。
在开始实验之前,请根据之前的[编译实验环境搭建](http://202.38.79.174/compiler_staff/2022fall-environment/-/blob/master/README.md)确保LLVM的版本为10.0.1,且PATH环境变量配置正确。可以通过`lli --version`命令是否可以输出10.0.1的版本信息来验证(其它版本不一定兼容)。 在开始实验之前,请根据之前的[编译实验环境搭建](http://202.38.79.174/compiler_staff/2022fall-environment/-/blob/master/README.md)确保LLVM的版本为10.0.1,且PATH环境变量配置正确。可以通过`lli --version`命令是否可以输出10.0.1的版本信息来验证(其它版本不一定兼容)。
本次实验设置的目的是为 Lab3 进行知识的准备与热身, coding 的工程量不大,但是需要一定的阅读、学习、理解。因此本次的实验报告相比之下内容要求会稍微多一些,以避免大家在 Lab3 时手足无措。 本次实验设置的目的是为 Lab3 进行知识的准备与热身, coding 的工程量不大,但是需要一定的阅读、学习、理解。因此本次的实验报告相比之下内容要求会稍微多一些,以避免大家在 Lab3 时手足无措。
这里助教提供了简单的[C++简介](Documentations/common/simple_cpp.md),对C++基本特性不熟悉的同学可以先阅读该文档。 这里助教提供了简单的[C++简介](../../Documentations/common/simple_cpp.md),对C++基本特性不熟悉的同学可以先阅读该文档。
### 主要工作 ### 主要工作
1. 第一部分: 了解 LLVM IR。通过 clang 生成的 .ll ,了解 LLVM IR 与 c 代码的对应关系,**完成1.3** 1. 第一部分: 了解 LLVM IR。通过 clang 生成的 .ll ,了解 LLVM IR 与 c 代码的对应关系,**完成1.3**
2. 第二部分: 了解 LightIR。通过助教提供的 c++ 例子,了解 LightIR 的 c++ 接口及实现,**完成2.3** 2. 第二部分: 了解 LightIR。通过助教提供的 c++ 例子,了解 LightIR 的 c++ 接口及实现,**完成2.3**
3. 第三部分: 理解 Visitor Pattern 。**完成3.1** 3. 第三部分: 理解 Visitor Pattern 。**完成3.1**
4. 实验报告:在 [report.md](./Reports/2-ir-gen-warmup/report.md)**回答3个问题** 4. 实验报告:在 [report.md](../../Reports/2-ir-gen-warmup/report.md)**回答3个问题**
## 1. LLVM IR 部分 ## 1. LLVM IR 部分
### 1.1 LLVM IR 介绍 ### 1.1 LLVM IR 介绍
根据[维基百科](https://zh.wikipedia.org/zh-cn/LLVM)的介绍,LLVM是一个自由软件项目,它是一种编译器基础设施,以C++写成,包含一系列模块化的编译器组件和工具链,用来开发编译器前端和后端。IR的全称是Intermediate Representation,即中间表示。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)。由于其手册过于复杂,助教筛选了后续实验中将要用到的子集,总结为了 [Light IR 手册](../common/LightIR.md#ir-%E6%A0%BC%E5%BC%8F)。如果有感兴趣的同学可以阅读原手册作为拓展。 LLVM IR的具体指令可以参考 [Reference Manual](https://llvm.org/docs/LangRef.html)。由于其手册过于复杂,助教筛选了后续实验中将要用到的子集,总结为了 [Light IR 手册](../common/LightIR.md#ir-%E6%A0%BC%E5%BC%8F)。如果有感兴趣的同学可以阅读原手册作为拓展。
作为一开始的参考,你可以先阅读其中 `IR格式``IR指令` 两节,后续有需要再反复参考。实验的最后,你需要在 [report.md](./Reports/2-ir-gen-warmup/report.md)**回答问题1** 作为一开始的参考,你可以先阅读其中 `IR格式``IR指令` 两节,后续有需要再反复参考。实验的最后,你需要在 [report.md](../../Reports/2-ir-gen-warmup/report.md)**回答问题1**
### 1.2 gcd 例子: 利用 clang 生成的 .ll ### 1.2 gcd 例子: 利用 clang 生成的 .ll
阅读 [tests/2-ir-gen-warmup/ta_gcd/gcd_array.c](../../tests/2-ir-gen-warmup/ta_gcd/gcd_array.c) 阅读 [tests/2-ir-gen-warmup/ta_gcd/gcd_array.c](../../tests/2-ir-gen-warmup/ta_gcd/gcd_array.c)
...@@ -67,14 +67,14 @@ lab3 部分会要求大家通过 `LightIR` 根据 `AST` 构建生成 LLVM IR。 ...@@ -67,14 +67,14 @@ lab3 部分会要求大家通过 `LightIR` 根据 `AST` 构建生成 LLVM IR。
该程序的编译与运行请参考 4.2 节。 该程序的编译与运行请参考 4.2 节。
### 2.3 你的提交2: 利用 LightIR + cpp 编写生成 .ll 的程序 ### 2.3 你的提交2: 利用 LightIR + cpp 编写生成 .ll 的程序
你需要在 `tests/2-ir-gen-warmup/stu_cpp/` 目录中,编写 [assign_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/assign_generator.cpp)[fun_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/fun_generator.cpp)[if_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/if_generator.cpp)[while_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/while_generator.cpp),以生成与 1.3 节的四个 c 程序相同逻辑功能的 `.ll` 文件。你需要完成 [report.md](./Reports/2-ir-gen-warmup/report.md) 中的**问题2** 你需要在 `tests/2-ir-gen-warmup/stu_cpp/` 目录中,编写 [assign_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/assign_generator.cpp)[fun_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/fun_generator.cpp)[if_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/if_generator.cpp)[while_generator.cpp](../../tests/2-ir-gen-warmup/stu_cpp/while_generator.cpp),以生成与 1.3 节的四个 c 程序相同逻辑功能的 `.ll` 文件。你需要完成 [report.md](../../Reports/2-ir-gen-warmup/report.md) 中的**问题2**
## 3. Lab3 的准备 ## 3. Lab3 的准备
### 3.1 了解 Visitor Pattern ### 3.1 了解 Visitor Pattern
Visitor Pattern(访问者模式)是一种在 LLVM 项目源码中被广泛使用的设计模式。在遍历某个数据结构(比如树)时,如果我们需要对每个节点做一些额外的特定操作, Visitor Pattern 就是个不错的思路。 Visitor Pattern(访问者模式)是一种在 LLVM 项目源码中被广泛使用的设计模式。在遍历某个数据结构(比如树)时,如果我们需要对每个节点做一些额外的特定操作, Visitor Pattern 就是个不错的思路。
Visitor Pattern 是为了解决**稳定的数据结构****易变的操作耦合问题**而产生的一种设计模式。解决方法就是在被访问的类里面加一个对外提供接待访问者的接口,其关键在于在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。这里举一个应用实例来帮助理解访问者模式: 您在朋友家做客,您是访问者;朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。 Visitor Pattern 是为了解决**稳定的数据结构****易变的操作耦合问题**而产生的一种设计模式。解决方法就是在被访问的类里面加一个对外提供接待访问者的接口,其关键在于在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。这里举一个应用实例来帮助理解访问者模式: 您在朋友家做客,您是访问者;朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。
有关 Visitor Pattern 的含义、模式和特点,有梯子的同学可参考 [维基百科](https://en.wikipedia.org/wiki/Visitor_pattern#C++_example)。其中较为重要的一点原则在于, C++ 中对函数重载特性的支持。 有关 Visitor Pattern 的含义、模式和特点,有梯子的同学可参考 [维基百科](https://en.wikipedia.org/wiki/Visitor_pattern#C++_example)。其中较为重要的一点原则在于, C++ 中对函数重载特性的支持。
`tests/2-ir-gen-warmup/calculator` 中,助教编写了一个利用访问者模式,产生计算算数表达式的中间代码的程序。该程序首先对算数表达式进行语法分析生成语法树,再使用访问者模式来遍历语法树,产生中间代码。在 [calc_ast.hpp](../../tests/2-ir-gen-warmup/calculator/calc_ast.hpp) 中,我们定义了语法树的不同节点类型。在 [calc_builder.cpp](../../tests/2-ir-gen-warmup/calculator/calc_builder.cpp) 中,我们使用 LightIR 编写了不同的 `visit` 函数。根据节点类型的不同,编译器会在多种 `visit` 函数中,选择对应的实现进行调用。请认真阅读这两个文件和其它相关代码,理解语法树是如何通过访问者模式被遍历的,并在 [report.md](./Reports/2-ir-gen-warmup/report.md)**回答问题3** `tests/2-ir-gen-warmup/calculator` 中,助教编写了一个利用访问者模式,产生计算算数表达式的中间代码的程序。该程序首先对算数表达式进行语法分析生成语法树,再使用访问者模式来遍历语法树,产生中间代码。在 [calc_ast.hpp](../../tests/2-ir-gen-warmup/calculator/calc_ast.hpp) 中,我们定义了语法树的不同节点类型。在 [calc_builder.cpp](../../tests/2-ir-gen-warmup/calculator/calc_builder.cpp) 中,我们使用 LightIR 编写了不同的 `visit` 函数。根据节点类型的不同,编译器会在多种 `visit` 函数中,选择对应的实现进行调用。请认真阅读这两个文件和其它相关代码,理解语法树是如何通过访问者模式被遍历的,并在 [report.md](../../Reports/2-ir-gen-warmup/report.md)**回答问题3**
该程序使用方法如下: 该程序使用方法如下:
...@@ -123,7 +123,7 @@ $ ./result ...@@ -123,7 +123,7 @@ $ ./result
   │   ├── fun.c    │   ├── fun.c
   │   ├── if.c    │   ├── if.c
   │   └── while.c    │   └── while.c
   ├── CMakeLists.txt <- 你在2.3节需要去掉注释(我们不收,你要改    ├── CMakeLists.txt <- 你在2.3节需要去掉注释(你要交
   ├── stu_cpp <- lab2 所需提交的 cpp 目录(你要交)    ├── stu_cpp <- lab2 所需提交的 cpp 目录(你要交)
   │   ├── assign_generator.cpp    │   ├── assign_generator.cpp
   │   ├── fun_generator.cpp    │   ├── fun_generator.cpp
...@@ -164,7 +164,7 @@ $ ./result ...@@ -164,7 +164,7 @@ $ ./result
* 需要完成 `./tests/2-ir-gen-warmup/stu_cpp` 目录下的4个文件 * 需要完成 `./tests/2-ir-gen-warmup/stu_cpp` 目录下的4个文件
* 需要在 `./Reports/2-ir-gen-warmup/` 目录下撰写实验报告 * 需要在 `./Reports/2-ir-gen-warmup/` 目录下撰写实验报告
* 实验报告内容包括: * 实验报告内容包括:
* 实验要求、3个问题、实验难点、实验反馈(具体参考 [report.md](./Reports/2-ir-gen-warmup/report.md)) * 实验要求、3个问题、实验难点、实验反馈(具体参考 [report.md](../../Reports/2-ir-gen-warmup/report.md))
* 本次实验报告**参与**评分标准. * 本次实验报告**参与**评分标准.
* git 提交规范: * git 提交规范:
* 不破坏目录结构( `report.md` 如果需要放图片,请放在 `./Reports/2-ir-gen-warmup/figs/` 下) * 不破坏目录结构( `report.md` 如果需要放图片,请放在 `./Reports/2-ir-gen-warmup/figs/` 下)
......
This diff is collapsed.
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
* [lab2](./Documentations/2-ir-gen-warmup/) * [lab2](./Documentations/2-ir-gen-warmup/)
+ DDL:2022-10-23 23:59:59 (UTC+8) + DDL:2022-10-23 23:59:59 (UTC+8)
* [lab2](./Documentations/3-ir-gen/)
+ DDL:2022-11-07 23:59:59 (UTC+8)
## FAQ: How to merge upstream remote branches ## FAQ: How to merge upstream remote branches
In brief, you need another alias for upstream repository (we assume you are now in your local copy of forked repository on Gitlab): In brief, you need another alias for upstream repository (we assume you are now in your local copy of forked repository on Gitlab):
......
...@@ -30,6 +30,7 @@ PB20111654 李晓奇 ...@@ -30,6 +30,7 @@ PB20111654 李晓奇
### assign.c ### assign.c
<<<<<<< HEAD
![](figures/assign.png) ![](figures/assign.png)
### fun.c ### fun.c
...@@ -69,6 +70,10 @@ PB20111654 李晓奇 ...@@ -69,6 +70,10 @@ PB20111654 李晓奇
1->2->3->4->5->7->8->9->11->14->16->12->15->10->13->6 1->2->3->4->5->7->8->9->11->14->16->12->15->10->13->6
> 个人感觉这个过程像是根据分析树构建语法树。过程中通过val保存一次visit调用的结果,只有在涉及到翻译的节点,即加减乘除运算时才做输出。 > 个人感觉这个过程像是根据分析树构建语法树。过程中通过val保存一次visit调用的结果,只有在涉及到翻译的节点,即加减乘除运算时才做输出。
=======
序列请按如下格式指明(序号为问题 3.1 中的编号):
3->2->5->1
>>>>>>> a27f5a5e24257d52caf0259ffdba533a4bcdf252
## 实验难点 ## 实验难点
......
# lab3 实验报告
学号 姓名
## 实验要求
## 实验难点
实验中遇到哪些挑战
## 实验设计
请写明为了顺利完成本次实验,加入了哪些亮点设计,并对这些设计进行解释。
可能的阐述方向有:
1. 如何设计全局变量
2. 遇到的难点以及解决方案
3. 如何降低生成 IR 中的冗余
4. ...
### 实验总结
此次实验有什么收获
### 实验反馈 (可选 不计入评分)
对本次实验的建议
#ifndef _CMINUSF_BUILDER_HPP_
#define _CMINUSF_BUILDER_HPP_
#include "BasicBlock.h"
#include "Constant.h"
#include "Function.h"
#include "IRBuilder.h"
#include "Module.h"
#include "Type.h"
#include "ast.hpp"
#include <map>
#include <memory>
class Scope {
public:
// enter a new scope
void enter() { inner.push_back({}); }
// exit a scope
void exit() { inner.pop_back(); }
bool in_global() { return inner.size() == 1; }
// push a name to scope
// return true if successful
// return false if this name already exits
bool push(std::string name, Value *val) {
auto result = inner[inner.size() - 1].insert({name, val});
return result.second;
}
Value *find(std::string name) {
for (auto s = inner.rbegin(); s != inner.rend(); s++) {
auto iter = s->find(name);
if (iter != s->end()) {
return iter->second;
}
}
return nullptr;
}
private:
std::vector<std::map<std::string, Value *>> inner;
};
class CminusfBuilder : public ASTVisitor {
public:
CminusfBuilder() {
module = std::unique_ptr<Module>(new Module("Cminus code"));
builder = std::make_unique<IRBuilder>(nullptr, module.get());
auto TyVoid = Type::get_void_type(module.get());
auto TyInt32 = Type::get_int32_type(module.get());
auto TyFloat = Type::get_float_type(module.get());
auto input_type = FunctionType::get(TyInt32, {});
auto input_fun = Function::create(input_type, "input", 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());
std::vector<Type *> output_float_params;
output_float_params.push_back(TyFloat);
auto output_float_type = FunctionType::get(TyVoid, output_float_params);
auto output_float_fun = Function::create(output_float_type, "outputFloat", module.get());
auto neg_idx_except_type = FunctionType::get(TyVoid, {});
auto neg_idx_except_fun = Function::create(neg_idx_except_type, "neg_idx_except", module.get());
scope.enter();
scope.push("input", input_fun);
scope.push("output", output_fun);
scope.push("outputFloat", output_float_fun);
scope.push("neg_idx_except", neg_idx_except_fun);
}
std::unique_ptr<Module> getModule() { return std::move(module); }
private:
virtual void visit(ASTProgram &) override final;
virtual void visit(ASTNum &) override final;
virtual void visit(ASTVarDeclaration &) override final;
virtual void visit(ASTFunDeclaration &) override final;
virtual void visit(ASTParam &) override final;
virtual void visit(ASTCompoundStmt &) override final;
virtual void visit(ASTExpressionStmt &) override final;
virtual void visit(ASTSelectionStmt &) override final;
virtual void visit(ASTIterationStmt &) override final;
virtual void visit(ASTReturnStmt &) override final;
virtual void visit(ASTAssignExpression &) override final;
virtual void visit(ASTSimpleExpression &) override final;
virtual void visit(ASTAdditiveExpression &) override final;
virtual void visit(ASTVar &) override final;
virtual void visit(ASTTerm &) override final;
virtual void visit(ASTCall &) override final;
std::unique_ptr<IRBuilder> builder;
Scope scope;
std::unique_ptr<Module> module;
};
#endif
...@@ -2,3 +2,4 @@ add_subdirectory(parser) ...@@ -2,3 +2,4 @@ add_subdirectory(parser)
add_subdirectory(common) add_subdirectory(common)
add_subdirectory(io) add_subdirectory(io)
add_subdirectory(lightir) add_subdirectory(lightir)
add_subdirectory(cminusfc)
\ No newline at end of file
add_executable(
cminusfc
cminusfc.cpp
cminusf_builder.cpp
)
target_link_libraries(
cminusfc
IR_lib
common
syntax
)
install(
TARGETS cminusfc
RUNTIME DESTINATION bin
)
/*
* 声明:本代码为 2020 秋 中国科大编译原理(李诚)课程实验参考实现。
* 请不要以任何方式,将本代码上传到可以公开访问的站点或仓库
*/
#include "cminusf_builder.hpp"
#define CONST_FP(num) ConstantFP::get((float)num, module.get())
#define CONST_INT(num) ConstantInt::get(num, module.get())
// TODO: Global Variable Declarations
// You can define global variables here
// to store state. You can expand these
// definitions if you need to.
// function that is being built
Function *cur_fun = nullptr;
// types
Type *VOID_T;
Type *INT1_T;
Type *INT32_T;
Type *INT32PTR_T;
Type *FLOAT_T;
Type *FLOATPTR_T;
/*
* use CMinusfBuilder::Scope to construct scopes
* scope.enter: enter a new scope
* scope.exit: exit current scope
* scope.push: add a new binding to current scope
* scope.find: find and return the value bound to the name
*/
void CminusfBuilder::visit(ASTProgram &node) {
VOID_T = Type::get_void_type(module.get());
INT1_T = Type::get_int1_type(module.get());
INT32_T = Type::get_int32_type(module.get());
INT32PTR_T = Type::get_int32_ptr_type(module.get());
FLOAT_T = Type::get_float_type(module.get());
FLOATPTR_T = Type::get_float_ptr_type(module.get());
for (auto decl : node.declarations) {
decl->accept(*this);
}
}
void CminusfBuilder::visit(ASTNum &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTVarDeclaration &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTFunDeclaration &node) {
FunctionType *fun_type;
Type *ret_type;
std::vector<Type *> param_types;
if (node.type == TYPE_INT)
ret_type = INT32_T;
else if (node.type == TYPE_FLOAT)
ret_type = FLOAT_T;
else
ret_type = VOID_T;
for (auto &param : node.params) {
//!TODO: Please accomplish param_types.
}
fun_type = FunctionType::get(ret_type, param_types);
auto fun = Function::create(fun_type, node.id, module.get());
scope.push(node.id, fun);
cur_fun = fun;
auto funBB = BasicBlock::create(module.get(), "entry", fun);
builder->set_insert_point(funBB);
scope.enter();
std::vector<Value *> args;
for (auto arg = fun->arg_begin(); arg != fun->arg_end(); arg++) {
args.push_back(*arg);
}
for (int i = 0; i < node.params.size(); ++i) {
//!TODO: You need to deal with params
// and store them in the scope.
}
node.compound_stmt->accept(*this);
if (builder->get_insert_block()->get_terminator() == nullptr)
{
if (cur_fun->get_return_type()->is_void_type())
builder->create_void_ret();
else if (cur_fun->get_return_type()->is_float_type())
builder->create_ret(CONST_FP(0.));
else
builder->create_ret(CONST_INT(0));
}
scope.exit();
}
void CminusfBuilder::visit(ASTParam &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTCompoundStmt &node) {
//!TODO: This function is not complete.
// You may need to add some code here
// to deal with complex statements.
for (auto &decl : node.local_declarations) {
decl->accept(*this);
}
for (auto &stmt : node.statement_list) {
stmt->accept(*this);
if (builder->get_insert_block()->get_terminator() != nullptr)
break;
}
}
void CminusfBuilder::visit(ASTExpressionStmt &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTSelectionStmt &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTIterationStmt &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTReturnStmt &node) {
if (node.expression == nullptr) {
builder->create_void_ret();
} else {
//!TODO: The given code is incomplete.
// You need to solve other return cases (e.g. return an integer).
}
}
void CminusfBuilder::visit(ASTVar &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTAssignExpression &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTSimpleExpression &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTAdditiveExpression &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTTerm &node) {
//!TODO: This function is empty now.
// Add some code here.
}
void CminusfBuilder::visit(ASTCall &node) {
//!TODO: This function is empty now.
// Add some code here.
}
#include "cminusf_builder.hpp"
#include <fstream>
#include <iostream>
#include <memory>
using namespace std::literals::string_literals;
void print_help(std::string exe_name) {
std::cout << "Usage: " << exe_name <<
" [ -h | --help ] [ -o <target-file> ] [ -emit-llvm ] <input-file>" << std::endl;
}
int main(int argc, char **argv) {
std::string target_path;
std::string input_path;
bool mem2reg = false;
bool const_propagation = false;
bool activevars = false;
bool loop_inv_hoist = false;
bool loop_search = false;
bool emit = false;
for (int i = 1; i < argc; ++i) {
if (argv[i] == "-h"s || argv[i] == "--help"s) {
print_help(argv[0]);
return 0;
} else if (argv[i] == "-o"s) {
if (target_path.empty() && i + 1 < argc) {
target_path = argv[i + 1];
i += 1;
} else {
print_help(argv[0]);
return 0;
}
} else if (argv[i] == "-emit-llvm"s) {
emit = true;
} else if (argv[i] == "-mem2reg"s) {
mem2reg = true;
} else if (argv[i] == "-loop-search"s) {
loop_search = true;
} else if (argv[i] == "-loop-inv-hoist"s) {
loop_inv_hoist = true;
} else if (argv[i] == "-const-propagation"s) {
const_propagation = true;
} else if (argv[i] == "-active-vars"s) {
activevars = true;
} else {
if (input_path.empty()) {
input_path = argv[i];
} else {
print_help(argv[0]);
return 0;
}
}
}
if (input_path.empty()) {
print_help(argv[0]);
return 0;
}
if (target_path.empty()) {
auto pos = input_path.rfind('.');
if (pos == std::string::npos) {
std::cerr << argv[0] << ": input file " << input_path << " has unknown filetype!" << std::endl;
return -1;
} else {
if (input_path.substr(pos) != ".cminus") {
std::cerr << argv[0] << ": input file " << input_path << " has unknown filetype!" << std::endl;
return -1;
}
if (emit) {
target_path = input_path.substr(0, pos);
} else {
target_path = input_path.substr(0, pos);
}
}
}
auto s = parse(input_path.c_str());
auto a = AST(s);
CminusfBuilder builder;
a.run_visitor(builder);
auto m = builder.getModule();
auto IR = m->print();
std::ofstream output_stream;
auto output_file = target_path + ".ll";
output_stream.open(output_file, std::ios::out);
output_stream << "; ModuleID = 'cminus'\n";
output_stream << "source_filename = \"" + input_path + "\"\n\n";
output_stream << IR;
output_stream.close();
if (!emit) {
std::string lib_path = argv[0];
lib_path.erase(lib_path.rfind('/')) += "/libcminus_io.a";
auto command_string = "clang -O0 -w "s + target_path + ".ll -o " + target_path + " " + lib_path;
int re_code0 = std::system(command_string.c_str());
command_string = "rm "s + target_path + ".ll";
int re_code1 = std::system(command_string.c_str());
if (re_code0 == 0 && re_code1 == 0)
return 0;
else
return 1;
}
return 0;
}
3
1
4
1
5
9
2
6
5
3
5
8
9
7
9
3
2
3
8
4
6
2
6
4
3
3
8
3
2
7
9
5
0
2
8
8
4
1
9
7
1
6
9
3
9
9
3
7
5
1
0
5
8
2
0
9
7
4
9
4
4
5
9
2
3
0
7
8
1
6
4
0
6
2
8
6
2
0
8
9
9
8
6
2
8
0
3
4
8
2
5
3
4
2
1
1
7
0
6
7
9
8
2
1
4
8
0
8
6
5
1
3
2
8
2
3
0
6
6
4
7
0
9
3
8
4
4
6
0
9
5
5
0
5
8
2
2
3
1
7
2
5
3
5
9
4
0
8
1
2
8
4
8
1
1
1
7
4
5
0
2
8
4
1
0
2
7
0
1
9
3
8
5
2
1
1
0
5
5
5
9
6
4
4
6
2
2
9
4
8
9
5
4
9
3
0
3
8
1
9
6
4
4
2
8
8
1
0
9
7
5
6
6
5
9
3
3
4
4
6
1
2
8
4
7
5
6
4
8
2
3
3
7
8
6
7
8
3
1
6
5
2
7
1
2
0
1
9
0
9
1
4
5
6
4
8
5
6
6
9
2
3
4
6
0
3
4
8
6
1
0
4
5
4
3
2
6
6
4
8
2
1
3
3
9
3
6
0
7
2
6
0
2
4
9
1
4
1
2
7
3
7
2
4
5
8
7
0
0
6
6
0
6
3
1
5
5
8
8
1
7
4
8
8
1
5
2
0
9
2
0
9
6
2
8
2
9
2
5
4
0
9
1
7
1
5
3
6
4
3
6
7
8
9
2
5
9
0
3
6
0
0
1
1
3
3
0
5
3
0
5
4
8
8
2
0
4
6
6
5
2
1
3
8
4
1
4
6
9
5
1
9
4
1
5
1
1
6
0
9
4
3
3
0
5
7
2
7
0
3
6
5
7
5
9
5
9
1
9
5
3
0
9
2
1
8
6
1
1
7
3
8
1
9
3
2
6
1
1
7
9
3
1
0
5
1
1
8
5
4
8
0
7
4
4
6
2
3
7
9
9
6
2
7
4
9
5
6
7
3
5
1
8
8
5
7
5
2
7
2
4
8
9
1
2
2
7
9
3
8
1
8
3
0
1
1
9
4
9
1
2
9
8
3
3
6
7
3
3
6
2
4
4
0
6
5
6
6
4
3
0
8
6
0
2
1
3
9
4
9
4
6
3
9
5
2
2
4
7
3
7
1
9
0
7
0
2
1
7
9
8
6
0
9
4
3
7
0
2
7
7
0
5
3
9
2
1
7
1
7
6
2
9
3
1
7
6
7
5
2
3
8
4
6
7
4
8
1
8
4
6
7
6
6
9
4
0
5
1
3
2
0
0
0
5
6
8
1
2
7
1
4
5
2
6
3
5
6
0
8
2
7
7
8
5
7
7
1
3
4
2
7
5
7
7
8
9
6
0
9
1
7
3
6
3
7
1
7
8
7
2
1
4
6
8
4
4
0
9
0
1
2
2
4
9
5
3
4
3
0
1
4
6
5
4
9
5
8
5
3
7
1
0
5
0
7
9
2
2
7
9
6
8
9
2
5
8
9
2
3
5
4
2
0
1
9
9
5
6
1
1
2
1
2
9
0
2
1
9
6
0
8
6
4
0
3
4
4
1
8
1
5
9
8
1
3
6
2
9
7
7
4
7
7
1
3
0
9
9
6
0
5
1
8
7
0
7
2
1
1
3
4
9
9
9
9
9
9
8
3
7
2
9
7
8
0
4
9
9
5
1
0
5
9
7
3
1
7
3
2
8
1
6
0
9
6
3
1
8
5
#!/usr/bin/env python3
import subprocess
# 17
lv0_1 = {
"return": (3, False),
"decl_int": (2, False),
"decl_float": (2, False),
"decl_int_array": (2, False),
"decl_float_array": (2, False),
"input": (2, True),
"output_float": (2, False),
"output_int": (2, False),
}
# 18
lv0_2 = {
"num_add_int": (0.5, False),
"num_sub_int": (0.5, False),
"num_mul_int": (0.5, False),
"num_div_int": (0.5, False),
"num_add_float": (0.5, False),
"num_sub_float": (0.5, False),
"num_mul_float": (0.5, False),
"num_div_float": (0.5, False),
"num_add_mixed": (0.5, False),
"num_sub_mixed": (0.5, False),
"num_mul_mixed": (0.5, False),
"num_div_mixed": (0.5, False),
"num_comp1": (1.5, False),
"num_le_int": (0.5, False),
"num_lt_int": (0.5, False),
"num_ge_int": (0.5, False),
"num_gt_int": (0.5, False),
"num_eq_int": (0.5, False),
"num_neq_int": (0.5, False),
"num_le_float": (0.5, False),
"num_lt_float": (0.5, False),
"num_ge_float": (0.5, False),
"num_gt_float": (0.5, False),
"num_eq_float": (0.5, False),
"num_neq_float": (0.5, False),
"num_le_mixed": (0.5, False),
"num_lt_mixed": (0.5, False),
"num_ge_mixed": (0.5, False),
"num_gt_mixed": (0.5, False),
"num_eq_mixed": (0.5, False),
"num_neq_mixed": (0.5, False),
"num_comp2": (1.5, False),
}
# 31
lv1 = {
"assign_int_var_local": (1, False),
"assign_int_array_local": (2, False),
"assign_int_var_global": (1, False),
"assign_int_array_global": (2, False),
"assign_float_var_local": (1, False),
"assign_float_array_local": (2, False),
"assign_float_var_global": (1, False),
"assign_float_array_global": (2, False),
"assign_cmp": (1, False),
"innout": (1, True),
"idx_float": (1, False),
"negidx_int": (1, False),
"negidx_float": (1, False),
"negidx_intfuncall": (1, False),
"negidx_floatfuncall": (1, False),
"negidx_voidfuncall": (1, False),
"selection1": (1.5, False),
"selection2": (1.5, False),
"selection3": (1.5, False),
"iteration1": (1.5, False),
"iteration2": (1.5, False),
"scope": (1.5, False),
"transfer_float_to_int": (1, False),
"transfer_int_to_float": (1, False),
}
# 23
lv2 = {
"funcall_chain": (2, False),
"assign_chain": (2, False),
"funcall_var": (2, False),
"funcall_int_array": (2, False),
"funcall_float_array": (2, False),
"funcall_array_array": (2, False),
"return_in_middle1": (2, False),
"return_in_middle2": (2, False),
"funcall_type_mismatch1": (2, False),
"funcall_type_mismatch2": (2, False),
"return_type_mismatch1": (1.5, False),
"return_type_mismatch2": (1.5, False),
}
# 11
lv3 = {
"complex1": (3, False),
"complex2": (3, True),
"complex3": (2, True),
"complex4": (3, False),
}
suite = [
("lv0_1", lv0_1, 0),
("lv0_2", lv0_2, 0),
("lv1", lv1, 0),
("lv2", lv2, 0),
("lv3", lv3, 0)
]
def eval():
f = open("eval_result", 'w')
EXE_PATH = "../../build/cminusfc"
TEST_BASE_PATH = "./testcases/"
ANSWER_BASE_PATH = "./answers/"
total_points = 0
for level in suite:
lv_points = 0
has_bonus = True
level_name = level[0]
bonus = level[2]
cases = level[1]
f.write('===========%s START========\n' % level_name)
for case in cases:
f.write('%s:' % case)
TEST_PATH = TEST_BASE_PATH + level_name + "/" + case
ANSWER_PATH = ANSWER_BASE_PATH + level_name + "/" + case
score = cases[case][0]
need_input = cases[case][1]
COMMAND = [TEST_PATH]
try:
result = subprocess.run([EXE_PATH, TEST_PATH + ".cminus"], stderr=subprocess.PIPE, timeout=1)
except Exception as _:
f.write('\tFail\n')
continue
if result.returncode == 0:
input_option = None
if need_input:
with open(ANSWER_PATH + ".in", "rb") as fin:
input_option = fin.read()
try:
result = subprocess.run(COMMAND, input=input_option, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1)
with open(ANSWER_PATH + ".out", "rb") as fout:
if result.stdout == fout.read():
f.write('\tSuccess\n')
lv_points += score
else:
f.write('\tFail\n')
has_bonus = False
except Exception as _:
f.write('\tFail\n')
has_bonus = False
finally:
subprocess.call(["rm", "-rf", TEST_PATH, TEST_PATH + ".o"])
else:
f.write('\tFail\n')
has_bonus = False
if has_bonus:
lv_points += bonus
total_points += lv_points
f.write('points of %s is: %d\n' % (level_name, lv_points))
f.write('===========%s END========\n\n' % level_name)
f.write('total points: %d\n' % total_points)
if __name__ == "__main__":
eval()
void main(void) {
float a;
return;
}
void main(void) {
float a[10];
return;
}
void main(void) {
int a;
return;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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