├── .gitignore ├── test ├── hello ├── hello.o ├── hello.c ├── hello.koopa └── hello.s ├── src ├── ast │ ├── ast.hpp │ ├── ast.cpp │ ├── base_ast.hpp │ ├── code_ast.cpp │ ├── array_ast.hpp │ ├── code_ast.hpp │ └── exp_ast.hpp ├── loop_maintainer.hpp ├── koopa_util.hpp ├── symbol_list.hpp ├── sysy.l ├── block_maintainer.hpp ├── builder │ ├── riscv_builder.hpp │ ├── builder_code.cpp │ └── builder_value.cpp ├── main.cpp ├── koopa_util.cpp └── sysy.y ├── .vscode └── settings.json ├── CMakeLists.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | /build 3 | -------------------------------------------------------------------------------- /test/hello: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaptainHarryChen/StupidSysY2RV/HEAD/test/hello -------------------------------------------------------------------------------- /test/hello.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CaptainHarryChen/StupidSysY2RV/HEAD/test/hello.o -------------------------------------------------------------------------------- /src/ast/ast.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/base_ast.hpp" 4 | #include "ast/code_ast.hpp" 5 | #include "ast/exp_ast.hpp" 6 | #include "ast/array_ast.hpp" 7 | -------------------------------------------------------------------------------- /src/ast/ast.cpp: -------------------------------------------------------------------------------- 1 | #include "ast/ast.hpp" 2 | 3 | BlockMaintainer BaseAST::block_maintainer; 4 | SymbolList BaseAST::symbol_list; 5 | LoopMaintainer BaseAST::loop_maintainer; 6 | 7 | char *new_char_arr(std::string str) 8 | { 9 | size_t n = str.length(); 10 | char *res = new char[n + 1]; 11 | str.copy(res, n + 1); 12 | res[n] = 0; 13 | return res; 14 | } 15 | -------------------------------------------------------------------------------- /src/loop_maintainer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "koopa_util.hpp" 8 | 9 | struct KoopaWhile 10 | { 11 | koopa_raw_basic_block_data_t *while_entry; 12 | koopa_raw_basic_block_data_t *while_body; 13 | koopa_raw_basic_block_data_t *end_block; 14 | }; 15 | 16 | class LoopMaintainer 17 | { 18 | std::vector loop_stk; 19 | 20 | public: 21 | void AddLoop(koopa_raw_basic_block_data_t *while_entry, koopa_raw_basic_block_data_t *while_body, koopa_raw_basic_block_data_t *end_block) 22 | { 23 | KoopaWhile kw; 24 | kw.while_entry = while_entry; 25 | kw.while_body = while_body; 26 | kw.end_block = end_block; 27 | loop_stk.push_back(kw); 28 | } 29 | KoopaWhile GetLoop() { return loop_stk[loop_stk.size() - 1]; } 30 | void PopLoop() { loop_stk.pop_back(); } 31 | }; 32 | -------------------------------------------------------------------------------- /test/hello.c: -------------------------------------------------------------------------------- 1 | const int ascii_0 = 48; 2 | 3 | int my_getint() 4 | { 5 | int sum = 0, c; 6 | 7 | while (1) { 8 | c = getch() - ascii_0; 9 | if (c < 0 || c > 9) { 10 | continue; 11 | } else { 12 | break; 13 | } 14 | } 15 | sum = c; 16 | 17 | while (1) { 18 | c = getch() - ascii_0; 19 | if (c >= 0 && c <= 9) { 20 | sum = sum * 10 + c; 21 | } else { 22 | break; 23 | } 24 | } 25 | 26 | return sum; 27 | } 28 | 29 | void my_putint(int a) 30 | { 31 | int b[16], i = 0; 32 | while (a > 0) { 33 | b[i] = a % 10 + ascii_0; 34 | a = a / 10; 35 | i = i + 1; 36 | } 37 | while (i > 0) { 38 | i = i - 1; 39 | putch(b[i]); 40 | } 41 | } 42 | 43 | int main() 44 | { 45 | int n = my_getint(); 46 | while (n > 0) { 47 | int m = my_getint(); 48 | my_putint(m); putch(10); 49 | n = n - 1; 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /src/koopa_util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | koopa_raw_slice_t empty_koopa_rs(koopa_raw_slice_item_kind_t kind = KOOPA_RSIK_UNKNOWN); 8 | koopa_raw_slice_t make_koopa_rs_from_vector(const std::vector &vec, koopa_raw_slice_item_kind_t kind = KOOPA_RSIK_UNKNOWN); 9 | koopa_raw_slice_t make_koopa_rs_single_element(const void *ele, koopa_raw_slice_item_kind_t kind = KOOPA_RSIK_UNKNOWN); 10 | koopa_raw_slice_t add_element_to_koopa_rs(koopa_raw_slice_t origin, const void *ele); 11 | 12 | koopa_raw_type_kind* make_array_type(const std::vector &sz, int st_pos = 0); 13 | koopa_raw_type_kind* simple_koopa_raw_type_kind(koopa_raw_type_tag_t tag); 14 | koopa_raw_type_kind* make_int_pointer_type(); 15 | 16 | koopa_raw_value_data *make_koopa_interger(int x); 17 | koopa_raw_value_data *JumpInst(koopa_raw_basic_block_t target); 18 | koopa_raw_value_data *AllocIntInst(const std::string &name); 19 | koopa_raw_value_data *AllocType(const std::string &name, koopa_raw_type_t ty); 20 | koopa_raw_value_data *ZeroInit(koopa_raw_type_kind *_type = nullptr); 21 | 22 | char *new_char_arr(std::string str); -------------------------------------------------------------------------------- /src/symbol_list.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | class BaseAST; 11 | 12 | struct LValSymbol 13 | { 14 | enum SymbolType 15 | { 16 | Const, 17 | Var, 18 | Array, 19 | Pointer, 20 | Function 21 | } type; 22 | void *number; 23 | LValSymbol() {} 24 | LValSymbol(SymbolType _type, void * _number) : type(_type), number(_number) {} 25 | }; 26 | 27 | class SymbolList 28 | { 29 | std::vector> sym_stk; 30 | 31 | public: 32 | void NewEnv() 33 | { 34 | sym_stk.push_back(std::map()); 35 | } 36 | void AddSymbol(const std::string &name, LValSymbol koopa_item) 37 | { 38 | auto &list = sym_stk[sym_stk.size() - 1]; 39 | assert(list.count(name) == 0); 40 | list[name] = koopa_item; 41 | } 42 | LValSymbol GetSymbol(const std::string &name) 43 | { 44 | LValSymbol res; 45 | for (size_t i = sym_stk.size() - 1; i >= 0; i--) 46 | if (sym_stk[i].count(name) != 0) 47 | { 48 | res = sym_stk[i][name]; 49 | break; 50 | } 51 | return res; 52 | } 53 | void DeleteEnv() 54 | { 55 | sym_stk.pop_back(); 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "array": "cpp", 4 | "atomic": "cpp", 5 | "bit": "cpp", 6 | "*.tcc": "cpp", 7 | "cctype": "cpp", 8 | "clocale": "cpp", 9 | "cmath": "cpp", 10 | "cstdarg": "cpp", 11 | "cstddef": "cpp", 12 | "cstdint": "cpp", 13 | "cstdio": "cpp", 14 | "cstdlib": "cpp", 15 | "cwchar": "cpp", 16 | "cwctype": "cpp", 17 | "deque": "cpp", 18 | "unordered_map": "cpp", 19 | "vector": "cpp", 20 | "exception": "cpp", 21 | "algorithm": "cpp", 22 | "functional": "cpp", 23 | "iterator": "cpp", 24 | "memory": "cpp", 25 | "memory_resource": "cpp", 26 | "numeric": "cpp", 27 | "optional": "cpp", 28 | "random": "cpp", 29 | "string": "cpp", 30 | "string_view": "cpp", 31 | "system_error": "cpp", 32 | "tuple": "cpp", 33 | "type_traits": "cpp", 34 | "utility": "cpp", 35 | "fstream": "cpp", 36 | "initializer_list": "cpp", 37 | "iosfwd": "cpp", 38 | "iostream": "cpp", 39 | "istream": "cpp", 40 | "limits": "cpp", 41 | "new": "cpp", 42 | "ostream": "cpp", 43 | "sstream": "cpp", 44 | "stdexcept": "cpp", 45 | "streambuf": "cpp", 46 | "cinttypes": "cpp", 47 | "typeinfo": "cpp", 48 | "cstring": "cpp", 49 | "cassert": "cpp", 50 | "map": "cpp" 51 | }, 52 | "cmake.debugConfig": { 53 | //"args":["-koopa", "../test/hello.c", "-o", "../test/hello.koopa"] 54 | "args":["-riscv", "../test/hello.c", "-o", "../test/hello.s"] 55 | } 56 | } -------------------------------------------------------------------------------- /src/ast/base_ast.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "koopa_util.hpp" 10 | #include "symbol_list.hpp" 11 | #include "block_maintainer.hpp" 12 | #include "loop_maintainer.hpp" 13 | 14 | char *new_char_arr(std::string str); 15 | 16 | // 所有 AST 的基类 17 | class BaseAST 18 | { 19 | public: 20 | static SymbolList symbol_list; 21 | static BlockMaintainer block_maintainer; 22 | static LoopMaintainer loop_maintainer; 23 | 24 | virtual ~BaseAST() = default; 25 | // 调试用字符串 26 | virtual std::string to_string() const 27 | { 28 | return "(Not Implement)"; 29 | } 30 | // 输出koopa对象,并在全局环境添加各种信息 31 | virtual void *build_koopa_values() const 32 | { 33 | std::cerr << "Not Implement build_koopa_values" << std::endl; 34 | assert(false); 35 | return nullptr; 36 | } 37 | // 用于表达式AST求值 38 | virtual int CalcValue() const 39 | { 40 | std::cerr << "Not Implement build_koopa_values" << std::endl; 41 | assert(false); 42 | return 0; 43 | } 44 | // 返回该AST的左值(用于变量) 45 | virtual void *koopa_leftvalue() const 46 | { 47 | std::cerr << "Not Implement build_koopa_values" << std::endl; 48 | assert(false); 49 | return 0; 50 | } 51 | }; 52 | 53 | class NumberAST : public BaseAST 54 | { 55 | public: 56 | int val; 57 | NumberAST(int _val) { val = _val; } 58 | std::string to_string() const override 59 | { 60 | return "NumberAST { int " + std::to_string(val) + " }"; 61 | } 62 | 63 | void *build_koopa_values() const override 64 | { 65 | koopa_raw_value_data *res = new koopa_raw_value_data(); 66 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 67 | res->name = nullptr; 68 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 69 | res->kind.tag = KOOPA_RVT_INTEGER; 70 | res->kind.data.integer.value = val; 71 | return res; 72 | } 73 | int CalcValue() const override 74 | { 75 | return val; 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /src/sysy.l: -------------------------------------------------------------------------------- 1 | %option noyywrap 2 | %option nounput 3 | %option noinput 4 | 5 | %{ 6 | 7 | #include 8 | #include 9 | 10 | // 因为 Flex 会用到 Bison 中关于 token 的定义 11 | // 所以需要 include Bison 生成的头文件 12 | #include "sysy.tab.hpp" 13 | 14 | using namespace std; 15 | 16 | %} 17 | 18 | /* 空白符和注释 */ 19 | WhiteSpace [ \t\n\r]* 20 | LineComment "//".* 21 | MultiLineComment \/\*([^*]|(\*+[^*/]))*\*+\/ 22 | 23 | /* 标识符 */ 24 | Identifier [a-zA-Z_][a-zA-Z0-9_]* 25 | 26 | /* 运算符 */ 27 | UnaryOperator \! 28 | AddOperator \+|\- 29 | MulOperator \*|\/|\% 30 | RelOperator <|>|<=|>= 31 | EqOperator ==|\!= 32 | LAndOperator && 33 | LOrOperator \|\| 34 | 35 | /* 整数字面量 */ 36 | Decimal [1-9][0-9]* 37 | Octal 0[0-7]* 38 | Hexadecimal 0[xX][0-9a-fA-F]+ 39 | 40 | %% 41 | 42 | {WhiteSpace} { /* 忽略, 不做任何操作 */ } 43 | {LineComment} { /* 忽略, 不做任何操作 */ } 44 | {MultiLineComment} { /* 忽略, 不做任何操作 */ } 45 | 46 | "int" { return INT; } 47 | "return" { return RETURN; } 48 | "const" { return CONST; } 49 | "if" { return IF; } 50 | "else" { return ELSE; } 51 | "while" { return WHILE; } 52 | "break" { return BREAK; } 53 | "continue" { return CONTINUE; } 54 | "void" { return VOID; } 55 | 56 | {Identifier} { yylval.str_val = new string(yytext); return IDENT; } 57 | {UnaryOperator} { yylval.str_val = new string(yytext); return UNARYOP; } 58 | {AddOperator} { yylval.str_val = new string(yytext); return ADDOP; } 59 | {MulOperator} { yylval.str_val = new string(yytext); return MULOP; } 60 | {RelOperator} { yylval.str_val = new string(yytext); return RELOP; } 61 | {EqOperator} { yylval.str_val = new string(yytext); return EQOP; } 62 | {LAndOperator} { yylval.str_val = new string(yytext); return LANDOP; } 63 | {LOrOperator} { yylval.str_val = new string(yytext); return LOROP; } 64 | 65 | {Decimal} { yylval.int_val = strtol(yytext, nullptr, 0); return INT_CONST; } 66 | {Octal} { yylval.int_val = strtol(yytext, nullptr, 0); return INT_CONST; } 67 | {Hexadecimal} { yylval.int_val = strtol(yytext, nullptr, 0); return INT_CONST; } 68 | 69 | . { return yytext[0]; } 70 | 71 | %% 72 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(compiler) 3 | 4 | # settings 5 | # set to OFF to enable C mode 6 | set(CPP_MODE ON) 7 | if(CPP_MODE) 8 | set(FB_EXT ".cpp") 9 | else() 10 | set(FB_EXT ".c") 11 | endif() 12 | message(STATUS "Flex/Bison generated source file extension: ${FB_EXT}") 13 | 14 | # enable all warnings 15 | if(MSVC) 16 | add_compile_options(/W3) 17 | else() 18 | # disable warnings caused by old version of Flex 19 | add_compile_options(-Wall -Wno-register) 20 | endif() 21 | 22 | # options about libraries and includes 23 | set(LIB_DIR "$ENV{CDE_LIBRARY_PATH}/native" CACHE STRING "directory of libraries") 24 | set(INC_DIR "$ENV{CDE_INCLUDE_PATH}" CACHE STRING "directory of includes") 25 | message(STATUS "Library directory: ${LIB_DIR}") 26 | message(STATUS "Include directory: ${INC_DIR}") 27 | 28 | # find Flex/Bison 29 | find_package(FLEX REQUIRED) 30 | find_package(BISON REQUIRED) 31 | 32 | # generate lexer/parser 33 | file(GLOB_RECURSE L_SOURCES "src/*.l") 34 | file(GLOB_RECURSE Y_SOURCES "src/*.y") 35 | if(NOT (L_SOURCES STREQUAL "" AND Y_SOURCES STREQUAL "")) 36 | string(REGEX REPLACE ".*/(.*)\\.l" "${CMAKE_CURRENT_BINARY_DIR}/\\1.lex${FB_EXT}" L_OUTPUTS "${L_SOURCES}") 37 | string(REGEX REPLACE ".*/(.*)\\.y" "${CMAKE_CURRENT_BINARY_DIR}/\\1.tab${FB_EXT}" Y_OUTPUTS "${Y_SOURCES}") 38 | flex_target(Lexer ${L_SOURCES} ${L_OUTPUTS}) 39 | bison_target(Parser ${Y_SOURCES} ${Y_OUTPUTS}) 40 | add_flex_bison_dependency(Lexer Parser) 41 | endif() 42 | 43 | # project link directories 44 | link_directories(${LIB_DIR}) 45 | 46 | # project include directories 47 | include_directories(src) 48 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 49 | include_directories(${INC_DIR}) 50 | 51 | # all of C/C++ source files 52 | file(GLOB_RECURSE C_SOURCES "src/*.c" "src/**/*.c") 53 | file(GLOB_RECURSE CXX_SOURCES "src/*.cpp" "src/**/*.cpp") 54 | file(GLOB_RECURSE CC_SOURCES "src/*.cc" "src/**/*.cc") 55 | set(SOURCES ${C_SOURCES} ${CXX_SOURCES} ${CC_SOURCES} 56 | ${FLEX_Lexer_OUTPUTS} ${BISON_Parser_OUTPUT_SOURCE}) 57 | 58 | # executable 59 | add_executable(compiler ${SOURCES}) 60 | set_target_properties(compiler PROPERTIES C_STANDARD 11 CXX_STANDARD 17) 61 | target_link_libraries(compiler koopa pthread dl) 62 | -------------------------------------------------------------------------------- /src/block_maintainer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "koopa_util.hpp" 9 | 10 | class BlockMaintainer 11 | { 12 | koopa_raw_function_t current_func; 13 | std::vector current_insts_buf; 14 | std::vector *basic_block_buf; 15 | 16 | public: 17 | void SetCurrentFunction(koopa_raw_function_t _cur_func) 18 | { 19 | current_func = _cur_func; 20 | } 21 | void SetBasicBlockBuf(std::vector *_basic_block_buf) 22 | { 23 | basic_block_buf = _basic_block_buf; 24 | } 25 | void FinishCurrentBlock() 26 | { 27 | if (basic_block_buf->size() > 0) 28 | { 29 | koopa_raw_basic_block_data_t *last_block = (koopa_raw_basic_block_data_t *)(*basic_block_buf)[basic_block_buf->size() - 1]; 30 | bool found = false; 31 | for (size_t i = 0; i < current_insts_buf.size(); i++) 32 | { 33 | koopa_raw_value_t t = (koopa_raw_value_t)current_insts_buf[i]; 34 | if (t->kind.tag == KOOPA_RVT_BRANCH || t->kind.tag == KOOPA_RVT_RETURN || t->kind.tag == KOOPA_RVT_JUMP) 35 | { 36 | current_insts_buf.resize(i + 1); 37 | found = true; 38 | break; 39 | } 40 | } 41 | if(!found) 42 | { 43 | koopa_raw_value_data *ret = new koopa_raw_value_data(); 44 | ret->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 45 | ret->name = nullptr; 46 | ret->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 47 | ret->kind.tag = KOOPA_RVT_RETURN; 48 | if(current_func->ty->data.function.ret->tag == KOOPA_RTT_UNIT) 49 | ret->kind.data.ret.value = nullptr; 50 | else 51 | ret->kind.data.ret.value = make_koopa_interger(0); 52 | current_insts_buf.push_back(ret); 53 | } 54 | if (!last_block->insts.buffer) 55 | last_block->insts = make_koopa_rs_from_vector(current_insts_buf, KOOPA_RSIK_VALUE); 56 | } 57 | current_insts_buf.clear(); 58 | } 59 | void AddNewBasicBlock(koopa_raw_basic_block_data_t *basic_block) 60 | { 61 | FinishCurrentBlock(); 62 | basic_block->insts.buffer = nullptr; 63 | basic_block_buf->push_back(basic_block); 64 | } 65 | void AddInst(const void *inst) 66 | { 67 | current_insts_buf.push_back(inst); 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /src/builder/riscv_builder.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | using std::ostream, std::endl, std::map, std::string; 10 | 11 | class RISCVBuilder 12 | { 13 | class Env 14 | { 15 | int total_size; 16 | map addr; 17 | 18 | public: 19 | int cur; 20 | bool has_call; 21 | 22 | void NewEnv(int size, bool _has_call) 23 | { 24 | total_size = cur = size; 25 | has_call = _has_call; 26 | addr.clear(); 27 | } 28 | int GetTotalSize() 29 | { 30 | return total_size; 31 | } 32 | int GetAddr(koopa_raw_value_t kval) 33 | { 34 | if (addr.count(kval)) 35 | return addr[kval]; 36 | int t = calc_inst_size(kval); 37 | if (t == 0) 38 | return 2333333; 39 | cur -= t; 40 | addr[kval] = cur; 41 | return cur; 42 | } 43 | }; 44 | 45 | int magic_cnt_num = 0; 46 | Env env; 47 | string current_func_name; 48 | ostream &output; 49 | 50 | static int calc_func_size(koopa_raw_function_t kfunc, bool &has_call); 51 | static int calc_blk_size(koopa_raw_basic_block_t kblk, bool &has_call); 52 | static int calc_inst_size(koopa_raw_value_t kval); 53 | static int calc_type_size(koopa_raw_type_t ty); 54 | 55 | void traversal_raw_slice(const koopa_raw_slice_t *rs); 56 | void gen_riscv_func(koopa_raw_function_t kfunc); 57 | void gen_riscv_block(koopa_raw_basic_block_t kblk); 58 | void gen_riscv_value(koopa_raw_value_t kval); 59 | 60 | void load_to_reg(koopa_raw_value_t kval, const char *reg); 61 | void store_to_stack(int addr, const char *reg); 62 | void gen_riscv_value_aggregate(koopa_raw_value_t kval); 63 | void gen_riscv_value_global_alloc(koopa_raw_value_t kalloc); 64 | void gen_riscv_value_load(const koopa_raw_load_t *kload, int addr); 65 | void gen_riscv_value_store(const koopa_raw_store_t *kstore); 66 | void gen_riscv_value_get_ptr(const koopa_raw_get_ptr_t *kget, int addr); 67 | void gen_riscv_value_get_elem_ptr(const koopa_raw_get_elem_ptr_t *kget, int addr); 68 | void gen_riscv_value_binary(const koopa_raw_binary_t *kbinary, int addr); 69 | void gen_riscv_value_branch(const koopa_raw_branch_t *kbranch); 70 | void gen_riscv_value_jump(const koopa_raw_jump_t *kjump); 71 | void gen_riscv_value_call(const koopa_raw_call_t *kcall, int addr); 72 | void gen_riscv_value_return(const koopa_raw_return_t *kret); 73 | 74 | public: 75 | RISCVBuilder(ostream &_out) : output(_out) {} 76 | 77 | void build(const koopa_raw_program_t *raw); 78 | }; 79 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ast/ast.hpp" 10 | #include "builder/riscv_builder.hpp" 11 | 12 | // 声明 lexer 的输入, 以及 parser 函数 13 | extern FILE *yyin; 14 | extern int yyparse(std::unique_ptr &ast); 15 | 16 | int main(int argc, const char *argv[]) 17 | { 18 | // 解析命令行参数. 测试脚本/评测平台要求你的编译器能接收如下参数: 19 | // compiler 模式 输入文件 -o 输出文件 20 | assert(argc == 5); 21 | auto mode = argv[1]; 22 | auto input = argv[2]; 23 | auto output = argv[4]; 24 | 25 | std::cout << "mode: " << mode << std::endl; 26 | // 打开输入文件, 并且指定 lexer 在解析的时候读取这个文件 27 | yyin = fopen(input, "r"); 28 | assert(yyin); 29 | 30 | // 调用 parser 函数, parser 函数会进一步调用 lexer 解析输入文件的 31 | std::unique_ptr ast; 32 | auto ret = yyparse(ast); 33 | if(ret) 34 | { 35 | std::cout << "yyparse error: " << ret << std::endl; 36 | assert(!ret); 37 | } 38 | 39 | // 输出解析得到的 AST 40 | // std::cout << "AST:" << std::endl << ast->to_string() << std::endl; 41 | 42 | std::unique_ptr comp_ast(dynamic_cast(ast.release())); 43 | koopa_raw_program_t krp = comp_ast->to_koopa_raw_program(); 44 | 45 | if(strcmp(mode, "-koopa") == 0) 46 | { 47 | std::cout << "generate koopa file..." << std::endl; 48 | koopa_program_t kp; 49 | koopa_error_code_t eno = koopa_generate_raw_to_koopa(&krp, &kp); 50 | if (eno != KOOPA_EC_SUCCESS) 51 | { 52 | std::cout << "generate raw to koopa error: " << (int)eno << std::endl; 53 | return 0; 54 | } 55 | koopa_dump_to_file(kp, output); 56 | } 57 | else if(strcmp(mode, "-riscv") == 0 || strcmp(mode, "-perf") == 0) 58 | { 59 | std::cout << "generate koopa file..." << std::endl; 60 | koopa_program_t kp; 61 | koopa_error_code_t eno = koopa_generate_raw_to_koopa(&krp, &kp); 62 | char *buffer = new char[1000000]; 63 | size_t sz = 1000000u; 64 | eno = koopa_dump_to_string(kp, buffer, &sz); 65 | if (eno != KOOPA_EC_SUCCESS) 66 | { 67 | std::cout << "koopa dump to string error: " << (int)eno << std::endl; 68 | return 0; 69 | } 70 | koopa_delete_program(kp); 71 | 72 | koopa_program_t new_kp; 73 | eno = koopa_parse_from_string(buffer, &new_kp); 74 | if (eno != KOOPA_EC_SUCCESS) 75 | { 76 | std::cout << "generate raw to koopa error: " << (int)eno << std::endl; 77 | return 0; 78 | } 79 | koopa_raw_program_builder_t kp_builder = koopa_new_raw_program_builder(); 80 | koopa_raw_program_t new_krp = koopa_build_raw_program(kp_builder, new_kp); 81 | koopa_delete_program(new_kp); 82 | 83 | std::cout << "generate riscv file..." << std::endl; 84 | std::ofstream out(output); 85 | //RISCVBuilder builder(std::cout); 86 | RISCVBuilder builder(out); 87 | builder.build(&new_krp); 88 | out.close(); 89 | koopa_delete_raw_program_builder(kp_builder); 90 | } 91 | 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /test/hello.koopa: -------------------------------------------------------------------------------- 1 | decl @getint(): i32 2 | 3 | decl @getch(): i32 4 | 5 | decl @getarray(*i32): i32 6 | 7 | decl @putint(i32) 8 | 9 | decl @putch(i32) 10 | 11 | decl @putarray(i32, *i32) 12 | 13 | decl @starttime() 14 | 15 | decl @stoptime() 16 | 17 | fun @my_getint(): i32 { 18 | %entry_my_getint: 19 | @sum = alloc i32 20 | store 0, @sum 21 | @c = alloc i32 22 | jump %while_entry 23 | 24 | %while_entry: 25 | br 1, %while_body, %end 26 | 27 | %while_body: 28 | %0 = call @getch() 29 | %1 = sub %0, 48 30 | store %1, @c 31 | %temp = alloc i32 32 | store 1, %temp 33 | %2 = load @c 34 | %3 = lt %2, 0 35 | %4 = eq %3, 0 36 | br %4, %true, %end_0 37 | 38 | %true: 39 | %5 = load @c 40 | %6 = gt %5, 9 41 | %7 = ne %6, 0 42 | store %7, %temp 43 | jump %end_0 44 | 45 | %end_0: 46 | %8 = load %temp 47 | br %8, %true_0, %false 48 | 49 | %true_0: 50 | jump %while_entry 51 | 52 | %false: 53 | jump %end 54 | 55 | %end: 56 | %9 = load @c 57 | store %9, @sum 58 | jump %while_entry_0 59 | 60 | %while_entry_0: 61 | br 1, %while_body_0, %end_1 62 | 63 | %while_body_0: 64 | %10 = call @getch() 65 | %11 = sub %10, 48 66 | store %11, @c 67 | %temp_0 = alloc i32 68 | store 0, %temp_0 69 | %12 = load @c 70 | %13 = ge %12, 0 71 | %14 = ne %13, 0 72 | br %14, %true_1, %end_2 73 | 74 | %true_1: 75 | %15 = load @c 76 | %16 = le %15, 9 77 | %17 = ne %16, 0 78 | store %17, %temp_0 79 | jump %end_2 80 | 81 | %end_2: 82 | %18 = load %temp_0 83 | br %18, %true_2, %false_0 84 | 85 | %true_2: 86 | %19 = load @sum 87 | %20 = mul %19, 10 88 | %21 = load @c 89 | %22 = add %20, %21 90 | store %22, @sum 91 | jump %end_3 92 | 93 | %end_3: 94 | jump %while_entry_0 95 | 96 | %false_0: 97 | jump %end_1 98 | 99 | %end_1: 100 | %23 = load @sum 101 | ret %23 102 | 103 | %end_4: 104 | jump %while_entry 105 | } 106 | 107 | fun @my_putint(@a: i32) { 108 | %entry_my_putint: 109 | @a_0 = alloc i32 110 | store @a, @a_0 111 | @b = alloc [i32, 16] 112 | @i = alloc i32 113 | store 0, @i 114 | jump %while_entry 115 | 116 | %while_entry: 117 | %24 = load @a_0 118 | %25 = gt %24, 0 119 | br %25, %while_body, %end 120 | 121 | %while_body: 122 | %26 = load @a_0 123 | %27 = mod %26, 10 124 | %28 = add %27, 48 125 | %29 = load @i 126 | %30 = getelemptr @b, %29 127 | store %28, %30 128 | %31 = load @a_0 129 | %32 = div %31, 10 130 | store %32, @a_0 131 | %33 = load @i 132 | %34 = add %33, 1 133 | store %34, @i 134 | jump %while_entry 135 | 136 | %end: 137 | jump %while_entry_0 138 | 139 | %while_entry_0: 140 | %35 = load @i 141 | %36 = gt %35, 0 142 | br %36, %while_body_0, %end_0 143 | 144 | %while_body_0: 145 | %37 = load @i 146 | %38 = sub %37, 1 147 | store %38, @i 148 | %39 = load @i 149 | %40 = getelemptr @b, %39 150 | %41 = load %40 151 | call @putch(%41) 152 | jump %while_entry_0 153 | 154 | %end_0: 155 | ret 156 | } 157 | 158 | fun @main(): i32 { 159 | %entry_main: 160 | @n = alloc i32 161 | %42 = call @my_getint() 162 | store %42, @n 163 | jump %while_entry 164 | 165 | %while_entry: 166 | %43 = load @n 167 | %44 = gt %43, 0 168 | br %44, %while_body, %end 169 | 170 | %while_body: 171 | @m = alloc i32 172 | %45 = call @my_getint() 173 | store %45, @m 174 | %46 = load @m 175 | call @my_putint(%46) 176 | call @putch(10) 177 | %47 = load @n 178 | %48 = sub %47, 1 179 | store %48, @n 180 | jump %while_entry 181 | 182 | %end: 183 | ret 0 184 | } 185 | -------------------------------------------------------------------------------- /src/koopa_util.cpp: -------------------------------------------------------------------------------- 1 | #include "koopa_util.hpp" 2 | 3 | #include 4 | #include 5 | 6 | koopa_raw_slice_t empty_koopa_rs(koopa_raw_slice_item_kind_t kind) 7 | { 8 | koopa_raw_slice_t res; 9 | res.buffer = nullptr; 10 | res.kind = kind; 11 | res.len = 0; 12 | return res; 13 | } 14 | 15 | koopa_raw_slice_t make_koopa_rs_from_vector(const std::vector &vec, koopa_raw_slice_item_kind_t kind) 16 | { 17 | koopa_raw_slice_t res; 18 | res.buffer = new const void *[vec.size()]; 19 | std::copy(vec.begin(), vec.end(), res.buffer); 20 | res.kind = kind; 21 | res.len = vec.size(); 22 | return res; 23 | } 24 | 25 | koopa_raw_slice_t make_koopa_rs_single_element(const void *ele, koopa_raw_slice_item_kind_t kind) 26 | { 27 | koopa_raw_slice_t res; 28 | res.buffer = new const void *[1]; 29 | res.buffer[0] = ele; 30 | res.kind = kind; 31 | res.len = 1; 32 | return res; 33 | } 34 | 35 | koopa_raw_slice_t add_element_to_koopa_rs(koopa_raw_slice_t origin, const void *ele) 36 | { 37 | koopa_raw_slice_t res; 38 | res.buffer = new const void *[origin.len + 1]; 39 | memcpy(res.buffer, origin.buffer, sizeof(void *) * origin.len); 40 | res.buffer[origin.len] = ele; 41 | res.len = origin.len + 1; 42 | res.kind = origin.kind; 43 | delete origin.buffer; 44 | 45 | return res; 46 | } 47 | 48 | koopa_raw_type_kind *simple_koopa_raw_type_kind(koopa_raw_type_tag_t tag) 49 | { 50 | assert(tag == KOOPA_RTT_INT32 || tag == KOOPA_RTT_UNIT); 51 | koopa_raw_type_kind *res = new koopa_raw_type_kind(); 52 | res->tag = tag; 53 | return res; 54 | } 55 | 56 | koopa_raw_type_kind* make_int_pointer_type() 57 | { 58 | koopa_raw_type_kind *res = new koopa_raw_type_kind(); 59 | res->tag = KOOPA_RTT_POINTER; 60 | res->data.pointer.base = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 61 | return res; 62 | } 63 | 64 | koopa_raw_type_kind* make_array_type(const std::vector &sz, int st_pos) 65 | { 66 | std::vector ty_list; 67 | for(size_t i = st_pos; i < sz.size(); i++) 68 | { 69 | koopa_raw_type_kind *new_rt = new koopa_raw_type_kind(); 70 | new_rt->tag = KOOPA_RTT_ARRAY; 71 | new_rt->data.array.len = sz[i]; 72 | ty_list.push_back(new_rt); 73 | } 74 | ty_list[ty_list.size() - 1]->data.array.base = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 75 | for(size_t i = 0; i < ty_list.size() - 1; i++) 76 | ty_list[i]->data.array.base = ty_list[i + 1]; 77 | return ty_list[0]; 78 | } 79 | 80 | koopa_raw_value_data *make_koopa_interger(int x) 81 | { 82 | koopa_raw_value_data *res = new koopa_raw_value_data(); 83 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 84 | res->name = nullptr; 85 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 86 | res->kind.tag = KOOPA_RVT_INTEGER; 87 | res->kind.data.integer.value = x; 88 | return res; 89 | } 90 | 91 | koopa_raw_value_data *JumpInst(koopa_raw_basic_block_t target) 92 | { 93 | koopa_raw_value_data *res = new koopa_raw_value_data(); 94 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 95 | res->name = nullptr; 96 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 97 | res->kind.tag = KOOPA_RVT_JUMP; 98 | res->kind.data.jump.args = empty_koopa_rs(KOOPA_RSIK_VALUE); 99 | res->kind.data.jump.target = target; 100 | return res; 101 | } 102 | 103 | koopa_raw_value_data *AllocIntInst(const std::string &name) 104 | { 105 | koopa_raw_value_data *res = new koopa_raw_value_data(); 106 | res->ty = make_int_pointer_type(); 107 | res->name = new_char_arr(name); 108 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 109 | res->kind.tag = KOOPA_RVT_ALLOC; 110 | return res; 111 | } 112 | 113 | koopa_raw_value_data *AllocType(const std::string &name, koopa_raw_type_t ty) 114 | { 115 | koopa_raw_value_data *res = new koopa_raw_value_data(); 116 | koopa_raw_type_kind *tty = new koopa_raw_type_kind(); 117 | tty->tag = KOOPA_RTT_POINTER; 118 | tty->data.pointer.base = ty; 119 | res->ty = tty; 120 | res->name = new_char_arr(name); 121 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 122 | res->kind.tag = KOOPA_RVT_ALLOC; 123 | return res; 124 | } 125 | 126 | koopa_raw_value_data *ZeroInit(koopa_raw_type_kind *_type) 127 | { 128 | koopa_raw_value_data *res = new koopa_raw_value_data(); 129 | if(_type) 130 | res->ty = _type; 131 | else 132 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 133 | res->name = nullptr; 134 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 135 | res->kind.tag = KOOPA_RVT_ZERO_INIT; 136 | return res; 137 | } 138 | -------------------------------------------------------------------------------- /src/builder/builder_code.cpp: -------------------------------------------------------------------------------- 1 | #include "builder/riscv_builder.hpp" 2 | 3 | int RISCVBuilder::calc_func_size(koopa_raw_function_t kfunc, bool &has_call) 4 | { 5 | int total_size = 0; 6 | for (uint32_t i = 0; i < kfunc->bbs.len; i++) 7 | { 8 | const void *data = kfunc->bbs.buffer[i]; 9 | total_size += calc_blk_size((koopa_raw_basic_block_t)data, has_call); 10 | } 11 | total_size += has_call ? 4 : 0; 12 | return total_size; 13 | } 14 | 15 | int RISCVBuilder::calc_blk_size(koopa_raw_basic_block_t kblk, bool &has_call) 16 | { 17 | // TODO: did not count params 18 | int total_size = 0; 19 | for (uint32_t i = 0; i < kblk->insts.len; i++) 20 | { 21 | const void *data = kblk->insts.buffer[i]; 22 | if(((koopa_raw_value_t)data)->kind.tag == KOOPA_RVT_CALL) 23 | has_call = true; 24 | total_size += calc_inst_size((koopa_raw_value_t)data); 25 | } 26 | return total_size; 27 | } 28 | 29 | int RISCVBuilder::calc_inst_size(koopa_raw_value_t kval) 30 | { 31 | if(kval->kind.tag == KOOPA_RVT_ALLOC) 32 | return calc_type_size(kval->ty->data.pointer.base); 33 | return calc_type_size(kval->ty); 34 | } 35 | 36 | int RISCVBuilder::calc_type_size(koopa_raw_type_t ty) 37 | { 38 | switch(ty->tag) 39 | { 40 | case KOOPA_RTT_INT32: 41 | return 4; 42 | case KOOPA_RTT_UNIT: 43 | return 0; 44 | case KOOPA_RTT_POINTER: 45 | return 4; 46 | case KOOPA_RTT_ARRAY: 47 | return calc_type_size(ty->data.array.base) * ty->data.array.len; 48 | } 49 | } 50 | 51 | void RISCVBuilder::gen_riscv_func(koopa_raw_function_t kfunc) 52 | { 53 | if(kfunc->bbs.len == 0) 54 | return; 55 | const char *name = kfunc->name + 1; 56 | output << ".globl " << name << endl; 57 | output << name << ":" << endl; 58 | 59 | bool has_call = false; 60 | int size = calc_func_size(kfunc, has_call); 61 | if(size != 0) 62 | { 63 | size = ((size - 1) / 16 + 1) * 16; 64 | if(-size < -2048 || -size > 2047) 65 | { 66 | output << "\tli t0, " << -size << endl; 67 | output << "\tadd sp, sp, t0" << endl; 68 | } 69 | else 70 | output << "\taddi sp, sp, " << -size << endl; 71 | } 72 | if(has_call) 73 | { 74 | int offset = size - 4; 75 | if(offset < -2048 || offset > 2047) 76 | { 77 | output << "\tli t0, " << offset << endl; 78 | output << "\tadd t0, sp, t0" << endl; 79 | output << "\tsw ra, 0(t0)" << endl; 80 | } 81 | else 82 | output << "\tsw ra, " << offset << "(sp)" << endl; 83 | } 84 | env.NewEnv(size, has_call); 85 | env.cur -= (has_call ? 4 : 0); 86 | // blocks 87 | current_func_name = kfunc->name + 1; 88 | traversal_raw_slice(&kfunc->bbs); 89 | } 90 | 91 | void RISCVBuilder::gen_riscv_block(koopa_raw_basic_block_t kblk) 92 | { 93 | //TODO: params 94 | //TODO: used_by 95 | output << endl; 96 | output << current_func_name << "_" << kblk->name + 1 << ":" << endl; 97 | traversal_raw_slice(&kblk->insts); 98 | } 99 | 100 | void RISCVBuilder::gen_riscv_value(koopa_raw_value_t kval) 101 | { 102 | int addr = env.GetAddr(kval); 103 | switch(kval->kind.tag) 104 | { 105 | case KOOPA_RVT_INTEGER: 106 | output << kval->kind.data.integer.value; 107 | break; 108 | case KOOPA_RVT_ALLOC: 109 | break; 110 | case KOOPA_RVT_GLOBAL_ALLOC: 111 | gen_riscv_value_global_alloc(kval); 112 | break; 113 | case KOOPA_RVT_LOAD: 114 | gen_riscv_value_load(&kval->kind.data.load, addr); 115 | break; 116 | case KOOPA_RVT_STORE: 117 | gen_riscv_value_store(&kval->kind.data.store); 118 | break; 119 | case KOOPA_RVT_GET_PTR: 120 | gen_riscv_value_get_ptr(&kval->kind.data.get_ptr, addr); 121 | break; 122 | case KOOPA_RVT_GET_ELEM_PTR: 123 | gen_riscv_value_get_elem_ptr(&kval->kind.data.get_elem_ptr, addr); 124 | break; 125 | case KOOPA_RVT_BINARY: 126 | gen_riscv_value_binary(&kval->kind.data.binary, addr); 127 | break; 128 | case KOOPA_RVT_BRANCH: 129 | gen_riscv_value_branch(&kval->kind.data.branch); 130 | break; 131 | case KOOPA_RVT_JUMP: 132 | gen_riscv_value_jump(&kval->kind.data.jump); 133 | break; 134 | case KOOPA_RVT_CALL: 135 | gen_riscv_value_call(&kval->kind.data.call, kval->ty->tag == KOOPA_RTT_UNIT ? -1 : addr); 136 | break; 137 | case KOOPA_RVT_RETURN: 138 | gen_riscv_value_return(&kval->kind.data.ret); 139 | break; 140 | } 141 | } 142 | 143 | void RISCVBuilder::traversal_raw_slice(const koopa_raw_slice_t *rs) 144 | { 145 | for (uint32_t i = 0; i < rs->len; i++) 146 | { 147 | const void *data = rs->buffer[i]; 148 | switch (rs->kind) 149 | { 150 | case KOOPA_RSIK_FUNCTION: 151 | gen_riscv_func((koopa_raw_function_t)data); 152 | break; 153 | case KOOPA_RSIK_BASIC_BLOCK: 154 | gen_riscv_block((koopa_raw_basic_block_t)data); 155 | break; 156 | case KOOPA_RSIK_VALUE: 157 | gen_riscv_value((koopa_raw_value_t)data); 158 | break; 159 | } 160 | } 161 | } 162 | 163 | void RISCVBuilder::build(const koopa_raw_program_t *raw) 164 | { 165 | output << ".data" << endl; 166 | traversal_raw_slice(&raw->values); 167 | output << ".text" << endl; 168 | traversal_raw_slice(&raw->funcs); 169 | } 170 | -------------------------------------------------------------------------------- /src/ast/code_ast.cpp: -------------------------------------------------------------------------------- 1 | #include "ast/code_ast.hpp" 2 | #include "ast/array_ast.hpp" 3 | 4 | void CompUnitAST::add_lib_funcs(std::vector &funcs) const 5 | { 6 | koopa_raw_function_data_t *func; 7 | koopa_raw_type_kind_t *ty; 8 | std::vector fparams; 9 | 10 | func = new koopa_raw_function_data_t(); 11 | ty = new koopa_raw_type_kind_t(); 12 | ty->tag = KOOPA_RTT_FUNCTION; 13 | ty->data.function.params = empty_koopa_rs(KOOPA_RSIK_TYPE); 14 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 15 | func->ty = ty; 16 | func->name = "@getint"; 17 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 18 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 19 | symbol_list.AddSymbol("getint", LValSymbol(LValSymbol::Function, func)); 20 | funcs.push_back(func); 21 | 22 | func = new koopa_raw_function_data_t(); 23 | ty = new koopa_raw_type_kind_t(); 24 | ty->tag = KOOPA_RTT_FUNCTION; 25 | ty->data.function.params = empty_koopa_rs(KOOPA_RSIK_TYPE); 26 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 27 | func->ty = ty; 28 | func->name = "@getch"; 29 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 30 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 31 | symbol_list.AddSymbol("getch", LValSymbol(LValSymbol::Function, func)); 32 | funcs.push_back(func); 33 | 34 | func = new koopa_raw_function_data_t(); 35 | ty = new koopa_raw_type_kind_t(); 36 | ty->tag = KOOPA_RTT_FUNCTION; 37 | fparams.clear(); 38 | fparams.push_back(make_int_pointer_type()); 39 | ty->data.function.params = make_koopa_rs_from_vector(fparams, KOOPA_RSIK_TYPE); 40 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 41 | func->ty = ty; 42 | func->name = "@getarray"; 43 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 44 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 45 | symbol_list.AddSymbol("getarray", LValSymbol(LValSymbol::Function, func)); 46 | funcs.push_back(func); 47 | 48 | func = new koopa_raw_function_data_t(); 49 | ty = new koopa_raw_type_kind_t(); 50 | ty->tag = KOOPA_RTT_FUNCTION; 51 | fparams.clear(); 52 | fparams.push_back(simple_koopa_raw_type_kind(KOOPA_RTT_INT32)); 53 | ty->data.function.params = make_koopa_rs_from_vector(fparams, KOOPA_RSIK_TYPE); 54 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 55 | func->ty = ty; 56 | func->name = "@putint"; 57 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 58 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 59 | symbol_list.AddSymbol("putint", LValSymbol(LValSymbol::Function, func)); 60 | funcs.push_back(func); 61 | 62 | func = new koopa_raw_function_data_t(); 63 | ty = new koopa_raw_type_kind_t(); 64 | ty->tag = KOOPA_RTT_FUNCTION; 65 | fparams.clear(); 66 | fparams.push_back(simple_koopa_raw_type_kind(KOOPA_RTT_INT32)); 67 | ty->data.function.params = make_koopa_rs_from_vector(fparams, KOOPA_RSIK_TYPE); 68 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 69 | func->ty = ty; 70 | func->name = "@putch"; 71 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 72 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 73 | symbol_list.AddSymbol("putch", LValSymbol(LValSymbol::Function, func)); 74 | funcs.push_back(func); 75 | 76 | func = new koopa_raw_function_data_t(); 77 | ty = new koopa_raw_type_kind_t(); 78 | ty->tag = KOOPA_RTT_FUNCTION; 79 | fparams.clear(); 80 | fparams.push_back(simple_koopa_raw_type_kind(KOOPA_RTT_INT32)); 81 | fparams.push_back(make_int_pointer_type()); 82 | ty->data.function.params = make_koopa_rs_from_vector(fparams, KOOPA_RSIK_TYPE); 83 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 84 | func->ty = ty; 85 | func->name = "@putarray"; 86 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 87 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 88 | symbol_list.AddSymbol("putarray", LValSymbol(LValSymbol::Function, func)); 89 | funcs.push_back(func); 90 | 91 | func = new koopa_raw_function_data_t(); 92 | ty = new koopa_raw_type_kind_t(); 93 | ty->tag = KOOPA_RTT_FUNCTION; 94 | ty->data.function.params = empty_koopa_rs(KOOPA_RSIK_TYPE); 95 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 96 | func->ty = ty; 97 | func->name = "@starttime"; 98 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 99 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 100 | symbol_list.AddSymbol("starttime", LValSymbol(LValSymbol::Function, func)); 101 | funcs.push_back(func); 102 | 103 | func = new koopa_raw_function_data_t(); 104 | ty = new koopa_raw_type_kind_t(); 105 | ty->tag = KOOPA_RTT_FUNCTION; 106 | ty->data.function.params = empty_koopa_rs(KOOPA_RSIK_TYPE); 107 | ty->data.function.ret = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 108 | func->ty = ty; 109 | func->name = "@stoptime"; 110 | func->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 111 | func->bbs = empty_koopa_rs(KOOPA_RSIK_BASIC_BLOCK); 112 | symbol_list.AddSymbol("stoptime", LValSymbol(LValSymbol::Function, func)); 113 | funcs.push_back(func); 114 | } 115 | 116 | CompUnitAST::CompUnitAST(std::vector &_func_list, InstSet &_value_list) 117 | { 118 | for(BaseAST* func : _func_list) 119 | func_list.emplace_back(func); 120 | for(auto &pa : _value_list) 121 | { 122 | if(pa.first == Decl) 123 | value_list.push_back(make_pair(pa.first, std::unique_ptr(new GlobalVarDefAST(pa.second)))); 124 | else if(pa.first == ArrayDecl) 125 | value_list.push_back(make_pair(pa.first, std::unique_ptr(new GlobalArrayDefAST(pa.second)))); 126 | else 127 | value_list.push_back(make_pair(pa.first, std::move(pa.second))); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /test/hello.s: -------------------------------------------------------------------------------- 1 | .data 2 | .text 3 | .globl my_getint 4 | my_getint: 5 | addi sp, sp, -128 6 | sw ra, 124(sp) 7 | 8 | my_getint_entry_my_getint: 9 | 10 | li t0, 0 11 | sw t0, 120(sp) 12 | 13 | j my_getint_while_entry 14 | 15 | my_getint_while_entry: 16 | 17 | li t0, 1 18 | bnez t0, my_getint_skip0 19 | j my_getint_while_body 20 | my_getint_skip0: 21 | j my_getint_end 22 | 23 | my_getint_while_body: 24 | 25 | call getch 26 | sw a0, 112(sp) 27 | 28 | lw t0, 112(sp) 29 | li t1, 48 30 | sub t0, t0, t1 31 | sw t0, 108(sp) 32 | 33 | lw t0, 108(sp) 34 | sw t0, 116(sp) 35 | 36 | li t0, 1 37 | sw t0, 104(sp) 38 | 39 | lw t0, 116(sp) 40 | sw t0, 100(sp) 41 | 42 | lw t0, 100(sp) 43 | li t1, 0 44 | slt t0, t0, t1 45 | sw t0, 96(sp) 46 | 47 | lw t0, 96(sp) 48 | li t1, 0 49 | xor t0, t0, t1 50 | seqz t0, t0 51 | sw t0, 92(sp) 52 | 53 | lw t0, 92(sp) 54 | bnez t0, my_getint_skip1 55 | j my_getint_true 56 | my_getint_skip1: 57 | j my_getint_end_0 58 | 59 | my_getint_end: 60 | 61 | lw t0, 116(sp) 62 | sw t0, 88(sp) 63 | 64 | lw t0, 88(sp) 65 | sw t0, 120(sp) 66 | 67 | j my_getint_while_entry_0 68 | 69 | my_getint_true: 70 | 71 | lw t0, 116(sp) 72 | sw t0, 84(sp) 73 | 74 | lw t0, 84(sp) 75 | li t1, 9 76 | sgt t0, t0, t1 77 | sw t0, 80(sp) 78 | 79 | lw t0, 80(sp) 80 | li t1, 0 81 | xor t0, t0, t1 82 | snez t0, t0 83 | sw t0, 76(sp) 84 | 85 | lw t0, 76(sp) 86 | sw t0, 104(sp) 87 | 88 | j my_getint_end_0 89 | 90 | my_getint_end_0: 91 | 92 | lw t0, 104(sp) 93 | sw t0, 72(sp) 94 | 95 | lw t0, 72(sp) 96 | bnez t0, my_getint_skip2 97 | j my_getint_true_0 98 | my_getint_skip2: 99 | j my_getint_false 100 | 101 | my_getint_while_entry_0: 102 | 103 | li t0, 1 104 | bnez t0, my_getint_skip3 105 | j my_getint_while_body_0 106 | my_getint_skip3: 107 | j my_getint_end_1 108 | 109 | my_getint_true_0: 110 | 111 | j my_getint_while_entry 112 | 113 | my_getint_false: 114 | 115 | j my_getint_end 116 | 117 | my_getint_while_body_0: 118 | 119 | call getch 120 | sw a0, 68(sp) 121 | 122 | lw t0, 68(sp) 123 | li t1, 48 124 | sub t0, t0, t1 125 | sw t0, 64(sp) 126 | 127 | lw t0, 64(sp) 128 | sw t0, 116(sp) 129 | 130 | li t0, 0 131 | sw t0, 60(sp) 132 | 133 | lw t0, 116(sp) 134 | sw t0, 56(sp) 135 | 136 | lw t0, 56(sp) 137 | li t1, 0 138 | slt t0, t0, t1 139 | xori t0, t0, 1 140 | sw t0, 52(sp) 141 | 142 | lw t0, 52(sp) 143 | li t1, 0 144 | xor t0, t0, t1 145 | snez t0, t0 146 | sw t0, 48(sp) 147 | 148 | lw t0, 48(sp) 149 | bnez t0, my_getint_skip4 150 | j my_getint_true_1 151 | my_getint_skip4: 152 | j my_getint_end_2 153 | 154 | my_getint_end_1: 155 | 156 | lw t0, 120(sp) 157 | sw t0, 44(sp) 158 | 159 | lw a0, 44(sp) 160 | lw ra, 124(sp) 161 | addi sp, sp, 128 162 | ret 163 | 164 | my_getint_true_1: 165 | 166 | lw t0, 116(sp) 167 | sw t0, 40(sp) 168 | 169 | lw t0, 40(sp) 170 | li t1, 9 171 | sgt t0, t0, t1 172 | xori t0, t0, 1 173 | sw t0, 36(sp) 174 | 175 | lw t0, 36(sp) 176 | li t1, 0 177 | xor t0, t0, t1 178 | snez t0, t0 179 | sw t0, 32(sp) 180 | 181 | lw t0, 32(sp) 182 | sw t0, 60(sp) 183 | 184 | j my_getint_end_2 185 | 186 | my_getint_end_2: 187 | 188 | lw t0, 60(sp) 189 | sw t0, 28(sp) 190 | 191 | lw t0, 28(sp) 192 | bnez t0, my_getint_skip5 193 | j my_getint_true_2 194 | my_getint_skip5: 195 | j my_getint_false_0 196 | 197 | my_getint_true_2: 198 | 199 | lw t0, 120(sp) 200 | sw t0, 24(sp) 201 | 202 | lw t0, 24(sp) 203 | li t1, 10 204 | mul t0, t0, t1 205 | sw t0, 20(sp) 206 | 207 | lw t0, 116(sp) 208 | sw t0, 16(sp) 209 | 210 | lw t0, 20(sp) 211 | lw t1, 16(sp) 212 | add t0, t0, t1 213 | sw t0, 12(sp) 214 | 215 | lw t0, 12(sp) 216 | sw t0, 120(sp) 217 | 218 | j my_getint_end_3 219 | 220 | my_getint_false_0: 221 | 222 | j my_getint_end_1 223 | 224 | my_getint_end_3: 225 | 226 | j my_getint_while_entry_0 227 | .globl my_putint 228 | my_putint: 229 | addi sp, sp, -160 230 | sw ra, 156(sp) 231 | 232 | my_putint_entry_my_putint: 233 | 234 | sw a0, 152(sp) 235 | 236 | li t0, 0 237 | sw t0, 84(sp) 238 | 239 | j my_putint_while_entry 240 | 241 | my_putint_while_entry: 242 | 243 | lw t0, 152(sp) 244 | sw t0, 80(sp) 245 | 246 | lw t0, 80(sp) 247 | li t1, 0 248 | sgt t0, t0, t1 249 | sw t0, 76(sp) 250 | 251 | lw t0, 76(sp) 252 | bnez t0, my_putint_skip6 253 | j my_putint_while_body 254 | my_putint_skip6: 255 | j my_putint_end 256 | 257 | my_putint_while_body: 258 | 259 | lw t0, 152(sp) 260 | sw t0, 72(sp) 261 | 262 | lw t0, 72(sp) 263 | li t1, 10 264 | rem t0, t0, t1 265 | sw t0, 68(sp) 266 | 267 | lw t0, 68(sp) 268 | li t1, 48 269 | add t0, t0, t1 270 | sw t0, 64(sp) 271 | 272 | lw t0, 84(sp) 273 | sw t0, 60(sp) 274 | 275 | addi t0, sp, 88 276 | lw t1, 60(sp) 277 | li t2, 4 278 | mul t1, t1, t2 279 | add t0, t0, t1 280 | sw t0, 56(sp) 281 | 282 | lw t1, 56(sp) 283 | lw t0, 64(sp) 284 | sw t0, 0(t1) 285 | 286 | lw t0, 152(sp) 287 | sw t0, 52(sp) 288 | 289 | lw t0, 52(sp) 290 | li t1, 10 291 | div t0, t0, t1 292 | sw t0, 48(sp) 293 | 294 | lw t0, 48(sp) 295 | sw t0, 152(sp) 296 | 297 | lw t0, 84(sp) 298 | sw t0, 44(sp) 299 | 300 | lw t0, 44(sp) 301 | li t1, 1 302 | add t0, t0, t1 303 | sw t0, 40(sp) 304 | 305 | lw t0, 40(sp) 306 | sw t0, 84(sp) 307 | 308 | j my_putint_while_entry 309 | 310 | my_putint_end: 311 | 312 | j my_putint_while_entry_0 313 | 314 | my_putint_while_entry_0: 315 | 316 | lw t0, 84(sp) 317 | sw t0, 36(sp) 318 | 319 | lw t0, 36(sp) 320 | li t1, 0 321 | sgt t0, t0, t1 322 | sw t0, 32(sp) 323 | 324 | lw t0, 32(sp) 325 | bnez t0, my_putint_skip7 326 | j my_putint_while_body_0 327 | my_putint_skip7: 328 | j my_putint_end_0 329 | 330 | my_putint_while_body_0: 331 | 332 | lw t0, 84(sp) 333 | sw t0, 28(sp) 334 | 335 | lw t0, 28(sp) 336 | li t1, 1 337 | sub t0, t0, t1 338 | sw t0, 24(sp) 339 | 340 | lw t0, 24(sp) 341 | sw t0, 84(sp) 342 | 343 | lw t0, 84(sp) 344 | sw t0, 20(sp) 345 | 346 | addi t0, sp, 88 347 | lw t1, 20(sp) 348 | li t2, 4 349 | mul t1, t1, t2 350 | add t0, t0, t1 351 | sw t0, 16(sp) 352 | 353 | lw t0, 16(sp) 354 | lw t0, 0(t0) 355 | sw t0, 12(sp) 356 | 357 | lw a0, 12(sp) 358 | call putch 359 | 360 | j my_putint_while_entry_0 361 | 362 | my_putint_end_0: 363 | 364 | lw ra, 156(sp) 365 | addi sp, sp, 160 366 | ret 367 | .globl main 368 | main: 369 | addi sp, sp, -48 370 | sw ra, 44(sp) 371 | 372 | main_entry_main: 373 | 374 | call my_getint 375 | sw a0, 36(sp) 376 | 377 | lw t0, 36(sp) 378 | sw t0, 40(sp) 379 | 380 | j main_while_entry 381 | 382 | main_while_entry: 383 | 384 | lw t0, 40(sp) 385 | sw t0, 32(sp) 386 | 387 | lw t0, 32(sp) 388 | li t1, 0 389 | sgt t0, t0, t1 390 | sw t0, 28(sp) 391 | 392 | lw t0, 28(sp) 393 | bnez t0, main_skip8 394 | j main_while_body 395 | main_skip8: 396 | j main_end 397 | 398 | main_while_body: 399 | 400 | call my_getint 401 | sw a0, 20(sp) 402 | 403 | lw t0, 20(sp) 404 | sw t0, 24(sp) 405 | 406 | lw t0, 24(sp) 407 | sw t0, 16(sp) 408 | 409 | lw a0, 16(sp) 410 | call my_putint 411 | 412 | li a0, 10 413 | call putch 414 | 415 | lw t0, 40(sp) 416 | sw t0, 12(sp) 417 | 418 | lw t0, 12(sp) 419 | li t1, 1 420 | sub t0, t0, t1 421 | sw t0, 8(sp) 422 | 423 | lw t0, 8(sp) 424 | sw t0, 40(sp) 425 | 426 | j main_while_entry 427 | 428 | main_end: 429 | 430 | li a0, 0 431 | lw ra, 44(sp) 432 | addi sp, sp, 48 433 | ret 434 | -------------------------------------------------------------------------------- /src/ast/array_ast.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/base_ast.hpp" 4 | #include "koopa_util.hpp" 5 | 6 | class InitValAST : public BaseAST 7 | { 8 | enum ValType{ 9 | Exp, 10 | Array 11 | }; 12 | 13 | std::vector cache; 14 | 15 | public: 16 | bool is_const = false; 17 | ValType type; 18 | std::unique_ptr exp; 19 | std::vector> arr_list; 20 | 21 | InitValAST(std::unique_ptr &_exp) 22 | { 23 | type = Exp; 24 | exp = std::move(_exp); 25 | } 26 | InitValAST(std::vector &_arr_list) 27 | { 28 | type = Array; 29 | for(auto t : _arr_list) 30 | arr_list.emplace_back(dynamic_cast(t)); 31 | } 32 | 33 | void sub_preprocess(std::vector &pro, int align_pos, std::vector &buf) 34 | { 35 | int target_size = buf.size() + pro[align_pos]; 36 | for(size_t i = 0; i < arr_list.size(); i++) 37 | { 38 | auto &t = arr_list[i]; 39 | if(t->type == Exp) 40 | { 41 | if(is_const) 42 | buf.push_back(make_koopa_interger(t->exp->CalcValue())); 43 | else 44 | buf.push_back((koopa_raw_value_t)t->exp->build_koopa_values()); 45 | } 46 | else 47 | { 48 | int new_align_pos = align_pos + 1; 49 | while(cache.size() % pro[new_align_pos] != 0) 50 | new_align_pos ++; 51 | arr_list[i]->sub_preprocess(pro, new_align_pos, buf); 52 | } 53 | } 54 | while(buf.size() < target_size) 55 | buf.push_back(make_koopa_interger(0)); 56 | } 57 | 58 | void preprocess(const std::vector &sz) 59 | { 60 | std::vector pro(sz.size() + 1); 61 | pro[sz.size()] = 1; 62 | for(int i = sz.size() - 1; i >= 0; i--) 63 | pro[i] = pro[i + 1] * sz[i]; 64 | sub_preprocess(pro, 0, cache); 65 | } 66 | 67 | koopa_raw_value_t At(int idx) 68 | { 69 | if(type == Array) 70 | return cache[idx]; 71 | else if(type == Exp) 72 | return (koopa_raw_value_t)exp->build_koopa_values(); 73 | return nullptr; 74 | } 75 | 76 | koopa_raw_value_t sub_make_aggerate(const std::vector &sz, std::vector &pro, int align_pos, std::vector &buf, int st_pos) 77 | { 78 | if(pro[align_pos] == 1) 79 | return buf[st_pos]; 80 | koopa_raw_value_data *res = new koopa_raw_value_data(); 81 | res->ty = make_array_type(sz, align_pos); 82 | res->name = nullptr; 83 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 84 | res->kind.tag = KOOPA_RVT_AGGREGATE; 85 | 86 | std::vector elems; 87 | for(int i = 0; i < sz[align_pos]; i++) 88 | elems.push_back(sub_make_aggerate(sz, pro, align_pos + 1, buf, st_pos + pro[align_pos + 1] * i)); 89 | res->kind.data.aggregate.elems = make_koopa_rs_from_vector(elems, KOOPA_RSIK_VALUE); 90 | return res; 91 | } 92 | 93 | koopa_raw_value_t make_aggerate(const std::vector &sz) 94 | { 95 | std::vector pro(sz.size() + 1); 96 | pro[sz.size()] = 1; 97 | for(int i = sz.size() - 1; i >= 0; i--) 98 | pro[i] = pro[i + 1] * sz[i]; 99 | return sub_make_aggerate(sz, pro, 0, cache, 0); 100 | } 101 | }; 102 | 103 | class ArrayDefAST : public BaseAST 104 | { 105 | koopa_raw_value_data *get_index(int i, std::vector &pro, koopa_raw_value_data *src, int cur_pos = 0) const 106 | { 107 | if(cur_pos >= pro.size()) 108 | return src; 109 | koopa_raw_value_data *get = new koopa_raw_value_data(); 110 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 111 | ty->tag = KOOPA_RTT_POINTER; 112 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 113 | get->ty = ty; 114 | get->name = nullptr; 115 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 116 | get->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 117 | get->kind.data.get_elem_ptr.src = src; 118 | get->kind.data.get_elem_ptr.index = make_koopa_interger(i / pro[cur_pos]); 119 | block_maintainer.AddInst(get); 120 | return get_index(i % pro[cur_pos], pro, get, cur_pos + 1); 121 | } 122 | 123 | public: 124 | std::string name; 125 | std::vector> sz_exp; 126 | std::unique_ptr init_val; 127 | 128 | ArrayDefAST(const char *_name, std::vector &_exp) : name(_name) 129 | { 130 | for(auto &e : _exp) 131 | sz_exp.emplace_back(e); 132 | init_val = nullptr; 133 | } 134 | ArrayDefAST(const char *_name, std::vector &_exp, std::unique_ptr &_init_val) : name(_name) 135 | { 136 | for(auto &e : _exp) 137 | sz_exp.emplace_back(e); 138 | init_val = std::unique_ptr(dynamic_cast(_init_val.release())); 139 | } 140 | 141 | void *build_koopa_values() const override 142 | { 143 | int total_size = 1; 144 | std::vector sz; 145 | for(auto &e : sz_exp) 146 | { 147 | int tmp = e->CalcValue(); 148 | total_size *= tmp; 149 | sz.push_back(tmp); 150 | } 151 | 152 | koopa_raw_value_data *res = new koopa_raw_value_data(); 153 | koopa_raw_type_kind *ty = make_array_type(sz); 154 | koopa_raw_type_kind *tty = new koopa_raw_type_kind(); 155 | tty->tag = KOOPA_RTT_POINTER; 156 | tty->data.pointer.base = ty; 157 | res->ty = tty; 158 | res->name = new_char_arr("@" + name); 159 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 160 | res->kind.tag = KOOPA_RVT_ALLOC; 161 | block_maintainer.AddInst(res); 162 | symbol_list.AddSymbol(name, LValSymbol(LValSymbol::Array, res)); 163 | 164 | if(init_val) 165 | { 166 | init_val->preprocess(sz); 167 | std::vector pro(sz.size()); 168 | pro[sz.size() - 1] = 1; 169 | for(int i = sz.size() - 2; i >= 0; i--) 170 | pro[i] = pro[i + 1] * sz[i + 1]; 171 | for(int i = 0; i < total_size; i++) 172 | { 173 | koopa_raw_value_data *get = get_index(i, pro, res); 174 | 175 | koopa_raw_value_data *st = new koopa_raw_value_data(); 176 | st->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 177 | st->name = nullptr; 178 | st->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 179 | st->kind.tag = KOOPA_RVT_STORE; 180 | st->kind.data.store.dest = get; 181 | st->kind.data.store.value = init_val->At(i); 182 | block_maintainer.AddInst(st); 183 | } 184 | } 185 | return res; 186 | } 187 | }; 188 | 189 | class GlobalArrayDefAST : public BaseAST 190 | { 191 | public: 192 | std::string name; 193 | std::vector> sz_exp; 194 | std::unique_ptr init_val; 195 | 196 | GlobalArrayDefAST(std::unique_ptr &arraydef_ast) 197 | { 198 | ArrayDefAST *arraydef = dynamic_cast(arraydef_ast.release()); 199 | name = arraydef->name; 200 | sz_exp = std::move(arraydef->sz_exp); 201 | init_val = std::move(arraydef->init_val); 202 | } 203 | 204 | void *build_koopa_values() const override 205 | { 206 | std::vector sz; 207 | for(auto &e : sz_exp) 208 | sz.push_back(e->CalcValue()); 209 | koopa_raw_value_data *res = new koopa_raw_value_data(); 210 | koopa_raw_type_kind *ty = make_array_type(sz); 211 | koopa_raw_type_kind *tty = new koopa_raw_type_kind(); 212 | tty->tag = KOOPA_RTT_POINTER; 213 | tty->data.pointer.base = ty; 214 | res->ty = tty; 215 | res->name = new_char_arr("@" + name); 216 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 217 | res->kind.tag = KOOPA_RVT_GLOBAL_ALLOC; 218 | if(init_val) 219 | { 220 | init_val->is_const = true; 221 | init_val->preprocess(sz); 222 | res->kind.data.global_alloc.init = init_val->make_aggerate(sz); 223 | } 224 | else 225 | res->kind.data.global_alloc.init = ZeroInit(ty); 226 | symbol_list.AddSymbol(name, LValSymbol(LValSymbol::Array, res)); 227 | 228 | return res; 229 | } 230 | }; 231 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 编译原理课程实践报告:StupidSysY2RV 2 | 3 | ## 一、编译器概述 4 | 5 | ### 1.1 基本功能 6 | 7 | 本编译器基本具备如下功能: 8 | 1. 将[SysY](https://pku-minic.github.io/online-doc/#/misc-app-ref/sysy-spec)语言编译为[Koopa IR](https://pku-minic.github.io/online-doc/#/misc-app-ref/koopa)形式; 9 | 1. 将[SysY](https://pku-minic.github.io/online-doc/#/misc-app-ref/sysy-spec)语言编译为RISC-V代码; 10 | 1. 大概率通过自身崩溃检查代码错误的功能; 11 | 12 | ### 1.2 主要特点 13 | 14 | 包含了基本要求的功能:表达式编译、常量变量、语句块作用域、if, while语句、函数调用、全局变量、数组。 15 | 16 | 还有如下等特点:速度慢、容易崩溃……/(ㄒoㄒ)/~~ 17 | 18 | ## 二、编译器设计 19 | 20 | 整体设计: 21 | 22 | 1. 使用词法、语法分析器分析SysY代码文件,构建抽象语法树AST; 23 | 2. 调用根节点AST的函数,直接通过AST生成Koopa IR结构的内存形式; 24 | 3. 将Koopa IR结构输出为代码,重新读取后,再遍历Koopa IR结构的内存形式,生成RISC-V代码。 25 | 26 | ### 2.1 主要模块组成 27 | 28 | 编译器由4个主要模块组成: 29 | 30 | 1. 分析模块:```sysy.l```以及```sysy.y```分别进行词法分析和语法分析,构建抽象语法树(AST); 31 | 2. AST模块:```ast```文件夹中的代码。实现AST结构,并使用该结构生成Koopa结构。 32 | 3. Builder模块:```builder```文件夹中的代码。读取Koopa结构,生成RISC-V代码。 33 | 4. 工具模块:其他文件。包含基本块维护器,循环结构维护器,生成Koopa结构的工具函数等。 34 | 35 | ### 2.2 主要数据结构 36 | 37 | #### 抽象语法树 38 | 39 | 抽象语法树节点均继承自```BaseAST```类,该类规定了一些可以实现的功能,方便使用多态调用。比如```build_koopa_values```用于将该节点的语义转化为Koopa结构并返回;```CalcValue```用于计算常量表达式的值。 40 | 41 | ```BaseAST``` 中有3个static成员,作为全局信息:用于维护生成IR时需要的符号表```symbol_list```;当前基本块的语句缓存区```block_maintainer```;维护嵌套循环结构的```loop_maintainer``` 42 | 43 | ```c++ 44 | class BaseAST 45 | { 46 | public: 47 | static SymbolList symbol_list; 48 | static BlockMaintainer block_maintainer; 49 | static LoopMaintainer loop_maintainer; 50 | 51 | virtual ~BaseAST() = default; 52 | virtual std::string to_string() const; 53 | virtual void *build_koopa_values() const; 54 | virtual int CalcValue() const; 55 | virtual void *koopa_leftvalue() const; 56 | }; 57 | ``` 58 | 59 | AST节点示例: 60 | 61 | 赋值语句的AST需要包含左值节点和右值表达式节点。其重写函数```build_koopa_values```中,调用了子节点的函数,以获取他们的Koopa结构,并由此构建自己的Koopa结构(Store语句),再通过全局结构```block_maintainer```将该语句添加进当前基本块。 62 | 63 | ```c++ 64 | class AssignmentAST : public BaseAST 65 | { 66 | public: 67 | std::unique_ptr lval; 68 | std::unique_ptr exp; 69 | AssignmentAST(std::unique_ptr &_lval, std::unique_ptr &_exp); 70 | void *build_koopa_values() const override 71 | { 72 | koopa_raw_value_data *res = new koopa_raw_value_data(); 73 | // .. some code to build koopa_raw_value_data 74 | block_maintainer.AddInst(res); 75 | return res; 76 | } 77 | }; 78 | ``` 79 | 80 | #### 基本块维护器 81 | 82 | 在```BlockMaintainer```中,需要存储当前正在构建的函数、基本块、指令缓冲区等Koopa结构信息。由于其为静态成员,任意AST节点都可以调用他来添加基本块、语句等。 83 | 84 | 当一个基本块完成时,该类的```FinishCurrentBlock```函数负责清楚基本块末尾无法到达的语句,以及添加Jump、Return之类的语句防止基本块出错。 85 | 86 | ```c++ 87 | class BlockMaintainer 88 | { 89 | koopa_raw_function_t current_func; 90 | std::vector current_insts_buf; 91 | std::vector *basic_block_buf; 92 | public: 93 | void SetCurrentFunction(koopa_raw_function_t _cur_func); 94 | void SetBasicBlockBuf(std::vector *_basic_block_buf); 95 | void FinishCurrentBlock(); 96 | void AddNewBasicBlock(koopa_raw_basic_block_data_t *basic_block); 97 | void AddInst(const void *inst); 98 | }; 99 | ``` 100 | 101 | #### 循环维护器 102 | 103 | 嵌套的循环结构会造成大量基本块,出现复杂的跳转结构,为此实现了一个类来维护。 104 | 105 | 该类使用一个vector来构建一个栈,用于表示嵌套的循环结构。栈中元素存储对应循环的各个基本块信息,方便AST节点构建Koopa时使用。 106 | 107 | ```c++ 108 | struct KoopaWhile 109 | { 110 | koopa_raw_basic_block_data_t *while_entry; 111 | koopa_raw_basic_block_data_t *while_body; 112 | koopa_raw_basic_block_data_t *end_block; 113 | }; 114 | class LoopMaintainer 115 | { 116 | std::vector loop_stk; 117 | public: 118 | void AddLoop(...) 119 | { 120 | KoopaWhile kw; 121 | // ... 构建kw 122 | loop_stk.push_back(kw); 123 | } 124 | KoopaWhile GetLoop() { return loop_stk[loop_stk.size() - 1]; } 125 | void PopLoop() { loop_stk.pop_back(); } 126 | }; 127 | ``` 128 | 129 | #### RISC-V构建器 (builder) 130 | 131 | RISC-V构建器中包含一个输出流```output```,通过```build```函数递归遍历Koopa结构,生成的RISC-V代码直接输出到output中。 132 | 133 | 构建器中包含一个```Env```结构,用于存储Koopa指令到int的映射,代表该指令的计算结果存储在栈上的位置,RISC-V找到该结构并读取。 134 | 135 | ```c++ 136 | class RISCVBuilder 137 | { 138 | class Env 139 | { 140 | int total_size; 141 | map addr; 142 | public: 143 | int cur; 144 | bool has_call; 145 | void NewEnv(int size, bool _has_call); 146 | int GetTotalSize(); 147 | int GetAddr(koopa_raw_value_t kval); 148 | } env; 149 | ostream &output; 150 | 151 | static int calc_func_size(koopa_raw_function_t kfunc, bool &has_call); 152 | // ... some functions to calculate memory 153 | static int calc_type_size(koopa_raw_type_t ty); 154 | 155 | void traversal_raw_slice(const koopa_raw_slice_t *rs); 156 | // ... some functions for every instructions 157 | void gen_riscv_value_return(const koopa_raw_return_t *kret); 158 | public: 159 | RISCVBuilder(ostream &_out) : output(_out) {} 160 | void build(const koopa_raw_program_t *raw); 161 | }; 162 | ``` 163 | 164 | ### 2.3 主要设计考虑及算法选择 165 | 166 | #### 2.3.1 符号表的设计考虑 167 | 168 | 符号表类里面定义了一个vector实现的栈,表示作用域的嵌套结构,新建作用域时在栈顶添加元素。 169 | 170 | 栈中每个元素为一个map,将字符串映射到Koopa结构,表示该作用域的符号表。 171 | 172 | 当需要查找符号时,从栈顶开始在map中查找,若没有找到,则进入栈中前一个元素继续查找,实现往父作用域的查找。 173 | 174 | ```c++ 175 | struct LValSymbol 176 | { 177 | enum SymbolType type; 178 | void *number; 179 | }; 180 | class SymbolList 181 | { 182 | std::vector> sym_stk; 183 | public: 184 | void NewEnv(); 185 | void AddSymbol(const std::string &name, LValSymbol koopa_item); 186 | LValSymbol GetSymbol(const std::string &name) 187 | { 188 | LValSymbol res; 189 | for (size_t i = sym_stk.size() - 1; i >= 0; i--) 190 | if (sym_stk[i].count(name) != 0) 191 | { 192 | res = sym_stk[i][name]; 193 | break; 194 | } 195 | return res; 196 | } 197 | void DeleteEnv(); 198 | }; 199 | ``` 200 | 201 | #### 2.3.2 寄存器分配策略 202 | 寄存器分配采用全部放在栈上的策略,仅在一些运算中途会使用寄存器。 203 | 204 | 首先Builder进入函数时,计算所有语句以及变量等占用的空间大小,在栈上分配足够的空间。 205 | 206 | 每个语句确保自己执行的内部寄存器不会冲突,执行完毕将语句的结构存在栈上指定位置,寄存器信息不再保存,可被其他语句复用。 207 | 208 | 每个语句仅使用t0~t6寄存器,函数参数即返回值使用a0~a7。 209 | 210 | #### 2.3.3 其它补充设计考虑 211 | 212 | ##### 优化语法分析中的列表 213 | 214 | 在语法分析器中,针对列表状的语句。=,如```int x0,x1,x2....```任意多个变量。 215 | 216 | 在yacc中设计为如下形式: 217 | 218 | ```c 219 | VarDecl : BType VarDefList ';'; 220 | VarDefList : VarDef | VarDefList ',' VarDef; 221 | VarDef : ..... {add_inst(...);} 222 | ``` 223 | 224 | 并在全局开一个vector 225 | 226 | 对于VarDecl,VarDefList不再定义语法分析树节点,而是仅将VarDef生成的语法分析树节点添加到全局的vector中。然后上一级AST节点读取全局vector,将子节点添加进自己的结构。 227 | 228 | 这样设计有效简化了复杂的AST链状结构。 229 | 230 | ## 三、编译器实现 231 | 232 | ### 3.1 各阶段编码细节 233 | 234 | [lab文档](https://pku-minic.github.io/online-doc/#/) 235 | 236 | #### Lv1. main函数和Lv2. 初试目标代码生成 237 | 238 | 该阶段仅仅按照文档完成简易功能。构建了AST的类结构,选择了直接生成Koopa结构内存形式的方式。 239 | 240 | 使用简单函数生成RISC-V,没有构建其他复杂的数据结构。 241 | 242 | #### Lv3. 表达式 243 | 按照文档的语法规范,对每种表达式设计AST类。 244 | 245 | 由于Koopa没有逻辑与/或,只有按位与/或,所以这两个运算之前,添加不等于运算来将结果转化为1和0,再进行按位运算。 246 | 247 | 对于RISC-V代码,此时设计了栈的大小计算,将koopa语句与栈上地址映射,设计对应的类。 248 | 249 | Koopa格式已经是简单的三地址语句,只需要读取栈上数据,使用固定语句计算,再存回栈上即可。 250 | 251 | #### Lv4. 常量和变量 252 | 对于常量,在表达式的AST中添加了CalcValue功能用于求值。 253 | 254 | 因为变量的出现,完成了SymbolList类,并将其设为静态,作为全局信息管理。 255 | 256 | 由于之前把所有AST都视为BaseAST,使用多态调用build_koopa_value。在这里LValAST有时需要右值形态的Koopa,有时需要左值形态的Koopa,无法使用一个函数的多态来完成,出现了一定困难。于是在BaseAST中添加了新的虚函数用于处理左值。 257 | 258 | 对于RISC-V代码,仅在栈空间计算以及koopa与地址映射中添加了对变量的处理。 259 | 260 | #### Lv5. 语句块和作用域 261 | 和Lv4一起完成的,在设计SymbolList时已经实现为栈结构,能够处理嵌套的作用域。 262 | 263 | 在语法分析阶段,建立了全局的语句缓存区栈 264 | 265 | 栈中每个元素为一个vector,存储该语句块中的语句 266 | 267 | 到了需要存储语句的AST时,从栈顶开始读取语句块内容,将其存入自己的结构中。 268 | 269 | #### Lv6. if语句 270 | 出现二义性时,我将```IF exp ```合并为```IfExp : IF exp```,再将if语句定义为 271 | 272 | ``` 273 | Stmt : IfExp Stmt | IfExp Stmt ELSE {...} Stmt {...}; 274 | ``` 275 | 276 | 解决了问题。 277 | 278 | 对于If中的几个语句块,他们都存在了全局语句栈中。读取栈顶的两项即可获得If的语句块和Else的语句块。 279 | 280 | 由于基本块越来越多,在这个阶段设计了BlockMaintainer来专门维护各个基本块的语句缓存。 281 | 282 | 对于短路求值,直接将&&,||改为跳转形式,而不再使用按位与等运算。 283 | 284 | #### Lv7. while语句 285 | 因为嵌套的循环语句不方便找到需要跳转的块,设计了LoopMaintainer类来维护嵌套的循环,使用栈结构来存储每个循环的基本块信息。 286 | 287 | 这样break,continue能找到当前所在的循环,从而找到跳转位置。 288 | 289 | 这些跳转语句,直接对应RISC-V中的bnez和j命令,比较简单。 290 | 291 | 由于Koopa库能够自动处理名字重复问题,通过生成Koopa代码再重新读入回来,已经不存在标签重名的情况。 292 | 293 | #### Lv8. 函数和全局变量 294 | 对于形参和实参都设计了专门的AST类实现,同时在语法分析阶段开了全局vector用来存储这些参数列表。 295 | 296 | 在函数定义FuncDefAST中读取列表构建AST,函数调用LVal中读取列表生成参数。 297 | 298 | 对于RISC-V阶段,增加了计算函数返回地址,传参在栈上存储的位置。以及调用函数将参数放入指定寄存器或栈上位置的功能。 299 | 300 | #### Lv9. 数组 301 | 设计InitValAST专门用于处理数组的初始化列表,并且分开处理了全局变量和局部变量的形式。 302 | 303 | InitValAST首先调用预处理preprocess,根据指定的数组size将数据预处理成数组格式的数据。 304 | 305 | 然后根据是全局还是局部变量,生成aggerate的koopa内容或者读取某一位的值,在函数内部通过赋值初始化。 306 | 307 | 对于RISC-V,由于之前将Koopa对象映射到栈上位置,用的一直是Koopa语句对象本身的指针,他的ty表示的一定是一个整数指针(koopa语句返回值都是指针)。而目前因为数组参数的出现,出现了真正的指针,导致映射器无法区分是要读取指针本身还是指针指向的对象,于是只能对get_element_ptr和get_ptr进行特判处理。 308 | 309 | get_element_ptr等语句,处理时会读取koopa对象中的ty以计算指针需要移动的大小,使用mul,add等语句计算得到指定位置的指针。 310 | 311 | ### 3.2 工具软件介绍 312 | 1. `flex/bison`:编写```sysy.l```和```sysy.y```,完成词法分析和语法分析,通过表达式识别代码生成了语法分析树。 313 | 2. [libkoopa](https://github.com/pku-minic/koopa):使用该库的Koopa各种结构体,直接在AST中构建了Koopa结构的内存形式。使用该库生成Koopa代码。该库生成的代码自动完成了各种名称的去重,于是通过该库的生成再读取得到一个名字没有重复的Koopa程序,方便RISC-V的生成。 314 | 315 | ### 3.3 测试情况说明 316 | 317 | 使用了往年的测试数据,测试某些编译器崩溃的问题,有以下重点问题: 318 | 319 | 1. 对于int类型函数,如果执行结束没有return,需要自己添加return 0命令; 320 | 2. 对于极长的代码,会超出```bnez```的跳转范围,必须修改为跳转到近处某个位置,使用```j```命令跳转到远处。 321 | 3. 发现把```new char[len]```写成了```new char(len)```,到处内存非法访问,到处出错。。。 322 | 323 | ## 四、实习总结 324 | 325 | ### 4.1 收获和体会 326 | 327 | 实现了一个编译器,非常有成就感。 328 | 329 | 加深理解了这门课程各个部分的内容。 330 | 331 | 通过实践学到了大软件开发的一些难点,最初的设计会如何影响到后续的扩展问题。 332 | 333 | ### 4.2 学习过程中的难点,以及对实习过程和内容的建议 334 | 335 | 1. Koopa库的文档不足,无法准确理解koopa中每个结构体的意思,需要自己去猜或试出来,建议助教完善一些; 336 | 2. 有些常见错误比较难考虑到,最好在文档里添加:比如int类型函数没写返回需要自己添加return 0 337 | 338 | ### 4.3 对老师讲解内容与方式的建议 339 | 340 | 希望老师上课能讲得更有趣一些 341 | -------------------------------------------------------------------------------- /src/builder/builder_value.cpp: -------------------------------------------------------------------------------- 1 | #include "builder/riscv_builder.hpp" 2 | 3 | void RISCVBuilder::load_to_reg(koopa_raw_value_t kval, const char *reg) 4 | { 5 | if (kval->kind.tag == KOOPA_RVT_INTEGER) 6 | output << "\tli " << reg << ", " << kval->kind.data.integer.value << endl; 7 | else if(kval->kind.tag == KOOPA_RVT_GLOBAL_ALLOC) 8 | { 9 | output << "\tla t0, " << kval->name + 1 << endl; 10 | output << "\tlw " << reg << ", 0(t0)" << endl; 11 | } 12 | else 13 | { 14 | int addr = env.GetAddr(kval); 15 | if(addr < -2048 || addr > 2047) 16 | { 17 | output << "\tli t6, " << addr << endl; 18 | output << "\tadd t6, t6, sp" << endl; 19 | output << "\tlw " << reg << ", " << "0(t6)" << endl; 20 | } 21 | else 22 | output << "\tlw " << reg << ", " << addr << "(sp)" << endl; 23 | } 24 | } 25 | 26 | void RISCVBuilder::store_to_stack(int addr, const char *reg) 27 | { 28 | if(addr < -2048 || addr > 2047) 29 | { 30 | output << "\tli t6, " << addr << endl; 31 | output << "\tadd t6, t6, sp" << endl; 32 | output << "\tsw " << reg << ", " << "0(t6)" << endl; 33 | } 34 | else 35 | output << "\tsw " << reg << ", " << addr << "(sp)" << endl; 36 | } 37 | 38 | void RISCVBuilder::gen_riscv_value_aggregate(koopa_raw_value_t kval) 39 | { 40 | if(kval->ty->tag == KOOPA_RTT_ARRAY) 41 | { 42 | for(int i = 0; i < kval->kind.data.aggregate.elems.len; i++) 43 | gen_riscv_value_aggregate((koopa_raw_value_t)kval->kind.data.aggregate.elems.buffer[i]); 44 | } 45 | else 46 | output << "\t.word " << kval->kind.data.integer.value << endl; 47 | } 48 | 49 | void RISCVBuilder::gen_riscv_value_global_alloc(koopa_raw_value_t kalloc) 50 | { 51 | output << ".globl " << kalloc->name + 1 << endl; 52 | output << kalloc->name + 1 << ":" << endl; 53 | if (kalloc->kind.data.global_alloc.init->kind.tag == KOOPA_RVT_ZERO_INIT) 54 | { 55 | output << "\t.zero " << calc_type_size(kalloc->ty->data.pointer.base) << endl; 56 | } 57 | else if(kalloc->kind.data.global_alloc.init->kind.tag == KOOPA_RVT_AGGREGATE) 58 | gen_riscv_value_aggregate(kalloc->kind.data.global_alloc.init); 59 | else 60 | output << "\t.word " << kalloc->kind.data.global_alloc.init->kind.data.integer.value << endl; 61 | } 62 | 63 | void RISCVBuilder::gen_riscv_value_load(const koopa_raw_load_t *kload, int addr) 64 | { 65 | output << endl; 66 | 67 | if(kload->src->kind.tag == KOOPA_RVT_GET_ELEM_PTR || kload->src->kind.tag == KOOPA_RVT_GET_PTR) 68 | { 69 | load_to_reg(kload->src, "t0"); 70 | output << "\tlw t0, 0(t0)" << endl; 71 | store_to_stack(addr, "t0"); 72 | } 73 | else 74 | { 75 | load_to_reg(kload->src, "t0"); 76 | store_to_stack(addr, "t0"); 77 | } 78 | } 79 | 80 | void RISCVBuilder::gen_riscv_value_store(const koopa_raw_store_t *kstore) 81 | { 82 | output << endl; 83 | 84 | std::string dest; 85 | if(kstore->dest->kind.tag == KOOPA_RVT_GLOBAL_ALLOC) 86 | { 87 | output << "\tla t1, " << kstore->dest->name + 1 << endl; 88 | dest = "0(t1)"; 89 | } 90 | else if(kstore->dest->kind.tag == KOOPA_RVT_GET_ELEM_PTR || kstore->dest->kind.tag == KOOPA_RVT_GET_PTR) 91 | { 92 | load_to_reg(kstore->dest, "t1"); 93 | dest = "0(t1)"; 94 | } 95 | else 96 | { 97 | int addr = env.GetAddr(kstore->dest); 98 | if(addr < -2048 || addr > 2047) 99 | { 100 | output << "\tli t1, " << addr << endl; 101 | output << "\tadd t1, t1, sp" << endl; 102 | dest = "0(t1)"; 103 | } 104 | else 105 | dest = std::to_string(addr) + "(sp)"; 106 | } 107 | if(kstore->value->kind.tag == KOOPA_RVT_FUNC_ARG_REF) 108 | { 109 | if(kstore->value->kind.data.func_arg_ref.index < 8) 110 | output << "\tsw a" << kstore->value->kind.data.func_arg_ref.index << ", " << dest << endl; 111 | else 112 | { 113 | int offset = (kstore->value->kind.data.func_arg_ref.index - 8) * 4; 114 | if(offset < -2048 || offset > 2047) 115 | { 116 | output << "\tli t2, " << offset << endl; 117 | output << "\taddi t2, t2, sp" << endl; 118 | output << "\tlw t0, 0(t2)" << endl; 119 | } 120 | else 121 | output << "\tlw t0, " << offset << "(sp)" << endl; 122 | output << "\tsw t0, " << dest << endl; 123 | } 124 | } 125 | else 126 | { 127 | load_to_reg(kstore->value, "t0"); 128 | output << "\tsw t0, " << dest << endl; 129 | } 130 | } 131 | 132 | void RISCVBuilder::gen_riscv_value_get_ptr(const koopa_raw_get_ptr_t *kget, int addr) 133 | { 134 | output << endl; 135 | 136 | int src_addr = env.GetAddr(kget->src); 137 | if(src_addr > 2047 || src_addr < -2048) 138 | { 139 | output << "\tli t0, " << src_addr << endl; 140 | output << "\tadd t0, sp, t0" << endl; 141 | } 142 | else 143 | output << "\taddi t0, sp, " << src_addr << endl; 144 | output << "\tlw t0, 0(t0)" << endl; 145 | 146 | load_to_reg(kget->index, "t1"); 147 | int n = calc_type_size(kget->src->ty->data.pointer.base); 148 | output << "\tli t2, " << n << endl; 149 | output << "\tmul t1, t1, t2" << endl; 150 | output << "\tadd t0, t0, t1" << endl; 151 | store_to_stack(addr, "t0"); 152 | } 153 | 154 | void RISCVBuilder::gen_riscv_value_get_elem_ptr(const koopa_raw_get_elem_ptr_t *kget, int addr) 155 | { 156 | output << endl; 157 | 158 | if(kget->src->kind.tag == KOOPA_RVT_GLOBAL_ALLOC) 159 | { 160 | output << "\tla t0, " << kget->src->name + 1 << endl; 161 | } 162 | else 163 | { 164 | int src_addr = env.GetAddr(kget->src); 165 | if(src_addr > 2047 || src_addr < -2048) 166 | { 167 | output << "\tli t0, " << src_addr << endl; 168 | output << "\tadd t0, sp, t0" << endl; 169 | } 170 | else 171 | output << "\taddi t0, sp, " << src_addr << endl; 172 | if(kget->src->kind.tag == KOOPA_RVT_GET_ELEM_PTR || kget->src->kind.tag == KOOPA_RVT_GET_PTR) 173 | output << "\tlw t0, 0(t0)" << endl; 174 | } 175 | load_to_reg(kget->index, "t1"); 176 | int n = calc_type_size(kget->src->ty->data.pointer.base->data.array.base); 177 | output << "\tli t2, " << n << endl; 178 | output << "\tmul t1, t1, t2" << endl; 179 | output << "\tadd t0, t0, t1" << endl; 180 | store_to_stack(addr, "t0"); 181 | } 182 | 183 | void RISCVBuilder::gen_riscv_value_binary(const koopa_raw_binary_t *kbinary, int addr) 184 | { 185 | output << endl; 186 | 187 | load_to_reg(kbinary->lhs, "t0"); 188 | load_to_reg(kbinary->rhs, "t1"); 189 | switch (kbinary->op) 190 | { 191 | case KOOPA_RBO_NOT_EQ: 192 | output << "\txor t0, t0, t1" << endl; 193 | output << "\tsnez t0, t0" << endl; 194 | break; 195 | case KOOPA_RBO_EQ: 196 | output << "\txor t0, t0, t1" << endl; 197 | output << "\tseqz t0, t0" << endl; 198 | break; 199 | case KOOPA_RBO_GT: 200 | output << "\tsgt t0, t0, t1" << endl; 201 | break; 202 | case KOOPA_RBO_LT: 203 | output << "\tslt t0, t0, t1" << endl; 204 | break; 205 | case KOOPA_RBO_GE: 206 | output << "\tslt t0, t0, t1" << endl; 207 | output << "\txori t0, t0, 1" << endl; 208 | break; 209 | case KOOPA_RBO_LE: 210 | output << "\tsgt t0, t0, t1" << endl; 211 | output << "\txori t0, t0, 1" << endl; 212 | break; 213 | case KOOPA_RBO_ADD: 214 | output << "\tadd t0, t0, t1" << endl; 215 | break; 216 | case KOOPA_RBO_SUB: 217 | output << "\tsub t0, t0, t1" << endl; 218 | break; 219 | case KOOPA_RBO_MUL: 220 | output << "\tmul t0, t0, t1" << endl; 221 | break; 222 | case KOOPA_RBO_DIV: 223 | output << "\tdiv t0, t0, t1" << endl; 224 | break; 225 | case KOOPA_RBO_MOD: 226 | output << "\trem t0, t0, t1" << endl; 227 | break; 228 | case KOOPA_RBO_AND: 229 | output << "\tand t0, t0, t1" << endl; 230 | break; 231 | case KOOPA_RBO_OR: 232 | output << "\tor t0, t0, t1" << endl; 233 | break; 234 | case KOOPA_RBO_XOR: 235 | output << "\txor t0, t0, t1" << endl; 236 | break; 237 | case KOOPA_RBO_SHL: 238 | output << "\tsll t0, t0, t1" << endl; 239 | break; 240 | case KOOPA_RBO_SHR: 241 | output << "\tsrl t0, t0, t1" << endl; 242 | break; 243 | case KOOPA_RBO_SAR: 244 | output << "\tsra t0, t0, t1" << endl; 245 | break; 246 | } 247 | store_to_stack(addr, "t0"); 248 | } 249 | 250 | void RISCVBuilder::gen_riscv_value_branch(const koopa_raw_branch_t *kbranch) 251 | { 252 | output << endl; 253 | load_to_reg(kbranch->cond, "t0"); 254 | // output << "\tbnez t0, " << current_func_name << "_" << kbranch->true_bb->name + 1 << endl; 255 | // 解决跳转超限问题 256 | output << "\tbeqz t0, " << current_func_name << "_" << "skip" << magic_cnt_num << endl; 257 | output << "\tj " << current_func_name << "_" << kbranch->true_bb->name + 1 << endl; 258 | output << current_func_name << "_" << "skip" << magic_cnt_num++ << ":" << endl; 259 | 260 | output << "\tj " << current_func_name << "_" << kbranch->false_bb->name + 1 << endl; 261 | } 262 | 263 | void RISCVBuilder::gen_riscv_value_jump(const koopa_raw_jump_t *kjump) 264 | { 265 | output << endl; 266 | output << "\tj " << current_func_name << "_" << kjump->target->name + 1 << endl; 267 | } 268 | 269 | void RISCVBuilder::gen_riscv_value_call(const koopa_raw_call_t *kcall, int addr) 270 | { 271 | output << endl; 272 | for (int i = 0; i < kcall->args.len && i < 8; i++) 273 | { 274 | char reg[3] = "a0"; 275 | reg[1] += i; 276 | load_to_reg((koopa_raw_value_t)kcall->args.buffer[i], reg); 277 | } 278 | bool has_call = false; 279 | int func_sz = calc_func_size(kcall->callee, has_call); 280 | if(func_sz) 281 | func_sz = ((func_sz - 1) / 16 + 1) * 16; 282 | for (int i = 8; i < kcall->args.len; i++) 283 | { 284 | load_to_reg((koopa_raw_value_t)kcall->args.buffer[i], "t0"); 285 | int offset = (i - 8) * 4 - func_sz; 286 | if(offset < -2048 || offset > 2047) 287 | { 288 | output << "\tli t6, " << offset << endl; 289 | output << "\tadd t6, t6, sp" << endl; 290 | output << "\tsw t0, 0(t6)" << endl; 291 | } 292 | else 293 | output << "\tsw t0, " << offset << "(sp)" << endl; 294 | } 295 | output << "\tcall " << kcall->callee->name + 1 << endl; 296 | if (addr != -1) 297 | store_to_stack(addr, "a0"); 298 | } 299 | 300 | void RISCVBuilder::gen_riscv_value_return(const koopa_raw_return_t *kret) 301 | { 302 | output << endl; 303 | 304 | if (kret->value) 305 | load_to_reg(kret->value, "a0"); 306 | if (env.has_call) 307 | { 308 | int offset = env.GetTotalSize() - 4; 309 | if(offset < -2048 || offset > 2047) 310 | { 311 | output << "\tli t6, " << offset << endl; 312 | output << "\tadd t6, t6, sp" << endl; 313 | output << "\tlw ra, 0(t6)" << endl; 314 | } 315 | else 316 | output << "\tlw ra, " << offset << "(sp)" << endl; 317 | } 318 | if (env.GetTotalSize() != 0) 319 | { 320 | int sz = env.GetTotalSize(); 321 | if(sz < -2048 || sz > 2047) 322 | { 323 | output << "\tli t0, " << sz << endl; 324 | output << "\tadd sp, sp, t0" << endl; 325 | } 326 | else 327 | output << "\taddi sp, sp, " << sz << endl; 328 | } 329 | output << "\tret" << endl; 330 | } 331 | -------------------------------------------------------------------------------- /src/sysy.y: -------------------------------------------------------------------------------- 1 | %code requires { 2 | #include 3 | #include 4 | #include "ast/ast.hpp" 5 | } 6 | 7 | %{ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "ast/ast.hpp" 15 | 16 | static std::vector env_stk; 17 | static std::vector value_list; 18 | static std::vector func_list; 19 | static std::vector fparams; 20 | static std::vector> rparams; 21 | static std::vector arr_size; 22 | static std::vector> idx_stk; 23 | 24 | enum InitValType 25 | { 26 | array, 27 | exp 28 | }; 29 | static std::vector> arr_list; 30 | 31 | void add_inst(InstType instType, BaseAST *ast) 32 | { 33 | env_stk[env_stk.size()-1].push_back(make_pair(instType, std::unique_ptr(ast))); 34 | } 35 | 36 | 37 | // 声明 lexer 函数和错误处理函数 38 | int yylex(); 39 | void yyerror(std::unique_ptr &ast, const char *s); 40 | 41 | %} 42 | 43 | // 定义 parser 函数和错误处理函数的附加参数 44 | %parse-param { std::unique_ptr &ast } 45 | 46 | // yylval 的定义, 我们把它定义成了一个联合体 (union) 47 | // 因为 token 的值有的是字符串指针, 有的是整数 48 | // 之前我们在 lexer 中用到的 str_val 和 int_val 就是在这里被定义的 49 | %union { 50 | std::string *str_val; 51 | int int_val; 52 | BaseAST *base_ast_val; 53 | } 54 | 55 | // lexer 返回的所有 token 种类的声明 56 | %token INT VOID RETURN CONST IF ELSE WHILE BREAK CONTINUE 57 | %token IDENT UNARYOP MULOP ADDOP RELOP EQOP LANDOP LOROP 58 | %token INT_CONST 59 | 60 | // 非终结符的类型定义 61 | %type FuncDef BType Block IfExp 62 | %type LVal Number InitVal 63 | %type Exp PrimaryExp UnaryExp MulExp AddExp RelExp EqExp LAndExp LOrExp 64 | 65 | %% 66 | 67 | // 开始符, CompUnit ::= FuncDef, 大括号后声明了解析完成后 parser 要做的事情 68 | // $1 指代规则里第一个符号的返回值, 也就是 FuncDef 的返回值 69 | CompUnit 70 | : { 71 | env_stk.push_back(InstSet()); 72 | } 73 | GlobalList { 74 | ast = std::unique_ptr(new CompUnitAST(func_list, env_stk[env_stk.size()-1])); 75 | env_stk.pop_back(); 76 | }; 77 | 78 | GlobalList 79 | : FuncDef { 80 | func_list.push_back($1); 81 | } | GlobalList FuncDef { 82 | func_list.push_back($2); 83 | } 84 | | Decl | GlobalList Decl ; 85 | 86 | // FuncDef ::= FuncType IDENT '(' ')' Block; 87 | // $$ 表示非终结符的返回值, 我们可以通过给这个符号赋值的方法来返回结果 88 | FuncDef 89 | : BType IDENT '(' { 90 | fparams.clear(); 91 | } FuncFParams ')' Block { 92 | auto rettype = std::unique_ptr($1); 93 | auto ident = std::unique_ptr($2); 94 | auto block = std::unique_ptr($7); 95 | $$ = new FuncDefAST(rettype, ident->c_str(), fparams, block); 96 | } | BType IDENT '(' ')' Block { 97 | auto rettype = std::unique_ptr($1); 98 | auto ident = std::unique_ptr($2); 99 | auto block = std::unique_ptr($5); 100 | fparams.clear(); 101 | $$ = new FuncDefAST(rettype, ident->c_str(), fparams, block); 102 | }; 103 | 104 | BType 105 | : INT { 106 | $$ = new BTypeAST("int"); 107 | } | VOID { 108 | $$ = new BTypeAST("void"); 109 | }; 110 | 111 | FuncFParams : FuncFParam | FuncFParams ',' FuncFParam; 112 | 113 | FuncFParam 114 | : INT IDENT { 115 | fparams.push_back(new FuncFParamAST(FuncFParamAST::Int, $2->c_str(), fparams.size())); 116 | } 117 | | INT IDENT '[' ']' { 118 | fparams.push_back(new FuncFParamAST(FuncFParamAST::Array, $2->c_str(), fparams.size(), arr_size)); 119 | } 120 | | INT IDENT '[' ']' ArraySizeList { 121 | fparams.push_back(new FuncFParamAST(FuncFParamAST::Array, $2->c_str(), fparams.size(), arr_size)); 122 | arr_size.clear(); 123 | }; 124 | 125 | Block : 126 | '{' { 127 | env_stk.push_back(InstSet()); 128 | } 129 | BlockItems '}' { 130 | $$ = new BlockAST(env_stk[env_stk.size()-1]); 131 | env_stk.pop_back(); 132 | } | '{' '}' { 133 | $$ = new BlockAST(); 134 | }; 135 | 136 | BlockItems : BlockItem | BlockItem BlockItems ; 137 | 138 | BlockItem : Decl | Stmt ; 139 | 140 | Stmt 141 | : RETURN ';' { 142 | add_inst(InstType::Stmt, new ReturnAST()); 143 | } 144 | | RETURN Exp ';' { 145 | auto number = std::unique_ptr($2); 146 | add_inst(InstType::Stmt, new ReturnAST(number)); 147 | } | LVal '=' Exp ';' { 148 | auto lval = std::unique_ptr($1); 149 | auto exp = std::unique_ptr($3); 150 | add_inst(InstType::Stmt, new AssignmentAST(lval, exp)); 151 | } | IfExp Stmt ELSE { 152 | env_stk.push_back(InstSet()); 153 | } Stmt { 154 | auto exp = std::unique_ptr($1); 155 | InstSet true_instset, false_instset; 156 | for(auto &inst : env_stk[env_stk.size()-2]) 157 | true_instset.push_back(std::make_pair(inst.first, std::move(inst.second))); 158 | for(auto &inst : env_stk[env_stk.size()-1]) 159 | false_instset.push_back(std::make_pair(inst.first, std::move(inst.second))); 160 | env_stk.pop_back(); 161 | env_stk.pop_back(); 162 | add_inst(InstType::Branch, new BranchAST(exp, true_instset, false_instset)); 163 | } 164 | | IfExp Stmt { 165 | auto exp = std::unique_ptr($1); 166 | InstSet true_instset; 167 | for(auto &inst : env_stk[env_stk.size()-1]) 168 | true_instset.push_back(std::make_pair(inst.first, std::move(inst.second))); 169 | env_stk.pop_back(); 170 | add_inst(InstType::Branch, new BranchAST(exp, true_instset)); 171 | } | WHILE '(' Exp ')' { 172 | env_stk.push_back(InstSet()); 173 | } Stmt { 174 | auto exp = std::unique_ptr($3); 175 | InstSet while_body; 176 | for(auto &inst : env_stk[env_stk.size()-1]) 177 | while_body.push_back(std::make_pair(inst.first, std::move(inst.second))); 178 | env_stk.pop_back(); 179 | add_inst(InstType::While, new WhileAST(exp, while_body)); 180 | } | BREAK ';' { 181 | add_inst(InstType::Break, new BreakAST()); 182 | } | CONTINUE ';' { 183 | add_inst(InstType::Continue, new ContinueAST()); 184 | } 185 | | ';' | Exp ';' { 186 | add_inst(InstType::Stmt, $1); 187 | } | Block { 188 | add_inst(InstType::Stmt, $1); 189 | }; 190 | 191 | IfExp 192 | : IF '(' Exp ')' { 193 | env_stk.push_back(InstSet()); 194 | $$ = $3; 195 | }; 196 | 197 | Decl : ConstDecl | VarDecl; 198 | 199 | ConstDecl : CONST BType ConstDefList ';'; 200 | ConstDefList : ConstDef | ConstDefList ',' ConstDef 201 | ConstDef 202 | : IDENT '=' Exp { 203 | auto exp = std::unique_ptr($3); 204 | add_inst(InstType::ConstDecl, new ConstDefAST($1->c_str(), exp)); 205 | } 206 | | IDENT ArraySizeList '=' InitVal { 207 | auto initval = std::unique_ptr($4); 208 | add_inst(InstType::ArrayDecl, new ArrayDefAST($1->c_str(), arr_size, initval)); 209 | arr_size.clear(); 210 | }; 211 | | IDENT ArraySizeList { 212 | add_inst(InstType::ArrayDecl, new ArrayDefAST($1->c_str(), arr_size)); 213 | arr_size.clear(); 214 | }; 215 | 216 | VarDecl : BType VarDefList ';'; 217 | VarDefList : VarDef | VarDefList ',' VarDef 218 | VarDef 219 | : IDENT { 220 | add_inst(InstType::Decl, new VarDefAST($1->c_str())); 221 | } 222 | | IDENT '=' Exp { 223 | auto exp = std::unique_ptr($3); 224 | add_inst(InstType::Decl, new VarDefAST($1->c_str(), exp)); 225 | } 226 | | IDENT ArraySizeList '=' InitVal { 227 | auto initval = std::unique_ptr($4); 228 | add_inst(InstType::ArrayDecl, new ArrayDefAST($1->c_str(), arr_size, initval)); 229 | arr_size.clear(); 230 | }; 231 | | IDENT ArraySizeList { 232 | add_inst(InstType::ArrayDecl, new ArrayDefAST($1->c_str(), arr_size)); 233 | arr_size.clear(); 234 | } 235 | 236 | ArraySizeList : ArraySize | ArraySizeList ArraySize; 237 | 238 | ArraySize 239 | : '[' Exp ']' { 240 | arr_size.push_back($2); 241 | }; 242 | 243 | InitVal : Exp { 244 | auto exp = std::unique_ptr($1); 245 | $$ = new InitValAST(exp); 246 | } 247 | | '{' { 248 | arr_list.push_back(std::vector()); 249 | } ArrInitList '}' { 250 | $$ = new InitValAST(arr_list[arr_list.size()-1]); 251 | arr_list.pop_back(); 252 | } 253 | | '{' '}' { 254 | arr_list.push_back(std::vector()); 255 | $$ = new InitValAST(arr_list[arr_list.size()-1]); 256 | arr_list.pop_back(); 257 | }; 258 | 259 | ArrInitList : InitVal { 260 | arr_list[arr_list.size()-1].push_back($1); 261 | } 262 | | ArrInitList ',' InitVal { 263 | arr_list[arr_list.size()-1].push_back($3); 264 | }; 265 | 266 | LVal 267 | : IDENT { 268 | $$ = new LValAST($1->c_str()); 269 | } 270 | | IDENT { 271 | idx_stk.push_back(std::vector()); 272 | } IndexList { 273 | $$ = new LValAST($1->c_str(), idx_stk[idx_stk.size()-1]); 274 | idx_stk.pop_back(); 275 | }; 276 | 277 | IndexList : Index | IndexList Index 278 | 279 | Index : '[' Exp ']' { 280 | idx_stk[idx_stk.size()-1].push_back($2); 281 | } 282 | 283 | Exp 284 | : LOrExp { 285 | auto add_exp = std::unique_ptr($1); 286 | $$ = new ExpAST(add_exp); 287 | } 288 | ; 289 | 290 | PrimaryExp 291 | : '(' Exp ')' { 292 | auto exp = std::unique_ptr($2); 293 | $$ = new PrimaryExpAST(exp); 294 | } 295 | | Number { 296 | auto number = std::unique_ptr($1); 297 | $$ = new PrimaryExpAST(number); 298 | } 299 | | LVal { 300 | auto lval = std::unique_ptr($1); 301 | $$ = new PrimaryExpAST(lval); 302 | }; 303 | 304 | UnaryExp 305 | : PrimaryExp { 306 | auto primary_exp = std::unique_ptr($1); 307 | $$ = new UnaryExpAST(primary_exp); 308 | } 309 | | UNARYOP UnaryExp { 310 | auto op = std::unique_ptr($1); 311 | auto unary_exp = std::unique_ptr($2); 312 | $$ = new UnaryExpAST(op->c_str(), unary_exp); 313 | } 314 | | ADDOP UnaryExp { 315 | auto op = std::unique_ptr($1); 316 | auto unary_exp = std::unique_ptr($2); 317 | $$ = new UnaryExpAST(op->c_str(), unary_exp); 318 | } 319 | | IDENT '(' { 320 | rparams.push_back(std::vector()); 321 | } FuncRParams ')' { 322 | $$ = new UnaryExpAST($1->c_str(), rparams[rparams.size()-1]); 323 | rparams.pop_back(); 324 | } 325 | | IDENT '(' ')' { 326 | rparams.push_back(std::vector()); 327 | $$ = new UnaryExpAST($1->c_str(), rparams[rparams.size()-1]); 328 | rparams.pop_back(); 329 | } 330 | ; 331 | 332 | FuncRParams : FuncRParam | FuncRParams ',' FuncRParam; 333 | 334 | FuncRParam 335 | : Exp { 336 | rparams[rparams.size()-1].push_back($1); 337 | } 338 | 339 | MulExp 340 | : UnaryExp { 341 | auto unary_exp = std::unique_ptr($1); 342 | $$ = new MulExpAST(unary_exp); 343 | } 344 | | MulExp MULOP UnaryExp { 345 | auto left_exp = std::unique_ptr($1); 346 | auto op = std::unique_ptr($2); 347 | auto right_exp = std::unique_ptr($3); 348 | $$ = new MulExpAST(left_exp, op->c_str(), right_exp); 349 | }; 350 | 351 | AddExp 352 | : MulExp { 353 | auto mul_exp = std::unique_ptr($1); 354 | $$ = new MulExpAST(mul_exp); 355 | } 356 | | AddExp ADDOP MulExp { 357 | auto left_exp = std::unique_ptr($1); 358 | auto op = std::unique_ptr($2); 359 | auto right_exp = std::unique_ptr($3); 360 | $$ = new AddExpAST(left_exp, op->c_str(), right_exp); 361 | }; 362 | 363 | RelExp 364 | : AddExp { 365 | auto add_exp = std::unique_ptr($1); 366 | $$ = new RelExpAST(add_exp); 367 | } 368 | | RelExp RELOP AddExp { 369 | auto left_exp = std::unique_ptr($1); 370 | auto op = std::unique_ptr($2); 371 | auto right_exp = std::unique_ptr($3); 372 | $$ = new RelExpAST(left_exp, op->c_str(), right_exp); 373 | }; 374 | 375 | EqExp 376 | : RelExp { 377 | auto rel_exp = std::unique_ptr($1); 378 | $$ = new EqExpAST(rel_exp); 379 | } 380 | | EqExp EQOP RelExp { 381 | auto left_exp = std::unique_ptr($1); 382 | auto op = std::unique_ptr($2); 383 | auto right_exp = std::unique_ptr($3); 384 | $$ = new EqExpAST(left_exp, op->c_str(), right_exp); 385 | }; 386 | 387 | LAndExp 388 | : EqExp { 389 | auto eq_exp = std::unique_ptr($1); 390 | $$ = new LAndExpAST(eq_exp); 391 | } 392 | | LAndExp LANDOP EqExp { 393 | auto left_exp = std::unique_ptr($1); 394 | auto op = std::unique_ptr($2); 395 | auto right_exp = std::unique_ptr($3); 396 | $$ = new LAndExpAST(left_exp, op->c_str(), right_exp); 397 | }; 398 | 399 | LOrExp 400 | : LAndExp { 401 | auto land_exp = std::unique_ptr($1); 402 | $$ = new LOrExpAST(land_exp); 403 | } 404 | | LOrExp LOROP LAndExp { 405 | auto left_exp = std::unique_ptr($1); 406 | auto op = std::unique_ptr($2); 407 | auto right_exp = std::unique_ptr($3); 408 | $$ = new LOrExpAST(left_exp, op->c_str(), right_exp); 409 | }; 410 | 411 | Number 412 | : INT_CONST { 413 | $$ = new NumberAST($1); 414 | } 415 | ; 416 | 417 | %% 418 | 419 | // 定义错误处理函数, 其中第二个参数是错误信息 420 | // parser 如果发生错误 (例如输入的程序出现了语法错误), 就会调用这个函数 421 | void yyerror(std::unique_ptr &ast, const char *s) { 422 | std::cerr << "error: " << s << std::endl; 423 | } 424 | -------------------------------------------------------------------------------- /src/ast/code_ast.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "ast/base_ast.hpp" 6 | #include "koopa_util.hpp" 7 | 8 | enum InstType 9 | { 10 | ConstDecl, 11 | Decl, 12 | ArrayDecl, 13 | Stmt, 14 | Branch, 15 | While, 16 | Break, 17 | Continue 18 | }; 19 | typedef std::vector>> InstSet; 20 | 21 | // CompUnit 是 BaseAST 22 | class CompUnitAST : public BaseAST 23 | { 24 | void add_lib_funcs(std::vector &funcs) const; 25 | 26 | public: 27 | // 用智能指针管理对象 28 | std::vector> func_list; 29 | InstSet value_list; 30 | 31 | CompUnitAST(std::vector &_func_list, InstSet &_value_list); 32 | 33 | koopa_raw_program_t to_koopa_raw_program() const 34 | { 35 | symbol_list.NewEnv(); 36 | std::vector values; 37 | std::vector funcs; 38 | add_lib_funcs(funcs); 39 | for(auto &pa : value_list) 40 | { 41 | assert(pa.first == ConstDecl || pa.first == Decl || pa.first == ArrayDecl); 42 | if(pa.first == ConstDecl) 43 | pa.second->build_koopa_values(); 44 | else 45 | values.push_back(pa.second->build_koopa_values()); 46 | } 47 | for(auto &func_ast : func_list) 48 | funcs.push_back(func_ast->build_koopa_values()); 49 | symbol_list.DeleteEnv(); 50 | 51 | koopa_raw_program_t res; 52 | res.values = make_koopa_rs_from_vector(values, KOOPA_RSIK_VALUE); 53 | res.funcs = make_koopa_rs_from_vector(funcs, KOOPA_RSIK_FUNCTION); 54 | 55 | return res; 56 | } 57 | }; 58 | 59 | class BTypeAST : public BaseAST 60 | { 61 | public: 62 | std::string name; 63 | BTypeAST(const char *_name) : name(_name) {} 64 | 65 | void *build_koopa_values() const override 66 | { 67 | if (name == "int") 68 | return simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 69 | else if(name == "void") 70 | return simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 71 | return nullptr; // not implement 72 | } 73 | }; 74 | 75 | class FuncFParamAST : public BaseAST 76 | { 77 | public: 78 | enum ParamType 79 | { 80 | Int, 81 | Array 82 | } type; 83 | std::string name; 84 | int index; 85 | std::vector> sz_exp; 86 | 87 | FuncFParamAST(ParamType _type, const char *_name, int _index) : type(_type), name(_name), index(_index) {} 88 | FuncFParamAST(ParamType _type, const char *_name, int _index, std::vector &_sz_Exp) : type(_type), name(_name), index(_index) 89 | { 90 | for(auto e : _sz_Exp) 91 | sz_exp.emplace_back(e); 92 | } 93 | 94 | void *get_koopa_type() const 95 | { 96 | if(type == Array) 97 | { 98 | if(sz_exp.empty()) 99 | return make_int_pointer_type(); 100 | else 101 | { 102 | std::vector sz; 103 | for(auto &e : sz_exp) 104 | sz.push_back(e->CalcValue()); 105 | koopa_raw_type_kind *ty = make_array_type(sz); 106 | koopa_raw_type_kind *tty = new koopa_raw_type_kind(); 107 | tty->tag = KOOPA_RTT_POINTER; 108 | tty->data.pointer.base = ty; 109 | return tty; 110 | } 111 | } 112 | else if (type == Int) 113 | return simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 114 | return nullptr; 115 | } 116 | 117 | void *build_koopa_values() const override 118 | { 119 | koopa_raw_value_data *res = new koopa_raw_value_data(); 120 | res->ty = (koopa_raw_type_kind*)get_koopa_type(); 121 | res->name = new_char_arr("@" + name); 122 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 123 | res->kind.tag = KOOPA_RVT_FUNC_ARG_REF; 124 | res->kind.data.func_arg_ref.index = index; 125 | return res; 126 | } 127 | }; 128 | 129 | // AST code block, enclosed in '{}'. Different from koopa basic block 130 | class BlockAST : public BaseAST 131 | { 132 | public: 133 | InstSet insts; 134 | 135 | BlockAST() {} 136 | BlockAST(InstSet &_insts) 137 | { 138 | for (auto &inst : _insts) 139 | insts.push_back(std::make_pair(inst.first, std::move(inst.second))); 140 | } 141 | 142 | static void add_InstSet(const InstSet &insts) 143 | { 144 | symbol_list.NewEnv(); 145 | for (const auto &inst : insts) 146 | inst.second->build_koopa_values(); 147 | symbol_list.DeleteEnv(); 148 | } 149 | 150 | void build_koopa_values_no_env() const 151 | { 152 | for (const auto &inst : insts) 153 | inst.second->build_koopa_values(); 154 | } 155 | 156 | void *build_koopa_values() const override 157 | { 158 | add_InstSet(insts); 159 | return nullptr; 160 | } 161 | }; 162 | 163 | // FuncDef 也是 BaseAST 164 | class FuncDefAST : public BaseAST 165 | { 166 | public: 167 | std::unique_ptr func_type; 168 | std::string ident; 169 | std::vector> fparams; 170 | std::unique_ptr block; 171 | 172 | FuncDefAST(std::unique_ptr &_func_type, const char *_ident, std::vector &_fparams, std::unique_ptr &_block) 173 | : ident(_ident) 174 | { 175 | func_type = std::move(_func_type); 176 | for(BaseAST* fp : _fparams) 177 | fparams.emplace_back(dynamic_cast(fp)); 178 | block = std::unique_ptr(dynamic_cast(_block.release())); 179 | } 180 | 181 | std::string to_string() const override 182 | { 183 | return "FuncDefAST { " + func_type->to_string() + ", " + ident + ", " + block->to_string() + " }"; 184 | } 185 | 186 | void *build_koopa_values() const override 187 | { 188 | koopa_raw_function_data_t *res = new koopa_raw_function_data_t(); 189 | symbol_list.AddSymbol(ident, LValSymbol(LValSymbol::Function, res)); 190 | 191 | koopa_raw_type_kind_t *ty = new koopa_raw_type_kind_t(); 192 | ty->tag = KOOPA_RTT_FUNCTION; 193 | std::vector par; 194 | for(auto &fp : fparams) 195 | par.push_back(fp->get_koopa_type()); 196 | ty->data.function.params = make_koopa_rs_from_vector(par, KOOPA_RSIK_TYPE); 197 | ty->data.function.ret = (const struct koopa_raw_type_kind *)func_type->build_koopa_values(); 198 | res->ty = ty; 199 | res->name = new_char_arr("@" + ident); 200 | par.clear(); 201 | for(auto &fp : fparams) 202 | par.push_back(fp->build_koopa_values()); 203 | res->params = make_koopa_rs_from_vector(par, KOOPA_RSIK_VALUE); 204 | 205 | std::vector blocks; 206 | block_maintainer.SetBasicBlockBuf(&blocks); 207 | 208 | koopa_raw_basic_block_data_t *entry_block = new koopa_raw_basic_block_data_t(); 209 | entry_block->name = new_char_arr("%entry_" + ident); 210 | entry_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 211 | entry_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 212 | 213 | symbol_list.NewEnv(); 214 | block_maintainer.AddNewBasicBlock(entry_block); 215 | block_maintainer.SetCurrentFunction(res); 216 | for(size_t i = 0; i < fparams.size(); i++) 217 | { 218 | auto &fp = fparams[i]; 219 | koopa_raw_value_data *allo = AllocType("@" + fp->name, ((koopa_raw_value_t)par[i])->ty); 220 | if(allo->ty->data.pointer.base->tag == KOOPA_RTT_POINTER) 221 | symbol_list.AddSymbol(fp->name, LValSymbol(LValSymbol::Pointer, allo)); 222 | else 223 | symbol_list.AddSymbol(fp->name, LValSymbol(LValSymbol::Var, allo)); 224 | block_maintainer.AddInst(allo); 225 | koopa_raw_value_data *sto = new koopa_raw_value_data(); 226 | sto->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 227 | sto->name = nullptr; 228 | sto->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 229 | sto->kind.tag = KOOPA_RVT_STORE; 230 | sto->kind.data.store.value = (koopa_raw_value_t)par[i]; 231 | sto->kind.data.store.dest = allo; 232 | block_maintainer.AddInst(sto); 233 | } 234 | block->build_koopa_values_no_env(); 235 | symbol_list.DeleteEnv(); 236 | block_maintainer.FinishCurrentBlock(); 237 | 238 | res->bbs = make_koopa_rs_from_vector(blocks, KOOPA_RSIK_BASIC_BLOCK); 239 | 240 | return res; 241 | } 242 | }; 243 | 244 | class ReturnAST : public BaseAST 245 | { 246 | public: 247 | std::unique_ptr ret_num; 248 | ReturnAST() 249 | { 250 | ret_num = nullptr; 251 | } 252 | ReturnAST(std::unique_ptr &_ret_num) 253 | { 254 | ret_num = std::move(_ret_num); 255 | } 256 | void *build_koopa_values() const override 257 | { 258 | koopa_raw_value_data *res = new koopa_raw_value_data(); 259 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 260 | res->name = nullptr; 261 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 262 | res->kind.tag = KOOPA_RVT_RETURN; 263 | if(ret_num) 264 | res->kind.data.ret.value = (const koopa_raw_value_data *)ret_num->build_koopa_values(); 265 | else 266 | res->kind.data.ret.value = nullptr; 267 | block_maintainer.AddInst(res); 268 | return res; 269 | } 270 | }; 271 | 272 | class AssignmentAST : public BaseAST 273 | { 274 | public: 275 | std::unique_ptr lval; 276 | std::unique_ptr exp; 277 | AssignmentAST(std::unique_ptr &_lval, std::unique_ptr &_exp) 278 | { 279 | lval = std::move(_lval); 280 | exp = std::move(_exp); 281 | } 282 | void *build_koopa_values() const override 283 | { 284 | koopa_raw_value_data *res = new koopa_raw_value_data(); 285 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 286 | res->name = nullptr; 287 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 288 | res->kind.tag = KOOPA_RVT_STORE; 289 | res->kind.data.store.value = (koopa_raw_value_t)exp->build_koopa_values(); 290 | res->kind.data.store.dest = (koopa_raw_value_t)lval->koopa_leftvalue(); 291 | block_maintainer.AddInst(res); 292 | return nullptr; 293 | } 294 | }; 295 | 296 | class BranchAST : public BaseAST 297 | { 298 | public: 299 | std::unique_ptr exp; 300 | InstSet true_instset; 301 | InstSet false_instset; 302 | BranchAST(std::unique_ptr &_exp, InstSet &_true_insts) 303 | { 304 | for (auto &inst : _true_insts) 305 | true_instset.push_back(std::make_pair(inst.first, std::move(inst.second))); 306 | exp = std::move(_exp); 307 | } 308 | BranchAST(std::unique_ptr &_exp, InstSet &_true_insts, InstSet &_false_insts) 309 | { 310 | for (auto &inst : _true_insts) 311 | true_instset.push_back(std::make_pair(inst.first, std::move(inst.second))); 312 | for (auto &inst : _false_insts) 313 | false_instset.push_back(std::make_pair(inst.first, std::move(inst.second))); 314 | exp = std::move(_exp); 315 | } 316 | void *build_koopa_values() const override 317 | { 318 | koopa_raw_value_data *res = new koopa_raw_value_data(); 319 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 320 | res->name = nullptr; 321 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 322 | res->kind.tag = KOOPA_RVT_BRANCH; 323 | res->kind.data.branch.cond = (koopa_raw_value_t)exp->build_koopa_values(); 324 | koopa_raw_basic_block_data_t *true_block = new koopa_raw_basic_block_data_t(); 325 | koopa_raw_basic_block_data_t *false_block = new koopa_raw_basic_block_data_t(); 326 | koopa_raw_basic_block_data_t *end_block = new koopa_raw_basic_block_data_t(); 327 | res->kind.data.branch.true_bb = true_block; 328 | res->kind.data.branch.false_bb = false_block; 329 | res->kind.data.branch.true_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 330 | res->kind.data.branch.false_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 331 | block_maintainer.AddInst(res); 332 | 333 | true_block->name = new_char_arr("%true"); 334 | true_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 335 | true_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 336 | block_maintainer.AddNewBasicBlock(true_block); 337 | BlockAST::add_InstSet(this->true_instset); 338 | block_maintainer.AddInst(JumpInst(end_block)); 339 | 340 | false_block->name = new_char_arr("%false"); 341 | false_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 342 | false_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 343 | block_maintainer.AddNewBasicBlock(false_block); 344 | std::vector false_insts; 345 | BlockAST::add_InstSet(this->false_instset); 346 | block_maintainer.AddInst(JumpInst(end_block)); 347 | 348 | end_block->name = new_char_arr("%end"); 349 | end_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 350 | end_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 351 | block_maintainer.AddNewBasicBlock(end_block); 352 | 353 | return nullptr; 354 | } 355 | }; 356 | 357 | class WhileAST : public BaseAST 358 | { 359 | public: 360 | std::unique_ptr exp; 361 | InstSet body_insts; 362 | WhileAST(std::unique_ptr &_exp, InstSet &_body_insts) 363 | { 364 | for (auto &inst : _body_insts) 365 | body_insts.push_back(std::make_pair(inst.first, std::move(inst.second))); 366 | exp = std::move(_exp); 367 | } 368 | void *build_koopa_values() const override 369 | { 370 | koopa_raw_basic_block_data_t *while_entry = new koopa_raw_basic_block_data_t(); 371 | koopa_raw_basic_block_data_t *while_body = new koopa_raw_basic_block_data_t(); 372 | koopa_raw_basic_block_data_t *end_block = new koopa_raw_basic_block_data_t(); 373 | loop_maintainer.AddLoop(while_entry, while_body, end_block); 374 | 375 | block_maintainer.AddInst(JumpInst(while_entry)); 376 | 377 | while_entry->name = new_char_arr("%while_entry"); 378 | while_entry->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 379 | while_entry->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 380 | block_maintainer.AddNewBasicBlock(while_entry); 381 | 382 | koopa_raw_value_data *br = new koopa_raw_value_data(); 383 | br->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 384 | br->name = nullptr; 385 | br->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 386 | br->kind.tag = KOOPA_RVT_BRANCH; 387 | br->kind.data.branch.cond = (koopa_raw_value_t)exp->build_koopa_values(); 388 | br->kind.data.branch.true_bb = while_body; 389 | br->kind.data.branch.false_bb = end_block; 390 | br->kind.data.branch.true_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 391 | br->kind.data.branch.false_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 392 | block_maintainer.AddInst(br); 393 | 394 | while_body->name = new_char_arr("%while_body"); 395 | while_body->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 396 | while_body->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 397 | block_maintainer.AddNewBasicBlock(while_body); 398 | BlockAST::add_InstSet(this->body_insts); 399 | block_maintainer.AddInst(JumpInst(while_entry)); 400 | 401 | end_block->name = new_char_arr("%end"); 402 | end_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 403 | end_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 404 | block_maintainer.AddNewBasicBlock(end_block); 405 | 406 | loop_maintainer.PopLoop(); 407 | return nullptr; 408 | } 409 | }; 410 | 411 | class BreakAST : public BaseAST 412 | { 413 | public: 414 | void *build_koopa_values() const override 415 | { 416 | block_maintainer.AddInst(JumpInst(loop_maintainer.GetLoop().end_block)); 417 | return nullptr; 418 | } 419 | }; 420 | 421 | class ContinueAST : public BaseAST 422 | { 423 | public: 424 | void *build_koopa_values() const override 425 | { 426 | block_maintainer.AddInst(JumpInst(loop_maintainer.GetLoop().while_entry)); 427 | return nullptr; 428 | } 429 | }; 430 | 431 | class ConstDefAST : public BaseAST 432 | { 433 | public: 434 | std::string name; 435 | std::unique_ptr exp; 436 | 437 | ConstDefAST(const char *_name, std::unique_ptr &_exp) 438 | : name(_name) 439 | { 440 | exp = std::move(_exp); 441 | } 442 | 443 | void *build_koopa_values() const override 444 | { 445 | koopa_raw_value_data *res = new koopa_raw_value_data(); 446 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 447 | res->name = nullptr; 448 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 449 | res->kind.tag = KOOPA_RVT_INTEGER; 450 | res->kind.data.integer.value = exp->CalcValue(); 451 | symbol_list.AddSymbol(name, LValSymbol(LValSymbol::Const, res)); 452 | return res; 453 | } 454 | }; 455 | 456 | class VarDefAST : public BaseAST 457 | { 458 | public: 459 | std::string name; 460 | std::unique_ptr exp; 461 | 462 | VarDefAST(const char *_name) 463 | : name(_name) 464 | { 465 | exp = nullptr; 466 | } 467 | 468 | VarDefAST(const char *_name, std::unique_ptr &_exp) 469 | : name(_name) 470 | { 471 | exp = std::move(_exp); 472 | } 473 | 474 | void *build_koopa_values() const override 475 | { 476 | koopa_raw_value_data *res = new koopa_raw_value_data(); 477 | res->ty = make_int_pointer_type(); 478 | res->name = new_char_arr("@" + name); 479 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 480 | res->kind.tag = KOOPA_RVT_ALLOC; 481 | block_maintainer.AddInst(res); 482 | symbol_list.AddSymbol(name, LValSymbol(LValSymbol::Var, res)); 483 | 484 | if (exp) 485 | { 486 | koopa_raw_value_data *store = new koopa_raw_value_data(); 487 | store->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 488 | store->name = nullptr; 489 | store->used_by = empty_koopa_rs(); 490 | store->kind.tag = KOOPA_RVT_STORE; 491 | store->kind.data.store.dest = res; 492 | store->kind.data.store.value = (koopa_raw_value_t)exp->build_koopa_values(); 493 | block_maintainer.AddInst(store); 494 | } 495 | 496 | return res; 497 | } 498 | }; 499 | 500 | class GlobalVarDefAST : public BaseAST 501 | { 502 | public: 503 | std::string name; 504 | std::unique_ptr exp; 505 | 506 | GlobalVarDefAST(std::unique_ptr &vardef_ast) 507 | { 508 | VarDefAST *var = dynamic_cast(vardef_ast.release()); 509 | name = var->name; 510 | exp = std::move(var->exp); 511 | delete var; 512 | } 513 | 514 | void *build_koopa_values() const override 515 | { 516 | koopa_raw_value_data *res = new koopa_raw_value_data(); 517 | res->ty = make_int_pointer_type(); 518 | res->name = new_char_arr("@" + name); 519 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 520 | res->kind.tag = KOOPA_RVT_GLOBAL_ALLOC; 521 | if(exp) 522 | res->kind.data.global_alloc.init = make_koopa_interger(exp->CalcValue());//(koopa_raw_value_data*)exp->build_koopa_values(); 523 | else 524 | res->kind.data.global_alloc.init = ZeroInit(); 525 | block_maintainer.AddInst(res); 526 | symbol_list.AddSymbol(name, LValSymbol(LValSymbol::Var, res)); 527 | return res; 528 | } 529 | }; 530 | -------------------------------------------------------------------------------- /src/ast/exp_ast.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ast/base_ast.hpp" 4 | 5 | class ExpAST : public BaseAST 6 | { 7 | public: 8 | std::unique_ptr unaryExp; 9 | 10 | ExpAST(std::unique_ptr &_unaryExp) 11 | { 12 | unaryExp = std::move(_unaryExp); 13 | } 14 | 15 | void *build_koopa_values() const override 16 | { 17 | return unaryExp->build_koopa_values(); 18 | } 19 | 20 | int CalcValue() const override 21 | { 22 | return unaryExp->CalcValue(); 23 | } 24 | }; 25 | 26 | class LValAST : public BaseAST 27 | { 28 | enum ValType 29 | { 30 | Num, 31 | Array 32 | }; 33 | public: 34 | ValType type; 35 | std::string name; 36 | std::vector> idx; 37 | LValAST(const char *_name) : name(_name) 38 | { 39 | type = Num; 40 | } 41 | LValAST(const char *_name, std::vector &_idx) : name(_name) 42 | { 43 | type = Array; 44 | for(auto &i : _idx) 45 | idx.emplace_back(i); 46 | } 47 | 48 | // 将变量作为左值返回(返回该左值的变量本身) 49 | void *koopa_leftvalue() const override 50 | { 51 | if(type == Array) 52 | { 53 | koopa_raw_value_data *get; 54 | koopa_raw_value_t src = (koopa_raw_value_t)symbol_list.GetSymbol(name).number; 55 | if(src->ty->data.pointer.base->tag == KOOPA_RTT_POINTER) 56 | { 57 | koopa_raw_value_t src = (koopa_raw_value_t)symbol_list.GetSymbol(name).number; 58 | koopa_raw_value_data *load0 = new koopa_raw_value_data(); 59 | load0->ty = src->ty->data.pointer.base; 60 | load0->name = nullptr; 61 | load0->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 62 | load0->kind.tag = KOOPA_RVT_LOAD; 63 | load0->kind.data.load.src = src; 64 | block_maintainer.AddInst(load0); 65 | 66 | bool first = true; 67 | src = load0; 68 | for(auto &i : idx) 69 | { 70 | get = new koopa_raw_value_data(); 71 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 72 | if(first) 73 | { 74 | get->ty = src->ty; 75 | get->name = nullptr; 76 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 77 | get->kind.tag = KOOPA_RVT_GET_PTR; 78 | get->kind.data.get_ptr.src = src; 79 | get->kind.data.get_ptr.index = (koopa_raw_value_t)i->build_koopa_values(); 80 | first = false; 81 | } 82 | else 83 | { 84 | ty->tag = KOOPA_RTT_POINTER; 85 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 86 | get->ty = ty; 87 | get->name = nullptr; 88 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 89 | get->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 90 | get->kind.data.get_elem_ptr.src = src; 91 | get->kind.data.get_elem_ptr.index = (koopa_raw_value_t)i->build_koopa_values(); 92 | } 93 | block_maintainer.AddInst(get); 94 | src = get; 95 | } 96 | } 97 | else 98 | { 99 | for(auto &i : idx) 100 | { 101 | get = new koopa_raw_value_data(); 102 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 103 | ty->tag = KOOPA_RTT_POINTER; 104 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 105 | get->ty = ty; 106 | get->name = nullptr; 107 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 108 | get->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 109 | get->kind.data.get_elem_ptr.src = src; 110 | get->kind.data.get_elem_ptr.index = (koopa_raw_value_t)i->build_koopa_values(); 111 | block_maintainer.AddInst(get); 112 | src = get; 113 | } 114 | } 115 | return get; 116 | } 117 | else if (type == Num) 118 | { 119 | return (void *)symbol_list.GetSymbol(name).number; 120 | } 121 | return nullptr; 122 | } 123 | 124 | // 将变量作为右值返回(读取变量里存储的值) 125 | void *build_koopa_values() const override 126 | { 127 | koopa_raw_value_data *res = new koopa_raw_value_data(); 128 | auto var = symbol_list.GetSymbol(name); 129 | if (var.type == LValSymbol::Const) 130 | return (void *)var.number; 131 | else if (var.type == LValSymbol::Var) 132 | { 133 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 134 | res->name = nullptr; 135 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 136 | res->kind.tag = KOOPA_RVT_LOAD; 137 | res->kind.data.load.src = (koopa_raw_value_t)var.number; 138 | block_maintainer.AddInst(res); 139 | } 140 | else if (var.type == LValSymbol::Array) 141 | { 142 | bool need_load = false; 143 | koopa_raw_value_data *get; 144 | koopa_raw_value_data *src = (koopa_raw_value_data*)var.number; 145 | if(idx.empty()) 146 | { 147 | get = new koopa_raw_value_data(); 148 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 149 | ty->tag = KOOPA_RTT_POINTER; 150 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 151 | get->ty = ty; 152 | get->name = nullptr; 153 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 154 | get->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 155 | get->kind.data.get_elem_ptr.src = src; 156 | get->kind.data.get_elem_ptr.index = make_koopa_interger(0); 157 | block_maintainer.AddInst(get); 158 | } 159 | else 160 | { 161 | for(auto &i : idx) 162 | { 163 | get = new koopa_raw_value_data(); 164 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 165 | ty->tag = KOOPA_RTT_POINTER; 166 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 167 | get->ty = ty; 168 | get->name = nullptr; 169 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 170 | get->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 171 | get->kind.data.get_elem_ptr.src = src; 172 | get->kind.data.get_elem_ptr.index = (koopa_raw_value_t)i->build_koopa_values(); 173 | block_maintainer.AddInst(get); 174 | src = get; 175 | if(ty->data.pointer.base->tag == KOOPA_RTT_INT32) 176 | need_load = true; 177 | } 178 | } 179 | if(need_load) 180 | { 181 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 182 | res->name = nullptr; 183 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 184 | res->kind.tag = KOOPA_RVT_LOAD; 185 | res->kind.data.load.src = get; 186 | block_maintainer.AddInst(res); 187 | } 188 | else if(src->ty->data.pointer.base->tag == KOOPA_RTT_ARRAY) 189 | { 190 | res = new koopa_raw_value_data(); 191 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 192 | ty->tag = KOOPA_RTT_POINTER; 193 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 194 | res->ty = ty; 195 | res->name = nullptr; 196 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 197 | res->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 198 | res->kind.data.get_elem_ptr.src = src; 199 | res->kind.data.get_elem_ptr.index = make_koopa_interger(0); 200 | block_maintainer.AddInst(res); 201 | } 202 | else 203 | res = src; 204 | } 205 | else if (var.type == LValSymbol::Pointer) 206 | { 207 | koopa_raw_value_data *src = (koopa_raw_value_data*)var.number; 208 | koopa_raw_value_data *load0 = new koopa_raw_value_data(); 209 | load0->ty = src->ty->data.pointer.base; 210 | load0->name = nullptr; 211 | load0->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 212 | load0->kind.tag = KOOPA_RVT_LOAD; 213 | load0->kind.data.load.src = src; 214 | block_maintainer.AddInst(load0); 215 | 216 | bool need_load = false; 217 | bool first = true; 218 | koopa_raw_value_data *get; 219 | src = load0; 220 | for(auto &i : idx) 221 | { 222 | get = new koopa_raw_value_data(); 223 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 224 | if(first) 225 | { 226 | get->ty = src->ty; 227 | get->name = nullptr; 228 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 229 | get->kind.tag = KOOPA_RVT_GET_PTR; 230 | get->kind.data.get_ptr.src = src; 231 | get->kind.data.get_ptr.index = (koopa_raw_value_t)i->build_koopa_values(); 232 | first = false; 233 | } 234 | else 235 | { 236 | ty->tag = KOOPA_RTT_POINTER; 237 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 238 | get->ty = ty; 239 | get->name = nullptr; 240 | get->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 241 | get->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 242 | get->kind.data.get_elem_ptr.src = src; 243 | get->kind.data.get_elem_ptr.index = (koopa_raw_value_t)i->build_koopa_values(); 244 | } 245 | block_maintainer.AddInst(get); 246 | src = get; 247 | if(get->ty->data.pointer.base->tag == KOOPA_RTT_INT32) 248 | need_load = true; 249 | } 250 | if(need_load) 251 | { 252 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 253 | res->name = nullptr; 254 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 255 | res->kind.tag = KOOPA_RVT_LOAD; 256 | res->kind.data.load.src = get; 257 | block_maintainer.AddInst(res); 258 | } 259 | else if(src->ty->data.pointer.base->tag == KOOPA_RTT_ARRAY) 260 | { 261 | res = new koopa_raw_value_data(); 262 | koopa_raw_type_kind *ty = new koopa_raw_type_kind(); 263 | ty->tag = KOOPA_RTT_POINTER; 264 | ty->data.pointer.base = src->ty->data.pointer.base->data.array.base; 265 | res->ty = ty; 266 | res->name = nullptr; 267 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 268 | res->kind.tag = KOOPA_RVT_GET_ELEM_PTR; 269 | res->kind.data.get_elem_ptr.src = src; 270 | res->kind.data.get_elem_ptr.index = make_koopa_interger(0); 271 | block_maintainer.AddInst(res); 272 | } 273 | else 274 | res = src; 275 | } 276 | return res; 277 | } 278 | 279 | int CalcValue() const override 280 | { 281 | auto var = symbol_list.GetSymbol(name); 282 | assert(var.type == LValSymbol::Const); 283 | return ((koopa_raw_value_t)var.number)->kind.data.integer.value; 284 | } 285 | }; 286 | 287 | class PrimaryExpAST : public BaseAST 288 | { 289 | public: 290 | std::unique_ptr nextExp; // Exp or Number 291 | PrimaryExpAST(std::unique_ptr &_nextExp) 292 | { 293 | nextExp = std::move(_nextExp); 294 | } 295 | void *build_koopa_values() const override 296 | { 297 | return nextExp->build_koopa_values(); 298 | } 299 | int CalcValue() const override 300 | { 301 | return nextExp->CalcValue(); 302 | } 303 | }; 304 | 305 | class UnaryExpAST : public BaseAST 306 | { 307 | public: 308 | enum 309 | { 310 | Primary, 311 | Op, 312 | Function 313 | } type; 314 | std::string op; 315 | std::unique_ptr nextExp; // PrimaryExp or UnaryExp 316 | std::vector funcRParams; 317 | 318 | UnaryExpAST(std::unique_ptr &_primary_exp) 319 | { 320 | type = Primary; 321 | nextExp = std::move(_primary_exp); 322 | } 323 | UnaryExpAST(const char *_op, std::unique_ptr &_unary_exp) 324 | { 325 | type = Op; 326 | op = std::string(_op); 327 | nextExp = std::move(_unary_exp); 328 | } 329 | UnaryExpAST(const char *_ident, std::vector &rparams) : op(_ident), funcRParams(rparams) 330 | { 331 | type = Function; 332 | } 333 | 334 | void *build_koopa_values() const override 335 | { 336 | NumberAST zero(0); 337 | koopa_raw_value_data *res = nullptr; 338 | koopa_raw_function_data_t *func = nullptr; 339 | std::vector rpa; 340 | switch (type) 341 | { 342 | case Primary: 343 | res = (koopa_raw_value_data *)nextExp->build_koopa_values(); 344 | break; 345 | case Function: 346 | func = (koopa_raw_function_data_t *)symbol_list.GetSymbol(op).number; 347 | for(auto rp : funcRParams) 348 | rpa.push_back(rp->build_koopa_values()); 349 | res = new koopa_raw_value_data(); 350 | res->ty = func->ty->data.function.ret; 351 | res->name = nullptr; 352 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 353 | res->kind.tag = KOOPA_RVT_CALL; 354 | res->kind.data.call.callee = func; 355 | res->kind.data.call.args = make_koopa_rs_from_vector(rpa, KOOPA_RSIK_VALUE); 356 | block_maintainer.AddInst(res); 357 | break; 358 | case Op: 359 | if (op == "+") 360 | { 361 | res = (koopa_raw_value_data *)nextExp->build_koopa_values(); 362 | break; 363 | } 364 | res = new koopa_raw_value_data(); 365 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 366 | res->name = nullptr; 367 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 368 | res->kind.tag = KOOPA_RVT_BINARY; 369 | auto &binary = res->kind.data.binary; 370 | if (op == "-") 371 | binary.op = KOOPA_RBO_SUB; 372 | else if (op == "!") 373 | binary.op = KOOPA_RBO_EQ; 374 | binary.lhs = (koopa_raw_value_t)zero.build_koopa_values(); 375 | binary.rhs = (koopa_raw_value_t)nextExp->build_koopa_values(); 376 | block_maintainer.AddInst(res); 377 | break; 378 | } 379 | return res; 380 | } 381 | int CalcValue() const override 382 | { 383 | if (type == Primary) 384 | return nextExp->CalcValue(); 385 | int res = 0; 386 | if (op == "+") 387 | res = nextExp->CalcValue(); 388 | else if (op == "-") 389 | res = -nextExp->CalcValue(); 390 | else if (op == "!") 391 | res = !nextExp->CalcValue(); 392 | return res; 393 | } 394 | }; 395 | 396 | class MulExpAST : public BaseAST 397 | { 398 | public: 399 | enum 400 | { 401 | Primary, 402 | Op 403 | } type; 404 | std::string op; 405 | std::unique_ptr leftExp; // may be primary 406 | std::unique_ptr rightExp; 407 | 408 | MulExpAST(std::unique_ptr &_primary_exp) 409 | { 410 | type = Primary; 411 | leftExp = std::move(_primary_exp); 412 | } 413 | MulExpAST(std::unique_ptr &_left_exp, const char *_op, std::unique_ptr &_right_exp) 414 | { 415 | type = Op; 416 | leftExp = std::move(_left_exp); 417 | op = std::string(_op); 418 | rightExp = std::move(_right_exp); 419 | } 420 | 421 | void *build_koopa_values() const override 422 | { 423 | koopa_raw_value_data *res = nullptr; 424 | switch (type) 425 | { 426 | case Primary: 427 | res = (koopa_raw_value_data *)leftExp->build_koopa_values(); 428 | break; 429 | case Op: 430 | res = new koopa_raw_value_data(); 431 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 432 | res->name = nullptr; 433 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 434 | res->kind.tag = KOOPA_RVT_BINARY; 435 | auto &binary = res->kind.data.binary; 436 | if (op == "*") 437 | binary.op = KOOPA_RBO_MUL; 438 | else if (op == "/") 439 | binary.op = KOOPA_RBO_DIV; 440 | else if (op == "%") 441 | binary.op = KOOPA_RBO_MOD; 442 | binary.lhs = (koopa_raw_value_t)leftExp->build_koopa_values(); 443 | binary.rhs = (koopa_raw_value_t)rightExp->build_koopa_values(); 444 | block_maintainer.AddInst(res); 445 | break; 446 | } 447 | return res; 448 | } 449 | int CalcValue() const override 450 | { 451 | if (type == Primary) 452 | return leftExp->CalcValue(); 453 | int res = 0; 454 | if (op == "*") 455 | res = leftExp->CalcValue() * rightExp->CalcValue(); 456 | else if (op == "/") 457 | res = leftExp->CalcValue() / rightExp->CalcValue(); 458 | else if (op == "%") 459 | res = leftExp->CalcValue() % rightExp->CalcValue(); 460 | return res; 461 | } 462 | }; 463 | 464 | class AddExpAST : public BaseAST 465 | { 466 | public: 467 | enum 468 | { 469 | Primary, 470 | Op 471 | } type; 472 | std::string op; 473 | std::unique_ptr leftExp; // may be primary 474 | std::unique_ptr rightExp; 475 | 476 | AddExpAST(std::unique_ptr &_primary_exp) 477 | { 478 | type = Primary; 479 | leftExp = std::move(_primary_exp); 480 | } 481 | AddExpAST(std::unique_ptr &_left_exp, const char *_op, std::unique_ptr &_right_exp) 482 | { 483 | type = Op; 484 | leftExp = std::move(_left_exp); 485 | op = std::string(_op); 486 | rightExp = std::move(_right_exp); 487 | } 488 | 489 | void *build_koopa_values() const override 490 | { 491 | koopa_raw_value_data *res = nullptr; 492 | switch (type) 493 | { 494 | case Primary: 495 | res = (koopa_raw_value_data *)leftExp->build_koopa_values(); 496 | break; 497 | case Op: 498 | res = new koopa_raw_value_data(); 499 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 500 | res->name = nullptr; 501 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 502 | res->kind.tag = KOOPA_RVT_BINARY; 503 | auto &binary = res->kind.data.binary; 504 | if (op == "+") 505 | binary.op = KOOPA_RBO_ADD; 506 | else if (op == "-") 507 | binary.op = KOOPA_RBO_SUB; 508 | binary.lhs = (koopa_raw_value_t)leftExp->build_koopa_values(); 509 | binary.rhs = (koopa_raw_value_t)rightExp->build_koopa_values(); 510 | block_maintainer.AddInst(res); 511 | break; 512 | } 513 | return res; 514 | } 515 | int CalcValue() const override 516 | { 517 | if (type == Primary) 518 | return leftExp->CalcValue(); 519 | int res = 0; 520 | if (op == "+") 521 | res = leftExp->CalcValue() + rightExp->CalcValue(); 522 | else if (op == "-") 523 | res = leftExp->CalcValue() - rightExp->CalcValue(); 524 | return res; 525 | } 526 | }; 527 | 528 | class RelExpAST : public BaseAST 529 | { 530 | public: 531 | enum 532 | { 533 | Primary, 534 | Op 535 | } type; 536 | std::string op; 537 | std::unique_ptr leftExp; // may be primary 538 | std::unique_ptr rightExp; 539 | 540 | RelExpAST(std::unique_ptr &_primary_exp) 541 | { 542 | type = Primary; 543 | leftExp = std::move(_primary_exp); 544 | } 545 | RelExpAST(std::unique_ptr &_left_exp, const char *_op, std::unique_ptr &_right_exp) 546 | { 547 | type = Op; 548 | leftExp = std::move(_left_exp); 549 | op = std::string(_op); 550 | rightExp = std::move(_right_exp); 551 | } 552 | 553 | void *build_koopa_values() const override 554 | { 555 | koopa_raw_value_data *res = nullptr; 556 | switch (type) 557 | { 558 | case Primary: 559 | res = (koopa_raw_value_data *)leftExp->build_koopa_values(); 560 | break; 561 | case Op: 562 | res = new koopa_raw_value_data(); 563 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 564 | res->name = nullptr; 565 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 566 | res->kind.tag = KOOPA_RVT_BINARY; 567 | auto &binary = res->kind.data.binary; 568 | if (op == "<") 569 | binary.op = KOOPA_RBO_LT; 570 | else if (op == "<=") 571 | binary.op = KOOPA_RBO_LE; 572 | else if (op == ">") 573 | binary.op = KOOPA_RBO_GT; 574 | else if (op == ">=") 575 | binary.op = KOOPA_RBO_GE; 576 | binary.lhs = (koopa_raw_value_t)leftExp->build_koopa_values(); 577 | binary.rhs = (koopa_raw_value_t)rightExp->build_koopa_values(); 578 | block_maintainer.AddInst(res); 579 | break; 580 | } 581 | return res; 582 | } 583 | int CalcValue() const override 584 | { 585 | if (type == Primary) 586 | return leftExp->CalcValue(); 587 | int res = 0; 588 | if (op == "<") 589 | res = leftExp->CalcValue() < rightExp->CalcValue(); 590 | else if (op == "<=") 591 | res = leftExp->CalcValue() <= rightExp->CalcValue(); 592 | else if (op == ">") 593 | res = leftExp->CalcValue() > rightExp->CalcValue(); 594 | else if (op == ">=") 595 | res = leftExp->CalcValue() >= rightExp->CalcValue(); 596 | return res; 597 | } 598 | }; 599 | 600 | class EqExpAST : public BaseAST 601 | { 602 | public: 603 | enum 604 | { 605 | Primary, 606 | Op 607 | } type; 608 | std::string op; 609 | std::unique_ptr leftExp; // may be primary 610 | std::unique_ptr rightExp; 611 | 612 | EqExpAST(std::unique_ptr &_primary_exp) 613 | { 614 | type = Primary; 615 | leftExp = std::move(_primary_exp); 616 | } 617 | EqExpAST(std::unique_ptr &_left_exp, const char *_op, std::unique_ptr &_right_exp) 618 | { 619 | type = Op; 620 | leftExp = std::move(_left_exp); 621 | op = std::string(_op); 622 | rightExp = std::move(_right_exp); 623 | } 624 | 625 | void *build_koopa_values() const override 626 | { 627 | koopa_raw_value_data *res = nullptr; 628 | switch (type) 629 | { 630 | case Primary: 631 | res = (koopa_raw_value_data *)leftExp->build_koopa_values(); 632 | break; 633 | case Op: 634 | res = new koopa_raw_value_data(); 635 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 636 | res->name = nullptr; 637 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 638 | res->kind.tag = KOOPA_RVT_BINARY; 639 | auto &binary = res->kind.data.binary; 640 | if (op == "==") 641 | binary.op = KOOPA_RBO_EQ; 642 | else if (op == "!=") 643 | binary.op = KOOPA_RBO_NOT_EQ; 644 | binary.lhs = (koopa_raw_value_t)leftExp->build_koopa_values(); 645 | binary.rhs = (koopa_raw_value_t)rightExp->build_koopa_values(); 646 | block_maintainer.AddInst(res); 647 | break; 648 | } 649 | return res; 650 | } 651 | int CalcValue() const override 652 | { 653 | if (type == Primary) 654 | return leftExp->CalcValue(); 655 | int res = 0; 656 | if (op == "==") 657 | res = leftExp->CalcValue() == rightExp->CalcValue(); 658 | else if (op == "!=") 659 | res = leftExp->CalcValue() != rightExp->CalcValue(); 660 | return res; 661 | } 662 | }; 663 | 664 | class LAndExpAST : public BaseAST 665 | { 666 | koopa_raw_value_data *make_not_eq_koopa(koopa_raw_value_t exp) const 667 | { 668 | NumberAST zero(0); 669 | koopa_raw_value_data *res = new koopa_raw_value_data(); 670 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 671 | res->name = nullptr; 672 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 673 | res->kind.tag = KOOPA_RVT_BINARY; 674 | auto &binary = res->kind.data.binary; 675 | binary.op = KOOPA_RBO_NOT_EQ; 676 | binary.lhs = exp; 677 | binary.rhs = (koopa_raw_value_t)zero.build_koopa_values(); 678 | block_maintainer.AddInst(res); 679 | return res; 680 | } 681 | 682 | public: 683 | enum 684 | { 685 | Primary, 686 | Op 687 | } type; 688 | std::string op; 689 | std::unique_ptr leftExp; // may be primary 690 | std::unique_ptr rightExp; 691 | 692 | LAndExpAST(std::unique_ptr &_primary_exp) 693 | { 694 | type = Primary; 695 | leftExp = std::move(_primary_exp); 696 | } 697 | LAndExpAST(std::unique_ptr &_left_exp, const char *_op, std::unique_ptr &_right_exp) 698 | { 699 | type = Op; 700 | leftExp = std::move(_left_exp); 701 | op = std::string(_op); 702 | rightExp = std::move(_right_exp); 703 | } 704 | 705 | void *build_koopa_values() const override 706 | { 707 | std::unique_ptr zero(new NumberAST(0)); 708 | koopa_raw_value_data *res = nullptr; 709 | switch (type) 710 | { 711 | case Primary: 712 | res = (koopa_raw_value_data *)leftExp->build_koopa_values(); 713 | break; 714 | case Op: 715 | koopa_raw_value_data *temp_var = new koopa_raw_value_data(); 716 | temp_var->ty = make_int_pointer_type(); 717 | temp_var->name = new_char_arr("%temp"); 718 | temp_var->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 719 | temp_var->kind.tag = KOOPA_RVT_ALLOC; 720 | block_maintainer.AddInst(temp_var); 721 | 722 | koopa_raw_value_data *temp_store = new koopa_raw_value_data(); 723 | temp_store->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 724 | temp_store->name = nullptr; 725 | temp_store->used_by = empty_koopa_rs(); 726 | temp_store->kind.tag = KOOPA_RVT_STORE; 727 | temp_store->kind.data.store.dest = temp_var; 728 | temp_store->kind.data.store.value = (koopa_raw_value_t)zero->build_koopa_values(); 729 | block_maintainer.AddInst(temp_store); 730 | 731 | koopa_raw_value_data *br = new koopa_raw_value_data(); 732 | br->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 733 | br->name = nullptr; 734 | br->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 735 | br->kind.tag = KOOPA_RVT_BRANCH; 736 | br->kind.data.branch.cond = make_not_eq_koopa((koopa_raw_value_t)leftExp->build_koopa_values()); 737 | koopa_raw_basic_block_data_t *true_block = new koopa_raw_basic_block_data_t(); 738 | koopa_raw_basic_block_data_t *end_block = new koopa_raw_basic_block_data_t(); 739 | br->kind.data.branch.true_bb = true_block; 740 | br->kind.data.branch.false_bb = end_block; 741 | br->kind.data.branch.true_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 742 | br->kind.data.branch.false_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 743 | block_maintainer.AddInst(br); 744 | 745 | true_block->name = new_char_arr("%true"); 746 | true_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 747 | true_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 748 | block_maintainer.AddNewBasicBlock(true_block); 749 | 750 | koopa_raw_value_data *b_store = new koopa_raw_value_data(); 751 | b_store->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 752 | b_store->name = nullptr; 753 | b_store->used_by = empty_koopa_rs(); 754 | b_store->kind.tag = KOOPA_RVT_STORE; 755 | b_store->kind.data.store.dest = temp_var; 756 | b_store->kind.data.store.value = make_not_eq_koopa((koopa_raw_value_t)rightExp->build_koopa_values()); 757 | block_maintainer.AddInst(b_store); 758 | block_maintainer.AddInst(JumpInst(end_block)); 759 | 760 | end_block->name = new_char_arr("%end"); 761 | end_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 762 | end_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 763 | block_maintainer.AddNewBasicBlock(end_block); 764 | 765 | res = new koopa_raw_value_data(); 766 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 767 | res->name = nullptr; 768 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 769 | res->kind.tag = KOOPA_RVT_LOAD; 770 | res->kind.data.load.src = temp_var; 771 | block_maintainer.AddInst(res); 772 | 773 | break; 774 | } 775 | return res; 776 | } 777 | int CalcValue() const override 778 | { 779 | if (type == Primary) 780 | return leftExp->CalcValue(); 781 | int res = 0; 782 | if (op == "&&") 783 | res = leftExp->CalcValue() && rightExp->CalcValue(); 784 | return res; 785 | } 786 | }; 787 | 788 | class LOrExpAST : public BaseAST 789 | { 790 | koopa_raw_value_data *make_eq_koopa(koopa_raw_value_t exp) const 791 | { 792 | NumberAST zero(0); 793 | koopa_raw_value_data *res = new koopa_raw_value_data(); 794 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 795 | res->name = nullptr; 796 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 797 | res->kind.tag = KOOPA_RVT_BINARY; 798 | auto &binary = res->kind.data.binary; 799 | binary.op = KOOPA_RBO_EQ; 800 | binary.lhs = exp; 801 | binary.rhs = (koopa_raw_value_t)zero.build_koopa_values(); 802 | block_maintainer.AddInst(res); 803 | return res; 804 | } 805 | 806 | koopa_raw_value_data *make_not_eq_koopa(koopa_raw_value_t exp) const 807 | { 808 | NumberAST zero(0); 809 | koopa_raw_value_data *res = new koopa_raw_value_data(); 810 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 811 | res->name = nullptr; 812 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 813 | res->kind.tag = KOOPA_RVT_BINARY; 814 | auto &binary = res->kind.data.binary; 815 | binary.op = KOOPA_RBO_NOT_EQ; 816 | binary.lhs = exp; 817 | binary.rhs = (koopa_raw_value_t)zero.build_koopa_values(); 818 | block_maintainer.AddInst(res); 819 | return res; 820 | } 821 | 822 | public: 823 | enum 824 | { 825 | Primary, 826 | Op 827 | } type; 828 | std::string op; 829 | std::unique_ptr leftExp; // may be primary 830 | std::unique_ptr rightExp; 831 | 832 | LOrExpAST(std::unique_ptr &_primary_exp) 833 | { 834 | type = Primary; 835 | leftExp = std::move(_primary_exp); 836 | } 837 | LOrExpAST(std::unique_ptr &_left_exp, const char *_op, std::unique_ptr &_right_exp) 838 | { 839 | type = Op; 840 | leftExp = std::move(_left_exp); 841 | op = std::string(_op); 842 | rightExp = std::move(_right_exp); 843 | } 844 | 845 | void *build_koopa_values() const override 846 | { 847 | std::unique_ptr zero(new NumberAST(0)); 848 | std::unique_ptr one(new NumberAST(1)); 849 | koopa_raw_value_data *res = nullptr; 850 | switch (type) 851 | { 852 | case Primary: 853 | res = (koopa_raw_value_data *)leftExp->build_koopa_values(); 854 | break; 855 | case Op: 856 | koopa_raw_value_data *temp_var = new koopa_raw_value_data(); 857 | temp_var->ty = make_int_pointer_type(); 858 | temp_var->name = new_char_arr("%temp"); 859 | temp_var->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 860 | temp_var->kind.tag = KOOPA_RVT_ALLOC; 861 | block_maintainer.AddInst(temp_var); 862 | 863 | koopa_raw_value_data *temp_store = new koopa_raw_value_data(); 864 | temp_store->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 865 | temp_store->name = nullptr; 866 | temp_store->used_by = empty_koopa_rs(); 867 | temp_store->kind.tag = KOOPA_RVT_STORE; 868 | temp_store->kind.data.store.dest = temp_var; 869 | temp_store->kind.data.store.value = (koopa_raw_value_t)one->build_koopa_values(); 870 | block_maintainer.AddInst(temp_store); 871 | 872 | koopa_raw_value_data *br = new koopa_raw_value_data(); 873 | br->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 874 | br->name = nullptr; 875 | br->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 876 | br->kind.tag = KOOPA_RVT_BRANCH; 877 | br->kind.data.branch.cond = make_eq_koopa((koopa_raw_value_t)leftExp->build_koopa_values()); 878 | koopa_raw_basic_block_data_t *true_block = new koopa_raw_basic_block_data_t(); 879 | koopa_raw_basic_block_data_t *end_block = new koopa_raw_basic_block_data_t(); 880 | br->kind.data.branch.true_bb = true_block; 881 | br->kind.data.branch.false_bb = end_block; 882 | br->kind.data.branch.true_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 883 | br->kind.data.branch.false_args = empty_koopa_rs(KOOPA_RSIK_VALUE); 884 | block_maintainer.AddInst(br); 885 | 886 | true_block->name = new_char_arr("%true"); 887 | true_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 888 | true_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 889 | block_maintainer.AddNewBasicBlock(true_block); 890 | 891 | koopa_raw_value_data *b_store = new koopa_raw_value_data(); 892 | b_store->ty = simple_koopa_raw_type_kind(KOOPA_RTT_UNIT); 893 | b_store->name = nullptr; 894 | b_store->used_by = empty_koopa_rs(); 895 | b_store->kind.tag = KOOPA_RVT_STORE; 896 | b_store->kind.data.store.dest = temp_var; 897 | b_store->kind.data.store.value = make_not_eq_koopa((koopa_raw_value_t)rightExp->build_koopa_values()); 898 | block_maintainer.AddInst(b_store); 899 | block_maintainer.AddInst(JumpInst(end_block)); 900 | 901 | end_block->name = new_char_arr("%end"); 902 | end_block->params = empty_koopa_rs(KOOPA_RSIK_VALUE); 903 | end_block->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 904 | block_maintainer.AddNewBasicBlock(end_block); 905 | 906 | res = new koopa_raw_value_data(); 907 | res->ty = simple_koopa_raw_type_kind(KOOPA_RTT_INT32); 908 | res->name = nullptr; 909 | res->used_by = empty_koopa_rs(KOOPA_RSIK_VALUE); 910 | res->kind.tag = KOOPA_RVT_LOAD; 911 | res->kind.data.load.src = temp_var; 912 | block_maintainer.AddInst(res); 913 | 914 | break; 915 | } 916 | return res; 917 | } 918 | int CalcValue() const override 919 | { 920 | if (type == Primary) 921 | return leftExp->CalcValue(); 922 | int res = 0; 923 | if (op == "||") 924 | res = leftExp->CalcValue() || rightExp->CalcValue(); 925 | return res; 926 | } 927 | }; 928 | --------------------------------------------------------------------------------