diff --git a/compiler/CMakeLists.txt b/compiler/CMakeLists.txt new file mode 100644 index 0000000..fca04fa --- /dev/null +++ b/compiler/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.21) +option(BUILD_IR_TESTING "Build IR testing" OFF) + +project(CarrotCompiler VERSION 0.1 + DESCRIPTION "Simple compiler targeted RV64 for SysY Language" + LANGUAGES CXX) +# Common build options +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") +# set(BUILD_IR_TESTING true) + +# Generic includes +set(INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/include") +include_directories(${INCLUDE_DIRECTORIES}) + +# Compiler sources +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) +add_subdirectory(src) +add_subdirectory(runtime) + +# Unit tests +include(CTest) +if(BUILD_TESTING) + add_subdirectory(test) +endif(BUILD_TESTING) \ No newline at end of file diff --git a/compiler/cmake/LLVMIRTest.cmake b/compiler/cmake/LLVMIRTest.cmake new file mode 100644 index 0000000..f90523a --- /dev/null +++ b/compiler/cmake/LLVMIRTest.cmake @@ -0,0 +1,111 @@ +# arguments checking +if(NOT COMPILER) + message(FATAL_ERROR "Require COMPILER to be defined") +endif(NOT COMPILER) + +if(NOT RUNTIME) + message(FATAL_ERROR "Require RUNTIME to be defined") +endif(NOT RUNTIME) + +if(NOT TEST_DIR) + message(FATAL_ERROR "Require TEST_DIR to be defined") +endif(NOT TEST_DIR) + +if(NOT TEST_NAME) + message(FATAL_ERROR "Require TEST_NAME to be defined") +endif(NOT TEST_NAME) + +# Sources +set(TEST_SRC "${TEST_DIR}/${TEST_NAME}.sy") + +if(EXISTS "${TEST_DIR}/${TEST_NAME}.in") + set(TEST_INS "${TEST_DIR}/${TEST_NAME}.in") +else(EXISTS "${TEST_DIR}/${TEST_NAME}.in") + set(TEST_INS "/dev/null") +endif(EXISTS "${TEST_DIR}/${TEST_NAME}.in") + +set(RUNTIME_ASM "${RUNTIME}/sysy.ll") + +# Generated +set(TEST_ASM "${TEST_NAME}.ll") +set(TEST_BTC "${TEST_NAME}.bc") +set(TEST_OUT "${TEST_NAME}_ir.out") +configure_file("${TEST_DIR}/${TEST_NAME}.out" "${TEST_NAME}.ref" NEWLINE_STYLE LF) +set(TEST_REF "${TEST_NAME}.ref") + +# SysY to LLVM IR +execute_process( + COMMAND + ${COMPILER} -c ${TEST_SRC} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + OUTPUT_FILE ${TEST_ASM} + ERROR_VARIABLE TEST_ERR + RESULT_VARIABLE TEST_RET +) + +if(TEST_RET) + message(SEND_ERROR "Failed: SysY Compiler Error in ${TEST_SRC}: ${TEST_ERR}") + file(READ "${TEST_SRC}" TEST_SRC_CONTENT) + message(NOTICE "Source File:\n ${TEST_SRC_CONTENT}") + return() +endif(TEST_RET) + +# LLVM IR & Runtime link to BitCode +execute_process( + COMMAND + llvm-link "${RUNTIME_ASM}" "${CMAKE_CURRENT_BINARY_DIR}/${TEST_ASM}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + OUTPUT_FILE ${TEST_BTC} + ERROR_VARIABLE TEST_ERR + RESULT_VARIABLE TEST_RET +) + +if(TEST_RET) + message(SEND_ERROR "Failed: LLVM Link Error in ${TEST_SRC}: ${TEST_ERR}") + file(READ "${TEST_ERR}" TEST_ERR_CONTENT) + message(NOTICE "Generated Assmebly:\n ${TEST_ERR_CONTENT}") + return() +endif(TEST_RET) + +# Run BitCode with lli +execute_process( + COMMAND + lli ${TEST_BTC} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + INPUT_FILE ${TEST_INS} + OUTPUT_VARIABLE TEST_OUT_CONTENT + ERROR_VARIABLE TEST_ERR + RESULT_VARIABLE TEST_RET + TIMEOUT 10 +) + +# Append EOF LR, if not presented +if(TEST_OUT_CONTENT) + string(LENGTH "${TEST_OUT_CONTENT}" TEST_OUT_LEN) + math(EXPR TEST_OUT_LAST "${TEST_OUT_LEN} - 1") + string(SUBSTRING "${TEST_OUT_CONTENT}" ${TEST_OUT_LAST} 1 LAST_CHAR) + + if(NOT "${LAST_CHAR}" STREQUAL "\n") + # If it's not, append a newline to var + set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}\n") + endif() +endif(TEST_OUT_CONTENT) + +set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}${TEST_RET}\n") +file(WRITE "${TEST_OUT}" "${TEST_OUT_CONTENT}") + +execute_process( + COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUT}" "${TEST_REF}" + RESULT_VARIABLE TEST_RESULT +) + +if(TEST_RESULT) + # get_filename_component(TESTNAME "${TEST_ARGS}" NAME) + # file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out") + # file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR}) + message(SEND_ERROR "Failed: The output of ${TEST_NAME} did not match ${TEST_REF}") + file(READ ${TEST_REF} TEST_REF_CONTENT) + message(NOTICE "Expected Output: ${TEST_REF_CONTENT}") + message(NOTICE "Auctual Output: ${TEST_OUT_CONTENT}") + return() +endif(TEST_RESULT) \ No newline at end of file diff --git a/compiler/cmake/RISCVTest.cmake b/compiler/cmake/RISCVTest.cmake new file mode 100644 index 0000000..6f41ef7 --- /dev/null +++ b/compiler/cmake/RISCVTest.cmake @@ -0,0 +1,110 @@ +# arguments checking +if(NOT COMPILER) + message(FATAL_ERROR "Require COMPILER to be defined") +endif(NOT COMPILER) + +if(NOT RUNTIME) + message(FATAL_ERROR "Require RUNTIME to be defined") +endif(NOT RUNTIME) + +if(NOT TEST_DIR) + message(FATAL_ERROR "Require TEST_DIR to be defined") +endif(NOT TEST_DIR) + +if(NOT TEST_NAME) + message(FATAL_ERROR "Require TEST_NAME to be defined") +endif(NOT TEST_NAME) + +# Sources +set(TEST_SRC "${TEST_DIR}/${TEST_NAME}.sy") + +if(EXISTS "${TEST_DIR}/${TEST_NAME}.in") + set(TEST_INS "${TEST_DIR}/${TEST_NAME}.in") +else(EXISTS "${TEST_DIR}/${TEST_NAME}.in") + set(TEST_INS "/dev/null") +endif(EXISTS "${TEST_DIR}/${TEST_NAME}.in") + +set(RUNTIME_LIB "${RUNTIME}/libsysy.a") + +# Generated +set(TEST_ASM "${TEST_NAME}.s") +set(TEST_EXE "${TEST_NAME}") +set(TEST_OUT "${TEST_NAME}_rv.out") +configure_file("${TEST_DIR}/${TEST_NAME}.out" "${TEST_NAME}.ref" NEWLINE_STYLE LF) +set(TEST_REF "${TEST_NAME}.ref") + +# SysY to RISC-V Assembly +execute_process( + COMMAND + ${COMPILER} -S ${TEST_SRC} -O1 + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + OUTPUT_FILE ${TEST_ASM} + ERROR_VARIABLE TEST_ERR + RESULT_VARIABLE TEST_RET +) + +if(TEST_RET) + message(SEND_ERROR "Failed: SysY Compiler Error in ${TEST_SRC}: ${TEST_ERR}") + file(READ "${TEST_SRC}" TEST_SRC_CONTENT) + message(NOTICE "Source File:\n ${TEST_SRC_CONTENT}") + return() +endif(TEST_RET) + +# GCC Assemble and Link +execute_process( + COMMAND + riscv64-linux-gnu-gcc "${CMAKE_CURRENT_BINARY_DIR}/${TEST_ASM}" "${RUNTIME_LIB}" -march=rv64gc -static -o "${CMAKE_CURRENT_BINARY_DIR}/${TEST_EXE}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ERROR_VARIABLE TEST_ERR + RESULT_VARIABLE TEST_RET +) + +if(TEST_RET) + message(SEND_ERROR "Failed: GCC Assemble and Link Error in ${TEST_SRC}: ${TEST_ERR}") + # file(READ "${TEST_ASM}" TEST_ASM_CONTENT) + message(NOTICE "Generated Assmebly:\n ${TEST_ASM_CONTENT}") + return() +endif(TEST_RET) + +# Run the executable with qemu +execute_process( + COMMAND + qemu-riscv64 ${TEST_EXE} -M sifive_u -smp 5 -m 2G + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + INPUT_FILE ${TEST_INS} + OUTPUT_VARIABLE TEST_OUT_CONTENT + ERROR_VARIABLE TEST_ERR + RESULT_VARIABLE TEST_RET + TIMEOUT 60 +) + +# Append EOF LR, if not presented +if(TEST_OUT_CONTENT) + string(LENGTH "${TEST_OUT_CONTENT}" TEST_OUT_LEN) + math(EXPR TEST_OUT_LAST "${TEST_OUT_LEN} - 1") + string(SUBSTRING "${TEST_OUT_CONTENT}" ${TEST_OUT_LAST} 1 LAST_CHAR) + + if(NOT "${LAST_CHAR}" STREQUAL "\n") + # If it's not, append a newline to var + set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}\n") + endif() +endif(TEST_OUT_CONTENT) + +set(TEST_OUT_CONTENT "${TEST_OUT_CONTENT}${TEST_RET}\n") +file(WRITE "${TEST_OUT}" "${TEST_OUT_CONTENT}") + +execute_process( + COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUT}" "${TEST_REF}" + RESULT_VARIABLE TEST_RESULT +) + +if(TEST_RESULT) + # get_filename_component(TESTNAME "${TEST_ARGS}" NAME) + # file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out") + # file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR}) + message(SEND_ERROR "Failed: The output of ${TEST_NAME} did not match ${TEST_REF}") + file(READ ${TEST_REF} TEST_REF_CONTENT) + message(NOTICE "Expected Output: ${TEST_REF_CONTENT}") + message(NOTICE "Auctual Output: ${TEST_OUT_CONTENT}") + return() +endif(TEST_RESULT) \ No newline at end of file diff --git a/compiler/include/.gitkeep b/compiler/include/.gitkeep new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/compiler/include/.gitkeep @@ -0,0 +1 @@ + diff --git a/compiler/runtime/CMakeLists.txt b/compiler/runtime/CMakeLists.txt new file mode 100644 index 0000000..1808e9b --- /dev/null +++ b/compiler/runtime/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.21) + +project(SysYRuntime VERSION 1.0 + DESCRIPTION "SysY Language official runtime environment" + LANGUAGES C) + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_COMPILER "riscv64-unknown-elf-gcc") + +set(INCLUDE_DIRECTORY "${PROJECT_SOURCE_DIR}/include") +include_directories(${INCLUDE_DIRECTORY}) + +set(SOURCE_FILES "${PROJECT_SOURCE_DIR}/src/sylib.c") + +if(BUILD_IR_TESTING) + add_custom_target(sysy-ir ALL + COMMAND clang ${CMAKE_C_FLAGS} + -I ${INCLUDE_DIRECTORY} + -S -emit-llvm + ${SOURCE_FILES} + -o ${CMAKE_CURRENT_BINARY_DIR}/sysy.ll + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Compiling SysY Runtime Library to LLVM-IR" + SOURCES ${SOURCE_FILES}) +endif(BUILD_IR_TESTING) + +add_library(sysy STATIC ${SOURCE_FILES}) + +# target_compile_options(sysy PUBLIC ${CMAKE_C_FLAGS} -flto) +# target_compile_options(sysy PUBLIC ${CMAKE_C_FLAGS} -emit-llvm -S) +target_compile_options(sysy PRIVATE ${CMAKE_C_FLAGS} --verbose) diff --git a/compiler/runtime/include/sylib.h b/compiler/runtime/include/sylib.h new file mode 100644 index 0000000..de9066b --- /dev/null +++ b/compiler/runtime/include/sylib.h @@ -0,0 +1,31 @@ +#ifndef __SYLIB_H_ +#define __SYLIB_H_ + +#include +#include +#include +/* Input & output functions */ +int getint(),getch(),getarray(int a[]); +float getfloat(); +int getfarray(float a[]); + +void putint(int a),putch(int a),putarray(int n,int a[]); +void putfloat(float a); +void putfarray(int n, float a[]); + +void putf(char a[], ...); + +/* Timing function implementation */ +struct timeval _sysy_start,_sysy_end; +#define starttime() _sysy_starttime(__LINE__) +#define stoptime() _sysy_stoptime(__LINE__) +#define _SYSY_N 1024 +int _sysy_l1[_SYSY_N],_sysy_l2[_SYSY_N]; +int _sysy_h[_SYSY_N], _sysy_m[_SYSY_N],_sysy_s[_SYSY_N],_sysy_us[_SYSY_N]; +int _sysy_idx; +__attribute((constructor)) void before_main(); +__attribute((destructor)) void after_main(); +void _sysy_starttime(int lineno); +void _sysy_stoptime(int lineno); + +#endif diff --git a/compiler/runtime/src/sylib.c b/compiler/runtime/src/sylib.c new file mode 100644 index 0000000..dc3d92c --- /dev/null +++ b/compiler/runtime/src/sylib.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include"sylib.h" +/* Input & output functions */ +int getint(){int t; scanf("%d",&t); return t; } +int getch(){char c; scanf("%c",&c); return (int)c; } +float getfloat(){ + float n; + scanf("%a", &n); + return n; +} + +int getarray(int a[]){ + int n; + scanf("%d",&n); + for(int i=0;iint32_ty_, num) +#define CONST_FLOAT(num) new ConstantFloat(module->float32_ty_, num) +#define VOID_T (module->void_ty_) +#define INT1_T (module->int1_ty_) +#define INT32_T (module->int32_ty_) +#define FLOAT_T (module->float32_ty_) +#define INT32PTR_T (module->get_pointer_type(module->int32_ty_)) +#define FLOATPTR_T (module->get_pointer_type(module->float32_ty_)) + +// store temporary value +Type *curType; // 当前decl类型 +bool isConst; // 当前decl是否是const +bool useConst = false; // 计算是否使用常量 +std::vector params; // 函数形参类型表 +std::vector paramNames; // 函数形参名表 +Value *retAlloca = nullptr; // 返回值 +BasicBlock *retBB = nullptr; // 返回语句块 +bool isNewFunc = false; // 判断是否为新函数,用来处理函数作用域问题 +bool requireLVal = false; // 告诉LVal节点不需要发射load指令 +Function *currentFunction = nullptr; // 当前函数 +Value *recentVal = nullptr; // 最近的表达式的value +BasicBlock *functionBB = nullptr; // To Fix the bug: current function's basic block +BasicBlock *whileCondBB = nullptr; // while语句cond分支 +BasicBlock *trueBB = nullptr; // 通用true分支,即while和if为真时所跳转的基本块 +BasicBlock *falseBB = nullptr; // 通用false分支,即while和if为假时所跳转的基本块 +BasicBlock *whileFalseBB; // while语句false分支,用于break跳转 +int id = 1; // recent标号 +bool has_br = false; // 一个BB中是否已经出现了br +bool is_single_exp = false; // 作为单独的exp语句出现,形如 "exp;" + +// 判断得到的赋值与声明类型是否一致,并做转换 +void GenIR::checkInitType() const { + if (curType == INT32_T) { + if (dynamic_cast(recentVal)) { + auto temp = dynamic_cast(recentVal); + recentVal = CONST_INT((int)temp->value_); + } else if (recentVal->type_->tid_ == Type::FloatTyID) { + recentVal = builder->create_fptosi(recentVal, INT32_T); + } + } else if (curType == FLOAT_T) { + if (dynamic_cast(recentVal)) { + auto temp = dynamic_cast(recentVal); + recentVal = CONST_FLOAT(temp->value_); + } else if (recentVal->type_->tid_ == Type::IntegerTyID) { + recentVal = builder->create_sitofp(recentVal, FLOAT_T); + } + } +} + +void GenIR::visit(CompUnitAST &ast) { + for (const auto &def : ast.declDefList) { + def->accept(*this); + } +} + +void GenIR::visit(DeclDefAST &ast) { + if (ast.Decl != nullptr) { + ast.Decl->accept(*this); + } else { + ast.funcDef->accept(*this); + } +} + +void GenIR::visit(DeclAST &ast) { + isConst = ast.isConst; + curType = ast.bType == TYPE_INT ? INT32_T : FLOAT_T; + for (auto &def : ast.defList) { + def->accept(*this); + } +} + +void GenIR::visit(DefAST &ast) { + string varName = *ast.id; + // 全局变量或常量 + if (scope.in_global()) { + if (ast.arrays.empty()) { // 不是数组,即全局量 + if (ast.initVal == nullptr) { // 无初始化 + if (isConst) + cout << "no initVal when define const!" + << endl; // 无初始化全局常量报错 + // 无初始化全局量一定是变量 + GlobalVariable *var; + if (curType == INT32_T) + var = new GlobalVariable(varName, module.get(), curType, false, + CONST_INT(0)); + else + var = new GlobalVariable(varName, module.get(), curType, false, + CONST_FLOAT(0)); + scope.push(varName, var); + } else { // 有初始化 + useConst = true; + ast.initVal->accept(*this); + useConst = false; + checkInitType(); + if (isConst) { + scope.push(varName, recentVal); // 单个常量定义不用new GlobalVariable + } else { // 全局变量 + auto initializer = static_cast(recentVal); + GlobalVariable *var; + var = new GlobalVariable(varName, module.get(), curType, false, + initializer); + scope.push(varName, var); + } + } + } else { // 是数组,即全局数组量 + vector dimensions; // 数组各维度; [2][3][4]对应 + useConst = true; + // 获取数组各维度 + for (auto &exp : ast.arrays) { + exp->accept(*this); + int dimension = dynamic_cast(recentVal)->value_; + dimensions.push_back(dimension); + } + useConst = false; + vector arrayTys( + dimensions.size()); // 数组类型, {[2 x [3 x [4 x i32]]], [3 x [4 x + // i32]], [4 x i32]} + for (int i = dimensions.size() - 1; i >= 0; i--) { + if (i == dimensions.size() - 1) + arrayTys[i] = module->get_array_type(curType, dimensions[i]); + else + arrayTys[i] = module->get_array_type(arrayTys[i + 1], dimensions[i]); + } + // 无初始化或者初始化仅为大括号 + if (ast.initVal == nullptr || ast.initVal->initValList.empty()) { + auto init = new ConstantZero(arrayTys[0]); + auto var = new GlobalVariable(varName, module.get(), arrayTys[0], + isConst, init); + scope.push(varName, var); + } else { + useConst = true; // 全局数组量的初始值必为常量 + auto init = + globalInit(dimensions, arrayTys, 0, ast.initVal->initValList); + useConst = false; + auto var = new GlobalVariable(varName, module.get(), arrayTys[0], + isConst, init); + scope.push(varName, var); + } + } + return; + } + + // TODO: 修复在循环中多次分配同名变量的Bug + // 局部变量或常量 + if (ast.arrays.empty()) { // 不是数组,即普通局部量 + if (ast.initVal == nullptr) { // 无初始化 + if (isConst) + cout << "no initVal when define const!" << endl; // 无初始化局部常量报错 + else { // 无初始化变量 + auto _backupBB = builder->get_insert_block(); + builder->set_insert_point(functionBB); // 将局部变量移动至当前函数头部的 Basic block + AllocaInst *varAlloca; + varAlloca = builder->create_alloca(curType); + builder->set_insert_point(_backupBB); // 还原插入点 + scope.push(varName, varAlloca); + } + } else { // 有初始化 + ast.initVal->accept(*this); + checkInitType(); + if (isConst) { + scope.push(varName, recentVal); // 单个常量定义不用create_alloca + } else { + auto _backupBB = builder->get_insert_block(); + builder->set_insert_point(functionBB); + AllocaInst *varAlloca; + varAlloca = builder->create_alloca(curType); + builder->set_insert_point(_backupBB); + scope.push(varName, varAlloca); + builder->create_store(recentVal, varAlloca); + } + } + } else { // 局部数组量 + vector dimensions(ast.arrays.size()), + dimensionsCnt((ast.arrays.size())); // 数组各维度, [2][3][4]对应; + // 次维度数组元素个数, [24][12][4] + int totalByte = 1; // 存储总共的字节数 + useConst = true; + // 获取数组各维度 + for (int i = dimensions.size() - 1; i >= 0; i--) { + ast.arrays[i]->accept(*this); + int dimension = dynamic_cast(recentVal)->value_; + totalByte *= dimension; + dimensions[i] = dimension; + dimensionsCnt[i] = totalByte; + } + totalByte *= 4; // 计算字节数 + useConst = false; + ArrayType *arrayTy = nullptr; // 数组类型 + for (int i = dimensions.size() - 1; i >= 0; i--) { + if (i == dimensions.size() - 1) + arrayTy = module->get_array_type(curType, dimensions[i]); + else + arrayTy = module->get_array_type(arrayTy, dimensions[i]); + } + auto arrayAlloc = builder->create_alloca(arrayTy); + scope.push(varName, arrayAlloc); + if (ast.initVal == nullptr) { // 无初始化 + if (isConst) + cout << "no initVal when define const!" << endl; // 无初始化局部常量报错 + return; // 无初始化变量数组无需再做处理 + } + Value *i32P = builder->create_bitcast(arrayAlloc, INT32PTR_T); + auto memclr = scope.find("memclr"); + builder->create_call( + memclr, {i32P, CONST_INT(totalByte)}); // 全部清零,但float可以清零吗 + // 数组初始化时,成员exp一定是空,若initValList也是空,即是大括号,已经置零了直接返回 + if (ast.initVal->initValList.empty()) + return; + vector idxs(dimensions.size() + 1); + for (int i = 0; i < dimensions.size() + 1; i++) { + idxs[i] = CONST_INT(0); + } + Value *ptr = builder->create_gep(arrayAlloc, idxs); // 获取数组开头地址 + localInit(ptr, ast.initVal->initValList, dimensionsCnt, 1); + } +} + +// 嵌套大括号数组的维度,即倒数连续0的第一个。 +// 如[0,1,0,0],返回2;[0,0,0,1],返回4; 若全是0,[0,0,0,0],返回1 +int GenIR::getNextDim(vector &elementsCnts, int up) { + for (int i = elementsCnts.size() - 1; i > up; i--) { + if (elementsCnts[i] != 0) + return i + 1; + } + return up + 1; +} + +// 增加元素后,合并所有能合并的数组元素,即对齐 +void GenIR::mergeElements(vector &dimensions, + vector &arrayTys, int up, int dimAdd, + vector &elements, + vector &elementsCnts) { + for (int i = dimAdd; i > up; i--) { + if (elementsCnts[i] % dimensions[i] == 0) { + vector temp; + temp.assign(elements.end() - dimensions[i], elements.end()); + elements.erase(elements.end() - dimensions[i], elements.end()); + elements.push_back(new ConstantArray(arrayTys[i], temp)); + elementsCnts[i] = 0; + elementsCnts[i - 1]++; + } else + break; + } +} + +// 最后合并所有元素,不足合并则填0元素,使得elements只剩下一个arrayTys[up]类型的最终数组 +void GenIR::finalMerge(vector &dimensions, vector &arrayTys, + int up, vector &elements, + vector &elementsCnts) const { + for (int i = dimensions.size() - 1; i >= up; i--) { + while (elementsCnts[i] % dimensions[i] != 0) { // 补充当前数组类型所需0元素 + if (i == dimensions.size() - 1) { + if (curType == INT32_T) { + elements.push_back(CONST_INT(0)); + } else { + elements.push_back(CONST_FLOAT(0)); + } + } else { + elements.push_back(new ConstantZero(arrayTys[i + 1])); + } + elementsCnts[i]++; + } + if (elementsCnts[i] != 0) { + vector temp; + temp.assign(elements.end() - dimensions[i], elements.end()); + elements.erase(elements.end() - dimensions[i], elements.end()); + elements.push_back(new ConstantArray(arrayTys[i], temp)); + elementsCnts[i] = 0; + if (i != up) + elementsCnts[i - 1]++; + } + } +} + +// 生成变量数组的初始化 +ConstantArray *GenIR::globalInit(vector &dimensions, + vector &arrayTys, int up, + vector> &list) { + vector elementsCnts(dimensions.size()); // 对应各个维度的子数组的元素个数 + vector elements; // 各个元素 + int dimAdd; + for (auto &val : list) { + if (val->exp != nullptr) { + dimAdd = dimensions.size() - 1; + val->exp->accept(*this); + checkInitType(); + elements.push_back((ConstantInt *)recentVal); + } else { + auto nextUp = getNextDim(elementsCnts, up); // 该嵌套数组的维度 + dimAdd = nextUp - 1; // 比他高一维度的数组需要添加一个元素 + if (nextUp == dimensions.size()) + cout << "initial invalid" << endl; // 没有连续0,没对齐,不合法 + if (val->initValList.empty()) { + elements.push_back(new ConstantZero(arrayTys[nextUp])); + } else { + auto temp = globalInit(dimensions, arrayTys, nextUp, val->initValList); + elements.push_back(temp); + } + } + elementsCnts[dimAdd]++; + mergeElements(dimensions, arrayTys, up, dimAdd, elements, elementsCnts); + } + finalMerge(dimensions, arrayTys, up, elements, elementsCnts); + return static_cast(elements[0]); +} + +// 根据初始化的量决定嵌套数组的维度 +int GenIR::getNextDim(vector &dimensionsCnt, int up, int cnt) { + for (int i = up; i < dimensionsCnt.size(); i++) { + if (cnt % dimensionsCnt[i] == 0) + return i; + } + return 0; +} + +// 根据首指针递归初始化数组,up表示子数组的最高对齐位置,比如[4][2][4],子数组最高对齐[2][4],up为1 +void GenIR::localInit(Value *ptr, vector> &list, + vector &dimensionsCnt, int up) { + int cnt = 0; + Value *tempPtr = ptr; + for (auto &initVal : list) { + if (initVal->exp) { + if (cnt == 0) + cnt++; // 第一次赋值时可以少一次create_gep + else + tempPtr = builder->create_gep(ptr, {CONST_INT(cnt++)}); + initVal->exp->accept(*this); + checkInitType(); + builder->create_store(recentVal, tempPtr); + } else { + auto nextUp = getNextDim(dimensionsCnt, up, cnt); + if (nextUp == 0) + cout << "initial invalid!" << endl; + if (!initVal->initValList.empty()) { + if (cnt != 0) + tempPtr = builder->create_gep( + ptr, {CONST_INT(cnt)}); // 没赋值过,那tempPtr实际就是ptr + localInit(tempPtr, initVal->initValList, dimensionsCnt, nextUp); + } + cnt += dimensionsCnt[nextUp]; // 数组初始化量一定增加这么多 + } + } +} + +void GenIR::visit(InitValAST &ast) { + // 不是数组则求exp的值,若是数组不会进入此函数 + if (ast.exp != nullptr) { + ast.exp->accept(*this); + } +} + +void GenIR::visit(FuncDefAST &ast) { + isNewFunc = true; + params.clear(); + paramNames.clear(); + Type *retType; + if (ast.funcType == TYPE_INT) + retType = INT32_T; + else if (ast.funcType == TYPE_FLOAT) + retType = FLOAT_T; + else + retType = VOID_T; + + // 获取参数列表 + for (auto &funcFParam : ast.funcFParamList) { + funcFParam->accept(*this); + } + // 获取函数类型 + auto funTy = new FunctionType(retType, params); + // 添加函数 + auto func = new Function(funTy, *ast.id, module.get()); + currentFunction = func; + scope.push(*ast.id, func); // 在进入新的作用域之前添加到符号表中 + // 进入函数(进入新的作用域) + scope.enter(); + + std::vector args; // 获取函数的形参,通过Function中的iterator + for (auto arg = func->arguments_.begin(); arg != func->arguments_.end(); + arg++) + args.push_back(*arg); + + auto bb = new BasicBlock(module.get(), "label_entry", func); + builder->BB_ = bb; + functionBB = bb; + for (int i = 0; i < (int)(paramNames.size()); i++) { + auto alloc = builder->create_alloca(params[i]); // 分配形参空间 + builder->create_store(args[i], alloc); // store 形参 + scope.push(paramNames[i], alloc); // 加入作用域 + } + // 创建统一return分支 + retBB = new BasicBlock(module.get(), "label_ret", func); + if (retType == VOID_T) { + // void类型无需返回值 + builder->BB_ = retBB; + builder->create_void_ret(); + } else { + retAlloca = builder->create_alloca(retType); // 在内存中分配返回值的位置 + builder->BB_ = retBB; + auto retLoad = builder->create_load(retAlloca); + builder->create_ret(retLoad); + } + // 重新回到函数开始 + builder->BB_ = bb; + has_br = false; + ast.block->accept(*this); + + // 处理没有return的空块 + if (!builder->BB_->get_terminator()) + builder->create_br(retBB); +} + +void GenIR::visit(FuncFParamAST &ast) { + // 获取参数类型 + Type *paramType; + if (ast.bType == TYPE_INT) + paramType = INT32_T; + else + paramType = FLOAT_T; + // 是否为数组 + if (ast.isArray) { + useConst = true; // 数组维度是整型常量 + for (int i = ast.arrays.size() - 1; i >= 0; i--) { + ast.arrays[i]->accept(*this); + paramType = + module->get_array_type(paramType, ((ConstantInt *)recentVal)->value_); + } + useConst = false; + // 如int a[][2],则参数为[2 x i32]* ; int a[],参数为i32 * + paramType = module->get_pointer_type(paramType); + } + params.push_back(paramType); + paramNames.push_back(*ast.id); +} + +void GenIR::visit(BlockAST &ast) { + // 如果是一个新的函数,则不用再进入一个新的作用域 + if (isNewFunc) + isNewFunc = false; + // 其它情况,需要进入一个新的作用域 + else { + scope.enter(); + } + // 遍历每一个语句块 + for (auto &item : ast.blockItemList) { + if (has_br) + break; // 此BB已经出现了br,后续指令无效 + item->accept(*this); + } + + scope.exit(); +} + +void GenIR::visit(BlockItemAST &ast) { + if (ast.decl != nullptr) { + ast.decl->accept(*this); + } else { + ast.stmt->accept(*this); + } +} + +void GenIR::visit(StmtAST &ast) { + switch (ast.sType) { + case SEMI: + break; + case ASS: { + // Init lVal state + requireLVal = true; + // Visit lVal + ast.lVal->accept(*this); + // Get lVal + auto lVal = recentVal; + auto lValType = static_cast(lVal->type_)->contained_; + // Visit expression + ast.exp->accept(*this); + auto rVal = recentVal; + // if lVal.type != rVal.type + // Forge a cast + if (lValType != recentVal->type_) { + if (lValType == FLOAT_T) { + rVal = builder->create_sitofp(recentVal, FLOAT_T); + } else { + rVal = builder->create_fptosi(recentVal, INT32_T); + } + } + // Create a store primitive + builder->create_store(rVal, lVal); + break; + } + case EXP: + is_single_exp = true; + ast.exp->accept(*this); + is_single_exp = false; + break; + case CONT: + builder->create_br(whileCondBB); + has_br = true; + break; + case BRE: + builder->create_br(whileFalseBB); + has_br = true; + break; + case RET: + ast.returnStmt->accept(*this); + break; + case BLK: + ast.block->accept(*this); + break; + case SEL: + ast.selectStmt->accept(*this); + break; + case ITER: + ast.iterationStmt->accept(*this); + break; + } +} + +void GenIR::visit(ReturnStmtAST &ast) { + if (ast.exp == nullptr) { + recentVal = builder->create_br(retBB); + } else { + // 先把返回值store在retAlloca中,再跳转到统一的返回入口 + ast.exp->accept(*this); + // 类型转换 + if (recentVal->type_ == FLOAT_T && + currentFunction->get_return_type() == INT32_T) { + auto temp = builder->create_fptosi(recentVal, INT32_T); + builder->create_store(temp, retAlloca); + } else if (recentVal->type_ == INT32_T && + currentFunction->get_return_type() == FLOAT_T) { + auto temp = builder->create_sitofp(recentVal, FLOAT_T); + builder->create_store(temp, retAlloca); + } else + builder->create_store(recentVal, retAlloca); + recentVal = builder->create_br(retBB); + } + has_br = true; + // builder->BB_ = new BasicBlock(module.get(), to_string(id++), + // currentFunction); //return语句后必是新块 +} + +void GenIR::visit(SelectStmtAST &ast) { + // 先保存trueBB和falseBB,防止嵌套导致返回上一层后丢失块的地址 + auto tempTrue = trueBB; + auto tempFalse = falseBB; + + trueBB = new BasicBlock(module.get(), to_string(id++), currentFunction); + falseBB = new BasicBlock(module.get(), to_string(id++), currentFunction); + BasicBlock *nextIf; // if语句后的基本块 + if (ast.elseStmt == nullptr) + nextIf = falseBB; + else + nextIf = new BasicBlock(module.get(), to_string(id++), currentFunction); + ast.cond->accept(*this); + // 检查是否是i1,不是则进行比较 + if (recentVal->type_ == INT32_T) { + recentVal = builder->create_icmp_ne(recentVal, CONST_INT(0)); + } else if (recentVal->type_ == FLOAT_T) { + recentVal = builder->create_fcmp_ne(recentVal, CONST_FLOAT(0)); + } + builder->create_cond_br(recentVal, trueBB, falseBB); + + builder->BB_ = trueBB; // 开始构建trueBB + has_br = false; + ast.ifStmt->accept(*this); + if (!builder->BB_->get_terminator()) { + builder->create_br(nextIf); + } + + if (ast.elseStmt != nullptr) { // 开始构建falseBB + builder->BB_ = falseBB; + has_br = false; + ast.elseStmt->accept(*this); + if (!builder->BB_->get_terminator()) { + builder->create_br(nextIf); + } + } + + builder->BB_ = nextIf; + has_br = false; + // 还原trueBB和falseBB + trueBB = tempTrue; + falseBB = tempFalse; +} + +void GenIR::visit(IterationStmtAST &ast) { + // 先保存trueBB和falseBB,防止嵌套导致返回上一层后丢失块的地址 + auto tempTrue = trueBB; + auto tempFalse = falseBB; // 即while的next block + auto tempCond = whileCondBB; + auto tempWhileFalseBB = + whileFalseBB; // break只跳while的false,而不跳全局false + + whileCondBB = new BasicBlock(module.get(), to_string(id++), currentFunction); + trueBB = new BasicBlock(module.get(), to_string(id++), currentFunction); + falseBB = new BasicBlock(module.get(), to_string(id++), currentFunction); + whileFalseBB = falseBB; + + builder->create_br(whileCondBB); + builder->BB_ = whileCondBB; // 条件也是一个基本块 + has_br = false; + ast.cond->accept(*this); + if (recentVal->type_ == INT32_T) { + recentVal = builder->create_icmp_ne(recentVal, CONST_INT(0)); + } else if (recentVal->type_ == FLOAT_T) { + recentVal = builder->create_fcmp_ne(recentVal, CONST_FLOAT(0.0)); + } + builder->create_cond_br(recentVal, trueBB, falseBB); + + builder->BB_ = trueBB; + has_br = false; + ast.stmt->accept(*this); + // while语句体一定是跳回cond + if (!builder->BB_->get_terminator()) { + builder->create_br(whileCondBB); + } + + builder->BB_ = falseBB; + has_br = false; + + // 还原trueBB,falseBB,tempCond + trueBB = tempTrue; + falseBB = tempFalse; + whileCondBB = tempCond; + whileFalseBB = tempWhileFalseBB; +} + +// 根据待计算的两个Constant的类型,求出对应的值赋值到intVal,floatVal中,返回计算结果是否为int +bool GenIR::checkCalType(Value *val[], int intVal[], float floatVal[]) { + bool resultIsInt = false; + if (dynamic_cast(val[0]) && + dynamic_cast(val[1])) { + resultIsInt = true; + intVal[0] = dynamic_cast(val[0])->value_; + intVal[1] = dynamic_cast(val[1])->value_; + } else { // 操作结果一定是float + if (dynamic_cast(val[0])) + floatVal[0] = dynamic_cast(val[0])->value_; + else + floatVal[0] = dynamic_cast(val[0])->value_; + if (dynamic_cast(val[1])) + floatVal[1] = dynamic_cast(val[1])->value_; + else + floatVal[1] = dynamic_cast(val[1])->value_; + } + return resultIsInt; +} + +// 根据待计算的两个寄存器数的类型,若需要转换类型输出转换指令 +void GenIR::checkCalType(Value *val[]) { + if (val[0]->type_ == INT1_T) { + val[0] = builder->create_zext(val[0], INT32_T); + } + if (val[1]->type_ == INT1_T) { + val[1] = builder->create_zext(val[1], INT32_T); + } + if (val[0]->type_ == INT32_T && val[1]->type_ == FLOAT_T) { + val[0] = builder->create_sitofp(val[0], FLOAT_T); + } + if (val[1]->type_ == INT32_T && val[0]->type_ == FLOAT_T) { + val[1] = builder->create_sitofp(val[1], FLOAT_T); + } +} + +void GenIR::visit(AddExpAST &ast) { + if (ast.addExp == nullptr) { + ast.mulExp->accept(*this); + return; + } + + Value *val[2]; // lVal, rVal + ast.addExp->accept(*this); + val[0] = recentVal; + ast.mulExp->accept(*this); + val[1] = recentVal; + + // 若都是常量 + if (useConst) { + int intVal[3]; // lInt, rInt, relInt; + float floatVal[3]; // lFloat, rFloat, relFloat; + bool resultIsInt = checkCalType(val, intVal, floatVal); + switch (ast.op) { + case AOP_ADD: + intVal[2] = intVal[0] + intVal[1]; + floatVal[2] = floatVal[0] + floatVal[1]; + break; + case AOP_MINUS: + intVal[2] = intVal[0] - intVal[1]; + floatVal[2] = floatVal[0] - floatVal[1]; + break; + } + if (resultIsInt) + recentVal = CONST_INT(intVal[2]); + else + recentVal = CONST_FLOAT(floatVal[2]); + return; + } + + // 若不是常量,进行计算,输出指令 + checkCalType(val); + if (val[0]->type_ == INT32_T) { + switch (ast.op) { + case AOP_ADD: + recentVal = builder->create_iadd(val[0], val[1]); + break; + case AOP_MINUS: + recentVal = builder->create_isub(val[0], val[1]); + break; + } + } else { + switch (ast.op) { + case AOP_ADD: + recentVal = builder->create_fadd(val[0], val[1]); + break; + case AOP_MINUS: + recentVal = builder->create_fsub(val[0], val[1]); + break; + } + } +} + +void GenIR::visit(MulExpAST &ast) { + if (ast.mulExp == nullptr) { + ast.unaryExp->accept(*this); + return; + } + + Value *val[2]; // lVal, rVal + ast.mulExp->accept(*this); + val[0] = recentVal; + ast.unaryExp->accept(*this); + val[1] = recentVal; + + // 若都是常量 + if (useConst) { + int intVal[3]; // lInt, rInt, relInt; + float floatVal[3]; // lFloat, rFloat, relFloat; + bool resultIsInt = checkCalType(val, intVal, floatVal); + switch (ast.op) { + case MOP_MUL: + intVal[2] = intVal[0] * intVal[1]; + floatVal[2] = floatVal[0] * floatVal[1]; + break; + case MOP_DIV: + intVal[2] = intVal[0] / intVal[1]; + floatVal[2] = floatVal[0] / floatVal[1]; + break; + case MOP_MOD: + intVal[2] = intVal[0] % intVal[1]; + break; + } + if (resultIsInt) + recentVal = CONST_INT(intVal[2]); + else + recentVal = CONST_FLOAT(floatVal[2]); + return; + } + + // 若不是常量,进行计算,输出指令 + checkCalType(val); + if (val[0]->type_ == INT32_T) { + switch (ast.op) { + case MOP_MUL: + recentVal = builder->create_imul(val[0], val[1]); + break; + case MOP_DIV: + recentVal = builder->create_isdiv(val[0], val[1]); + break; + case MOP_MOD: + recentVal = builder->create_isrem(val[0], val[1]); + break; + } + } else { + switch (ast.op) { + case MOP_MUL: + recentVal = builder->create_fmul(val[0], val[1]); + break; + case MOP_DIV: + recentVal = builder->create_fdiv(val[0], val[1]); + break; + case MOP_MOD: // never occur + break; + } + } +} + +void GenIR::visit(UnaryExpAST &ast) { + // 为常量算式 + if (useConst) { + if (ast.primaryExp) { + ast.primaryExp->accept(*this); + } else if (ast.unaryExp) { + ast.unaryExp->accept(*this); + if (ast.op == UOP_MINUS) { + // 是整型常量 + if (dynamic_cast(recentVal)) { + auto temp = (ConstantInt *)recentVal; + temp->value_ = -temp->value_; + recentVal = temp; + } else { + auto temp = (ConstantFloat *)recentVal; + temp->value_ = -temp->value_; + recentVal = temp; + } + } + } else { + cout << "Function call in ConstExp!" << endl; + } + return; + } + + // 不是常量算式 + if (ast.primaryExp != nullptr) { + ast.primaryExp->accept(*this); + } else if (ast.call != nullptr) { + ast.call->accept(*this); + } else { + ast.unaryExp->accept(*this); + if (recentVal->type_ == VOID_T) + return; + else if (recentVal->type_ == INT1_T) // INT1-->INT32 + recentVal = builder->create_zext(recentVal, INT32_T); + + if (recentVal->type_ == INT32_T) { + switch (ast.op) { + case UOP_MINUS: + recentVal = builder->create_isub(CONST_INT(0), recentVal); + break; + case UOP_NOT: + recentVal = builder->create_icmp_eq(recentVal, CONST_INT(0)); + break; + case UOP_ADD: + break; + } + } else { + switch (ast.op) { + case UOP_MINUS: + recentVal = builder->create_fsub(CONST_FLOAT(0), recentVal); + break; + case UOP_NOT: + recentVal = builder->create_fcmp_eq(recentVal, CONST_FLOAT(0)); + break; + case UOP_ADD: + break; + } + } + } +} + +void GenIR::visit(PrimaryExpAST &ast) { + if (ast.exp) { + ast.exp->accept(*this); + } else if (ast.lval) { + ast.lval->accept(*this); + } else if (ast.number) { + ast.number->accept(*this); + } +} + +void GenIR::visit(LValAST &ast) { + bool isTrueLVal = requireLVal; // 是否真是作为左值 + requireLVal = false; + auto var = scope.find(*ast.id); + // 全局作用域内,一定使用常量,全局作用域下访问到LValAST,那么use_const一定被置为了true + if (scope.in_global()) { + // 不是数组,直接返回该常量 + if (ast.arrays.empty()) { + recentVal = var; + return; + } + // 若是数组,则var一定是全局常量数组 + vector index; + for (auto &exp : ast.arrays) { + exp->accept(*this); + index.push_back(dynamic_cast(recentVal)->value_); + } + recentVal = + ((GlobalVariable *)var)->init_val_; // 使用var的初始化数组查找常量元素 + for (int i : index) { + // 某数组元素为ConstantZero,则该数一定是0 + if (dynamic_cast(recentVal)) { + Type *arrayTy = recentVal->type_; + // 找数组元素标签 + while (dynamic_cast(arrayTy)) { + arrayTy = dynamic_cast(arrayTy)->contained_; + } + if (arrayTy == INT32_T) + recentVal = CONST_INT(0); + else + recentVal = CONST_FLOAT(0); + return; + } + if (dynamic_cast(recentVal)) { + recentVal = ((ConstantArray *)recentVal)->const_array[i]; + } + } + return; + } + + // 局部作用域 + if (var->type_->tid_ == Type::IntegerTyID || + var->type_->tid_ == Type::FloatTyID) { // 说明为局部常量 + recentVal = var; + return; + } + // 不是常量那么var一定是指针类型 + Type *varType = + static_cast(var->type_)->contained_; // 所指的类型 + if (!ast.arrays.empty()) { // 说明是数组 + vector idxs; + for (auto &exp : ast.arrays) { + exp->accept(*this); + idxs.push_back(recentVal); + } + // 当函数传入参数i32 *,会生成类型为i32 **的局部变量,即此情况 + if (varType->tid_ == Type::PointerTyID) { + var = builder->create_load(var); + } else if (varType->tid_ == Type::ArrayTyID) { + idxs.insert(idxs.begin(), CONST_INT(0)); + } + var = builder->create_gep(var, idxs); // 获取的一定是指针类型 + varType = ((PointerType *)var->type_)->contained_; + } + + // 指向的还是数组,那么一定是传数组参,数组若为x[2], 参数为int a[],需要传i32 * + if (varType->tid_ == Type::ArrayTyID) { + recentVal = builder->create_gep(var, {CONST_INT(0), CONST_INT(0)}); + } else if (!isTrueLVal) { // 如果不是取左值,那么load + recentVal = builder->create_load(var); + } else { // 否则返回地址值 + recentVal = var; + } +} + +void GenIR::visit(NumberAST &ast) { + if (ast.isInt) + recentVal = CONST_INT(ast.intval); + else + recentVal = CONST_FLOAT(ast.floatval); +} + +void GenIR::visit(CallAST &ast) { + auto fun = (Function *)scope.find(*ast.id); + // 引用函数返回值 + if (fun->basic_blocks_.size() && !is_single_exp) + fun->use_ret_cnt++; + is_single_exp = false; + vector args; + for (int i = 0; i < ast.funcCParamList.size(); i++) { + ast.funcCParamList[i]->accept(*this); + // 检查函数形参与实参类型是否匹配 + if (recentVal->type_ == INT32_T && fun->arguments_[i]->type_ == FLOAT_T) { + recentVal = builder->create_sitofp(recentVal, FLOAT_T); + } else if (recentVal->type_ == FLOAT_T && + fun->arguments_[i]->type_ == INT32_T) { + recentVal = builder->create_fptosi(recentVal, INT32_T); + } + args.push_back(recentVal); + } + recentVal = builder->create_call(fun, args); +} + +void GenIR::visit(RelExpAST &ast) { + if (ast.relExp == nullptr) { + ast.addExp->accept(*this); + return; + } + Value *val[2]; + ast.relExp->accept(*this); + val[0] = recentVal; + ast.addExp->accept(*this); + val[1] = recentVal; + checkCalType(val); + if (val[0]->type_ == INT32_T) { + switch (ast.op) { + case ROP_LTE: + recentVal = builder->create_icmp_le(val[0], val[1]); + break; + case ROP_LT: + recentVal = builder->create_icmp_lt(val[0], val[1]); + break; + case ROP_GT: + recentVal = builder->create_icmp_gt(val[0], val[1]); + break; + case ROP_GTE: + recentVal = builder->create_icmp_ge(val[0], val[1]); + break; + } + } else { + switch (ast.op) { + case ROP_LTE: + recentVal = builder->create_fcmp_le(val[0], val[1]); + break; + case ROP_LT: + recentVal = builder->create_fcmp_lt(val[0], val[1]); + break; + case ROP_GT: + recentVal = builder->create_fcmp_gt(val[0], val[1]); + break; + case ROP_GTE: + recentVal = builder->create_fcmp_ge(val[0], val[1]); + break; + } + } +} + +void GenIR::visit(EqExpAST &ast) { + if (ast.eqExp == nullptr) { + ast.relExp->accept(*this); + return; + } + Value *val[2]; + ast.eqExp->accept(*this); + val[0] = recentVal; + ast.relExp->accept(*this); + val[1] = recentVal; + checkCalType(val); + if (val[0]->type_ == INT32_T) { + switch (ast.op) { + case EOP_EQ: + recentVal = builder->create_icmp_eq(val[0], val[1]); + break; + case EOP_NEQ: + recentVal = builder->create_icmp_ne(val[0], val[1]); + break; + } + } else { + switch (ast.op) { + case EOP_EQ: + recentVal = builder->create_fcmp_eq(val[0], val[1]); + break; + case EOP_NEQ: + recentVal = builder->create_fcmp_ne(val[0], val[1]); + break; + } + } +} + +void GenIR::visit(LAndExpAST &ast) { + if (ast.lAndExp == nullptr) { + ast.eqExp->accept(*this); + return; + } + auto tempTrue = trueBB; // 防止嵌套and导致原trueBB丢失。用于生成短路模块 + trueBB = new BasicBlock(module.get(), to_string(id++), currentFunction); + ast.lAndExp->accept(*this); + + if (recentVal->type_ == INT32_T) { + recentVal = builder->create_icmp_ne(recentVal, CONST_INT(0)); + } else if (recentVal->type_ == FLOAT_T) { + recentVal = builder->create_fcmp_ne(recentVal, CONST_FLOAT(0)); + } + builder->create_cond_br(recentVal, trueBB, falseBB); + builder->BB_ = trueBB; + has_br = false; + trueBB = tempTrue; // 还原原来的true模块 + + ast.eqExp->accept(*this); +} + +void GenIR::visit(LOrExpAST &ast) { + if (ast.lOrExp == nullptr) { + ast.lAndExp->accept(*this); + return; + } + auto tempFalse = falseBB; // 防止嵌套and导致原trueBB丢失。用于生成短路模块 + falseBB = new BasicBlock(module.get(), to_string(id++), currentFunction); + ast.lOrExp->accept(*this); + if (recentVal->type_ == INT32_T) { + recentVal = builder->create_icmp_ne(recentVal, CONST_INT(0)); + } else if (recentVal->type_ == FLOAT_T) { + recentVal = builder->create_fcmp_ne(recentVal, CONST_FLOAT(0)); + } + builder->create_cond_br(recentVal, trueBB, falseBB); + builder->BB_ = falseBB; + has_br = false; + falseBB = tempFalse; + + ast.lAndExp->accept(*this); +} diff --git a/compiler/src/ir/genIR.h b/compiler/src/ir/genIR.h new file mode 100644 index 0000000..ec25179 --- /dev/null +++ b/compiler/src/ir/genIR.h @@ -0,0 +1,210 @@ +#pragma once + +#include "ast.h" +#include "ir.h" +#include + +class Scope { +public: + // enter a new scope + void enter() { symbol.push_back({}); } + + // exit a scope + void exit() { symbol.pop_back(); } + + bool in_global() { return symbol.size() == 1; } + + // push a name to scope + // return true if successful + // return false if this name already exits + // but func name could be same with variable name + bool push(std::string name, Value *val) { + bool result; + result = (symbol[symbol.size() - 1].insert({name, val})).second; + return result; + } + + Value *find(std::string name) { + for (auto s = symbol.rbegin(); s != symbol.rend(); s++) { + auto iter = s->find(name); + if (iter != s->end()) { + return iter->second; + } + } + return nullptr; + } + +private: + std::vector> symbol; +}; + +class GenIR : public Visitor { +public: + void visit(CompUnitAST &ast) override; + void visit(DeclDefAST &ast) override; + void visit(DeclAST &ast) override; + void visit(DefAST &ast) override; + void visit(InitValAST &ast) override; + void visit(FuncDefAST &ast) override; + void visit(FuncFParamAST &ast) override; + void visit(BlockAST &ast) override; + void visit(BlockItemAST &ast) override; + void visit(StmtAST &ast) override; + void visit(ReturnStmtAST &ast) override; + void visit(SelectStmtAST &ast) override; + void visit(IterationStmtAST &ast) override; + void visit(AddExpAST &ast) override; + void visit(LValAST &ast) override; + void visit(MulExpAST &ast) override; + void visit(UnaryExpAST &ast) override; + void visit(PrimaryExpAST &ast) override; + void visit(CallAST &ast) override; + void visit(NumberAST &ast) override; + void visit(RelExpAST &ast) override; + void visit(EqExpAST &ast) override; + void visit(LAndExpAST &ast) override; + void visit(LOrExpAST &ast) override; + + IRStmtBuilder *builder; + Scope scope; + std::unique_ptr module; + + GenIR() { + module = std::unique_ptr(new Module()); + builder = new IRStmtBuilder(nullptr, module.get()); + auto TyVoid = module->void_ty_; + auto TyInt32 = module->int32_ty_; + auto TyInt32Ptr = module->get_pointer_type(module->int32_ty_); + auto TyFloat = module->float32_ty_; + auto TyFloatPtr = module->get_pointer_type(module->float32_ty_); + + auto input_type = new FunctionType(TyInt32, {}); + auto get_int = new Function(input_type, "getint", module.get()); + + input_type = new FunctionType(TyFloat, {}); + auto get_float = new Function(input_type, "getfloat", module.get()); + + input_type = new FunctionType(TyInt32, {}); + auto get_char = new Function(input_type, "getch", module.get()); + + std::vector input_params; + std::vector().swap(input_params); + input_params.push_back(TyInt32Ptr); + input_type = new FunctionType(TyInt32, input_params); + auto get_int_array = new Function(input_type, "getarray", module.get()); + + std::vector().swap(input_params); + input_params.push_back(TyFloatPtr); + input_type = new FunctionType(TyInt32, input_params); + auto get_float_array = new Function(input_type, "getfarray", module.get()); + + std::vector output_params; + std::vector().swap(output_params); + output_params.push_back(TyInt32); + auto output_type = new FunctionType(TyVoid, output_params); + auto put_int = new Function(output_type, "putint", module.get()); + + std::vector().swap(output_params); + output_params.push_back(TyFloat); + output_type = new FunctionType(TyVoid, output_params); + auto put_float = new Function(output_type, "putfloat", module.get()); + + std::vector().swap(output_params); + output_params.push_back(TyInt32); + output_type = new FunctionType(TyVoid, output_params); + auto put_char = new Function(output_type, "putch", module.get()); + + std::vector().swap(output_params); + output_params.push_back(TyInt32); + output_params.push_back(TyInt32Ptr); + output_type = new FunctionType(TyVoid, output_params); + auto put_int_array = new Function(output_type, "putarray", module.get()); + + std::vector().swap(output_params); + output_params.push_back(TyInt32); + output_params.push_back(TyFloatPtr); + output_type = new FunctionType(TyVoid, output_params); + auto put_float_array = new Function(output_type, "putfarray", module.get()); + + output_params.clear(); + // output_params.push_back(TyInt32); + auto time_type = new FunctionType(TyVoid, output_params); + auto sysy_start_time = + new Function(time_type, "_sysy_starttime", module.get()); + auto sysy_stop_time = + new Function(time_type, "_sysy_stoptime", module.get()); + + output_params.clear(); + output_params.push_back(TyInt32Ptr); + output_params.push_back(TyInt32Ptr); + output_params.push_back(TyInt32); + output_type = new FunctionType(TyVoid, output_params); + auto memcpy = new Function(output_type, "__aeabi_memcpy4", module.get()); + + output_params.clear(); + output_params.push_back(TyInt32Ptr); + output_params.push_back(TyInt32); + output_type = new FunctionType(TyVoid, output_params); + auto memclr = new Function(output_type, "__aeabi_memclr4", module.get()); + + output_params.push_back(TyInt32); + output_type = new FunctionType(TyVoid, output_params); + auto memset = new Function(output_type, "__aeabi_memset4", module.get()); + + output_params.clear(); + output_type = new FunctionType(TyVoid, output_params); + auto llvm_memset = + new Function(output_type, "llvm.memset.p0.i32", module.get()); + + // output_params.clear(); + // output_params.push_back(TyInt32); + // output_type = new FunctionType(TyInt32, output_params); + // auto my_malloc = new Function(output_type, "malloc", module.get()); + + scope.enter(); + scope.push("getint", get_int); + scope.push("getfloat", get_float); + scope.push("getch", get_char); + scope.push("getarray", get_int_array); + scope.push("getfarray", get_float_array); + scope.push("putint", put_int); + scope.push("putfloat", put_float); + scope.push("putch", put_char); + scope.push("putarray", put_int_array); + scope.push("putfarray", put_float_array); + scope.push("starttime", sysy_start_time); + scope.push("stoptime", sysy_stop_time); + scope.push("memcpy", memcpy); + scope.push("memclr", memclr); + scope.push("memset", memset); + scope.push("llvm.memset.p0.i32", llvm_memset); + // scope.push("malloc",my_malloc); + } + std::unique_ptr getModule() { return std::move(module); } + + void checkInitType() const; + + static int getNextDim(vector &dimensionsCnt, int up, int cnt); + + void localInit(Value *ptr, vector> &list, + vector &dimensionsCnt, int up); + + static int getNextDim(vector &elementsCnts, int up); + + ConstantArray *globalInit(vector &dimensions, + vector &arrayTys, int up, + vector> &list); + + static void mergeElements(vector &dimensions, + vector &arrayTys, int up, int dimAdd, + vector &elements, + vector &elementsCnts); + + void finalMerge(vector &dimensions, vector &arrayTys, + int up, vector &elements, + vector &elementsCnts) const; + + bool checkCalType(Value **val, int *intVal, float *floatVal); + + void checkCalType(Value **val); +}; diff --git a/compiler/src/ir/ir.cpp b/compiler/src/ir/ir.cpp new file mode 100644 index 0000000..bfb5cf0 --- /dev/null +++ b/compiler/src/ir/ir.cpp @@ -0,0 +1,838 @@ +#include "ir.h" + +std::map instr_id2string_ = { + {Instruction::Ret, "ret"}, + {Instruction::Br, "br"}, + {Instruction::FNeg, "fneg"}, + {Instruction::Add, "add"}, + {Instruction::Sub, "sub"}, + {Instruction::Mul, "mul"}, + {Instruction::SDiv, "sdiv"}, + {Instruction::SRem, "srem"}, + {Instruction::UDiv, "udiv"}, + {Instruction::URem, "urem"}, + {Instruction::FAdd, "fadd"}, + {Instruction::FSub, "fsub"}, + {Instruction::FMul, "fmul"}, + {Instruction::FDiv, "fdiv"}, + {Instruction::Shl, "shl"}, + {Instruction::LShr, "lshr"}, + {Instruction::AShr, "ashr"}, + {Instruction::And, "and"}, + {Instruction::Or, "or"}, + {Instruction::Xor, "xor"}, + {Instruction::Alloca, "alloca"}, + {Instruction::Load, "load"}, + {Instruction::Store, "store"}, + {Instruction::GetElementPtr, "getelementptr"}, + {Instruction::ZExt, "zext"}, + {Instruction::FPtoSI, "fptosi"}, + {Instruction::SItoFP, "sitofp"}, + {Instruction::BitCast, "bitcast"}, + {Instruction::ICmp, "icmp"}, + {Instruction::FCmp, "fcmp"}, + {Instruction::PHI, "phi"}, + {Instruction::Call, "call"}}; // Instruction from opid to string +const std::map ICmpInst::ICmpOpName = { + {ICmpInst::ICmpOp::ICMP_EQ, "eq"}, {ICmpInst::ICmpOp::ICMP_NE, "ne"}, + {ICmpInst::ICmpOp::ICMP_UGT, "hi"}, {ICmpInst::ICmpOp::ICMP_UGE, "cs"}, + {ICmpInst::ICmpOp::ICMP_ULT, "cc"}, {ICmpInst::ICmpOp::ICMP_ULE, "ls"}, + {ICmpInst::ICmpOp::ICMP_SGT, "gt"}, {ICmpInst::ICmpOp::ICMP_SGE, "ge"}, + {ICmpInst::ICmpOp::ICMP_SLT, "lt"}, {ICmpInst::ICmpOp::ICMP_SLE, "le"}}; +const std::map FCmpInst::FCmpOpName = { + {FCmpInst::FCmpOp::FCMP_FALSE, "nv"}, {FCmpInst::FCmpOp::FCMP_OEQ, "eq"}, + {FCmpInst::FCmpOp::FCMP_OGT, "gt"}, {FCmpInst::FCmpOp::FCMP_OGE, "ge"}, + {FCmpInst::FCmpOp::FCMP_OLT, "cc"}, {FCmpInst::FCmpOp::FCMP_OLE, "ls"}, + {FCmpInst::FCmpOp::FCMP_ONE, "ne"}, {FCmpInst::FCmpOp::FCMP_ORD, "vc"}, + {FCmpInst::FCmpOp::FCMP_UNO, "vs"}, {FCmpInst::FCmpOp::FCMP_UEQ, "eq"}, + {FCmpInst::FCmpOp::FCMP_UGT, "hi"}, {FCmpInst::FCmpOp::FCMP_UGE, "cs"}, + {FCmpInst::FCmpOp::FCMP_ULT, "lt"}, {FCmpInst::FCmpOp::FCMP_ULE, "le"}, + {FCmpInst::FCmpOp::FCMP_UNE, "ne"}, {FCmpInst::FCmpOp::FCMP_TRUE, "al"}}; +std::string print_as_op(Value *v, bool print_ty); +std::string print_cmp_type(ICmpInst::ICmpOp op); +std::string print_fcmp_type(FCmpInst::FCmpOp op); +//-----------------------------------------------Type----------------------------------------------- +std::string Type::print() { + std::string type_ir; + switch (this->tid_) { + case VoidTyID: + type_ir += "void"; + break; + case LabelTyID: + type_ir += "label"; + break; + case IntegerTyID: + type_ir += "i"; + type_ir += std::to_string(static_cast(this)->num_bits_); + break; + case FloatTyID: + type_ir += "float"; + break; + case FunctionTyID: + type_ir += static_cast(this)->result_->print(); + type_ir += " ("; + for (size_t i = 0; i < static_cast(this)->args_.size(); + i++) { + if (i) + type_ir += ", "; + type_ir += static_cast(this)->args_[i]->print(); + } + type_ir += ")"; + break; + case PointerTyID: + type_ir += static_cast(this)->contained_->print(); + type_ir += "*"; + break; + case ArrayTyID: + type_ir += "["; + type_ir += std::to_string(static_cast(this)->num_elements_); + type_ir += " x "; + type_ir += static_cast(this)->contained_->print(); + type_ir += "]"; + break; + default: + break; + } + return type_ir; +} + +//-----------------------------------------------Value----------------------------------------------- +void Value::replace_all_use_with(Value *new_val) { + for (auto use : use_list_) { + auto val = dynamic_cast(use.val_); +#ifdef DEBUG + assert(val && "new_val is not a user"); +#endif + val->set_operand(use.arg_no_, new_val); + } +} +bool Value::remove_used(Instruction *user, unsigned int i) { + if (this != user->operands_[i]) { + return false; + } + auto pos = user->use_pos_[i]; + use_list_.erase(pos); + user->operands_[i] = + nullptr; // 表示user->use_pos_[i]失效了,提示set_operand不要再删除 + return true; +} + +bool Value::is_constant() { return name_[0] == 0; } + +//-----------------------------------------------Constant----------------------------------------------- +std::string ConstantInt::print() { + std::string const_ir; + if (this->type_->tid_ == Type::IntegerTyID && + static_cast(this->type_)->num_bits_ == 1) { + // int1 + const_ir += (this->value_ == 0) ? "0" : "1"; + } else // int32 + const_ir += std::to_string(this->value_); + return const_ir; +} + +std::string ConstantFloat::print() { + std::stringstream fp_ir_ss; + std::string fp_ir; + double val = this->value_; + fp_ir_ss << "0x" << std::hex << *(uint64_t *)&val << std::endl; + fp_ir_ss >> fp_ir; + return fp_ir; +} + +std::string ConstantFloat::print32() { + std::stringstream fp_ir_ss; + std::string fp_ir; + float val = this->value_; + fp_ir_ss << "0x" << std::hex << *(uint32_t *)&val << std::endl; + fp_ir_ss >> fp_ir; + return fp_ir; +} + +std::string ConstantArray::print() { + std::string const_ir; + const_ir += "["; + const_ir += static_cast(this->type_)->contained_->print(); + const_ir += " "; + const_ir += const_array[0]->print(); + for (size_t i = 1; i < this->const_array.size(); i++) { + const_ir += ", "; + const_ir += static_cast(this->type_)->contained_->print(); + const_ir += " "; + const_ir += const_array[i]->print(); + } + const_ir += "]"; + return const_ir; +} + +std::string ConstantZero::print() { return "zeroinitializer"; } + +//-----------------------------------------------Module----------------------------------------------- +std::string Module::print() { + std::string module_ir; + for (auto global_val : this->global_list_) { + module_ir += global_val->print(); + module_ir += "\n"; + } + for (auto func : this->function_list_) { + module_ir += func->print(); + module_ir += "\n"; + } + return module_ir; +} + +Function *Module::getMainFunc() { + for (auto f : function_list_) { + if (f->name_ == "main") { + return f; + } + } + return nullptr; +} + +//-----------------------------------------------GlobalVariable----------------------------------------------- +std::string GlobalVariable::print() { + std::string global_val_ir; + global_val_ir += print_as_op(this, false); + global_val_ir += " = "; + global_val_ir += (this->is_const_ ? "constant " : "global "); + global_val_ir += static_cast(this->type_)->contained_->print(); + global_val_ir += " "; + global_val_ir += this->init_val_->print(); + return global_val_ir; +} + +//-----------------------------------------------Function----------------------------------------------- +std::string Function::print() { + if (this->name_ == "llvm.memset.p0.i32") { + std::string func_ir = "declare void @llvm.memset.p0.i32(i32*, i8, i32, i1)"; + return func_ir; + } + set_instr_name(); + std::string func_ir; + if (this->is_declaration()) + func_ir += "declare "; + else + func_ir += "define "; + + func_ir += this->get_return_type()->print(); + func_ir += " "; + func_ir += print_as_op(this, false); + func_ir += "("; + + // print arg + if (this->is_declaration()) { + for (size_t i = 0; i < this->arguments_.size(); i++) { + if (i) + func_ir += ", "; + func_ir += static_cast(this->type_)->args_[i]->print(); + } + } else { + for (auto arg = this->arguments_.begin(); arg != arguments_.end(); arg++) { + if (arg != this->arguments_.begin()) { + func_ir += ", "; + } + func_ir += static_cast(*arg)->print(); + } + } + func_ir += ")"; + + // print bb + if (!this->is_declaration()) { + func_ir += " {"; + func_ir += "\n"; + for (auto bb : this->basic_blocks_) { + func_ir += bb->print(); + } + func_ir += "}"; + } + + return func_ir; +} + +std::string Argument::print() { + std::string arg_ir; + arg_ir += this->type_->print(); + arg_ir += " %"; + arg_ir += this->name_; + return arg_ir; +} + +void Function::remove_bb(BasicBlock *bb) { + // basic_blocks_.remove(bb); + basic_blocks_.erase( + std::remove(basic_blocks_.begin(), basic_blocks_.end(), bb), + basic_blocks_.end()); + for (auto pre : bb->pre_bbs_) { + pre->remove_succ_basic_block(bb); + } + for (auto succ : bb->succ_bbs_) { + succ->remove_pre_basic_block(bb); + } +} + +BasicBlock *Function::getRetBB() { + for (auto bb : basic_blocks_) { + if (bb->get_terminator()->is_ret()) { + return bb; + } + } + return nullptr; +} + +//-----------------------------------------------BasicBlock----------------------------------------------- +std::string BasicBlock::print() { + std::string bb_ir; + bb_ir += this->name_; + bb_ir += ":"; + // print prebb + if (!this->pre_bbs_.empty()) { + bb_ir += " ; preds = "; + } + for (auto bb : this->pre_bbs_) { + if (bb != *this->pre_bbs_.begin()) + bb_ir += ", "; + bb_ir += print_as_op(bb, false); + } + + // print prebb + if (!this->parent_) { + bb_ir += "\n"; + bb_ir += "; Error: Block without parent!"; + } + bb_ir += "\n"; + for (auto instr : this->instr_list_) { + bb_ir += " "; + bb_ir += instr->print(); + bb_ir += "\n"; + } + + return bb_ir; +} + +Instruction *BasicBlock::get_terminator() { + if (instr_list_.empty()) + return nullptr; + switch (instr_list_.back()->op_id_) { + case Instruction::Ret: + case Instruction::Br: + return instr_list_.back(); + default: + return nullptr; + } +} + +bool BasicBlock::delete_instr(Instruction *instr) { + //******************--------instvec2list-----qwc20220814 + // instr_list_.remove(instr); + if ((!instr) || instr->pos_in_bb.size() != 1 || instr->parent_ != this) + return false; + this->instr_list_.erase(instr->pos_in_bb.back()); + // instr_list_.erase(std::remove(instr_list_.begin(), instr_list_.end(), + // instr) , instr_list_.end()); + instr->remove_use_of_ops(); + instr->pos_in_bb.clear(); // 保证指令自由身 + instr->parent_ = nullptr; + return true; +} + +bool BasicBlock::add_instruction(Instruction *instr) { + //******************--------instvec2list-----qwc20220814 + + if (instr->pos_in_bb.size() != 0) { // 指令已经插入到某个地方了 + return false; + } else { + instr_list_.push_back(instr); + std::list::iterator tail = instr_list_.end(); + instr->pos_in_bb.emplace_back(--tail); + instr->parent_ = this; + return true; + } +} + +bool BasicBlock::add_instruction_front(Instruction *instr) { + //******************--------instvec2list-----qwc20220814 + if (instr->pos_in_bb.size() != 0) { // 指令已经插入到某个地方了 + return false; + } else { + instr_list_.push_front(instr); + std::list::iterator head = instr_list_.begin(); + instr->pos_in_bb.emplace_back(head); + instr->parent_ = this; + return true; + } +} + +// 插入到倒数第二位 +bool BasicBlock::add_instruction_before_terminator(Instruction *instr) { + if (instr->pos_in_bb.size() != 0) { // 指令已经插入到某个地方了 + return false; + } else if (instr_list_.empty()) { // 没有“倒数第1位”何来的倒数第二位 + return false; + } else { + auto it = std::end(instr_list_); // 最后一位的后一位位置 + instr_list_.emplace( + --it, + instr); // 插入使得代替最后一位(--it)的位置,此时it是最后一位,插入的是倒数第二位 + instr->pos_in_bb.emplace_back(--it); // 记录插入的结果 + instr->parent_ = this; + return true; + } +} + +bool BasicBlock::add_instruction_before_inst(Instruction *new_instr, + Instruction *instr) { + if ((!instr) || instr->pos_in_bb.size() != 1 || instr->parent_ != this) + return false; + if (new_instr->pos_in_bb.size() != 0) // 指令已经插入到某个地方了 + return false; + else if ( + instr_list_ + .empty()) // bb原本没有指令,那instr不在bb内,那为啥instr->parent_== + // this + return false; + else { + auto it = instr->pos_in_bb.back(); // + instr_list_.emplace( + it, + new_instr); // 插入使得代替最后一位(--it)的位置,此时it是最后一位,插入的是倒数第二位 + new_instr->pos_in_bb.emplace_back(--it); // 记录插入的结果 + new_instr->parent_ = this; + return true; + } +} + +// 从bb移出一个指令,但是不删指令的use关系,因为还要插入其他bb +bool BasicBlock::remove_instr(Instruction *instr) { + // instr_list_.remove(instr); + if ((!instr) || instr->pos_in_bb.size() != 1 || instr->parent_ != this) + return false; + this->instr_list_.erase(instr->pos_in_bb.back()); + // instr->remove_use_of_ops(); + instr->pos_in_bb.clear(); // 保证指令自由身 + instr->parent_ = nullptr; + return true; +} + +//-----------------------------------------------Instruction----------------------------------------------- +std::string BinaryInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->operands_[0]->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += ", "; + assert(this->get_operand(0)->type_->tid_ == + this->get_operand(1)->type_->tid_); + instr_ir += print_as_op(this->get_operand(1), false); + // instr_ir += print_as_op(this->get_operand(1), true); + return instr_ir; +} + +std::string UnaryInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->operands_[0]->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + switch (this->op_id_) { + case Instruction::ZExt: + assert(this->type_->tid_ == Type::IntegerTyID); + instr_ir += " to i32"; + break; + case Instruction::FPtoSI: + assert(this->type_->tid_ == Type::IntegerTyID); + instr_ir += " to i32"; + break; + case Instruction::SItoFP: + assert(this->type_->tid_ == Type::FloatTyID); + instr_ir += " to float"; + break; + default: + assert(0 && "UnaryInst opID invalid!"); + break; + } + return instr_ir; +} + +std::string ICmpInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += print_cmp_type(this->icmp_op_); + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += ", "; + if (this->get_operand(0)->type_->tid_ == this->get_operand(1)->type_->tid_) { + instr_ir += print_as_op(this->get_operand(1), false); + } else { + instr_ir += print_as_op(this->get_operand(1), true); + } + return instr_ir; +} + +std::string FCmpInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += print_fcmp_type(this->fcmp_op_); + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += ", "; + if (this->get_operand(0)->type_->tid_ == this->get_operand(1)->type_->tid_) { + instr_ir += print_as_op(this->get_operand(1), false); + } else { + instr_ir += print_as_op(this->get_operand(1), true); + } + return instr_ir; +} + +std::string CallInst::print() { + std::string instr_ir; + if (!(this->type_->tid_ == Type::VoidTyID)) { + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + } + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + unsigned int numops = this->num_ops_; + instr_ir += static_cast(this->get_operand(numops - 1)->type_) + ->result_->print(); + + instr_ir += " "; + assert(dynamic_cast(this->get_operand(numops - 1)) && + "Wrong call operand function"); + //__aeabi_memclr4 -> llvm_memset + if (dynamic_cast(this->get_operand(numops - 1))->name_ == + "__aeabi_memclr4") { + instr_ir += "@llvm.memset.p0.i32("; + // i32* 目的内存地址 + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + // i8 0 + instr_ir += ", i8 0, "; + // i32 修改总字节数 + instr_ir += this->get_operand(1)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(1), false); + // i1 false + instr_ir += ", i1 false)"; + return instr_ir; + } + + instr_ir += print_as_op(this->get_operand(numops - 1), false); + instr_ir += "("; + for (unsigned int i = 0; i < numops - 1; i++) { + if (i > 0) + instr_ir += ", "; + instr_ir += this->get_operand(i)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(i), false); + } + instr_ir += ")"; + return instr_ir; +} + +std::string BranchInst::print() { + std::string instr_ir; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), true); + + if (this->num_ops_ == 3) { + instr_ir += ", "; + instr_ir += print_as_op(this->get_operand(1), true); + instr_ir += ", "; + instr_ir += print_as_op(this->get_operand(2), true); + } + return instr_ir; +} + +std::string ReturnInst::print() { + std::string instr_ir; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + if (this->num_ops_ != 0) { + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + } else { + instr_ir += "void"; + } + + return instr_ir; +} + +std::string GetElementPtrInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + assert(this->get_operand(0)->type_->tid_ == Type::PointerTyID); + instr_ir += static_cast(this->get_operand(0)->type_) + ->contained_->print(); + instr_ir += ", "; + for (unsigned int i = 0; i < this->num_ops_; i++) { + if (i > 0) + instr_ir += ", "; + instr_ir += this->get_operand(i)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(i), false); + } + return instr_ir; +} + +std::string StoreInst::print() { + std::string instr_ir; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += ", "; + instr_ir += print_as_op(this->get_operand(1), true); + return instr_ir; +} + +std::string LoadInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + assert(this->get_operand(0)->type_->tid_ == Type::PointerTyID); + instr_ir += static_cast(this->get_operand(0)->type_) + ->contained_->print(); + instr_ir += ","; + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), true); + return instr_ir; +} + +std::string AllocaInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += alloca_ty_->print(); + return instr_ir; +} + +std::string ZextInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += " to "; + instr_ir += this->dest_ty_->print(); + return instr_ir; +} + +std::string FpToSiInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += " to "; + instr_ir += this->dest_ty_->print(); + return instr_ir; +} + +std::string SiToFpInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += " to "; + instr_ir += this->dest_ty_->print(); + return instr_ir; +} + +std::string Bitcast::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + instr_ir += print_as_op(this->get_operand(0), false); + instr_ir += " to "; + instr_ir += this->dest_ty_->print(); + return instr_ir; +} + +std::string PhiInst::print() { + std::string instr_ir; + instr_ir += "%"; + instr_ir += this->name_; + instr_ir += " = "; + instr_ir += instr_id2string_[this->op_id_]; + instr_ir += " "; + instr_ir += this->get_operand(0)->type_->print(); + instr_ir += " "; + for (int i = 0; i < this->num_ops_ / 2; i++) { + if (i > 0) + instr_ir += ", "; + instr_ir += "[ "; + instr_ir += print_as_op(this->get_operand(2 * i), false); + instr_ir += ", "; + instr_ir += print_as_op(this->get_operand(2 * i + 1), false); + instr_ir += " ]"; + } + if (this->num_ops_ / 2 < this->parent_->pre_bbs_.size()) { + for (auto pre_bb : this->parent_->pre_bbs_) { + if (std::find(this->operands_.begin(), this->operands_.end(), + static_cast(pre_bb)) == this->operands_.end()) { + // find a pre_bb is not in phi + instr_ir += ", [ undef, " + print_as_op(pre_bb, false) + " ]"; + } + } + } + return instr_ir; +} + +std::string print_as_op(Value *v, bool print_ty) { + std::string op_ir; + if (print_ty) { + op_ir += v->type_->print(); + op_ir += " "; + } + + if (dynamic_cast(v)) { + op_ir += "@" + v->name_; + } else if (dynamic_cast(v)) { + op_ir += "@" + v->name_; + } else if (dynamic_cast(v)) { + op_ir += v->print(); + } else { + op_ir += "%" + v->name_; + } + + return op_ir; +} + +std::string print_cmp_type(ICmpInst::ICmpOp op) { + switch (op) { + case ICmpInst::ICMP_SGE: + return "sge"; + break; + case ICmpInst::ICMP_SGT: + return "sgt"; + break; + case ICmpInst::ICMP_SLE: + return "sle"; + break; + case ICmpInst::ICMP_SLT: + return "slt"; + break; + case ICmpInst::ICMP_EQ: + return "eq"; + break; + case ICmpInst::ICMP_NE: + return "ne"; + break; + default: + break; + } + return "wrong cmpop"; +} + +std::string print_fcmp_type(FCmpInst::FCmpOp op) { + switch (op) { + case FCmpInst::FCMP_UGE: + return "uge"; + break; + case FCmpInst::FCMP_UGT: + return "ugt"; + break; + case FCmpInst::FCMP_ULE: + return "ule"; + break; + case FCmpInst::FCMP_ULT: + return "ult"; + break; + case FCmpInst::FCMP_UEQ: + return "ueq"; + break; + case FCmpInst::FCMP_UNE: + return "une"; + break; + default: + break; + } + return "wrong fcmpop"; +} + +void Function::set_instr_name() { + std::map seq; + for (auto arg : this->arguments_) { + if (!seq.count(arg)) { + auto seq_num = seq.size() + seq_cnt_; + if (arg->name_ == "") { + arg->name_ = "arg_" + std::to_string(seq_num); + seq.insert({arg, seq_num}); + } + } + } + for (auto bb : basic_blocks_) { + if (!seq.count(bb)) { + auto seq_num = seq.size() + seq_cnt_; + if (bb->name_.length() <= 6 || bb->name_.substr(0, 6) != "label_") { + bb->name_ = "label_" + std::to_string(seq_num); + seq.insert({bb, seq_num}); + } + } + for (auto instr : bb->instr_list_) { + if (instr->type_->tid_ != Type::VoidTyID && !seq.count(instr)) { + auto seq_num = seq.size() + seq_cnt_; + if (instr->name_ == "") { + instr->name_ = "v" + std::to_string(seq_num); + seq.insert({instr, seq_num}); + } + } + } + } + seq_cnt_ += seq.size(); +} diff --git a/compiler/src/ir/ir.h b/compiler/src/ir/ir.h new file mode 100644 index 0000000..31eae49 --- /dev/null +++ b/compiler/src/ir/ir.h @@ -0,0 +1,973 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Type; +class IntegerType; +class ArrayType; +class PointerType; +class FunctionType; +class Value; +class Constant; +class ConstantInt; +class ConstantFloat; +class ConstantArray; +class ConstantZero; +class Module; +class GlobalVariable; +class Function; +class BasicBlock; +class Argument; +class Instruction; +class BinaryInst; +class UnaryInst; +class ICmpInst; +class FCmpInst; +class CallInst; +class BranchInst; +class ReturnInst; +class GetElementPtrInst; +class StoreInst; +class LoadInst; +class AllocaInst; + +struct Use { + Value *val_; + unsigned int arg_no_; // 操作数的序号,如func(a,b)中a的序号为0,b的序号为1 + Use(Value *val, unsigned int no) : val_(val), arg_no_(no) {} +}; + +//-----------------------------------------------Type----------------------------------------------- +class Type { +public: + enum TypeID { + VoidTyID, // Void + LabelTyID, // Labels, e.g., BasicBlock + IntegerTyID, // Integers, include 32 bits and 1 bit + FloatTyID, // Floats, only 32 bits + FunctionTyID, // Functions + ArrayTyID, // Arrays + PointerTyID, // Pointer + }; + explicit Type(TypeID tid) : tid_(tid) {} + ~Type() = default; + virtual std::string print(); + TypeID tid_; +}; + +class IntegerType : public Type { +public: + explicit IntegerType(unsigned num_bits) + : Type(Type::IntegerTyID), num_bits_(num_bits) {} + unsigned num_bits_; +}; + +//[2 x [3 x i32]]: num_elements_ = 2, contained_ = [3 x i32] +class ArrayType : public Type { +public: + ArrayType(Type *contained, unsigned num_elements) + : Type(Type::ArrayTyID), num_elements_(num_elements), + contained_(contained) {} + Type *contained_; // The element type of the array. + unsigned num_elements_; // Number of elements in the array. +}; + +//[2 x [3 x i32]]* +class PointerType : public Type { +public: + PointerType(Type *contained) + : Type(Type::PointerTyID), contained_(contained) {} + Type *contained_; // The element type of the ptr. +}; + +// declare i32 @putarray(i32, i32*) +class FunctionType : public Type { +public: + FunctionType(Type *result, std::vector params) + : Type(Type::FunctionTyID) { + result_ = result; + for (Type *p : params) { + args_.push_back(p); + } + } + Type *result_; + std::vector args_; +}; + +//-----------------------------------------------Value----------------------------------------------- +class Value { +public: + explicit Value(Type *ty, const std::string &name = "") + : type_(ty), name_(name) {} + ~Value() = default; + virtual std::string print() = 0; + + void remove_use(Value *val) { + auto is_val = [val](const Use &use) { return use.val_ == val; }; + use_list_.remove_if(is_val); + } + + //****************************************************************** + std::list::iterator add_use(Value *val, unsigned arg_no) { + use_list_.emplace_back(Use(val, arg_no)); + std::list::iterator re = use_list_.end(); + return --re; + } + // 删除迭代器指出的use + void remove_use(std::list::iterator it) { use_list_.erase(it); } + // user的第i个操作数准备不再使用this,因此删除this与user相关的use联系 + bool remove_used(Instruction *user, unsigned int i); + + // Return if the value is a constant. + bool is_constant(); + + //****************************************************************** + + void replace_all_use_with(Value *new_val); + Type *type_; + std::string name_; + std::list + use_list_; // 所有引用该Value的Instruction的集合,以及该Value在该Instruction的第几个操作数位置被引用 +}; + +//-----------------------------------------------Constant----------------------------------------------- +// 常量都是无名的(name=="") +class Constant : public Value { +public: + Constant(Type *ty, const std::string &name = "") : Value(ty, name) {} + ~Constant() = default; +}; + +// i32 -23 +class ConstantInt : public Constant { +public: + ConstantInt(Type *ty, int val) : Constant(ty, ""), value_(val) {} + virtual std::string print() override; + int value_; +}; + +// float 0x4057C21FC0000000 +// float -3.300000e+04 +class ConstantFloat : public Constant { +public: + ConstantFloat(Type *ty, float val) : Constant(ty, ""), value_(val) {} + virtual std::string print() override; + float value_; + std::string print32(); +}; + +//[3 x i32] [i32 42, i32 11, i32 74] +class ConstantArray : public Constant { +public: + ConstantArray(ArrayType *ty, const std::vector &val) + : Constant(ty, "") { + this->const_array.assign(val.begin(), val.end()); + } + ~ConstantArray() = default; + virtual std::string print() override; + std::vector const_array; +}; + +// i32 zeroinitializer +//[2 x [100 x float]] zeroinitializer +// 注意zeroinitializer是有类型的! +class ConstantZero : public Constant { +public: + ConstantZero(Type *ty) : Constant(ty, "") {} + virtual std::string print() override; +}; + +//-----------------------------------------------Module----------------------------------------------- +class Module { +public: + explicit Module() { + void_ty_ = new Type(Type::VoidTyID); + label_ty_ = new Type(Type::LabelTyID); + int1_ty_ = new IntegerType(1); + int32_ty_ = new IntegerType(32); + float32_ty_ = new Type(Type::FloatTyID); + } + ~Module() { + delete void_ty_; + delete label_ty_; + delete int1_ty_; + delete int32_ty_; + delete float32_ty_; + } + virtual std::string print(); + void add_global_variable(GlobalVariable *g) { global_list_.push_back(g); } + void add_function(Function *f) { function_list_.push_back(f); } + PointerType *get_pointer_type(Type *contained) { + if (!pointer_map_.count(contained)) { + pointer_map_[contained] = new PointerType(contained); + } + return pointer_map_[contained]; + } + ArrayType *get_array_type(Type *contained, unsigned num_elements) { + if (!array_map_.count({contained, num_elements})) { + array_map_[{contained, num_elements}] = + new ArrayType(contained, num_elements); + } + return array_map_[{contained, num_elements}]; + } + + Function *getMainFunc(); + + std::vector global_list_; + std::vector function_list_; + + IntegerType *int1_ty_; + IntegerType *int32_ty_; + Type *float32_ty_; + Type *label_ty_; + Type *void_ty_; + std::map pointer_map_; + std::map, ArrayType *> array_map_; +}; + +//-----------------------------------------------GlobalVariable----------------------------------------------- +//@c = global [4 x i32] [i32 6, i32 7, i32 8, i32 9] +//@a = constant [5 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4] +class GlobalVariable : public Value { +public: + GlobalVariable(std::string name, Module *m, Type *ty, bool is_const, + Constant *init = nullptr) + : Value(m->get_pointer_type(ty), name), is_const_(is_const), + init_val_(init) { + m->add_global_variable(this); + } + virtual std::string print() override; + bool is_const_; + Constant *init_val_; +}; + +//-----------------------------------------------Function----------------------------------------------- + +// 注:Argument的构造函数只由Function的构造函数调用,不单独调用!! +class Argument : public Value { +public: + explicit Argument(Type *ty, const std::string &name = "", + Function *f = nullptr, unsigned arg_no = 0) + : Value(ty, name), parent_(f), arg_no_(arg_no) {} + ~Argument() {} + virtual std::string print() override; + Function *parent_; + unsigned arg_no_; // argument No. +}; + +class Function : public Value { +public: + Function(FunctionType *ty, const std::string &name, Module *parent) + : Value(ty, name), parent_(parent), seq_cnt_(0) { + parent->add_function(this); + size_t num_args = ty->args_.size(); + use_ret_cnt = 0; + for (size_t i = 0; i < num_args; i++) { + arguments_.push_back(new Argument(ty->args_[i], "", this, i)); + } + } + ~Function(); + virtual std::string print() override; + void add_basic_block(BasicBlock *bb) { basic_blocks_.push_back(bb); } + Type *get_return_type() const { + return static_cast(type_)->result_; + } + bool is_declaration() { return basic_blocks_.empty(); } + void set_instr_name(); + void remove_bb(BasicBlock *bb); + BasicBlock *getRetBB(); + + std::vector basic_blocks_; // basic blocks + std::vector arguments_; // argument + Module *parent_; + unsigned seq_cnt_; + std::vector> vreg_set_; + int use_ret_cnt; // 程序中真正使用返回值的次数 +}; +//-----------------------------------------------BasicBlock----------------------------------------------- +// 注:BasicBlock一定是LabelTyID +class BasicBlock : public Value { +public: + explicit BasicBlock(Module *m, const std::string &name, Function *parent) + : Value(m->label_ty_, name), parent_(parent) { + parent_->add_basic_block(this); + } + bool add_instruction(Instruction *instr); // 尾部插入指令,返回成功与否 + bool add_instruction_front(Instruction *instr); // 头部插入指令,返回成功与否 + bool add_instruction_before_terminator( + Instruction *instr); // 插入到BB倒数第二条指令,即br前 + bool add_instruction_before_inst( + Instruction *new_inst, + Instruction * + inst); // 将新指令插入到原来指令前,返回成功与否,需要保证原指令在bb内 + void add_pre_basic_block(BasicBlock *bb) { pre_bbs_.push_back(bb); } + void add_succ_basic_block(BasicBlock *bb) { succ_bbs_.push_back(bb); } + void remove_pre_basic_block(BasicBlock *bb) { + // pre_bbs_.remove(bb); + pre_bbs_.erase(std::remove(pre_bbs_.begin(), pre_bbs_.end(), bb), + pre_bbs_.end()); + } + void remove_succ_basic_block(BasicBlock *bb) { + // succ_bbs_.remove(bb); + succ_bbs_.erase(std::remove(succ_bbs_.begin(), succ_bbs_.end(), bb), + succ_bbs_.end()); + } + int isDominate( + BasicBlock + *bb2) { // 返回1表示支配bb2,返回0表示不支配,返回-1输入的块出错 + if (!bb2 || this->parent_ != bb2->parent_) + return -1; + while (bb2->name_ != "label_entry") { + if (bb2->idom_ == this) + return 1; + bb2 = bb2->idom_; + } + return 0; + } + // Returns the terminator instruction if the block is well formed or null + // if the block is not well formed. + Instruction *get_terminator(); + bool delete_instr( + Instruction *instr); // 返回false则说明指令不能重复删除或者不属于这个bb, + bool remove_instr( + Instruction * + instr); // 从bb移出一个指令,但是不删指令的use关系,因为还要插入其他bb + virtual std::string print() override; + + //********************使用list替换vector--------- + std::list instr_list_; + //********************使用list替换vector--------- + + Function *parent_; + /****************api about cfg****************/ + std::vector pre_bbs_; + std::vector succ_bbs_; + /****************api about dominate tree****************/ + std::set dom_frontier_; + std::set rdom_frontier_; + std::set rdoms_; + BasicBlock *idom_; + std::set live_in; + std::set live_out; +}; + +//-----------------------------------------------Instruction----------------------------------------------- +class Instruction : public Value { +public: + enum OpID { + // Terminator Instructions + Ret = 11, + Br, + // Standard unary operators + FNeg, + // Standard binary operators + Add, + Sub, + Mul, + SDiv, + SRem, + UDiv, + URem, + // Float binary opeartors + FAdd, + FSub, + FMul, + FDiv, + // Logical operators + Shl, + LShr, + AShr, + And, + Or, + Xor, + // Memory operators + Alloca, + Load, + Store, + GetElementPtr, + // Cast operators + ZExt, + FPtoSI, + SItoFP, + BitCast, + // Other operators + ICmp, + FCmp, + PHI, + Call, + }; + // 创建指令并插入基本块(ty是指令返回值类型) + // If before set to true, then use add_instruction_front() instead of + // add_instruction() + Instruction(Type *ty, OpID id, unsigned num_ops, BasicBlock *parent, + bool before = false) + : Value(ty, ""), op_id_(id), num_ops_(num_ops), parent_(parent) { + operands_.resize( + num_ops_, + nullptr); // 此句不能删去!否则operands_为空时无法用set_operand设置操作数,而只能用push_back设置操作数! + use_pos_.resize(num_ops_); + if (!before) + parent_->add_instruction(this); + else + parent_->add_instruction_front(this); + } + // 仅创建指令,不插入基本块(ty是指令返回值类型) + Instruction(Type *ty, OpID id, unsigned num_ops) + : Value(ty, ""), op_id_(id), num_ops_(num_ops), parent_(nullptr) { + operands_.resize(num_ops_, nullptr); + use_pos_.resize(num_ops_); + } + Value *get_operand(unsigned i) const { return operands_[i]; } + + //*************************** + void set_operand(unsigned i, Value *v) { + operands_[i] = v; + use_pos_[i] = v->add_use(this, i); + } + void add_operand(Value *v) { // 添加指令操作数,用于phi指令 + operands_.push_back(v); + use_pos_.emplace_back(v->add_use(this, num_ops_)); + num_ops_++; + } + void + remove_use_of_ops() { // 删除此指令所有操作数的uselist中,与此指令相关的use + for (int i = 0; i < operands_.size(); i++) { + operands_[i]->remove_use(use_pos_[i]); + } + } + // 删除phi指令中的一对操作数 + void remove_operands(int index1, int index2) { + for (int i = index1; i <= index2; i++) { + operands_[i]->remove_use(use_pos_[i]); + } + // 后面操作数的位置要做相应修改 + for (int i = index2 + 1; i < operands_.size(); i++) { + for (auto &use : operands_[i]->use_list_) { + if (use.val_ == this) { + use.arg_no_ -= index2 - index1 + 1; + break; + } + } + } + operands_.erase(operands_.begin() + index1, operands_.begin() + index2 + 1); + use_pos_.erase(use_pos_.begin() + index1, use_pos_.begin() + index2 + 1); + // std::cout<type_->tid_ == Type::VoidTyID)); + } + + bool is_phi() { return op_id_ == PHI; } + bool is_store() { return op_id_ == Store; } + bool is_alloca() { return op_id_ == Alloca; } + bool is_ret() { return op_id_ == Ret; } + bool is_load() { return op_id_ == Load; } + bool is_br() { return op_id_ == Br; } + + bool is_add() { return op_id_ == Add; } + bool is_sub() { return op_id_ == Sub; } + bool is_mul() { return op_id_ == Mul; } + bool is_div() { return op_id_ == SDiv; } + bool is_rem() { return op_id_ == SRem; } + + bool is_fadd() { return op_id_ == FAdd; } + bool is_fsub() { return op_id_ == FSub; } + bool is_fmul() { return op_id_ == FMul; } + bool is_fdiv() { return op_id_ == FDiv; } + + bool is_cmp() { return op_id_ == ICmp; } + bool is_fcmp() { return op_id_ == FCmp; } + + bool is_call() { return op_id_ == Call; } + bool is_gep() { return op_id_ == GetElementPtr; } + bool is_zext() { return op_id_ == ZExt; } + bool is_fptosi() { return op_id_ == FPtoSI; } + bool is_sitofp() { return op_id_ == SItoFP; } + + bool is_int_binary() { + return (is_add() || is_sub() || is_mul() || is_div() || is_rem()) && + (num_ops_ == 2); + } + + bool is_float_binary() { + return (is_fadd() || is_fsub() || is_fmul() || is_fdiv()) && + (num_ops_ == 2); + } + + bool is_binary() { return is_int_binary() || is_float_binary(); } + + bool isTerminator() { return is_br() || is_ret(); } + + // ↑↑↑↑↑↑↑↑--------增加快速类型判断- + + virtual std::string print() = 0; + BasicBlock *parent_; + OpID op_id_; + unsigned num_ops_; + std::vector operands_; // operands of this value + std::vector::iterator> + use_pos_; // 与操作数数组一一对应,是对应的操作数的uselist里面,与当前指令相关的use的迭代器 + std::vector::iterator> + pos_in_bb; // 在bb的指令list的位置迭代器,最多只能有一个 +}; + +//%77 = add i32 %74, %76 +//%10 = and i1 %7, %9 +//%7 = xor i1 %6, true +//%13 = fmul float %12, 0x400921FB60000000 +class BinaryInst : public Instruction { +public: + BinaryInst(Type *ty, OpID op, Value *v1, Value *v2, BasicBlock *bb) + : Instruction(ty, op, 2, bb) { + set_operand(0, v1); + set_operand(1, v2); + } + // 只创建,不加入基本块末尾 + BinaryInst(Type *ty, OpID op, Value *v1, Value *v2, BasicBlock *bb, bool flag) + : Instruction(ty, op, 2) { + set_operand(0, v1); + set_operand(1, v2); + this->parent_ = bb; + } + virtual std::string print() override; +}; + +//%8 = zext i1 %7 to i32 +//%51 = fptosi float %50 to i32 +//%4 = sitofp i32 %3 to float +//%8 = fneg float %7 +//%3 = bitcast [4 x [2 x i32]]* %2 to i32* +class UnaryInst : public Instruction { +public: + UnaryInst(Type *ty, OpID op, Value *val, BasicBlock *bb) + : Instruction(ty, op, 1, bb) { + set_operand(0, val); + } + virtual std::string print() override; +}; + +//%18 = icmp ne i32 %12, %17 +class ICmpInst : public Instruction { +public: + enum ICmpOp { + ICMP_EQ = 32, ///< equal + ICMP_NE = 33, ///< not equal + ICMP_UGT = 34, ///< unsigned greater than + ICMP_UGE = 35, ///< unsigned greater or equal + ICMP_ULT = 36, ///< unsigned less than + ICMP_ULE = 37, ///< unsigned less or equal + ICMP_SGT = 38, ///< signed greater than + ICMP_SGE = 39, ///< signed greater or equal + ICMP_SLT = 40, ///< signed less than + ICMP_SLE = 41 ///< signed less or equal + }; + static const std::map ICmpOpName; + ICmpInst(ICmpOp op, Value *v1, Value *v2, BasicBlock *bb) + : Instruction(bb->parent_->parent_->int1_ty_, Instruction::ICmp, 2, bb), + icmp_op_(op) { + set_operand(0, v1); + set_operand(1, v2); + } + virtual std::string print() override; + ICmpOp icmp_op_; +}; + +//%5 = fcmp olt float %4, 0.000000e+00 +class FCmpInst : public Instruction { +public: + enum FCmpOp { + FCMP_FALSE = 10, // Always false (always folded) + FCMP_OEQ = 11, // True if ordered and equal + FCMP_OGT = 12, // True if ordered and greater than + FCMP_OGE = 13, // True if ordered and greater than or equal + FCMP_OLT = 14, // True if ordered and less than + FCMP_OLE = 15, // True if ordered and less than or equal + FCMP_ONE = 16, // True if ordered and operands are unequal + FCMP_ORD = 17, // True if ordered (no nans) + FCMP_UNO = 18, // True if unordered: isnan(X) | isnan(Y) + FCMP_UEQ = 19, // True if unordered or equal + FCMP_UGT = 20, // True if unordered or greater than + FCMP_UGE = 21, // True if unordered, greater than, or equal + FCMP_ULT = 22, // True if unordered or less than + FCMP_ULE = 23, // True if unordered, less than, or equal + FCMP_UNE = 24, // True if unordered or not equal + FCMP_TRUE = 25 // Always true (always folded) + }; + static const std::map FCmpOpName; + FCmpInst(FCmpOp op, Value *v1, Value *v2, BasicBlock *bb) + : Instruction(bb->parent_->parent_->int1_ty_, Instruction::FCmp, 2, bb), + fcmp_op_(op) { + set_operand(0, v1); + set_operand(1, v2); + } + virtual std::string print() override; + FCmpOp fcmp_op_; +}; + +//%111 = call i32 @QuickSort(i32* %108, i32 %109, i32 %110) +class CallInst : public Instruction { +public: + CallInst(Function *func, std::vector args, BasicBlock *bb) + : Instruction(static_cast(func->type_)->result_, + Instruction::Call, args.size() + 1, bb) { + int num_ops = args.size() + 1; + for (int i = 0; i < num_ops - 1; i++) { + set_operand(i, args[i]); + } + set_operand(num_ops - 1, func); + } + virtual std::string print() override; +}; + +// 注:br的返回值类型一定是VoidTyID +class BranchInst : public Instruction { +public: + // br i1 %7, label %8, label %9 + BranchInst(Value *cond, BasicBlock *if_true, BasicBlock *if_false, + BasicBlock *bb) + : Instruction(if_true->parent_->parent_->void_ty_, Instruction::Br, 3, + bb) { + if_true->add_pre_basic_block(bb); + if_false->add_pre_basic_block(bb); + bb->add_succ_basic_block(if_false); + bb->add_succ_basic_block(if_true); + set_operand(0, cond); + set_operand(1, if_true); + set_operand(2, if_false); + } + // br label %31 + BranchInst(BasicBlock *if_true, BasicBlock *bb) + : Instruction(if_true->parent_->parent_->void_ty_, Instruction::Br, 1, + bb) { + if_true->add_pre_basic_block(bb); + bb->add_succ_basic_block(if_true); + set_operand(0, if_true); + } + virtual std::string print() override; +}; + +// ret i32 %4 +// ret void +// 注:ret的返回值类型一定是VoidTyID +class ReturnInst : public Instruction { +public: + ReturnInst(Value *val, BasicBlock *bb) + : Instruction(bb->parent_->parent_->void_ty_, Instruction::Ret, 1, bb) { + set_operand(0, val); + } + ReturnInst(Value *val, BasicBlock *bb, bool flag) + : Instruction(bb->parent_->parent_->void_ty_, Instruction::Ret, 1) { + set_operand(0, val); + this->parent_ = bb; + } + ReturnInst(BasicBlock *bb) + : Instruction(bb->parent_->parent_->void_ty_, Instruction::Ret, 0, bb) {} + virtual std::string print() override; +}; + +//%1 = getelementptr [5 x [4 x i32]], [5 x [4 x i32]]* @a, i32 0, i32 2, i32 3 +class GetElementPtrInst : public Instruction { +public: + GetElementPtrInst(Value *ptr, std::vector idxs, BasicBlock *bb) + : Instruction(bb->parent_->parent_->get_pointer_type( + get_GEP_return_type(ptr, idxs.size())), + Instruction::GetElementPtr, idxs.size() + 1, bb) { + set_operand(0, ptr); + for (size_t i = 0; i < idxs.size(); i++) { + set_operand(i + 1, idxs[i]); + } + } + Type *get_GEP_return_type(Value *ptr, size_t idxs_size) { + Type *ty = + static_cast(ptr->type_)->contained_; //[5 x [4 x i32]] + if (ty->tid_ == Type::ArrayTyID) { + ArrayType *arr_ty = static_cast(ty); + for (size_t i = 1; i < idxs_size; i++) { + ty = arr_ty->contained_; //[4 x i32], i32 + if (ty->tid_ == Type::ArrayTyID) { + arr_ty = static_cast(ty); + } + } + } + return ty; + } + virtual std::string print() override; +}; + +// store , * +// store i32 %57, i32* %55 +// 注:store的返回值类型一定是VoidTyID +class StoreInst : public Instruction { +public: + StoreInst(Value *val, Value *ptr, BasicBlock *bb) + : Instruction(bb->parent_->parent_->void_ty_, Instruction::Store, 2, bb) { + assert(val->type_ == static_cast(ptr->type_)->contained_); + set_operand(0, val); + set_operand(1, ptr); + } + + // 创建store指令,不插入到基本块中,但是设定parent + StoreInst(Value *val, Value *ptr, BasicBlock *bb, bool) + : Instruction(bb->parent_->parent_->void_ty_, Instruction::Store, 2) { + assert(val->type_ == static_cast(ptr->type_)->contained_); + set_operand(0, val); + set_operand(1, ptr); + this->parent_ = bb; + } + + virtual std::string print() override; +}; + +// = load , * +//%60 = load i32, i32* %59 +class LoadInst : public Instruction { +public: + LoadInst(Value *ptr, BasicBlock *bb) + : Instruction(static_cast(ptr->type_)->contained_, + Instruction::Load, 1, bb) { + set_operand(0, ptr); + } + virtual std::string print() override; +}; + +//%8 = alloca i32 +class AllocaInst : public Instruction { +public: + AllocaInst(Type *ty, BasicBlock *bb) + : Instruction(bb->parent_->parent_->get_pointer_type(ty), + Instruction::Alloca, 0, bb, true), + alloca_ty_(ty) {} + + // 创建指令,不插入到最后,但是会设定parent + AllocaInst(Type *ty, BasicBlock *bb, bool) + : Instruction(bb->parent_->parent_->get_pointer_type(ty), + Instruction::Alloca, 0), + alloca_ty_(ty) { + this->parent_ = bb; + } + + virtual std::string print() override; + Type *alloca_ty_; +}; + +class ZextInst : public Instruction { +public: + ZextInst(OpID op, Value *val, Type *ty, BasicBlock *bb) + : Instruction(ty, op, 1, bb), dest_ty_(ty) { + set_operand(0, val); + } + virtual std::string print() override; + Type *dest_ty_; +}; + +class FpToSiInst : public Instruction { +public: + FpToSiInst(OpID op, Value *val, Type *ty, BasicBlock *bb) + : Instruction(ty, op, 1, bb), dest_ty_(ty) { + set_operand(0, val); + } + virtual std::string print() override; + Type *dest_ty_; +}; + +class SiToFpInst : public Instruction { +public: + SiToFpInst(OpID op, Value *val, Type *ty, BasicBlock *bb) + : Instruction(ty, op, 1, bb), dest_ty_(ty) { + set_operand(0, val); + } + virtual std::string print() override; + Type *dest_ty_; +}; + +//%3 = bitcast [4 x [2 x i32]]* %2 to i32* +class Bitcast : public Instruction { +public: + Bitcast(OpID op, Value *val, Type *ty, BasicBlock *bb) + : Instruction(ty, op, 1, bb), dest_ty_(ty) { + set_operand(0, val); + } + virtual std::string print() override; + Type *dest_ty_; +}; + +//%4 = phi i32 [ 1, %2 ], [ %6, %5 ] +class PhiInst : public Instruction { +public: + PhiInst(OpID op, std::vector vals, std::vector val_bbs, + Type *ty, BasicBlock *bb) + : Instruction(ty, op, 2 * vals.size()) { + for (int i = 0; i < vals.size(); i++) { + set_operand(2 * i, vals[i]); + set_operand(2 * i + 1, val_bbs[i]); + } + this->parent_ = bb; + } + static PhiInst *create_phi(Type *ty, BasicBlock *bb) { + std::vector vals; + std::vector val_bbs; + return new PhiInst(Instruction::PHI, vals, val_bbs, ty, bb); + } + void add_phi_pair_operand(Value *val, Value *pre_bb) { + this->add_operand(val); + this->add_operand(pre_bb); + } + virtual std::string print() override; + + Value *l_val_; +}; + +//-----------------------------------------------IRStmtBuilder----------------------------------------------- +class IRStmtBuilder { +public: + BasicBlock *BB_; + Module *m_; + + IRStmtBuilder(BasicBlock *bb, Module *m) : BB_(bb), m_(m){}; + ~IRStmtBuilder() = default; + Module *get_module() { return m_; } + BasicBlock *get_insert_block() { return this->BB_; } + void set_insert_point(BasicBlock *bb) { + this->BB_ = bb; + } // 在某个基本块中插入指令 + BinaryInst *create_iadd(Value *v1, Value *v2) { + return new BinaryInst(this->m_->int32_ty_, Instruction::Add, v1, v2, + this->BB_); + } // 创建加法指令(以及其他算术指令) + BinaryInst *create_isub(Value *v1, Value *v2) { + return new BinaryInst(this->m_->int32_ty_, Instruction::Sub, v1, v2, + this->BB_); + } + BinaryInst *create_imul(Value *v1, Value *v2) { + return new BinaryInst(this->m_->int32_ty_, Instruction::Mul, v1, v2, + this->BB_); + } + BinaryInst *create_isdiv(Value *v1, Value *v2) { + return new BinaryInst(this->m_->int32_ty_, Instruction::SDiv, v1, v2, + this->BB_); + } + BinaryInst *create_isrem(Value *v1, Value *v2) { + return new BinaryInst(this->m_->int32_ty_, Instruction::SRem, v1, v2, + this->BB_); + } + + ICmpInst *create_icmp_eq(Value *v1, Value *v2) { + return new ICmpInst(ICmpInst::ICMP_EQ, v1, v2, this->BB_); + } + ICmpInst *create_icmp_ne(Value *v1, Value *v2) { + return new ICmpInst(ICmpInst::ICMP_NE, v1, v2, this->BB_); + } + ICmpInst *create_icmp_gt(Value *v1, Value *v2) { + return new ICmpInst(ICmpInst::ICMP_SGT, v1, v2, this->BB_); + } + ICmpInst *create_icmp_ge(Value *v1, Value *v2) { + return new ICmpInst(ICmpInst::ICMP_SGE, v1, v2, this->BB_); + } + ICmpInst *create_icmp_lt(Value *v1, Value *v2) { + return new ICmpInst(ICmpInst::ICMP_SLT, v1, v2, this->BB_); + } + ICmpInst *create_icmp_le(Value *v1, Value *v2) { + return new ICmpInst(ICmpInst::ICMP_SLE, v1, v2, this->BB_); + } + + BinaryInst *create_fadd(Value *v1, Value *v2) { + return new BinaryInst(this->m_->float32_ty_, Instruction::FAdd, v1, v2, + this->BB_); + } + BinaryInst *create_fsub(Value *v1, Value *v2) { + return new BinaryInst(this->m_->float32_ty_, Instruction::FSub, v1, v2, + this->BB_); + } + BinaryInst *create_fmul(Value *v1, Value *v2) { + return new BinaryInst(this->m_->float32_ty_, Instruction::FMul, v1, v2, + this->BB_); + } + BinaryInst *create_fdiv(Value *v1, Value *v2) { + return new BinaryInst(this->m_->float32_ty_, Instruction::FDiv, v1, v2, + this->BB_); + } + + FCmpInst *create_fcmp_eq(Value *v1, Value *v2) { + return new FCmpInst(FCmpInst::FCMP_UEQ, v1, v2, this->BB_); + } + FCmpInst *create_fcmp_ne(Value *v1, Value *v2) { + return new FCmpInst(FCmpInst::FCMP_UNE, v1, v2, this->BB_); + } + FCmpInst *create_fcmp_gt(Value *v1, Value *v2) { + return new FCmpInst(FCmpInst::FCMP_UGT, v1, v2, this->BB_); + } + FCmpInst *create_fcmp_ge(Value *v1, Value *v2) { + return new FCmpInst(FCmpInst::FCMP_UGE, v1, v2, this->BB_); + } + FCmpInst *create_fcmp_lt(Value *v1, Value *v2) { + return new FCmpInst(FCmpInst::FCMP_ULT, v1, v2, this->BB_); + } + FCmpInst *create_fcmp_le(Value *v1, Value *v2) { + return new FCmpInst(FCmpInst::FCMP_ULE, v1, v2, this->BB_); + } + + CallInst *create_call(Value *func, std::vector args) { +#ifdef DEBUG + assert(dynamic_cast(func) && "func must be Function * type"); +#endif + return new CallInst(static_cast(func), args, this->BB_); + } + + BranchInst *create_br(BasicBlock *if_true) { + return new BranchInst(if_true, this->BB_); + } + BranchInst *create_cond_br(Value *cond, BasicBlock *if_true, + BasicBlock *if_false) { + return new BranchInst(cond, if_true, if_false, this->BB_); + } + + ReturnInst *create_ret(Value *val) { return new ReturnInst(val, this->BB_); } + ReturnInst *create_void_ret() { return new ReturnInst(this->BB_); } + + GetElementPtrInst *create_gep(Value *ptr, std::vector idxs) { + return new GetElementPtrInst(ptr, idxs, this->BB_); + } + + StoreInst *create_store(Value *val, Value *ptr) { + return new StoreInst(val, ptr, this->BB_); + } + LoadInst *create_load(Type *ty, Value *ptr) { + return new LoadInst(ptr, this->BB_); + } + LoadInst *create_load(Value *ptr) { +#ifdef DEBUG + assert(ptr->get_type()->is_pointer_type() && "ptr must be pointer type"); +#endif + // return LoadInst::create_load(ptr->get_type()->get_pointer_element_type(), + // ptr, this->BB_); + return new LoadInst(ptr, this->BB_); + } + + AllocaInst *create_alloca(Type *ty) { return new AllocaInst(ty, this->BB_); } + ZextInst *create_zext(Value *val, Type *ty) { + return new ZextInst(Instruction::ZExt, val, ty, this->BB_); + } + FpToSiInst *create_fptosi(Value *val, Type *ty) { + return new FpToSiInst(Instruction::FPtoSI, val, ty, this->BB_); + } + SiToFpInst *create_sitofp(Value *val, Type *ty) { + return new SiToFpInst(Instruction::SItoFP, val, ty, this->BB_); + } + Bitcast *create_bitcast(Value *val, Type *ty) { + return new Bitcast(Instruction::BitCast, val, ty, this->BB_); + } +}; diff --git a/compiler/src/main.cpp b/compiler/src/main.cpp new file mode 100644 index 0000000..279285b --- /dev/null +++ b/compiler/src/main.cpp @@ -0,0 +1,108 @@ +#include "CombineInstr.h" +#include "ConstSpread.h" +#include "LoopInvariant.h" +#include "SimplifyJump.h" +#include "ast.h" +#include "backend.h" +#include "define.h" +#include "genIR.h" +#include "DeleteDeadCode.h" +#include "opt.h" +#include +#include +#include +#include + +extern unique_ptr root; +extern int yyparse(); +extern FILE *yyin; + +int main(int argc, char **argv) { + // Assert the number of arguments + assert(argc >= 2); + + // TODO: advanced argument parser + char *filename = nullptr; + int print_ir = false; + int print_asm = false; + + std::string output = "-"; + + int opt; + bool isO2 = false; + while ((opt = getopt(argc, argv, "Sco:O::")) != -1) { + switch (opt) { + case 'S': + print_asm = true; + print_ir = false; + break; + case 'c': + print_ir = true; + print_asm = false; + break; + case 'o': + output = optarg; + break; + case 'O': + isO2 = true; + break; + default: + break; + } + } + filename = argv[optind]; + + yyin = fopen(filename, "r"); + if (yyin == nullptr) { + std::cout << "yyin open" << filename << "failed" << std::endl; + return -1; + } + + // Frontend parser + yyparse(); + + // Generate IR from AST + GenIR genIR; + root->accept(genIR); + std::unique_ptr m = genIR.getModule(); + + // Run IR optimization + // TODO + if (isO2) { + std::vector Opt; + Opt.push_back(new DeadCodeDeletion(m.get())); + Opt.push_back(new ConstSpread(m.get())); + Opt.push_back(new CombineInstr(m.get())); + Opt.push_back(new DomainTree(m.get())); + Opt.push_back(new SimplifyJump(m.get())); + Opt.push_back(new LoopInvariant(m.get())); + Opt.push_back(new SimplifyJump(m.get())); + for (auto x : Opt) + x->execute(); + } + + // Open output file + std::ofstream fout; + std::ostream *out; + if (output == "-") { + out = &std::cout; + } else { + fout.open(output); + out = &fout; + } + + // Print IR result + const std::string IR = m->print(); + if (print_ir) { + *out << IR << std::endl; + } + + // Generate assembly file + // TODO + if (print_asm) { + auto builder = new RiscvBuilder(); + const std::string RiscvCode = builder->buildRISCV(m.get()); + *out << RiscvCode << std::endl; + } + return 0; +} diff --git a/compiler/src/opt/BasicOperation.cpp b/compiler/src/opt/BasicOperation.cpp new file mode 100644 index 0000000..7fe0af3 --- /dev/null +++ b/compiler/src/opt/BasicOperation.cpp @@ -0,0 +1,54 @@ +#include "BasicOperation.h" + +void deleteUse(Value *opnd, Instruction *inst) { + for (auto it = opnd->use_list_.begin(); it != opnd->use_list_.end(); ++it) + if (it->val_ == inst) { + opnd->use_list_.erase(it); + return; + } +} + +void SolvePhi(BasicBlock *bb, BasicBlock *suc) { + std::vector uselessPhi; + for (auto instr : suc->instr_list_) { + if (instr->op_id_ == Instruction::PHI) { + for (int i = 1; i < instr->num_ops_; i = i + 2) + if (instr->get_operand(i) == bb) { + instr->remove_operands(i - 1, i); + break; + } + if (instr->parent_->pre_bbs_.size() == 1) { + Value *only = instr->get_operand(0); + instr->replace_all_use_with(only); + uselessPhi.push_back(instr); + } + } + } + for (auto instr : uselessPhi) + suc->delete_instr(instr); +} + +void dfsGraph(BasicBlock *bb, std::set &vis) { + if (!bb) + return; + vis.insert(bb); + for (auto suc : bb->succ_bbs_) { + if (vis.find(suc) == vis.end()) + dfsGraph(suc, vis); + } +} + +void DeleteUnusedBB(Function *func) { + std::set vis; + for (auto bb : func->basic_blocks_) + if (bb->name_ == "label_entry") { + dfsGraph(bb, vis); + break; + } + for (auto bb : func->basic_blocks_) + if (vis.find(bb) == vis.end()) { + bb->parent_->remove_bb(bb); + for (auto suc : bb->succ_bbs_) + SolvePhi(bb, suc); + } +} diff --git a/compiler/src/opt/BasicOperation.h b/compiler/src/opt/BasicOperation.h new file mode 100644 index 0000000..3ee2696 --- /dev/null +++ b/compiler/src/opt/BasicOperation.h @@ -0,0 +1,15 @@ +#ifndef BASICOPERATION +#define BASICOPERATION +#include "../ir/ir.h" +#include +#include +#include +#include +#include "opt.h" + +void deleteUse(Value* opnd,Instruction *inst); +void dfsGraph(BasicBlock *bb, std::set &vis); +void SolvePhi(BasicBlock *bb, BasicBlock *succ_bb); +void DeleteUnusedBB(Function *func); + +#endif // !BASICOPERATION \ No newline at end of file diff --git a/compiler/src/opt/CMakeLists.txt b/compiler/src/opt/CMakeLists.txt new file mode 100644 index 0000000..1091000 --- /dev/null +++ b/compiler/src/opt/CMakeLists.txt @@ -0,0 +1,6 @@ +set(SOURCE_FILES ConstSpread.cpp BasicOperation.cpp LoopInvariant.cpp CombineInstr.cpp SimplifyJump.cpp opt.cpp DeleteDeadCode.cpp) + +add_library(opt ${SOURCE_FILES}) + +target_link_libraries(opt PRIVATE ir) +target_include_directories(opt PRIVATE ${CMAKE_SOURCE_DIR}/src/ir) \ No newline at end of file diff --git a/compiler/src/opt/CombineInstr.cpp b/compiler/src/opt/CombineInstr.cpp new file mode 100644 index 0000000..cf4e276 --- /dev/null +++ b/compiler/src/opt/CombineInstr.cpp @@ -0,0 +1,95 @@ +#include "CombineInstr.h" +#include + +void CombineInstr::execute() { + for (auto foo : m->function_list_) + if (!foo->basic_blocks_.empty()) + for (BasicBlock *bb : foo->basic_blocks_) + checkBlock(bb); +} + +void CombineInstr::checkBlock(BasicBlock *bb) { + bool change = true; + while (change) { + change = false; + for (auto instr : bb->instr_list_) { + if (instr->op_id_ != Instruction::Add && + instr->op_id_ != Instruction::Sub) + continue; + if (instr->use_list_.size() != 1 || instr->use_list_.back().arg_no_ != 0) + continue; + Instruction *nextInstr = + dynamic_cast(instr->use_list_.back().val_); + if (nextInstr == nullptr || instr->op_id_ != nextInstr->op_id_ || + instr->parent_ != nextInstr->parent_) + continue; + std::unordered_map Optime; + Instruction *StartInstr = instr, *EndInstr = nullptr; + Instruction *invalidStart = nullptr, *invalidEnd = nullptr; // 无效指令 + bool isRepeat = false; + Value *dupOp = nullptr, *Candi0 = instr->get_operand(0), + *Candi1 = instr->get_operand(1); + Optime[Candi0]++; + Optime[Candi1]++; + Optime[nextInstr->get_operand(1)]++; + // 迭代过程 + instr = nextInstr; + while (instr->use_list_.size() == 1 && + instr->use_list_.back().arg_no_ == 0) { + nextInstr = dynamic_cast(instr->use_list_.back().val_); + if (nextInstr == nullptr || instr->op_id_ != nextInstr->op_id_ || + instr->parent_ != nextInstr->parent_) + break; + if (!isRepeat) { + if (Optime.find(nextInstr->get_operand(1)) != Optime.end()) + isRepeat = true; + EndInstr = instr; + invalidStart = nextInstr; + } else if (Optime.find(nextInstr->get_operand(1)) == Optime.end()) + break; + Optime[nextInstr->get_operand(1)]++; + instr = nextInstr; + } + invalidEnd = instr; + // 尝试合并:1相同,很多0;0相同,很多1都可以合并 + unsigned int dupTime = 0; + if (Optime[Candi1] == 1 && Optime[Candi0] > 1) { + dupOp = Candi0; + dupTime = Optime[Candi0]; + } else if (Optime[Candi0] == 1 && Optime[Candi1] > 1) { + dupOp = Candi1; + dupTime = Optime[Candi1]; + } else + continue; + for (auto p : Optime) { + if (p.second == 1) { + if (p.first != dupOp) { + dupTime = 0; + break; + } + } else { + if (dupTime != p.second) { + dupTime = 0; + break; + } + } + } + if (!dupTime) + continue; + ConstantInt *dupTimeConst = + new ConstantInt(instr->parent_->parent_->parent_->int32_ty_, dupTime); + Instruction *toMulInst = new BinaryInst( + bb->parent_->parent_->int32_ty_, Instruction::Mul, + static_cast(EndInstr), dupTimeConst, bb, true); + toMulInst->name_ = invalidStart->name_; + bb->add_instruction_before_inst(toMulInst, invalidStart); + invalidEnd->replace_all_use_with(toMulInst); + for (Instruction *ins = invalidStart; ins != nextInstr;) { + bb->delete_instr(ins); + ins = dynamic_cast(ins->use_list_.back().val_); + } + change = true; + break; + } + } +} \ No newline at end of file diff --git a/compiler/src/opt/CombineInstr.h b/compiler/src/opt/CombineInstr.h new file mode 100644 index 0000000..6b1dc2e --- /dev/null +++ b/compiler/src/opt/CombineInstr.h @@ -0,0 +1,13 @@ +#ifndef COMBINEINSTRH +#define COMBINEINSTRH +#include "opt.h" + +class CombineInstr : public Optimization { + +public: + CombineInstr(Module *m) : Optimization(m) {} + void execute(); + void checkBlock(BasicBlock *bb); +}; + +#endif // !COMBINEINSTRH \ No newline at end of file diff --git a/compiler/src/opt/ConstSpread.cpp b/compiler/src/opt/ConstSpread.cpp new file mode 100644 index 0000000..7aa59a2 --- /dev/null +++ b/compiler/src/opt/ConstSpread.cpp @@ -0,0 +1,354 @@ +#include "ConstSpread.h" + +ConstantInt *ConstSpread::CalcInt(Instruction::OpID op, ConstantInt *v1, + ConstantInt *v2) { + int a = v1->value_, b = v2->value_; + switch (op) { + case Instruction::Add: + return new ConstantInt(m->int32_ty_, a + b); + case Instruction::Sub: + return new ConstantInt(m->int32_ty_, a - b); + case Instruction::Mul: + return new ConstantInt(m->int32_ty_, a * b); + case Instruction::SDiv: + return new ConstantInt(m->int32_ty_, a / b); + case Instruction::SRem: + return new ConstantInt(m->int32_ty_, a % b); + case Instruction::Shl: + return new ConstantInt(m->int32_ty_, a << b); + case Instruction::LShr: + return new ConstantInt(m->int32_ty_, (unsigned)a >> b); + case Instruction::AShr: + return new ConstantInt(m->int32_ty_, a >> b); + case Instruction::And: + return new ConstantInt(m->int32_ty_, a & b); + case Instruction::Or: + return new ConstantInt(m->int32_ty_, a | b); + case Instruction::Xor: + return new ConstantInt(m->int32_ty_, a ^ b); + default: + return nullptr; + } +} + +ConstantFloat *ConstSpread::CalcFloat(Instruction::OpID op, ConstantFloat *v1, + ConstantFloat *v2) { + float a = v1->value_, b = v2->value_; + switch (op) { + case Instruction::FAdd: + return new ConstantFloat(m->float32_ty_, a + b); + case Instruction::FSub: + return new ConstantFloat(m->float32_ty_, a - b); + case Instruction::FMul: + return new ConstantFloat(m->float32_ty_, a * b); + case Instruction::FDiv: + return new ConstantFloat(m->float32_ty_, a / b); + default: + return nullptr; + } +} + +ConstantInt *ConstSpread::CalcICMP(ICmpInst::ICmpOp op, ConstantInt *v1, + ConstantInt *v2) { + int lhs = v1->value_; + int rhs = v2->value_; + switch (op) { + case ICmpInst::ICMP_EQ: + return new ConstantInt(m->int1_ty_, lhs == rhs); + case ICmpInst::ICMP_NE: + return new ConstantInt(m->int1_ty_, lhs != rhs); + case ICmpInst::ICMP_SGT: + return new ConstantInt(m->int1_ty_, lhs > rhs); + case ICmpInst::ICMP_SGE: + return new ConstantInt(m->int1_ty_, lhs >= rhs); + case ICmpInst::ICMP_SLE: + return new ConstantInt(m->int1_ty_, lhs <= rhs); + case ICmpInst::ICMP_SLT: + return new ConstantInt(m->int1_ty_, lhs < rhs); + case ICmpInst::ICMP_UGE: + return new ConstantInt(m->int1_ty_, (unsigned)lhs >= (unsigned)rhs); + case ICmpInst::ICMP_ULE: + return new ConstantInt(m->int1_ty_, (unsigned)lhs <= (unsigned)rhs); + case ICmpInst::ICMP_ULT: + return new ConstantInt(m->int1_ty_, (unsigned)lhs < (unsigned)rhs); + case ICmpInst::ICMP_UGT: + return new ConstantInt(m->int1_ty_, (unsigned)lhs > (unsigned)rhs); + default: + return nullptr; + } +} +ConstantInt *ConstSpread::CalcFCMP(FCmpInst::FCmpOp op, ConstantFloat *v1, + ConstantFloat *v2) { + float lhs = v1->value_; + float rhs = v2->value_; + switch (op) { + case FCmpInst::FCMP_UEQ: + return new ConstantInt(m->int1_ty_, lhs == rhs); + case FCmpInst::FCMP_UNE: + return new ConstantInt(m->int1_ty_, lhs != rhs); + case FCmpInst::FCMP_UGT: + return new ConstantInt(m->int1_ty_, lhs > rhs); + case FCmpInst::FCMP_UGE: + return new ConstantInt(m->int1_ty_, lhs >= rhs); + case FCmpInst::FCMP_ULE: + return new ConstantInt(m->int1_ty_, lhs <= rhs); + case FCmpInst::FCMP_ULT: + return new ConstantInt(m->int1_ty_, lhs < rhs); + case FCmpInst::FCMP_FALSE: + return new ConstantInt(m->int1_ty_, 0); + case FCmpInst::FCMP_TRUE: + return new ConstantInt(m->int1_ty_, 1); + case FCmpInst::FCMP_OEQ: + return new ConstantInt(m->int1_ty_, lhs == rhs); + case FCmpInst::FCMP_ONE: + return new ConstantInt(m->int1_ty_, lhs != rhs); + case FCmpInst::FCMP_OGE: + return new ConstantInt(m->int1_ty_, lhs >= rhs); + case FCmpInst::FCMP_OGT: + return new ConstantInt(m->int1_ty_, lhs > rhs); + case FCmpInst::FCMP_OLE: + return new ConstantInt(m->int1_ty_, lhs <= rhs); + case FCmpInst::FCMP_OLT: + return new ConstantInt(m->int1_ty_, lhs < rhs); + default: + return nullptr; + } +} + +void ConstSpread::execute() { + assert(m != nullptr); + for (Function *foo : m->function_list_) { + if (foo->basic_blocks_.size()) { + bool change = true; + while (change) { + change = false; + change |= SpreadingConst(foo); + change |= BranchProcess(foo); + DeleteUnusedBB(foo); + } + } + } +} + +bool ConstSpread::SpreadingConst(Function *func) { + uselessInstr.clear(); + for (auto bb : func->basic_blocks_) { + ConstIntMap.clear(); + ConstFloatMap.clear(); + for (auto instr : bb->instr_list_) { + ConstantInt *testConstInta = nullptr, *testConstIntb = nullptr; + ConstantFloat *testConstFloata = nullptr, *testConstFloatb = nullptr; + switch (instr->op_id_) { + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::SDiv: + case Instruction::UDiv: + case Instruction::SRem: + case Instruction::URem: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + case Instruction::Shl: + case Instruction::AShr: + case Instruction::LShr: + testConstInta = dynamic_cast(instr->get_operand(0)); + testConstIntb = dynamic_cast(instr->get_operand(1)); + if (testConstInta && testConstIntb) { + auto intRes = + this->CalcInt(instr->op_id_, testConstInta, testConstIntb); + if (intRes) { + instr->replace_all_use_with(intRes); + uselessInstr[instr] = bb; + } + } + break; + case Instruction::ICmp: + testConstInta = dynamic_cast(instr->get_operand(0)); + testConstIntb = dynamic_cast(instr->get_operand(1)); + if (testConstInta && testConstIntb) { + auto res = this->CalcICMP(dynamic_cast(instr)->icmp_op_, + testConstInta, testConstIntb); + if (res) { + instr->replace_all_use_with(res); + uselessInstr[instr] = bb; + } + } + break; + case Instruction::FCmp: + testConstFloata = dynamic_cast(instr->get_operand(0)); + testConstFloatb = dynamic_cast(instr->get_operand(1)); + if (testConstFloata && testConstFloatb) { + auto res = this->CalcFCMP(dynamic_cast(instr)->fcmp_op_, + testConstFloata, testConstFloatb); + if (res) { + instr->replace_all_use_with(res); + uselessInstr[instr] = bb; + } + } + break; + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FMul: + case Instruction::FDiv: + testConstFloata = dynamic_cast(instr->get_operand(0)); + testConstFloatb = dynamic_cast(instr->get_operand(1)); + if (testConstFloata && testConstFloatb) { + auto floaRes = + this->CalcFloat(instr->op_id_, testConstFloata, testConstFloatb); + if (floaRes) { + instr->replace_all_use_with(floaRes); + uselessInstr[instr] = bb; + } + } + break; + case Instruction::FNeg: + testConstFloata = dynamic_cast(instr->get_operand(0)); + if (testConstFloata) { + instr->replace_all_use_with( + new ConstantFloat(m->float32_ty_, -testConstFloata->value_)); + uselessInstr[instr] = bb; + } + break; + case Instruction::FPtoSI: + testConstFloata = dynamic_cast(instr->get_operand(0)); + if (testConstFloata) { + instr->replace_all_use_with( + new ConstantInt(m->int32_ty_, testConstFloata->value_)); + uselessInstr[instr] = bb; + } + break; + case Instruction::SItoFP: + testConstInta = dynamic_cast(instr->get_operand(0)); + if (testConstInta) { + instr->replace_all_use_with( + new ConstantFloat(m->float32_ty_, testConstInta->value_)); + uselessInstr[instr] = bb; + } + break; + case Instruction::ZExt: + testConstInta = dynamic_cast(instr->get_operand(0)); + if (testConstInta) { + instr->replace_all_use_with( + new ConstantInt(m->int32_ty_, testConstInta->value_)); + uselessInstr[instr] = bb; + } + break; + case Instruction::Call: + ConstIntMap.clear(); + ConstFloatMap.clear(); + case Instruction::Load: { + auto globalVar = dynamic_cast(instr->get_operand(0)); + if (globalVar) { + auto iterInt = ConstIntMap.find(globalVar); + auto iterFloat = ConstFloatMap.find(globalVar); + if (iterInt != ConstIntMap.end()) { + instr->replace_all_use_with(iterInt->second); + uselessInstr[instr] = bb; + } else if (iterFloat != ConstFloatMap.end()) { + instr->replace_all_use_with(iterFloat->second); + uselessInstr[instr] = bb; + } + } else if (dynamic_cast(instr->get_operand(0))) { + auto pos = dynamic_cast(instr->get_operand(0)); + if (pos->alloca_ty_->tid_ == Type::IntegerTyID) { + auto iterInt = ConstIntMap.find(pos); + if (iterInt != ConstIntMap.end()) { + instr->replace_all_use_with(iterInt->second); + uselessInstr[instr] = bb; + } + } else if (pos->alloca_ty_->tid_ == Type::FloatTyID) { + auto iterFloat = ConstFloatMap.find(pos); + if (iterFloat != ConstFloatMap.end()) { + instr->replace_all_use_with(iterFloat->second); + uselessInstr[instr] = bb; + } + } + } + } break; + case Instruction::Store: { + // std::cout << "EVER STORE\n"; + auto storePos = instr->get_operand(1); + auto storeValInt = dynamic_cast(instr->get_operand(0)); + auto storeValFloat = + dynamic_cast(instr->get_operand(0)); + if (storeValInt) { + auto iter1 = ConstIntMap.find(storePos); + if (iter1 != ConstIntMap.end()) { + if (iter1->second->value_ == storeValInt->value_) + uselessInstr[instr] = bb; + else + iter1->second = storeValInt; + } else + ConstIntMap[storePos] = storeValInt; + } else if (storeValFloat) { + auto iter = ConstFloatMap.find(storePos); + if (iter != ConstFloatMap.end()) { + if (iter->second->value_ == storeValInt->value_) + uselessInstr[instr] = bb; + else + iter->second = storeValFloat; + } else + ConstFloatMap[storePos] = storeValFloat; + } else { + // 非常量存储,则该地址数据不再是常量 + auto iterInt = ConstIntMap.find(storePos); + auto iterFloat = ConstFloatMap.find(storePos); + if (iterInt != ConstIntMap.end()) + ConstIntMap.erase(iterInt); + if (iterFloat != ConstFloatMap.end()) + ConstFloatMap.erase(iterFloat); + } + } break; + default: + break; + } + } + } + if (!uselessInstr.empty()) { + for (auto [instr, bb] : uselessInstr) + bb->delete_instr(instr); + return true; + } + return false; +} + +bool ConstSpread::BranchProcess(Function *func) { + bool change = false; + for (auto bb : func->basic_blocks_) { + auto br = bb->get_terminator(); + if (!br) + continue; + if (br->op_id_ == Instruction::Br && + dynamic_cast(br)->num_ops_ == 3) { + auto cond = dynamic_cast(br->get_operand(0)); + auto truebb = br->get_operand(1); + auto falsebb = br->get_operand(2); + if (!cond) + continue; + change = true; + if (cond->value_ == 0) { + bb->delete_instr(br); + for (auto succ_bb : bb->succ_bbs_) { + succ_bb->remove_pre_basic_block(bb); + if (succ_bb != falsebb) { + SolvePhi(bb, succ_bb); + } + } + bb->succ_bbs_.clear(); + new BranchInst(dynamic_cast(falsebb), bb); + } else { + bb->delete_instr(br); + for (auto succ_bb : bb->succ_bbs_) { + succ_bb->remove_pre_basic_block(bb); + if (succ_bb != truebb) { + SolvePhi(bb, succ_bb); + } + } + bb->succ_bbs_.clear(); + new BranchInst(dynamic_cast(truebb), bb); + } + } + } + return change; +} \ No newline at end of file diff --git a/compiler/src/opt/ConstSpread.h b/compiler/src/opt/ConstSpread.h new file mode 100644 index 0000000..c3ff9ff --- /dev/null +++ b/compiler/src/opt/ConstSpread.h @@ -0,0 +1,23 @@ +#ifndef CONSTSPREAD +#define CONSTSPREAD +#include "../ir/ir.h" +#include "BasicOperation.h" +#include "opt.h" + +class ConstSpread : public Optimization { +public: + ConstSpread(Module *m_) : Optimization(m_) {} + void execute(); + ConstantInt *CalcInt(Instruction::OpID op, ConstantInt *v1, ConstantInt *v2); + ConstantFloat *CalcFloat(Instruction::OpID op, ConstantFloat *v1, + ConstantFloat *v2); + ConstantInt *CalcICMP(ICmpInst::ICmpOp op, ConstantInt *v1, ConstantInt *v2); + ConstantInt *CalcFCMP(FCmpInst::FCmpOp op, ConstantFloat *v1, ConstantFloat *v2); + bool SpreadingConst(Function *func); + bool BranchProcess(Function *func); + std::map ConstIntMap; + std::map ConstFloatMap; + std::map uselessInstr; +}; + +#endif // !CONSTSPREAD \ No newline at end of file diff --git a/compiler/src/opt/DeleteDeadCode.cpp b/compiler/src/opt/DeleteDeadCode.cpp new file mode 100644 index 0000000..71c4b99 --- /dev/null +++ b/compiler/src/opt/DeleteDeadCode.cpp @@ -0,0 +1,180 @@ +#include "DeleteDeadCode.h" +#include "ConstSpread.h" + +std::set OptFunc = {"getint", "getfloat", + "getch", "getarray", + "getfarray", "putint", + "putfloat", "putch", + "putarray", "putfarray", + "_sysy_starttime", "_sysy_stoptime", + "memcpy", "memclr", + "memset", "llvm.memset.p0.i32", + "__aeabi_memcpy4", "__aeabi_memclr4", + "__aeabi_memset4"}; + +void DeadCodeDeletion::initFuncPtrArg() { + for (auto foo : m->function_list_) { + if (foo->basic_blocks_.empty()) + continue; + for (auto arg : foo->arguments_) + if (arg->type_->tid_ == Type::PointerTyID) { + if (!funcPtrArgs.count(foo)) + funcPtrArgs[foo] = {}; + funcPtrArgs[foo].insert(arg); + } + } +} +void DeadCodeDeletion::Init(Function *foo) { + storePos.clear(); + for (auto bb : foo->basic_blocks_) { + for (auto ins : bb->instr_list_) { + if (ins->op_id_ == Instruction::GetElementPtr) { + } else if (ins->op_id_ == Instruction::Store) { + if (!storePos.count(ins->get_operand(1))) { + storePos.insert({ins->get_operand(1), {}}); + } + storePos[ins->get_operand(1)].push_back(ins); + if (dynamic_cast(ins->get_operand(1))) + OptFunc.insert(foo->name_); + if (dynamic_cast(ins->get_operand(1))) + OptFunc.insert(foo->name_); + if (funcPtrArgs[foo].count(ins->get_operand(1))) + OptFunc.insert(foo->name_); + } else if (ins->op_id_ == Instruction::Call) { + auto f = ins->get_operand(ins->operands_.size() - 1); + if (OptFunc.count(f->name_)) + OptFunc.insert(foo->name_); + } + } + } +} +bool DeadCodeDeletion::checkOpt(Function *foo, Instruction *ins) { + if (ins->op_id_ == Instruction::Ret) { + exitBlock = ins->parent_; + return true; + } else if (ins->op_id_ == Instruction::Call) { + auto f = ins->get_operand(ins->operands_.size() - 1); + return OptFunc.count(f->name_); + } else if (ins->op_id_ == Instruction::Store) { + if (dynamic_cast(ins->get_operand(1))) + return true; + if (dynamic_cast(ins->get_operand(1))) + return true; + if (funcPtrArgs[foo].count(ins->get_operand(1))) + return true; + return false; + } + return false; +} + +void DeadCodeDeletion::findInstr(Function *foo) { + std::list workList; + for (auto bb : foo->basic_blocks_) { + for (auto ins : bb->instr_list_) { + if (checkOpt(foo, ins)) { + uselessInstr.insert(ins); + workList.push_back(ins); + } + } + } + while (!workList.empty()) { + auto ins = dynamic_cast(workList.back()); + workList.pop_back(); + if (ins == nullptr) { + continue; + } + for (auto operand : ins->operands_) { + auto temp = dynamic_cast(operand); + if (!temp) + continue; + if (uselessInstr.insert(temp).second) { + workList.push_back(temp); + } + } + if (ins->op_id_ == Instruction::PHI) { + for (int i = 1; i < ins->operands_.size(); i += 2) { + auto bb = dynamic_cast(ins->get_operand(i)); + auto br = bb->get_terminator(); + if (uselessInstr.insert(br).second) { + workList.push_back(br); + } + } + } + if (storePos.count(ins)) { + for (auto curInstr : storePos[ins]) { + if (uselessInstr.insert(dynamic_cast(curInstr)).second) { + workList.push_back(curInstr); + } + } + storePos.erase(ins); + } + if (uselessBlock.insert(ins->parent_).second) { + for (auto RFrontier : ins->parent_->rdom_frontier_) { + auto t = RFrontier->get_terminator(); + if (uselessInstr.insert(t).second) { + workList.push_back(t); + } + } + } + } +} +void DeadCodeDeletion::deleteInstr(Function *foo) { + int deleteCnt = 0, changeCnt = 0; + for (auto bb : foo->basic_blocks_) { + std::vector ins2Del; + for (auto ins : bb->instr_list_) { + if (!uselessInstr.count(ins)) { + if (ins->op_id_ != Instruction::Br) { + ins2Del.push_back(ins); + } else { + if (ins->operands_.size() == 3) { + changeCnt++; + auto trueBB = dynamic_cast(ins->get_operand(1)); + auto falseBB = dynamic_cast(ins->get_operand(2)); + trueBB->remove_pre_basic_block(bb); + falseBB->remove_pre_basic_block(bb); + bb->remove_succ_basic_block(trueBB); + bb->remove_succ_basic_block(falseBB); + BasicBlock *temp = exitBlock; + std::vector rdoms(bb->rdoms_.begin(), + bb->rdoms_.end()); + std::sort(rdoms.begin(), rdoms.end(), + [=](BasicBlock *x, BasicBlock *y) -> bool { + return x->rdoms_.count(y); + }); + for (auto rdbb : rdoms) { + if (rdbb != bb && uselessBlock.count(rdbb)) { + temp = rdbb; + break; + } + } + ins->remove_operands(0, 2); + ins->num_ops_ = 1; + ins->operands_.resize(1); + ins->use_pos_.resize(1); + ins->set_operand(0, temp); + bb->add_succ_basic_block(temp); + temp->add_pre_basic_block(bb); + } + } + } + } + deleteCnt += ins2Del.size(); + for (auto ins : ins2Del) { + bb->delete_instr(ins); + } + } +} + +void DeadCodeDeletion::execute() { + ReverseDomainTree reverseDomainTree(m); + reverseDomainTree.execute(); + initFuncPtrArg(); + for (auto foo : m->function_list_) + if (!foo->basic_blocks_.empty()) { + Init(foo); + findInstr(foo); + deleteInstr(foo); + DeleteUnusedBB(foo); + } +} diff --git a/compiler/src/opt/DeleteDeadCode.h b/compiler/src/opt/DeleteDeadCode.h new file mode 100644 index 0000000..fe0e1fb --- /dev/null +++ b/compiler/src/opt/DeleteDeadCode.h @@ -0,0 +1,25 @@ +#ifndef DELETEDEADCODEH +#define DELETEDEADCODEH + +#include "opt.h" + +extern std::set sysLibFunc; + +class DeadCodeDeletion : public Optimization { + std::map> funcPtrArgs; + std::map> storePos; + BasicBlock *exitBlock; + std::set uselessInstr; + std::set uselessBlock; + +public: + DeadCodeDeletion(Module *m) : Optimization(m), exitBlock(nullptr) {} + void execute(); + void initFuncPtrArg(); + void Init(Function *foo); + bool checkOpt(Function *foo, Instruction *instr); + void findInstr(Function *foo); + void deleteInstr(Function *foo); +}; + +#endif // !DELETEDEADCODEH \ No newline at end of file diff --git a/compiler/src/opt/LoopInvariant.cpp b/compiler/src/opt/LoopInvariant.cpp new file mode 100644 index 0000000..5230177 --- /dev/null +++ b/compiler/src/opt/LoopInvariant.cpp @@ -0,0 +1,149 @@ +#include "LoopInvariant.h" + +void LoopInvariant::execute() { + searchLoop(); + while (!loopStack.empty()) { + auto loop = loopStack.top(); + loopStack.pop(); + std::set assignVals; + std::set visInstr; // 标记下这条语句是不是被操作过 + std::vector invarInstrs; // 存在不变量的语句集合 + std::map instrPos; + for (auto bb : *loop) + for (Instruction *inst : bb->instr_list_) + // 赋值语句做操作 + if (inst->is_binary() || inst->is_cmp() || inst->is_fcmp() || + inst->is_call() || inst->is_phi() || inst->is_zext() || + inst->is_fptosi() || inst->is_sitofp() || inst->is_gep() || + inst->is_load()) + assignVals.insert(inst); + bool changed = true; + while (changed) { + changed = false; + for (auto bb : *loop) { + for (auto instr : bb->instr_list_) { + if (visInstr.find(instr) != visInstr.end()) + continue; + if (!instr->is_gep() && !instr->is_alloca() && !instr->is_br() && + !instr->is_ret() && !instr->is_phi() && !instr->is_store() && + !instr->is_load() && + !(instr->is_call() && + instr->get_operand(instr->num_ops_ - 1)->print() != "rand")) { + bool move = true; + // 一个操作数不是不变量就不能动 + for (unsigned int i = 0; i < instr->num_ops_; i++) + if (assignVals.find(instr->get_operand(i)) != assignVals.end()) + move = false; + if (move) { + instrPos[instr] = bb; + invarInstrs.push_back(instr); + assignVals.erase(instr); + visInstr.insert(instr); + changed = true; + } + } + } + } + } + auto enter = entryPos[loop]; + for (auto prev : enter->pre_bbs_) + if (loop->find(prev) == loop->end()) + for (auto inst : invarInstrs) + prev->add_instruction_before_terminator(inst); + } +} + +void LoopInvariant::searchLoop() { + for (auto foo : m->function_list_) { + if (foo->basic_blocks_.empty()) + continue; + std::set nodes; + std::set entry; + std::set *> SCCs; + std::map nodeMap; + for (auto bb : foo->basic_blocks_) { + auto cur = new node(bb, -1, -1, 0); + nodeMap[bb] = cur; + nodes.insert(cur); + } + for (auto bb : foo->basic_blocks_) { + auto BlockNode = nodeMap[bb]; + for (auto suc : bb->succ_bbs_) + BlockNode->suc.insert(nodeMap[suc]); + for (auto pre : bb->succ_bbs_) + BlockNode->pre.insert(nodeMap[pre]); + } + + while (LoopInvariant::searchSCC(nodes, SCCs)) { + for (auto SCC : SCCs) { + node *enter = nullptr; + for (auto curBlock : *SCC) + for (auto pre : curBlock->pre) + if (SCC->find(pre) == SCC->end()) + enter = curBlock; + else if (entry.find(pre) != entry.end()) + enter = pre; + + auto curLoop = new std::set; + for (auto curBlock : *SCC) + curLoop->insert(curBlock->bb); + entryPos[curLoop] = enter->bb; + loopStack.push(curLoop); + entry.insert(enter); + nodes.erase(enter); + for (auto pre : enter->pre) + pre->suc.erase(enter); + for (auto suc : enter->suc) + suc->pre.erase(enter); + } + for (auto SCC : SCCs) + SCC->clear(); + SCCs.clear(); + for (auto NodeBlock : nodes) + NodeBlock = new node(nullptr, -1, -1, false); + } + for (auto node : nodes) + delete node; + } +} + +bool LoopInvariant::searchSCC(std::set &basicBlocks, + std::set *> &SCCs) { + ind = 0; + while (!tarjanStack.empty()) + tarjanStack.pop(); + for (auto cur : basicBlocks) + if (cur->dfn == -1) + tarjan(cur, SCCs); + return SCCs.size() != 0; +} + +void LoopInvariant::tarjan(node *cur, std::set *> &SCCs) { + cur->dfn = cur->low = ++ind; + cur->inStack = true; + tarjanStack.push(cur); + for (auto succ : cur->suc) + if (succ->dfn == -1) { + tarjan(succ, SCCs); + if (succ->low < cur->low) + cur->low = succ->low; + } else if (succ->inStack && succ->low < cur->low) + cur->low = succ->low; + // 找到low=dfn的,出现强连通分量 + if (cur->dfn == cur->low) { + if (cur == tarjanStack.top()) { + tarjanStack.pop(); + cur->inStack = false; + return; + } + auto SCC = new std::set; + node *tp = nullptr; + do { + tp = tarjanStack.top(); + SCC->insert(tp); + tarjanStack.pop(); + tp->inStack = false; + } while (tp != cur); + SCCs.insert(SCC); + } +} \ No newline at end of file diff --git a/compiler/src/opt/LoopInvariant.h b/compiler/src/opt/LoopInvariant.h new file mode 100644 index 0000000..dec8635 --- /dev/null +++ b/compiler/src/opt/LoopInvariant.h @@ -0,0 +1,31 @@ +#ifndef LOOPH +#define LOOPH + +#include "BasicOperation.h" + +struct node { + BasicBlock *bb; + std::set pre; + std::set suc; + int dfn, low; + bool inStack; + node() = default; + node(BasicBlock *bb_, int dfn_, int low_, bool inStack_) + : bb(bb_), dfn(dfn_), low(low_), inStack(inStack_) {} +}; + +class LoopInvariant : public Optimization { + int ind; + std::stack tarjanStack; + std::stack *> loopStack; + std::map *, BasicBlock *> entryPos; + +public: + LoopInvariant(Module *m) : Optimization(m) {} + void execute(); + void searchLoop(); + bool searchSCC(std::set &basicBlock, std::set *> &SCCs); + void tarjan(node *pos, std::set *> &SCCs); +}; + +#endif // !LOOPH \ No newline at end of file diff --git a/compiler/src/opt/SimplifyJump.cpp b/compiler/src/opt/SimplifyJump.cpp new file mode 100644 index 0000000..7fee0ba --- /dev/null +++ b/compiler/src/opt/SimplifyJump.cpp @@ -0,0 +1,120 @@ +#include "SimplifyJump.h" + +void SimplifyJump::execute() { + for (auto foo : m->function_list_) + if (foo->basic_blocks_.empty()) { + deleteUnReachableBlock(foo); + mergePreBlock(foo); + deleteUselessPhi(foo); + deleteUselessJump(foo); + } +} + +void SimplifyJump::deleteUselessBlock(Function *foo, + std::vector &uselessBlock) { + for (auto bb : uselessBlock) + foo->remove_bb(bb); +} + +bool SimplifyJump::checkUselessJump(BasicBlock *bb) { + auto JumpPos = bb->get_terminator()->get_operand(0); + for (auto preBB : bb->pre_bbs_) { + auto br = preBB->get_terminator(); + if (br->operands_.size() == 1) + continue; + auto trueBB = br->get_operand(1); + auto falseBB = br->get_operand(2); + if (trueBB == JumpPos || falseBB == JumpPos) + return false; + } + return true; +} + +void SimplifyJump::deleteUnReachableBlock(Function *foo) { + std::vector uselessBlock; + for (int i = 2; i < foo->basic_blocks_.size(); i++) { + auto curbb = foo->basic_blocks_[i]; + if (curbb->pre_bbs_.empty()) { + uselessBlock.push_back(curbb); + // 发现无用块后需要提前进行phi合流处理 + for (auto use : curbb->use_list_) { + auto instr = dynamic_cast(use.val_); + if (instr != nullptr) + instr->remove_operands(use.arg_no_ - 1, use.arg_no_); + } + } + } +} + +void SimplifyJump::mergePreBlock(Function *foo) { + std::vector uselessBlock; + for (int i = 2; i < foo->basic_blocks_.size(); i++) { + auto bb = foo->basic_blocks_[i]; + if (bb->pre_bbs_.size() == 1) { + auto preBlock = *bb->pre_bbs_.begin(); + auto preBr = preBlock->get_terminator(); + if (preBlock->succ_bbs_.size() != 1) + continue; + preBlock->delete_instr(preBr); + for (auto instr : bb->instr_list_) { + preBlock->add_instruction(instr); + bb->remove_instr(instr); + } + preBlock->remove_succ_basic_block(bb); + for (auto suc : bb->succ_bbs_) { + preBlock->add_succ_basic_block(suc); + suc->remove_pre_basic_block(bb); + suc->add_pre_basic_block(preBlock); + } + bb->replace_all_use_with(preBlock); + uselessBlock.push_back(bb); + } + } + deleteUselessBlock(foo, uselessBlock); +} + +void SimplifyJump::deleteUselessPhi(Function *foo) { + for (auto bb : foo->basic_blocks_) + if (bb->pre_bbs_.size() == 1) + for (auto instr : bb->instr_list_) + if (instr->is_phi()) { + instr->replace_all_use_with(instr->get_operand(0)); + bb->delete_instr(instr); + } +} + +void SimplifyJump::deleteUselessJump(Function *foo) { + std::vector uselessBlock; + for (int i = 2; i < foo->basic_blocks_.size(); i++) { + BasicBlock *curbb = foo->basic_blocks_[i]; + if (curbb->instr_list_.size() != 1) + continue; + auto branchInstr = curbb->get_terminator(); + if (branchInstr->operands_.size() != 1 || branchInstr->is_ret()) + continue; + if (!checkUselessJump(curbb)) + continue; + uselessBlock.push_back(curbb); + auto JumpTarget = dynamic_cast(branchInstr->get_operand(0)); + for (auto instr : JumpTarget->instr_list_) + if (instr->is_phi()) { + for (int i = 1; i < instr->operands_.size(); i += 2) { + if (instr->get_operand(i) == curbb) { + auto val = instr->get_operand(i - 1); + instr->remove_operands(i - 1, i); + for (auto preBB : curbb->pre_bbs_) { + instr->add_operand(val); + instr->add_operand(preBB); + } + break; + } + } + } + curbb->replace_all_use_with(JumpTarget); + for (auto preBB : curbb->pre_bbs_) { + preBB->add_succ_basic_block(JumpTarget); + JumpTarget->add_pre_basic_block(preBB); + } + } + deleteUselessBlock(foo, uselessBlock); +} \ No newline at end of file diff --git a/compiler/src/opt/SimplifyJump.h b/compiler/src/opt/SimplifyJump.h new file mode 100644 index 0000000..a477ce5 --- /dev/null +++ b/compiler/src/opt/SimplifyJump.h @@ -0,0 +1,19 @@ +#ifndef SIMPLIFYJUMPH +#define SIMPLIFYJUMPH +#include "opt.h" + +class SimplifyJump : public Optimization { + +public: + SimplifyJump(Module *m) : Optimization(m) {} + void execute(); + void deleteUselessBlock(Function *foo, + std::vector &uselessBlock); + bool checkUselessJump(BasicBlock *bb); + void deleteUselessPhi(Function *foo); + void deleteUselessJump(Function *foo); + void mergePreBlock(Function *foo); + void deleteUnReachableBlock(Function *foo); +}; + +#endif // !SIMPLIFYJUMPH \ No newline at end of file diff --git a/compiler/src/opt/opt.cpp b/compiler/src/opt/opt.cpp new file mode 100644 index 0000000..96f5880 --- /dev/null +++ b/compiler/src/opt/opt.cpp @@ -0,0 +1,206 @@ +#include "opt.h" +#include +#include + +void DomainTree::execute() { + for (auto foo : m->function_list_) + if (!foo->basic_blocks_.empty()) { + getBlockDom(foo); + getBlockDomFront(foo); + } +} + +bool DomainTree::isLoopEdge(BasicBlock *a, BasicBlock *b) { + return TraverseInd[a] > TraverseInd[b]; +} + +std::vector DomainTree::postTraverse(BasicBlock *bb) { + std::set vis; + std::vector ans; + std::function dfs = [&](BasicBlock *place) { + vis.insert(place); + for (auto child : place->succ_bbs_) + if (vis.find(child) == vis.end()) + dfs(child); + ans.push_back(place); + }; + dfs(bb); + return ans; +} + +void DomainTree::getReversePostTraverse(Function *f) { + doms.clear(); + reversePostTraverse.clear(); + TraverseInd.clear(); + auto entryBlock = *f->basic_blocks_.begin(); + auto seq = postTraverse(entryBlock); + std::reverse(reversePostTraverse.begin(), reversePostTraverse.end()); + for (int i = 0; i < seq.size(); i++) + TraverseInd[seq[i]] = i; + reversePostTraverse = seq; +} + +void DomainTree::getBlockDom(Function *f) { + getReversePostTraverse(f); + auto root = *f->basic_blocks_.begin(); + auto root_id = TraverseInd[root]; + doms.resize(root_id + 1, nullptr); + doms.back() = root; + bool change = true; + while (change) { + change = false; + for (auto bb : reversePostTraverse) + if (bb != root) { + auto preds = bb->pre_bbs_; + BasicBlock *curDom = nullptr; + for (auto pred_bb : preds) + if (doms[TraverseInd[pred_bb]] != nullptr) { + curDom = pred_bb; + break; + } + for (auto pred_bb : preds) + if (doms[TraverseInd[pred_bb]] != nullptr) + curDom = intersect(pred_bb, curDom); + if (doms[TraverseInd[bb]] != curDom) { + doms[TraverseInd[bb]] = curDom; + change = true; + } + } + } + for (auto bb : reversePostTraverse) + bb->idom_ = doms[TraverseInd[bb]]; +} + +void DomainTree::getBlockDomFront(Function *foo) { + for (auto b : foo->basic_blocks_) { + auto b_pred = b->pre_bbs_; + if (b_pred.size() >= 2) { + for (auto pred : b_pred) { + auto runner = pred; + while (runner != doms[TraverseInd[b]]) { + runner->dom_frontier_.insert(b); + runner = doms[TraverseInd[runner]]; + } + } + } + } +} + +BasicBlock *DomainTree::intersect(BasicBlock *b1, BasicBlock *b2) { + auto head1 = b1; + auto head2 = b2; + while (head1 != head2) { + while (TraverseInd[head1] < TraverseInd[head2]) + head1 = doms[TraverseInd[head1]]; + while (TraverseInd[head2] < TraverseInd[head1]) + head2 = doms[TraverseInd[head2]]; + } + return head1; +} + +void ReverseDomainTree::execute() { + for (auto f : m->function_list_) + if (!f->basic_blocks_.empty()) { + for (auto bb : f->basic_blocks_) { + bb->rdoms_.clear(); + bb->rdom_frontier_.clear(); + } + getBlockDomR(f); + getBlockDomFrontR(f); + getBlockRdoms(f); + } +} + +void ReverseDomainTree::getPostTraverse(BasicBlock *bb, + std::set &visited) { + visited.insert(bb); + for (auto parent : bb->pre_bbs_) + if (visited.find(parent) == visited.end()) + getPostTraverse(parent, visited); + reverseTraverseInd[bb] = reverseTraverse.size(); + reverseTraverse.push_back(bb); +} + +void ReverseDomainTree::getReversePostTraverse(Function *f) { + reverseDomainBlock.clear(); + reverseTraverse.clear(); + reverseTraverseInd.clear(); + for (auto bb : f->basic_blocks_) { + auto terminate_instr = bb->get_terminator(); + if (terminate_instr->op_id_ == Instruction::Ret) { + exitBlock = bb; + break; + } + } + assert(exitBlock != nullptr); + std::set visited = {}; + getPostTraverse(exitBlock, visited); + reverse(reverseTraverse.begin(), reverseTraverse.end()); +} + +void ReverseDomainTree::getBlockDomR(Function *f) { + getReversePostTraverse(f); + auto root = exitBlock; + auto root_id = reverseTraverseInd[root]; + for (int i = 0; i < root_id; i++) + reverseDomainBlock.push_back(nullptr); + reverseDomainBlock.push_back(root); + bool change = true; + while (change) { + change = false; + for (auto bb : reverseTraverse) { + if (bb != root) { + BasicBlock *new_irdom = nullptr; + for (auto rpred_bb : bb->succ_bbs_) + if (reverseDomainBlock[reverseTraverseInd[rpred_bb]] != nullptr) { + new_irdom = rpred_bb; + break; + } + for (auto rpred_bb : bb->succ_bbs_) + if (reverseDomainBlock[reverseTraverseInd[rpred_bb]] != nullptr) + new_irdom = intersect(rpred_bb, new_irdom); + if (reverseDomainBlock[reverseTraverseInd[bb]] != new_irdom) { + reverseDomainBlock[reverseTraverseInd[bb]] = new_irdom; + change = true; + } + } + } + } +} +void ReverseDomainTree::getBlockRdoms(Function *f) { + for (auto bb : f->basic_blocks_) { + if (bb == exitBlock) + continue; + auto current = bb; + while (current != exitBlock) { + bb->rdoms_.insert(current); + current = reverseDomainBlock[reverseTraverseInd[current]]; + } + } +} +void ReverseDomainTree::getBlockDomFrontR(Function *f) { + for (auto bb_iter = f->basic_blocks_.rbegin(); + bb_iter != f->basic_blocks_.rend(); bb_iter++) { + auto bb = *bb_iter; + if (bb->succ_bbs_.size() >= 2) { + for (auto rpred : bb->succ_bbs_) { + auto runner = rpred; + while (runner != reverseDomainBlock[reverseTraverseInd[bb]]) { + runner->rdom_frontier_.insert(bb); + runner = reverseDomainBlock[reverseTraverseInd[runner]]; + } + } + } + } +} +BasicBlock *ReverseDomainTree::intersect(BasicBlock *b1, BasicBlock *b2) { + auto head1 = b1; + auto head2 = b2; + while (head1 != head2) { + while (reverseTraverseInd[head1] < reverseTraverseInd[head2]) + head1 = reverseDomainBlock[reverseTraverseInd[head1]]; + while (reverseTraverseInd[head2] < reverseTraverseInd[head1]) + head2 = reverseDomainBlock[reverseTraverseInd[head2]]; + } + return head1; +} diff --git a/compiler/src/opt/opt.h b/compiler/src/opt/opt.h new file mode 100644 index 0000000..b43b4bb --- /dev/null +++ b/compiler/src/opt/opt.h @@ -0,0 +1,46 @@ +// Currently a dummy file +#ifndef OPTH +#define OPTH + +#include "ir.h" + +class Optimization { +public: + Module *m; + explicit Optimization(Module *m_) : m(m_) {} + virtual void execute() = 0; +}; + +class DomainTree : public Optimization { + std::vector reversePostTraverse; + std::map TraverseInd; + std::vector doms; + +public: + DomainTree(Module *m) : Optimization(m) {} + void execute(); + void getReversePostTraverse(Function *foo); + std::vector postTraverse(BasicBlock *bb); + void getBlockDom(Function *foo); + void getBlockDomFront(Function *foo); + BasicBlock *intersect(BasicBlock *b1, BasicBlock *b2); + bool isLoopEdge(BasicBlock *a, BasicBlock *b); +}; + +class ReverseDomainTree : public Optimization { + std::map reverseTraverseInd; + std::vector reverseDomainBlock; + std::vector reverseTraverse; + BasicBlock *exitBlock; + +public: + ReverseDomainTree(Module *m) : Optimization(m), exitBlock(nullptr) {} + void execute(); + BasicBlock *intersect(BasicBlock *b1, BasicBlock *b2); + void getReversePostTraverse(Function *foo); + void getBlockDomR(Function *foo); + void getBlockRdoms(Function *foo); + void getBlockDomFrontR(Function *foo); + void getPostTraverse(BasicBlock *bb, std::set &visited); +}; +#endif // !OPTH \ No newline at end of file diff --git a/compiler/src/parser/CMakeLists.txt b/compiler/src/parser/CMakeLists.txt new file mode 100644 index 0000000..ee796f0 --- /dev/null +++ b/compiler/src/parser/CMakeLists.txt @@ -0,0 +1,22 @@ +# Require Flex & Bison as generator +# find_package(FLEX 2.5.4 REQUIRED) +# find_package(BISON 2.4.1 REQUIRED) + +set(PARSER_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +# set(PARSER_DIR "${CMAKE_CURRENT_BINARY_DIR}") + +set(LEXER_CPP "${PARSER_DIR}/tokens.cpp") +set(LEXER_DEF "${PARSER_DIR}/tokens.hpp") +set(PARSER_CPP "${PARSER_DIR}/parser.cpp") +set(PARSER_DEF "${PARSER_DIR}/parser.hpp") + +# Generate tokenizer & parser via Flex & Bison +# flex_target(LEXER "tokens.l" "${LEXER_CPP}" DEFINES_FILE "${LEXER_DEF}") +# bison_target(PARSER "parser.y" "${PARSER_CPP}" DEFINES_FILE "${PARSER_DEF}") +# add_flex_bison_dependency(LEXER PARSER) + +set(SOURCE_FILES "${LEXER_CPP}" "${PARSER_CPP}" "ast.cpp") +set(PARSER_INCLUDE ${PARSER_DIR} ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) + +add_library(parser STATIC ${SOURCE_FILES}) +target_include_directories(parser PRIVATE "${PARSER_INCLUDE}") diff --git a/compiler/src/parser/ast.cpp b/compiler/src/parser/ast.cpp new file mode 100644 index 0000000..699b72f --- /dev/null +++ b/compiler/src/parser/ast.cpp @@ -0,0 +1,49 @@ +#include "ast.h" + +void CompUnitAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void DeclDefAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void DefAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void DeclAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void InitValAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void FuncDefAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void FuncFParamAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void BlockAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void StmtAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void ReturnStmtAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void SelectStmtAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void IterationStmtAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void AddExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void MulExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void UnaryExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void PrimaryExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void NumberAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void CallAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void LValAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void RelExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void EqExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void LAndExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void LOrExpAST::accept(Visitor &visitor) { visitor.visit(*this); } + +void BlockItemAST::accept(Visitor &visitor) { visitor.visit(*this); } diff --git a/compiler/src/parser/ast.h b/compiler/src/parser/ast.h new file mode 100644 index 0000000..bd3f0f1 --- /dev/null +++ b/compiler/src/parser/ast.h @@ -0,0 +1,297 @@ +#pragma once + +#include "define.h" +#include +#include +#include +#include +#include + +using namespace std; +class BaseAST; + +class CompUnitAST; +class DeclDefAST; +class DeclAST; +class DefListAST; +class DefAST; +class ArraysAST; +class InitValListAST; +class InitValAST; +class FuncDefAST; +class FuncFParamListAST; +class FuncFParamAST; +class BlockAST; +class BlockItemListAST; +class BlockItemAST; +class StmtAST; +class ReturnStmtAST; +class SelectStmtAST; +class IterationStmtAST; +class LValAST; +class PrimaryExpAST; +class NumberAST; +class UnaryExpAST; +class CallAST; +class FuncCParamListAST; +class MulExpAST; +class AddExpAST; +class RelExpAST; +class EqExpAST; +class LAndExpAST; +class LOrExpAST; + +class Visitor; + +class BaseAST { +public: + virtual void accept(Visitor &visitor) = 0; + BaseAST() = default; + virtual ~BaseAST() = default; +}; + +class CompUnitAST : public BaseAST { +public: + vector> declDefList; + void accept(Visitor &visitor) override; +}; + +class DeclDefAST : public BaseAST { +public: + unique_ptr Decl = nullptr; + unique_ptr funcDef = nullptr; + void accept(Visitor &visitor) override; +}; + +class DeclAST : public BaseAST { +public: + TYPE bType = TYPE_VOID; + bool isConst = false; + vector> defList; + void accept(Visitor &visitor) override; +}; + +class DefListAST { +public: + vector> list; +}; + +class DefAST : public BaseAST { +public: + unique_ptr id; + vector> arrays; + unique_ptr initVal; + void accept(Visitor &visitor) override; +}; + +class ArraysAST { +public: + vector> list; +}; + +class InitValAST : public BaseAST { +public: + unique_ptr exp; + vector> initValList; + void accept(Visitor &visitor) override; +}; + +class InitValListAST { +public: + vector> list; +}; + +class FuncDefAST : public BaseAST { +public: + TYPE funcType = TYPE_VOID; + unique_ptr id; + vector> funcFParamList; + unique_ptr block = nullptr; + void accept(Visitor &visitor) override; +}; + +class FuncFParamListAST { +public: + vector> list; +}; + +class FuncFParamAST : public BaseAST { +public: + TYPE bType; + unique_ptr id; + bool isArray = + false; // 用于区分是否是数组参数,此时一维数组和多维数组expArrays都是empty + vector> arrays; + void accept(Visitor &visitor) override; +}; + +class BlockAST : public BaseAST { +public: + vector> blockItemList; + void accept(Visitor &visitor) override; +}; + +class BlockItemListAST { +public: + vector> list; +}; + +class BlockItemAST : public BaseAST { +public: + unique_ptr decl = nullptr; + unique_ptr stmt = nullptr; + void accept(Visitor &visitor) override; +}; + +class StmtAST : public BaseAST { +public: + STYPE sType; + unique_ptr lVal = nullptr; + unique_ptr exp = nullptr; + unique_ptr returnStmt = nullptr; + unique_ptr selectStmt = nullptr; + unique_ptr iterationStmt = nullptr; + unique_ptr block = nullptr; + void accept(Visitor &visitor) override; +}; + +class ReturnStmtAST : public BaseAST { +public: + unique_ptr exp = nullptr; + void accept(Visitor &visitor) override; +}; + +class SelectStmtAST : public BaseAST { +public: + unique_ptr cond; + unique_ptr ifStmt, elseStmt; + void accept(Visitor &visitor) override; +}; + +class IterationStmtAST : public BaseAST { +public: + unique_ptr cond; + unique_ptr stmt; + void accept(Visitor &visitor) override; +}; + +class AddExpAST : public BaseAST { +public: + unique_ptr addExp; + unique_ptr mulExp; + AOP op; + void accept(Visitor &visitor) override; +}; + +class MulExpAST : public BaseAST { +public: + unique_ptr unaryExp; + unique_ptr mulExp; + MOP op; + void accept(Visitor &visitor) override; +}; + +class UnaryExpAST : public BaseAST { +public: + unique_ptr primaryExp; + unique_ptr call; + unique_ptr unaryExp; + UOP op; + void accept(Visitor &visitor) override; +}; + +class PrimaryExpAST : public BaseAST { +public: + unique_ptr exp; + unique_ptr lval; + unique_ptr number; + void accept(Visitor &visitor) override; +}; + +class NumberAST : public BaseAST { +public: + bool isInt; + union { + int intval; + float floatval; + }; + void accept(Visitor &visitor) override; +}; + +class LValAST : public BaseAST { +public: + unique_ptr id; + vector> arrays; + void accept(Visitor &visitor) override; +}; + +class CallAST : public BaseAST { +public: + unique_ptr id; + vector> funcCParamList; + void accept(Visitor &visitor) override; +}; + +class FuncCParamListAST { +public: + vector> list; +}; + +class RelExpAST : public BaseAST { +public: + unique_ptr addExp; + unique_ptr relExp; + ROP op; + void accept(Visitor &visitor) override; +}; + +class EqExpAST : public BaseAST { +public: + unique_ptr relExp; + unique_ptr eqExp; + EOP op; + void accept(Visitor &visitor) override; +}; + +class LAndExpAST : public BaseAST { +public: + // lAndExp不为空则说明有and符号,or类似 + unique_ptr eqExp; + unique_ptr lAndExp; + void accept(Visitor &visitor) override; +}; + +class LOrExpAST : public BaseAST { +public: + unique_ptr lOrExp; + unique_ptr lAndExp; + void accept(Visitor &visitor) override; +}; + +class Visitor { +public: + virtual void visit(CompUnitAST &ast) = 0; + virtual void visit(DeclDefAST &ast) = 0; + virtual void visit(DeclAST &ast) = 0; + virtual void visit(DefAST &ast) = 0; + virtual void visit(InitValAST &ast) = 0; + virtual void visit(FuncDefAST &ast) = 0; + virtual void visit(FuncFParamAST &ast) = 0; + virtual void visit(BlockAST &ast) = 0; + virtual void visit(BlockItemAST &ast) = 0; + virtual void visit(StmtAST &ast) = 0; + virtual void visit(ReturnStmtAST &ast) = 0; + virtual void visit(SelectStmtAST &ast) = 0; + virtual void visit(IterationStmtAST &ast) = 0; + virtual void visit(AddExpAST &ast) = 0; + virtual void visit(MulExpAST &ast) = 0; + virtual void visit(UnaryExpAST &ast) = 0; + virtual void visit(PrimaryExpAST &ast) = 0; + virtual void visit(LValAST &ast) = 0; + virtual void visit(NumberAST &ast) = 0; + virtual void visit(CallAST &ast) = 0; + virtual void visit(RelExpAST &ast) = 0; + virtual void visit(EqExpAST &ast) = 0; + virtual void visit(LAndExpAST &ast) = 0; + virtual void visit(LOrExpAST &ast) = 0; +}; diff --git a/compiler/src/parser/define.h b/compiler/src/parser/define.h new file mode 100644 index 0000000..a485993 --- /dev/null +++ b/compiler/src/parser/define.h @@ -0,0 +1,15 @@ +#pragma once + +enum STYPE { SEMI, ASS, EXP, CONT, BRE, RET, BLK, SEL, ITER }; + +enum UOP { UOP_ADD, UOP_MINUS, UOP_NOT }; + +enum AOP { AOP_ADD, AOP_MINUS }; + +enum MOP { MOP_MUL, MOP_DIV, MOP_MOD }; + +enum ROP { ROP_GTE, ROP_LTE, ROP_GT, ROP_LT }; + +enum EOP { EOP_EQ, EOP_NEQ }; + +enum TYPE { TYPE_VOID, TYPE_INT, TYPE_FLOAT }; diff --git a/compiler/src/parser/parser.cpp b/compiler/src/parser/parser.cpp new file mode 100644 index 0000000..56a7d7e --- /dev/null +++ b/compiler/src/parser/parser.cpp @@ -0,0 +1,2761 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output, and Bison version. */ +#define YYBISON 30802 + +/* Bison version string. */ +#define YYBISON_VERSION "3.8.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + + + +/* First part of user prologue. */ +#line 4 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + + #include "ast.h" + #include "define.h" + #include + #include + #include + using namespace std; + unique_ptr root; /* the top level root node of our final AST */ + + extern int yylineno; + extern int yylex(); + extern void yyerror(const char *s); + extern void initFileName(char *name); + char filename[100]; + +#line 87 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +#include "parser.hpp" +/* Symbol kind. */ +enum yysymbol_kind_t +{ + YYSYMBOL_YYEMPTY = -2, + YYSYMBOL_YYEOF = 0, /* "end of file" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_INT = 3, /* INT */ + YYSYMBOL_FLOAT = 4, /* FLOAT */ + YYSYMBOL_ID = 5, /* ID */ + YYSYMBOL_GTE = 6, /* GTE */ + YYSYMBOL_LTE = 7, /* LTE */ + YYSYMBOL_GT = 8, /* GT */ + YYSYMBOL_LT = 9, /* LT */ + YYSYMBOL_EQ = 10, /* EQ */ + YYSYMBOL_NEQ = 11, /* NEQ */ + YYSYMBOL_INTTYPE = 12, /* INTTYPE */ + YYSYMBOL_FLOATTYPE = 13, /* FLOATTYPE */ + YYSYMBOL_VOID = 14, /* VOID */ + YYSYMBOL_CONST = 15, /* CONST */ + YYSYMBOL_RETURN = 16, /* RETURN */ + YYSYMBOL_IF = 17, /* IF */ + YYSYMBOL_ELSE = 18, /* ELSE */ + YYSYMBOL_WHILE = 19, /* WHILE */ + YYSYMBOL_BREAK = 20, /* BREAK */ + YYSYMBOL_CONTINUE = 21, /* CONTINUE */ + YYSYMBOL_LP = 22, /* LP */ + YYSYMBOL_RP = 23, /* RP */ + YYSYMBOL_LB = 24, /* LB */ + YYSYMBOL_RB = 25, /* RB */ + YYSYMBOL_LC = 26, /* LC */ + YYSYMBOL_RC = 27, /* RC */ + YYSYMBOL_COMMA = 28, /* COMMA */ + YYSYMBOL_SEMICOLON = 29, /* SEMICOLON */ + YYSYMBOL_NOT = 30, /* NOT */ + YYSYMBOL_ASSIGN = 31, /* ASSIGN */ + YYSYMBOL_MINUS = 32, /* MINUS */ + YYSYMBOL_ADD = 33, /* ADD */ + YYSYMBOL_MUL = 34, /* MUL */ + YYSYMBOL_DIV = 35, /* DIV */ + YYSYMBOL_MOD = 36, /* MOD */ + YYSYMBOL_AND = 37, /* AND */ + YYSYMBOL_OR = 38, /* OR */ + YYSYMBOL_LOWER_THEN_ELSE = 39, /* LOWER_THEN_ELSE */ + YYSYMBOL_YYACCEPT = 40, /* $accept */ + YYSYMBOL_Program = 41, /* Program */ + YYSYMBOL_CompUnit = 42, /* CompUnit */ + YYSYMBOL_DeclDef = 43, /* DeclDef */ + YYSYMBOL_Decl = 44, /* Decl */ + YYSYMBOL_BType = 45, /* BType */ + YYSYMBOL_VoidType = 46, /* VoidType */ + YYSYMBOL_DefList = 47, /* DefList */ + YYSYMBOL_Def = 48, /* Def */ + YYSYMBOL_Arrays = 49, /* Arrays */ + YYSYMBOL_InitVal = 50, /* InitVal */ + YYSYMBOL_InitValList = 51, /* InitValList */ + YYSYMBOL_FuncDef = 52, /* FuncDef */ + YYSYMBOL_FuncFParamList = 53, /* FuncFParamList */ + YYSYMBOL_FuncFParam = 54, /* FuncFParam */ + YYSYMBOL_Block = 55, /* Block */ + YYSYMBOL_BlockItemList = 56, /* BlockItemList */ + YYSYMBOL_BlockItem = 57, /* BlockItem */ + YYSYMBOL_Stmt = 58, /* Stmt */ + YYSYMBOL_SelectStmt = 59, /* SelectStmt */ + YYSYMBOL_IterationStmt = 60, /* IterationStmt */ + YYSYMBOL_ReturnStmt = 61, /* ReturnStmt */ + YYSYMBOL_Exp = 62, /* Exp */ + YYSYMBOL_Cond = 63, /* Cond */ + YYSYMBOL_LVal = 64, /* LVal */ + YYSYMBOL_PrimaryExp = 65, /* PrimaryExp */ + YYSYMBOL_Number = 66, /* Number */ + YYSYMBOL_UnaryExp = 67, /* UnaryExp */ + YYSYMBOL_Call = 68, /* Call */ + YYSYMBOL_UnaryOp = 69, /* UnaryOp */ + YYSYMBOL_FuncCParamList = 70, /* FuncCParamList */ + YYSYMBOL_MulExp = 71, /* MulExp */ + YYSYMBOL_AddExp = 72, /* AddExp */ + YYSYMBOL_RelExp = 73, /* RelExp */ + YYSYMBOL_EqExp = 74, /* EqExp */ + YYSYMBOL_LAndExp = 75, /* LAndExp */ + YYSYMBOL_LOrExp = 76 /* LOrExp */ +}; +typedef enum yysymbol_kind_t yysymbol_kind_t; + + + + +#ifdef short +# undef short +#endif + +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + and (if available) are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif +#endif + +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; +#else +typedef short yytype_int16; +#endif + +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + . */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + + +/* Stored state numbers (used for stacks). */ +typedef yytype_uint8 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YY_USE(E) ((void) (E)) +#else +# define YY_USE(E) /* empty */ +#endif + +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) + +#if 1 + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* 1 */ + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yy_state_t yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \ + + YYSIZEOF (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 13 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 225 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 40 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 37 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 91 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 161 + +/* YYMAXUTOK -- Last valid token kind. */ +#define YYMAXUTOK 294 + + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK \ + ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ + : YYSYMBOL_YYUNDEF) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_int8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39 +}; + +#if YYDEBUG +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_int16 yyrline[] = +{ + 0, 124, 124, 130, 134, 141, 145, 152, 158, 167, + 170, 176, 182, 186, 193, 199, 204, 209, 216, 220, + 228, 232, 235, 242, 246, 253, 260, 266, 273, 282, + 286, 293, 299, 305, 315, 318, 325, 329, 336, 340, + 347, 351, 357, 362, 366, 370, 375, 380, 385, 393, + 398, 407, 415, 419, 425, 431, 437, 441, 449, 453, + 457, 464, 469, 477, 481, 485, 493, 497, 505, 508, + 511, 517, 521, 528, 532, 538, 544, 553, 557, 563, + 572, 576, 582, 588, 594, 603, 607, 613, 622, 626, + 634, 638 +}; +#endif + +/** Accessing symbol of state STATE. */ +#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) + +#if 1 +/* The user-facing name of the symbol whose (internal) number is + YYSYMBOL. No bounds checking. */ +static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; + +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of file\"", "error", "\"invalid token\"", "INT", "FLOAT", "ID", + "GTE", "LTE", "GT", "LT", "EQ", "NEQ", "INTTYPE", "FLOATTYPE", "VOID", + "CONST", "RETURN", "IF", "ELSE", "WHILE", "BREAK", "CONTINUE", "LP", + "RP", "LB", "RB", "LC", "RC", "COMMA", "SEMICOLON", "NOT", "ASSIGN", + "MINUS", "ADD", "MUL", "DIV", "MOD", "AND", "OR", "LOWER_THEN_ELSE", + "$accept", "Program", "CompUnit", "DeclDef", "Decl", "BType", "VoidType", + "DefList", "Def", "Arrays", "InitVal", "InitValList", "FuncDef", + "FuncFParamList", "FuncFParam", "Block", "BlockItemList", "BlockItem", + "Stmt", "SelectStmt", "IterationStmt", "ReturnStmt", "Exp", "Cond", + "LVal", "PrimaryExp", "Number", "UnaryExp", "Call", "UnaryOp", + "FuncCParamList", "MulExp", "AddExp", "RelExp", "EqExp", "LAndExp", + "LOrExp", YY_NULLPTR +}; + +static const char * +yysymbol_name (yysymbol_kind_t yysymbol) +{ + return yytname[yysymbol]; +} +#endif + +#define YYPACT_NINF (-127) + +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) + +#define YYTABLE_NINF (-1) + +#define yytable_value_is_error(Yyn) \ + 0 + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 118, -127, -127, -127, 63, 19, 118, -127, -127, 45, + 53, -127, 55, -127, -127, -11, 61, -127, 40, -2, + 66, 3, 192, 156, 25, 55, -127, 12, -127, 73, + 74, 0, -127, -127, -127, 14, 192, -127, -127, -127, + 82, -127, -127, -127, -127, -127, 192, 37, 69, 144, + -127, -127, 192, 156, -127, 73, 31, 93, -127, 87, + 73, 63, 176, 94, 98, -127, -127, 192, 192, 192, + 192, 192, -127, -127, 89, 99, -127, -127, 73, 188, + 116, 120, 123, 126, -127, -127, -127, 55, -127, 124, + -127, -127, -127, -127, -127, 129, 136, 143, -127, -127, + -127, -127, 59, -127, -127, -127, -127, 37, 37, -127, + 156, -127, -127, -127, 140, 192, 192, -127, -127, -127, + -127, -127, 192, 148, -127, 192, -127, -127, 150, 69, + 194, 152, 138, 145, 161, 158, 94, -127, 48, 192, + 192, 192, 192, 192, 192, 192, 192, 48, -127, 167, + 69, 69, 69, 69, 194, 194, 152, 138, -127, 48, + -127 +}; + +/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_int8 yydefact[] = +{ + 0, 9, 10, 11, 0, 0, 2, 4, 5, 0, + 0, 6, 0, 1, 3, 17, 0, 12, 0, 17, + 0, 0, 0, 0, 16, 0, 8, 0, 7, 0, + 0, 0, 29, 61, 62, 56, 0, 70, 69, 68, + 0, 59, 63, 60, 73, 64, 0, 77, 54, 0, + 15, 20, 0, 0, 13, 0, 0, 0, 26, 31, + 0, 0, 0, 57, 0, 18, 65, 0, 0, 0, + 0, 0, 21, 24, 0, 0, 14, 28, 0, 0, + 0, 0, 0, 0, 34, 40, 38, 0, 45, 0, + 36, 39, 47, 48, 46, 0, 59, 0, 25, 30, + 66, 71, 0, 58, 74, 75, 76, 79, 78, 22, + 0, 19, 27, 53, 0, 0, 0, 44, 43, 35, + 37, 42, 0, 32, 67, 0, 23, 52, 0, 80, + 85, 88, 90, 55, 0, 0, 33, 72, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 41, 49, + 81, 82, 83, 84, 86, 87, 89, 91, 51, 0, + 50 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -127, -127, -127, 184, -50, 4, -127, 182, 179, -32, + -44, -127, -127, 178, 146, -23, -127, 122, -126, -127, + -127, -127, -22, 96, -55, -127, -127, 17, -127, -127, + -127, 64, -98, 21, 68, 70, -127 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_uint8 yydefgoto[] = +{ + 0, 5, 6, 7, 8, 30, 10, 16, 17, 24, + 50, 74, 11, 31, 32, 88, 89, 90, 91, 92, + 93, 94, 95, 128, 41, 42, 43, 44, 45, 46, + 102, 47, 48, 130, 131, 132, 133 +}; + +/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 40, 51, 96, 63, 9, 73, 58, 86, 12, 76, + 9, 21, 149, 22, 64, 1, 2, 129, 129, 13, + 23, 158, 22, 60, 1, 2, 29, 51, 61, 23, + 75, 51, 77, 160, 96, 55, 62, 98, 22, 86, + 101, 150, 151, 152, 153, 129, 129, 129, 129, 52, + 15, 33, 34, 35, 78, 112, 53, 114, 18, 61, + 19, 87, 27, 66, 79, 80, 126, 81, 82, 83, + 36, 67, 68, 69, 57, 1, 2, 85, 37, 59, + 38, 39, 124, 96, 104, 105, 106, 125, 51, 25, + 26, 136, 96, 87, 25, 28, 33, 34, 35, 57, + 135, 70, 71, 137, 96, 1, 2, 65, 4, 79, + 80, 97, 81, 82, 83, 36, 109, 110, 52, 57, + 84, 103, 85, 37, 111, 38, 39, 33, 34, 35, + 1, 2, 3, 4, 107, 108, 1, 2, 115, 4, + 79, 80, 116, 81, 82, 83, 36, 33, 34, 35, + 57, 119, 117, 85, 37, 118, 38, 39, 121, 33, + 34, 35, 143, 144, 154, 155, 36, 122, 123, 127, + 49, 72, 22, 138, 37, 145, 38, 39, 36, 33, + 34, 35, 49, 146, 147, 159, 37, 148, 38, 39, + 14, 33, 34, 35, 20, 33, 34, 35, 36, 100, + 139, 140, 141, 142, 54, 56, 37, 99, 38, 39, + 36, 120, 134, 156, 36, 0, 157, 113, 37, 0, + 38, 39, 37, 0, 38, 39 +}; + +static const yytype_int16 yycheck[] = +{ + 22, 23, 57, 35, 0, 49, 29, 57, 4, 53, + 6, 22, 138, 24, 36, 12, 13, 115, 116, 0, + 31, 147, 24, 23, 12, 13, 23, 49, 28, 31, + 52, 53, 55, 159, 89, 23, 22, 60, 24, 89, + 62, 139, 140, 141, 142, 143, 144, 145, 146, 24, + 5, 3, 4, 5, 23, 78, 31, 79, 5, 28, + 5, 57, 22, 46, 16, 17, 110, 19, 20, 21, + 22, 34, 35, 36, 26, 12, 13, 29, 30, 5, + 32, 33, 23, 138, 67, 68, 69, 28, 110, 28, + 29, 123, 147, 89, 28, 29, 3, 4, 5, 26, + 122, 32, 33, 125, 159, 12, 13, 25, 15, 16, + 17, 24, 19, 20, 21, 22, 27, 28, 24, 26, + 27, 23, 29, 30, 25, 32, 33, 3, 4, 5, + 12, 13, 14, 15, 70, 71, 12, 13, 22, 15, + 16, 17, 22, 19, 20, 21, 22, 3, 4, 5, + 26, 27, 29, 29, 30, 29, 32, 33, 29, 3, + 4, 5, 10, 11, 143, 144, 22, 31, 25, 29, + 26, 27, 24, 23, 30, 37, 32, 33, 22, 3, + 4, 5, 26, 38, 23, 18, 30, 29, 32, 33, + 6, 3, 4, 5, 12, 3, 4, 5, 22, 23, + 6, 7, 8, 9, 25, 27, 30, 61, 32, 33, + 22, 89, 116, 145, 22, -1, 146, 29, 30, -1, + 32, 33, 30, -1, 32, 33 +}; + +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ +static const yytype_int8 yystos[] = +{ + 0, 12, 13, 14, 15, 41, 42, 43, 44, 45, + 46, 52, 45, 0, 43, 5, 47, 48, 5, 5, + 47, 22, 24, 31, 49, 28, 29, 22, 29, 23, + 45, 53, 54, 3, 4, 5, 22, 30, 32, 33, + 62, 64, 65, 66, 67, 68, 69, 71, 72, 26, + 50, 62, 24, 31, 48, 23, 53, 26, 55, 5, + 23, 28, 22, 49, 62, 25, 67, 34, 35, 36, + 32, 33, 27, 50, 51, 62, 50, 55, 23, 16, + 17, 19, 20, 21, 27, 29, 44, 45, 55, 56, + 57, 58, 59, 60, 61, 62, 64, 24, 55, 54, + 23, 62, 70, 23, 67, 67, 67, 71, 71, 27, + 28, 25, 55, 29, 62, 22, 22, 29, 29, 27, + 57, 29, 31, 25, 23, 28, 50, 29, 63, 72, + 73, 74, 75, 76, 63, 62, 49, 62, 23, 6, + 7, 8, 9, 10, 11, 37, 38, 23, 29, 58, + 72, 72, 72, 72, 73, 73, 74, 75, 58, 18, + 58 +}; + +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr1[] = +{ + 0, 40, 41, 42, 42, 43, 43, 44, 44, 45, + 45, 46, 47, 47, 48, 48, 48, 48, 49, 49, + 50, 50, 50, 51, 51, 52, 52, 52, 52, 53, + 53, 54, 54, 54, 55, 55, 56, 56, 57, 57, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 59, + 59, 60, 61, 61, 62, 63, 64, 64, 65, 65, + 65, 66, 66, 67, 67, 67, 68, 68, 69, 69, + 69, 70, 70, 71, 71, 71, 71, 72, 72, 72, + 73, 73, 73, 73, 73, 74, 74, 74, 75, 75, + 76, 76 +}; + +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr2[] = +{ + 0, 2, 1, 2, 1, 1, 1, 4, 3, 1, + 1, 1, 1, 3, 4, 3, 2, 1, 3, 4, + 1, 2, 3, 3, 1, 6, 5, 6, 5, 1, + 3, 2, 4, 5, 2, 3, 1, 2, 1, 1, + 1, 4, 2, 2, 2, 1, 1, 1, 1, 5, + 7, 5, 3, 2, 1, 1, 1, 2, 3, 1, + 1, 1, 1, 1, 1, 2, 3, 4, 1, 1, + 1, 1, 3, 1, 3, 3, 3, 1, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 3, 1, 3, + 1, 3 +}; + + +enum { YYENOMEM = -2 }; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Backward compatibility with an undocumented macro. + Use YYerror or YYUNDEF. */ +#define YYERRCODE YYUNDEF + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + +/* YYLOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +# ifndef YYLOCATION_PRINT + +# if defined YY_LOCATION_PRINT + + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YYLOCATION_PRINT(File, Loc) YY_LOCATION_PRINT(File, *(Loc)) + +# elif defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + +/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ + +YY_ATTRIBUTE_UNUSED +static int +yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) +{ + int res = 0; + int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; + if (0 <= yylocp->first_line) + { + res += YYFPRINTF (yyo, "%d", yylocp->first_line); + if (0 <= yylocp->first_column) + res += YYFPRINTF (yyo, ".%d", yylocp->first_column); + } + if (0 <= yylocp->last_line) + { + if (yylocp->first_line < yylocp->last_line) + { + res += YYFPRINTF (yyo, "-%d", yylocp->last_line); + if (0 <= end_col) + res += YYFPRINTF (yyo, ".%d", end_col); + } + else if (0 <= end_col && yylocp->first_column < end_col) + res += YYFPRINTF (yyo, "-%d", end_col); + } + return res; +} + +# define YYLOCATION_PRINT yy_location_print_ + + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YY_LOCATION_PRINT(File, Loc) YYLOCATION_PRINT(File, &(Loc)) + +# else + +# define YYLOCATION_PRINT(File, Loc) ((void) 0) + /* Temporary convenience wrapper in case some people defined the + undocumented and private YY_LOCATION_PRINT macros. */ +# define YY_LOCATION_PRINT YYLOCATION_PRINT + +# endif +# endif /* !defined YYLOCATION_PRINT */ + + +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Kind, Value, Location); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) +{ + FILE *yyoutput = yyo; + YY_USE (yyoutput); + YY_USE (yylocationp); + if (!yyvaluep) + return; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void +yy_symbol_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) +{ + YYFPRINTF (yyo, "%s %s (", + yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); + + YYLOCATION_PRINT (yyo, yylocationp); + YYFPRINTF (yyo, ": "); + yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp); + YYFPRINTF (yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, + int yyrule) +{ + int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), + &yyvsp[(yyi + 1) - (yynrhs)], + &(yylsp[(yyi + 1) - (yynrhs)])); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) ((void) 0) +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +/* Context of a parse error. */ +typedef struct +{ + yy_state_t *yyssp; + yysymbol_kind_t yytoken; + YYLTYPE *yylloc; +} yypcontext_t; + +/* Put in YYARG at most YYARGN of the expected tokens given the + current YYCTX, and return the number of tokens stored in YYARG. If + YYARG is null, return the number of expected tokens (guaranteed to + be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. + Return 0 if there are more than YYARGN expected tokens, yet fill + YYARG up to YYARGN. */ +static int +yypcontext_expected_tokens (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + int yyn = yypact[+*yyctx->yyssp]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (!yyarg) + ++yycount; + else if (yycount == yyargn) + return 0; + else + yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); + } + } + if (yyarg && yycount == 0 && 0 < yyargn) + yyarg[0] = YYSYMBOL_YYEMPTY; + return yycount; +} + + + + +#ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) +# else +/* Return the length of YYSTR. */ +static YYPTRDIFF_T +yystrlen (const char *yystr) +{ + YYPTRDIFF_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +#endif + +#ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +#endif + +#ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYPTRDIFF_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYPTRDIFF_T yyn = 0; + char const *yyp = yystr; + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + else + goto append; + + append: + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (yyres) + return yystpcpy (yyres, yystr) - yyres; + else + return yystrlen (yystr); +} +#endif + + +static int +yy_syntax_error_arguments (const yypcontext_t *yyctx, + yysymbol_kind_t yyarg[], int yyargn) +{ + /* Actual size of YYARG. */ + int yycount = 0; + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yyctx->yytoken != YYSYMBOL_YYEMPTY) + { + int yyn; + if (yyarg) + yyarg[yycount] = yyctx->yytoken; + ++yycount; + yyn = yypcontext_expected_tokens (yyctx, + yyarg ? yyarg + 1 : yyarg, yyargn - 1); + if (yyn == YYENOMEM) + return YYENOMEM; + else + yycount += yyn; + } + return yycount; +} + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, + const yypcontext_t *yyctx) +{ + enum { YYARGS_MAX = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat: reported tokens (one for the "unexpected", + one per "expected"). */ + yysymbol_kind_t yyarg[YYARGS_MAX]; + /* Cumulated lengths of YYARG. */ + YYPTRDIFF_T yysize = 0; + + /* Actual size of YYARG. */ + int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); + if (yycount == YYENOMEM) + return YYENOMEM; + + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: /* Avoid compiler warnings. */ + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + /* Compute error message size. Don't count the "%s"s, but reserve + room for the terminator. */ + yysize = yystrlen (yyformat) - 2 * yycount + 1; + { + int yyi; + for (yyi = 0; yyi < yycount; ++yyi) + { + YYPTRDIFF_T yysize1 + = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); + if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) + yysize = yysize1; + else + return YYENOMEM; + } + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return -1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); + yyformat += 2; + } + else + { + ++yyp; + ++yyformat; + } + } + return 0; +} + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, + yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) +{ + YY_USE (yyvaluep); + YY_USE (yylocationp); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/* Lookahead token kind. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; +/* Location data for the lookahead symbol. */ +YYLTYPE yylloc +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + = { 1, 1, 1, 1 } +# endif +; +/* Number of syntax errors so far. */ +int yynerrs; + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (void) +{ + yy_state_fast_t yystate = 0; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus = 0; + + /* Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* Their size. */ + YYPTRDIFF_T yystacksize = YYINITDEPTH; + + /* The state stack: array, bottom, top. */ + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; + + /* The semantic value stack: array, bottom, top. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; + + /* The location stack: array, bottom, top. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp = yyls; + + int yyn; + /* The return value of yyparse. */ + int yyresult; + /* Lookahead symbol kind. */ + yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[3]; + + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yychar = YYEMPTY; /* Cause a token to be read. */ + + yylsp[0] = yylloc; + goto yysetstate; + + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END + YY_STACK_PRINT (yyss, yyssp); + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + YYNOMEM; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYPTRDIFF_T yysize = yyssp - yyss + 1; + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + yy_state_t *yyss1 = yyss; + YYSTYPE *yyvs1 = yyvs; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yyls1, yysize * YYSIZEOF (*yylsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + yyls = yyls1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + YYNOMEM; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yy_state_t *yyss1 = yyss; + union yyalloc *yyptr = + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); + if (! yyptr) + YYNOMEM; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token\n")); + yychar = yylex (); + } + + if (yychar <= YYEOF) + { + yychar = YYEOF; + yytoken = YYSYMBOL_YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else if (yychar == YYerror) + { + /* The scanner already issued an error message, process directly + to error recovery. But do not keep the error token as + lookahead, it is too special and may lead us to an endless + loop in error recovery. */ + yychar = YYUNDEF; + yytoken = YYSYMBOL_YYerror; + yyerror_range[1] = yylloc; + goto yyerrlab1; + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + *++yylsp = yylloc; + + /* Discard the shifted token. */ + yychar = YYEMPTY; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + yyerror_range[1] = yyloc; + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: /* Program: CompUnit */ +#line 124 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + root = unique_ptr((yyvsp[0].compUnit)); + } +#line 1664 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 3: /* CompUnit: CompUnit DeclDef */ +#line 130 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.compUnit) = (yyvsp[-1].compUnit); + (yyval.compUnit)->declDefList.push_back(unique_ptr((yyvsp[0].declDef))); + } +#line 1673 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 4: /* CompUnit: DeclDef */ +#line 134 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.compUnit) = new CompUnitAST(); + (yyval.compUnit)->declDefList.push_back(unique_ptr((yyvsp[0].declDef))); + } +#line 1682 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 5: /* DeclDef: Decl */ +#line 141 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.declDef) = new DeclDefAST(); + (yyval.declDef)->Decl = unique_ptr((yyvsp[0].decl)); + } +#line 1691 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 6: /* DeclDef: FuncDef */ +#line 145 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.declDef) = new DeclDefAST(); + (yyval.declDef)->funcDef = unique_ptr((yyvsp[0].funcDef)); + } +#line 1700 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 7: /* Decl: CONST BType DefList SEMICOLON */ +#line 152 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.decl) = new DeclAST(); + (yyval.decl)->isConst = true; + (yyval.decl)->bType = (yyvsp[-2].ty); + (yyval.decl)->defList.swap((yyvsp[-1].defList)->list); + } +#line 1711 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 8: /* Decl: BType DefList SEMICOLON */ +#line 158 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.decl) = new DeclAST(); + (yyval.decl)->isConst = false; + (yyval.decl)->bType = (yyvsp[-2].ty); + (yyval.decl)->defList.swap((yyvsp[-1].defList)->list); + } +#line 1722 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 9: /* BType: INTTYPE */ +#line 167 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.ty) = TYPE_INT; + } +#line 1730 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 10: /* BType: FLOATTYPE */ +#line 170 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.ty) = TYPE_FLOAT; + } +#line 1738 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 11: /* VoidType: VOID */ +#line 176 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.ty) = TYPE_VOID; + } +#line 1746 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 12: /* DefList: Def */ +#line 182 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.defList) = new DefListAST(); + (yyval.defList)->list.push_back(unique_ptr((yyvsp[0].def))); + } +#line 1755 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 13: /* DefList: DefList COMMA Def */ +#line 186 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.defList) = (yyvsp[-2].defList); + (yyval.defList)->list.push_back(unique_ptr((yyvsp[0].def))); + } +#line 1764 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 14: /* Def: ID Arrays ASSIGN InitVal */ +#line 193 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.def) = new DefAST(); + (yyval.def)->id = unique_ptr((yyvsp[-3].token)); + (yyval.def)->arrays.swap((yyvsp[-2].arrays)->list); + (yyval.def)->initVal = unique_ptr((yyvsp[0].initVal)); + } +#line 1775 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 15: /* Def: ID ASSIGN InitVal */ +#line 199 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.def) = new DefAST(); + (yyval.def)->id = unique_ptr((yyvsp[-2].token)); + (yyval.def)->initVal = unique_ptr((yyvsp[0].initVal)); + } +#line 1785 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 16: /* Def: ID Arrays */ +#line 204 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.def) = new DefAST(); + (yyval.def)->id = unique_ptr((yyvsp[-1].token)); + (yyval.def)->arrays.swap((yyvsp[0].arrays)->list); + } +#line 1795 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 17: /* Def: ID */ +#line 209 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.def) = new DefAST(); + (yyval.def)->id = unique_ptr((yyvsp[0].token)); + } +#line 1804 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 18: /* Arrays: LB Exp RB */ +#line 216 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.arrays) = new ArraysAST(); + (yyval.arrays)->list.push_back(unique_ptr((yyvsp[-1].addExp))); + } +#line 1813 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 19: /* Arrays: Arrays LB Exp RB */ +#line 220 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.arrays) = (yyvsp[-3].arrays); + (yyval.arrays)->list.push_back(unique_ptr((yyvsp[-1].addExp))); + } +#line 1822 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 20: /* InitVal: Exp */ +#line 228 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.initVal) = new InitValAST(); + (yyval.initVal)->exp = unique_ptr((yyvsp[0].addExp)); + } +#line 1831 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 21: /* InitVal: LC RC */ +#line 232 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.initVal) = new InitValAST(); + } +#line 1839 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 22: /* InitVal: LC InitValList RC */ +#line 235 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.initVal) = new InitValAST(); + (yyval.initVal)->initValList.swap((yyvsp[-1].initValList)->list); + } +#line 1848 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 23: /* InitValList: InitValList COMMA InitVal */ +#line 242 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.initValList) = (yyvsp[-2].initValList); + (yyval.initValList)->list.push_back(unique_ptr((yyvsp[0].initVal))); + } +#line 1857 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 24: /* InitValList: InitVal */ +#line 246 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.initValList) = new InitValListAST(); + (yyval.initValList)->list.push_back(unique_ptr((yyvsp[0].initVal))); + } +#line 1866 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 25: /* FuncDef: BType ID LP FuncFParamList RP Block */ +#line 253 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcDef) = new FuncDefAST(); + (yyval.funcDef)->funcType = (yyvsp[-5].ty); + (yyval.funcDef)->id = unique_ptr((yyvsp[-4].token)); + (yyval.funcDef)->funcFParamList.swap((yyvsp[-2].FuncFParamList)->list); + (yyval.funcDef)->block = unique_ptr((yyvsp[0].block)); + } +#line 1878 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 26: /* FuncDef: BType ID LP RP Block */ +#line 260 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcDef) = new FuncDefAST(); + (yyval.funcDef)->funcType = (yyvsp[-4].ty); + (yyval.funcDef)->id = unique_ptr((yyvsp[-3].token)); + (yyval.funcDef)->block = unique_ptr((yyvsp[0].block)); + } +#line 1889 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 27: /* FuncDef: VoidType ID LP FuncFParamList RP Block */ +#line 266 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcDef) = new FuncDefAST(); + (yyval.funcDef)->funcType = (yyvsp[-5].ty); + (yyval.funcDef)->id = unique_ptr((yyvsp[-4].token)); + (yyval.funcDef)->funcFParamList.swap((yyvsp[-2].FuncFParamList)->list); + (yyval.funcDef)->block = unique_ptr((yyvsp[0].block)); + } +#line 1901 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 28: /* FuncDef: VoidType ID LP RP Block */ +#line 273 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcDef) = new FuncDefAST(); + (yyval.funcDef)->funcType = (yyvsp[-4].ty); + (yyval.funcDef)->id = unique_ptr((yyvsp[-3].token)); + (yyval.funcDef)->block = unique_ptr((yyvsp[0].block)); + } +#line 1912 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 29: /* FuncFParamList: FuncFParam */ +#line 282 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.FuncFParamList) = new FuncFParamListAST(); + (yyval.FuncFParamList)->list.push_back(unique_ptr((yyvsp[0].funcFParam))); + } +#line 1921 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 30: /* FuncFParamList: FuncFParamList COMMA FuncFParam */ +#line 286 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.FuncFParamList) = (yyvsp[-2].FuncFParamList); + (yyval.FuncFParamList)->list.push_back(unique_ptr((yyvsp[0].funcFParam))); + } +#line 1930 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 31: /* FuncFParam: BType ID */ +#line 293 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcFParam) = new FuncFParamAST(); + (yyval.funcFParam)->bType = (yyvsp[-1].ty); + (yyval.funcFParam)->id = unique_ptr((yyvsp[0].token)); + (yyval.funcFParam)->isArray = false; + } +#line 1941 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 32: /* FuncFParam: BType ID LB RB */ +#line 299 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcFParam) = new FuncFParamAST(); + (yyval.funcFParam)->bType = (yyvsp[-3].ty); + (yyval.funcFParam)->id = unique_ptr((yyvsp[-2].token)); + (yyval.funcFParam)->isArray = true; + } +#line 1952 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 33: /* FuncFParam: BType ID LB RB Arrays */ +#line 305 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcFParam) = new FuncFParamAST(); + (yyval.funcFParam)->bType = (yyvsp[-4].ty); + (yyval.funcFParam)->id = unique_ptr((yyvsp[-3].token)); + (yyval.funcFParam)->isArray = true; + (yyval.funcFParam)->arrays.swap((yyvsp[0].arrays)->list); + } +#line 1964 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 34: /* Block: LC RC */ +#line 315 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.block) = new BlockAST(); + } +#line 1972 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 35: /* Block: LC BlockItemList RC */ +#line 318 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.block) = new BlockAST(); + (yyval.block)->blockItemList.swap((yyvsp[-1].blockItemList)->list); + } +#line 1981 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 36: /* BlockItemList: BlockItem */ +#line 325 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.blockItemList) = new BlockItemListAST(); + (yyval.blockItemList)->list.push_back(unique_ptr((yyvsp[0].blockItem))); + } +#line 1990 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 37: /* BlockItemList: BlockItemList BlockItem */ +#line 329 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.blockItemList) = (yyvsp[-1].blockItemList); + (yyval.blockItemList)->list.push_back(unique_ptr((yyvsp[0].blockItem))); + } +#line 1999 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 38: /* BlockItem: Decl */ +#line 336 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.blockItem) = new BlockItemAST(); + (yyval.blockItem)->decl = unique_ptr((yyvsp[0].decl)); + } +#line 2008 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 39: /* BlockItem: Stmt */ +#line 340 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.blockItem) = new BlockItemAST(); + (yyval.blockItem)->stmt = unique_ptr((yyvsp[0].stmt)); + } +#line 2017 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 40: /* Stmt: SEMICOLON */ +#line 347 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = SEMI; + } +#line 2026 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 41: /* Stmt: LVal ASSIGN Exp SEMICOLON */ +#line 351 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = ASS; + (yyval.stmt)->lVal = unique_ptr((yyvsp[-3].lVal)); + (yyval.stmt)->exp = unique_ptr((yyvsp[-1].addExp)); + } +#line 2037 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 42: /* Stmt: Exp SEMICOLON */ +#line 357 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = EXP; + (yyval.stmt)->exp = unique_ptr((yyvsp[-1].addExp)); + } +#line 2047 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 43: /* Stmt: CONTINUE SEMICOLON */ +#line 362 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = CONT; + } +#line 2056 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 44: /* Stmt: BREAK SEMICOLON */ +#line 366 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = BRE; + } +#line 2065 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 45: /* Stmt: Block */ +#line 370 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = BLK; + (yyval.stmt)->block = unique_ptr((yyvsp[0].block)); + } +#line 2075 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 46: /* Stmt: ReturnStmt */ +#line 375 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = RET; + (yyval.stmt)->returnStmt = unique_ptr((yyvsp[0].returnStmt)); + } +#line 2085 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 47: /* Stmt: SelectStmt */ +#line 380 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = SEL; + (yyval.stmt)->selectStmt = unique_ptr((yyvsp[0].selectStmt)); + } +#line 2095 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 48: /* Stmt: IterationStmt */ +#line 385 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.stmt) = new StmtAST(); + (yyval.stmt)->sType = ITER; + (yyval.stmt)->iterationStmt = unique_ptr((yyvsp[0].iterationStmt)); + } +#line 2105 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 49: /* SelectStmt: IF LP Cond RP Stmt */ +#line 393 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.selectStmt) = new SelectStmtAST(); + (yyval.selectStmt)->cond = unique_ptr((yyvsp[-2].lOrExp)); + (yyval.selectStmt)->ifStmt = unique_ptr((yyvsp[0].stmt)); + } +#line 2115 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 50: /* SelectStmt: IF LP Cond RP Stmt ELSE Stmt */ +#line 398 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.selectStmt) = new SelectStmtAST(); + (yyval.selectStmt)->cond = unique_ptr((yyvsp[-4].lOrExp)); + (yyval.selectStmt)->ifStmt = unique_ptr((yyvsp[-2].stmt)); + (yyval.selectStmt)->elseStmt = unique_ptr((yyvsp[0].stmt)); + } +#line 2126 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 51: /* IterationStmt: WHILE LP Cond RP Stmt */ +#line 407 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.iterationStmt) = new IterationStmtAST(); + (yyval.iterationStmt)->cond = unique_ptr((yyvsp[-2].lOrExp)); + (yyval.iterationStmt)->stmt = unique_ptr((yyvsp[0].stmt)); + } +#line 2136 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 52: /* ReturnStmt: RETURN Exp SEMICOLON */ +#line 415 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.returnStmt) = new ReturnStmtAST(); + (yyval.returnStmt)->exp = unique_ptr((yyvsp[-1].addExp)); + } +#line 2145 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 53: /* ReturnStmt: RETURN SEMICOLON */ +#line 419 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.returnStmt) = new ReturnStmtAST(); + } +#line 2153 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 54: /* Exp: AddExp */ +#line 425 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.addExp) = (yyvsp[0].addExp); + } +#line 2161 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 55: /* Cond: LOrExp */ +#line 431 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.lOrExp) = (yyvsp[0].lOrExp); + } +#line 2169 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 56: /* LVal: ID */ +#line 437 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.lVal) = new LValAST(); + (yyval.lVal)->id = unique_ptr((yyvsp[0].token)); + } +#line 2178 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 57: /* LVal: ID Arrays */ +#line 441 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.lVal) = new LValAST(); + (yyval.lVal)->id = unique_ptr((yyvsp[-1].token)); + (yyval.lVal)->arrays.swap((yyvsp[0].arrays)->list); + } +#line 2188 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 58: /* PrimaryExp: LP Exp RP */ +#line 449 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.primaryExp) = new PrimaryExpAST(); + (yyval.primaryExp)->exp = unique_ptr((yyvsp[-1].addExp)); + } +#line 2197 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 59: /* PrimaryExp: LVal */ +#line 453 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.primaryExp) = new PrimaryExpAST(); + (yyval.primaryExp)->lval = unique_ptr((yyvsp[0].lVal)); + } +#line 2206 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 60: /* PrimaryExp: Number */ +#line 457 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.primaryExp) = new PrimaryExpAST(); + (yyval.primaryExp)->number = unique_ptr((yyvsp[0].number)); + } +#line 2215 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 61: /* Number: INT */ +#line 464 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.number) = new NumberAST(); + (yyval.number)->isInt = true; + (yyval.number)->intval = (yyvsp[0].int_val); + } +#line 2225 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 62: /* Number: FLOAT */ +#line 469 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.number) = new NumberAST(); + (yyval.number)->isInt = false; + (yyval.number)->floatval = (yyvsp[0].float_val); + } +#line 2235 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 63: /* UnaryExp: PrimaryExp */ +#line 477 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.unaryExp) = new UnaryExpAST(); + (yyval.unaryExp)->primaryExp = unique_ptr((yyvsp[0].primaryExp)); + } +#line 2244 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 64: /* UnaryExp: Call */ +#line 481 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.unaryExp) = new UnaryExpAST(); + (yyval.unaryExp)->call = unique_ptr((yyvsp[0].call)); + } +#line 2253 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 65: /* UnaryExp: UnaryOp UnaryExp */ +#line 485 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.unaryExp) = new UnaryExpAST(); + (yyval.unaryExp)->op = (yyvsp[-1].op); + (yyval.unaryExp)->unaryExp = unique_ptr((yyvsp[0].unaryExp)); + } +#line 2263 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 66: /* Call: ID LP RP */ +#line 493 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.call) = new CallAST(); + (yyval.call)->id = unique_ptr((yyvsp[-2].token)); + } +#line 2272 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 67: /* Call: ID LP FuncCParamList RP */ +#line 497 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.call) = new CallAST(); + (yyval.call)->id = unique_ptr((yyvsp[-3].token)); + (yyval.call)->funcCParamList.swap((yyvsp[-1].funcCParamList)->list); + } +#line 2282 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 68: /* UnaryOp: ADD */ +#line 505 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.op) = UOP_ADD; + } +#line 2290 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 69: /* UnaryOp: MINUS */ +#line 508 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.op) = UOP_MINUS; + } +#line 2298 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 70: /* UnaryOp: NOT */ +#line 511 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.op) = UOP_NOT; + } +#line 2306 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 71: /* FuncCParamList: Exp */ +#line 517 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcCParamList) = new FuncCParamListAST(); + (yyval.funcCParamList)->list.push_back(unique_ptr((yyvsp[0].addExp))); + } +#line 2315 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 72: /* FuncCParamList: FuncCParamList COMMA Exp */ +#line 521 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.funcCParamList) = (FuncCParamListAST*) (yyvsp[-2].funcCParamList); + (yyval.funcCParamList)->list.push_back(unique_ptr((yyvsp[0].addExp))); + } +#line 2324 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 73: /* MulExp: UnaryExp */ +#line 528 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.mulExp) = new MulExpAST(); + (yyval.mulExp)->unaryExp = unique_ptr((yyvsp[0].unaryExp)); + } +#line 2333 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 74: /* MulExp: MulExp MUL UnaryExp */ +#line 532 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.mulExp) = new MulExpAST(); + (yyval.mulExp)->mulExp = unique_ptr((yyvsp[-2].mulExp)); + (yyval.mulExp)->op = MOP_MUL; + (yyval.mulExp)->unaryExp = unique_ptr((yyvsp[0].unaryExp)); + } +#line 2344 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 75: /* MulExp: MulExp DIV UnaryExp */ +#line 538 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.mulExp) = new MulExpAST(); + (yyval.mulExp)->mulExp = unique_ptr((yyvsp[-2].mulExp)); + (yyval.mulExp)->op = MOP_DIV; + (yyval.mulExp)->unaryExp = unique_ptr((yyvsp[0].unaryExp)); + } +#line 2355 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 76: /* MulExp: MulExp MOD UnaryExp */ +#line 544 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.mulExp) = new MulExpAST(); + (yyval.mulExp)->mulExp = unique_ptr((yyvsp[-2].mulExp)); + (yyval.mulExp)->op = MOP_MOD; + (yyval.mulExp)->unaryExp = unique_ptr((yyvsp[0].unaryExp)); + } +#line 2366 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 77: /* AddExp: MulExp */ +#line 553 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.addExp) = new AddExpAST(); + (yyval.addExp)->mulExp = unique_ptr((yyvsp[0].mulExp)); + } +#line 2375 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 78: /* AddExp: AddExp ADD MulExp */ +#line 557 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.addExp) = new AddExpAST(); + (yyval.addExp)->addExp = unique_ptr((yyvsp[-2].addExp)); + (yyval.addExp)->op = AOP_ADD; + (yyval.addExp)->mulExp = unique_ptr((yyvsp[0].mulExp)); + } +#line 2386 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 79: /* AddExp: AddExp MINUS MulExp */ +#line 563 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.addExp) = new AddExpAST(); + (yyval.addExp)->addExp = unique_ptr((yyvsp[-2].addExp)); + (yyval.addExp)->op = AOP_MINUS; + (yyval.addExp)->mulExp = unique_ptr((yyvsp[0].mulExp)); + } +#line 2397 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 80: /* RelExp: AddExp */ +#line 572 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.relExp) = new RelExpAST(); + (yyval.relExp)->addExp = unique_ptr((yyvsp[0].addExp)); + } +#line 2406 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 81: /* RelExp: RelExp GTE AddExp */ +#line 576 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.relExp) = new RelExpAST(); + (yyval.relExp)->relExp = unique_ptr((yyvsp[-2].relExp)); + (yyval.relExp)->op = ROP_GTE; + (yyval.relExp)->addExp = unique_ptr((yyvsp[0].addExp)); + } +#line 2417 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 82: /* RelExp: RelExp LTE AddExp */ +#line 582 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.relExp) = new RelExpAST(); + (yyval.relExp)->relExp = unique_ptr((yyvsp[-2].relExp)); + (yyval.relExp)->op = ROP_LTE; + (yyval.relExp)->addExp = unique_ptr((yyvsp[0].addExp)); + } +#line 2428 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 83: /* RelExp: RelExp GT AddExp */ +#line 588 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.relExp) = new RelExpAST(); + (yyval.relExp)->relExp = unique_ptr((yyvsp[-2].relExp)); + (yyval.relExp)->op = ROP_GT; + (yyval.relExp)->addExp = unique_ptr((yyvsp[0].addExp)); + } +#line 2439 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 84: /* RelExp: RelExp LT AddExp */ +#line 594 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.relExp) = new RelExpAST(); + (yyval.relExp)->relExp = unique_ptr((yyvsp[-2].relExp)); + (yyval.relExp)->op = ROP_LT; + (yyval.relExp)->addExp = unique_ptr((yyvsp[0].addExp)); + } +#line 2450 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 85: /* EqExp: RelExp */ +#line 603 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.eqExp) = new EqExpAST(); + (yyval.eqExp)->relExp = unique_ptr((yyvsp[0].relExp)); + } +#line 2459 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 86: /* EqExp: EqExp EQ RelExp */ +#line 607 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.eqExp) = new EqExpAST(); + (yyval.eqExp)->eqExp = unique_ptr((yyvsp[-2].eqExp)); + (yyval.eqExp)->op = EOP_EQ; + (yyval.eqExp)->relExp = unique_ptr((yyvsp[0].relExp)); + } +#line 2470 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 87: /* EqExp: EqExp NEQ RelExp */ +#line 613 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.eqExp) = new EqExpAST(); + (yyval.eqExp)->eqExp = unique_ptr((yyvsp[-2].eqExp)); + (yyval.eqExp)->op = EOP_NEQ; + (yyval.eqExp)->relExp = unique_ptr((yyvsp[0].relExp)); + } +#line 2481 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 88: /* LAndExp: EqExp */ +#line 622 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.lAndExp) = new LAndExpAST(); + (yyval.lAndExp)->eqExp = unique_ptr((yyvsp[0].eqExp)); + } +#line 2490 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 89: /* LAndExp: LAndExp AND EqExp */ +#line 626 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.lAndExp) = new LAndExpAST(); + (yyval.lAndExp)->lAndExp = unique_ptr((yyvsp[-2].lAndExp)); + (yyval.lAndExp)->eqExp = unique_ptr((yyvsp[0].eqExp)); + } +#line 2500 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 90: /* LOrExp: LAndExp */ +#line 634 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.lOrExp) = new LOrExpAST(); + (yyval.lOrExp)->lAndExp = unique_ptr((yyvsp[0].lAndExp)); + } +#line 2509 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + case 91: /* LOrExp: LOrExp OR LAndExp */ +#line 638 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + { + (yyval.lOrExp) = new LOrExpAST(); + (yyval.lOrExp)->lOrExp = unique_ptr((yyvsp[-2].lOrExp)); + (yyval.lOrExp)->lAndExp = unique_ptr((yyvsp[0].lAndExp)); + } +#line 2519 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + break; + + +#line 2523 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.cpp" + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + { + yypcontext_t yyctx + = {yyssp, yytoken, &yylloc}; + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == -1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = YY_CAST (char *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); + if (yymsg) + { + yysyntax_error_status + = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); + yymsgp = yymsg; + } + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = YYENOMEM; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == YYENOMEM) + YYNOMEM; + } + } + + yyerror_range[1] = yylloc; + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + ++yynerrs; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + /* Pop stack until we find a state that shifts the error token. */ + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYSYMBOL_YYerror; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[1] = *yylsp; + yydestruct ("Error: popping", + YY_ACCESSING_SYMBOL (yystate), yyvsp, yylsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + yyerror_range[2] = yylloc; + ++yylsp; + YYLLOC_DEFAULT (*yylsp, yyerror_range, 2); + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturnlab; + + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturnlab; + + +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + goto yyreturnlab; + + +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + return yyresult; +} + +#line 643 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + + +void initFileName(char *name) { + strcpy(filename, name); +} + +void yyerror(const char* fmt) { + printf("%s:%d ", filename, yylloc.first_line); + printf("%s\n", fmt); +} diff --git a/compiler/src/parser/parser.hpp b/compiler/src/parser/parser.hpp new file mode 100644 index 0000000..53e11d4 --- /dev/null +++ b/compiler/src/parser/parser.hpp @@ -0,0 +1,170 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +#ifndef YY_YY_HOME_SEAS0_CODES_COMPILER_CARROTCOMPILER_SRC_PARSER_PARSER_HPP_INCLUDED +# define YY_YY_HOME_SEAS0_CODES_COMPILER_CARROTCOMPILER_SRC_PARSER_PARSER_HPP_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token kinds. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + YYEMPTY = -2, + YYEOF = 0, /* "end of file" */ + YYerror = 256, /* error */ + YYUNDEF = 257, /* "invalid token" */ + INT = 258, /* INT */ + FLOAT = 259, /* FLOAT */ + ID = 260, /* ID */ + GTE = 261, /* GTE */ + LTE = 262, /* LTE */ + GT = 263, /* GT */ + LT = 264, /* LT */ + EQ = 265, /* EQ */ + NEQ = 266, /* NEQ */ + INTTYPE = 267, /* INTTYPE */ + FLOATTYPE = 268, /* FLOATTYPE */ + VOID = 269, /* VOID */ + CONST = 270, /* CONST */ + RETURN = 271, /* RETURN */ + IF = 272, /* IF */ + ELSE = 273, /* ELSE */ + WHILE = 274, /* WHILE */ + BREAK = 275, /* BREAK */ + CONTINUE = 276, /* CONTINUE */ + LP = 277, /* LP */ + RP = 278, /* RP */ + LB = 279, /* LB */ + RB = 280, /* RB */ + LC = 281, /* LC */ + RC = 282, /* RC */ + COMMA = 283, /* COMMA */ + SEMICOLON = 284, /* SEMICOLON */ + NOT = 285, /* NOT */ + ASSIGN = 286, /* ASSIGN */ + MINUS = 287, /* MINUS */ + ADD = 288, /* ADD */ + MUL = 289, /* MUL */ + DIV = 290, /* DIV */ + MOD = 291, /* MOD */ + AND = 292, /* AND */ + OR = 293, /* OR */ + LOWER_THEN_ELSE = 294 /* LOWER_THEN_ELSE */ + }; + typedef enum yytokentype yytoken_kind_t; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +union YYSTYPE +{ +#line 20 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.y" + + CompUnitAST* compUnit; + DeclDefAST* declDef; + DeclAST* decl; + DefListAST* defList; + DefAST* def; + ArraysAST* arrays; + InitValListAST* initValList; + InitValAST* initVal; + FuncDefAST* funcDef; + FuncFParamListAST* FuncFParamList; + FuncFParamAST* funcFParam; + BlockAST* block; + BlockItemListAST* blockItemList; + BlockItemAST* blockItem; + StmtAST* stmt; + ReturnStmtAST* returnStmt; + SelectStmtAST* selectStmt; + IterationStmtAST* iterationStmt; + LValAST* lVal; + PrimaryExpAST* primaryExp; + NumberAST* number; + UnaryExpAST* unaryExp; + CallAST* call; + FuncCParamListAST* funcCParamList; + MulExpAST* mulExp; + AddExpAST* addExp; + RelExpAST* relExp; + EqExpAST* eqExp; + LAndExpAST* lAndExp; + LOrExpAST* lOrExp; + + TYPE ty; + UOP op; + string* token; + int int_val; + float float_val; + +#line 142 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/parser.hpp" + +}; +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + +/* Location type. */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + +extern YYSTYPE yylval; +extern YYLTYPE yylloc; + +int yyparse (void); + + +#endif /* !YY_YY_HOME_SEAS0_CODES_COMPILER_CARROTCOMPILER_SRC_PARSER_PARSER_HPP_INCLUDED */ diff --git a/compiler/src/parser/parser.y b/compiler/src/parser/parser.y new file mode 100644 index 0000000..d0dd743 --- /dev/null +++ b/compiler/src/parser/parser.y @@ -0,0 +1,652 @@ +%define parse.error verbose +%locations + +%{ + #include "ast.h" + #include "define.h" + #include + #include + #include + using namespace std; + unique_ptr root; /* the top level root node of our final AST */ + + extern int yylineno; + extern int yylex(); + extern void yyerror(const char *s); + extern void initFileName(char *name); + char filename[100]; +%} + +%union { + CompUnitAST* compUnit; + DeclDefAST* declDef; + DeclAST* decl; + DefListAST* defList; + DefAST* def; + ArraysAST* arrays; + InitValListAST* initValList; + InitValAST* initVal; + FuncDefAST* funcDef; + FuncFParamListAST* FuncFParamList; + FuncFParamAST* funcFParam; + BlockAST* block; + BlockItemListAST* blockItemList; + BlockItemAST* blockItem; + StmtAST* stmt; + ReturnStmtAST* returnStmt; + SelectStmtAST* selectStmt; + IterationStmtAST* iterationStmt; + LValAST* lVal; + PrimaryExpAST* primaryExp; + NumberAST* number; + UnaryExpAST* unaryExp; + CallAST* call; + FuncCParamListAST* funcCParamList; + MulExpAST* mulExp; + AddExpAST* addExp; + RelExpAST* relExp; + EqExpAST* eqExp; + LAndExpAST* lAndExp; + LOrExpAST* lOrExp; + + TYPE ty; + UOP op; + string* token; + int int_val; + float float_val; +}; + +// %union is not used, and %token and %type expect genuine types, not type tags +%type CompUnit; +%type DeclDef; +%type Decl; +%type DefList; +%type Def; +%type Arrays; +%type InitValList; +%type InitVal; +%type FuncDef; +%type FuncFParamList +%type FuncFParam; +%type Block; +%type BlockItemList; +%type BlockItem; +%type Stmt; +%type ReturnStmt; +%type SelectStmt; +%type IterationStmt; +%type LVal; +%type PrimaryExp; +%type Number; +%type UnaryExp; +%type Call; +%type FuncCParamList; +%type MulExp; +%type Exp AddExp; +%type RelExp; +%type EqExp; +%type LAndExp; +%type Cond LOrExp; + +%type BType VoidType +%type UnaryOp + +// %token 定义终结符的语义值类型 +%token INT // 指定INT字面量的语义值是type_int,有词法分析得到的数值 +%token FLOAT // 指定FLOAT字面量的语义值是type_float,有词法分析得到的数值 +%token ID // 指定ID +%token GTE LTE GT LT EQ NEQ // 关系运算 +%token INTTYPE FLOATTYPE VOID // 数据类型 +%token CONST RETURN IF ELSE WHILE BREAK CONTINUE +%token LP RP LB RB LC RC COMMA SEMICOLON +// 用bison对该文件编译时,带参数-d,生成的exp.tab.h中给这些单词进行编码,可在lex.l中包含parser.tab.h使用这些单词种类码 +%token NOT ASSIGN MINUS ADD MUL DIV MOD AND OR +// Unused tokens +/* %token POS NEG */ + +%left ASSIGN +%left OR AND +%left EQ NEQ +%left GTE LTE GT LT +%left ADD MINUS +%left MOD MUL DIV +%right NOT +// Unused tokens +/* %right POS NEG */ + +%nonassoc LOWER_THEN_ELSE +%nonassoc ELSE + +%start Program + +%% +Program: + CompUnit { + root = unique_ptr($1); + }; + +// 编译单元 +CompUnit: + CompUnit DeclDef { + $$ = $1; + $$->declDefList.push_back(unique_ptr($2)); + }| + DeclDef { + $$ = new CompUnitAST(); + $$->declDefList.push_back(unique_ptr($1)); + }; + +//声明或者函数定义 +DeclDef: + Decl { + $$ = new DeclDefAST(); + $$->Decl = unique_ptr($1); + }| + FuncDef { + $$ = new DeclDefAST(); + $$->funcDef = unique_ptr($1); + }; + +// 变量或常量声明 +Decl: + CONST BType DefList SEMICOLON { + $$ = new DeclAST(); + $$->isConst = true; + $$->bType = $2; + $$->defList.swap($3->list); + }| + BType DefList SEMICOLON { + $$ = new DeclAST(); + $$->isConst = false; + $$->bType = $1; + $$->defList.swap($2->list); + }; + +// 基本类型 +BType: + INTTYPE { + $$ = TYPE_INT; + }| + FLOATTYPE { + $$ = TYPE_FLOAT; + }; + +// 空类型 +VoidType: + VOID { + $$ = TYPE_VOID; + }; + +// 定义列表 +DefList: + Def { + $$ = new DefListAST(); + $$->list.push_back(unique_ptr($1)); + }| + DefList COMMA Def { + $$ = $1; + $$->list.push_back(unique_ptr($3)); + }; + +// 定义 +Def: + ID Arrays ASSIGN InitVal { + $$ = new DefAST(); + $$->id = unique_ptr($1); + $$->arrays.swap($2->list); + $$->initVal = unique_ptr($4); + }| + ID ASSIGN InitVal { + $$ = new DefAST(); + $$->id = unique_ptr($1); + $$->initVal = unique_ptr($3); + }| + ID Arrays { + $$ = new DefAST(); + $$->id = unique_ptr($1); + $$->arrays.swap($2->list); + }| + ID { + $$ = new DefAST(); + $$->id = unique_ptr($1); + }; + +// 数组 +Arrays: + LB Exp RB { + $$ = new ArraysAST(); + $$->list.push_back(unique_ptr($2)); + }| + Arrays LB Exp RB { + $$ = $1; + $$->list.push_back(unique_ptr($3)); + }; + + +// 变量或常量初值 +InitVal: + Exp { + $$ = new InitValAST(); + $$->exp = unique_ptr($1); + }| + LC RC { + $$ = new InitValAST(); + }| + LC InitValList RC { + $$ = new InitValAST(); + $$->initValList.swap($2->list); + }; + +// 变量列表 +InitValList: + InitValList COMMA InitVal { + $$ = $1; + $$->list.push_back(unique_ptr($3)); + }| + InitVal { + $$ = new InitValListAST(); + $$->list.push_back(unique_ptr($1)); + }; + +// 函数定义 +FuncDef: + BType ID LP FuncFParamList RP Block { + $$ = new FuncDefAST(); + $$->funcType = $1; + $$->id = unique_ptr($2); + $$->funcFParamList.swap($4->list); + $$->block = unique_ptr($6); + }| + BType ID LP RP Block { + $$ = new FuncDefAST(); + $$->funcType = $1; + $$->id = unique_ptr($2); + $$->block = unique_ptr($5); + }| + VoidType ID LP FuncFParamList RP Block { + $$ = new FuncDefAST(); + $$->funcType = $1; + $$->id = unique_ptr($2); + $$->funcFParamList.swap($4->list); + $$->block = unique_ptr($6); + }| + VoidType ID LP RP Block { + $$ = new FuncDefAST(); + $$->funcType = $1; + $$->id = unique_ptr($2); + $$->block = unique_ptr($5); + }; + +// 函数形参列表 +FuncFParamList: + FuncFParam { + $$ = new FuncFParamListAST(); + $$->list.push_back(unique_ptr($1)); + }| + FuncFParamList COMMA FuncFParam { + $$ = $1; + $$->list.push_back(unique_ptr($3)); + }; + +// 函数形参 +FuncFParam: + BType ID { + $$ = new FuncFParamAST(); + $$->bType = $1; + $$->id = unique_ptr($2); + $$->isArray = false; + }| + BType ID LB RB { + $$ = new FuncFParamAST(); + $$->bType = $1; + $$->id = unique_ptr($2); + $$->isArray = true; + }| + BType ID LB RB Arrays { + $$ = new FuncFParamAST(); + $$->bType = $1; + $$->id = unique_ptr($2); + $$->isArray = true; + $$->arrays.swap($5->list); + }; + +// 语句块 +Block: + LC RC { + $$ = new BlockAST(); + }| + LC BlockItemList RC { + $$ = new BlockAST(); + $$->blockItemList.swap($2->list); + }; + +// 语句块项列表 +BlockItemList: + BlockItem { + $$ = new BlockItemListAST(); + $$->list.push_back(unique_ptr($1)); + }| + BlockItemList BlockItem { + $$ = $1; + $$->list.push_back(unique_ptr($2)); + }; + +// 语句块项 +BlockItem: + Decl { + $$ = new BlockItemAST(); + $$->decl = unique_ptr($1); + }| + Stmt { + $$ = new BlockItemAST(); + $$->stmt = unique_ptr($1); + }; + +// 语句,根据type判断是何种类型的Stmt +Stmt: + SEMICOLON { + $$ = new StmtAST(); + $$->sType = SEMI; + }| + LVal ASSIGN Exp SEMICOLON { + $$ = new StmtAST(); + $$->sType = ASS; + $$->lVal = unique_ptr($1); + $$->exp = unique_ptr($3); + }| + Exp SEMICOLON { + $$ = new StmtAST(); + $$->sType = EXP; + $$->exp = unique_ptr($1); + }| + CONTINUE SEMICOLON { + $$ = new StmtAST(); + $$->sType = CONT; + }| + BREAK SEMICOLON { + $$ = new StmtAST(); + $$->sType = BRE; + }| + Block { + $$ = new StmtAST(); + $$->sType = BLK; + $$->block = unique_ptr($1); + }| + ReturnStmt { + $$ = new StmtAST(); + $$->sType = RET; + $$->returnStmt = unique_ptr($1); + }| + SelectStmt { + $$ = new StmtAST(); + $$->sType = SEL; + $$->selectStmt = unique_ptr($1); + }| + IterationStmt { + $$ = new StmtAST(); + $$->sType = ITER; + $$->iterationStmt = unique_ptr($1); + }; + +//选择语句 +SelectStmt: + IF LP Cond RP Stmt %prec LOWER_THEN_ELSE { + $$ = new SelectStmtAST(); + $$->cond = unique_ptr($3); + $$->ifStmt = unique_ptr($5); + }| + IF LP Cond RP Stmt ELSE Stmt { + $$ = new SelectStmtAST(); + $$->cond = unique_ptr($3); + $$->ifStmt = unique_ptr($5); + $$->elseStmt = unique_ptr($7); + }; + +//循环语句 +IterationStmt: + WHILE LP Cond RP Stmt { + $$ = new IterationStmtAST(); + $$->cond = unique_ptr($3); + $$->stmt = unique_ptr($5); + }; + +//返回语句 +ReturnStmt: + RETURN Exp SEMICOLON { + $$ = new ReturnStmtAST(); + $$->exp = unique_ptr($2); + }| + RETURN SEMICOLON { + $$ = new ReturnStmtAST(); + }; + +// 表达式 +Exp: + AddExp { + $$ = $1; + }; + +// 条件表达式 +Cond: + LOrExp { + $$ = $1; + }; + +// 左值表达式 +LVal: + ID { + $$ = new LValAST(); + $$->id = unique_ptr($1); + }| + ID Arrays { + $$ = new LValAST(); + $$->id = unique_ptr($1); + $$->arrays.swap($2->list); + }; + +// 基本表达式 +PrimaryExp: + LP Exp RP { + $$ = new PrimaryExpAST(); + $$->exp = unique_ptr($2); + }| + LVal { + $$ = new PrimaryExpAST(); + $$->lval = unique_ptr($1); + }| + Number { + $$ = new PrimaryExpAST(); + $$->number = unique_ptr($1); + }; + +// 数值 +Number: + INT { + $$ = new NumberAST(); + $$->isInt = true; + $$->intval = $1; + }| + FLOAT { + $$ = new NumberAST(); + $$->isInt = false; + $$->floatval = $1; + }; + +// 一元表达式 +UnaryExp: + PrimaryExp { + $$ = new UnaryExpAST(); + $$->primaryExp = unique_ptr($1); + }| + Call { + $$ = new UnaryExpAST(); + $$->call = unique_ptr($1); + }| + UnaryOp UnaryExp { + $$ = new UnaryExpAST(); + $$->op = $1; + $$->unaryExp = unique_ptr($2); + }; + +//函数调用 +Call: + ID LP RP { + $$ = new CallAST(); + $$->id = unique_ptr($1); + }| + ID LP FuncCParamList RP { + $$ = new CallAST(); + $$->id = unique_ptr($1); + $$->funcCParamList.swap($3->list); + }; + +// 单目运算符,这里可能与优先级相关,不删除该非终结符 +UnaryOp: + ADD { + $$ = UOP_ADD; + }| + MINUS { + $$ = UOP_MINUS; + }| + NOT { + $$ = UOP_NOT; + }; + +// 函数实参表 +FuncCParamList: + Exp { + $$ = new FuncCParamListAST(); + $$->list.push_back(unique_ptr($1)); + }| + FuncCParamList COMMA Exp { + $$ = (FuncCParamListAST*) $1; + $$->list.push_back(unique_ptr($3)); + }; + +//乘除模表达式 +MulExp: + UnaryExp { + $$ = new MulExpAST(); + $$->unaryExp = unique_ptr($1); + }| + MulExp MUL UnaryExp { + $$ = new MulExpAST(); + $$->mulExp = unique_ptr($1); + $$->op = MOP_MUL; + $$->unaryExp = unique_ptr($3); + }| + MulExp DIV UnaryExp { + $$ = new MulExpAST(); + $$->mulExp = unique_ptr($1); + $$->op = MOP_DIV; + $$->unaryExp = unique_ptr($3); + }| + MulExp MOD UnaryExp { + $$ = new MulExpAST(); + $$->mulExp = unique_ptr($1); + $$->op = MOP_MOD; + $$->unaryExp = unique_ptr($3); + }; + +// 加减表达式 +AddExp: + MulExp { + $$ = new AddExpAST(); + $$->mulExp = unique_ptr($1); + }| + AddExp ADD MulExp { + $$ = new AddExpAST(); + $$->addExp = unique_ptr($1); + $$->op = AOP_ADD; + $$->mulExp = unique_ptr($3); + }| + AddExp MINUS MulExp { + $$ = new AddExpAST(); + $$->addExp = unique_ptr($1); + $$->op = AOP_MINUS; + $$->mulExp = unique_ptr($3); + }; + +// 关系表达式 +RelExp: + AddExp { + $$ = new RelExpAST(); + $$->addExp = unique_ptr($1); + }| + RelExp GTE AddExp { + $$ = new RelExpAST(); + $$->relExp = unique_ptr($1); + $$->op = ROP_GTE; + $$->addExp = unique_ptr($3); + }| + RelExp LTE AddExp { + $$ = new RelExpAST(); + $$->relExp = unique_ptr($1); + $$->op = ROP_LTE; + $$->addExp = unique_ptr($3); + }| + RelExp GT AddExp { + $$ = new RelExpAST(); + $$->relExp = unique_ptr($1); + $$->op = ROP_GT; + $$->addExp = unique_ptr($3); + }| + RelExp LT AddExp { + $$ = new RelExpAST(); + $$->relExp = unique_ptr($1); + $$->op = ROP_LT; + $$->addExp = unique_ptr($3); + }; + +// 相等性表达式 +EqExp: + RelExp { + $$ = new EqExpAST(); + $$->relExp = unique_ptr($1); + }| + EqExp EQ RelExp { + $$ = new EqExpAST(); + $$->eqExp = unique_ptr($1); + $$->op = EOP_EQ; + $$->relExp = unique_ptr($3); + }| + EqExp NEQ RelExp { + $$ = new EqExpAST(); + $$->eqExp = unique_ptr($1); + $$->op = EOP_NEQ; + $$->relExp = unique_ptr($3); + }; + +// 逻辑与表达式 +LAndExp: + EqExp { + $$ = new LAndExpAST(); + $$->eqExp = unique_ptr($1); + }| + LAndExp AND EqExp { + $$ = new LAndExpAST(); + $$->lAndExp = unique_ptr($1); + $$->eqExp = unique_ptr($3); + }; + +// 逻辑或表达式 +LOrExp: + LAndExp { + $$ = new LOrExpAST(); + $$->lAndExp = unique_ptr($1); + }| + LOrExp OR LAndExp { + $$ = new LOrExpAST(); + $$->lOrExp = unique_ptr($1); + $$->lAndExp = unique_ptr($3); + }; +%% + +void initFileName(char *name) { + strcpy(filename, name); +} + +void yyerror(const char* fmt) { + printf("%s:%d ", filename, yylloc.first_line); + printf("%s\n", fmt); +} diff --git a/compiler/src/parser/tokens.cpp b/compiler/src/parser/tokens.cpp new file mode 100644 index 0000000..91950f2 --- /dev/null +++ b/compiler/src/parser/tokens.cpp @@ -0,0 +1,2121 @@ +#line 1 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.cpp" + +#line 3 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + #define YY_LINENO_REWIND_TO(dst) \ + do {\ + const char *p;\ + for ( p = yy_cp-1; p >= (dst); --p)\ + if ( *p == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +#define YY_NUM_RULES 42 +#define YY_END_OF_BUFFER 43 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[122] = + { 0, + 0, 0, 43, 41, 38, 37, 28, 34, 41, 20, + 21, 32, 31, 26, 30, 41, 33, 1, 1, 27, + 17, 29, 16, 13, 22, 23, 13, 13, 13, 13, + 13, 13, 13, 13, 24, 41, 25, 19, 35, 2, + 0, 39, 2, 1, 0, 0, 0, 1, 15, 18, + 14, 13, 13, 13, 13, 13, 8, 13, 13, 13, + 13, 36, 0, 2, 0, 0, 0, 39, 0, 2, + 0, 2, 0, 1, 13, 13, 13, 13, 3, 13, + 13, 13, 0, 2, 40, 0, 2, 2, 0, 0, + 0, 13, 13, 13, 9, 13, 13, 5, 13, 0, + + 0, 0, 2, 11, 6, 13, 4, 13, 10, 0, + 2, 0, 2, 2, 13, 7, 2, 2, 13, 12, + 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 1, 1, 1, 5, 6, 1, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, + 16, 16, 16, 16, 16, 17, 17, 1, 18, 19, + 20, 21, 1, 1, 22, 22, 22, 22, 23, 24, + 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, + 25, 25, 25, 25, 25, 25, 25, 28, 25, 25, + 29, 1, 30, 1, 25, 1, 31, 32, 33, 34, + + 35, 36, 25, 37, 38, 25, 39, 40, 25, 41, + 42, 27, 25, 43, 44, 45, 46, 47, 48, 49, + 25, 25, 50, 51, 52, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[53] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 1, 4, 4, 4, 1, 1, 1, + 1, 4, 4, 4, 5, 5, 5, 5, 1, 1, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, + 1, 1 + } ; + +static const flex_int16_t yy_base[128] = + { 0, + 0, 0, 243, 293, 293, 293, 222, 293, 234, 293, + 293, 293, 293, 293, 293, 38, 47, 49, 58, 293, + 219, 218, 216, 0, 293, 293, 187, 174, 175, 173, + 22, 173, 165, 168, 293, 149, 293, 293, 293, 84, + 69, 0, 110, 74, 79, 101, 186, 124, 293, 293, + 293, 0, 160, 151, 145, 146, 0, 137, 134, 138, + 124, 293, 139, 293, 71, 114, 121, 0, 148, 293, + 52, 151, 0, 102, 130, 15, 122, 122, 0, 106, + 114, 98, 88, 154, 293, 127, 157, 293, 105, 104, + 186, 83, 76, 74, 0, 61, 45, 0, 51, 194, + + 202, 169, 205, 0, 0, 41, 0, 38, 0, 208, + 211, 217, 233, 293, 30, 0, 293, 293, 35, 0, + 293, 270, 275, 280, 283, 287, 53 + } ; + +static const flex_int16_t yy_def[128] = + { 0, + 121, 1, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 122, 121, 121, 122, 122, 122, 122, + 122, 122, 122, 122, 121, 121, 121, 121, 121, 121, + 123, 124, 121, 121, 121, 121, 125, 121, 121, 121, + 121, 122, 122, 122, 122, 122, 122, 122, 122, 122, + 122, 121, 121, 121, 123, 126, 123, 124, 121, 121, + 121, 121, 127, 125, 122, 122, 122, 122, 122, 122, + 122, 122, 121, 121, 121, 121, 121, 121, 127, 127, + 121, 122, 122, 122, 122, 122, 122, 122, 122, 121, + + 121, 121, 121, 122, 122, 122, 122, 122, 122, 121, + 121, 121, 121, 121, 122, 122, 121, 121, 122, 122, + 0, 121, 121, 121, 121, 121, 121 + } ; + +static const flex_int16_t yy_nxt[346] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, + 23, 24, 24, 24, 24, 24, 24, 24, 25, 26, + 24, 27, 28, 24, 29, 30, 24, 31, 24, 24, + 24, 24, 32, 24, 24, 24, 33, 34, 24, 35, + 36, 37, 40, 40, 40, 41, 89, 57, 93, 94, + 42, 43, 58, 44, 44, 45, 72, 72, 72, 120, + 43, 46, 48, 48, 48, 119, 47, 66, 116, 66, + 46, 115, 67, 46, 67, 109, 43, 108, 44, 44, + 45, 43, 46, 45, 45, 45, 46, 47, 40, 40, + + 40, 46, 84, 84, 84, 107, 63, 64, 46, 64, + 71, 106, 71, 46, 90, 72, 72, 72, 63, 64, + 105, 104, 66, 64, 40, 40, 40, 85, 91, 66, + 101, 100, 69, 70, 67, 70, 43, 99, 48, 48, + 48, 87, 87, 87, 69, 70, 46, 98, 83, 70, + 83, 97, 96, 84, 84, 84, 95, 86, 46, 86, + 92, 82, 87, 87, 87, 72, 72, 72, 84, 84, + 84, 87, 87, 87, 88, 81, 88, 64, 80, 64, + 70, 79, 70, 103, 103, 103, 88, 78, 77, 64, + 88, 76, 70, 64, 75, 102, 70, 102, 73, 62, + + 103, 103, 103, 110, 61, 110, 60, 59, 111, 111, + 111, 112, 56, 112, 55, 54, 113, 113, 113, 103, + 103, 103, 111, 111, 111, 111, 111, 111, 114, 53, + 114, 113, 113, 113, 117, 51, 117, 50, 49, 39, + 114, 38, 121, 121, 114, 121, 117, 113, 113, 113, + 117, 121, 121, 121, 121, 121, 118, 121, 118, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 118, 121, + 121, 121, 118, 52, 52, 65, 65, 65, 65, 65, + 68, 121, 68, 68, 68, 74, 74, 67, 67, 67, + 67, 67, 3, 121, 121, 121, 121, 121, 121, 121, + + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121 + } ; + +static const flex_int16_t yy_chk[346] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 16, 16, 16, 17, 127, 31, 76, 76, + 17, 18, 31, 18, 18, 18, 71, 71, 71, 119, + 19, 18, 19, 19, 19, 115, 18, 41, 108, 65, + 19, 106, 41, 18, 65, 99, 44, 97, 44, 44, + 44, 45, 19, 45, 45, 45, 44, 18, 40, 40, + + 40, 45, 83, 83, 83, 96, 40, 40, 44, 40, + 46, 94, 46, 45, 74, 46, 46, 46, 40, 40, + 93, 92, 66, 40, 43, 43, 43, 66, 74, 67, + 90, 89, 43, 43, 67, 43, 48, 82, 48, 48, + 48, 86, 86, 86, 43, 43, 48, 81, 63, 43, + 63, 80, 78, 63, 63, 63, 77, 69, 48, 69, + 75, 61, 69, 69, 69, 72, 72, 72, 84, 84, + 84, 87, 87, 87, 72, 60, 72, 84, 59, 84, + 87, 58, 87, 102, 102, 102, 72, 56, 55, 84, + 72, 54, 87, 84, 53, 91, 87, 91, 47, 36, + + 91, 91, 91, 100, 34, 100, 33, 32, 100, 100, + 100, 101, 30, 101, 29, 28, 101, 101, 101, 103, + 103, 103, 110, 110, 110, 111, 111, 111, 103, 27, + 103, 112, 112, 112, 111, 23, 111, 22, 21, 9, + 103, 7, 3, 0, 103, 0, 111, 113, 113, 113, + 111, 0, 0, 0, 0, 0, 113, 0, 113, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, + 0, 0, 113, 122, 122, 123, 123, 123, 123, 123, + 124, 0, 124, 124, 124, 125, 125, 126, 126, 126, + 126, 126, 121, 121, 121, 121, 121, 121, 121, 121, + + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, + 121, 121, 121, 121, 121 + } ; + +/* Table of booleans, true if rule could match eol. */ +static const flex_int32_t yy_rule_can_match_eol[43] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 1, 0, 0, }; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +#line 4 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" + #include + #include "ast.h" + #include "parser.hpp" + //extern "C" int yywrap() {} + int yycolumn=1; + #define YY_USER_ACTION yylloc.first_line=yylloc.last_line=yylineno; \ + yylloc.first_column=yycolumn; yylloc.last_column=yycolumn+yyleng-1; yycolumn+=yyleng; +#line 596 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.cpp" +/* TODO: Float rules is direct copied from C + * maybe shrinking down is needed? + */ +/* EXP ([Ee][-+]?[0-9]+) */ +/* FLOAT (([0-9]*\.[0-9]+|[0-9]+\.){EXP}?[fF]?)|[0-9]+{EXP}[fF]? */ +/* Invalid ([0-9]+[A-Za-z]+[0-9]*|0[0-9]*[8-9]+[0-9]*) */ +#line 603 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.cpp" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals ( void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr ); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 44 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" + + +#line 823 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.cpp" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 122 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 293 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + yylineno++; +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 46 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{yylval.int_val = strtol(yytext, nullptr, 0); return INT;} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 47 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{yylval.float_val = strtof(yytext, nullptr); return FLOAT;} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 49 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return INTTYPE;} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 50 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return FLOATTYPE;} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 51 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return VOID;} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 52 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return CONST;} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 53 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return RETURN;} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 54 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return IF;} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 55 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return ELSE;} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 56 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return WHILE;} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 57 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return BREAK;} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 58 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return CONTINUE;} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 60 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{yylval.token = new string(yytext); return ID;} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 62 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return GTE;} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 63 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return LTE;} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 64 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return GT;} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 65 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return LT;} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 66 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return EQ;} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 67 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return NEQ;} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 69 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return LP;} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 70 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return RP;} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 71 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return LB;} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 72 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return RB;} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 73 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return LC;} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 74 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return RC;} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 75 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return COMMA;} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 76 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return SEMICOLON;} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 78 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return NOT;} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 79 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return ASSIGN;} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 80 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return MINUS;} + YY_BREAK +case 31: +YY_RULE_SETUP +#line 81 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return ADD;} + YY_BREAK +case 32: +YY_RULE_SETUP +#line 82 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return MUL;} + YY_BREAK +case 33: +YY_RULE_SETUP +#line 83 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return DIV;} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 84 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return MOD;} + YY_BREAK +case 35: +YY_RULE_SETUP +#line 85 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return AND;} + YY_BREAK +case 36: +YY_RULE_SETUP +#line 86 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{return OR;} + YY_BREAK +case 37: +/* rule 37 can match eol */ +YY_RULE_SETUP +#line 88 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{yycolumn=1;} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 89 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{/* Ignore useless whitespaces */} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 91 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{/* Ignore Comments */} + YY_BREAK +case 40: +/* rule 40 can match eol */ +YY_RULE_SETUP +#line 92 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{/* Ignore Comments */} + YY_BREAK +case 41: +YY_RULE_SETUP +#line 94 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +{printf("Error type A :Mysterious character \"%s\"\n\t at Line %d\n", yytext, yylineno);} + YY_BREAK +case 42: +YY_RULE_SETUP +#line 95 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" +ECHO; + YY_BREAK +#line 1102 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.cpp" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 122 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 122 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 121); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp ) +{ + char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = (yy_n_chars) + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + if ( c == '\n' ){ + --yylineno; + } + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + if ( c == '\n' ) + + yylineno++; +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + /* We do not touch yylineno unless the option is enabled. */ + yylineno = 1; + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 95 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" + + diff --git a/compiler/src/parser/tokens.hpp b/compiler/src/parser/tokens.hpp new file mode 100644 index 0000000..0d83884 --- /dev/null +++ b/compiler/src/parser/tokens.hpp @@ -0,0 +1,477 @@ +#ifndef yyHEADER_H +#define yyHEADER_H 1 +#define yyIN_HEADER 1 + +#line 5 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.hpp" + +#line 7 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.hpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +/* Begin user sect3 */ + +#define yywrap() (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +extern int yylineno; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#ifndef yy_create_buffer_ALREADY_DEFINED +#undef yy_create_buffer +#endif +#ifndef yy_delete_buffer_ALREADY_DEFINED +#undef yy_delete_buffer +#endif +#ifndef yy_scan_buffer_ALREADY_DEFINED +#undef yy_scan_buffer +#endif +#ifndef yy_scan_string_ALREADY_DEFINED +#undef yy_scan_string +#endif +#ifndef yy_scan_bytes_ALREADY_DEFINED +#undef yy_scan_bytes +#endif +#ifndef yy_init_buffer_ALREADY_DEFINED +#undef yy_init_buffer +#endif +#ifndef yy_flush_buffer_ALREADY_DEFINED +#undef yy_flush_buffer +#endif +#ifndef yy_load_buffer_state_ALREADY_DEFINED +#undef yy_load_buffer_state +#endif +#ifndef yy_switch_to_buffer_ALREADY_DEFINED +#undef yy_switch_to_buffer +#endif +#ifndef yypush_buffer_state_ALREADY_DEFINED +#undef yypush_buffer_state +#endif +#ifndef yypop_buffer_state_ALREADY_DEFINED +#undef yypop_buffer_state +#endif +#ifndef yyensure_buffer_stack_ALREADY_DEFINED +#undef yyensure_buffer_stack +#endif +#ifndef yylex_ALREADY_DEFINED +#undef yylex +#endif +#ifndef yyrestart_ALREADY_DEFINED +#undef yyrestart +#endif +#ifndef yylex_init_ALREADY_DEFINED +#undef yylex_init +#endif +#ifndef yylex_init_extra_ALREADY_DEFINED +#undef yylex_init_extra +#endif +#ifndef yylex_destroy_ALREADY_DEFINED +#undef yylex_destroy +#endif +#ifndef yyget_debug_ALREADY_DEFINED +#undef yyget_debug +#endif +#ifndef yyset_debug_ALREADY_DEFINED +#undef yyset_debug +#endif +#ifndef yyget_extra_ALREADY_DEFINED +#undef yyget_extra +#endif +#ifndef yyset_extra_ALREADY_DEFINED +#undef yyset_extra +#endif +#ifndef yyget_in_ALREADY_DEFINED +#undef yyget_in +#endif +#ifndef yyset_in_ALREADY_DEFINED +#undef yyset_in +#endif +#ifndef yyget_out_ALREADY_DEFINED +#undef yyget_out +#endif +#ifndef yyset_out_ALREADY_DEFINED +#undef yyset_out +#endif +#ifndef yyget_leng_ALREADY_DEFINED +#undef yyget_leng +#endif +#ifndef yyget_text_ALREADY_DEFINED +#undef yyget_text +#endif +#ifndef yyget_lineno_ALREADY_DEFINED +#undef yyget_lineno +#endif +#ifndef yyset_lineno_ALREADY_DEFINED +#undef yyset_lineno +#endif +#ifndef yyget_column_ALREADY_DEFINED +#undef yyget_column +#endif +#ifndef yyset_column_ALREADY_DEFINED +#undef yyset_column +#endif +#ifndef yywrap_ALREADY_DEFINED +#undef yywrap +#endif +#ifndef yyget_lval_ALREADY_DEFINED +#undef yyget_lval +#endif +#ifndef yyset_lval_ALREADY_DEFINED +#undef yyset_lval +#endif +#ifndef yyget_lloc_ALREADY_DEFINED +#undef yyget_lloc +#endif +#ifndef yyset_lloc_ALREADY_DEFINED +#undef yyset_lloc +#endif +#ifndef yyalloc_ALREADY_DEFINED +#undef yyalloc +#endif +#ifndef yyrealloc_ALREADY_DEFINED +#undef yyrealloc +#endif +#ifndef yyfree_ALREADY_DEFINED +#undef yyfree +#endif +#ifndef yytext_ALREADY_DEFINED +#undef yytext +#endif +#ifndef yyleng_ALREADY_DEFINED +#undef yyleng +#endif +#ifndef yyin_ALREADY_DEFINED +#undef yyin +#endif +#ifndef yyout_ALREADY_DEFINED +#undef yyout +#endif +#ifndef yy_flex_debug_ALREADY_DEFINED +#undef yy_flex_debug +#endif +#ifndef yylineno_ALREADY_DEFINED +#undef yylineno +#endif +#ifndef yytables_fload_ALREADY_DEFINED +#undef yytables_fload +#endif +#ifndef yytables_destroy_ALREADY_DEFINED +#undef yytables_destroy +#endif +#ifndef yyTABLES_NAME_ALREADY_DEFINED +#undef yyTABLES_NAME +#endif + +#line 95 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.l" + + +#line 475 "/home/seas0/Codes/compiler/carrotcompiler/src/parser/tokens.hpp" +#undef yyIN_HEADER +#endif /* yyHEADER_H */ diff --git a/compiler/src/parser/tokens.l b/compiler/src/parser/tokens.l new file mode 100644 index 0000000..4750f4d --- /dev/null +++ b/compiler/src/parser/tokens.l @@ -0,0 +1,95 @@ +%option noyywrap + +%{ + #include + #include "ast.h" + #include "parser.hpp" + //extern "C" int yywrap() {} + int yycolumn=1; + #define YY_USER_ACTION yylloc.first_line=yylloc.last_line=yylineno; \ + yylloc.first_column=yycolumn; yylloc.last_column=yycolumn+yyleng-1; yycolumn+=yyleng; +%} + +%option yylineno + +ID [a-z_A-Z][a-z_A-Z0-9]* + +INT_LIT ([1-9][0-9]*|0[0-7]*|(0x|0X)[0-9a-fA-F]+) + +/* TODO: Float rules is direct copied from C + * maybe shrinking down is needed? + */ +FLOAT_SUFFIX [fFlL] + +DEC_EXP ([Ee][-+]?[0-9]+) +DEC_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT ([0-9]*\.[0-9]+{DEC_EXP}?{FLOAT_SUFFIX}?) +DEC_FLOAT_LIT_HAVE_POINT_NO_RIGHT ([0-9]+\.{DEC_EXP}?{FLOAT_SUFFIX}?) +DEC_FLOAT_LIT_NO_POINT ([0-9]+{DEC_EXP}{FLOAT_SUFFIX}?) +DEC_FLOAT_LIT ({DEC_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT}|{DEC_FLOAT_LIT_HAVE_POINT_NO_RIGHT}|{DEC_FLOAT_LIT_NO_POINT}) + +HEX_EXP ([Pp][-+]?[0-9]+) +HEX_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT ((0[xX])[a-fA-F0-9]*\.[a-fA-F0-9]+{HEX_EXP}{FLOAT_SUFFIX}?) +HEX_FLOAT_LIT_HAVE_POINT_NO_RIGHT ((0[xX])[a-fA-F0-9]+\.{HEX_EXP}{FLOAT_SUFFIX}?) +HEX_FLOAT_LIT_NO_POINT ((0[xX])[a-fA-F0-9]+{HEX_EXP}{FLOAT_SUFFIX}?) +HEX_FLOAT_LIT ({HEX_FLOAT_LIT_HAVE_POINT_HAVE_RIGHT}|{HEX_FLOAT_LIT_HAVE_POINT_NO_RIGHT}|{HEX_FLOAT_LIT_NO_POINT}) + +FLOAT_LIT ({DEC_FLOAT_LIT}|{HEX_FLOAT_LIT}) +/* EXP ([Ee][-+]?[0-9]+) */ +/* FLOAT (([0-9]*\.[0-9]+|[0-9]+\.){EXP}?[fF]?)|[0-9]+{EXP}[fF]? */ + +SingleLineComment "//".* +MultilineComment "/*"([^\*]|(\*)*[^\*/])*(\*)*"*/" + +/* Invalid ([0-9]+[A-Za-z]+[0-9]*|0[0-9]*[8-9]+[0-9]*) */ +%% + +{INT_LIT} {yylval.int_val = strtol(yytext, nullptr, 0); return INT;} +{FLOAT_LIT} {yylval.float_val = strtof(yytext, nullptr); return FLOAT;} + +"int" {return INTTYPE;} +"float" {return FLOATTYPE;} +"void" {return VOID;} +"const" {return CONST;} +"return" {return RETURN;} +"if" {return IF;} +"else" {return ELSE;} +"while" {return WHILE;} +"break" {return BREAK;} +"continue" {return CONTINUE;} + +{ID} {yylval.token = new string(yytext); return ID;} + +">=" {return GTE;} +"<=" {return LTE;} +">" {return GT;} +"<" {return LT;} +"==" {return EQ;} +"!=" {return NEQ;} + +"(" {return LP;} +")" {return RP;} +"[" {return LB;} +"]" {return RB;} +"{" {return LC;} +"}" {return RC;} +"," {return COMMA;} +";" {return SEMICOLON;} + +"!" {return NOT;} +"=" {return ASSIGN;} +"-" {return MINUS;} +"+" {return ADD;} +"*" {return MUL;} +"/" {return DIV;} +"%" {return MOD;} +"&&" {return AND;} +"||" {return OR;} + +[\n] {yycolumn=1;} +[ \r\t] {/* Ignore useless whitespaces */} + +{SingleLineComment} {/* Ignore Comments */} +{MultilineComment} {/* Ignore Comments */} + +. {printf("Error type A :Mysterious character \"%s\"\n\t at Line %d\n", yytext, yylineno);} +%% diff --git a/compiler/src/riscv/CMakeLists.txt b/compiler/src/riscv/CMakeLists.txt new file mode 100644 index 0000000..b622912 --- /dev/null +++ b/compiler/src/riscv/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.21) + +set(SOURCE_FILES "riscv.cpp" instruction.cpp optimize.cpp backend.cpp regalloc.cpp) + +add_library(riscv STATIC ${SOURCE_FILES}) + +target_link_libraries(riscv PRIVATE ir) +target_include_directories(riscv PRIVATE ${CMAKE_SOURCE_DIR}/src/ir) \ No newline at end of file diff --git a/compiler/src/riscv/backend.cpp b/compiler/src/riscv/backend.cpp new file mode 100644 index 0000000..cde8fd9 --- /dev/null +++ b/compiler/src/riscv/backend.cpp @@ -0,0 +1,970 @@ +#include "backend.h" +#include + +void RiscvBuilder::initializeRegisterFile() { + // todo:分配寄存器堆,初始化寄存器堆各项参数 + // assert(false); +} + +// 进行标号 +// 未知指令:FNeg +// 注意:IR中因为没有addi和add和浮点的区别,该步操作由build操作进行修正 +const std::map toRiscvOp = { + {Instruction::OpID::Add, RiscvInstr::InstrType::ADD}, + {Instruction::OpID::Sub, RiscvInstr::InstrType::SUB}, + {Instruction::OpID::Mul, RiscvInstr::InstrType::MUL}, + {Instruction::OpID::SDiv, RiscvInstr::InstrType::DIV}, + {Instruction::OpID::SRem, RiscvInstr::InstrType::REM}, + {Instruction::OpID::FAdd, RiscvInstr::InstrType::FADD}, + {Instruction::OpID::FSub, RiscvInstr::InstrType::FSUB}, + {Instruction::OpID::FMul, RiscvInstr::InstrType::FMUL}, + {Instruction::OpID::FDiv, RiscvInstr::InstrType::FDIV}, + {Instruction::OpID::Ret, RiscvInstr::InstrType::RET}, + {Instruction::OpID::ICmp, RiscvInstr::InstrType::ICMP}, + {Instruction::OpID::FCmp, RiscvInstr::InstrType::FCMP}, + {Instruction::OpID::Call, RiscvInstr::InstrType::CALL}, + {Instruction::OpID::SItoFP, RiscvInstr::InstrType::SITOFP}, + {Instruction::OpID::FPtoSI, RiscvInstr::InstrType::FPTOSI}, + {Instruction::OpID::Or, RiscvInstr::InstrType::OR}, + {Instruction::OpID::And, RiscvInstr::InstrType::AND}, + {Instruction::OpID::Shl, RiscvInstr::InstrType::SHL}, + {Instruction::OpID::LShr, RiscvInstr::InstrType::LSHR}, + {Instruction::OpID::AShr, RiscvInstr::InstrType::ASHR}, + {Instruction::OpID::Load, RiscvInstr::InstrType::LW}, + {Instruction::OpID::Store, RiscvInstr::InstrType::SW}, +}; + +int LabelCount = 0; +std::map rbbLabel; +std::map functionLabel; +std::string toLabel(int ind) { return ".L" + std::to_string(ind); } + +RiscvBasicBlock *createRiscvBasicBlock(BasicBlock *bb) { + if (bb == nullptr) { + LabelCount++; + return new RiscvBasicBlock(toLabel(LabelCount), LabelCount); + } + if (rbbLabel.count(bb)) + return rbbLabel[bb]; + LabelCount++; + auto cur = new RiscvBasicBlock(toLabel(LabelCount), LabelCount); + return rbbLabel[bb] = cur; +} + +RiscvFunction *createRiscvFunction(Function *foo) { + assert(foo != nullptr); + if (functionLabel.count(foo) == 0) { + auto ty = RiscvOperand::Void; + switch (foo->type_->tid_) { + case Type::VoidTyID: + ty = RiscvOperand::Void; + break; + case Type::IntegerTyID: + ty = RiscvOperand::IntReg; + break; + case Type::FloatTyID: + ty = RiscvOperand::FloatReg; + break; + } + RiscvFunction *cur = + new RiscvFunction(foo->name_, foo->arguments_.size(), ty); + return functionLabel[foo] = cur; + } + return functionLabel[foo]; +} + +BinaryRiscvInst *RiscvBuilder::createBinaryInstr(RegAlloca *regAlloca, + BinaryInst *binaryInstr, + RiscvBasicBlock *rbb) { + auto id = toRiscvOp.at(binaryInstr->op_id_); + // 立即数处理 + + // If both operands are imm value, caculate the result directly and save to + // binaryInstr value. + if (binaryInstr->operands_[0]->is_constant() && + binaryInstr->operands_[1]->is_constant() && + dynamic_cast(binaryInstr->operands_[0]) != nullptr) { + int value[] = { + static_cast(binaryInstr->operands_[0])->value_, + static_cast(binaryInstr->operands_[1])->value_}; + int value_result; + switch (binaryInstr->op_id_) { + case Instruction::OpID::Add: + value_result = value[0] + value[1]; + break; + case Instruction::OpID::Sub: + value_result = value[0] - value[1]; + break; + case Instruction::OpID::Mul: + value_result = value[0] * value[1]; + break; + case Instruction::OpID::SDiv: + value_result = value[0] / value[1]; + break; + case Instruction::OpID::SRem: + value_result = value[0] % value[1]; + break; + default: + std::cerr << "[Fatal Error] Binary instruction immediate caculation not " + "implemented." + << std::endl; + std::terminate(); + } + rbb->addInstrBack( + new MoveRiscvInst(regAlloca->findReg(binaryInstr, rbb, nullptr, 0, 0), + value_result, rbb)); + return nullptr; + } + BinaryRiscvInst *instr = new BinaryRiscvInst( + id, regAlloca->findReg(binaryInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findReg(binaryInstr->operands_[1], rbb, nullptr, 1), + regAlloca->findReg(binaryInstr, rbb, nullptr, 1, 0), rbb, true); + return instr; +} + +UnaryRiscvInst *RiscvBuilder::createUnaryInstr(RegAlloca *regAlloca, + UnaryInst *unaryInstr, + RiscvBasicBlock *rbb) { + UnaryRiscvInst *instr = new UnaryRiscvInst( + toRiscvOp.at(unaryInstr->op_id_), + regAlloca->findReg(unaryInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findReg(unaryInstr, rbb, nullptr, 1, 0), rbb); + return instr; +} + +// IR中的Store对应到RISCV为MOV指令或浮点MOV指令或LI指令或真正的store指令 +std::vector RiscvBuilder::createStoreInstr(RegAlloca *regAlloca, + StoreInst *storeInstr, + RiscvBasicBlock *rbb) { + auto testConstInt = dynamic_cast(storeInstr->operands_[0]); + if (testConstInt != nullptr) { + // 整数部分可以直接li指令 + std::vector ans; + auto regPos = getRegOperand("t0"); + ans.push_back( + new MoveRiscvInst(regPos, new RiscvConst(testConstInt->value_), rbb)); + // 指针类型找ptr + if (storeInstr->operands_[1]->type_->tid_ == Type::TypeID::PointerTyID) + ans.push_back(new StoreRiscvInst( + storeInstr->operands_[0]->type_, regPos, + regAlloca->findMem(storeInstr->operands_[1], rbb, nullptr, 0), rbb)); + else + ans.push_back(new StoreRiscvInst( + storeInstr->operands_[0]->type_, regPos, + regAlloca->findMem(storeInstr->operands_[1], rbb, nullptr, 0), rbb)); + return ans; + } + // 真正的store:第二操作数为一个指针类型 + if (storeInstr->operands_[1]->type_->tid_ == Type::TypeID::PointerTyID) { + auto curType = static_cast(storeInstr->operands_[1]->type_); + + // Alignment check. + // if (calcTypeSize(curType->contained_) > 4) { + // auto mem = + // regAlloca->findMem(storeInstr->operands_[1], rbb, nullptr, false); + // if (static_cast(mem)->shift_ & 7) { + // std::cerr << "[Error] Alignment error." << std::endl; + // std::terminate(); + // } + // } + + StoreRiscvInst *instr = new StoreRiscvInst( + curType->contained_, + regAlloca->findReg(storeInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findMem(storeInstr->operands_[1], rbb, nullptr, 0), rbb); + return {instr}; + } + // 下面为整型或浮点的mov + // 浮点部分需要提前写入内存中,然后等效于直接mov + // TODO:先把浮点常数以全局变量形式存入内存中,再直接fmv + std::vector ans; + auto regPos = regAlloca->findReg(storeInstr->operands_[0], rbb, nullptr, 1); + ans.push_back(new MoveRiscvInst( + regAlloca->findReg(storeInstr->operands_[1], rbb), regPos, rbb)); + ans.push_back(new StoreRiscvInst(storeInstr->operands_[0]->type_, regPos, + regAlloca->findMem(storeInstr->operands_[0]), + rbb)); + return ans; +} + +// Load 指令仅一个参数!它本身就是一个value +std::vector RiscvBuilder::createLoadInstr(RegAlloca *regAlloca, + LoadInst *loadInstr, + RiscvBasicBlock *rbb) { + assert(loadInstr->operands_[0]->type_->tid_ == Type::TypeID::PointerTyID); + auto curType = static_cast(loadInstr->operands_[0]->type_); + // if (calcTypeSize(curType->contained_) > 4) { + // auto mem = regAlloca->findMem(loadInstr->operands_[0], rbb, nullptr, false); + // if (static_cast(mem)->shift_ & 7) { + // std::cerr << "[Error] Alignment error." << std::endl; + // std::terminate(); + // } + // } + std::vector ans; + auto regPos = + regAlloca->findReg(static_cast(loadInstr), rbb, nullptr, 1, 0); + ans.push_back(new LoadRiscvInst( + curType->contained_, regPos, + regAlloca->findMem(loadInstr->operands_[0], rbb, nullptr, false), rbb)); + return ans; +} + +ICmpRiscvInstr *RiscvBuilder::createICMPInstr(RegAlloca *regAlloca, + ICmpInst *icmpInstr, + BranchInst *brInstr, + RiscvBasicBlock *rbb) { + ICmpRiscvInstr *instr = new ICmpRiscvInstr( + icmpInstr->icmp_op_, + regAlloca->findReg(icmpInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findReg(icmpInstr->operands_[1], rbb, nullptr, 1), + createRiscvBasicBlock(static_cast(brInstr->operands_[1])), + createRiscvBasicBlock(static_cast(brInstr->operands_[2])), + rbb); + return instr; +} + +ICmpRiscvInstr *RiscvBuilder::createICMPSInstr(RegAlloca *regAlloca, + ICmpInst *icmpInstr, + RiscvBasicBlock *rbb) { + bool swap = ICmpSRiscvInstr::ICmpOpSName.count(icmpInstr->icmp_op_) == 0; + if (swap) { + std::swap(icmpInstr->operands_[0], icmpInstr->operands_[1]); + icmpInstr->icmp_op_ = + ICmpRiscvInstr::ICmpOpEquiv.find(icmpInstr->icmp_op_)->second; + } + bool inv = false; + switch (icmpInstr->icmp_op_) { + case ICmpInst::ICMP_SGE: + case ICmpInst::ICMP_SLE: + case ICmpInst::ICMP_UGE: + case ICmpInst::ICMP_ULE: + inv = true; + default: + break; + } + ICmpSRiscvInstr *instr = new ICmpSRiscvInstr( + icmpInstr->icmp_op_, + regAlloca->findReg(icmpInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findReg(icmpInstr->operands_[1], rbb, nullptr, 1), + regAlloca->findReg(icmpInstr, rbb, nullptr, 1, 0), rbb); + rbb->addInstrBack(instr); + if (inv) { + auto instr_reg = regAlloca->findReg(icmpInstr, rbb, nullptr, 1, 0); + rbb->addInstrBack(new BinaryRiscvInst(RiscvInstr::XORI, instr_reg, + new RiscvConst(1), instr_reg, rbb)); + } + return instr; +} + +RiscvInstr *RiscvBuilder::createFCMPInstr(RegAlloca *regAlloca, + FCmpInst *fcmpInstr, + RiscvBasicBlock *rbb) { + // Deal with always true + if (fcmpInstr->fcmp_op_ == fcmpInstr->FCMP_TRUE || + fcmpInstr->fcmp_op_ == fcmpInstr->FCMP_FALSE) { + auto instr = + new MoveRiscvInst(regAlloca->findReg(fcmpInstr, rbb, nullptr, 1, 0), + fcmpInstr->fcmp_op_ == fcmpInstr->FCMP_TRUE, rbb); + rbb->addInstrBack(instr); + return instr; + } + bool swap = FCmpRiscvInstr::FCmpOpName.count(fcmpInstr->fcmp_op_) == 0; + if (swap) { + std::swap(fcmpInstr->operands_[0], fcmpInstr->operands_[1]); + fcmpInstr->fcmp_op_ = + FCmpRiscvInstr::FCmpOpEquiv.find(fcmpInstr->fcmp_op_)->second; + } + bool inv = false; + bool inv_classify = false; + switch (fcmpInstr->fcmp_op_) { + case FCmpInst::FCMP_ONE: + case FCmpInst::FCMP_UNE: + inv = true; + default: + break; + } + switch (fcmpInstr->fcmp_op_) { + case FCmpInst::FCMP_OEQ: + case FCmpInst::FCMP_OGT: + case FCmpInst::FCMP_OGE: + case FCmpInst::FCMP_OLT: + case FCmpInst::FCMP_OLE: + case FCmpInst::FCMP_ONE: + case FCmpInst::FCMP_ORD: + inv_classify = true; + default: + break; + } + + if (inv_classify) { + std::cerr << "[Warning] Not implemented FCLASS yet.\n"; + } + FCmpRiscvInstr *instr = new FCmpRiscvInstr( + fcmpInstr->fcmp_op_, + regAlloca->findReg(fcmpInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findReg(fcmpInstr->operands_[1], rbb, nullptr, 1), + regAlloca->findReg(fcmpInstr, rbb, nullptr, 1, 0), rbb); + rbb->addInstrBack(instr); + if (inv) { + auto instr_reg = regAlloca->findReg(fcmpInstr, rbb, nullptr, 1, 0); + rbb->addInstrBack(new BinaryRiscvInst(RiscvInstr::XORI, instr_reg, + new RiscvConst(1), instr_reg, rbb)); + return instr; + } + return instr; +} + +CallRiscvInst *RiscvBuilder::createCallInstr(RegAlloca *regAlloca, + CallInst *callInstr, + RiscvBasicBlock *rbb) { + // push 指令需要寄存器 + int argnum = callInstr->operands_.size() - 1; + // 涉及从Function 到RISCV function转换问题(第一个参数) + CallRiscvInst *instr = + new CallRiscvInst(createRiscvFunction(static_cast( + callInstr->operands_[argnum])), + rbb); + return instr; +} + +// 注意:return语句本身并不负责返回值的传递,该语句由storeRet函数实现 +ReturnRiscvInst *RiscvBuilder::createRetInstr(RegAlloca *regAlloca, + ReturnInst *returnInstr, + RiscvBasicBlock *rbb, + RiscvFunction *rfoo) { + RiscvOperand *reg_to_save = nullptr; + + // If ret i32 %4 + if (returnInstr->num_ops_ > 0) { + // 写返回值到 a0/fa0 中 + auto operand = returnInstr->operands_[0]; + if (operand->type_->tid_ == Type::TypeID::IntegerTyID) + reg_to_save = regAlloca->findSpecificReg(operand, "a0", rbb); + else if (operand->type_->tid_ == Type::TypeID::FloatTyID) + reg_to_save = regAlloca->findSpecificReg(operand, "fa0", rbb); + // auto instr = regAlloca->writeback(reg_to_save, rbb); + + rbb->addInstrBack(new MoveRiscvInst( + reg_to_save, regAlloca->findReg(operand, rbb, nullptr), rbb)); + } + + return new ReturnRiscvInst(rbb); +} + +BranchRiscvInstr *RiscvBuilder::createBrInstr(RegAlloca *regAlloca, + BranchInst *brInstr, + RiscvBasicBlock *rbb) { + + BranchRiscvInstr *instr; + if (brInstr->num_ops_ == 1) { + instr = new BranchRiscvInstr( + nullptr, nullptr, + createRiscvBasicBlock(static_cast(brInstr->operands_[0])), + rbb); + } else { + instr = new BranchRiscvInstr( + regAlloca->findReg(brInstr->operands_[0], rbb, nullptr, 1), + createRiscvBasicBlock(static_cast(brInstr->operands_[1])), + createRiscvBasicBlock(static_cast(brInstr->operands_[2])), + rbb); + } + return instr; +} + +SiToFpRiscvInstr *RiscvBuilder::createSiToFpInstr(RegAlloca *regAlloca, + SiToFpInst *sitofpInstr, + RiscvBasicBlock *rbb) { + return new SiToFpRiscvInstr( + regAlloca->findReg(sitofpInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findReg(static_cast(sitofpInstr), rbb, nullptr, 1, 0), + rbb); +} + +FpToSiRiscvInstr *RiscvBuilder::createFptoSiInstr(RegAlloca *regAlloca, + FpToSiInst *fptosiInstr, + RiscvBasicBlock *rbb) { + return new FpToSiRiscvInstr( + regAlloca->findReg(fptosiInstr->operands_[0], rbb, nullptr, 1), + regAlloca->findReg(static_cast(fptosiInstr), rbb, nullptr, 1, 0), + rbb); +} + +// 固定采用x30作为偏移量,x31作为乘法的LI指令地址 +RiscvInstr *RiscvBuilder::solveGetElementPtr(RegAlloca *regAlloca, + GetElementPtrInst *instr, + RiscvBasicBlock *rbb) { + Value *op0 = instr->get_operand(0); + RiscvOperand *dest = getRegOperand("t2"); + bool isConst = 1; // 能否用确定的形如 -12(sp)访问 + int finalOffset = 0; + if (dynamic_cast(op0) != nullptr) { + // 全局变量:使用la指令取基础地址 + isConst = 0; + rbb->addInstrBack(new LoadAddressRiscvInstr(dest, op0->name_, rbb)); + } else if (auto oi = dynamic_cast(op0)) { + // 获取指针指向的地址 + int varOffset = 0; + + rbb->addInstrBack(new MoveRiscvInst( + dest, regAlloca->findReg(op0, rbb, nullptr, 1, 1), rbb)); + + finalOffset += varOffset; + } + int curTypeSize = 0; + unsigned int num_operands = instr->num_ops_; + int indexVal, totalOffset = 0; + Type *cur_type = + static_cast(instr->get_operand(0)->type_)->contained_; + for (unsigned int i = 1; i <= num_operands - 1; i++) { + if (i > 1) + cur_type = static_cast(cur_type)->contained_; + Value *opi = instr->get_operand(i); + curTypeSize = calcTypeSize(cur_type); + if (auto ci = dynamic_cast(opi)) { + indexVal = ci->value_; + totalOffset += indexVal * curTypeSize; + } else { + // 存在变量参与偏移量计算 + isConst = 0; + // 考虑目标数是int还是float + RiscvOperand *mulTempReg = getRegOperand("t3"); + rbb->addInstrBack(new MoveRiscvInst(mulTempReg, curTypeSize, rbb)); + rbb->addInstrBack(new BinaryRiscvInst( + RiscvInstr::InstrType::MUL, regAlloca->findReg(opi, rbb, nullptr, 1), + mulTempReg, mulTempReg, rbb)); + rbb->addInstrBack(new BinaryRiscvInst(RiscvInstr::InstrType::ADD, + mulTempReg, dest, dest, rbb)); + } + } + // if (totalOffset > 0) + rbb->addInstrBack(new BinaryRiscvInst(RiscvInstr::InstrType::ADDI, dest, + new RiscvConst(totalOffset), dest, + rbb)); + rbb->addInstrBack( + new StoreRiscvInst(instr->type_, dest, regAlloca->findMem(instr), rbb)); + return nullptr; +} + +void RiscvBuilder::initRetInstr(RegAlloca *regAlloca, RiscvInstr *returnInstr, + RiscvBasicBlock *rbb, RiscvFunction *foo) { + // 将被保护的寄存器还原 + // ! FP 必须被最后还原。 + int curSP = foo->querySP(); + auto reg_to_recover = regAlloca->savedRegister; + auto reg_used = regAlloca->getUsedReg(); + reverse(reg_to_recover.begin(), reg_to_recover.end()); + for (auto reg : reg_to_recover) + if (reg_used.find(reg) != reg_used.end()) { + if (reg->getType() == reg->IntReg) + rbb->addInstrBefore(new LoadRiscvInst(new Type(Type::PointerTyID), reg, + new RiscvIntPhiReg("fp", curSP), + rbb), + returnInstr); + else + rbb->addInstrBefore(new LoadRiscvInst(new Type(Type::FloatTyID), reg, + new RiscvIntPhiReg("fp", curSP), + rbb), + returnInstr); + curSP += VARIABLE_ALIGN_BYTE; + } + + // 还原 fp + rbb->addInstrBefore(new LoadRiscvInst(new Type(Type::PointerTyID), + getRegOperand("fp"), + new RiscvIntPhiReg("fp", curSP), rbb), + returnInstr); + + // 释放栈帧 + rbb->addInstrBefore(new BinaryRiscvInst(RiscvInstr::ADDI, getRegOperand("sp"), + new RiscvConst(-foo->querySP()), + getRegOperand("sp"), rbb), + returnInstr); +} + +RiscvBasicBlock *RiscvBuilder::transferRiscvBasicBlock(BasicBlock *bb, + RiscvFunction *foo) { + int translationCount = 0; + RiscvBasicBlock *rbb = createRiscvBasicBlock(bb); + Instruction *forward = nullptr; // 前置指令,用于icmp、fcmp和branch指令合并 + bool brFound = false; + for (Instruction *instr : bb->instr_list_) { + switch (instr->op_id_) { + case Instruction::Ret: + // Before leaving basic block writeback all registers + foo->regAlloca->writeback_all(rbb); + brFound = true; + // 在翻译过程中先指ret,恢复寄存器等操作在第二遍扫描的时候再插入 + rbb->addInstrBack(this->createRetInstr( + foo->regAlloca, static_cast(instr), rbb, foo)); + break; + // 分支指令 + case Instruction::Br: + // Before leaving basic block writeback all registers + foo->regAlloca->writeback_all(rbb); + brFound = true; + + rbb->addInstrBack(this->createBrInstr( + foo->regAlloca, static_cast(instr), rbb)); + break; + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::SDiv: + case Instruction::SRem: + case Instruction::UDiv: + case Instruction::URem: + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FMul: + case Instruction::FDiv: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + rbb->addInstrBack(this->createBinaryInstr( + foo->regAlloca, static_cast(instr), rbb)); + // foo->regAlloca->writeback(static_cast(instr), rbb); + break; + case Instruction::FNeg: + rbb->addInstrBack(this->createUnaryInstr( + foo->regAlloca, static_cast(instr), rbb)); + // foo->regAlloca->writeback(static_cast(instr), rbb); + break; + case Instruction::PHI: + break; + // 直接删除的指令 + case Instruction::BitCast: + break; + case Instruction::ZExt: + // 等价一条合流语句操作 + break; + case Instruction::Alloca: + break; + case Instruction::GetElementPtr: { + this->solveGetElementPtr(foo->regAlloca, + static_cast(instr), rbb); + // Writeback inside solveGetElementPtr(). + break; + } + case Instruction::FPtoSI: + rbb->addInstrBack(this->createFptoSiInstr( + foo->regAlloca, static_cast(instr), rbb)); + // foo->regAlloca->writeback(static_cast(instr), rbb); + break; + case Instruction::SItoFP: + rbb->addInstrBack(this->createSiToFpInstr( + foo->regAlloca, static_cast(instr), rbb)); + // foo->regAlloca->writeback(static_cast(instr), rbb); + break; + case Instruction::Load: { + auto instrSet = this->createLoadInstr( + foo->regAlloca, static_cast(instr), rbb); + for (auto x : instrSet) + rbb->addInstrBack(x); + // foo->regAlloca->writeback(static_cast(instr), rbb); + break; + } + case Instruction::Store: { + auto instrSet = this->createStoreInstr( + foo->regAlloca, static_cast(instr), rbb); + for (auto *x : instrSet) + rbb->addInstrBack(x); + // Store Instruction returns void value. + break; + } + case Instruction::ICmp: + createICMPSInstr(foo->regAlloca, static_cast(instr), rbb); + // foo->regAlloca->writeback(static_cast(instr), rbb); + break; + case Instruction::FCmp: + createFCMPInstr(foo->regAlloca, static_cast(instr), rbb); + // foo->regAlloca->writeback(static_cast(instr), rbb); + break; + case Instruction::Call: { + // 注意:该部分并未单独考虑系统函数! + // 注意:区分float还是int调用是看寄存器分配部分实现 + // 说明:call函数部分本身需要进行栈寄存器调整,调整到0栈帧供新函数使用 + // 除此之外不在任何地方调整sp的值 + // 在call语句结束之后要手动恢复回原来的栈帧 + CallInst *curInstr = static_cast(instr); + RiscvFunction *calleeFoo = createRiscvFunction( + static_cast(curInstr->operands_.back())); + + // 根据函数调用约定,按需传递参数。 + + int sp_shift_for_paras = 0; + int sp_shift_alignment_padding = 0; // Align sp pointer to 16-byte + int paraShift = 0; + + int intRegCount = 0, floatRegCount = 0; + + // 计算存储参数需要的额外栈帧大小 + for (int i = 0; i < curInstr->operands_.size() - 1; i++) { + sp_shift_for_paras += VARIABLE_ALIGN_BYTE; + } + + sp_shift_alignment_padding = + 16 - ((abs(foo->querySP()) + sp_shift_for_paras) & 15); + sp_shift_for_paras += sp_shift_alignment_padding; + + // 为参数申请栈帧 + rbb->addInstrBack(new BinaryRiscvInst( + BinaryRiscvInst::ADDI, getRegOperand("sp"), + new RiscvConst(-sp_shift_for_paras), getRegOperand("sp"), rbb)); + + // 将参数移动至寄存器与内存中 + for (int i = 0; i < curInstr->operands_.size() - 1; i++) { + std::string name = ""; + auto operand = curInstr->operands_[i]; + if (operand->type_->tid_ != Type::FloatTyID) { + if (intRegCount < 8) + name = "a" + std::to_string(intRegCount); + intRegCount++; + } else if (operand->type_->tid_ == Type::FloatTyID) { + if (floatRegCount < 8) + name = "fa" + std::to_string(floatRegCount); + floatRegCount++; + } + // 将额外的参数直接写入内存中 + if (name.empty()) { + if (operand->type_->tid_ != Type::FloatTyID) { + rbb->addInstrBack(new StoreRiscvInst( + operand->type_, + foo->regAlloca->findSpecificReg(operand, "t1", rbb), + new RiscvIntPhiReg("sp", paraShift), rbb)); + } else { + rbb->addInstrBack(new StoreRiscvInst( + operand->type_, + foo->regAlloca->findSpecificReg(operand, "ft1", rbb), + new RiscvIntPhiReg("sp", paraShift), rbb)); + } + } else { + foo->regAlloca->findSpecificReg(operand, name, rbb, nullptr); + } + paraShift += VARIABLE_ALIGN_BYTE; // Add operand size lastly + } + + // Call the function. + rbb->addInstrBack(this->createCallInstr(foo->regAlloca, curInstr, rbb)); + + // 为参数释放栈帧 + rbb->addInstrBack(new BinaryRiscvInst( + BinaryRiscvInst::ADDI, getRegOperand("sp"), + new RiscvConst(sp_shift_for_paras), getRegOperand("sp"), rbb)); + + // At last, save return value (a0) to target value. + if (curInstr->type_->tid_ != curInstr->type_->VoidTyID) { + if (curInstr->type_->tid_ != curInstr->type_->FloatTyID) { + rbb->addInstrBack( + new StoreRiscvInst(new IntegerType(32), getRegOperand("a0"), + foo->regAlloca->findMem(curInstr), rbb)); + } else { + rbb->addInstrBack(new StoreRiscvInst( + new Type(Type::FloatTyID), getRegOperand("fa0"), + foo->regAlloca->findMem(curInstr), rbb)); + } + } + break; + } + } + // std::cout << "FINISH TRANSFER " << ++translationCount << "Codes\n"; + } + // If br instruction is not found, then leave basic block at the block's end. + if (!brFound) { + foo->regAlloca->writeback_all(rbb); + } + return rbb; +} + +// 总控程序 +std::string RiscvBuilder::buildRISCV(Module *m) { + this->rm = new RiscvModule(); + std::string data = ".align 2\n.section .data\n"; // Add align attribute + // 全局变量 + if (m->global_list_.size()) { + for (GlobalVariable *gb : m->global_list_) { + auto curType = static_cast(gb->type_)->contained_; + RiscvGlobalVariable *curGB = nullptr; + Type *containedType = nullptr; + switch (curType->tid_) { + case Type::PointerTyID: + assert(false); + break; + case Type::ArrayTyID: + containedType = curType; + while (1) { + if (containedType->tid_ == Type::TypeID::ArrayTyID) + containedType = static_cast(containedType)->contained_; + else + break; + } + if (containedType->tid_ == Type::IntegerTyID) { + curGB = new RiscvGlobalVariable(RiscvOperand::IntImm, gb->name_, + gb->is_const_, gb->init_val_, + calcTypeSize(curType) / 4); + rm->addGlobalVariable(curGB); + data += curGB->print(); + } else if (containedType->tid_ == Type::FloatTyID) { + curGB = new RiscvGlobalVariable(RiscvOperand::FloatImm, gb->name_, + gb->is_const_, gb->init_val_, + calcTypeSize(curType) / 4); + rm->addGlobalVariable(curGB); + data += curGB->print(); + } + break; + case Type::TypeID::IntegerTyID: { + auto curGB = + new RiscvGlobalVariable(RiscvOperand::OpTy::IntImm, gb->name_, + gb->is_const_, gb->init_val_); + assert(curGB != nullptr); + rm->addGlobalVariable(curGB); + data += curGB->print(); + break; + } + case Type::TypeID::FloatTyID: { + auto curGB = + new RiscvGlobalVariable(RiscvOperand::OpTy::FloatImm, gb->name_, + gb->is_const_, gb->init_val_); + rm->addGlobalVariable(curGB); + data += curGB->print(); + break; + } + } + } + } + // 浮点常量进入内存 + int ConstFloatCount = 0; + std::string code = ".section .text\n"; + // 函数体 + // 预处理:首先合并所有的合流语句操作,然后在分配单元(storeOnStack)部分使用DSU合并 + for (Function *foo : m->function_list_) { + auto rfoo = createRiscvFunction(foo); + rm->addFunction(rfoo); + if (rfoo->is_libfunc()) { + auto *libFunc = createSyslibFunc(foo); + if (libFunc != nullptr) + code += libFunc->print(); + continue; + } + for (BasicBlock *bb : foo->basic_blocks_) + for (Instruction *instr : bb->instr_list_) + if (instr->op_id_ == Instruction::OpID::PHI) { + for (auto *operand : instr->operands_) + rfoo->regAlloca->DSU_for_Variable.merge( + operand, static_cast(instr)); + } else if (instr->op_id_ == Instruction::OpID::ZExt) { + rfoo->regAlloca->DSU_for_Variable.merge(instr->operands_[0], + static_cast(instr)); + } else if (instr->op_id_ == Instruction::OpID::BitCast) { + // std::cerr << "[Debug] [DSU] Bitcast Instruction: Merge value " + // << static_cast(instr)->print() << " to " + // << instr->operands_[0]->print() << " ." << std::endl; + rfoo->regAlloca->DSU_for_Variable.merge(static_cast(instr), + instr->operands_[0]); + } + // 将该函数内的浮点常量全部处理出来并告知寄存器分配单元 + for (BasicBlock *bb : foo->basic_blocks_) + for (Instruction *instr : bb->instr_list_) + for (auto *Operand : instr->operands_) + // 找到浮点常数,存入内存,写入全局变量区 + if (dynamic_cast(Operand) != nullptr) { + std::string curFloatName = + "FloatConst" + std::to_string(ConstFloatCount); + ConstFloatCount++; + std::string valString = + dynamic_cast(Operand)->print32(); + while (valString.length() < 10) + valString += "0"; + data += + curFloatName + ":\n\t.word\t" + valString.substr(0, 10) + "\n"; + rfoo->regAlloca->setPosition(Operand, + new RiscvFloatPhiReg(curFloatName, 0)); + } + // 首先检查所有的alloca指令,加入一个基本块进行寄存器保护以及栈空间分配 + RiscvBasicBlock *initBlock = createRiscvBasicBlock(); + std::map haveAllocated; + int IntParaCount = 0, FloatParaCount = 0; + int sp_shift_for_paras = 0; + int paraShift = 0; + + rfoo->setSP(0); // set sp to 0 initially. + + // Lambda function to write value to stack frame. + auto storeOnStack = [&](Value **val) { + if (val == nullptr) + return; + assert(*val != nullptr); + if (haveAllocated.count(*val)) + return; + // 几种特殊类型,不需要分栈空间 + if (dynamic_cast(*val) != nullptr) + return; + if (dynamic_cast(*val) != nullptr) + return; + // 注意:函数参数不用分配,而是直接指定! + // 这里设定是:v开头的是局部变量,arg开头的是函数寄存器变量 + // 无名常量 + if ((*val)->name_.empty()) + return; + // 全局变量不用给他保存栈上地址,它本身就有对应的内存地址,直接忽略 + if (dynamic_cast(*val) != nullptr) { + auto curType = (*val)->type_; + while (1) { + if (curType->tid_ == Type::TypeID::ArrayTyID) + curType = static_cast(curType)->contained_; + else if (curType->tid_ == Type::TypeID::PointerTyID) + curType = static_cast(curType)->contained_; + else + break; + } + if (curType->tid_ != Type::TypeID::FloatTyID) + rfoo->regAlloca->setPosition(*val, + new RiscvIntPhiReg((*val)->name_, 0, 1)); + else + rfoo->regAlloca->setPosition( + *val, new RiscvFloatPhiReg((*val)->name_, 0, 1)); + return; + } + // 除了全局变量之外的参数 + if (dynamic_cast(*val) != nullptr) { + // 不用额外分配空间 + // 整型参数 + if ((*val)->type_->tid_ == Type::TypeID::IntegerTyID || + (*val)->type_->tid_ == Type::TypeID::PointerTyID) { + // Pointer type's size is set to 8 byte. + if (IntParaCount < 8) + rfoo->regAlloca->setPositionReg( + *val, getRegOperand("a" + std::to_string(IntParaCount))); + rfoo->regAlloca->setPosition( + *val, new RiscvIntPhiReg(NamefindReg("fp"), paraShift)); + IntParaCount++; + } + // 浮点参数 + else { + assert((*val)->type_->tid_ == Type::TypeID::FloatTyID); + // 寄存器有 + if (FloatParaCount < 8) { + rfoo->regAlloca->setPositionReg( + *val, getRegOperand("fa" + std::to_string(FloatParaCount))); + } + rfoo->regAlloca->setPosition( + *val, new RiscvFloatPhiReg(NamefindReg("fp"), paraShift)); + FloatParaCount++; + } + paraShift += VARIABLE_ALIGN_BYTE; + } + // 函数内变量 + else { + int curSP = rfoo->querySP(); + RiscvOperand *stackPos = static_cast( + new RiscvIntPhiReg(NamefindReg("fp"), curSP - VARIABLE_ALIGN_BYTE)); + rfoo->regAlloca->setPosition(static_cast(*val), stackPos); + rfoo->addTempVar(stackPos); + } + haveAllocated[*val] = 1; + }; + + // 关联函数参数、寄存器与内存 + for (Value *arg : foo->arguments_) + storeOnStack(&arg); + + for (BasicBlock *bb : foo->basic_blocks_) + for (Instruction *instr : bb->instr_list_) + if (instr->op_id_ != Instruction::OpID::PHI && + instr->op_id_ != Instruction::OpID::ZExt && + instr->op_id_ != Instruction::OpID::Alloca) { + // 所有的函数局部变量都要压入栈 + Value *tempPtr = static_cast(instr); + storeOnStack(&tempPtr); + for (auto *val : instr->operands_) { + tempPtr = static_cast(val); + storeOnStack(&tempPtr); + } + } + for (BasicBlock *bb : foo->basic_blocks_) + for (Instruction *instr : bb->instr_list_) + if (instr->op_id_ == Instruction::OpID::Alloca) { + // 分配指针,并且将指针地址也同步保存 + auto curInstr = static_cast(instr); + int curTypeSize = calcTypeSize(curInstr->alloca_ty_); + rfoo->storeArray(curTypeSize); + int curSP = rfoo->querySP(); + RiscvOperand *ptrPos = new RiscvIntPhiReg(NamefindReg("fp"), curSP); + rfoo->regAlloca->setPosition(static_cast(instr), ptrPos); + rfoo->regAlloca->setPointerPos(static_cast(instr), ptrPos); + } + + // 添加初始化基本块 + rfoo->addBlock(initBlock); + // 翻译语句并计算被使用的寄存器 + for (BasicBlock *bb : foo->basic_blocks_) + rfoo->addBlock(this->transferRiscvBasicBlock(bb, rfoo)); + rfoo->ChangeBlock(initBlock, 0); + + // 保护寄存器 + rfoo->shiftSP(-VARIABLE_ALIGN_BYTE); + int fp_sp = rfoo->querySP(); // 为保护 fp 分配空间 + auto ®_to_save = rfoo->regAlloca->savedRegister; + auto reg_used = rfoo->regAlloca->getUsedReg(); + for (auto reg : reg_to_save) + if (reg_used.find(reg) != reg_used.end()) { + rfoo->shiftSP(-VARIABLE_ALIGN_BYTE); + if (reg->getType() == reg->IntReg) + initBlock->addInstrBack(new StoreRiscvInst( + new Type(Type::PointerTyID), reg, + new RiscvIntPhiReg(NamefindReg("fp"), rfoo->querySP()), + initBlock)); + else + initBlock->addInstrBack(new StoreRiscvInst( + new Type(Type::FloatTyID), reg, + new RiscvIntPhiReg(NamefindReg("fp"), rfoo->querySP()), + initBlock)); + } + + // 分配整体的栈空间,并设置s0为原sp + initBlock->addInstrFront(new BinaryRiscvInst( + RiscvInstr::ADDI, getRegOperand("sp"), new RiscvConst(-rfoo->querySP()), + getRegOperand("fp"), + initBlock)); // 3: fp <- t0 + initBlock->addInstrFront(new StoreRiscvInst( + new Type(Type::PointerTyID), getRegOperand("fp"), + new RiscvIntPhiReg(NamefindReg("sp"), fp_sp - rfoo->querySP()), + initBlock)); // 2: 保护 fp + initBlock->addInstrFront(new BinaryRiscvInst( + RiscvInstr::ADDI, getRegOperand("sp"), new RiscvConst(rfoo->querySP()), + getRegOperand("sp"), initBlock)); // 1: 分配栈帧 + + // 扫描所有的返回语句并插入寄存器还原等相关内容 + for (RiscvBasicBlock *rbb : rfoo->blk) + for (RiscvInstr *rinstr : rbb->instruction) + if (rinstr->type_ == rinstr->RET) { + initRetInstr(rfoo->regAlloca, rinstr, rbb, rfoo); + break; + } + + code += rfoo->print(); + } + return data + code; +} + +/** + * 辅助函数,计算一个类型的字节大小。 + * @param ty 将要计算的类型 `ty` 。 + * @return 返回类型的字节大小。 + */ +int calcTypeSize(Type *ty) { + int totalsize = 1; + while (ty->tid_ == Type::ArrayTyID) { + totalsize *= static_cast(ty)->num_elements_; + ty = static_cast(ty)->contained_; + } + assert(ty->tid_ == Type::IntegerTyID || ty->tid_ == Type::FloatTyID || + ty->tid_ == Type::PointerTyID); + if (ty->tid_ == Type::IntegerTyID || ty->tid_ == Type::FloatTyID) + totalsize *= 4; + else if (ty->tid_ == Type::PointerTyID) + totalsize *= 8; + return totalsize; +} \ No newline at end of file diff --git a/compiler/src/riscv/backend.h b/compiler/src/riscv/backend.h new file mode 100644 index 0000000..12a2649 --- /dev/null +++ b/compiler/src/riscv/backend.h @@ -0,0 +1,82 @@ +#ifndef BACKENDH +#define BACKENDH +#include "instruction.h" +#include "ir.h" +#include "optimize.h" +#include "regalloc.h" +#include "riscv.h" +#include + +// 建立IR到RISCV指令集的映射 +const extern std::map toRiscvOp; + +extern int LabelCount; +extern std::map rbbLabel; +extern std::map functionLabel; + +// 下面的函数仅为一个basic +// block产生一个标号,指令集为空,需要使用总控程序中具体遍历该bb才会产生内部指令 +RiscvBasicBlock *createRiscvBasicBlock(BasicBlock *bb = nullptr); +RiscvFunction *createRiscvFunction(Function *foo = nullptr); +std::string toLabel(int ind); +int calcTypeSize(Type *ty); + +// 总控程序 +class RiscvBuilder { +private: + void initializeRegisterFile(); + +public: + RiscvBuilder() { + rm = new RiscvModule(); + initializeRegisterFile(); + } + RiscvModule *rm; + // phi语句的合流:此处建立一个并查集DSU_for_Variable维护相同的变量。 + // 例如,对于if (A) y1=do something else y2=do another thing. Phi y3 y1, y2 + std::string buildRISCV(Module *m); + + // 下面的语句是需要生成对应riscv语句 + // Zext语句零扩展,因而没有必要 + // ZExtRiscvInstr createZextInstr(ZextInst *instr); + // void resolveLibfunc(RiscvFunction *foo); + BinaryRiscvInst *createBinaryInstr(RegAlloca *regAlloca, + BinaryInst *binaryInstr, + RiscvBasicBlock *rbb); + UnaryRiscvInst *createUnaryInstr(RegAlloca *regAlloca, UnaryInst *unaryInstr, + RiscvBasicBlock *rbb); + std::vector createStoreInstr(RegAlloca *regAlloca, + StoreInst *storeInstr, + RiscvBasicBlock *rbb); + std::vector createLoadInstr(RegAlloca *regAlloca, + LoadInst *loadInstr, + RiscvBasicBlock *rbb); + ICmpRiscvInstr *createICMPInstr(RegAlloca *regAlloca, ICmpInst *icmpInstr, + BranchInst *brInstr, RiscvBasicBlock *rbb); + ICmpRiscvInstr *createICMPSInstr(RegAlloca *regAlloca, ICmpInst *icmpInstr, + RiscvBasicBlock *rbb); + RiscvInstr *createFCMPInstr(RegAlloca *regAlloca, FCmpInst *fcmpInstr, + RiscvBasicBlock *rbb); + SiToFpRiscvInstr *createSiToFpInstr(RegAlloca *regAlloca, + SiToFpInst *sitofpInstr, + RiscvBasicBlock *rbb); + FpToSiRiscvInstr *createFptoSiInstr(RegAlloca *regAlloca, + FpToSiInst *fptosiInstr, + RiscvBasicBlock *rbb); + CallRiscvInst *createCallInstr(RegAlloca *regAlloca, CallInst *callInstr, + RiscvBasicBlock *rbb); + RiscvBasicBlock *transferRiscvBasicBlock(BasicBlock *bb, RiscvFunction *foo); + ReturnRiscvInst *createRetInstr(RegAlloca *regAlloca, ReturnInst *returnInstr, + RiscvBasicBlock *rbb, RiscvFunction *rfoo); + BranchRiscvInstr *createBrInstr(RegAlloca *regAlloca, BranchInst *brInstr, + RiscvBasicBlock *rbb); + RiscvInstr *solveGetElementPtr(RegAlloca *regAlloca, GetElementPtrInst *instr, + RiscvBasicBlock *rbb); + + /** + * 在返回语句前插入必要的语句。 + */ + void initRetInstr(RegAlloca *regAlloca, RiscvInstr *returnInstr, + RiscvBasicBlock *rbb, RiscvFunction *foo); +}; +#endif // !BACKENDH \ No newline at end of file diff --git a/compiler/src/riscv/instruction.cpp b/compiler/src/riscv/instruction.cpp new file mode 100644 index 0000000..9fa25ae --- /dev/null +++ b/compiler/src/riscv/instruction.cpp @@ -0,0 +1,360 @@ +#include "instruction.h" +#include "riscv.h" +#include +#include +// IR的指令转变到RISV的指令 +std::map instrTy2Riscv = { + {RiscvInstr::ADD, "ADD"}, {RiscvInstr::ADDI, "ADDI"}, + {RiscvInstr::ADDIW, "ADDIW"}, {RiscvInstr::SUB, "SUB"}, + {RiscvInstr::SUBI, "SUBI"}, {RiscvInstr::FADD, "FADD.S"}, + {RiscvInstr::FSUB, "FSUB.S"}, {RiscvInstr::FMUL, "FMUL.S"}, + {RiscvInstr::FDIV, "FDIV.S"}, {RiscvInstr::MUL, "MUL"}, + {RiscvInstr::DIV, "DIV"}, {RiscvInstr::REM, "REM"}, + {RiscvInstr::AND, "AND"}, {RiscvInstr::OR, "OR"}, + {RiscvInstr::ANDI, "ANDI"}, {RiscvInstr::ORI, "ORI"}, + {RiscvInstr::XOR, "XOR"}, {RiscvInstr::XORI, "XORI"}, + {RiscvInstr::RET, "RET"}, {RiscvInstr::FPTOSI, "FCVT.W.S"}, + {RiscvInstr::SITOFP, "FCVT.S.W"}, {RiscvInstr::FMV, "FMV.S"}, + {RiscvInstr::CALL, "CALL"}, {RiscvInstr::LI, "LI"}, + {RiscvInstr::MOV, "MV"}, {RiscvInstr::PUSH, "PUSH"}, + {RiscvInstr::POP, "POP"}, {RiscvInstr::SW, "SW"}, + {RiscvInstr::LW, "LW"}, {RiscvInstr::FSW, "FSW"}, + {RiscvInstr::FLW, "FLW"}, {RiscvInstr::SHL, "SLL"}, + {RiscvInstr::ASHR, "SRA"}, {RiscvInstr::SHLI, "SLLI"}, + {RiscvInstr::LSHR, "SRL"}, {RiscvInstr::ASHRI, "SRAI"}, + {RiscvInstr::LSHRI, "SRLI"}, +}; +// Instruction from opid to string +const std::map ICmpRiscvInstr::ICmpOpName = { + {ICmpInst::ICmpOp::ICMP_EQ, "BEQ"}, {ICmpInst::ICmpOp::ICMP_NE, "BNE"}, + {ICmpInst::ICmpOp::ICMP_UGE, "BGEU"}, {ICmpInst::ICmpOp::ICMP_ULT, "BLTU"}, + {ICmpInst::ICmpOp::ICMP_SGE, "BGE"}, {ICmpInst::ICmpOp::ICMP_SLT, "BLT"}, + {ICmpInst::ICmpOp::ICMP_SLE, "BLE"}}; +const std::map ICmpRiscvInstr::ICmpOpSName = { + {ICmpInst::ICmpOp::ICMP_EQ, "SEQZ"}, {ICmpInst::ICmpOp::ICMP_NE, "SNEZ"}, + {ICmpInst::ICmpOp::ICMP_UGE, "SLTU"}, {ICmpInst::ICmpOp::ICMP_ULT, "SLTU"}, + {ICmpInst::ICmpOp::ICMP_SGE, "SLT"}, {ICmpInst::ICmpOp::ICMP_SLT, "SLT"}}; +const std::map ICmpRiscvInstr::ICmpOpEquiv = + {{ICmpInst::ICmpOp::ICMP_ULE, ICmpInst::ICmpOp::ICMP_UGE}, + {ICmpInst::ICmpOp::ICMP_UGT, ICmpInst::ICmpOp::ICMP_ULT}, + {ICmpInst::ICmpOp::ICMP_SLE, ICmpInst::ICmpOp::ICMP_SGE}, + {ICmpInst::ICmpOp::ICMP_SGT, ICmpInst::ICmpOp::ICMP_SLT}}; +const std::map FCmpRiscvInstr::FCmpOpName = { + {FCmpInst::FCmpOp::FCMP_OLT, "FLT.S"}, + {FCmpInst::FCmpOp::FCMP_ULT, "FLT.S"}, + {FCmpInst::FCmpOp::FCMP_OLE, "FLE.S"}, + {FCmpInst::FCmpOp::FCMP_ULE, "FLE.S"}, + {FCmpInst::FCmpOp::FCMP_ORD, "FCLASS.S"}, + {FCmpInst::FCmpOp::FCMP_UNO, "FCLASS.S"}, // 取反 + {FCmpInst::FCmpOp::FCMP_OEQ, "FEQ.S"}, + {FCmpInst::FCmpOp::FCMP_UEQ, "FEQ.S"}, + {FCmpInst::FCmpOp::FCMP_ONE, "FEQ.S"}, // 取反 + {FCmpInst::FCmpOp::FCMP_UNE, "FEQ.S"} // 取反 +}; +const std::map FCmpRiscvInstr::FCmpOpEquiv = + {{FCmpInst::FCmpOp::FCMP_OGT, FCmpInst::FCmpOp::FCMP_OLT}, + {FCmpInst::FCmpOp::FCMP_UGT, FCmpInst::FCmpOp::FCMP_ULT}, + {FCmpInst::FCmpOp::FCMP_OGE, FCmpInst::FCmpOp::FCMP_OLE}, + {FCmpInst::FCmpOp::FCMP_UGE, FCmpInst::FCmpOp::FCMP_ULE}}; +std::string print_as_op(Value *v, bool print_ty); +std::string print_cmp_type(ICmpInst::ICmpOp op); +std::string print_fcmp_type(FCmpInst::FCmpOp op); + +RiscvInstr::RiscvInstr(InstrType type, int op_nums) + : type_(type), parent_(nullptr) { + operand_.resize(op_nums); +} + +RiscvInstr::RiscvInstr(InstrType type, int op_nums, RiscvBasicBlock *bb) + : type_(type), parent_(bb) { + operand_.resize(op_nums); +} + +// 格式:op tar, v1, v2->tar=v1 op v2 +std::string BinaryRiscvInst::print() { + // 这里需要将每个参数根据当前需要进行upcasting + assert(this->operand_.size() == 2); + std::string riscv_instr = "\t\t"; + + bool overflow = false; + if (type_ == ADDI && + std::abs(static_cast(operand_[1])->intval) >= 1024) { + overflow = true; + type_ = ADD; + riscv_instr += "LI\tt6, " + operand_[1]->print(); + riscv_instr += "\n\t\t"; + } + + riscv_instr += instrTy2Riscv.at(this->type_); + if (word && (type_ == ADDI || type_ == ADD || type_ == MUL || type_ == REM || + type_ == DIV)) + riscv_instr += "W"; // Integer word type instruction. + riscv_instr += "\t"; + riscv_instr += this->result_->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + if (overflow) { + riscv_instr += "t6"; + } else { + riscv_instr += this->operand_[1]->print(); + } + riscv_instr += "\n"; + return riscv_instr; +} + +std::string UnaryRiscvInst::print() { + assert(this->operand_.size() == 1); + std::string riscv_instr = "\t\t"; + riscv_instr += instrTy2Riscv[this->type_]; + riscv_instr += "\t"; + riscv_instr += this->result_->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + return riscv_instr; +} + +std::string CallRiscvInst::print() { + std::string riscv_instr = "\t\tCALL\t"; + riscv_instr += static_cast(this->operand_[0])->name_; + riscv_instr += "\n"; + return riscv_instr; +} + +// 注意:return 语句不会进行相应的寄存器约定检查 +std::string ReturnRiscvInst::print() { + std::string riscv_instr = "\t\tRET\n"; + return riscv_instr; +} + +std::string PushRiscvInst::print() { + std::string riscv_instr = ""; + int shift = this->basicShift_; + for (auto x : this->operand_) { + shift -= VARIABLE_ALIGN_BYTE; + riscv_instr += + "\t\tSD\t" + x->print() + ", " + std::to_string(shift) + "(sp)\n"; + } + return riscv_instr; +} + +std::string PopRiscvInst::print() { + std::string riscv_instr = ""; + int shift = this->basicShift_; + for (auto x : this->operand_) { + shift -= VARIABLE_ALIGN_BYTE; + riscv_instr += + "\t\tLD\t" + x->print() + ", " + std::to_string(shift) + "(sp)\n"; + } + riscv_instr += "\t\tADDI\tsp, " + std::to_string(-shift) + "\n"; + return riscv_instr; +} + +std::string ICmpRiscvInstr::print() { + std::string riscv_instr = "\t\t"; + // 注意:由于RISCV不支持全部的比较运算,因而需要根据比较条件对式子进行等价变换 + if (ICmpOpName.count(this->icmp_op_) == 0) { + std::swap(this->operand_[0], this->operand_[1]); + this->icmp_op_ = ICmpRiscvInstr::ICmpOpEquiv.find(this->icmp_op_)->second; + } + riscv_instr += ICmpOpName.at(this->icmp_op_) + "\t"; + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[1]->print(); + riscv_instr += ", "; + riscv_instr += static_cast(this->operand_[2])->name_; + riscv_instr += "\n"; + auto falseLink = dynamic_cast(this->operand_[3]); + // Force Jump + if (falseLink != nullptr) + riscv_instr += "\t\tJ\t" + falseLink->name_ + "\n"; + return riscv_instr; +} + +std::string ICmpSRiscvInstr::print() { + std::string riscv_instr = "\t\t"; + + // If equal or nequal instruction + bool eorne = false; + switch (icmp_op_) { + case ICmpInst::ICMP_EQ: + case ICmpInst::ICMP_NE: + eorne = true; + default: + break; + } + + if (eorne) { + riscv_instr += "SUB\t"; + riscv_instr += "t6"; + riscv_instr += ", "; + riscv_instr += operand_[0]->print(); + riscv_instr += ", "; + riscv_instr += operand_[1]->print(); + riscv_instr += "\n\t\t"; + } + + riscv_instr += ICmpOpSName.at(this->icmp_op_) + "\t"; + riscv_instr += this->result_->print(); + riscv_instr += ", "; + if (!eorne) { + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[1]->print(); + riscv_instr += "\n"; + } else { + riscv_instr += "t6\n"; + } + return riscv_instr; +} + +std::string FCmpRiscvInstr::print() { + std::string riscv_instr = "\t\t"; + + riscv_instr += FCmpOpName.at(this->fcmp_op_) + "\t"; + riscv_instr += this->result_->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[1]->print(); + riscv_instr += "\n"; + return riscv_instr; +} + +std::string StoreRiscvInst::print() { + std::string riscv_instr = "\t\t"; + + auto mem_addr = static_cast(operand_[1]); + bool overflow = mem_addr->overflow(); + + if (overflow) { + riscv_instr += "LI\tt6, " + std::to_string(mem_addr->shift_); + riscv_instr += "\n\t\t"; + riscv_instr += "ADD\tt6, t6, " + mem_addr->MemBaseName; + riscv_instr += "\n\t\t"; + } + + if (this->type.tid_ == Type::FloatTyID) + riscv_instr += "FSW\t"; + else if (this->type.tid_ == Type::IntegerTyID) + riscv_instr += "SW\t"; + else if (this->type.tid_ == Type::PointerTyID) + riscv_instr += "SD\t"; + else { + std::cerr << "[Error] Unknown store instruction type." << std::endl; + std::terminate(); + } + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + + if (overflow) { + riscv_instr += "(t6)"; + } else { + riscv_instr += this->operand_[1]->print(); + } + riscv_instr += "\n"; + return riscv_instr; +} + +// 注意:简易版 load。如果不存在目标内存地址,本条指令不执行 +std::string LoadRiscvInst::print() { + if (this->operand_[0] == nullptr || this->operand_[1] == nullptr) + return ""; + std::string riscv_instr = "\t\t"; + + auto mem_addr = static_cast(operand_[1]); + bool overflow = mem_addr->overflow(); + + if (overflow) { + riscv_instr += "LI\tt6, " + std::to_string(mem_addr->shift_); + riscv_instr += "\n\t\t"; + riscv_instr += "ADD\tt6, t6, " + mem_addr->MemBaseName; + riscv_instr += "\n\t\t"; + } + + if (this->type.tid_ == Type::FloatTyID) + riscv_instr += "FLW\t"; + else if (this->type.tid_ == Type::IntegerTyID) + riscv_instr += "LW\t"; + else if (this->type.tid_ == Type::PointerTyID) + riscv_instr += "LD\t"; + else { + std::cerr << "[Error] Unknown load instruction type." << std::endl; + std::terminate(); + } + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + if (overflow) { + riscv_instr += "(t6)"; + } else { + riscv_instr += this->operand_[1]->print(); + } + riscv_instr += "\n"; + return riscv_instr; +} + +std::string MoveRiscvInst::print() { + // Optmize: 若两个操作数相等则忽略该指令 + if (this->operand_[0] == this->operand_[1]) + return ""; + std::string riscv_instr = "\t\t"; + // li 指令 + if (this->operand_[1]->tid_ == RiscvOperand::IntImm) + riscv_instr += "LI\t"; + // 寄存器传寄存器 + else if (this->operand_[1]->tid_ == RiscvOperand::IntReg) + riscv_instr += "MV\t"; + // 浮点数 + else + riscv_instr += "FMV.S\t"; + if (this->operand_[0]->print() == this->operand_[1]->print()) + return ""; + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[1]->print(); + riscv_instr += "\n"; + return riscv_instr; +} + +std::string SiToFpRiscvInstr::print() { + std::string riscv_instr = "\t\tFCVT.S.W\t"; + riscv_instr += this->operand_[1]->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[0]->print(); + riscv_instr += "\n"; + return riscv_instr; +} + +std::string FpToSiRiscvInstr::print() { + std::string riscv_instr = "\t\tFCVT.W.S\t"; + riscv_instr += this->operand_[1]->print(); + riscv_instr += ", "; + riscv_instr += this->operand_[0]->print(); + riscv_instr += ", "; + riscv_instr += "rtz"; // round to zero. + riscv_instr += "\n"; + return riscv_instr; +} + +std::string LoadAddressRiscvInstr::print() { + std::string riscv_instr = + "\t\tLA\t" + this->operand_[0]->print() + ", " + this->name_ + "\n"; + return riscv_instr; +} + +std::string BranchRiscvInstr::print() { + std::string riscv_instr = "\t\t"; + // If single label operand then force jump + if (operand_[0] != nullptr) { + riscv_instr += "BGTZ\t"; + riscv_instr += operand_[0]->print(); + riscv_instr += ", "; + riscv_instr += static_cast(operand_[1])->name_; + riscv_instr += "\n\t\t"; + } + riscv_instr += "J\t"; + riscv_instr += static_cast(operand_[2])->name_; + riscv_instr += "\n"; + return riscv_instr; +} \ No newline at end of file diff --git a/compiler/src/riscv/instruction.h b/compiler/src/riscv/instruction.h new file mode 100644 index 0000000..5fac619 --- /dev/null +++ b/compiler/src/riscv/instruction.h @@ -0,0 +1,431 @@ +#ifndef INSTRUCTIONH +#define INSTRUCTIONH + +#include "ir.h" +#include "riscv.h" +#include "regalloc.h" + +// 语句块,也使用标号标识 +// 必须挂靠在函数下,否则无法正常生成标号 +// 可以考虑转化到riscv basic block做数据流分析,预留接口 +class RiscvBasicBlock : public RiscvLabel { +public: + RiscvFunction *func_; + std::vector instruction; + int blockInd_; // 表示了各个block之间的顺序 + RiscvBasicBlock(std::string name, RiscvFunction *func, int blockInd) + : RiscvLabel(Block, name), func_(func), blockInd_(blockInd) { + func->addBlock(this); + } + RiscvBasicBlock(std::string name, int blockInd) + : RiscvLabel(Block, name), func_(nullptr), blockInd_(blockInd) {} + void addFunction(RiscvFunction *func) { func->addBlock(this); } + std::string printname() { return name_; } + // void addOutBlock(RiscvBasicBlock *bb) { inB.push_back(bb); } + // void addInBlock(RiscvBasicBlock *bb) { outB.push_back(bb); } + void deleteInstr(RiscvInstr *instr) { + auto it = std::find(instruction.begin(), instruction.end(), instr); + if (it != instruction.end()) + instruction.erase( + std::remove(instruction.begin(), instruction.end(), instr), + instruction.end()); + } + void replaceInstr(RiscvInstr *oldinst, RiscvInstr *newinst) {} + // 在全部指令后面加入 + void addInstrBack(RiscvInstr *instr) { + if (instr == nullptr) + return; + instruction.push_back(instr); + } + // 在全部指令之前加入 + void addInstrFront(RiscvInstr *instr) { + if (instr == nullptr) + return; + instruction.insert(instruction.begin(), instr); + } + void addInstrBefore(RiscvInstr *instr, RiscvInstr *dst) { + if (instr == nullptr) + return; + auto it = std::find(instruction.begin(), instruction.end(), dst); + if (it != instruction.end()) + instruction.insert(it, instr); + else + addInstrBack(instr); + } + void addInstrAfter(RiscvInstr *instr, RiscvInstr *dst) { + if (instr == nullptr) + return; + auto it = std::find(instruction.begin(), instruction.end(), dst); + if (it != instruction.end()) { + if (next(it) == instruction.end()) + instruction.push_back(instr); + else + instruction.insert(next(it), instr); + } else { + addInstrBack(instr); + } + } + std::string print(); +}; + +// 传入寄存器编号以生成一条语句, +// 上层由basic block整合 +class RiscvInstr { +public: + // 指令类型,除分支语句外,其他对应到riscv + // 加立即数或者浮点加需要做区分 + enum InstrType { + ADD = 0, + ADDI, + SUB, + SUBI, + MUL, + DIV = 6, + REM, + FADD = 8, + FSUB = 10, + FMUL = 12, + FDIV = 14, + XOR = 16, + XORI, + AND, + ANDI, + OR, + ORI, + SW, + LW, + FSW = 30, + FLW, + ICMP, + FCMP, + PUSH, + POP, + CALL, + RET, + LI, + MOV, + FMV, + FPTOSI, + SITOFP, + JMP, + SHL, + LSHR, + ASHR, + SHLI = 52, + LSHRI, + ASHRI, + LA, + ADDIW, + BGT + }; + const static std::map RiscvName; + + InstrType type_; + RiscvBasicBlock *parent_; + std::vector operand_; + + RiscvInstr(InstrType type, int op_nums); + RiscvInstr(InstrType type, int op_nums, RiscvBasicBlock *bb); + ~RiscvInstr() = default; + + virtual std::string print() = 0; + + RiscvOperand *result_; + void setOperand(int ind, RiscvOperand *val) { + assert(ind >= 0 && ind < operand_.size()); + operand_[ind] = val; + } + void setResult(RiscvOperand *result) { result_ = result; } + void removeResult() { result_ = nullptr; } + // 消除一个操作数 + void removeOperand(int i) { operand_[i] = nullptr; } + // 清除指令 + void clear() { operand_.clear(), removeResult(); } + // 先操作数后返回值 + std::vector getOperandResult() { + std::vector ans(operand_); + if (result_ != nullptr) + ans.push_back(result_); + return ans; + } + RiscvOperand *getOperand(int i) const { return operand_[i]; } +}; + +// 二元指令 +class BinaryRiscvInst : public RiscvInstr { +public: + std::string print() override; + BinaryRiscvInst() = default; + // target = v1 op v2,后面接一个flag参数表示要不要加入到对应的basic block中 + BinaryRiscvInst(InstrType op, RiscvOperand *v1, RiscvOperand *v2, + RiscvOperand *target, RiscvBasicBlock *bb, bool flag = 0) + : RiscvInstr(op, 2, bb), word(flag) { + setOperand(0, v1); + setOperand(1, v2); + setResult(target); + this->parent_ = bb; + // Optimize: 若立即数为0,则改用寄存器zero。 + if(v2->getType() == v2->IntImm && static_cast(v2)->intval == 0){ + type_ = ADD; + setOperand(1, getRegOperand("zero")); + } + } + bool word; +}; + +// 一元指令 +class UnaryRiscvInst : public RiscvInstr { +public: + std::string print() override; + UnaryRiscvInst() = default; + // target = op v1,后面接一个flag参数表示要不要加入到对应的basic block中 + UnaryRiscvInst(InstrType op, RiscvOperand *v1, RiscvOperand *target, + RiscvBasicBlock *bb, bool flag = 0) + : RiscvInstr(op, 1, bb) { + setOperand(0, v1); + setResult(target); + this->parent_ = bb; + if (flag) + this->parent_->addInstrBack(this); + } +}; + +// 加入一个整型mov指令(LI) +class MoveRiscvInst : public RiscvInstr { +public: + std::string print() override; + MoveRiscvInst() = default; + MoveRiscvInst(RiscvOperand *v1, int Imm, RiscvBasicBlock *bb, bool flag = 0) + : RiscvInstr(InstrType::LI, 2, bb) { + RiscvOperand *Const = new RiscvConst(Imm); + setOperand(0, v1); + setOperand(1, Const); + this->parent_ = bb; + if (flag) + this->parent_->addInstrBack(this); + } + // v2->v1 + MoveRiscvInst(RiscvOperand *v1, RiscvOperand *v2, RiscvBasicBlock *bb, + bool flag = 0) + : RiscvInstr(InstrType::MOV, 2, bb) { + setOperand(0, v1); + setOperand(1, v2); + this->parent_ = bb; + if (flag) + this->parent_->addInstrBack(this); + } +}; + +// 注意压栈顺序问题!打印的时候严格按照lists内顺序 +class PushRiscvInst : public RiscvInstr { + int basicShift_; + +public: + PushRiscvInst(std::vector &lists, RiscvBasicBlock *bb, + int basicShift) + : RiscvInstr(InstrType::PUSH, lists.size(), bb), basicShift_(basicShift) { + for (int i = 0; i < lists.size(); i++) + setOperand(i, lists[i]); + } + std::string print() override; +}; + +// 注意出栈顺序问题!打印的时候严格按照lists内顺序 +class PopRiscvInst : public RiscvInstr { + int basicShift_; + +public: + // 传入所有要pop的变量 + PopRiscvInst(std::vector &lists, RiscvBasicBlock *bb, + int basicShift) + : RiscvInstr(InstrType::POP, lists.size(), bb), basicShift_(basicShift) { + for (int i = 0; i < lists.size(); i++) + setOperand(i, lists[i]); + } + std::string print() override; +}; + +// call调用语句+压栈语句 +// 0作为函数名,1-n是函数各参数 +class CallRiscvInst : public RiscvInstr { +public: + CallRiscvInst(RiscvFunction *func, RiscvBasicBlock *bb) + : RiscvInstr(InstrType::CALL, 1, bb) { + setOperand(0, func); + } + virtual std::string print() override; +}; + +// 仅返回语句,返回参数由上层的block对应的function构造push语句和lw sw指令 +class ReturnRiscvInst : public RiscvInstr { +public: + ReturnRiscvInst(RiscvBasicBlock *bb) : RiscvInstr(InstrType::RET, 0, bb) {} + std::string print() override; +}; + +// Store 指令格式:sw source_value(reg), shift(base reg) +// 目的:source_value->M[base reg + shift] +// 传入源寄存器,目的寄存器和偏移地址(默认为0) +// 如果是直接寻址,则base填x0号寄存器 +class StoreRiscvInst : public RiscvInstr { + +public: + int shift_; // 地址偏移量 + Type type; // 到底是浮点还是整型 + StoreRiscvInst(Type *ty, RiscvOperand *source, RiscvOperand *target, + RiscvBasicBlock *bb, int shift = 0) + : RiscvInstr(InstrType::SW, 2, bb), shift_(shift), type(ty->tid_) { + setOperand(0, source); + setOperand(1, target); + this->parent_ = bb; + if (source->isRegister() == false) { + std::cerr << "[Fatal error] Invalid store instruction: " << print() + << std::endl; + std::terminate(); + } + } + std::string print() override; +}; + +// 指令传入格式同store +// 先dest 后base reg +// 目的:M[base reg + shift]->dest reg +// 需指明是浮点还是整型 +class LoadRiscvInst : public RiscvInstr { +public: + int shift_; // 地址偏移量 + Type type; // 到底是浮点还是整型 + LoadRiscvInst(Type *ty, RiscvOperand *dest, RiscvOperand *target, + RiscvBasicBlock *bb, int shift = 0) + : RiscvInstr(InstrType::LW, 2, bb), shift_(shift), type(ty->tid_) { + setOperand(0, dest); + setOperand(1, target); + if (target == nullptr) { + std::cerr << "[Fatal Error] Load Instruction's target is nullptr." + << std::endl; + std::terminate(); + } + this->parent_ = bb; + } + std::string print() override; +}; + +// 整型比较 +// 类型:cmpop val1, val2, true_link +// 传入参数:val1, val2, true_link, false_link(basic block指针形式) +// false_link如果为为下一条语句则不会发射j false_link指令 +class ICmpRiscvInstr : public RiscvInstr { +public: + static const std::map ICmpOpName; + static const std::map ICmpOpSName; + static const std::map ICmpOpEquiv; + ICmpRiscvInstr(ICmpInst::ICmpOp op, RiscvOperand *v1, RiscvOperand *v2, + RiscvBasicBlock *trueLink, RiscvBasicBlock *falseLink, + RiscvBasicBlock *bb) + : RiscvInstr(ICMP, 4, bb), icmp_op_(op) { + setOperand(0, v1); + setOperand(1, v2); + setOperand(2, trueLink); + setOperand(3, falseLink); + } + ICmpRiscvInstr(ICmpInst::ICmpOp op, RiscvOperand *v1, RiscvOperand *v2, + RiscvBasicBlock *trueLink, RiscvBasicBlock *bb) + : RiscvInstr(ICMP, 4, bb), icmp_op_(op) { + setOperand(0, v1); + setOperand(1, v2); + setOperand(2, trueLink); + setOperand(3, nullptr); + } + ICmpInst::ICmpOp icmp_op_; + std::string print() override; +}; + +class ICmpSRiscvInstr : public ICmpRiscvInstr { +public: + ICmpSRiscvInstr(ICmpInst::ICmpOp op, RiscvOperand *v1, RiscvOperand *v2, + RiscvOperand *target, RiscvBasicBlock *bb) + : ICmpRiscvInstr(op, v1, v2, nullptr, bb) { + setOperand(0, v1); + setOperand(1, v2); + setResult(target); + } + std::string print() override; +}; + + +// 浮点比较 +// 类型:cmpop val1, val2, true_link, false_link +// 假定basic block是顺序排布的,那么如果false_link恰好为下一个basic +// block,则不会发射j false_link指令 +class FCmpRiscvInstr : public RiscvInstr { +public: + static const std::map FCmpOpName; + static const std::map FCmpOpEquiv; + FCmpRiscvInstr(FCmpInst::FCmpOp op, RiscvOperand *v1, RiscvOperand *v2, + RiscvOperand *target, RiscvBasicBlock *bb) + : RiscvInstr(FCMP, 2, bb), fcmp_op_(op) { + setOperand(0, v1); + setOperand(1, v2); + setResult(target); + } + FCmpInst::FCmpOp fcmp_op_; + std::string print() override; +}; +class FpToSiRiscvInstr : public RiscvInstr { +public: + FpToSiRiscvInstr(RiscvOperand *Source, RiscvOperand *Target, + RiscvBasicBlock *bb) + : RiscvInstr(FPTOSI, 2, bb) { + setOperand(0, Source); + setOperand(1, Target); + } + virtual std::string print() override; +}; + +class SiToFpRiscvInstr : public RiscvInstr { +public: + SiToFpRiscvInstr(RiscvOperand *Source, RiscvOperand *Target, + RiscvBasicBlock *bb) + : RiscvInstr(SITOFP, 2, bb) { + setOperand(0, Source); + setOperand(1, Target); + } + virtual std::string print() override; +}; + +// LA rd, symbol ; x[rd] = &symbol +// `dest` : rd +// `name` : symbol +class LoadAddressRiscvInstr : public RiscvInstr { +public: + std::string name_; + LoadAddressRiscvInstr(RiscvOperand *dest, std::string name, + RiscvBasicBlock *bb) + : RiscvInstr(LA, 1, bb), name_(name) { + setOperand(0, dest); + } + virtual std::string print() override; +}; + +/** + * 分支指令类。 + * BEQ rs1, zero, label1 + * J label2 + */ +class BranchRiscvInstr : public RiscvInstr { +public: + + /// @brief 生成分支指令类。 + /// @param rs1 存储布尔值的寄存器 + /// @param trueLink 真值跳转基本块 + /// @param falseLink 假值跳转基本块 + BranchRiscvInstr(RiscvOperand *rs1, RiscvBasicBlock *trueLink, + RiscvBasicBlock *falseLink, RiscvBasicBlock *bb) + : RiscvInstr(BGT, 3, bb) { + setOperand(0, rs1); + setOperand(1, trueLink); + setOperand(2, falseLink); + } + virtual std::string print() override; +}; +#endif // !INSTRUCTIONH \ No newline at end of file diff --git a/compiler/src/riscv/optimize.cpp b/compiler/src/riscv/optimize.cpp new file mode 100644 index 0000000..7a1b6d7 --- /dev/null +++ b/compiler/src/riscv/optimize.cpp @@ -0,0 +1,3 @@ +#include "optimize.h" + +void OptimizeBlock() {} \ No newline at end of file diff --git a/compiler/src/riscv/optimize.h b/compiler/src/riscv/optimize.h new file mode 100644 index 0000000..64fb6bd --- /dev/null +++ b/compiler/src/riscv/optimize.h @@ -0,0 +1,11 @@ +#ifndef OPTIMIZEH +#define OPTIMIZEH + +#include "riscv.h" +#include "ir.h" + +// 进行数据流的优化 +// 在此之前先分配各寄存器 +// 可选 +void OptimizeBlock(); +#endif // !OPTIMIZEH \ No newline at end of file diff --git a/compiler/src/riscv/regalloc.cpp b/compiler/src/riscv/regalloc.cpp new file mode 100644 index 0000000..140a785 --- /dev/null +++ b/compiler/src/riscv/regalloc.cpp @@ -0,0 +1,380 @@ +#include "regalloc.h" +#include "instruction.h" +#include "riscv.h" + +int IntRegID = 32, FloatRegID = 32; // 测试阶段使用 + +Register *NamefindReg(std::string reg) { + if (reg.size() > 4) + return nullptr; + + Register *reg_to_ret = new Register(Register::Int, 0); + + // Check if int registers + for (int i = 0; i < 32; i++) { + reg_to_ret->rid_ = i; + if (reg_to_ret->print() == reg) + return reg_to_ret; + } + + // Else then float registers + reg_to_ret->regtype_ = reg_to_ret->Float; + for (int i = 0; i < 32; i++) { + reg_to_ret->rid_ = i; + if (reg_to_ret->print() == reg) + return reg_to_ret; + } + + return nullptr; +} + +RiscvOperand *getRegOperand(std::string reg) { + for (auto regope : regPool) { + if (regope->print() == reg) + return regope; + } + assert(false); + return nullptr; +} + +RiscvOperand *getRegOperand(Register::RegType op_ty_, int id) { + Register *reg = new Register(op_ty_, id); + for (auto regope : regPool) { + if (regope->print() == reg->print()) { + delete reg; + return regope; + } + } + assert(false); + return nullptr; +} + +Type *getStoreTypeFromRegType(RiscvOperand *riscvReg) { + return riscvReg->getType() == RiscvOperand::OpTy::FloatReg + ? new Type(Type::TypeID::FloatTyID) + : new Type(Type::TypeID::IntegerTyID); +} + +RiscvOperand *RegAlloca::findReg(Value *val, RiscvBasicBlock *bb, + RiscvInstr *instr, int inReg, int load, + RiscvOperand *specified, bool direct) { + safeFindTimeStamp++; + val = this->DSU_for_Variable.query(val); + bool isGVar = dynamic_cast(val) != nullptr; + bool isAlloca = dynamic_cast(val) != nullptr; + bool isPointer = val->type_->tid_ == val->type_->PointerTyID; + + // If there is no register allocated for value then get a new one + if (specified != nullptr) + setPositionReg(val, specified, bb, instr); + else if (curReg.find(val) == curReg.end() || isAlloca || + val->is_constant()) { // Alloca and constant value is always unsafe. + bool found = false; + RiscvOperand *cur = nullptr; + IntRegID = 32; + FloatRegID = 32; + while (!found) { + if (val->type_->tid_ != Type::FloatTyID) { + ++IntRegID; + if (IntRegID > 27) + IntRegID = 18; + + cur = getRegOperand(Register::Int, IntRegID); + } else { + ++FloatRegID; + if (FloatRegID > 27) + FloatRegID = 18; + cur = getRegOperand(Register::Float, FloatRegID); + } + if (regFindTimeStamp.find(cur) == regFindTimeStamp.end() || + safeFindTimeStamp - regFindTimeStamp[cur] > SAFE_FIND_LIMIT) { + setPositionReg(val, cur, bb, instr); + found = true; + } + } + } else { + regFindTimeStamp[curReg[val]] = safeFindTimeStamp; + return curReg[val]; + } + + // ! Though all registers are considered unsafe, there is no way + // ! to writeback registers properly in findReg() for now. + // ! Therefore unsafe part below is not being executed for now. + // ! Maybe should consider using writeback() instead. + // For now, all registers are considered unsafe thus registers should always + // load from memory before using and save to memory after using. + auto mem_addr = findMem(val, bb, instr, 1); // Value's direct memory address + auto current_reg = curReg[val]; // Value's current register + auto load_type = val->type_; + + regFindTimeStamp[current_reg] = safeFindTimeStamp; // Update time stamp + if (load) { + // Load before usage. + if (mem_addr != nullptr) { + bb->addInstrBefore( + new LoadRiscvInst(load_type, current_reg, mem_addr, bb), instr); + } else if (val->is_constant()) { + // If value is a int constant, create a LI instruction. + auto cval = dynamic_cast(val); + if (cval != nullptr) + bb->addInstrBefore(new MoveRiscvInst(current_reg, cval->value_, bb), + instr); + else if (dynamic_cast(val) != nullptr) + bb->addInstrBefore( + new MoveRiscvInst(current_reg, this->findMem(val), bb), instr); + else { + std::cerr << "[Warning] Trying to find a register for unknown type of " + "constant value which is not implemented for now." + << std::endl; + } + } else if (isAlloca) { + bb->addInstrBefore( + new BinaryRiscvInst( + BinaryRiscvInst::ADDI, getRegOperand("fp"), + new RiscvConst(static_cast(pos[val])->shift_), + current_reg, bb), + instr); + // std::cerr << "[Debug] Get a alloca position <" << val->print() << ", " + // << static_cast(pos[val])->print() + // << "> into the register <" << current_reg->print() << ">" + // << std::endl; + } else { + std::cerr << "[Error] Unknown error in findReg()." << std::endl; + std::terminate(); + } + } + + return current_reg; +} + +RiscvOperand *RegAlloca::findMem(Value *val, RiscvBasicBlock *bb, + RiscvInstr *instr, bool direct) { + val = this->DSU_for_Variable.query(val); + if (pos.count(val) == 0 && !val->is_constant()) { + std::cerr << "[Warning] Value " << std::hex << val << " (" << val->name_ + << ")'s memory map not found." << std::endl; + } + bool isGVar = dynamic_cast(val) != nullptr; + bool isPointer = val->type_->tid_ == val->type_->PointerTyID; + bool isAlloca = dynamic_cast(val) != nullptr; + // All float constant considered as global variables for now. + isGVar = isGVar || dynamic_cast(val) != nullptr; + // Always loading global variable's address into t5 when execute findMem(). + if (isGVar) { + if (bb == nullptr) { + std::cerr << "[Warning] Trying to add global var addressing " + "instruction, but basic block pointer is null." + << std::endl; + return nullptr; + } + bb->addInstrBefore( + new LoadAddressRiscvInstr(getRegOperand("t5"), pos[val]->print(), bb), + instr); + return new RiscvIntPhiReg("t5"); + } + // If not loading pointer's address directly, then use indirect addressing. + // Ignore alloca due to the instruction only being dealt by findReg() + if (isPointer && !isAlloca && !direct) { + if (bb == nullptr) { + std::cerr << "[Warning] Trying to add indirect pointer addressing " + "instruction, but basic block pointer is null." + << std::endl; + return nullptr; + } + + bb->addInstrBefore(new LoadRiscvInst(new Type(Type::PointerTyID), + getRegOperand("t4"), pos[val], bb), + instr); + return new RiscvIntPhiReg("t4"); + } + // Cannot access to alloca's memory directly. + else if (direct && isAlloca) + return nullptr; + + if (pos.find(val) == pos.end()) + return nullptr; + + return pos[val]; +} + +RiscvOperand *RegAlloca::findMem(Value *val) { + return findMem(val, nullptr, nullptr, true); +} + +RiscvOperand *RegAlloca::findNonuse(Type *ty, RiscvBasicBlock *bb, + RiscvInstr *instr) { + if (ty->tid_ == Type::IntegerTyID || ty->tid_ == Type::PointerTyID) { + ++IntRegID; + if (IntRegID > 27) + IntRegID = 18; + return getRegOperand(Register::Int, IntRegID); + } else { + ++FloatRegID; + if (FloatRegID > 27) + FloatRegID = 18; + return getRegOperand(Register::Float, FloatRegID); + } +} + +void RegAlloca::setPosition(Value *val, RiscvOperand *riscvVal) { + val = this->DSU_for_Variable.query(val); + if (pos.find(val) != pos.end()) { + // std::cerr << "[Warning] Trying overwriting memory address map of value " + // << std::hex << val << " (" << val->name_ << ") [" + // << riscvVal->print() << " -> " << pos[val]->print() << "]" + // << std::endl; + // std::terminate(); + } + + // std::cerr << "[Debug] [RegAlloca] Map value <" << val->print() + // << "> to operand <" << riscvVal->print() << ">" << std::endl; + + pos[val] = riscvVal; +} + +RiscvOperand *RegAlloca::findSpecificReg(Value *val, std::string RegName, + RiscvBasicBlock *bb, RiscvInstr *instr, + bool direct) { + val = this->DSU_for_Variable.query(val); + RiscvOperand *retOperand = getRegOperand(RegName); + + return findReg(val, bb, instr, 0, 1, retOperand, direct); +} + +void RegAlloca::setPositionReg(Value *val, RiscvOperand *riscvReg, + RiscvBasicBlock *bb, RiscvInstr *instr) { + val = this->DSU_for_Variable.query(val); + Value *old_val = getRegPosition(riscvReg); + RiscvOperand *old_reg = getPositionReg(val); + if (old_val != nullptr && old_val != val) + writeback(riscvReg, bb, instr); + if (old_reg != nullptr && old_reg != riscvReg) + writeback(old_reg, bb, instr); + setPositionReg(val, riscvReg); +} + +void RegAlloca::setPositionReg(Value *val, RiscvOperand *riscvReg) { + val = this->DSU_for_Variable.query(val); + if (riscvReg->isRegister() == false) { + std::cerr << "[Fatal error] Trying to map value " << std::hex << val + << " to not a register operand." << std::endl; + std::terminate(); + } + + // std::cerr << "[Debug] Map register <" << riscvReg->print() << "> to value <" + // << val->print() << ">\n"; + + curReg[val] = riscvReg; + regPos[riscvReg] = val; + regUsed.insert(riscvReg); +} + +RiscvInstr *RegAlloca::writeback(RiscvOperand *riscvReg, RiscvBasicBlock *bb, + RiscvInstr *instr) { + Value *value = getRegPosition(riscvReg); + if (value == nullptr) + return nullptr; // Value not found in map + + value = this->DSU_for_Variable.query(value); + + // std::cerr << "[Debug] [RegAlloca] Writeback register <" << riscvReg->print() + // << "> to value <" << value->print() << ">.\n"; + + // Erase map info + regPos.erase(riscvReg); + regFindTimeStamp.erase(riscvReg); + curReg.erase(value); + + RiscvOperand *mem_addr = findMem(value); + + if (mem_addr == nullptr) { + // std::cerr << "[Debug] [RegAlloca] Writeback ignore alloca pointer direct " + // "access and immvalue.\n"; + return nullptr; // Maybe an immediate value or dicrect accessing alloca + } + + auto store_type = value->type_; + auto store_instr = new StoreRiscvInst(value->type_, riscvReg, mem_addr, bb); + + // Write store instruction + if (instr != nullptr) + bb->addInstrBefore(store_instr, instr); + else + bb->addInstrBack(store_instr); + + return store_instr; +} + +RegAlloca::RegAlloca() { + // 初始化寄存器对象池。 + if (regPool.size() == 0) { + for (int i = 0; i < 32; i++) + regPool.push_back(new RiscvIntReg(new Register(Register::Int, i))); + for (int i = 0; i < 32; i++) + regPool.push_back(new RiscvFloatReg(new Register(Register::Float, i))); + } + + // fp 的保护单独进行处理 + regUsed.insert(getRegOperand("ra")); + savedRegister.push_back(getRegOperand("ra")); // 保护 ra + // 保护 s1-s11 + for (int i = 1; i <= 11; i++) + savedRegister.push_back(getRegOperand("s" + std::to_string(i))); + // 保护 fs0-fs11 + for (int i = 0; i <= 11; i++) + savedRegister.push_back(getRegOperand("fs" + std::to_string(i))); +} + +RiscvInstr *RegAlloca::writeback(Value *val, RiscvBasicBlock *bb, + RiscvInstr *instr) { + auto reg = getPositionReg(val); + return writeback(reg, bb, instr); +} + +Value *RegAlloca::getRegPosition(RiscvOperand *reg) { + if (regPos.find(reg) == regPos.end()) + return nullptr; + return this->DSU_for_Variable.query(regPos[reg]); +} + +RiscvOperand *RegAlloca::getPositionReg(Value *val) { + val = this->DSU_for_Variable.query(val); + if (curReg.find(val) == curReg.end()) + return nullptr; + return curReg[val]; +} + +RiscvOperand *RegAlloca::findPtr(Value *val, RiscvBasicBlock *bb, + RiscvInstr *instr) { + val = this->DSU_for_Variable.query(val); + if (ptrPos.find(val) == ptrPos.end()) { + std::cerr << "[Fatal Error] Value's pointer position not found." + << std::endl; + std::terminate(); + } + return ptrPos[val]; +} + +void RegAlloca::writeback_all(RiscvBasicBlock *bb, RiscvInstr *instr) { + std::vector regs_to_writeback; + for (auto p : regPos) + regs_to_writeback.push_back(p.first); + for (auto r : regs_to_writeback) + writeback(r, bb, instr); +} + +void RegAlloca::setPointerPos(Value *val, RiscvOperand *PointerMem) { + val = this->DSU_for_Variable.query(val); + assert(val->type_->tid_ == Type::TypeID::PointerTyID || + val->type_->tid_ == Type::TypeID::ArrayTyID); + // std::cerr << "SET POINTER: " << val->name_ << "!" << PointerMem->print() + // << "\n"; + this->ptrPos[val] = PointerMem; +} + +void RegAlloca::clear() { + curReg.clear(); + regPos.clear(); + safeFindTimeStamp = 0; + regFindTimeStamp.clear(); +} \ No newline at end of file diff --git a/compiler/src/riscv/regalloc.h b/compiler/src/riscv/regalloc.h new file mode 100644 index 0000000..233ffae --- /dev/null +++ b/compiler/src/riscv/regalloc.h @@ -0,0 +1,297 @@ +#ifndef REGALLOCH +#define REGALLOCH + +#include "riscv.h" +#include + +template class DSU { +private: + std::map father; + T getfather(T x) { + return father[x] == x ? x : (father[x] = getfather(father[x])); + } + +public: + DSU() = default; + T query(T id) { + // 不存在变量初值为自己 + if (father.find(id) == father.end()) { + // std::cerr << std::hex << "[Debug] [DSU] [" << this << "] New value " << + // id + // << std::endl; + return father[id] = id; + } else { + // std::cerr << std::hex << "[Debug] [DSU] [" << this << "] Find value " + // << id + // << std::endl; + return getfather(id); + } + } + + /** + * Merge DSU's node u to v. + * @param u child + * @param v father + */ + void merge(T u, T v) { + u = query(u), v = query(v); + assert(u != nullptr && v != nullptr); + if (u == v) + return; + // std::cerr << std::hex << "[Debug] [DSU] [" << this << "] Merge " << u + // << " to " << v << std::endl; + father[u] = v; + } +}; + +// 关于额外发射指令问题说明 +// 举例:如果当前需要使用特定寄存器(以a0为例)以存取返回值 +// 1. 如果当前变量在内存:a) +// a) +// 由regalloca发射一个sw指令(使用rbb中addInstrback函数)将现在的a0送回对应内存或栈上地址 +// b) 由regalloca发射一个lw指令(使用rbb中addInstrback函数)将该变量移入a0中 +// 2. 如果该变量在寄存器x中: +// a) +// 由regalloca发射一个sw指令(使用rbb中addInstrback函数)将现在的a0送回对应内存或栈上地址 +// b) 由regalloca发射一个mv指令(使用rbb中addInstrback函数)将该变量从x移入a0中 + +// 举例:为当前一个未指定寄存器,或当前寄存器堆中没有存放该变量的寄存器。现在需要为该变量找一个寄存器以进行运算 +// 存在空寄存器:找一个空闲未分配寄存器,然后返回一个寄存器指针riscvOperand* +// 不存在空寄存器: +// a) 找一个寄存器 +// b) +// 由regalloca发射一个sw指令(使用rbb中addInstrback函数)将现在该寄存器的数字送回对应内存或栈上地址 +// c) 返回该寄存器指针riscvOperand* + +// 注意区分指针类型(如*a0)和算数值(a0)的区别 + +// 每个变量会有一个固定的内存或栈地址,可能会被分配一个固定寄存器地址 + +extern int IntRegID, FloatRegID; // 测试阶段使用 + +Register *NamefindReg(std::string reg); + +// 辅助函数 +// 根据寄存器 riscvReg 的类型返回存储指令的类型 +Type *getStoreTypeFromRegType(RiscvOperand *riscvReg); + +// RegAlloca类被放置在**每个函数**内,每个函数内是一个新的寄存器分配类。 +// 因而约定x8-x9 x18-27、f8-9、f18-27 +// 是约定的所有函数都要保护的寄存器,用完要恢复原值 +// 其他的寄存器(除函数参数所用的a0-a7等寄存器)都视为是不安全的,可能会在之后的运算中发生变化 +// TODO:3 +// 在该类的实例生存周期内,使用到的需要保护的寄存器使用一个vector +// 存储 + +// 寄存器分配(IR变量到汇编变量地址映射) +// 所有的临时变量均分配在栈上(从当前函数开始的地方开始计算栈地址,相对栈偏移地址),所有的全局变量放置在内存中(首地址+偏移量形式) +// 当存在需要寄存器保护的时候,直接找回原地址去进行 +class RegAlloca { +public: + DSU DSU_for_Variable; + + /** + * 返回 Value 所关联的寄存器操作数。若 Value + * 未关联寄存器,则分配寄存器并进行关联,并处理相关的数据载入与写回。 + * @param val 需要查找寄存器的 Value + * @param bb 插入指令需要提供的基本块 + * @param instr 在 instr 之前插入指令(可选) + * @param inReg 是否一定返回一个寄存器操作数,若为 true 则是 + * @param load 是否将 Value 所对应的物理地址内容载入到寄存器中,若为 true 则是 + * @param specified 是否指定关联的寄存器,若为 nullptr + * 则不指定,若为一个寄存器操作数则在任何情况下都将 Value + * 与指定的寄存器进行强制关联。 + * @param direct 仅在 Value 为指针时生效,用于在载入物理地址时传递参数给 + * findMem + * @return 返回一个 IntegerReg* 或 FloatReg* 类型的操作数 rs 。 + * @attention 该函数将在 Value 为 Alloca 指令时进行特殊处理,在 load=1 时将 + * Alloca 指针所指向的地址载入到分配的寄存器中。 + * @attention 该函数将在 Value 为常量时进行特殊处理,在 load=1 时将常量通过 LI + * 指令载入到分配的寄存器中。 + * @attention 目前不应使用 direct 参数。 + */ + RiscvOperand *findReg(Value *val, RiscvBasicBlock *bb, + RiscvInstr *instr = nullptr, int inReg = 0, + int load = 1, RiscvOperand *specified = nullptr, + bool direct = true); + + /** + * 对传递过来的 Value 返回其所处的物理地址操作数 offset(rs) 。 + * @param val 需要查找物理地址的 Value + * @param bb 插入指令需要提供的基本块 + * @param instr 在 instr 之前插入指令(可选) + * @param direct 当 direct 为 false 时将使用间接寻址。若使用间接寻址且 + * Value 为指针 (getElementInstr) ,则 findMem() + * 将会将指针所指向的地址载入临时寄存器 t5,并返回操作数 0(t5) 。 + * @return 返回一个 IntegerPhiReg* 或 FloatPhiReg* 类型的操作数 offset(rs) + * 。若操作数偏移量溢出,则将会计算返回操作数所指代的地址 (t5)。 + */ + RiscvOperand *findMem(Value *val, RiscvBasicBlock *bb, RiscvInstr *instr, + bool direct); + /** + * 对传递过来的 Value 返回其所处的物理地址操作数 offset(rs) 。 + * @attention 这是一个重载形式的函数,其不支持间接寻址。 + * @param val 需要查找物理地址的 Value + */ + RiscvOperand *findMem(Value *val); + + // TODO:2 findNonuse + // 实现一个函数,以找到一个当前尚未使用的寄存器以存放某个值。 + RiscvOperand *findNonuse(Type *ty, RiscvBasicBlock *bb, + RiscvInstr *instr = nullptr); + + /** + * 将 Value 与指定的寄存器强制关联并返回寄存器操作数。 + * @param val 需要查找寄存器的 Value + * @param RegName 需要强制关联的寄存器接口名称 + * @param bb 插入指令需要提供的基本块 + * @param instr 在 instr 之前插入指令(可选) + * @param direct 仅在 Value 为指针时生效,用于在载入物理地址时传递参数给 + * findMem + * @return 返回强制关联的寄存器操作数 rs 。 + * @note 该函数将在 Value 为 Alloca 指令时进行特殊处理,在 load=1 时将 + * Alloca 指针所指向的地址载入到分配的寄存器中。 + * @note 该函数将在 Value 为常量时进行特殊处理,在 load=1 时将常量通过 LI + * 指令载入到分配的寄存器中。 + * @attention 目前不应使用 direct 参数。 + */ + RiscvOperand *findSpecificReg(Value *val, std::string RegName, + RiscvBasicBlock *bb, + RiscvInstr *instr = nullptr, + bool direct = true); + + /** + * 将 Value 与指定的物理地址操作数 offset(rs) 相关联。 + * @param val 需要关联的 Value + * @param riscvVal 被关联的物理地址操作数 offset(rs) + * @attention 该函数也被用于关联 Alloca 指针与其指向的地址。 + */ + void setPosition(Value *val, RiscvOperand *riscvVal); + + /** + * 将 Value 与指定的寄存器 rs 相关联。若寄存器内已有值,则将值写回。 + * @param val 需要关联的 Value + * @param riscvReg 被关联的寄存器 rs + * @param bb 用于插入的基本块 + * @param instr 在 instr 之前插入指令(可选) + * @attention 在大多数情况下你不应直接使用此函数。作为替代,你应该使用 findReg + * 与 findSpecificReg 函数来进行关联。 + */ + void setPositionReg(Value *val, RiscvOperand *riscvReg, RiscvBasicBlock *bb, + RiscvInstr *instr = nullptr); + /** + * 将 Value 与指定的寄存器 rs 相关联。若寄存器内已有值,则将值写回。 + * @param val 需要关联的 Value + * @param riscvReg 被关联的寄存器 rs + * @attention 在大多数情况下你不应直接使用此函数。作为替代,你应该使用 findReg + * 与 findSpecificReg 函数来进行关联。 + */ + void setPositionReg(Value *val, RiscvOperand *riscvReg); + + /** + * 记录 getElementPtr 类型的 Value 所指向的常量相对物理地址操作数 offset(sp) + * 。 + * @param val 指针类型的 Value + * @param PointerMem 被关联的操作数 offset(sp) + * @attention offset 只能为一常量。 + */ + void setPointerPos(Value *val, RiscvOperand *PointerMem); + + /** + * 将寄存器内容写回到内存地址中,并移除该寄存器在pos中映射的地址。 + * @param riscvReg 将要写回的寄存器 + * @param bb 指令将要插入的基本块 + * @param instr 当前需要在哪一条指令前方插入sw指令 + * @return 返回最后写入的指令 + */ + RiscvInstr *writeback(RiscvOperand *riscvReg, RiscvBasicBlock *bb, + RiscvInstr *instr = nullptr); + /** + * 将 Value 所关联的寄存器写回到内存地址中,并移除该寄存器在pos中映射的地址。 + * @param val 将要写回的 Value + * @param bb 指令将要插入的基本块 + * @param instr 当前需要在哪一条指令前方插入sw指令 + * @return 返回最后写入的指令 + */ + RiscvInstr *writeback(Value *val, RiscvBasicBlock *bb, + RiscvInstr *instr = nullptr); + + /** + * 返回寄存器 reg 所对应的 Value 。 + */ + Value *getRegPosition(RiscvOperand *reg); + + /** + * 返回 Value 所对应的寄存器 reg 。 + */ + RiscvOperand *getPositionReg(Value *val); + + /** + * 保护的寄存器对象数组。 + */ + std::vector savedRegister; + + /** + * 初始化寄存器对象池,需要保护的寄存器对象等。 + */ + RegAlloca(); + + // 指针所指向的内存地址 + std::map ptrPos; + + /** + * 返回指针类型的 Value 所指向的常量相对物理地址操作数 offset(sp) 。 + * @attention 参数 bb, instr 目前不被使用。 + */ + RiscvOperand *findPtr(Value *val, RiscvBasicBlock *bb, + RiscvInstr *instr = nullptr); + + /** + * 写回所有与内存存在关联的寄存器并删除关联。 + * @param bb 被插入基本块 + * @param instr 在特定指令前插入 + */ + void writeback_all(RiscvBasicBlock *bb, RiscvInstr *instr = nullptr); + + /** + * 清空所有寄存器关系。 + */ + void clear(); + + /** + * 返回所有被使用过的寄存器集合。 + */ + std::set getUsedReg() { return regUsed; } + +private: + std::map pos, curReg; + std::map regPos; + /** + * 安全寄存器寻找。用于确保寄存器在被寻找之后的 SAFE_FIND_LIMIT + * 个时间戳内不被写回。 + */ + std::map regFindTimeStamp; + int safeFindTimeStamp = 0; + static const int SAFE_FIND_LIMIT = 3; + /** + * 被使用过的寄存器。 + */ + std::set regUsed; +}; + +/** + * 寄存器对象池。 + */ +static std::vector regPool; + +/** + * 根据提供的寄存器名,从寄存器池中返回操作数。 + */ +RiscvOperand *getRegOperand(std::string reg); + +/** + * 根据提供的寄存器类型与编号,从寄存器池中返回操作数。 + */ +RiscvOperand *getRegOperand(Register::RegType op_ty_, int id); + +#endif // !REGALLOCH \ No newline at end of file diff --git a/compiler/src/riscv/riscv.cpp b/compiler/src/riscv/riscv.cpp new file mode 100644 index 0000000..972b3c6 --- /dev/null +++ b/compiler/src/riscv/riscv.cpp @@ -0,0 +1,137 @@ +#include "riscv.h" +#include "backend.h" +#include "ir.h" + +const int REG_NUMBER = 32; + +RiscvFunction::RiscvFunction(std::string name, int num_args, + OpTy Ty) // 返回值,无返回使用void类型 + : RiscvLabel(Function, name), num_args_(num_args), resType_(Ty), + base_(-VARIABLE_ALIGN_BYTE) { + regAlloca = new RegAlloca(); +} +// 输出函数对应的全部riscv语句序列 +// 由于一个函数可能有若干个出口,因而恢复现场的语句根据basic block +// 语句中的ret语句前面附带出现,因而不在此出现 +std::string RiscvFunction::print() { + // TODO: temporaily add '.global' to declare function + // Don't know if '.type' is needed + std::string riscvInstr = + ".global " + this->name_ + "\n" + this->name_ + ":\n"; // 函数标号打印 + // 对各个basic block进行拼接 + for (auto x : this->blk) + riscvInstr += x->print(); + return riscvInstr; +} + +std::string RiscvBasicBlock::print() { + std::string riscvInstr = this->name_ + ":\n"; + for (auto x : this->instruction) + riscvInstr += x->print(); + return riscvInstr; +} + +// 出栈顺序和入栈相反 +// 建议不使用pop语句,直接从栈中取值,最后直接修改sp的值即可 +// 使用一个单独的return block以防止多出口return +extern int LabelCount; + +RiscvOperand::OpTy RiscvOperand::getType() { return tid_; } + +bool RiscvOperand::isRegister() { return tid_ == FloatReg || tid_ == IntReg; } + +Type *findPtrType(Type *ty) { + while (ty->tid_ == Type::PointerTyID) { + ty = static_cast(ty)->contained_; + } + while (ty->tid_ == Type::ArrayTyID) { + ty = static_cast(ty)->contained_; + } + assert(ty->tid_ == Type::IntegerTyID || ty->tid_ == Type::FloatTyID); + return ty; +} + +std::string RiscvGlobalVariable::print(bool print_name, Constant *initVal) { + std::string code = ""; + // 如果在调用的第一层,初始化 initVal + if (print_name) { + code += this->name_ + ":\n"; + initVal = initValue_; + } + + if (initVal == nullptr) + return "\t.zero\t" + std::to_string(this->elementNum_ * 4) + "\n";; + + // 如果无初始值,或初始值为0(IR中有ConstZero类),则直接用zero命令 + if (dynamic_cast(initVal) != nullptr) { + code += "\t.zero\t" + std::to_string(calcTypeSize(initVal->type_)) + "\n"; + return code; + } + // 下面是非零的处理 + // 整型 + if (initVal->type_->tid_ == Type::TypeID::IntegerTyID) { + code += "\t.word\t" + std::to_string(dynamic_cast(initVal)->value_) + "\n"; + return code; + } + // 浮点 + else if (initVal->type_->tid_ == Type::TypeID::FloatTyID) { + std::string valString = dynamic_cast(initVal)->print32(); + while (valString.length() < 10) + valString += "0"; + code += "\t.word\t" + valString.substr(0, 10) + "\n"; + return code; + } + else if (initVal->type_->tid_ == Type::TypeID::ArrayTyID) { + ConstantArray *const_arr = dynamic_cast(initVal); + assert(const_arr != nullptr); + int zeroSpace = calcTypeSize(initVal->type_); + for (auto elements : const_arr->const_array) { + code += print(false, elements); + zeroSpace -= 4; + } + if (zeroSpace) + code += "\t.zero\t" + std::to_string(zeroSpace) + "\n"; + return code; + } else { + std::cerr + << "[Fatal Error] Unknown RiscvGlobalVariable::print() initValue type." + << std::endl; + std::terminate(); + } +} + +std::string RiscvGlobalVariable::print() { return print(true, nullptr); } + +RiscvFunction *createSyslibFunc(Function *foo) { + if (foo->name_ == "__aeabi_memclr4") { + auto *rfoo = createRiscvFunction(foo); + // 预处理块 + auto *bb1 = createRiscvBasicBlock(); + bb1->addInstrBack(new MoveRiscvInst(getRegOperand("t5"), + getRegOperand("a0"), bb1)); + bb1->addInstrBack(new MoveRiscvInst(getRegOperand("t6"), + getRegOperand("a1"), bb1)); + bb1->addInstrBack(new BinaryRiscvInst(RiscvInstr::ADD, getRegOperand("a0"), + getRegOperand("t6"), + getRegOperand("t6"), bb1)); + bb1->addInstrBack( + new MoveRiscvInst(getRegOperand("a0"), new RiscvConst(0), bb1)); + auto *bb2 = createRiscvBasicBlock(); + // 循环块 + // 默认clear为全0 + bb2->addInstrBack(new StoreRiscvInst( + new Type(Type::TypeID::IntegerTyID), getRegOperand("zero"), + new RiscvIntPhiReg(NamefindReg("t5")), bb2)); + bb2->addInstrBack(new BinaryRiscvInst(RiscvInstr::ADDI, getRegOperand("t5"), + new RiscvConst(4), + getRegOperand("t5"), bb1)); + bb2->addInstrBack(new ICmpRiscvInstr(ICmpInst::ICMP_SLT, + getRegOperand("t5"), + getRegOperand("t6"), bb2, bb2)); + bb2->addInstrBack(new ReturnRiscvInst(bb2)); + rfoo->addBlock(bb1); + rfoo->addBlock(bb2); + return rfoo; + } + return nullptr; +} \ No newline at end of file diff --git a/compiler/src/riscv/riscv.h b/compiler/src/riscv/riscv.h new file mode 100644 index 0000000..a5e8d97 --- /dev/null +++ b/compiler/src/riscv/riscv.h @@ -0,0 +1,343 @@ +#ifndef RISCVH +#define RISCVH + +class RiscvLabel; +class RiscvBasicBlock; +class RiscvInstr; +class RegAlloca; +class Register; +class RiscvOperand; + +const int VARIABLE_ALIGN_BYTE = 8; + +#include "ir.h" +#include "string.h" + +class RiscvOperand { +public: + enum OpTy { + Void = 0, // 空类型,为无函数返回值专用的类型 + IntImm, // 整型立即数 + FloatImm, // 浮点立即数 + IntReg, // 数值直接保存在整型寄存器 + FloatReg, // 数值直接保存在浮点寄存器 + IntMem, // 整型M[R(rd)+shift],无寄存器可用x0,无偏移可用shift=0 + FloatMem, // 浮点,同上 + Function, // 调用函数 + Block // 基本语句块标号 + }; + OpTy tid_; + explicit RiscvOperand(OpTy tid) : tid_(tid) {} + ~RiscvOperand() = default; + virtual std::string print() = 0; + OpTy getType(); + + // If this operand is a register, return true. + bool isRegister(); +}; + +// 寄存器堆 +class Register { + +public: + Register() = default; + ~Register() = default; + enum RegType { + Int = 1, // 整型 + Float, // 浮点 + Stack, // 栈专用 + Zero // 零寄存器 + }; + RegType regtype_; + int rid_; // 寄存器编号 + Register(RegType regtype, int rid) : regtype_(regtype), rid_(rid) {} + std::string print() { + using std::to_string; + if (this->regtype_ == Float) { + if (this->rid_ <= 7) + return "ft" + to_string(rid_); + else if (this->rid_ <= 9) + return "fs" + to_string(rid_ - 8); + else if (this->rid_ <= 17) + return "fa" + to_string(rid_ - 10); + else if (this->rid_ <= 27) + return "fs" + to_string(rid_ - 18 + 2); + else if (this->rid_ <= 31) + return "ft" + to_string(rid_ - 28 + 8); + else + return "wtf"; + } + // 整型各类输出 + switch (this->rid_) { + case 0: + return "zero"; + case 1: + return "ra"; + case 2: + return "sp"; + case 3: + return "gp"; + case 4: + return "tp"; + case 5: + case 6: + case 7: + return "t" + to_string(this->rid_ - 5); + case 8: + return "fp"; // another name: s0 + case 9: + return "s1"; + } + if (this->rid_ >= 10 && this->rid_ <= 17) + return "a" + to_string(this->rid_ - 10); + if (this->rid_ >= 18 && this->rid_ <= 27) + return "s" + to_string(this->rid_ - 16); + return "t" + to_string(this->rid_ - 25); + } +}; + +extern const int REG_NUMBER; + +// 常数 +class RiscvConst : public RiscvOperand { + +public: + int intval; + float floatval; + RiscvConst() = default; + explicit RiscvConst(int val) : RiscvOperand(IntImm), intval(val) {} + explicit RiscvConst(float val) : RiscvOperand(FloatImm), floatval(val) {} + std::string print() { + if (this->tid_ == IntImm) + return std::to_string(intval); + else + return std::to_string(floatval); + } +}; + +// 整型寄存器直接存储 +class RiscvIntReg : public RiscvOperand { + +public: + Register *reg_; + RiscvIntReg(Register *reg) : RiscvOperand(IntReg), reg_(reg) { + assert(reg_->regtype_ == Register::Int); // 判断整型寄存器存储 + } + std::string print() { return reg_->print(); } +}; + +class RiscvFloatReg : public RiscvOperand { + +public: + Register *reg_; + RiscvFloatReg(Register *reg) : RiscvOperand(FloatReg), reg_(reg) { + assert(reg_->regtype_ == Register::Float); // 判断整型寄存器存储 + } + std::string print() { return reg_->print(); } +}; + +// 需间接寻址得到的数据,整型 +class RiscvIntPhiReg : public RiscvOperand { + +public: + int shift_; + int isGlobalVariable; + Register *base_; + std::string MemBaseName; + RiscvIntPhiReg(Register *base, int shift = 0, int isGVar = false) + : RiscvOperand(IntMem), base_(base), shift_(shift), + isGlobalVariable(isGVar), MemBaseName(base_->print()) {} + // 内存以全局形式存在的变量(常量) + RiscvIntPhiReg(std::string s, int shift = 0, int isGVar = false) + : RiscvOperand(IntMem), base_(nullptr), shift_(shift), MemBaseName(s), + isGlobalVariable(isGVar) {} + std::string print() { + std::string ans = ""; + if (base_ != nullptr) + ans += "(" + base_->print() + ")"; + else { + if (isGlobalVariable) + return MemBaseName; // If global variable, use direct addressing + else + ans += "(" + MemBaseName + ")"; + } + if (shift_) + ans = std::to_string(shift_) + ans; + return ans; + } + /** + * Return if shift value overflows. + */ + bool overflow() { return std::abs(shift_) >= 1024; } +}; + +// 需间接寻址得到的数据,浮点 +class RiscvFloatPhiReg : public RiscvOperand { + +public: + int shift_; + Register *base_; + std::string MemBaseName; + int isGlobalVariable; + RiscvFloatPhiReg(Register *base, int shift = 0, int isGVar = false) + : RiscvOperand(FloatMem), base_(base), shift_(shift), + isGlobalVariable(isGVar), MemBaseName(base_->print()) {} + // 内存以全局形式存在的变量(常量) + RiscvFloatPhiReg(std::string s, int shift = 0, int isGVar = false) + : RiscvOperand(FloatMem), base_(nullptr), shift_(shift), MemBaseName(s), + isGlobalVariable(isGVar) {} + std::string print() { + std::string ans = ""; + if (base_ != nullptr) + ans += "(" + base_->print() + ")"; + else { + if (isGlobalVariable) + return MemBaseName; // If global variable, use direct addressing + else + ans += "(" + MemBaseName + ")"; + } + if (shift_) + ans = std::to_string(shift_) + ans; + return ans; + } + /** + * Return if shift value overflows. + */ + bool overflow() { return std::abs(shift_) >= 1024; } +}; + +class RiscvLabel : public RiscvOperand { +public: + std::string name_; // 标号名称 + ~RiscvLabel() = default; + RiscvLabel(OpTy Type, std::string name) : RiscvOperand(Type), name_(name) { + // std::cout << "CREATE A LABEL:" << name << "\n"; + } + virtual std::string print() = 0; +}; + +// 全局变量 +// 需指明是浮点还是整型 +// 最后拼装 +class RiscvGlobalVariable : public RiscvLabel { +public: + bool isConst_; + bool isData; // 是否是给定初值的变量 + int elementNum_; + Constant *initValue_; + // 对于一般单个全局变量的定义 + RiscvGlobalVariable(OpTy Type, std::string name, bool isConst, + Constant *initValue) + : RiscvLabel(Type, name), isConst_(isConst), initValue_(initValue), + elementNum_(1) {} + // 对于数组全局变量的定义 + RiscvGlobalVariable(OpTy Type, std::string name, bool isConst, + Constant *initValue, int elementNum) + : RiscvLabel(Type, name), isConst_(isConst), initValue_(initValue), + elementNum_(elementNum) {} + // 输出全局变量定义 + // 根据ir中全局变量定义转化 + // 问题在于全局变量如果是数组有初值如何处理 + std::string print(); + std::string print(bool print_name, Constant *initVal); +}; + +// 用标号标识函数 +// 函数挂靠在module下,接入若干条instruction,以及function不设置module指针 +// 默认不保护现场,如果当寄存器不够的时候再临时压栈 +// 父函数调用子函数的参数算在子函数的栈空间内,子函数结束后由子函数清除这部分栈空间 +class RiscvFunction : public RiscvLabel { +public: + RegAlloca *regAlloca; + int num_args_; + OpTy resType_; + std::vector args; + RiscvFunction(std::string name, int num_args, + OpTy Ty); // 返回值,无返回使用void类型 + void setArgs(int ind, RiscvOperand *op) { + assert(ind >= 0 && ind < args.size()); + args[ind] = op; + } + void deleteArgs(int ind) { + assert(ind >= 0 && ind < args.size()); + args[ind] = nullptr; + } + ~RiscvFunction() = default; + std::string printname() { return name_; } + std::vector blk; + bool is_libfunc() { + if (name_ == "putint" || name_ == "putch" || name_ == "putarray" || + name_ == "_sysy_starttime" || name_ == "_sysy_stoptime" || + name_ == "__aeabi_memclr4" || name_ == "__aeabi_memset4" || + name_ == "__aeabi_memcpy4" || name_ == "getint" || name_ == "getch" || + name_ == "getarray" || name_ == "getfloat" || name_ == "getfarray" || + name_ == "putfloat" || name_ == "putfarray" || + name_ == "llvm.memset.p0.i32") { + return true; + } else + return false; + } + std::map + argsOffset; // 函数使用到的参数(含调用参数、局部变量和返回值)在栈中位置。需满足字对齐(4的倍数) + // 届时将根据该函数的参数情况决定sp下移距离 + void addArgs(RiscvOperand *val) { // 在栈上新增操作数映射 + if (argsOffset.count(val) == 0) { + argsOffset[val] = base_; + base_ -= VARIABLE_ALIGN_BYTE; + } + } + int querySP() { return base_; } + void setSP(int SP) { base_ = SP; } + void addTempVar(RiscvOperand *val) { + addArgs(val); + tempRange += VARIABLE_ALIGN_BYTE; + } + void shiftSP(int shift_value) { base_ += shift_value; } + void storeArray(int elementNum) { + if(elementNum & 7) { + elementNum += 8 - (elementNum & 7); // Align to 8 byte. + } + base_ -= elementNum; + } + void deleteArgs(RiscvOperand *val) { argsOffset.erase(val); } // 删除一个参数 + // 默认所有寄存器不保护 + // 如果这个时候寄存器不够了,则临时把其中一个寄存器对应的值压入栈上,等函数结束的时候再恢复 + // 仅考虑函数内部SP相对关系而不要计算其绝对关系 + void saveOperand(RiscvOperand *val) { + storedEnvironment[val] = base_; + argsOffset[val] = base_; + base_ -= VARIABLE_ALIGN_BYTE; + } + int findArgs(RiscvOperand *val) { // 查询栈上位置 + if (argsOffset.count(val) == 0) + addArgs(val); + return argsOffset[val]; + } + void ChangeBlock(RiscvBasicBlock *bb, int ind) { + assert(ind >= 0 && ind < blk.size()); + blk[ind] = bb; + } + void addBlock(RiscvBasicBlock *bb) { blk.push_back(bb); } + std::string + print(); // 函数语句,需先push保护现场,然后pop出需要的参数,再接入各block +private: + int base_; + int tempRange; // 局部变量的数量,需要根据这个数量进行栈帧下移操作 + std::map + storedEnvironment; // 栈中要保护的地址。该部分需要在函数结束的时候全部恢复 +}; + +class RiscvModule { +public: + std::vector func_; + std::vector globalVariable_; + void addFunction(RiscvFunction *foo) { func_.push_back(foo); } + void addGlobalVariable(RiscvGlobalVariable *g) { + globalVariable_.push_back(g); + } +}; + +Type *findPtrType(Type *ty); + +RiscvFunction *createSyslibFunc(Function *foo); +#endif // !RISCVH \ No newline at end of file diff --git a/compiler/src/utils/CMakeLists.txt b/compiler/src/utils/CMakeLists.txt new file mode 100644 index 0000000..23473ad --- /dev/null +++ b/compiler/src/utils/CMakeLists.txt @@ -0,0 +1,3 @@ +set(SOURCE_FILES utils.cpp) + +add_library(utils ${SOURCE_FILES}) diff --git a/compiler/src/utils/utils.cpp b/compiler/src/utils/utils.cpp new file mode 100644 index 0000000..6158307 --- /dev/null +++ b/compiler/src/utils/utils.cpp @@ -0,0 +1 @@ +// Currently a dummy file diff --git a/compiler/test-cases/68_brainfk.in b/compiler/test-cases/68_brainfk.in new file mode 100644 index 0000000..23a0b41 --- /dev/null +++ b/compiler/test-cases/68_brainfk.in @@ -0,0 +1,2 @@ +4010 +++++++++[->++++++++<]>+++++++++.<+++++[->-----<]>---------.<++++++++[->++++++++<]>++++++.<++++++++[->--------<]>-------------.<+++++++[->+++++++<]>++.<+++++[->+++++<]>+++++++++.+++++.-----.--------.----.<++++[->++++<]>.<++++[->----<]>--------.<++++++++[->--------<]>-.<++++++[->++++++<]>++++.<+++++[->+++++<]>.<++++[->++++<]>+.+++.<+++[->---<]>----.+.<++++++++[->--------<]>---------.<++++++++[->++++++++<]>++++++.<+++[->+++<]>+++.---.--.<++++++++[->--------<]>-------------.<+++++++++[->+++++++++<]>+++.<+++[->---<]>---.---.<++++++++[->--------<]>-----.<++++++[->++++++<]>+.<+++++[->+++++<]>+++.<++++[->++++<]>++.+.<+++++++++[->---------<]>---.<++++++[->++++++<]>++++++.<++++++[->++++++<]>+++++++.-------.-----.++++++.+++.<+++++++++[->---------<]>-.<++++++[->++++++<]>++++.<+++++[->+++++<]>++++++++.--.+.<++++++++[->--------<]>--------.<+++++++[->+++++++<]>++.<++++[->++++<]>.+++++.+++++++..---.<++++++++[->--------<]>.<+++[->---<]>---.<++++++++[->++++++++<]>+.<+++[->+++<]>++++.<+++[->---<]>-.<++++++++[->--------<]>----.<++++++[->++++++<]>+++++.<+++++[->-----<]>---------.<++++++++[->++++++++<]>++++++.<++++++++[->--------<]>-------------.<++++++++[->++++++++<]>++++++++++++++.+.+++++.<+++++++++[->---------<]>---.<++++++++[->++++++++<]>+++++++++.+++++.++++++.<+++[->---<]>------.<+++[->+++<]>++++.<+++[->---<]>----.<+++[->+++<]>+++++.+.<+++[->---<]>------.-.<++++++++[->--------<]>----.<++++++++[->++++++++<]>+++++++++.+++++.<++++++++[->--------<]>--------------.<++++++++[->++++++++<]>+++++++++++++++.+++.<+++[->---<]>-----.+++++.+++++.<+++[->---<]>----.<++++[->++++<]>+.+++++++.<+++++++++[->---------<]>--------.<++++++++[->++++++++<]>++++++++.<+++[->+++<]>++++.--------.<+++[->---<]>---.<+++[->+++<]>++++.+++++.<++++++++[->--------<]>-----.<+++[->---<]>-----.<++++++[->++++++<]>+++++.<+++++[->+++++<]>++++.<++++++++[->--------<]>------.<+++++++++[->+++++++++<]>+++.<+++[->---<]>---.---.<+++[->+++<]>++++.<+++[->---<]>----.<++++++++[->--------<]>-----.<+++++++++[->+++++++++<]>++++++.<++++[->----<]>--.<+++[->+++<]>++++.<+++[->---<]>----.<++++++++[->--------<]>-----.<++++++++[->++++++++<]>+.<+++[->+++<]>++++.<++++++++[->--------<]>--------------.<++++++++[->++++++++<]>+.<+++[->+++<]>++.---.----.+++++++++.<++++++++[->--------<]>--.<+++[->---<]>---.<++++++++[->++++++++<]>+.<++++++++[->--------<]>-.<+++++++++[->+++++++++<]>+++.<+++[->---<]>--.++++.--------.<++++++++[->--------<]>-----.<+++++++++[->+++++++++<]>+++.--.<++++[->----<]>-.<++++[->++++<]>+++++.<++++[->----<]>-.+++++++..-------.<+++[->+++<]>++++.<++++++++[->--------<]>------.<+++[->---<]>---.<++++++++[->++++++++<]>+.<+++[->+++<]>++++.<++++++++[->--------<]>--------------.<++++++++[->++++++++<]>+++++++++++++++.+++++.<+++[->---<]>---.---.<+++[->+++<]>++++.+++++.--------.+++.------.--------.+.<+++[->+++<]>++++.<+++++++++[->---------<]>-.<++++++++[->++++++++<]>+++++++++++++++.+++.<+++++++++[->---------<]>-.<++++++++[->++++++++<]>+.<++++++++[->--------<]>-.<+++++++++[->+++++++++<]>++.++.-----.<+++[->---<]>--.<+++[->+++<]>++++.<+++[->---<]>-.---.<+++[->+++<]>++++.---.<++++++++[->--------<]>---------------.<++++++++[->++++++++<]>+.<+++[->+++<]>+++.++.-.-------.<++++++++[->--------<]>-------.<+++++++++[->+++++++++<]>++++++++.<+++[->---<]>-.++++++.<++++++++[->--------<]>---------.<+++[->---<]>---.<++++++++[->++++++++<]>++++++++++++++++.----.-------.----.<++++[->++++<]>++.<+++[->---<]>-----.<++++++++[->--------<]>-----.<++++++++[->++++++++<]>+++.<+++[->+++<]>+++.--.--------.<++++++++[->--------<]>-----.<+++++++++[->+++++++++<]>+++.-----.<++++++++[->--------<]>---------------.<++++++++[->++++++++<]>+++++++++++++.--------..<+++[->+++<]>++++++.<+++++++++[->---------<]>---.<++++++++[->++++++++<]>+++++++++++++.--------.<++++++++[->--------<]>----.-.<+++++++[->+++++++<]>+++.<++++[->++++<]>++++.-------.<++++[->++++<]>+++.<++++++++[->--------<]>-------------.<++++++++[->++++++++<]>++++++++++++.<+++++++++[->---------<]>--.<++++++++[->++++++++<]>+.<+++[->+++<]>++..<+++++++[->-------<]>-------------.<+++++[->-----<]>--------.---.< diff --git a/compiler/test-cases/68_brainfk.out b/compiler/test-cases/68_brainfk.out new file mode 100644 index 0000000..843dc54 --- /dev/null +++ b/compiler/test-cases/68_brainfk.out @@ -0,0 +1,2 @@ +I'm Suzumiya Haruhi from the East Junior High School, and I'm not interested in ordinary humans. If there were an alien, a time traveller, an otherworlder or a superhero among you, please come to meet me! That's all. +0 diff --git a/compiler/test-cases/68_brainfk.sy b/compiler/test-cases/68_brainfk.sy new file mode 100644 index 0000000..d1ee0c1 --- /dev/null +++ b/compiler/test-cases/68_brainfk.sy @@ -0,0 +1,73 @@ +/* +a brainfuck interpreter +reference: https://gist.github.com/maxcountryman/1699708 +*/ + +// tape, input buffer, and read/write pointer +const int TAPE_LEN = 65536, BUFFER_LEN = 32768; +int tape[TAPE_LEN], program[BUFFER_LEN], ptr = 0; + +// read the input program +void read_program() { + int i = 0, len = getint(); + while (i < len) { + program[i] = getch(); + i = i + 1; + } + program[i] = 0; +} + +// interpret the input program +void interpret(int input[]) { + int cur_char, loop, i = 0; + while (input[i]) { + cur_char = input[i]; + if (cur_char == 62) { + // '>' + ptr = ptr + 1; + } + else if (cur_char == 60) { + // '<' + ptr = ptr - 1; + } + else if (cur_char == 43) { + // '+' + tape[ptr] = tape[ptr] + 1; + } + else if (cur_char == 45) { + // '-' + tape[ptr] = tape[ptr] - 1; + } + else if (cur_char == 46) { + // '.' + putch(tape[ptr]); + } + else if (cur_char == 44) { + // ',' + tape[ptr] = getch(); + } + else if (cur_char == 93 && tape[ptr]) { + // ']' + loop = 1; + while (loop > 0) { + i = i - 1; + cur_char = input[i]; + if (cur_char == 91) { + // '[' + loop = loop - 1; + } + else if (cur_char == 93) { + // ']' + loop = loop + 1; + } + } + } + i = i + 1; + } +} + +int main() { + read_program(); + interpret(program); + return 0; +} diff --git a/compiler/test-cases/70_dijkstra.in b/compiler/test-cases/70_dijkstra.in new file mode 100644 index 0000000..5dc7677 --- /dev/null +++ b/compiler/test-cases/70_dijkstra.in @@ -0,0 +1,10 @@ +6 9 +1 2 1 +2 3 9 +1 3 12 +2 4 3 +4 3 4 +3 5 5 +4 5 13 +5 6 4 +4 6 15 diff --git a/compiler/test-cases/70_dijkstra.out b/compiler/test-cases/70_dijkstra.out new file mode 100644 index 0000000..5cfcce8 --- /dev/null +++ b/compiler/test-cases/70_dijkstra.out @@ -0,0 +1,2 @@ +0 1 8 4 13 17 +0 diff --git a/compiler/test-cases/70_dijkstra.sy b/compiler/test-cases/70_dijkstra.sy new file mode 100644 index 0000000..78895e6 --- /dev/null +++ b/compiler/test-cases/70_dijkstra.sy @@ -0,0 +1,82 @@ +const int INF = 65535; +int e[16][16]; +int book[16]; +int dis[16]; +int n, m; +int v1, v2, w; + +void Dijkstra() +{ + int i, j; + + i = 1; + while (i <= n) { + dis[i] = e[1][i]; + book[i] = 0; + i = i + 1; + } + book[1] = 1; + + i = 1; + while (i <= n - 1) { + int min_num = INF; + int min_index = 0; + int k = 1; + while (k <= n) { + if (min_num > dis[k] && book[k] == 0) { + min_num = dis[k]; + min_index = k; + } + k = k + 1; + } + book[min_index] = 1; + int j = 1; + while (j <= n) { + if (e[min_index][j] < INF) { + if (dis[j] > dis[min_index] + e[min_index][j]) { + dis[j] = dis[min_index] + e[min_index][j]; + } + } + j = j + 1; + } + i = i + 1; + } +} + +int main() +{ + int i; + n = getint(); + m = getint(); + + i = 1; + while (i <= n) { + int j = 1; + while (j <= n) { + if (i == j) + e[i][j] = 0; + else + e[i][j] = INF; + j = j + 1; + } + i = i + 1; + } + + i = 1; + while (i <= m) { + int u = getint(), v = getint(); + e[u][v] = getint(); + i = i + 1; + } + + Dijkstra(); + + i = 1; + while (i <= n) { + putint(dis[i]); + putch(32); + i = i + 1; + } + putch(10); + return 0; +} diff --git a/compiler/test-cases/71_full_conn.in b/compiler/test-cases/71_full_conn.in new file mode 100644 index 0000000..ec3c569 --- /dev/null +++ b/compiler/test-cases/71_full_conn.in @@ -0,0 +1,37 @@ +6 + +233 95 179 178 105 +115 190 92 216 21 +48 252 184 148 36 +252 20 92 99 18 +61 245 40 190 16 + +61 197 150 246 225 +27 99 197 227 206 +130 134 172 149 52 +147 246 171 52 84 +174 42 90 23 42 + +130 207 209 104 168 +139 248 84 142 225 +127 242 45 62 7 +102 191 119 168 190 +14 249 239 188 118 + +159 29 212 96 189 +159 220 97 71 180 +202 131 217 165 138 +94 98 86 68 140 +132 92 247 99 110 + +228 10 119 127 21 +247 8 230 81 251 +216 213 24 114 68 +83 188 240 196 231 +90 206 224 49 28 + +158 252 95 171 239 +90 66 22 221 10 +177 32 38 24 93 +227 55 4 59 211 +80 92 38 238 42 diff --git a/compiler/test-cases/71_full_conn.out b/compiler/test-cases/71_full_conn.out new file mode 100644 index 0000000..b69acee --- /dev/null +++ b/compiler/test-cases/71_full_conn.out @@ -0,0 +1,7 @@ +dog +cat +dog +dog +cat +cat +0 diff --git a/compiler/test-cases/71_full_conn.sy b/compiler/test-cases/71_full_conn.sy new file mode 100644 index 0000000..01f83aa --- /dev/null +++ b/compiler/test-cases/71_full_conn.sy @@ -0,0 +1,50 @@ + +int relu_reg(int a) +{ + if (a > 0x7F) return 0x7F; + if (a < 0) return 0; + return a; +} + +int model(int a[][5]) +{ + if (+ relu_reg( + a[0][0] * 85 + a[0][1] * 23 + a[0][2] * -82 + a[0][3] * -103 + a[0][4] * -123 + a[1][0] * 64 + a[1][1] * -120 + a[1][2] * 50 + a[1][3] * -59 + a[1][4] * 47 + a[2][0] * -111 + a[2][1] * -67 + a[2][2] * -106 + a[2][3] * -75 + a[2][4] * -102 + a[3][0] * 34 + a[3][1] * -39 + a[3][2] * 65 + a[3][3] * 47 + a[3][4] * 113 + a[4][0] * 110 + a[4][1] * 47 + a[4][2] * -4 + a[4][3] * 80 + a[4][4] * 46) * 39 + + relu_reg( + a[0][0] * -106 + a[0][1] * 126 + a[0][2] * -18 + a[0][3] * -31 + a[0][4] * -8 + a[1][0] * 47 + a[1][1] * -4 + a[1][2] * 67 + a[1][3] * -94 + a[1][4] * -121 + a[2][0] * 7 + a[2][1] * -21 + a[2][2] * -60 + a[2][3] * -43 + a[2][4] * 105 + a[3][0] * -42 + a[3][1] * 87 + a[3][2] * 29 + a[3][3] * -106 + a[3][4] * -31 + a[4][0] * -110 + a[4][1] * -100 + a[4][2] * -22 + a[4][3] * -75 + a[4][4] * -125) * 77 + + relu_reg( + a[0][0] * 26 + a[0][1] * 76 + a[0][2] * -70 + a[0][3] * 29 + a[0][4] * -95 + a[1][0] * 96 + a[1][1] * 52 + a[1][2] * -68 + a[1][3] * -5 + a[1][4] * 34 + a[2][0] * -34 + a[2][1] * 102 + a[2][2] * 6 + a[2][3] * -38 + a[2][4] * 27 + a[3][0] * 110 + a[3][1] * 116 + a[3][2] * 39 + a[3][3] * -63 + a[3][4] * -99 + a[4][0] * 65 + a[4][1] * 120 + a[4][2] * -39 + a[4][3] * -6 + a[4][4] * 94) * 127 + + relu_reg( + a[0][0] * -23 + a[0][1] * -63 + a[0][2] * 49 + a[0][3] * 50 + a[0][4] * 72 + a[1][0] * 85 + a[1][1] * -30 + a[1][2] * 12 + a[1][3] * 125 + a[1][4] * -117 + a[2][0] * -65 + a[2][1] * -67 + a[2][2] * 125 + a[2][3] * 110 + a[2][4] * -31 + a[3][0] * -123 + a[3][1] * 83 + a[3][2] * 122 + a[3][3] * 11 + a[3][4] * -23 + a[4][0] * -47 + a[4][1] * -32 + a[4][2] * -117 + a[4][3] * 95 + a[4][4] * 118) * -106 + + relu_reg( + a[0][0] * 8 + a[0][1] * 82 + a[0][2] * -104 + a[0][3] * 101 + a[0][4] * -116 + a[1][0] * -63 + a[1][1] * -16 + a[1][2] * -70 + a[1][3] * 125 + a[1][4] * 75 + a[2][0] * 66 + a[2][1] * -96 + a[2][2] * -101 + a[2][3] * -114 + a[2][4] * 59 + a[3][0] * 12 + a[3][1] * 5 + a[3][2] * -95 + a[3][3] * 116 + a[3][4] * -93 + a[4][0] * 15 + a[4][1] * 79 + a[4][2] * 3 + a[4][3] * 49 + a[4][4] * -124) * -3 + + relu_reg( + a[0][0] * 81 + a[0][1] * 68 + a[0][2] * -102 + a[0][3] * -74 + a[0][4] * 121 + a[1][0] * -15 + a[1][1] * 55 + a[1][2] * 101 + a[1][3] * -13 + a[1][4] * -62 + a[2][0] * 64 + a[2][1] * 114 + a[2][2] * 38 + a[2][3] * -21 + a[2][4] * 112 + a[3][0] * 114 + a[3][1] * 112 + a[3][2] * -10 + a[3][3] * -16 + a[3][4] * -50 + a[4][0] * -112 + a[4][1] * -116 + a[4][2] * -54 + a[4][3] * 82 + a[4][4] * -72) * 32 + + relu_reg( + a[0][0] * 15 + a[0][1] * -77 + a[0][2] * 66 + a[0][3] * -90 + a[0][4] * -6 + a[1][0] * -30 + a[1][1] * -8 + a[1][2] * 81 + a[1][3] * 2 + a[1][4] * -110 + a[2][0] * -95 + a[2][1] * 59 + a[2][2] * 52 + a[2][3] * 15 + a[2][4] * 55 + a[3][0] * -33 + a[3][1] * 14 + a[3][2] * 58 + a[3][3] * 67 + a[3][4] * 86 + a[4][0] * -79 + a[4][1] * 48 + a[4][2] * -13 + a[4][3] * -15 + a[4][4] * 66) * -95 + + relu_reg( + a[0][0] * 33 + a[0][1] * 82 + a[0][2] * 67 + a[0][3] * 30 + a[0][4] * -2 + a[1][0] * 65 + a[1][1] * 120 + a[1][2] * -13 + a[1][3] * 18 + a[1][4] * 5 + a[2][0] * 104 + a[2][1] * -119 + a[2][2] * -7 + a[2][3] * 71 + a[2][4] * 107 + a[3][0] * 24 + a[3][1] * 82 + a[3][2] * -96 + a[3][3] * -104 + a[3][4] * -121 + a[4][0] * 65 + a[4][1] * 97 + a[4][2] * 83 + a[4][3] * 46 + a[4][4] * -84) * -50 + + relu_reg( + a[0][0] * -29 + a[0][1] * 7 + a[0][2] * -70 + a[0][3] * 38 + a[0][4] * -90 + a[1][0] * -15 + a[1][1] * -32 + a[1][2] * 37 + a[1][3] * 36 + a[1][4] * -62 + a[2][0] * -125 + a[2][1] * -46 + a[2][2] * -70 + a[2][3] * 37 + a[2][4] * -73 + a[3][0] * -34 + a[3][1] * -87 + a[3][2] * -75 + a[3][3] * 71 + a[3][4] * -77 + a[4][0] * 53 + a[4][1] * 37 + a[4][2] * -103 + a[4][3] * -13 + a[4][4] * -114) * -23 + + relu_reg( + a[0][0] * 67 + a[0][1] * 42 + a[0][2] * 41 + a[0][3] * -123 + a[0][4] * -92 + a[1][0] * 10 + a[1][1] * -77 + a[1][2] * 75 + a[1][3] * 96 + a[1][4] * -51 + a[2][0] * 109 + a[2][1] * -74 + a[2][2] * -7 + a[2][3] * -122 + a[2][4] * 67 + a[3][0] * 47 + a[3][1] * 22 + a[3][2] * -68 + a[3][3] * 38 + a[3][4] * 29 + a[4][0] * 115 + a[4][1] * -121 + a[4][2] * 36 + a[4][3] * -49 + a[4][4] * 85) * 46 + > 0) + return 1; + return 0; +} + +int main() +{ + int N = getint(); + int a[5][5]; + while (N > 0) { + int i = 0; + while (i < 5) { + int j = 0; + while (j < 5) { + a[i][j] = getint(); + j = j + 1; + } + i = i + 1; + } + if (model(a)) { + // cat + putch(99); putch(97); putch(116); putch(10); + } else { + // dog + putch(100); putch(111); putch(103); putch(10); + } + N = N - 1; + } + return 0; +} diff --git a/compiler/test-cases/72_hanoi.in b/compiler/test-cases/72_hanoi.in new file mode 100644 index 0000000..76dbb71 --- /dev/null +++ b/compiler/test-cases/72_hanoi.in @@ -0,0 +1,5 @@ +4 +4 +7 +3 +9 diff --git a/compiler/test-cases/72_hanoi.out b/compiler/test-cases/72_hanoi.out new file mode 100644 index 0000000..7102c51 --- /dev/null +++ b/compiler/test-cases/72_hanoi.out @@ -0,0 +1,5 @@ +1 2, 1 3, 2 3, 1 2, 3 1, 3 2, 1 2, 1 3, 2 3, 2 1, 3 1, 2 3, 1 2, 1 3, 2 3, +1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, +1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, +1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 3 1, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 1 2, 3 2, 3 1, 2 1, 3 2, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, 2 1, 3 2, 3 1, 2 1, 2 3, 1 3, 1 2, 3 2, 1 3, 2 1, 2 3, 1 3, +0 diff --git a/compiler/test-cases/72_hanoi.sy b/compiler/test-cases/72_hanoi.sy new file mode 100644 index 0000000..063bef8 --- /dev/null +++ b/compiler/test-cases/72_hanoi.sy @@ -0,0 +1,27 @@ + +void move(int x, int y) +{ + putint(x); putch(32); putint(y); putch(44); putch(32); +} + +void hanoi(int n, int one, int two, int three) +{ + if (n == 1) + move(one, three); + else { + hanoi(n - 1, one, three, two); + move(one, three); + hanoi(n - 1, two, one, three); + } +} + +int main() +{ + int n = getint(); + while (n > 0) { + hanoi(getint(), 1, 2, 3); + putch(10); + n = n - 1; + } + return 0; +} diff --git a/compiler/test-cases/73_int_io.in b/compiler/test-cases/73_int_io.in new file mode 100644 index 0000000..98c32c2 --- /dev/null +++ b/compiler/test-cases/73_int_io.in @@ -0,0 +1,14 @@ + + +5 + 4006571 + + 9900 + 1504379 + + +758219 + 99336677 + + + \ No newline at end of file diff --git a/compiler/test-cases/73_int_io.out b/compiler/test-cases/73_int_io.out new file mode 100644 index 0000000..651a1bc --- /dev/null +++ b/compiler/test-cases/73_int_io.out @@ -0,0 +1,6 @@ +4006571 +9900 +1504379 +758219 +99336677 +0 diff --git a/compiler/test-cases/73_int_io.sy b/compiler/test-cases/73_int_io.sy new file mode 100644 index 0000000..4f1b992 --- /dev/null +++ b/compiler/test-cases/73_int_io.sy @@ -0,0 +1,52 @@ +const int ascii_0 = 48; + +int my_getint() +{ + int sum = 0, c; + + while (1) { + c = getch() - ascii_0; + if (c < 0 || c > 9) { + continue; + } else { + break; + } + } + sum = c; + + while (1) { + c = getch() - ascii_0; + if (c >= 0 && c <= 9) { + sum = sum * 10 + c; + } else { + break; + } + } + + return sum; +} + +void my_putint(int a) +{ + int b[16], i = 0; + while (a > 0) { + b[i] = a % 10 + ascii_0; + a = a / 10; + i = i + 1; + } + while (i > 0) { + i = i - 1; + putch(b[i]); + } +} + +int main() +{ + int n = my_getint(); + while (n > 0) { + int m = my_getint(); + my_putint(m); putch(10); + n = n - 1; + } + return 0; +} diff --git a/compiler/test/CMakeLists.txt b/compiler/test/CMakeLists.txt new file mode 100644 index 0000000..6fcbbbf --- /dev/null +++ b/compiler/test/CMakeLists.txt @@ -0,0 +1,53 @@ +# Define test files +set(FUNCTIONAL_TESTS_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/case/functional") +set(HIDDEN_FUNCTIONAL_TESTS_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/case/hidden_functional") +set(PERFORMANCE_TESTS_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/case/performance") +set(FINAL_PERFORMANCE_TESTS_DIR + "${CMAKE_CURRENT_SOURCE_DIR}/case/final_performance") + +# set(BUILD_PERFORMANCE_TESTS true) +# set(BUILD_IR_TESTING true) + +# Define test function +function(add_test_dir testdir) + file(GLOB files "${testdir}/*.sy") + + foreach(file ${files}) + get_filename_component(testfile "${file}" NAME_WE) + get_filename_component(testcate "${testdir}" NAME) + set(testname "${testcate}_${testfile}") + if(BUILD_IR_TESTING) + add_test(NAME "${testname}_llir" + COMMAND ${CMAKE_COMMAND} + -D "COMPILER=${CMAKE_BINARY_DIR}/compiler" + -D "RUNTIME=${CMAKE_BINARY_DIR}/runtime" + -D "TEST_DIR=${testdir}" + -D "TEST_NAME=${testfile}" + -P ${CMAKE_SOURCE_DIR}/cmake/LLVMIRTest.cmake) + endif(BUILD_IR_TESTING) + add_test(NAME "${testname}_asm" + COMMAND ${CMAKE_COMMAND} + -D "COMPILER=${CMAKE_BINARY_DIR}/compiler" + -D "RUNTIME=${CMAKE_BINARY_DIR}/runtime" + -D "TEST_DIR=${testdir}" + -D "TEST_NAME=${testfile}" + -P ${CMAKE_SOURCE_DIR}/cmake/RISCVTest.cmake) + endforeach() +endfunction() + +# Functional tests +add_test_dir("${FUNCTIONAL_TESTS_DIR}") + +# Hidden functional tests +add_test_dir("${HIDDEN_FUNCTIONAL_TESTS_DIR}") + +if(BUILD_PERFORMANCE_TESTS) + # Performance tests + add_test_dir("${PERFORMANCE_TESTS_DIR}") + + # Final performance tests + add_test_dir("${FINAL_PERFORMANCE_TESTS_DIR}") +endif(BUILD_PERFORMANCE_TESTS) \ No newline at end of file