Commit 7b738bf2 authored by 张钏楠's avatar 张钏楠

feat(lab3): upload lab3 source file

parent ae229f0d
#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;
}
void main(void) {
int a[10];
return;
}
void main(void) {
input();
return;
}
void main(void) {
outputFloat(123.4);
return;
}
void main(void) {
output(1234);
return;
}
void main(void) {
output(100.0 + 23.4);
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.
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