diff --git a/README.md b/README.md index ae37344..52eb7f1 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ Scarlet is a custom compiler developed in C++, designed with the primary goal of [![ubuntu](https://github.com/Sh0g0-1758/scarlet/actions/workflows/UBUNTU_test_gcc.yml/badge.svg)](https://github.com/Sh0g0-1758/scarlet/actions/workflows/UBUNTU_test_gcc.yml) [![macos](https://github.com/Sh0g0-1758/scarlet/actions/workflows/MACOS_test_clang.yml/badge.svg)](https://github.com/Sh0g0-1758/scarlet/actions/workflows/MACOS_test_clang.yml) -To build Scarlet, invoke `cmake` with the `DCMAKE_CXX_COMPILER` flag within the build directory and then run `make`. +To build Scarlet, invoke `cmake` with the `DCMAKE_CXX_COMPILER` flag within the build directory and then run `make`. By default, scarlet builds in `Release` mode (-O3). ```sh -cmake -DCMAKE_CXX_COMPILER= .. +cmake -DCMAKE_CXX_COMPILER= -DCMAKE_BUILD_TYPE= .. make ``` diff --git a/codegen/CMakeLists.txt b/codegen/CMakeLists.txt index 255b69c..6bbf80b 100644 --- a/codegen/CMakeLists.txt +++ b/codegen/CMakeLists.txt @@ -1,6 +1,19 @@ add_library(scarCodegen STATIC codegen.cc codegen.hh + common.hh + + scargen/scar.cc + scargen/scar_statement.cc + scargen/scar_factor.cc + scargen/scar_expression.cc + scargen/scar_declaration.cc + scargen/scar_block.cc + scargen/pretty_print.cc + + scasmgen/scasm_generation.cc + scasmgen/fix_pseudo_registers.cc + scasmgen/fix_instructions.cc ) set_basic_compile_options(scarCodegen) diff --git a/codegen/codegen.cc b/codegen/codegen.cc index 6fbe234..ade9ca3 100644 --- a/codegen/codegen.cc +++ b/codegen/codegen.cc @@ -1,1504 +1,8 @@ #include "codegen.hh" -#define MAKE_SHARED(a, b) std::shared_ptr b = std::make_shared() namespace scarlet { namespace codegen { -#define UNREACHABLE() \ - std::cout << "Unreachable code reached in " << __FILE__ << " at line " \ - << __LINE__ << std::endl; \ - __builtin_unreachable(); - -void Codegen::gen_scar_factor( - std::shared_ptr factor, - std::shared_ptr scar_function) { - // firstly put all the unops (if they exist) in the unop buffer - for (auto it : factor->get_unop_nodes()) { - unop_buffer[curr_buff].emplace_back(it->get_op()); - } - // if exp exists, parse that. If exp is null, it will simply return - if (factor->get_exp_node() != nullptr) { - curr_buff++; - if (curr_buff >= (int)unop_buffer.size()) - unop_buffer.resize(curr_buff + 1); - gen_scar_exp(factor->get_exp_node(), scar_function); - curr_buff--; - } - // If we have an integer node and unops to operate on, proceed... - if (!unop_buffer[curr_buff].empty()) { - int num_unpos = unop_buffer[curr_buff].size(); - for (int i = num_unpos - 1; i >= 0; i--) { - // SPECIAL CASE WHEN WE HAVE INCREMENT OR DECREMENT OPERATOR - unop::UNOP op = unop_buffer[curr_buff][i]; - if (op == unop::UNOP::PREINCREMENT or op == unop::UNOP::PREDECREMENT) { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::BINARY); - if (op == unop::UNOP::PREINCREMENT) { - scar_instruction->set_binop(binop::BINOP::ADD); - } else { - scar_instruction->set_binop(binop::BINOP::SUB); - } - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - - scar_val_dst->set_type(scar::val_type::VAR); - // The destination will always be a variable - if (!variable_buffer.empty()) { - scar_val_dst->set_reg_name(variable_buffer); - variable_buffer.clear(); - } else { - scar_val_dst->set_reg_name( - factor->get_identifier_node()->get_value()); - } - - reg_name = scar_val_dst->get_reg(); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(reg_name); - scar_instruction->set_src1(std::move(scar_val_src)); - - scar_val_src2->set_type(scar::val_type::CONSTANT); - scar_val_src2->set_value("1"); - scar_instruction->set_src2(std::move(scar_val_src2)); - - scar_function->add_instruction(std::move(scar_instruction)); - continue; - } else if (op == unop::UNOP::POSTINCREMENT or - op == unop::UNOP::POSTDECREMENT) { - // SPECIAL CASE WHEN WE HAVE POST INCREMENT OR DECREMENT - // Since these return the original value and then increment or decrement - // We first make a copy of the original value and then increment or - // decrement - - // COPY THE ORIGINAL VALUE INTO A NEW SCAR REGISTER - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::COPY); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_src->set_type(scar::val_type::VAR); - if (!variable_buffer.empty()) { - scar_val_src->set_reg_name(variable_buffer); - variable_buffer.clear(); - } else { - scar_val_src->set_reg_name( - factor->get_identifier_node()->get_value()); - } - std::string _variable = scar_val_src->get_reg(); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name(get_reg_name()); - scar_instruction->set_dst(std::move(scar_val_dst)); - scar_function->add_instruction(std::move(scar_instruction)); - - // NOW DO THE BINARY OPERATION - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::BINARY); - if (op == unop::UNOP::POSTINCREMENT) { - scar_instruction2->set_binop(binop::BINOP::ADD); - } else { - scar_instruction2->set_binop(binop::BINOP::SUB); - } - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - - scar_val_src2->set_type(scar::val_type::VAR); - scar_val_src2->set_reg_name(_variable); - scar_instruction2->set_src1(std::move(scar_val_src2)); - - scar_val_src3->set_type(scar::val_type::CONSTANT); - scar_val_src3->set_value("1"); - scar_instruction2->set_src2(std::move(scar_val_src3)); - - scar_val_dst2->set_type(scar::val_type::VAR); - scar_val_dst2->set_reg_name(_variable); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - - scar_function->add_instruction(std::move(scar_instruction2)); - continue; - } - // scar::scar_Instruction_Node scar_instruction; - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::UNARY); - scar_instruction->set_unop(op); - - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - - // deal with the source - if (i == num_unpos - 1) { - if (factor->get_int_node() != nullptr and - !factor->get_int_node()->get_value().empty()) { - scar_val_src->set_type(scar::val_type::CONSTANT); - scar_val_src->set_value(factor->get_int_node()->get_value()); - } else if (factor->get_identifier_node() != nullptr and - !factor->get_identifier_node()->get_value().empty()) { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name( - factor->get_identifier_node()->get_value()); - } else if (!constant_buffer.empty()) { - scar_val_src->set_type(scar::val_type::CONSTANT); - scar_val_src->set_value(constant_buffer); - constant_buffer.clear(); - } else if (!variable_buffer.empty()) { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(variable_buffer); - variable_buffer.clear(); - } else { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(get_prev_reg_name()); - } - } else { - scar_val_src->set_type(scar::val_type::VAR); - scar_val_src->set_reg_name(get_prev_reg_name()); - } - scar_instruction->set_src1(std::move(scar_val_src)); - - // deal with the destination - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name(get_reg_name()); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_function->add_instruction(std::move(scar_instruction)); - } - // empty the unop buffer - unop_buffer[curr_buff].clear(); - } else { - // NOTE: It is guaranteed that the factor node will have either an int node - // or an identifier node - - // save constant for later use - if (factor->get_int_node() != nullptr and - !factor->get_int_node()->get_value().empty()) { - constant_buffer = factor->get_int_node()->get_value(); - } - - // save variable for later use - if (factor->get_identifier_node() != nullptr and - !factor->get_identifier_node()->get_value().empty()) { - variable_buffer = factor->get_identifier_node()->get_value(); - } - } -} - -#define SETVARCONSTANTREG(src) \ - if (!variable_buffer.empty()) { \ - src->set_type(scar::val_type::VAR); \ - src->set_reg_name(variable_buffer); \ - variable_buffer.clear(); \ - } else if (!constant_buffer.empty()) { \ - src->set_type(scar::val_type::CONSTANT); \ - src->set_value(constant_buffer); \ - constant_buffer.clear(); \ - } else { \ - src->set_type(scar::val_type::VAR); \ - src->set_reg_name(get_prev_reg_name()); \ - } - -#define SETUPLANDLOR(num) \ - if (exp->get_binop_node()->get_op() == binop::BINOP::LAND) { \ - /* Logical and */ \ - scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_ZERO); \ - } else { \ - /* Logical or */ \ - scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); \ - } \ - \ - if (exp->get_left() == nullptr) { \ - if (num == 1) \ - gen_scar_factor(exp->get_factor_node(), scar_function); \ - SETVARCONSTANTREG(scar_val_src##num); \ - } else { \ - scar_val_src##num->set_type(scar::val_type::VAR); \ - scar_val_src##num->set_reg_name(get_prev_reg_name()); \ - } \ - \ - scar_instruction##num->set_src1(std::move(scar_val_src##num)); \ - scar_val_dst##num->set_type(scar::val_type::UNKNOWN); - -void Codegen::gen_scar_exp( - std::shared_ptr exp, - std::shared_ptr scar_function) { - if (exp == nullptr) - return; - gen_scar_exp(exp->get_left(), scar_function); - if (exp->get_binop_node() != nullptr and - exp->get_binop_node()->get_op() != binop::BINOP::UNKNOWN) { - // when we have a binary operator - // deal with && and || separately using jmpif(not)zero, labels and copy - // operations since we need to apply short circuit for them - // - // There will be a separate case for the assignment operator as that - // will be represented by a simple copy operation - // - // There will be a separate case for the ternary operator as well - // So first we need to check whether it is the first expression - // or the second expression that will be returned using jmpifzero - // and copy the result to a new register. Ternary is actually a special - // case of short circuiting - if (exp->get_binop_node()->get_op() == binop::BINOP::ASSIGN) { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::COPY); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - // the semantic analyis phase should have ensured that the left child - // is null, factor is an identifier with no unops and the right child - // is an expression - gen_scar_exp(exp->get_right(), scar_function); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(std::move(scar_val_src)); - - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name( - exp->get_factor_node()->get_identifier_node()->get_value()); - // NOTE: we update the current scar register name to use the variable - // since we can have expressions like: - // int b = a = 5; - reg_name = scar_val_dst->get_reg(); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_function->add_instruction(std::move(scar_instruction)); - return; - } - bool short_circuit = binop::short_circuit(exp->get_binop_node()->get_op()); - binop::BINOP sc_binop = exp->get_binop_node()->get_op(); - const binop::BINOP compound_binop = sc_binop; - if (binop::is_compound(compound_binop)) { - sc_binop = compound_to_base[compound_binop]; - } - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - if (short_circuit) { - if (sc_binop == binop::BINOP::LAND) { - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - } else if (sc_binop == binop::BINOP::LOR) { - scar_instruction->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); - } else if (sc_binop == binop::BINOP::TERNARY) { - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - } - } else { - scar_instruction->set_type(scar::instruction_type::BINARY); - scar_instruction->set_binop(sc_binop); - } - MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - - if (exp->get_left() == nullptr) { - gen_scar_factor(exp->get_factor_node(), scar_function); - SETVARCONSTANTREG(scar_val_src1); - } else { - scar_val_src1->set_type(scar::val_type::VAR); - scar_val_src1->set_reg_name(get_prev_reg_name()); - } - - scar_instruction->set_src1(std::move(scar_val_src1)); - - if (short_circuit) { - // create a label to jump to - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst1); - scar_val_dst1->set_type(scar::val_type::UNKNOWN); - scar_val_dst1->set_value(get_fr_label_name()); - scar_instruction->set_dst(std::move(scar_val_dst1)); - scar_function->add_instruction(std::move(scar_instruction)); - } - - // TERNARY SPECIAL CASE - if (sc_binop == binop::BINOP::TERNARY) { - // generate the first expression - gen_scar_exp(exp->get_middle(), scar_function); - - // copy this result in a new register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_instruction2->set_type(scar::instruction_type::COPY); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - scar_val_dst2->set_type(scar::val_type::VAR); - // Doing this so that we can use the same scar register to - // store the result of the second expression as well. - // We cannot simply use get_prev_reg_name() since we need to - // parse the second expression first and that will change the - // register counter - std::string result = get_reg_name(); - scar_val_dst2->set_reg_name(result); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(std::move(scar_instruction2)); - - // jump to the end - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_instruction3->set_type(scar::instruction_type::JUMP); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value(get_res_label_name()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(std::move(scar_instruction3)); - - // generate the intermediate label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_instruction4->set_type(scar::instruction_type::LABEL); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(get_last_fr_label_name(true)); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(std::move(scar_instruction4)); - - // generate the second expression - gen_scar_exp(exp->get_right(), scar_function); - - // copy this result in a new register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst5); - scar_instruction5->set_type(scar::instruction_type::COPY); - SETVARCONSTANTREG(scar_val_src5); - scar_instruction5->set_src1(std::move(scar_val_src5)); - scar_val_dst5->set_type(scar::val_type::VAR); - scar_val_dst5->set_reg_name(result); - scar_instruction5->set_dst(std::move(scar_val_dst5)); - scar_function->add_instruction(std::move(scar_instruction5)); - - // generate the final label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); - scar_instruction6->set_type(scar::instruction_type::LABEL); - scar_val_src6->set_type(scar::val_type::UNKNOWN); - scar_val_src6->set_value(get_last_res_label_name()); - scar_instruction6->set_src1(std::move(scar_val_src6)); - scar_function->add_instruction(std::move(scar_instruction6)); - - // early return - return; - } - gen_scar_exp(exp->get_right(), scar_function); - SETVARCONSTANTREG(scar_val_src2); - - if (short_circuit) { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - if (sc_binop == binop::BINOP::LAND) { - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); - } else { - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); - } - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(get_last_fr_label_name()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(std::move(scar_instruction2)); - - // now copy 1(LAND) / 0(LOR) into a scar register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst3); - scar_instruction3->set_type(scar::instruction_type::COPY); - scar_val_src3->set_type(scar::val_type::CONSTANT); - if (sc_binop == binop::BINOP::LAND) { - scar_val_src3->set_value(std::to_string(1)); - } else { - scar_val_src3->set_value(std::to_string(0)); - } - scar_val_dst3->set_type(scar::val_type::VAR); - scar_val_dst3->set_reg_name(get_reg_name()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_instruction3->set_dst(std::move(scar_val_dst3)); - scar_function->add_instruction(std::move(scar_instruction3)); - - // now jump to the end - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_instruction4->set_type(scar::instruction_type::JUMP); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(get_res_label_name()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(std::move(scar_instruction4)); - - // Now generate the intermediate label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); - scar_instruction5->set_type(scar::instruction_type::LABEL); - scar_val_src5->set_type(scar::val_type::UNKNOWN); - scar_val_src5->set_value(get_last_fr_label_name(true)); - scar_instruction5->set_src1(std::move(scar_val_src5)); - scar_function->add_instruction(std::move(scar_instruction5)); - - // now copy 0(LAND) / 1(LOR) into a scar register - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst6); - scar_instruction6->set_type(scar::instruction_type::COPY); - scar_val_src6->set_type(scar::val_type::CONSTANT); - if (sc_binop == binop::BINOP::LAND) { - scar_val_src6->set_value(std::to_string(0)); - } else { - scar_val_src6->set_value(std::to_string(1)); - } - scar_val_dst6->set_type(scar::val_type::VAR); - scar_val_dst6->set_reg_name(get_prev_reg_name()); - scar_instruction6->set_src1(std::move(scar_val_src6)); - scar_instruction6->set_dst(std::move(scar_val_dst6)); - scar_function->add_instruction(std::move(scar_instruction6)); - - // now generate the final label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction7); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src7); - scar_instruction7->set_type(scar::instruction_type::LABEL); - scar_val_src7->set_type(scar::val_type::UNKNOWN); - scar_val_src7->set_value(get_last_res_label_name()); - scar_instruction7->set_src1(std::move(scar_val_src7)); - scar_function->add_instruction(std::move(scar_instruction7)); - } else { - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::VAR); - if (binop::is_compound(compound_binop)) { - scar_val_dst->set_reg_name( - exp->get_factor_node()->get_identifier_node()->get_value()); - reg_name = scar_val_dst->get_reg(); - } else { - scar_val_dst->set_reg_name(get_reg_name()); - } - scar_instruction->set_src2(std::move(scar_val_src2)); - scar_instruction->set_dst(std::move(scar_val_dst)); - - scar_function->add_instruction(std::move(scar_instruction)); - } - } else { - // When we do not have a binary operator, so only parse the factor node - gen_scar_factor(exp->get_factor_node(), scar_function); - } -} - -void Codegen::gen_scar_statement( - std::shared_ptr statement, - std::shared_ptr scar_function) { - switch (statement->get_type()) { - case ast::statementType::NULLSTMT: - break; - case ast::statementType::RETURN: { - gen_scar_exp(statement->get_exps(), scar_function); - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::RETURN); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(scar_val_src); - scar_function->add_instruction(scar_instruction); - } break; - case ast::statementType::EXP: { - gen_scar_exp(statement->get_exps(), scar_function); - } break; - case ast::statementType::IF: { - // (stored in exps) - // c = - // JumpIfZero(c, end) - // (handled in the next iteration) - // Label(end) (Added during the end of if statement) - auto if_statement = - std::static_pointer_cast(statement); - gen_scar_exp(if_statement->get_exps(), scar_function); - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(std::move(scar_val_src)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::UNKNOWN); - scar_val_dst->set_value(if_statement->get_labels().first->get_value()); - scar_instruction->set_dst(std::move(scar_val_dst)); - scar_function->add_instruction(std::move(scar_instruction)); - - // generate scar for the statement - gen_scar_statement(if_statement->get_stmt1(), scar_function); - - // generate the end label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - scar_val_src2->set_type(scar::val_type::UNKNOWN); - scar_val_src2->set_value(if_statement->get_labels().first->get_value()); - scar_instruction2->set_src1(std::move(scar_val_src2)); - scar_function->add_instruction(std::move(scar_instruction2)); - } break; - case ast::statementType::IFELSE: { - // - // c = - // JumpIfZero(c, else_label) - // - // Jump(end) - // Label(else_label) - // - // Label(end) - - auto if_else_statement = - std::static_pointer_cast(statement); - gen_scar_exp(if_else_statement->get_exps(), scar_function); - - // Jump if zero to else statement - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(std::move(scar_val_src)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::UNKNOWN); - scar_val_dst->set_value(if_else_statement->get_labels().first->get_value()); - scar_instruction->set_dst(std::move(scar_val_dst)); - scar_function->add_instruction(std::move(scar_instruction)); - - // generate scar for the if statement - gen_scar_statement(if_else_statement->get_stmt1(), scar_function); - - // jump to the end - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - scar_val_src2->set_type(scar::val_type::UNKNOWN); - scar_val_src2->set_value( - if_else_statement->get_labels().second->get_value()); - scar_instruction2->set_src1(std::move(scar_val_src2)); - scar_function->add_instruction(std::move(scar_instruction2)); - - // generate the else label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value( - if_else_statement->get_labels().first->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(std::move(scar_instruction3)); - - // generate scar for the else statement - gen_scar_statement(if_else_statement->get_stmt2(), scar_function); - - // generate the end label - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - scar_instruction4->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value( - if_else_statement->get_labels().second->get_value()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(std::move(scar_instruction4)); - } break; - - case ast::statementType::GOTO: - case ast::statementType::BREAK: - case ast::statementType::CONTINUE: { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(statement->get_labels().first->get_value()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - } break; - - case ast::statementType::LABEL: { - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(statement->get_labels().first->get_value()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - } break; - - case ast::statementType::BLOCK: { - auto block_statement = - std::static_pointer_cast(statement); - gen_scar_block(block_statement->get_block(), scar_function); - } break; - - case ast::statementType::WHILE: { - auto while_statement = - std::static_pointer_cast(statement); - - // Label(start) - // - // c = - // JumpIfZero(c, end) - // - // Jump(start) - // Label(end) - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(while_statement->get_labels().first->get_value()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - - gen_scar_exp(while_statement->get_exps(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(while_statement->get_labels().second->get_value()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(scar_instruction2); - - gen_scar_statement(while_statement->get_stmt(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value(while_statement->get_labels().first->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(scar_instruction3); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - scar_instruction4->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(while_statement->get_labels().second->get_value()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(scar_instruction4); - } break; - - case ast::statementType::DO_WHILE: { - auto do_while_statement = - std::static_pointer_cast(statement); - - // Label(start) - // - // Label(continue) - // - // c = - // JumpIfNotZero(c, start) - // Label(end) - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(do_while_statement->get_start_label()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - - gen_scar_statement(do_while_statement->get_stmt(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction1); - scar_instruction1->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); - scar_val_src1->set_type(scar::val_type::UNKNOWN); - scar_val_src1->set_value( - do_while_statement->get_labels().first->get_value()); - scar_instruction1->set_src1(std::move(scar_val_src1)); - scar_function->add_instruction(scar_instruction1); - - gen_scar_exp(do_while_statement->get_exps(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(do_while_statement->get_start_label()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(scar_instruction2); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value( - do_while_statement->get_labels().second->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(scar_instruction3); - } break; - - case ast::statementType::FOR: { - auto for_statement = - std::static_pointer_cast(statement); - - // - // Label(Forstart) - // - // c = - // JumpIfZero(c, end) - // - // Label(continue) - // - // Jump(Forstart) - // Label(end) - - if (for_statement->get_for_init() != nullptr) { - if (for_statement->get_for_init()->get_declaration() != nullptr) { - gen_scar_declaration(for_statement->get_for_init()->get_declaration(), - scar_function); - } else { - gen_scar_exp(for_statement->get_for_init()->get_exp(), scar_function); - } - } - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::UNKNOWN); - scar_val_src->set_value(for_statement->get_start_label()); - scar_instruction->set_src1(std::move(scar_val_src)); - scar_function->add_instruction(scar_instruction); - - gen_scar_exp(for_statement->get_exps(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); - scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); - SETVARCONSTANTREG(scar_val_src2); - scar_instruction2->set_src1(std::move(scar_val_src2)); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); - scar_val_dst2->set_type(scar::val_type::UNKNOWN); - scar_val_dst2->set_value(for_statement->get_labels().second->get_value()); - scar_instruction2->set_dst(std::move(scar_val_dst2)); - scar_function->add_instruction(scar_instruction2); - - gen_scar_statement(for_statement->get_stmt(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); - scar_instruction3->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); - scar_val_src3->set_type(scar::val_type::UNKNOWN); - scar_val_src3->set_value(for_statement->get_labels().first->get_value()); - scar_instruction3->set_src1(std::move(scar_val_src3)); - scar_function->add_instruction(scar_instruction3); - - gen_scar_exp(for_statement->get_exp2(), scar_function); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); - scar_instruction4->set_type(scar::instruction_type::JUMP); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); - scar_val_src4->set_type(scar::val_type::UNKNOWN); - scar_val_src4->set_value(for_statement->get_start_label()); - scar_instruction4->set_src1(std::move(scar_val_src4)); - scar_function->add_instruction(scar_instruction4); - - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); - scar_instruction5->set_type(scar::instruction_type::LABEL); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); - scar_val_src5->set_type(scar::val_type::UNKNOWN); - scar_val_src5->set_value(for_statement->get_labels().second->get_value()); - scar_instruction5->set_src1(std::move(scar_val_src5)); - scar_function->add_instruction(scar_instruction5); - } break; - case ast::statementType::UNKNOWN: - UNREACHABLE() - } -} -void Codegen::gen_scar_declaration( - std::shared_ptr declaration, - std::shared_ptr scar_function) { - // if there is no definition, we ignore it - if (declaration->get_exp() != nullptr) { - gen_scar_exp(declaration->get_exp(), scar_function); - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::COPY); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - SETVARCONSTANTREG(scar_val_src); - scar_instruction->set_src1(scar_val_src); - MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); - scar_val_dst->set_type(scar::val_type::VAR); - scar_val_dst->set_reg_name(declaration->get_identifier()->get_value()); - scar_instruction->set_dst(scar_val_dst); - scar_function->add_instruction(scar_instruction); - } -} - -void Codegen::gen_scar_block( - std::shared_ptr block, - std::shared_ptr scar_function) { - for (auto inst : block->get_blockItems()) { - switch (inst->get_type()) { - case ast::BlockItemType::STATEMENT: - gen_scar_statement(inst->get_statement(), scar_function); - break; - case ast::BlockItemType::DECLARATION: - gen_scar_declaration(inst->get_declaration(), scar_function); - break; - case ast::BlockItemType::UNKNOWN: - UNREACHABLE() - } - } -} - -void Codegen::gen_scar() { - scar::scar_Program_Node scar_program; - for (auto it : program.get_functions()) { - MAKE_SHARED(scar::scar_Function_Node, scar_function); - MAKE_SHARED(scar::scar_Identifier_Node, identifier); - identifier->set_value(it->get_identifier()->get_value()); - scar_function->set_identifier(identifier); - - gen_scar_block(it->get_block(), scar_function); - - // Add a complementary return 0 at the end of the function - // in case there is no return statement - MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); - scar_instruction->set_type(scar::instruction_type::RETURN); - MAKE_SHARED(scar::scar_Val_Node, scar_val_src); - scar_val_src->set_type(scar::val_type::CONSTANT); - scar_val_src->set_value("0"); - scar_instruction->set_src1(scar_val_src); - scar_function->add_instruction(scar_instruction); - - scar_program.add_function(scar_function); - } - - this->scar = scar_program; -} - -void Codegen::pretty_print() { - std::cout << "Program(" << std::endl; - for (auto function : scar.get_functions()) { - std::cout << "\tFunction(" << std::endl; - std::cout << "\t\tname=\"" << function->get_identifier()->get_value() - << "\"," << std::endl; - std::cout << "\t\tbody=[" << std::endl; - for (auto statement : function->get_instructions()) { - std::cout << "\t\t\t" << to_string(statement->get_type()) << "("; - if (statement->get_type() == scar::instruction_type::RETURN) { - if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::UNARY) { - std::cout << unop::to_string(statement->get_unop()) << ", "; - if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } - std::cout << ", "; - if (statement->get_dst()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; - } else if (statement->get_dst()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::BINARY) { - std::cout << binop::to_string(statement->get_binop()) << ", "; - if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } else if (statement->get_src1()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } - std::cout << ", "; - if (statement->get_src2()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src2()->get_reg() << ")"; - } else if (statement->get_src2()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src2()->get_value() << ")"; - } - std::cout << ", "; - if (statement->get_dst()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; - } else if (statement->get_dst()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::COPY) { - if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } else if (statement->get_src1()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } - std::cout << " ,"; - if (statement->get_dst()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; - } - std::cout << ")" << std::endl; - } else if (statement->get_type() == scar::instruction_type::JUMP or - statement->get_type() == scar::instruction_type::LABEL) { - std::cout << statement->get_src1()->get_value() << ")" << std::endl; - } else if (statement->get_type() == - scar::instruction_type::JUMP_IF_ZERO or - statement->get_type() == - scar::instruction_type::JUMP_IF_NOT_ZERO) { - if (statement->get_src1()->get_type() == scar::val_type::VAR) { - std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; - } else if (statement->get_src1()->get_type() == - scar::val_type::CONSTANT) { - std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; - } - std::cout << ", "; - std::cout << statement->get_dst()->get_value() << ")" << std::endl; - } - } - std::cout << "\t\t]" << std::endl; - std::cout << "\t)," << std::endl; - } - std::cout << ")" << std::endl; -} - -#define SET_MOV_SOURCE() \ - switch (inst->get_src1()->get_type()) { \ - case scar::val_type::VAR: \ - scasm_src->set_type(scasm::operand_type::PSEUDO); \ - scasm_src->set_identifier_stack(inst->get_src1()->get_reg()); \ - break; \ - case scar::val_type::CONSTANT: \ - scasm_src->set_type(scasm::operand_type::IMM); \ - scasm_src->set_imm(stoi(inst->get_src1()->get_value())); \ - break; \ - default: \ - break; \ - } \ - scasm_inst->set_src(std::move(scasm_src)) - -#define SET_DST(dst) \ - switch (inst->get_dst()->get_type()) { \ - case scar::val_type::VAR: \ - dst->set_type(scasm::operand_type::PSEUDO); \ - dst->set_identifier_stack(inst->get_dst()->get_reg()); \ - break; \ - default: \ - break; \ - } - -void Codegen::gen_scasm() { - scasm::scasm_program scasm_program{}; - for (auto func : scar.get_functions()) { - MAKE_SHARED(scasm::scasm_function, scasm_func); - scasm_func->set_name(func->get_identifier()->get_value()); - for (auto inst : func->get_instructions()) { - if (inst->get_type() == scar::instruction_type::RETURN) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - scasm_dst->set_type(scasm::operand_type::REG); - scasm_dst->set_reg(scasm::register_type::AX); - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::RET); - scasm_func->add_instruction(std::move(scasm_inst2)); - - } else if (inst->get_type() == scar::instruction_type::UNARY) { - if (inst->get_unop() == unop::UNOP::NOT) { - // Cmp(Imm(0), src) - // Mov(Imm(0), dst) - // SetCC(E, dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::CMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::IMM); - scasm_src->set_imm(0); - scasm_inst->set_src(std::move(scasm_src)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - switch (inst->get_src1()->get_type()) { - case scar::val_type::VAR: - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_dst->set_type(scasm::operand_type::IMM); - scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); - break; - default: - break; - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(0); - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - SET_DST(scasm_dst2); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::SETCC); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::COND); - scasm_src3->set_cond(scasm::cond_code::E); - scasm_inst3->set_src(std::move(scasm_src3)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst3); - switch (inst->get_dst()->get_type()) { - case scar::val_type::VAR: - scasm_dst3->set_type(scasm::operand_type::PSEUDO); - scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); - break; - default: - break; - } - scasm_inst3->set_dst(std::move(scasm_dst3)); - scasm_func->add_instruction(std::move(scasm_inst3)); - } else { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst->set_dst(std::move(scasm_dst)); - - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::UNARY); - scasm_inst2->set_unop(inst->get_unop()); - - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst2->set_type(scasm::operand_type::PSEUDO); - scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst2->set_dst(std::move(scasm_dst2)); - - scasm_func->add_instruction(std::move(scasm_inst2)); - } - } else if (inst->get_type() == scar::instruction_type::BINARY) { - if (binop::is_relational(inst->get_binop())) { - // Cmp(src2, src1) - // Mov(Imm(0), dst) - // SetCC(conditional, dst) - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::CMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - switch (inst->get_src2()->get_type()) { - case scar::val_type::VAR: - scasm_src->set_type(scasm::operand_type::PSEUDO); - scasm_src->set_identifier_stack(inst->get_src2()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_src->set_type(scasm::operand_type::IMM); - scasm_src->set_imm(stoi(inst->get_src2()->get_value())); - break; - default: - break; - } - scasm_inst->set_src(std::move(scasm_src)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - switch (inst->get_src1()->get_type()) { - case scar::val_type::VAR: - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_dst->set_type(scasm::operand_type::IMM); - scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); - break; - default: - break; - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(0); - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - SET_DST(scasm_dst2); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::SETCC); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::COND); - switch (inst->get_binop()) { - case binop::BINOP::EQUAL: - scasm_src3->set_cond(scasm::cond_code::E); - break; - case binop::BINOP::NOTEQUAL: - scasm_src3->set_cond(scasm::cond_code::NE); - break; - case binop::BINOP::LESSTHAN: - scasm_src3->set_cond(scasm::cond_code::L); - break; - case binop::BINOP::LESSTHANEQUAL: - scasm_src3->set_cond(scasm::cond_code::LE); - break; - case binop::BINOP::GREATERTHAN: - scasm_src3->set_cond(scasm::cond_code::G); - break; - case binop::BINOP::GREATERTHANEQUAL: - scasm_src3->set_cond(scasm::cond_code::GE); - break; - default: - break; - } - scasm_inst3->set_src(std::move(scasm_src3)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst3); - SET_DST(scasm_dst3); - scasm_inst3->set_dst(std::move(scasm_dst3)); - scasm_func->add_instruction(std::move(scasm_inst3)); - } else if (inst->get_binop() == binop::BINOP::DIV or - inst->get_binop() == binop::BINOP::MOD) { - // Mov(src1, Reg(AX)) - // Cdq - // Idiv(src2) - // Mov(Reg(AX), dst) | Mov(Reg(DX), dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - scasm_dst->set_type(scasm::operand_type::REG); - scasm_dst->set_reg(scasm::register_type::AX); - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::CDQ); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::IDIV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - if (inst->get_src2()->get_type() == scar::val_type::VAR) { - scasm_src2->set_type(scasm::operand_type::PSEUDO); - scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); - } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); - } - scasm_inst3->set_src(std::move(scasm_src2)); - scasm_func->add_instruction(std::move(scasm_inst3)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst4); - scasm_inst4->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - SET_DST(scasm_dst2); - scasm_inst4->set_dst(std::move(scasm_dst2)); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::REG); - if (inst->get_binop() == binop::BINOP::DIV) { - scasm_src3->set_reg(scasm::register_type::AX); - } else { - scasm_src3->set_reg(scasm::register_type::DX); - } - scasm_inst4->set_src(std::move(scasm_src3)); - scasm_func->add_instruction(std::move(scasm_inst4)); - } else if (inst->get_binop() == binop::BINOP::LEFT_SHIFT or - inst->get_binop() == binop::BINOP::RIGHT_SHIFT) { - // Mov(src1,dst) - // Mov(src2, Reg(CX)) - // Binary(binary operand, CL, dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); - } else if (inst->get_src2()->get_type() == scar::val_type::VAR) { - scasm_src2->set_type(scasm::operand_type::PSEUDO); - scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); - } - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - scasm_dst2->set_type(scasm::operand_type::REG); - scasm_dst2->set_reg(scasm::register_type::CX); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); - scasm_inst3->set_type(scasm::instruction_type::BINARY); - scasm_inst3->set_binop( - scasm::scar_binop_to_scasm_binop(inst->get_binop())); - MAKE_SHARED(scasm::scasm_operand, scasm_src3); - scasm_src3->set_type(scasm::operand_type::REG); - scasm_src3->set_reg(scasm::register_type::CL); - scasm_inst3->set_src(std::move(scasm_src3)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst3); - scasm_dst3->set_type(scasm::operand_type::PSEUDO); - scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); - scasm_inst3->set_dst(std::move(scasm_dst3)); - scasm_func->add_instruction(std::move(scasm_inst3)); - - } else { - // Mov(src1, dst) - // Binary(binary_operator, src2, dst) - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::BINARY); - scasm_inst2->set_binop( - scasm::scar_binop_to_scasm_binop(inst->get_binop())); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - if (inst->get_src2()->get_type() == scar::val_type::VAR) { - scasm_src2->set_type(scasm::operand_type::PSEUDO); - scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); - } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { - scasm_src2->set_type(scasm::operand_type::IMM); - scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); - } - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - if (inst->get_dst()->get_type() == scar::val_type::VAR) { - scasm_dst2->set_type(scasm::operand_type::PSEUDO); - scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); - } - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - } - } else if (inst->get_type() == scar::instruction_type::COPY) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - SET_MOV_SOURCE(); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - SET_DST(scasm_dst); - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - } else if (inst->get_type() == scar::instruction_type::LABEL) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::LABEL); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::LABEL); - scasm_src->set_identifier_stack(inst->get_src1()->get_value()); - scasm_inst->set_src(std::move(scasm_src)); - scasm_func->add_instruction(std::move(scasm_inst)); - } else if (inst->get_type() == scar::instruction_type::JUMP) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::JMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::LABEL); - scasm_src->set_identifier_stack(inst->get_src1()->get_value()); - scasm_inst->set_src(std::move(scasm_src)); - scasm_func->add_instruction(std::move(scasm_inst)); - } else if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO or - inst->get_type() == scar::instruction_type::JUMP_IF_NOT_ZERO) { - // Cmp(Imm(0), condition) - // JmpCC(E, label) | JmpCC(NE, label) - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::CMP); - MAKE_SHARED(scasm::scasm_operand, scasm_src); - scasm_src->set_type(scasm::operand_type::IMM); - scasm_src->set_imm(0); - scasm_inst->set_src(std::move(scasm_src)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst); - switch (inst->get_src1()->get_type()) { - case scar::val_type::VAR: - scasm_dst->set_type(scasm::operand_type::PSEUDO); - scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); - break; - case scar::val_type::CONSTANT: - scasm_dst->set_type(scasm::operand_type::IMM); - scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); - break; - default: - break; - } - scasm_inst->set_dst(std::move(scasm_dst)); - scasm_func->add_instruction(std::move(scasm_inst)); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::JMPCC); - MAKE_SHARED(scasm::scasm_operand, scasm_src2); - scasm_src2->set_type(scasm::operand_type::COND); - if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO) { - scasm_src2->set_cond(scasm::cond_code::E); - } else { - scasm_src2->set_cond(scasm::cond_code::NE); - } - scasm_inst2->set_src(std::move(scasm_src2)); - MAKE_SHARED(scasm::scasm_operand, scasm_dst2); - scasm_dst2->set_type(scasm::operand_type::LABEL); - scasm_dst2->set_identifier_stack(inst->get_dst()->get_value()); - scasm_inst2->set_dst(std::move(scasm_dst2)); - scasm_func->add_instruction(std::move(scasm_inst2)); - } - } - scasm_program.add_function(std::move(scasm_func)); - } - - this->scasm = scasm_program; -} - -#define FIX_PSEUDO(target) \ - if (NOTNULL(inst->get_##target()) && \ - inst->get_##target()->get_type() == scasm::operand_type::PSEUDO) { \ - if (pseduo_registers.find(inst->get_##target()->get_identifier_stack()) != \ - pseduo_registers.end()) { \ - inst->get_##target()->set_identifier_stack( \ - pseduo_registers[inst->get_##target()->get_identifier_stack()]); \ - } else { \ - std::string temp = inst->get_##target()->get_identifier_stack(); \ - inst->get_##target()->set_identifier_stack( \ - "-" + std::to_string(offset * 4) + "(%rbp)"); \ - pseduo_registers[temp] = inst->get_##target()->get_identifier_stack(); \ - offset++; \ - } \ - inst->get_##target()->set_type(scasm::operand_type::STACK); \ - } - -void Codegen::fix_pseudo_registers() { - int offset = 1; - for (auto &funcs : scasm.get_functions()) { - for (auto &inst : funcs->get_instructions()) { - FIX_PSEUDO(src); - FIX_PSEUDO(dst); - } - } - stack_offset = 4 * (offset - 1); -} - -void Codegen::fix_instructions() { - MAKE_SHARED(scasm::scasm_instruction, scasm_stack_instr); - scasm_stack_instr->set_type(scasm::instruction_type::ALLOCATE_STACK); - MAKE_SHARED(scasm::scasm_operand, val); - val->set_type(scasm::operand_type::IMM); - val->set_imm(stack_offset); - scasm_stack_instr->set_src(std::move(val)); - - scasm.get_functions()[0]->get_instructions().insert( - scasm.get_functions()[0]->get_instructions().begin(), - std::move(scasm_stack_instr)); - - for (auto &funcs : scasm.get_functions()) { - for (auto it = funcs->get_instructions().begin(); - it != funcs->get_instructions().end(); it++) { - if (NOTNULL((*it)->get_src()) && NOTNULL((*it)->get_dst()) && - (*it)->get_src()->get_type() == scasm::operand_type::STACK && - (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_src()); - - // fixing up stack to stack move - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R10); - scasm_inst->set_dst(dst); - - (*it)->set_src(std::move(dst)); - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - } - } - } - - // case when DIV uses a constant as an operand - // case when MUL have dst as a stack value - for (auto &funcs : scasm.get_functions()) { - for (auto it = funcs->get_instructions().begin(); - it != funcs->get_instructions().end(); it++) { - - if ((*it)->get_type() == scasm::instruction_type::CMP and - (*it)->get_dst()->get_type() == scasm::operand_type::IMM) { - // cmpl stack/reg, $5 - // | - // v - // movl $5, %r11d - // cmpl stack/reg, %r11d - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_dst()); - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R11); - scasm_inst->set_dst(dst); - (*it)->set_dst(std::move(dst)); - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - } - if ((*it)->get_type() == scasm::instruction_type::IDIV and - (*it)->get_src()->get_type() == scasm::operand_type::IMM) { - // idivl $3 - // | - // v - // movl $3, %r10d - // idivl %r10d - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_src()); - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R10); - scasm_inst->set_dst(dst); - (*it)->set_src(std::move(dst)); - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - } else if ((*it)->get_type() == scasm::instruction_type::BINARY and - (*it)->get_binop() == scasm::Binop::MUL and - (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { - // imull $3, STACK - // | - // v - // movl STACK, %r11d - // imull $3, %r11d - // movl %r11d, STACK - - MAKE_SHARED(scasm::scasm_operand, dst); - dst->set_type(scasm::operand_type::REG); - dst->set_reg(scasm::register_type::R11); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst); - scasm_inst->set_type(scasm::instruction_type::MOV); - scasm_inst->set_src((*it)->get_dst()); - scasm_inst->set_dst(dst); - - MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); - scasm_inst2->set_type(scasm::instruction_type::MOV); - scasm_inst2->set_src(dst); - scasm_inst2->set_dst((*it)->get_dst()); - - (*it)->set_dst(std::move(dst)); - - it = funcs->get_instructions().insert(it, std::move(scasm_inst)); - it++; - it = funcs->get_instructions().insert(it + 1, std::move(scasm_inst2)); - } - } - } -} - #define CODEGEN_SRC_DST() \ if (instr->get_src()->get_type() == scasm::operand_type::IMM) { \ assembly << "$" << instr->get_src()->get_imm(); \ diff --git a/codegen/codegen.hh b/codegen/codegen.hh index 9444c4a..f74c97d 100644 --- a/codegen/codegen.hh +++ b/codegen/codegen.hh @@ -36,6 +36,11 @@ namespace scarlet { namespace codegen { #define NOTNULL(x) x != nullptr +#define UNREACHABLE() \ + std::cout << "Unreachable code reached in " << __FILE__ << " at line " \ + << __LINE__ << std::endl; \ + __builtin_unreachable(); +#define MAKE_SHARED(a, b) std::shared_ptr b = std::make_shared() class Codegen { private: diff --git a/codegen/common.hh b/codegen/common.hh new file mode 100644 index 0000000..3e35f9a --- /dev/null +++ b/codegen/common.hh @@ -0,0 +1,23 @@ +#pragma once + +#include "codegen.hh" + +namespace scarlet { +namespace codegen { + +#define SETVARCONSTANTREG(src) \ + if (!variable_buffer.empty()) { \ + src->set_type(scar::val_type::VAR); \ + src->set_reg_name(variable_buffer); \ + variable_buffer.clear(); \ + } else if (!constant_buffer.empty()) { \ + src->set_type(scar::val_type::CONSTANT); \ + src->set_value(constant_buffer); \ + constant_buffer.clear(); \ + } else { \ + src->set_type(scar::val_type::VAR); \ + src->set_reg_name(get_prev_reg_name()); \ + } + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/pretty_print.cc b/codegen/scargen/pretty_print.cc new file mode 100644 index 0000000..6e66b0c --- /dev/null +++ b/codegen/scargen/pretty_print.cc @@ -0,0 +1,96 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::pretty_print() { + std::cout << "Program(" << std::endl; + for (auto function : scar.get_functions()) { + std::cout << "\tFunction(" << std::endl; + std::cout << "\t\tname=\"" << function->get_identifier()->get_value() + << "\"," << std::endl; + std::cout << "\t\tbody=[" << std::endl; + for (auto statement : function->get_instructions()) { + std::cout << "\t\t\t" << to_string(statement->get_type()) << "("; + if (statement->get_type() == scar::instruction_type::RETURN) { + if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::UNARY) { + std::cout << unop::to_string(statement->get_unop()) << ", "; + if (statement->get_src1()->get_type() == scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } else if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } + std::cout << ", "; + if (statement->get_dst()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; + } else if (statement->get_dst()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::BINARY) { + std::cout << binop::to_string(statement->get_binop()) << ", "; + if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } else if (statement->get_src1()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } + std::cout << ", "; + if (statement->get_src2()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src2()->get_reg() << ")"; + } else if (statement->get_src2()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src2()->get_value() << ")"; + } + std::cout << ", "; + if (statement->get_dst()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; + } else if (statement->get_dst()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_dst()->get_value() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::COPY) { + if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } else if (statement->get_src1()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } + std::cout << " ,"; + if (statement->get_dst()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_dst()->get_reg() << ")"; + } + std::cout << ")" << std::endl; + } else if (statement->get_type() == scar::instruction_type::JUMP or + statement->get_type() == scar::instruction_type::LABEL) { + std::cout << statement->get_src1()->get_value() << ")" << std::endl; + } else if (statement->get_type() == + scar::instruction_type::JUMP_IF_ZERO or + statement->get_type() == + scar::instruction_type::JUMP_IF_NOT_ZERO) { + if (statement->get_src1()->get_type() == scar::val_type::VAR) { + std::cout << "Var(" << statement->get_src1()->get_reg() << ")"; + } else if (statement->get_src1()->get_type() == + scar::val_type::CONSTANT) { + std::cout << "Constant(" << statement->get_src1()->get_value() << ")"; + } + std::cout << ", "; + std::cout << statement->get_dst()->get_value() << ")" << std::endl; + } + } + std::cout << "\t\t]" << std::endl; + std::cout << "\t)," << std::endl; + } + std::cout << ")" << std::endl; +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar.cc b/codegen/scargen/scar.cc new file mode 100644 index 0000000..8d785b2 --- /dev/null +++ b/codegen/scargen/scar.cc @@ -0,0 +1,33 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar() { + scar::scar_Program_Node scar_program; + for (auto it : program.get_functions()) { + MAKE_SHARED(scar::scar_Function_Node, scar_function); + MAKE_SHARED(scar::scar_Identifier_Node, identifier); + identifier->set_value(it->get_identifier()->get_value()); + scar_function->set_identifier(identifier); + + gen_scar_block(it->get_block(), scar_function); + + // Add a complementary return 0 at the end of the function + // in case there is no return statement + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::RETURN); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::CONSTANT); + scar_val_src->set_value("0"); + scar_instruction->set_src1(scar_val_src); + scar_function->add_instruction(scar_instruction); + + scar_program.add_function(scar_function); + } + + this->scar = scar_program; +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_block.cc b/codegen/scargen/scar_block.cc new file mode 100644 index 0000000..2576be5 --- /dev/null +++ b/codegen/scargen/scar_block.cc @@ -0,0 +1,24 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_block( + std::shared_ptr block, + std::shared_ptr scar_function) { + for (auto inst : block->get_blockItems()) { + switch (inst->get_type()) { + case ast::BlockItemType::STATEMENT: + gen_scar_statement(inst->get_statement(), scar_function); + break; + case ast::BlockItemType::DECLARATION: + gen_scar_declaration(inst->get_declaration(), scar_function); + break; + case ast::BlockItemType::UNKNOWN: + UNREACHABLE() + } + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_declaration.cc b/codegen/scargen/scar_declaration.cc new file mode 100644 index 0000000..7ed5d50 --- /dev/null +++ b/codegen/scargen/scar_declaration.cc @@ -0,0 +1,26 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_declaration( + std::shared_ptr declaration, + std::shared_ptr scar_function) { + // if there is no definition, we ignore it + if (declaration->get_exp() != nullptr) { + gen_scar_exp(declaration->get_exp(), scar_function); + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::COPY); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name(declaration->get_identifier()->get_value()); + scar_instruction->set_dst(scar_val_dst); + scar_function->add_instruction(scar_instruction); + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_expression.cc b/codegen/scargen/scar_expression.cc new file mode 100644 index 0000000..c1a8b88 --- /dev/null +++ b/codegen/scargen/scar_expression.cc @@ -0,0 +1,279 @@ +#include + +namespace scarlet { +namespace codegen { + +#define SETUPLANDLOR(num) \ + if (exp->get_binop_node()->get_op() == binop::BINOP::LAND) { \ + /* Logical and */ \ + scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_ZERO); \ + } else { \ + /* Logical or */ \ + scar_instruction##num->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); \ + } \ + \ + if (exp->get_left() == nullptr) { \ + if (num == 1) \ + gen_scar_factor(exp->get_factor_node(), scar_function); \ + SETVARCONSTANTREG(scar_val_src##num); \ + } else { \ + scar_val_src##num->set_type(scar::val_type::VAR); \ + scar_val_src##num->set_reg_name(get_prev_reg_name()); \ + } \ + \ + scar_instruction##num->set_src1(std::move(scar_val_src##num)); \ + scar_val_dst##num->set_type(scar::val_type::UNKNOWN); + +void Codegen::gen_scar_exp( + std::shared_ptr exp, + std::shared_ptr scar_function) { + if (exp == nullptr) + return; + gen_scar_exp(exp->get_left(), scar_function); + if (exp->get_binop_node() != nullptr and + exp->get_binop_node()->get_op() != binop::BINOP::UNKNOWN) { + // when we have a binary operator + // deal with && and || separately using jmpif(not)zero, labels and copy + // operations since we need to apply short circuit for them + // + // There will be a separate case for the assignment operator as that + // will be represented by a simple copy operation + // + // There will be a separate case for the ternary operator as well + // So first we need to check whether it is the first expression + // or the second expression that will be returned using jmpifzero + // and copy the result to a new register. Ternary is actually a special + // case of short circuiting + if (exp->get_binop_node()->get_op() == binop::BINOP::ASSIGN) { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::COPY); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + // the semantic analyis phase should have ensured that the left child + // is null, factor is an identifier with no unops and the right child + // is an expression + gen_scar_exp(exp->get_right(), scar_function); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(std::move(scar_val_src)); + + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name( + exp->get_factor_node()->get_identifier_node()->get_value()); + // NOTE: we update the current scar register name to use the variable + // since we can have expressions like: + // int b = a = 5; + reg_name = scar_val_dst->get_reg(); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_function->add_instruction(std::move(scar_instruction)); + return; + } + bool short_circuit = binop::short_circuit(exp->get_binop_node()->get_op()); + binop::BINOP sc_binop = exp->get_binop_node()->get_op(); + const binop::BINOP compound_binop = sc_binop; + if (binop::is_compound(compound_binop)) { + sc_binop = compound_to_base[compound_binop]; + } + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + if (short_circuit) { + if (sc_binop == binop::BINOP::LAND) { + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + } else if (sc_binop == binop::BINOP::LOR) { + scar_instruction->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); + } else if (sc_binop == binop::BINOP::TERNARY) { + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + } + } else { + scar_instruction->set_type(scar::instruction_type::BINARY); + scar_instruction->set_binop(sc_binop); + } + MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + + if (exp->get_left() == nullptr) { + gen_scar_factor(exp->get_factor_node(), scar_function); + SETVARCONSTANTREG(scar_val_src1); + } else { + scar_val_src1->set_type(scar::val_type::VAR); + scar_val_src1->set_reg_name(get_prev_reg_name()); + } + + scar_instruction->set_src1(std::move(scar_val_src1)); + + if (short_circuit) { + // create a label to jump to + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst1); + scar_val_dst1->set_type(scar::val_type::UNKNOWN); + scar_val_dst1->set_value(get_fr_label_name()); + scar_instruction->set_dst(std::move(scar_val_dst1)); + scar_function->add_instruction(std::move(scar_instruction)); + } + + // TERNARY SPECIAL CASE + if (sc_binop == binop::BINOP::TERNARY) { + // generate the first expression + gen_scar_exp(exp->get_middle(), scar_function); + + // copy this result in a new register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_instruction2->set_type(scar::instruction_type::COPY); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + scar_val_dst2->set_type(scar::val_type::VAR); + // Doing this so that we can use the same scar register to + // store the result of the second expression as well. + // We cannot simply use get_prev_reg_name() since we need to + // parse the second expression first and that will change the + // register counter + std::string result = get_reg_name(); + scar_val_dst2->set_reg_name(result); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(std::move(scar_instruction2)); + + // jump to the end + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_instruction3->set_type(scar::instruction_type::JUMP); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value(get_res_label_name()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(std::move(scar_instruction3)); + + // generate the intermediate label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_instruction4->set_type(scar::instruction_type::LABEL); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(get_last_fr_label_name(true)); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(std::move(scar_instruction4)); + + // generate the second expression + gen_scar_exp(exp->get_right(), scar_function); + + // copy this result in a new register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst5); + scar_instruction5->set_type(scar::instruction_type::COPY); + SETVARCONSTANTREG(scar_val_src5); + scar_instruction5->set_src1(std::move(scar_val_src5)); + scar_val_dst5->set_type(scar::val_type::VAR); + scar_val_dst5->set_reg_name(result); + scar_instruction5->set_dst(std::move(scar_val_dst5)); + scar_function->add_instruction(std::move(scar_instruction5)); + + // generate the final label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); + scar_instruction6->set_type(scar::instruction_type::LABEL); + scar_val_src6->set_type(scar::val_type::UNKNOWN); + scar_val_src6->set_value(get_last_res_label_name()); + scar_instruction6->set_src1(std::move(scar_val_src6)); + scar_function->add_instruction(std::move(scar_instruction6)); + + // early return + return; + } + gen_scar_exp(exp->get_right(), scar_function); + SETVARCONSTANTREG(scar_val_src2); + + if (short_circuit) { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + if (sc_binop == binop::BINOP::LAND) { + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); + } else { + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); + } + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(get_last_fr_label_name()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(std::move(scar_instruction2)); + + // now copy 1(LAND) / 0(LOR) into a scar register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst3); + scar_instruction3->set_type(scar::instruction_type::COPY); + scar_val_src3->set_type(scar::val_type::CONSTANT); + if (sc_binop == binop::BINOP::LAND) { + scar_val_src3->set_value(std::to_string(1)); + } else { + scar_val_src3->set_value(std::to_string(0)); + } + scar_val_dst3->set_type(scar::val_type::VAR); + scar_val_dst3->set_reg_name(get_reg_name()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_instruction3->set_dst(std::move(scar_val_dst3)); + scar_function->add_instruction(std::move(scar_instruction3)); + + // now jump to the end + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_instruction4->set_type(scar::instruction_type::JUMP); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(get_res_label_name()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(std::move(scar_instruction4)); + + // Now generate the intermediate label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); + scar_instruction5->set_type(scar::instruction_type::LABEL); + scar_val_src5->set_type(scar::val_type::UNKNOWN); + scar_val_src5->set_value(get_last_fr_label_name(true)); + scar_instruction5->set_src1(std::move(scar_val_src5)); + scar_function->add_instruction(std::move(scar_instruction5)); + + // now copy 0(LAND) / 1(LOR) into a scar register + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction6); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src6); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst6); + scar_instruction6->set_type(scar::instruction_type::COPY); + scar_val_src6->set_type(scar::val_type::CONSTANT); + if (sc_binop == binop::BINOP::LAND) { + scar_val_src6->set_value(std::to_string(0)); + } else { + scar_val_src6->set_value(std::to_string(1)); + } + scar_val_dst6->set_type(scar::val_type::VAR); + scar_val_dst6->set_reg_name(get_prev_reg_name()); + scar_instruction6->set_src1(std::move(scar_val_src6)); + scar_instruction6->set_dst(std::move(scar_val_dst6)); + scar_function->add_instruction(std::move(scar_instruction6)); + + // now generate the final label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction7); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src7); + scar_instruction7->set_type(scar::instruction_type::LABEL); + scar_val_src7->set_type(scar::val_type::UNKNOWN); + scar_val_src7->set_value(get_last_res_label_name()); + scar_instruction7->set_src1(std::move(scar_val_src7)); + scar_function->add_instruction(std::move(scar_instruction7)); + } else { + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::VAR); + if (binop::is_compound(compound_binop)) { + scar_val_dst->set_reg_name( + exp->get_factor_node()->get_identifier_node()->get_value()); + reg_name = scar_val_dst->get_reg(); + } else { + scar_val_dst->set_reg_name(get_reg_name()); + } + scar_instruction->set_src2(std::move(scar_val_src2)); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_function->add_instruction(std::move(scar_instruction)); + } + } else { + // When we do not have a binary operator, so only parse the factor node + gen_scar_factor(exp->get_factor_node(), scar_function); + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_factor.cc b/codegen/scargen/scar_factor.cc new file mode 100644 index 0000000..f7871ef --- /dev/null +++ b/codegen/scargen/scar_factor.cc @@ -0,0 +1,181 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_factor( + std::shared_ptr factor, + std::shared_ptr scar_function) { + // firstly put all the unops (if they exist) in the unop buffer + for (auto it : factor->get_unop_nodes()) { + unop_buffer[curr_buff].emplace_back(it->get_op()); + } + // if exp exists, parse that. If exp is null, it will simply return + if (factor->get_exp_node() != nullptr) { + curr_buff++; + if (curr_buff >= (int)unop_buffer.size()) + unop_buffer.resize(curr_buff + 1); + gen_scar_exp(factor->get_exp_node(), scar_function); + curr_buff--; + } + // If we have an integer node and unops to operate on, proceed... + if (!unop_buffer[curr_buff].empty()) { + int num_unpos = unop_buffer[curr_buff].size(); + for (int i = num_unpos - 1; i >= 0; i--) { + // SPECIAL CASE WHEN WE HAVE INCREMENT OR DECREMENT OPERATOR + unop::UNOP op = unop_buffer[curr_buff][i]; + if (op == unop::UNOP::PREINCREMENT or op == unop::UNOP::PREDECREMENT) { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::BINARY); + if (op == unop::UNOP::PREINCREMENT) { + scar_instruction->set_binop(binop::BINOP::ADD); + } else { + scar_instruction->set_binop(binop::BINOP::SUB); + } + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + + scar_val_dst->set_type(scar::val_type::VAR); + // The destination will always be a variable + if (!variable_buffer.empty()) { + scar_val_dst->set_reg_name(variable_buffer); + variable_buffer.clear(); + } else { + scar_val_dst->set_reg_name( + factor->get_identifier_node()->get_value()); + } + + reg_name = scar_val_dst->get_reg(); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(reg_name); + scar_instruction->set_src1(std::move(scar_val_src)); + + scar_val_src2->set_type(scar::val_type::CONSTANT); + scar_val_src2->set_value("1"); + scar_instruction->set_src2(std::move(scar_val_src2)); + + scar_function->add_instruction(std::move(scar_instruction)); + continue; + } else if (op == unop::UNOP::POSTINCREMENT or + op == unop::UNOP::POSTDECREMENT) { + // SPECIAL CASE WHEN WE HAVE POST INCREMENT OR DECREMENT + // Since these return the original value and then increment or decrement + // We first make a copy of the original value and then increment or + // decrement + + // COPY THE ORIGINAL VALUE INTO A NEW SCAR REGISTER + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::COPY); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_src->set_type(scar::val_type::VAR); + if (!variable_buffer.empty()) { + scar_val_src->set_reg_name(variable_buffer); + variable_buffer.clear(); + } else { + scar_val_src->set_reg_name( + factor->get_identifier_node()->get_value()); + } + std::string _variable = scar_val_src->get_reg(); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name(get_reg_name()); + scar_instruction->set_dst(std::move(scar_val_dst)); + scar_function->add_instruction(std::move(scar_instruction)); + + // NOW DO THE BINARY OPERATION + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::BINARY); + if (op == unop::UNOP::POSTINCREMENT) { + scar_instruction2->set_binop(binop::BINOP::ADD); + } else { + scar_instruction2->set_binop(binop::BINOP::SUB); + } + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + + scar_val_src2->set_type(scar::val_type::VAR); + scar_val_src2->set_reg_name(_variable); + scar_instruction2->set_src1(std::move(scar_val_src2)); + + scar_val_src3->set_type(scar::val_type::CONSTANT); + scar_val_src3->set_value("1"); + scar_instruction2->set_src2(std::move(scar_val_src3)); + + scar_val_dst2->set_type(scar::val_type::VAR); + scar_val_dst2->set_reg_name(_variable); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + + scar_function->add_instruction(std::move(scar_instruction2)); + continue; + } + // scar::scar_Instruction_Node scar_instruction; + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::UNARY); + scar_instruction->set_unop(op); + + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + + // deal with the source + if (i == num_unpos - 1) { + if (factor->get_int_node() != nullptr and + !factor->get_int_node()->get_value().empty()) { + scar_val_src->set_type(scar::val_type::CONSTANT); + scar_val_src->set_value(factor->get_int_node()->get_value()); + } else if (factor->get_identifier_node() != nullptr and + !factor->get_identifier_node()->get_value().empty()) { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name( + factor->get_identifier_node()->get_value()); + } else if (!constant_buffer.empty()) { + scar_val_src->set_type(scar::val_type::CONSTANT); + scar_val_src->set_value(constant_buffer); + constant_buffer.clear(); + } else if (!variable_buffer.empty()) { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(variable_buffer); + variable_buffer.clear(); + } else { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(get_prev_reg_name()); + } + } else { + scar_val_src->set_type(scar::val_type::VAR); + scar_val_src->set_reg_name(get_prev_reg_name()); + } + scar_instruction->set_src1(std::move(scar_val_src)); + + // deal with the destination + scar_val_dst->set_type(scar::val_type::VAR); + scar_val_dst->set_reg_name(get_reg_name()); + scar_instruction->set_dst(std::move(scar_val_dst)); + + scar_function->add_instruction(std::move(scar_instruction)); + } + // empty the unop buffer + unop_buffer[curr_buff].clear(); + } else { + // NOTE: It is guaranteed that the factor node will have either an int node + // or an identifier node + + // save constant for later use + if (factor->get_int_node() != nullptr and + !factor->get_int_node()->get_value().empty()) { + constant_buffer = factor->get_int_node()->get_value(); + } + + // save variable for later use + if (factor->get_identifier_node() != nullptr and + !factor->get_identifier_node()->get_value().empty()) { + variable_buffer = factor->get_identifier_node()->get_value(); + } + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scargen/scar_statement.cc b/codegen/scargen/scar_statement.cc new file mode 100644 index 0000000..b821209 --- /dev/null +++ b/codegen/scargen/scar_statement.cc @@ -0,0 +1,332 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::gen_scar_statement( + std::shared_ptr statement, + std::shared_ptr scar_function) { + switch (statement->get_type()) { + case ast::statementType::NULLSTMT: + break; + case ast::statementType::RETURN: { + gen_scar_exp(statement->get_exps(), scar_function); + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::RETURN); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(scar_val_src); + scar_function->add_instruction(scar_instruction); + } break; + case ast::statementType::EXP: { + gen_scar_exp(statement->get_exps(), scar_function); + } break; + case ast::statementType::IF: { + // (stored in exps) + // c = + // JumpIfZero(c, end) + // (handled in the next iteration) + // Label(end) (Added during the end of if statement) + auto if_statement = + std::static_pointer_cast(statement); + gen_scar_exp(if_statement->get_exps(), scar_function); + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(std::move(scar_val_src)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::UNKNOWN); + scar_val_dst->set_value(if_statement->get_labels().first->get_value()); + scar_instruction->set_dst(std::move(scar_val_dst)); + scar_function->add_instruction(std::move(scar_instruction)); + + // generate scar for the statement + gen_scar_statement(if_statement->get_stmt1(), scar_function); + + // generate the end label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + scar_val_src2->set_type(scar::val_type::UNKNOWN); + scar_val_src2->set_value(if_statement->get_labels().first->get_value()); + scar_instruction2->set_src1(std::move(scar_val_src2)); + scar_function->add_instruction(std::move(scar_instruction2)); + } break; + case ast::statementType::IFELSE: { + // + // c = + // JumpIfZero(c, else_label) + // + // Jump(end) + // Label(else_label) + // + // Label(end) + + auto if_else_statement = + std::static_pointer_cast(statement); + gen_scar_exp(if_else_statement->get_exps(), scar_function); + + // Jump if zero to else statement + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + SETVARCONSTANTREG(scar_val_src); + scar_instruction->set_src1(std::move(scar_val_src)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst); + scar_val_dst->set_type(scar::val_type::UNKNOWN); + scar_val_dst->set_value(if_else_statement->get_labels().first->get_value()); + scar_instruction->set_dst(std::move(scar_val_dst)); + scar_function->add_instruction(std::move(scar_instruction)); + + // generate scar for the if statement + gen_scar_statement(if_else_statement->get_stmt1(), scar_function); + + // jump to the end + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + scar_val_src2->set_type(scar::val_type::UNKNOWN); + scar_val_src2->set_value( + if_else_statement->get_labels().second->get_value()); + scar_instruction2->set_src1(std::move(scar_val_src2)); + scar_function->add_instruction(std::move(scar_instruction2)); + + // generate the else label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value( + if_else_statement->get_labels().first->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(std::move(scar_instruction3)); + + // generate scar for the else statement + gen_scar_statement(if_else_statement->get_stmt2(), scar_function); + + // generate the end label + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + scar_instruction4->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value( + if_else_statement->get_labels().second->get_value()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(std::move(scar_instruction4)); + } break; + + case ast::statementType::GOTO: + case ast::statementType::BREAK: + case ast::statementType::CONTINUE: { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(statement->get_labels().first->get_value()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + } break; + + case ast::statementType::LABEL: { + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(statement->get_labels().first->get_value()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + } break; + + case ast::statementType::BLOCK: { + auto block_statement = + std::static_pointer_cast(statement); + gen_scar_block(block_statement->get_block(), scar_function); + } break; + + case ast::statementType::WHILE: { + auto while_statement = + std::static_pointer_cast(statement); + + // Label(start) + // + // c = + // JumpIfZero(c, end) + // + // Jump(start) + // Label(end) + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(while_statement->get_labels().first->get_value()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + + gen_scar_exp(while_statement->get_exps(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(while_statement->get_labels().second->get_value()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(scar_instruction2); + + gen_scar_statement(while_statement->get_stmt(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value(while_statement->get_labels().first->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(scar_instruction3); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + scar_instruction4->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(while_statement->get_labels().second->get_value()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(scar_instruction4); + } break; + + case ast::statementType::DO_WHILE: { + auto do_while_statement = + std::static_pointer_cast(statement); + + // Label(start) + // + // Label(continue) + // + // c = + // JumpIfNotZero(c, start) + // Label(end) + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(do_while_statement->get_start_label()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + + gen_scar_statement(do_while_statement->get_stmt(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction1); + scar_instruction1->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src1); + scar_val_src1->set_type(scar::val_type::UNKNOWN); + scar_val_src1->set_value( + do_while_statement->get_labels().first->get_value()); + scar_instruction1->set_src1(std::move(scar_val_src1)); + scar_function->add_instruction(scar_instruction1); + + gen_scar_exp(do_while_statement->get_exps(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_NOT_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(do_while_statement->get_start_label()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(scar_instruction2); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value( + do_while_statement->get_labels().second->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(scar_instruction3); + } break; + + case ast::statementType::FOR: { + auto for_statement = + std::static_pointer_cast(statement); + + // + // Label(Forstart) + // + // c = + // JumpIfZero(c, end) + // + // Label(continue) + // + // Jump(Forstart) + // Label(end) + + if (for_statement->get_for_init() != nullptr) { + if (for_statement->get_for_init()->get_declaration() != nullptr) { + gen_scar_declaration(for_statement->get_for_init()->get_declaration(), + scar_function); + } else { + gen_scar_exp(for_statement->get_for_init()->get_exp(), scar_function); + } + } + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction); + scar_instruction->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src); + scar_val_src->set_type(scar::val_type::UNKNOWN); + scar_val_src->set_value(for_statement->get_start_label()); + scar_instruction->set_src1(std::move(scar_val_src)); + scar_function->add_instruction(scar_instruction); + + gen_scar_exp(for_statement->get_exps(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction2); + scar_instruction2->set_type(scar::instruction_type::JUMP_IF_ZERO); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src2); + SETVARCONSTANTREG(scar_val_src2); + scar_instruction2->set_src1(std::move(scar_val_src2)); + MAKE_SHARED(scar::scar_Val_Node, scar_val_dst2); + scar_val_dst2->set_type(scar::val_type::UNKNOWN); + scar_val_dst2->set_value(for_statement->get_labels().second->get_value()); + scar_instruction2->set_dst(std::move(scar_val_dst2)); + scar_function->add_instruction(scar_instruction2); + + gen_scar_statement(for_statement->get_stmt(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction3); + scar_instruction3->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src3); + scar_val_src3->set_type(scar::val_type::UNKNOWN); + scar_val_src3->set_value(for_statement->get_labels().first->get_value()); + scar_instruction3->set_src1(std::move(scar_val_src3)); + scar_function->add_instruction(scar_instruction3); + + gen_scar_exp(for_statement->get_exp2(), scar_function); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction4); + scar_instruction4->set_type(scar::instruction_type::JUMP); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src4); + scar_val_src4->set_type(scar::val_type::UNKNOWN); + scar_val_src4->set_value(for_statement->get_start_label()); + scar_instruction4->set_src1(std::move(scar_val_src4)); + scar_function->add_instruction(scar_instruction4); + + MAKE_SHARED(scar::scar_Instruction_Node, scar_instruction5); + scar_instruction5->set_type(scar::instruction_type::LABEL); + MAKE_SHARED(scar::scar_Val_Node, scar_val_src5); + scar_val_src5->set_type(scar::val_type::UNKNOWN); + scar_val_src5->set_value(for_statement->get_labels().second->get_value()); + scar_instruction5->set_src1(std::move(scar_val_src5)); + scar_function->add_instruction(scar_instruction5); + } break; + case ast::statementType::UNKNOWN: + UNREACHABLE() + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scasmgen/fix_instructions.cc b/codegen/scasmgen/fix_instructions.cc new file mode 100644 index 0000000..69f4cc4 --- /dev/null +++ b/codegen/scasmgen/fix_instructions.cc @@ -0,0 +1,117 @@ +#include + +namespace scarlet { +namespace codegen { + +void Codegen::fix_instructions() { + MAKE_SHARED(scasm::scasm_instruction, scasm_stack_instr); + scasm_stack_instr->set_type(scasm::instruction_type::ALLOCATE_STACK); + MAKE_SHARED(scasm::scasm_operand, val); + val->set_type(scasm::operand_type::IMM); + val->set_imm(stack_offset); + scasm_stack_instr->set_src(std::move(val)); + + scasm.get_functions()[0]->get_instructions().insert( + scasm.get_functions()[0]->get_instructions().begin(), + std::move(scasm_stack_instr)); + + for (auto &funcs : scasm.get_functions()) { + for (auto it = funcs->get_instructions().begin(); + it != funcs->get_instructions().end(); it++) { + if (NOTNULL((*it)->get_src()) && NOTNULL((*it)->get_dst()) && + (*it)->get_src()->get_type() == scasm::operand_type::STACK && + (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_src()); + + // fixing up stack to stack move + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R10); + scasm_inst->set_dst(dst); + + (*it)->set_src(std::move(dst)); + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + } + } + } + + // case when DIV uses a constant as an operand + // case when MUL have dst as a stack value + for (auto &funcs : scasm.get_functions()) { + for (auto it = funcs->get_instructions().begin(); + it != funcs->get_instructions().end(); it++) { + + if ((*it)->get_type() == scasm::instruction_type::CMP and + (*it)->get_dst()->get_type() == scasm::operand_type::IMM) { + // cmpl stack/reg, $5 + // | + // v + // movl $5, %r11d + // cmpl stack/reg, %r11d + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_dst()); + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R11); + scasm_inst->set_dst(dst); + (*it)->set_dst(std::move(dst)); + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + } + if ((*it)->get_type() == scasm::instruction_type::IDIV and + (*it)->get_src()->get_type() == scasm::operand_type::IMM) { + // idivl $3 + // | + // v + // movl $3, %r10d + // idivl %r10d + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_src()); + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R10); + scasm_inst->set_dst(dst); + (*it)->set_src(std::move(dst)); + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + } else if ((*it)->get_type() == scasm::instruction_type::BINARY and + (*it)->get_binop() == scasm::Binop::MUL and + (*it)->get_dst()->get_type() == scasm::operand_type::STACK) { + // imull $3, STACK + // | + // v + // movl STACK, %r11d + // imull $3, %r11d + // movl %r11d, STACK + + MAKE_SHARED(scasm::scasm_operand, dst); + dst->set_type(scasm::operand_type::REG); + dst->set_reg(scasm::register_type::R11); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + scasm_inst->set_src((*it)->get_dst()); + scasm_inst->set_dst(dst); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + scasm_inst2->set_src(dst); + scasm_inst2->set_dst((*it)->get_dst()); + + (*it)->set_dst(std::move(dst)); + + it = funcs->get_instructions().insert(it, std::move(scasm_inst)); + it++; + it = funcs->get_instructions().insert(it + 1, std::move(scasm_inst2)); + } + } + } +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scasmgen/fix_pseudo_registers.cc b/codegen/scasmgen/fix_pseudo_registers.cc new file mode 100644 index 0000000..474383d --- /dev/null +++ b/codegen/scasmgen/fix_pseudo_registers.cc @@ -0,0 +1,35 @@ +#include + +namespace scarlet { +namespace codegen { + +#define FIX_PSEUDO(target) \ + if (NOTNULL(inst->get_##target()) && \ + inst->get_##target()->get_type() == scasm::operand_type::PSEUDO) { \ + if (pseduo_registers.find(inst->get_##target()->get_identifier_stack()) != \ + pseduo_registers.end()) { \ + inst->get_##target()->set_identifier_stack( \ + pseduo_registers[inst->get_##target()->get_identifier_stack()]); \ + } else { \ + std::string temp = inst->get_##target()->get_identifier_stack(); \ + inst->get_##target()->set_identifier_stack( \ + "-" + std::to_string(offset * 4) + "(%rbp)"); \ + pseduo_registers[temp] = inst->get_##target()->get_identifier_stack(); \ + offset++; \ + } \ + inst->get_##target()->set_type(scasm::operand_type::STACK); \ + } + +void Codegen::fix_pseudo_registers() { + int offset = 1; + for (auto &funcs : scasm.get_functions()) { + for (auto &inst : funcs->get_instructions()) { + FIX_PSEUDO(src); + FIX_PSEUDO(dst); + } + } + stack_offset = 4 * (offset - 1); +} + +} // namespace codegen +} // namespace scarlet diff --git a/codegen/scasmgen/scasm_generation.cc b/codegen/scasmgen/scasm_generation.cc new file mode 100644 index 0000000..3c5697b --- /dev/null +++ b/codegen/scasmgen/scasm_generation.cc @@ -0,0 +1,424 @@ +#include + +namespace scarlet { +namespace codegen { + +#define SET_MOV_SOURCE() \ + switch (inst->get_src1()->get_type()) { \ + case scar::val_type::VAR: \ + scasm_src->set_type(scasm::operand_type::PSEUDO); \ + scasm_src->set_identifier_stack(inst->get_src1()->get_reg()); \ + break; \ + case scar::val_type::CONSTANT: \ + scasm_src->set_type(scasm::operand_type::IMM); \ + scasm_src->set_imm(stoi(inst->get_src1()->get_value())); \ + break; \ + default: \ + break; \ + } \ + scasm_inst->set_src(std::move(scasm_src)) + +#define SET_DST(dst) \ + switch (inst->get_dst()->get_type()) { \ + case scar::val_type::VAR: \ + dst->set_type(scasm::operand_type::PSEUDO); \ + dst->set_identifier_stack(inst->get_dst()->get_reg()); \ + break; \ + default: \ + break; \ + } + +void Codegen::gen_scasm() { + scasm::scasm_program scasm_program{}; + for (auto func : scar.get_functions()) { + MAKE_SHARED(scasm::scasm_function, scasm_func); + scasm_func->set_name(func->get_identifier()->get_value()); + for (auto inst : func->get_instructions()) { + if (inst->get_type() == scar::instruction_type::RETURN) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + scasm_dst->set_type(scasm::operand_type::REG); + scasm_dst->set_reg(scasm::register_type::AX); + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::RET); + scasm_func->add_instruction(std::move(scasm_inst2)); + + } else if (inst->get_type() == scar::instruction_type::UNARY) { + if (inst->get_unop() == unop::UNOP::NOT) { + // Cmp(Imm(0), src) + // Mov(Imm(0), dst) + // SetCC(E, dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::CMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::IMM); + scasm_src->set_imm(0); + scasm_inst->set_src(std::move(scasm_src)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + switch (inst->get_src1()->get_type()) { + case scar::val_type::VAR: + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_dst->set_type(scasm::operand_type::IMM); + scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); + break; + default: + break; + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(0); + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + SET_DST(scasm_dst2); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::SETCC); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::COND); + scasm_src3->set_cond(scasm::cond_code::E); + scasm_inst3->set_src(std::move(scasm_src3)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst3); + switch (inst->get_dst()->get_type()) { + case scar::val_type::VAR: + scasm_dst3->set_type(scasm::operand_type::PSEUDO); + scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); + break; + default: + break; + } + scasm_inst3->set_dst(std::move(scasm_dst3)); + scasm_func->add_instruction(std::move(scasm_inst3)); + } else { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst->set_dst(std::move(scasm_dst)); + + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::UNARY); + scasm_inst2->set_unop(inst->get_unop()); + + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst2->set_type(scasm::operand_type::PSEUDO); + scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst2->set_dst(std::move(scasm_dst2)); + + scasm_func->add_instruction(std::move(scasm_inst2)); + } + } else if (inst->get_type() == scar::instruction_type::BINARY) { + if (binop::is_relational(inst->get_binop())) { + // Cmp(src2, src1) + // Mov(Imm(0), dst) + // SetCC(conditional, dst) + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::CMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + switch (inst->get_src2()->get_type()) { + case scar::val_type::VAR: + scasm_src->set_type(scasm::operand_type::PSEUDO); + scasm_src->set_identifier_stack(inst->get_src2()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_src->set_type(scasm::operand_type::IMM); + scasm_src->set_imm(stoi(inst->get_src2()->get_value())); + break; + default: + break; + } + scasm_inst->set_src(std::move(scasm_src)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + switch (inst->get_src1()->get_type()) { + case scar::val_type::VAR: + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_dst->set_type(scasm::operand_type::IMM); + scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); + break; + default: + break; + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(0); + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + SET_DST(scasm_dst2); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::SETCC); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::COND); + switch (inst->get_binop()) { + case binop::BINOP::EQUAL: + scasm_src3->set_cond(scasm::cond_code::E); + break; + case binop::BINOP::NOTEQUAL: + scasm_src3->set_cond(scasm::cond_code::NE); + break; + case binop::BINOP::LESSTHAN: + scasm_src3->set_cond(scasm::cond_code::L); + break; + case binop::BINOP::LESSTHANEQUAL: + scasm_src3->set_cond(scasm::cond_code::LE); + break; + case binop::BINOP::GREATERTHAN: + scasm_src3->set_cond(scasm::cond_code::G); + break; + case binop::BINOP::GREATERTHANEQUAL: + scasm_src3->set_cond(scasm::cond_code::GE); + break; + default: + break; + } + scasm_inst3->set_src(std::move(scasm_src3)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst3); + SET_DST(scasm_dst3); + scasm_inst3->set_dst(std::move(scasm_dst3)); + scasm_func->add_instruction(std::move(scasm_inst3)); + } else if (inst->get_binop() == binop::BINOP::DIV or + inst->get_binop() == binop::BINOP::MOD) { + // Mov(src1, Reg(AX)) + // Cdq + // Idiv(src2) + // Mov(Reg(AX), dst) | Mov(Reg(DX), dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + scasm_dst->set_type(scasm::operand_type::REG); + scasm_dst->set_reg(scasm::register_type::AX); + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::CDQ); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::IDIV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + if (inst->get_src2()->get_type() == scar::val_type::VAR) { + scasm_src2->set_type(scasm::operand_type::PSEUDO); + scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); + } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); + } + scasm_inst3->set_src(std::move(scasm_src2)); + scasm_func->add_instruction(std::move(scasm_inst3)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst4); + scasm_inst4->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + SET_DST(scasm_dst2); + scasm_inst4->set_dst(std::move(scasm_dst2)); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::REG); + if (inst->get_binop() == binop::BINOP::DIV) { + scasm_src3->set_reg(scasm::register_type::AX); + } else { + scasm_src3->set_reg(scasm::register_type::DX); + } + scasm_inst4->set_src(std::move(scasm_src3)); + scasm_func->add_instruction(std::move(scasm_inst4)); + } else if (inst->get_binop() == binop::BINOP::LEFT_SHIFT or + inst->get_binop() == binop::BINOP::RIGHT_SHIFT) { + // Mov(src1,dst) + // Mov(src2, Reg(CX)) + // Binary(binary operand, CL, dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); + } else if (inst->get_src2()->get_type() == scar::val_type::VAR) { + scasm_src2->set_type(scasm::operand_type::PSEUDO); + scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); + } + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + scasm_dst2->set_type(scasm::operand_type::REG); + scasm_dst2->set_reg(scasm::register_type::CX); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst3); + scasm_inst3->set_type(scasm::instruction_type::BINARY); + scasm_inst3->set_binop( + scasm::scar_binop_to_scasm_binop(inst->get_binop())); + MAKE_SHARED(scasm::scasm_operand, scasm_src3); + scasm_src3->set_type(scasm::operand_type::REG); + scasm_src3->set_reg(scasm::register_type::CL); + scasm_inst3->set_src(std::move(scasm_src3)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst3); + scasm_dst3->set_type(scasm::operand_type::PSEUDO); + scasm_dst3->set_identifier_stack(inst->get_dst()->get_reg()); + scasm_inst3->set_dst(std::move(scasm_dst3)); + scasm_func->add_instruction(std::move(scasm_inst3)); + + } else { + // Mov(src1, dst) + // Binary(binary_operator, src2, dst) + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::BINARY); + scasm_inst2->set_binop( + scasm::scar_binop_to_scasm_binop(inst->get_binop())); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + if (inst->get_src2()->get_type() == scar::val_type::VAR) { + scasm_src2->set_type(scasm::operand_type::PSEUDO); + scasm_src2->set_identifier_stack(inst->get_src2()->get_reg()); + } else if (inst->get_src2()->get_type() == scar::val_type::CONSTANT) { + scasm_src2->set_type(scasm::operand_type::IMM); + scasm_src2->set_imm(stoi(inst->get_src2()->get_value())); + } + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + if (inst->get_dst()->get_type() == scar::val_type::VAR) { + scasm_dst2->set_type(scasm::operand_type::PSEUDO); + scasm_dst2->set_identifier_stack(inst->get_dst()->get_reg()); + } + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + } + } else if (inst->get_type() == scar::instruction_type::COPY) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::MOV); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + SET_MOV_SOURCE(); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + SET_DST(scasm_dst); + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + } else if (inst->get_type() == scar::instruction_type::LABEL) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::LABEL); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::LABEL); + scasm_src->set_identifier_stack(inst->get_src1()->get_value()); + scasm_inst->set_src(std::move(scasm_src)); + scasm_func->add_instruction(std::move(scasm_inst)); + } else if (inst->get_type() == scar::instruction_type::JUMP) { + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::JMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::LABEL); + scasm_src->set_identifier_stack(inst->get_src1()->get_value()); + scasm_inst->set_src(std::move(scasm_src)); + scasm_func->add_instruction(std::move(scasm_inst)); + } else if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO or + inst->get_type() == scar::instruction_type::JUMP_IF_NOT_ZERO) { + // Cmp(Imm(0), condition) + // JmpCC(E, label) | JmpCC(NE, label) + MAKE_SHARED(scasm::scasm_instruction, scasm_inst); + scasm_inst->set_type(scasm::instruction_type::CMP); + MAKE_SHARED(scasm::scasm_operand, scasm_src); + scasm_src->set_type(scasm::operand_type::IMM); + scasm_src->set_imm(0); + scasm_inst->set_src(std::move(scasm_src)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst); + switch (inst->get_src1()->get_type()) { + case scar::val_type::VAR: + scasm_dst->set_type(scasm::operand_type::PSEUDO); + scasm_dst->set_identifier_stack(inst->get_src1()->get_reg()); + break; + case scar::val_type::CONSTANT: + scasm_dst->set_type(scasm::operand_type::IMM); + scasm_dst->set_imm(stoi(inst->get_src1()->get_value())); + break; + default: + break; + } + scasm_inst->set_dst(std::move(scasm_dst)); + scasm_func->add_instruction(std::move(scasm_inst)); + + MAKE_SHARED(scasm::scasm_instruction, scasm_inst2); + scasm_inst2->set_type(scasm::instruction_type::JMPCC); + MAKE_SHARED(scasm::scasm_operand, scasm_src2); + scasm_src2->set_type(scasm::operand_type::COND); + if (inst->get_type() == scar::instruction_type::JUMP_IF_ZERO) { + scasm_src2->set_cond(scasm::cond_code::E); + } else { + scasm_src2->set_cond(scasm::cond_code::NE); + } + scasm_inst2->set_src(std::move(scasm_src2)); + MAKE_SHARED(scasm::scasm_operand, scasm_dst2); + scasm_dst2->set_type(scasm::operand_type::LABEL); + scasm_dst2->set_identifier_stack(inst->get_dst()->get_value()); + scasm_inst2->set_dst(std::move(scasm_dst2)); + scasm_func->add_instruction(std::move(scasm_inst2)); + } + } + scasm_program.add_function(std::move(scasm_func)); + } + + this->scasm = scasm_program; +} + +} // namespace codegen +} // namespace scarlet diff --git a/parser/CMakeLists.txt b/parser/CMakeLists.txt index 858a01f..8495df4 100644 --- a/parser/CMakeLists.txt +++ b/parser/CMakeLists.txt @@ -1,6 +1,25 @@ add_library(scarParser STATIC - parser.cc parser.hh + common.hh + parser.cc + parse_function.cc + parse_block.cc + parse_statement.cc + parse_declaration.cc + parse_expression.cc + parse_binop.cc + parse_unop.cc + parse_constants.cc + + semantic_analysis/analyze_block.cc + semantic_analysis/analyze_declaration.cc + semantic_analysis/analyze_expression.cc + semantic_analysis/analyze_statement.cc + + pretty_print/pretty_print_block.cc + pretty_print/pretty_print_declaration.cc + pretty_print/pretty_print_expression.cc + pretty_print/pretty_print_statement.cc ) set_basic_compile_options(scarParser) diff --git a/parser/common.hh b/parser/common.hh new file mode 100644 index 0000000..660452d --- /dev/null +++ b/parser/common.hh @@ -0,0 +1,75 @@ +#pragma once + +#include "parser.hh" + +namespace scarlet { +namespace parser { + +#define UNREACHABLE() \ + std::cout << "Unreachable code reached in " << __FILE__ << " at line " \ + << __LINE__ << std::endl; \ + __builtin_unreachable(); + +#define EXPECT(tok) \ + if (!success) { \ + return; \ + } \ + if (tokens.empty()) { \ + eof_error(tok); \ + return; \ + } \ + expect(tokens[0].get_token(), tok); \ + if (!success) { \ + return; \ + } \ + tokens.erase(tokens.begin()); + +#define EXPECT_FUNC(tok) \ + if (!success) { \ + return function; \ + } \ + if (tokens.empty()) { \ + eof_error(tok); \ + return function; \ + } \ + expect(tokens[0].get_token(), tok); \ + if (!success) { \ + return function; \ + } \ + tokens.erase(tokens.begin()); + +#define EXPECT_INT(tok) \ + if (!success) { \ + return; \ + } \ + if (tokens.empty()) { \ + eof_error(tok); \ + return; \ + } \ + expect(tokens[0].get_token(), tok); \ + if (!success) { \ + return; \ + } \ + MAKE_SHARED(ast::AST_int_Node, int_node); \ + int_node->set_value(tokens[0].get_value().value()); \ + factor->set_int_node(std::move(int_node)); \ + tokens.erase(tokens.begin()); + +#define EXPECT_IDENTIFIER() \ + if (!success) { \ + return; \ + } \ + if (tokens.empty()) { \ + eof_error(token::TOKEN::IDENTIFIER); \ + return; \ + } \ + expect(tokens[0].get_token(), token::TOKEN::IDENTIFIER); \ + if (!success) { \ + return; \ + } \ + MAKE_SHARED(ast::AST_identifier_Node, identifier); \ + identifier->set_identifier(tokens[0].get_value().value()); \ + tokens.erase(tokens.begin()); + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_binop.cc b/parser/parse_binop.cc new file mode 100644 index 0000000..a5a5ed2 --- /dev/null +++ b/parser/parse_binop.cc @@ -0,0 +1,109 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +void parser::parse_binop(std::vector &tokens, + std::shared_ptr &binop) { + switch (tokens[0].get_token()) { + case token::TOKEN::PLUS: + binop->set_op(binop::BINOP::ADD); + break; + case token::TOKEN::PERCENT_SIGN: + binop->set_op(binop::BINOP::MOD); + break; + case token::TOKEN::FORWARD_SLASH: + binop->set_op(binop::BINOP::DIV); + break; + case token::TOKEN::ASTERISK: + binop->set_op(binop::BINOP::MUL); + break; + case token::TOKEN::HYPHEN: + binop->set_op(binop::BINOP::SUB); + break; + case token::TOKEN::AAND: + binop->set_op(binop::BINOP::AAND); + break; + case token::TOKEN::AOR: + binop->set_op(binop::BINOP::AOR); + break; + case token::TOKEN::XOR: + binop->set_op(binop::BINOP::XOR); + break; + case token::TOKEN::LEFT_SHIFT: + binop->set_op(binop::BINOP::LEFT_SHIFT); + break; + case token::TOKEN::RIGHT_SHIFT: + binop->set_op(binop::BINOP::RIGHT_SHIFT); + break; + case token::TOKEN::LAND: + binop->set_op(binop::BINOP::LAND); + break; + case token::TOKEN::LOR: + binop->set_op(binop::BINOP::LOR); + break; + case token::TOKEN::EQUAL: + binop->set_op(binop::BINOP::EQUAL); + break; + case token::TOKEN::NOTEQUAL: + binop->set_op(binop::BINOP::NOTEQUAL); + break; + case token::TOKEN::LESSTHAN: + binop->set_op(binop::BINOP::LESSTHAN); + break; + case token::TOKEN::GREATERTHAN: + binop->set_op(binop::BINOP::GREATERTHAN); + break; + case token::TOKEN::LESSTHANEQUAL: + binop->set_op(binop::BINOP::LESSTHANEQUAL); + break; + case token::TOKEN::GREATERTHANEQUAL: + binop->set_op(binop::BINOP::GREATERTHANEQUAL); + break; + case token::TOKEN::ASSIGNMENT: + binop->set_op(binop::BINOP::ASSIGN); + break; + case token::TOKEN::COMPOUND_DIFFERENCE: + binop->set_op(binop::BINOP::COMPOUND_DIFFERENCE); + break; + case token::TOKEN::COMPOUND_DIVISION: + binop->set_op(binop::BINOP::COMPOUND_DIVISION); + break; + case token::TOKEN::COMPOUND_PRODUCT: + binop->set_op(binop::BINOP::COMPOUND_PRODUCT); + break; + case token::TOKEN::COMPOUND_REMAINDER: + binop->set_op(binop::BINOP::COMPOUND_REMAINDER); + break; + case token::TOKEN::COMPOUND_SUM: + binop->set_op(binop::BINOP::COMPOUND_SUM); + break; + case token::TOKEN::COMPOUND_AND: + binop->set_op(binop::BINOP::COMPOUND_AND); + break; + case token::TOKEN::COMPOUND_OR: + binop->set_op(binop::BINOP::COMPOUND_OR); + break; + case token::TOKEN::COMPOUND_XOR: + binop->set_op(binop::BINOP::COMPOUND_XOR); + break; + case token::TOKEN::COMPOUND_LEFTSHIFT: + binop->set_op(binop::BINOP::COMPOUND_LEFTSHIFT); + break; + case token::TOKEN::COMPOUND_RIGHTSHIFT: + binop->set_op(binop::BINOP::COMPOUND_RIGHTSHIFT); + break; + case token::TOKEN::QUESTION_MARK: + binop->set_op(binop::BINOP::TERNARY); + break; + default: + success = false; + error_messages.emplace_back("Expected binary operator but got " + + to_string(tokens[0].get_token())); + break; + } + tokens.erase(tokens.begin()); +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_block.cc b/parser/parse_block.cc new file mode 100644 index 0000000..41363a4 --- /dev/null +++ b/parser/parse_block.cc @@ -0,0 +1,34 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +void parser::parse_block(std::vector &tokens, + std::shared_ptr block) { + EXPECT(token::TOKEN::OPEN_BRACE); + while (!tokens.empty() and success and + tokens[0].get_token() != token::TOKEN::CLOSE_BRACE) { + parse_block_item(tokens, block); + } + EXPECT(token::TOKEN::CLOSE_BRACE); +} + +void parser::parse_block_item(std::vector &tokens, + std::shared_ptr &block) { + MAKE_SHARED(ast::AST_Block_Item_Node, block_item); + if (tokens[0].get_token() == token::TOKEN::INT) { + block_item->set_type(ast::BlockItemType::DECLARATION); + MAKE_SHARED(ast::AST_Declaration_Node, declaration); + parse_declaration(tokens, declaration); + block_item->set_declaration(std::move(declaration)); + } else { + block_item->set_type(ast::BlockItemType::STATEMENT); + MAKE_SHARED(ast::AST_Statement_Node, statement); + parse_statement(tokens, statement); + block_item->set_statement(std::move(statement)); + } + block->add_blockItem(std::move(block_item)); +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_constants.cc b/parser/parse_constants.cc new file mode 100644 index 0000000..2300e14 --- /dev/null +++ b/parser/parse_constants.cc @@ -0,0 +1,19 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +void parser::parse_identifier( + std::vector &tokens, + std::shared_ptr &function) { + EXPECT_IDENTIFIER(); + function->set_identifier(std::move(identifier)); +} + +void parser::parse_int(std::vector &tokens, + std::shared_ptr &factor) { + EXPECT_INT(token::TOKEN::CONSTANT); +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_declaration.cc b/parser/parse_declaration.cc new file mode 100644 index 0000000..d531feb --- /dev/null +++ b/parser/parse_declaration.cc @@ -0,0 +1,26 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +void parser::parse_declaration( + std::vector &tokens, + std::shared_ptr &declaration) { + EXPECT(token::TOKEN::INT); + EXPECT_IDENTIFIER(); + declaration->set_identifier(std::move(identifier)); + if (tokens[0].get_token() == token::TOKEN::SEMICOLON) { + // the variable just have a declaration + tokens.erase(tokens.begin()); + } else { + // the variable has a definition as well + EXPECT(token::TOKEN::ASSIGNMENT); + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + declaration->set_exp(std::move(exp)); + EXPECT(token::TOKEN::SEMICOLON); + } +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_expression.cc b/parser/parse_expression.cc new file mode 100644 index 0000000..3f40460 --- /dev/null +++ b/parser/parse_expression.cc @@ -0,0 +1,134 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +std::pair +parser::is_single_identifier_parentheses(std::vector &tokens) { + int i = 0; + int NUM_TOKENS = tokens.size(); + while (i < NUM_TOKENS) { + if (tokens[i].get_token() == token::TOKEN::OPEN_PARANTHESES) { + i++; + } else { + break; + } + } + if (tokens[i].get_token() == token::TOKEN::IDENTIFIER) { + int num_open_parentheses = i; + int tmp = i; + i++; + while (i < NUM_TOKENS) { + if (tokens[i].get_token() == token::TOKEN::CLOSE_PARANTHESES) { + tmp--; + i++; + } else { + break; + } + } + if (tmp == 0) { + return {true, num_open_parentheses}; + } + } + return {false, 0}; +} + +void parser::parse_factor(std::vector &tokens, + std::shared_ptr &factor) { + if (tokens[0].get_token() == token::TOKEN::CONSTANT) { + parse_int(tokens, factor); + } else if (tokens[0].get_token() == token::TOKEN::IDENTIFIER) { + EXPECT_IDENTIFIER(); + factor->set_identifier_node(std::move(identifier)); + } else if (token::is_unary_op(tokens[0].get_token())) { + parse_unary_op(tokens, factor); + parse_factor(tokens, factor); + } else if (tokens[0].get_token() == token::TOKEN::OPEN_PARANTHESES) { + /** + * Simplification for Single-Identifier Parentheses + * + * When encountering an expression with a single identifier wrapped in + * parentheses, e.g., (identifier), we treat it as a simple identifier + * rather than a complex expression. This optimization significantly reduces + * complexity during semantic analysis by avoiding unnecessary nested + * expression handling. + * + * Example: + * Input: (((((((((((((((((a))))))))))))))))) + * Treats as: a + */ + std::pair res = is_single_identifier_parentheses(tokens); + if (res.first) { + for (int i = 0; i < res.second; i++) { + tokens.erase(tokens.begin()); + } + EXPECT_IDENTIFIER(); + factor->set_identifier_node(std::move(identifier)); + for (int i = 0; i < res.second; i++) { + tokens.erase(tokens.begin()); + } + } else { + tokens.erase(tokens.begin()); + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + factor->set_exp_node(std::move(exp)); + EXPECT(token::TOKEN::CLOSE_PARANTHESES); + } + } else { + success = false; + error_messages.emplace_back("Expected constant, unary operator, semicolon " + "or open parantheses but got " + + to_string(tokens[0].get_token())); + } + // NOTE THIS IS A SPECIAL CASE WHERE WE HAVE A POST INCREMENT OR DECREMENT + // IF THIS BRANCH IS CALLED THEN WE CAN BE SURE THAT WE ARE DEALING WITH A + // POST INCREMENT OR DECREMENT + if (tokens[0].get_token() == token::TOKEN::INCREMENT_OPERATOR or + tokens[0].get_token() == token::TOKEN::DECREMENT_OPERATOR) { + MAKE_SHARED(ast::AST_unop_Node, unop); + if (tokens[0].get_token() == token::TOKEN::INCREMENT_OPERATOR) { + unop->set_op(unop::UNOP::POSTINCREMENT); + } else { + unop->set_op(unop::UNOP::POSTDECREMENT); + } + tokens.erase(tokens.begin()); + factor->add_unop_node(std::move(unop)); + } +} + +void parser::parse_exp(std::vector &tokens, + std::shared_ptr &root_exp, int prec) { + MAKE_SHARED(ast::AST_factor_Node, factor); + parse_factor(tokens, factor); + root_exp->set_factor_node(std::move(factor)); + while (token::is_binary_op(tokens[0].get_token()) and + token::get_binop_prec(tokens[0].get_token()) >= prec) { + int new_prec = token::get_binop_prec(tokens[0].get_token()) + 1; + // Handle right associative operators by reducing the new precedence by 1 + if (token::is_right_associative(tokens[0].get_token())) + new_prec--; + MAKE_SHARED(ast::AST_binop_Node, binop); + parse_binop(tokens, binop); + // Handle ternary operator + if (binop->get_op() == binop::BINOP::TERNARY) { + MAKE_SHARED(ast::AST_exp_Node, middle_exp); + // reset the precedence + parse_exp(tokens, middle_exp, 0); + root_exp->set_middle(std::move(middle_exp)); + EXPECT(token::TOKEN::COLON); + } + root_exp->set_binop_node(std::move(binop)); + MAKE_SHARED(ast::AST_exp_Node, rexp); + parse_exp(tokens, rexp, new_prec); + root_exp->set_right(std::move(rexp)); + if (token::is_binary_op(tokens[0].get_token()) and + token::get_binop_prec(tokens[0].get_token()) >= prec) { + MAKE_SHARED(ast::AST_exp_Node, new_root_exp); + new_root_exp->set_left(root_exp); + root_exp = new_root_exp; + } + } +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_function.cc b/parser/parse_function.cc new file mode 100644 index 0000000..1df2ab5 --- /dev/null +++ b/parser/parse_function.cc @@ -0,0 +1,21 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +std::shared_ptr +parser::parse_function(std::vector &tokens) { + MAKE_SHARED(ast::AST_Function_Node, function); + EXPECT_FUNC(token::TOKEN::INT); + parse_identifier(tokens, function); + EXPECT_FUNC(token::TOKEN::OPEN_PARANTHESES); + EXPECT_FUNC(token::TOKEN::VOID); + EXPECT_FUNC(token::TOKEN::CLOSE_PARANTHESES); + MAKE_SHARED(ast::AST_Block_Node, block); + parse_block(tokens, block); + function->set_block(block); + return function; +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_statement.cc b/parser/parse_statement.cc new file mode 100644 index 0000000..88e9bc4 --- /dev/null +++ b/parser/parse_statement.cc @@ -0,0 +1,222 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +void parser::parse_statement( + std::vector &tokens, + std::shared_ptr &statement) { + // NOTE THESE CHECKS ARE NECESSARY BECAUSE THE FUNCTION CAN BE CALLED + // RECURSIVELY + if (!success) + return; + if (tokens.empty()) { + eof_error(token::TOKEN::SEMICOLON); + return; + } + // =============================== + + if (tokens[0].get_token() == token::TOKEN::RETURN) { + tokens.erase(tokens.begin()); + statement->set_type(ast::statementType::RETURN); + + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + statement->set_exp(std::move(exp)); + + EXPECT(token::TOKEN::SEMICOLON); + } else if (tokens[0].get_token() == token::TOKEN::IF) { + // We first check for the if (exp) statement + MAKE_SHARED(ast::AST_if_else_statement_Node, if_else_statement); + tokens.erase(tokens.begin()); + + EXPECT(token::TOKEN::OPEN_PARANTHESES); + + // exp + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + if_else_statement->set_exp(std::move(exp)); + + EXPECT(token::TOKEN::CLOSE_PARANTHESES); + + // statement + MAKE_SHARED(ast::AST_Statement_Node, stmt); + parse_statement(tokens, stmt); + if_else_statement->set_stmt1(std::move(stmt)); + + if_else_statement->set_labels(get_ifelse_labels()); + + // Then we optionally check for the else statement + if (tokens[0].get_token() == token::TOKEN::ELSE) { + tokens.erase(tokens.begin()); + if_else_statement->set_type(ast::statementType::IFELSE); + + MAKE_SHARED(ast::AST_Statement_Node, stmt2); + parse_statement(tokens, stmt2); + + if_else_statement->set_stmt2(std::move(stmt2)); + } else { + if_else_statement->set_type(ast::statementType::IF); + } + statement = + std::static_pointer_cast(if_else_statement); + } else if (tokens[0].get_token() == token::TOKEN::SEMICOLON) { + // ignore the empty statement + tokens.erase(tokens.begin()); + statement->set_type(ast::statementType::NULLSTMT); + } else if (tokens[0].get_token() == token::TOKEN::GOTO) { + tokens.erase(tokens.begin()); + statement->set_type(ast::statementType::GOTO); + EXPECT_IDENTIFIER(); + statement->set_labels({std::move(identifier), nullptr}); + EXPECT(token::TOKEN::SEMICOLON); + } else if (tokens.size() >= 2 && + tokens[0].get_token() == token::TOKEN::IDENTIFIER && + tokens[1].get_token() == token::TOKEN::COLON) { + statement->set_type(ast::statementType::LABEL); + EXPECT_IDENTIFIER(); + statement->set_labels({std::move(identifier), nullptr}); + EXPECT(token::TOKEN::COLON); + } else if (tokens[0].get_token() == token::TOKEN::OPEN_BRACE) { + MAKE_SHARED(ast::AST_block_statement_node, block_stmt); + MAKE_SHARED(ast::AST_Block_Node, block_node); + parse_block(tokens, block_node); + block_stmt->set_type(ast::statementType::BLOCK); + block_stmt->set_block(std::move(block_node)); + statement = std::static_pointer_cast(block_stmt); + } else if (tokens[0].get_token() == token::TOKEN::WHILE) { + MAKE_SHARED(ast::AST_while_statement_Node, while_statement); + while_statement->set_type(ast::statementType::WHILE); + tokens.erase(tokens.begin()); + while_statement->set_labels(get_loop_labels()); + + EXPECT(token::TOKEN::OPEN_PARANTHESES); + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + while_statement->set_exp(std::move(exp)); + + EXPECT(token::TOKEN::CLOSE_PARANTHESES); + + MAKE_SHARED(ast::AST_Statement_Node, stmt); + parse_statement(tokens, stmt); + while_statement->set_stmt(std::move(stmt)); + + remove_loop_labels(); + statement = + std::static_pointer_cast(while_statement); + } else if (tokens[0].get_token() == token::TOKEN::CONTINUE) { + tokens.erase(tokens.begin()); + statement->set_type(ast::statementType::CONTINUE); + auto lbl = get_prev_loop_start_label(); + if (lbl == nullptr) { + error_messages.emplace_back( + "Continue statement found outside of a loop construct"); + success = false; + } else { + statement->set_labels({std::move(lbl), nullptr}); + } + EXPECT(token::TOKEN::SEMICOLON); + } else if (tokens[0].get_token() == token::TOKEN::BREAK) { + tokens.erase(tokens.begin()); + statement->set_type(ast::statementType::BREAK); + auto lbl = get_prev_loop_end_label(); + if (lbl == nullptr) { + error_messages.emplace_back( + "Break statement found outside of a loop construct"); + success = false; + } else { + statement->set_labels({std::move(lbl), nullptr}); + } + EXPECT(token::TOKEN::SEMICOLON); + } else if (tokens[0].get_token() == token::TOKEN::DO) { + tokens.erase(tokens.begin()); + MAKE_SHARED(ast::AST_while_statement_Node, while_statement); + while_statement->set_type(ast::statementType::DO_WHILE); + while_statement->set_labels(get_loop_labels()); + while_statement->set_start_label(get_loop_start_label()); + + MAKE_SHARED(ast::AST_Statement_Node, stmt); + parse_statement(tokens, stmt); + while_statement->set_stmt(std::move(stmt)); + + EXPECT(token::TOKEN::WHILE); + EXPECT(token::TOKEN::OPEN_PARANTHESES); + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + while_statement->set_exp(std::move(exp)); + EXPECT(token::TOKEN::CLOSE_PARANTHESES); + EXPECT(token::TOKEN::SEMICOLON); + + remove_loop_labels(); + statement = + std::static_pointer_cast(while_statement); + } else if (tokens[0].get_token() == token::TOKEN::FOR) { + // For statement has additional constructs, so we use a + // child class AST_For_Statement_Node to represent it. + // We will use the power of down and upcasting to handle this. + // for ( ; ; ) + tokens.erase(tokens.begin()); + EXPECT(token::TOKEN::OPEN_PARANTHESES); + + MAKE_SHARED(ast::AST_For_Statement_Node, for_statement); + for_statement->set_type(ast::statementType::FOR); + if (tokens[0].get_token() != token::TOKEN::SEMICOLON) { + parse_for_init(tokens, for_statement); + } else { + EXPECT(token::TOKEN::SEMICOLON); + } + + if (tokens[0].get_token() != token::TOKEN::SEMICOLON) { + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + for_statement->set_exp(std::move(exp)); + } + + EXPECT(token::TOKEN::SEMICOLON); + + if (tokens[0].get_token() != token::TOKEN::CLOSE_PARANTHESES) { + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + for_statement->set_exp2(std::move(exp)); + } + + EXPECT(token::TOKEN::CLOSE_PARANTHESES); + + for_statement->set_labels(get_loop_labels()); + for_statement->set_start_label(get_loop_start_label()); + + MAKE_SHARED(ast::AST_Statement_Node, stmt); + parse_statement(tokens, stmt); + for_statement->set_stmt(std::move(stmt)); + + remove_loop_labels(); + statement = + std::static_pointer_cast(for_statement); + } else { + statement->set_type(ast::statementType::EXP); + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + statement->set_exp(std::move(exp)); + EXPECT(token::TOKEN::SEMICOLON); + } +} + +void parser::parse_for_init( + std::vector &tokens, + std::shared_ptr &forstmt) { + MAKE_SHARED(ast::AST_For_Init_Node, for_init); + if (tokens[0].get_token() == token::TOKEN::INT) { + MAKE_SHARED(ast::AST_Declaration_Node, declaration); + parse_declaration(tokens, declaration); + for_init->set_declaration(std::move(declaration)); + } else { + MAKE_SHARED(ast::AST_exp_Node, exp); + parse_exp(tokens, exp); + for_init->set_exp(std::move(exp)); + EXPECT(token::TOKEN::SEMICOLON); + } + forstmt->set_for_init(std::move(for_init)); +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parse_unop.cc b/parser/parse_unop.cc new file mode 100644 index 0000000..109bbb0 --- /dev/null +++ b/parser/parse_unop.cc @@ -0,0 +1,33 @@ +#include "common.hh" + +namespace scarlet { +namespace parser { + +void parser::parse_unary_op(std::vector &tokens, + std::shared_ptr &factor) { + MAKE_SHARED(ast::AST_unop_Node, unop); + switch (tokens[0].get_token()) { + case token::TOKEN::TILDE: + unop->set_op(unop::UNOP::COMPLEMENT); + break; + case token::TOKEN::HYPHEN: + unop->set_op(unop::UNOP::NEGATE); + break; + case token::TOKEN::NOT: + unop->set_op(unop::UNOP::NOT); + break; + case token::TOKEN::INCREMENT_OPERATOR: + unop->set_op(unop::UNOP::PREINCREMENT); + break; + case token::TOKEN::DECREMENT_OPERATOR: + unop->set_op(unop::UNOP::PREDECREMENT); + break; + default: + UNREACHABLE() + } + factor->add_unop_node(std::move(unop)); + tokens.erase(tokens.begin()); +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/parser.cc b/parser/parser.cc index 165fa93..d56cf98 100644 --- a/parser/parser.cc +++ b/parser/parser.cc @@ -1,73 +1,7 @@ -#include "parser.hh" +#include "common.hh" namespace scarlet { namespace parser { -#define UNREACHABLE() \ - std::cout << "Unreachable code reached in " << __FILE__ << " at line " \ - << __LINE__ << std::endl; \ - __builtin_unreachable(); - -#define EXPECT(tok) \ - if (!success) { \ - return; \ - } \ - if (tokens.empty()) { \ - eof_error(tok); \ - return; \ - } \ - expect(tokens[0].get_token(), tok); \ - if (!success) { \ - return; \ - } \ - tokens.erase(tokens.begin()); - -#define EXPECT_FUNC(tok) \ - if (!success) { \ - return function; \ - } \ - if (tokens.empty()) { \ - eof_error(tok); \ - return function; \ - } \ - expect(tokens[0].get_token(), tok); \ - if (!success) { \ - return function; \ - } \ - tokens.erase(tokens.begin()); - -#define EXPECT_INT(tok) \ - if (!success) { \ - return; \ - } \ - if (tokens.empty()) { \ - eof_error(tok); \ - return; \ - } \ - expect(tokens[0].get_token(), tok); \ - if (!success) { \ - return; \ - } \ - MAKE_SHARED(ast::AST_int_Node, int_node); \ - int_node->set_value(tokens[0].get_value().value()); \ - factor->set_int_node(std::move(int_node)); \ - tokens.erase(tokens.begin()); - -#define EXPECT_IDENTIFIER() \ - if (!success) { \ - return; \ - } \ - if (tokens.empty()) { \ - eof_error(token::TOKEN::IDENTIFIER); \ - return; \ - } \ - expect(tokens[0].get_token(), token::TOKEN::IDENTIFIER); \ - if (!success) { \ - return; \ - } \ - MAKE_SHARED(ast::AST_identifier_Node, identifier); \ - identifier->set_identifier(tokens[0].get_value().value()); \ - tokens.erase(tokens.begin()); - void parser::parse_program(std::vector tokens) { ast::AST_Program_Node program; while (!tokens.empty() and success) { @@ -76,548 +10,6 @@ void parser::parse_program(std::vector tokens) { this->program = program; } -std::shared_ptr -parser::parse_function(std::vector &tokens) { - MAKE_SHARED(ast::AST_Function_Node, function); - EXPECT_FUNC(token::TOKEN::INT); - parse_identifier(tokens, function); - EXPECT_FUNC(token::TOKEN::OPEN_PARANTHESES); - EXPECT_FUNC(token::TOKEN::VOID); - EXPECT_FUNC(token::TOKEN::CLOSE_PARANTHESES); - MAKE_SHARED(ast::AST_Block_Node, block); - parse_block(tokens, block); - function->set_block(block); - return function; -} - -void parser::parse_block(std::vector &tokens, - std::shared_ptr block) { - EXPECT(token::TOKEN::OPEN_BRACE); - while (!tokens.empty() and success and - tokens[0].get_token() != token::TOKEN::CLOSE_BRACE) { - parse_block_item(tokens, block); - } - EXPECT(token::TOKEN::CLOSE_BRACE); -} - -void parser::parse_block_item(std::vector &tokens, - std::shared_ptr &block) { - MAKE_SHARED(ast::AST_Block_Item_Node, block_item); - if (tokens[0].get_token() == token::TOKEN::INT) { - block_item->set_type(ast::BlockItemType::DECLARATION); - MAKE_SHARED(ast::AST_Declaration_Node, declaration); - parse_declaration(tokens, declaration); - block_item->set_declaration(std::move(declaration)); - } else { - block_item->set_type(ast::BlockItemType::STATEMENT); - MAKE_SHARED(ast::AST_Statement_Node, statement); - parse_statement(tokens, statement); - block_item->set_statement(std::move(statement)); - } - block->add_blockItem(std::move(block_item)); -} - -void parser::parse_declaration( - std::vector &tokens, - std::shared_ptr &declaration) { - EXPECT(token::TOKEN::INT); - EXPECT_IDENTIFIER(); - declaration->set_identifier(std::move(identifier)); - if (tokens[0].get_token() == token::TOKEN::SEMICOLON) { - // the variable just have a declaration - tokens.erase(tokens.begin()); - } else { - // the variable has a definition as well - EXPECT(token::TOKEN::ASSIGNMENT); - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - declaration->set_exp(std::move(exp)); - EXPECT(token::TOKEN::SEMICOLON); - } -} - -void parser::parse_statement( - std::vector &tokens, - std::shared_ptr &statement) { - // NOTE THESE CHECKS ARE NECESSARY BECAUSE THE FUNCTION CAN BE CALLED - // RECURSIVELY - if (!success) - return; - if (tokens.empty()) { - eof_error(token::TOKEN::SEMICOLON); - return; - } - // =============================== - - if (tokens[0].get_token() == token::TOKEN::RETURN) { - tokens.erase(tokens.begin()); - statement->set_type(ast::statementType::RETURN); - - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - statement->set_exp(std::move(exp)); - - EXPECT(token::TOKEN::SEMICOLON); - } else if (tokens[0].get_token() == token::TOKEN::IF) { - // We first check for the if (exp) statement - MAKE_SHARED(ast::AST_if_else_statement_Node, if_else_statement); - tokens.erase(tokens.begin()); - - EXPECT(token::TOKEN::OPEN_PARANTHESES); - - // exp - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - if_else_statement->set_exp(std::move(exp)); - - EXPECT(token::TOKEN::CLOSE_PARANTHESES); - - // statement - MAKE_SHARED(ast::AST_Statement_Node, stmt); - parse_statement(tokens, stmt); - if_else_statement->set_stmt1(std::move(stmt)); - - if_else_statement->set_labels(get_ifelse_labels()); - - // Then we optionally check for the else statement - if (tokens[0].get_token() == token::TOKEN::ELSE) { - tokens.erase(tokens.begin()); - if_else_statement->set_type(ast::statementType::IFELSE); - - MAKE_SHARED(ast::AST_Statement_Node, stmt2); - parse_statement(tokens, stmt2); - - if_else_statement->set_stmt2(std::move(stmt2)); - } else { - if_else_statement->set_type(ast::statementType::IF); - } - statement = - std::static_pointer_cast(if_else_statement); - } else if (tokens[0].get_token() == token::TOKEN::SEMICOLON) { - // ignore the empty statement - tokens.erase(tokens.begin()); - statement->set_type(ast::statementType::NULLSTMT); - } else if (tokens[0].get_token() == token::TOKEN::GOTO) { - tokens.erase(tokens.begin()); - statement->set_type(ast::statementType::GOTO); - EXPECT_IDENTIFIER(); - statement->set_labels({std::move(identifier), nullptr}); - EXPECT(token::TOKEN::SEMICOLON); - } else if (tokens.size() >= 2 && - tokens[0].get_token() == token::TOKEN::IDENTIFIER && - tokens[1].get_token() == token::TOKEN::COLON) { - statement->set_type(ast::statementType::LABEL); - EXPECT_IDENTIFIER(); - statement->set_labels({std::move(identifier), nullptr}); - EXPECT(token::TOKEN::COLON); - } else if (tokens[0].get_token() == token::TOKEN::OPEN_BRACE) { - MAKE_SHARED(ast::AST_block_statement_node, block_stmt); - MAKE_SHARED(ast::AST_Block_Node, block_node); - parse_block(tokens, block_node); - block_stmt->set_type(ast::statementType::BLOCK); - block_stmt->set_block(std::move(block_node)); - statement = std::static_pointer_cast(block_stmt); - } else if (tokens[0].get_token() == token::TOKEN::WHILE) { - MAKE_SHARED(ast::AST_while_statement_Node, while_statement); - while_statement->set_type(ast::statementType::WHILE); - tokens.erase(tokens.begin()); - while_statement->set_labels(get_loop_labels()); - - EXPECT(token::TOKEN::OPEN_PARANTHESES); - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - while_statement->set_exp(std::move(exp)); - - EXPECT(token::TOKEN::CLOSE_PARANTHESES); - - MAKE_SHARED(ast::AST_Statement_Node, stmt); - parse_statement(tokens, stmt); - while_statement->set_stmt(std::move(stmt)); - - remove_loop_labels(); - statement = - std::static_pointer_cast(while_statement); - } else if (tokens[0].get_token() == token::TOKEN::CONTINUE) { - tokens.erase(tokens.begin()); - statement->set_type(ast::statementType::CONTINUE); - auto lbl = get_prev_loop_start_label(); - if (lbl == nullptr) { - error_messages.emplace_back( - "Continue statement found outside of a loop construct"); - success = false; - } else { - statement->set_labels({std::move(lbl), nullptr}); - } - EXPECT(token::TOKEN::SEMICOLON); - } else if (tokens[0].get_token() == token::TOKEN::BREAK) { - tokens.erase(tokens.begin()); - statement->set_type(ast::statementType::BREAK); - auto lbl = get_prev_loop_end_label(); - if (lbl == nullptr) { - error_messages.emplace_back( - "Break statement found outside of a loop construct"); - success = false; - } else { - statement->set_labels({std::move(lbl), nullptr}); - } - EXPECT(token::TOKEN::SEMICOLON); - } else if (tokens[0].get_token() == token::TOKEN::DO) { - tokens.erase(tokens.begin()); - MAKE_SHARED(ast::AST_while_statement_Node, while_statement); - while_statement->set_type(ast::statementType::DO_WHILE); - while_statement->set_labels(get_loop_labels()); - while_statement->set_start_label(get_loop_start_label()); - - MAKE_SHARED(ast::AST_Statement_Node, stmt); - parse_statement(tokens, stmt); - while_statement->set_stmt(std::move(stmt)); - - EXPECT(token::TOKEN::WHILE); - EXPECT(token::TOKEN::OPEN_PARANTHESES); - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - while_statement->set_exp(std::move(exp)); - EXPECT(token::TOKEN::CLOSE_PARANTHESES); - EXPECT(token::TOKEN::SEMICOLON); - - remove_loop_labels(); - statement = - std::static_pointer_cast(while_statement); - } else if (tokens[0].get_token() == token::TOKEN::FOR) { - // For statement has additional constructs, so we use a - // child class AST_For_Statement_Node to represent it. - // We will use the power of down and upcasting to handle this. - // for ( ; ; ) - tokens.erase(tokens.begin()); - EXPECT(token::TOKEN::OPEN_PARANTHESES); - - MAKE_SHARED(ast::AST_For_Statement_Node, for_statement); - for_statement->set_type(ast::statementType::FOR); - if (tokens[0].get_token() != token::TOKEN::SEMICOLON) { - parse_for_init(tokens, for_statement); - } else { - EXPECT(token::TOKEN::SEMICOLON); - } - - if (tokens[0].get_token() != token::TOKEN::SEMICOLON) { - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - for_statement->set_exp(std::move(exp)); - } - - EXPECT(token::TOKEN::SEMICOLON); - - if (tokens[0].get_token() != token::TOKEN::CLOSE_PARANTHESES) { - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - for_statement->set_exp2(std::move(exp)); - } - - EXPECT(token::TOKEN::CLOSE_PARANTHESES); - - for_statement->set_labels(get_loop_labels()); - for_statement->set_start_label(get_loop_start_label()); - - MAKE_SHARED(ast::AST_Statement_Node, stmt); - parse_statement(tokens, stmt); - for_statement->set_stmt(std::move(stmt)); - - remove_loop_labels(); - statement = - std::static_pointer_cast(for_statement); - } else { - statement->set_type(ast::statementType::EXP); - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - statement->set_exp(std::move(exp)); - EXPECT(token::TOKEN::SEMICOLON); - } -} - -void parser::parse_for_init( - std::vector &tokens, - std::shared_ptr &forstmt) { - MAKE_SHARED(ast::AST_For_Init_Node, for_init); - if (tokens[0].get_token() == token::TOKEN::INT) { - MAKE_SHARED(ast::AST_Declaration_Node, declaration); - parse_declaration(tokens, declaration); - for_init->set_declaration(std::move(declaration)); - } else { - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - for_init->set_exp(std::move(exp)); - EXPECT(token::TOKEN::SEMICOLON); - } - forstmt->set_for_init(std::move(for_init)); -} - -std::pair -parser::is_single_identifier_parentheses(std::vector &tokens) { - int i = 0; - int NUM_TOKENS = tokens.size(); - while (i < NUM_TOKENS) { - if (tokens[i].get_token() == token::TOKEN::OPEN_PARANTHESES) { - i++; - } else { - break; - } - } - if (tokens[i].get_token() == token::TOKEN::IDENTIFIER) { - int num_open_parentheses = i; - int tmp = i; - i++; - while (i < NUM_TOKENS) { - if (tokens[i].get_token() == token::TOKEN::CLOSE_PARANTHESES) { - tmp--; - i++; - } else { - break; - } - } - if (tmp == 0) { - return {true, num_open_parentheses}; - } - } - return {false, 0}; -} - -void parser::parse_factor(std::vector &tokens, - std::shared_ptr &factor) { - if (tokens[0].get_token() == token::TOKEN::CONSTANT) { - parse_int(tokens, factor); - } else if (tokens[0].get_token() == token::TOKEN::IDENTIFIER) { - EXPECT_IDENTIFIER(); - factor->set_identifier_node(std::move(identifier)); - } else if (token::is_unary_op(tokens[0].get_token())) { - parse_unary_op(tokens, factor); - parse_factor(tokens, factor); - } else if (tokens[0].get_token() == token::TOKEN::OPEN_PARANTHESES) { - /** - * Simplification for Single-Identifier Parentheses - * - * When encountering an expression with a single identifier wrapped in - * parentheses, e.g., (identifier), we treat it as a simple identifier - * rather than a complex expression. This optimization significantly reduces - * complexity during semantic analysis by avoiding unnecessary nested - * expression handling. - * - * Example: - * Input: (((((((((((((((((a))))))))))))))))) - * Treats as: a - */ - std::pair res = is_single_identifier_parentheses(tokens); - if (res.first) { - for (int i = 0; i < res.second; i++) { - tokens.erase(tokens.begin()); - } - EXPECT_IDENTIFIER(); - factor->set_identifier_node(std::move(identifier)); - for (int i = 0; i < res.second; i++) { - tokens.erase(tokens.begin()); - } - } else { - tokens.erase(tokens.begin()); - MAKE_SHARED(ast::AST_exp_Node, exp); - parse_exp(tokens, exp); - factor->set_exp_node(std::move(exp)); - EXPECT(token::TOKEN::CLOSE_PARANTHESES); - } - } else { - success = false; - error_messages.emplace_back("Expected constant, unary operator, semicolon " - "or open parantheses but got " + - to_string(tokens[0].get_token())); - } - // NOTE THIS IS A SPECIAL CASE WHERE WE HAVE A POST INCREMENT OR DECREMENT - // IF THIS BRANCH IS CALLED THEN WE CAN BE SURE THAT WE ARE DEALING WITH A - // POST INCREMENT OR DECREMENT - if (tokens[0].get_token() == token::TOKEN::INCREMENT_OPERATOR or - tokens[0].get_token() == token::TOKEN::DECREMENT_OPERATOR) { - MAKE_SHARED(ast::AST_unop_Node, unop); - if (tokens[0].get_token() == token::TOKEN::INCREMENT_OPERATOR) { - unop->set_op(unop::UNOP::POSTINCREMENT); - } else { - unop->set_op(unop::UNOP::POSTDECREMENT); - } - tokens.erase(tokens.begin()); - factor->add_unop_node(std::move(unop)); - } -} - -void parser::parse_exp(std::vector &tokens, - std::shared_ptr &root_exp, int prec) { - MAKE_SHARED(ast::AST_factor_Node, factor); - parse_factor(tokens, factor); - root_exp->set_factor_node(std::move(factor)); - while (token::is_binary_op(tokens[0].get_token()) and - token::get_binop_prec(tokens[0].get_token()) >= prec) { - int new_prec = token::get_binop_prec(tokens[0].get_token()) + 1; - // Handle right associative operators by reducing the new precedence by 1 - if (token::is_right_associative(tokens[0].get_token())) - new_prec--; - MAKE_SHARED(ast::AST_binop_Node, binop); - parse_binop(tokens, binop); - // Handle ternary operator - if (binop->get_op() == binop::BINOP::TERNARY) { - MAKE_SHARED(ast::AST_exp_Node, middle_exp); - // reset the precedence - parse_exp(tokens, middle_exp, 0); - root_exp->set_middle(std::move(middle_exp)); - EXPECT(token::TOKEN::COLON); - } - root_exp->set_binop_node(std::move(binop)); - MAKE_SHARED(ast::AST_exp_Node, rexp); - parse_exp(tokens, rexp, new_prec); - root_exp->set_right(std::move(rexp)); - if (token::is_binary_op(tokens[0].get_token()) and - token::get_binop_prec(tokens[0].get_token()) >= prec) { - MAKE_SHARED(ast::AST_exp_Node, new_root_exp); - new_root_exp->set_left(root_exp); - root_exp = new_root_exp; - } - } -} - -void parser::parse_binop(std::vector &tokens, - std::shared_ptr &binop) { - switch (tokens[0].get_token()) { - case token::TOKEN::PLUS: - binop->set_op(binop::BINOP::ADD); - break; - case token::TOKEN::PERCENT_SIGN: - binop->set_op(binop::BINOP::MOD); - break; - case token::TOKEN::FORWARD_SLASH: - binop->set_op(binop::BINOP::DIV); - break; - case token::TOKEN::ASTERISK: - binop->set_op(binop::BINOP::MUL); - break; - case token::TOKEN::HYPHEN: - binop->set_op(binop::BINOP::SUB); - break; - case token::TOKEN::AAND: - binop->set_op(binop::BINOP::AAND); - break; - case token::TOKEN::AOR: - binop->set_op(binop::BINOP::AOR); - break; - case token::TOKEN::XOR: - binop->set_op(binop::BINOP::XOR); - break; - case token::TOKEN::LEFT_SHIFT: - binop->set_op(binop::BINOP::LEFT_SHIFT); - break; - case token::TOKEN::RIGHT_SHIFT: - binop->set_op(binop::BINOP::RIGHT_SHIFT); - break; - case token::TOKEN::LAND: - binop->set_op(binop::BINOP::LAND); - break; - case token::TOKEN::LOR: - binop->set_op(binop::BINOP::LOR); - break; - case token::TOKEN::EQUAL: - binop->set_op(binop::BINOP::EQUAL); - break; - case token::TOKEN::NOTEQUAL: - binop->set_op(binop::BINOP::NOTEQUAL); - break; - case token::TOKEN::LESSTHAN: - binop->set_op(binop::BINOP::LESSTHAN); - break; - case token::TOKEN::GREATERTHAN: - binop->set_op(binop::BINOP::GREATERTHAN); - break; - case token::TOKEN::LESSTHANEQUAL: - binop->set_op(binop::BINOP::LESSTHANEQUAL); - break; - case token::TOKEN::GREATERTHANEQUAL: - binop->set_op(binop::BINOP::GREATERTHANEQUAL); - break; - case token::TOKEN::ASSIGNMENT: - binop->set_op(binop::BINOP::ASSIGN); - break; - case token::TOKEN::COMPOUND_DIFFERENCE: - binop->set_op(binop::BINOP::COMPOUND_DIFFERENCE); - break; - case token::TOKEN::COMPOUND_DIVISION: - binop->set_op(binop::BINOP::COMPOUND_DIVISION); - break; - case token::TOKEN::COMPOUND_PRODUCT: - binop->set_op(binop::BINOP::COMPOUND_PRODUCT); - break; - case token::TOKEN::COMPOUND_REMAINDER: - binop->set_op(binop::BINOP::COMPOUND_REMAINDER); - break; - case token::TOKEN::COMPOUND_SUM: - binop->set_op(binop::BINOP::COMPOUND_SUM); - break; - case token::TOKEN::COMPOUND_AND: - binop->set_op(binop::BINOP::COMPOUND_AND); - break; - case token::TOKEN::COMPOUND_OR: - binop->set_op(binop::BINOP::COMPOUND_OR); - break; - case token::TOKEN::COMPOUND_XOR: - binop->set_op(binop::BINOP::COMPOUND_XOR); - break; - case token::TOKEN::COMPOUND_LEFTSHIFT: - binop->set_op(binop::BINOP::COMPOUND_LEFTSHIFT); - break; - case token::TOKEN::COMPOUND_RIGHTSHIFT: - binop->set_op(binop::BINOP::COMPOUND_RIGHTSHIFT); - break; - case token::TOKEN::QUESTION_MARK: - binop->set_op(binop::BINOP::TERNARY); - break; - default: - success = false; - error_messages.emplace_back("Expected binary operator but got " + - to_string(tokens[0].get_token())); - break; - } - tokens.erase(tokens.begin()); -} - -void parser::parse_unary_op(std::vector &tokens, - std::shared_ptr &factor) { - MAKE_SHARED(ast::AST_unop_Node, unop); - switch (tokens[0].get_token()) { - case token::TOKEN::TILDE: - unop->set_op(unop::UNOP::COMPLEMENT); - break; - case token::TOKEN::HYPHEN: - unop->set_op(unop::UNOP::NEGATE); - break; - case token::TOKEN::NOT: - unop->set_op(unop::UNOP::NOT); - break; - case token::TOKEN::INCREMENT_OPERATOR: - unop->set_op(unop::UNOP::PREINCREMENT); - break; - case token::TOKEN::DECREMENT_OPERATOR: - unop->set_op(unop::UNOP::PREDECREMENT); - break; - default: - UNREACHABLE() - } - factor->add_unop_node(std::move(unop)); - tokens.erase(tokens.begin()); -} - -void parser::parse_identifier( - std::vector &tokens, - std::shared_ptr &function) { - EXPECT_IDENTIFIER(); - function->set_identifier(std::move(identifier)); -} - -void parser::parse_int(std::vector &tokens, - std::shared_ptr &factor) { - EXPECT_INT(token::TOKEN::CONSTANT); -} - void parser::expect(token::TOKEN actual_token, token::TOKEN expected_token) { if (actual_token != expected_token) { success = false; @@ -626,322 +18,13 @@ void parser::expect(token::TOKEN actual_token, token::TOKEN expected_token) { } } -void parser::analyze_exp( - std::shared_ptr exp, - std::map, std::string> &symbol_table, - int indx) { - if (exp == nullptr) - return; - analyze_exp(exp->get_left(), symbol_table, indx); - // here we check that the factor of the expresssion is not an undeclared - // variable - if (exp->get_factor_node() != nullptr and - exp->get_factor_node()->get_identifier_node() != nullptr) { - std::string var_name = - exp->get_factor_node()->get_identifier_node()->get_value(); - int level = indx; - bool found = false; - while (level >= 0) { - if (symbol_table.find({var_name, level}) != symbol_table.end()) { - exp->get_factor_node()->get_identifier_node()->set_identifier( - symbol_table[{var_name, level}]); - found = true; - break; - } - level--; - } - if (!found) { - success = false; - error_messages.emplace_back("Variable " + var_name + " not declared"); - } - } - - // now we check that if the exp is of type assignment, then factor is an - // identifier - if (exp->get_binop_node() != nullptr and - (exp->get_binop_node()->get_op() == binop::BINOP::ASSIGN or - binop::is_compound(exp->get_binop_node()->get_op()))) { - // ERROR CONDITION: (no factor node) or (factor node is a constant, not a - // variable) or (factor node is a variable but has unary operators) Here we - // exploit the benefit of short circuiting power of the logical operator - // this means that as we proceed, we are ensured that the earlier checks - // must not be satisfied. Note that an identifier with unops makes it an - // rvalue. - if (exp->get_factor_node() == nullptr or - exp->get_factor_node()->get_identifier_node() == nullptr or - exp->get_factor_node()->get_unop_nodes().size() > 0) { - success = false; - error_messages.emplace_back("Expected a modifiable lvalue on the left " - "side of the assignment operator"); - } - } - // SEMANTIC ANALYSIS FOR INCREMENT AND DECREMENT OPERATOR - if (exp->get_factor_node() != nullptr) { - auto check_factor = exp->get_factor_node(); - bool has_i_d = false; - bool has_multiple_i_d = false; - // CHECK WHETHER INCREMENT OR DECREMENT OPERATOR IS PRESENT - for (auto it : check_factor->get_unop_nodes()) { - if (it->get_op() == unop::UNOP::PREINCREMENT or - it->get_op() == unop::UNOP::PREDECREMENT or - it->get_op() == unop::UNOP::POSTINCREMENT or - it->get_op() == unop::UNOP::POSTDECREMENT) { - if (has_i_d) { - has_multiple_i_d = true; - break; - } - has_i_d = true; - } - } - if (has_multiple_i_d) { - success = false; - error_messages.emplace_back( - "Expected an lvalue for the increment / decrement operator"); - } else if (has_i_d) { - // THE INCREMENT AND DECREMENT OPERATOR MUST BE APPLIED TO AN LVALUE - // THAT MEANS IT SHOULD BE THE LAST UNOP IN THE UNOPS VECTOR - if (check_factor->get_unop_nodes().back()->get_op() != - unop::UNOP::PREINCREMENT and - check_factor->get_unop_nodes().back()->get_op() != - unop::UNOP::PREDECREMENT and - check_factor->get_unop_nodes().back()->get_op() != - unop::UNOP::POSTINCREMENT and - check_factor->get_unop_nodes().back()->get_op() != - unop::UNOP::POSTDECREMENT) { - success = false; - error_messages.emplace_back( - "Expected an lvalue for the increment / decrement operator"); - } else { - // NOW THERE ARE ONLY TWO VALID CASES - // CASE 1: FACTOR HAS AN IDENTIFIER - // CASE 2: FACTOR HAS A DEEPLY NESTED EXPRESSION WHICH THEN - // CONTAINS THE IDENTIFIER (eg. ++(((((((a))))))) ) - // or ( (((((((a)))))))++ ) - if (check_factor->get_identifier_node() != nullptr) { - // EARLIER CHECKS ENSURE THAT THE IDENTIFIER IS ALREADY DECLARED - } else if (check_factor->get_exp_node() != nullptr) { - // NOW WE RECURSIVELY CHECK THAT THE EXPRESSION IS A SIMPLE IDENTIFIER - // AND NOT A COMPLEX EXPRESSION - auto check_exp = check_factor->get_exp_node(); - while (check_exp != nullptr) { - // ENSURE THAT BINOP FOR CHECK_EXP IS NULL - // ENSURE THAT LEFT FOR CHECK_EXP IS NULL - if (check_exp->get_binop_node() != nullptr or - check_exp->get_left() != nullptr) { - success = false; - error_messages.emplace_back( - "Expected an lvalue for the increment / decrement operator"); - break; - } - // ENSURE THAT THERE ARE NO UNOPS AS WELL - // WE ARE BASICALLY GUARANTEED THAT FACTOR IS NOT NULL - if (check_exp->get_factor_node()->get_unop_nodes().size() > 0) { - success = false; - error_messages.emplace_back( - "Expected an lvalue for the increment / decrement operator"); - break; - } - // NOW WE CHECK THAT THE FACTOR IS AN IDENTIFIER - if (exp->get_factor_node()->get_exp_node() == nullptr) { - if (exp->get_factor_node()->get_identifier_node() == nullptr) { - success = false; - error_messages.emplace_back("Expected an lvalue for the " - "increment / decrement operator"); - break; - } - } - check_exp = check_exp->get_factor_node()->get_exp_node(); - } - } else { - success = false; - error_messages.emplace_back( - "Expected an lvalue for the increment / decrement operator"); - } - } - } - } - // since the factor can have its own exp as well, we recursively check that - if (exp->get_factor_node() != nullptr) - analyze_exp(exp->get_factor_node()->get_exp_node(), symbol_table, indx); - // now we recursively check the right side of the expression - if (exp->get_right() != nullptr) - analyze_exp(exp->get_right(), symbol_table, indx); - // and a recursive check for the middle expression -> special case(ternary - // operator) - if (exp->get_middle() != nullptr) - analyze_exp(exp->get_middle(), symbol_table, indx); -} - -void parser::analyze_declaration( - std::shared_ptr declaration, - std::map, std::string> &symbol_table, - int indx) { - std::string var_name = declaration->get_identifier()->get_value(); - if (symbol_table.find({var_name, indx}) != symbol_table.end()) { - // the symbol has been declared twice which is illegal - success = false; - error_messages.emplace_back("Variable " + var_name + " already declared"); - } else { - symbol_table[{var_name, indx}] = get_temp_name(var_name); - declaration->get_identifier()->set_identifier( - symbol_table[{var_name, indx}]); - if (declaration->get_exp() != nullptr) - analyze_exp(declaration->get_exp(), symbol_table, indx); - } -} - -void parser::analyze_statement( - std::shared_ptr statement, - std::map, std::string> &symbol_table, - int indx) { - - // every variable that is used in any of the statement should already - // have been declared. - - // We need to check that the labels used in goto statements are - // actually declared and we also need to make sure that there are no - // duplicate labels - - switch (statement->get_type()) { - case ast::statementType::RETURN: - analyze_exp(statement->get_exps(), symbol_table, indx); - break; - case ast::statementType::IF: { - auto if_statement = - std::static_pointer_cast(statement); - analyze_exp(if_statement->get_exps(), symbol_table, indx); - analyze_statement(if_statement->get_stmt1(), symbol_table, indx); - } break; - case ast::statementType::IFELSE: { - auto if_else_statement = - std::static_pointer_cast(statement); - analyze_exp(if_else_statement->get_exps(), symbol_table, indx); - analyze_statement(if_else_statement->get_stmt1(), symbol_table, indx); - analyze_statement(if_else_statement->get_stmt2(), symbol_table, indx); - } break; - case ast::statementType::WHILE: - case ast::statementType::DO_WHILE: { - auto while_statement = - std::static_pointer_cast(statement); - analyze_exp(while_statement->get_exps(), symbol_table, indx); - analyze_statement(while_statement->get_stmt(), symbol_table, indx); - } break; - case ast::statementType::FOR: - analyze_for_statement( - std::static_pointer_cast(statement), - symbol_table, indx); - break; - case ast::statementType::BLOCK: { - auto block_statement = - std::static_pointer_cast(statement); - std::map, std::string> proxy_symbol_table( - symbol_table); - analyze_block(block_statement->get_block(), proxy_symbol_table, indx + 1); - } break; - case ast::statementType::GOTO: { - std::string label = statement->get_labels().first->get_value(); - if (goto_labels.find(label) == goto_labels.end()) { - goto_labels[label] = false; - } - } break; - case ast::statementType::LABEL: { - std::string label = statement->get_labels().first->get_value(); - if (goto_labels.find(label) != goto_labels.end()) { - if (goto_labels[label] == false) { - goto_labels[label] = true; - } else { - success = false; - error_messages.emplace_back("Label " + label + " already declared"); - } - } else { - goto_labels[label] = true; - } - } break; - case ast::statementType::EXP: - analyze_exp(statement->get_exps(), symbol_table, indx); - break; - case ast::statementType::NULLSTMT: - case ast::statementType::CONTINUE: - case ast::statementType::BREAK: - break; - case ast::statementType::UNKNOWN: - UNREACHABLE() - } -} - -void parser::analyze_for_statement( - std::shared_ptr for_statement, - std::map, std::string> &symbol_table, - int indx) { - // When init is null or init is a simple expression, then - // we don't need to add another level to the symbol table - if (for_statement->get_for_init() == nullptr) { - analyze_exp(for_statement->get_exps(), symbol_table, indx); - analyze_exp(for_statement->get_exp2(), symbol_table, indx); - if (for_statement->get_stmt()->get_type() == ast::statementType::FOR) { - auto forstmt = std::static_pointer_cast( - for_statement->get_stmt()); - analyze_for_statement(forstmt, symbol_table, indx); - } else { - analyze_statement(for_statement->get_stmt(), symbol_table, indx); - } - } else if (for_statement->get_for_init()->get_declaration() == nullptr) { - analyze_exp(for_statement->get_for_init()->get_exp(), symbol_table, indx); - analyze_exp(for_statement->get_exps(), symbol_table, indx); - analyze_exp(for_statement->get_exp2(), symbol_table, indx); - if (for_statement->get_stmt()->get_type() == ast::statementType::FOR) { - auto forstmt = std::static_pointer_cast( - for_statement->get_stmt()); - analyze_for_statement(forstmt, symbol_table, indx); - } else { - analyze_statement(for_statement->get_stmt(), symbol_table, indx); - } - } else { - // Add another level to the symbol table - std::map, std::string> proxy_symbol_table( - symbol_table); - analyze_declaration(for_statement->get_for_init()->get_declaration(), - proxy_symbol_table, indx + 1); - analyze_exp(for_statement->get_exps(), proxy_symbol_table, indx + 1); - analyze_exp(for_statement->get_exp2(), proxy_symbol_table, indx + 1); - if (for_statement->get_stmt()->get_type() == ast::statementType::FOR) { - auto forstmt = std::static_pointer_cast( - for_statement->get_stmt()); - analyze_for_statement(forstmt, proxy_symbol_table, indx + 1); - } else { - analyze_statement(for_statement->get_stmt(), proxy_symbol_table, - indx + 1); - } - } -} - -// NOTE: symbol table here is a map from {variable_name, block_indx} -> -// temporary_variable_name(used as scar registers later) -void parser::analyze_block( - std::shared_ptr block, - std::map, std::string> &symbol_table, - int indx) { - if (block == nullptr) - return; - auto block_item = block->get_blockItems().begin(); - auto block_end = block->get_blockItems().end(); - while (block_item != block_end) { - if (((*block_item)->get_type()) == ast::BlockItemType::DECLARATION) { - analyze_declaration((*block_item)->get_declaration(), symbol_table, indx); - } else if ((*block_item)->get_type() == ast::BlockItemType::STATEMENT) { - analyze_statement((*block_item)->get_statement(), symbol_table, indx); - } - block_item++; - } -} - void parser::semantic_analysis() { // variable resolution for (auto funcs : program.get_functions()) { std::map, std::string> symbol_table; analyze_block(funcs->get_block(), symbol_table, 0); } - // Check that all varaibles are declared + // Check that all labels are declared for (auto label : goto_labels) { if (label.second == false) { success = false; @@ -963,237 +46,6 @@ void parser::eof_error(token::Token token) { " but got end of file"); } -std::string to_string(ast::BlockItemType type) { - switch (type) { - case ast::BlockItemType::STATEMENT: - return "Statement"; - case ast::BlockItemType::DECLARATION: - return "Declaration"; - case ast::BlockItemType::UNKNOWN: - UNREACHABLE() - } - UNREACHABLE() -} - -std::string to_string(ast::statementType type) { - switch (type) { - case ast::statementType::NULLSTMT: - return "NullStmt"; - case ast::statementType::RETURN: - return "Return"; - case ast::statementType::EXP: - return "Exp"; - case ast::statementType::IF: - return "If"; - case ast::statementType::IFELSE: - return "IfElse"; - case ast::statementType::GOTO: - return "Goto"; - case ast::statementType::LABEL: - return "Label"; - case ast::statementType::BLOCK: - return "Block"; - case ast::statementType::CONTINUE: - return "Continue"; - case ast::statementType::BREAK: - return "Break"; - case ast::statementType::WHILE: - return "While"; - case ast::statementType::DO_WHILE: - return "DoWhile"; - case ast::statementType::FOR: - return "For"; - case ast::statementType::UNKNOWN: - UNREACHABLE() - } - return ""; -} - -void parser::pretty_print_factor(std::shared_ptr factor) { - if (!factor->get_unop_nodes().empty()) { - std::cout << "Unop( "; - for (auto unop : factor->get_unop_nodes()) { - std::cout << unop::to_string(unop->get_op()) << ", "; - } - } - if (factor->get_exp_node() != nullptr) { - pretty_print_exp(factor->get_exp_node()); - } else if (factor->get_int_node() != nullptr) { - std::cout << factor->get_int_node()->get_AST_name() << "(" - << factor->get_int_node()->get_value() << ")"; - if (!factor->get_unop_nodes().empty()) { - std::cout << ")"; - } - } else { - std::cout << factor->get_identifier_node()->get_AST_name() << "(" - << factor->get_identifier_node()->get_value() << ")"; - if (!factor->get_unop_nodes().empty()) { - std::cout << ")"; - } - } -} - -void parser::pretty_print_exp(std::shared_ptr exp) { - if (exp == nullptr) - return; - pretty_print_exp(exp->get_left()); - if (exp->get_binop_node() != nullptr and - exp->get_binop_node()->get_op() != binop::BINOP::UNKNOWN) { - std::cout << "\t\t\t\t\tBinop(" - << binop::to_string(exp->get_binop_node()->get_op()) << " ,"; - if (exp->get_left() == nullptr) { - pretty_print_factor(exp->get_factor_node()); - } else { - std::cout << "Earlier, "; - } - if (exp->get_middle() != nullptr) { - pretty_print_exp(exp->get_middle()); - std::cout << ", "; - } - pretty_print_exp(exp->get_right()); - std::cout << ")" << std::endl; - } else { - std::cout << "\t\t\t\t\t"; - pretty_print_factor(exp->get_factor_node()); - std::cout << std::endl; - } -} - -void parser::pretty_print_declaration( - std::shared_ptr declaration) { - if (declaration == nullptr) - return; - std::cout << "\t\t\tDeclaration=(" << std::endl; - std::cout << "\t\t\t\tidentifier=\"" - << declaration->get_identifier()->get_value() << "\"," << std::endl; - if (declaration->get_exp() != nullptr) { - std::cout << "\t\t\t\texp=(" << std::endl; - pretty_print_exp(declaration->get_exp()); - std::cout << "\t\t\t\t)," << std::endl; - } - std::cout << "\t\t\t)" << std::endl; -} - -void parser::pretty_print_statement( - std::shared_ptr statement) { - if (statement == nullptr) - return; - std::cout << "\t\t\tStatement=(" << std::endl; - std::cout << "\t\t\t\ttype=" << to_string(statement->get_type()) << "," - << std::endl; - switch (statement->get_type()) { - case ast::statementType::RETURN: - pretty_print_exp(statement->get_exps()); - break; - case ast::statementType::IF: { - auto if_statement = - std::static_pointer_cast(statement); - std::cout << "\t\t\t\tlabels=(" - << if_statement->get_labels().first->get_value() << "," - << if_statement->get_labels().second->get_value() << ")," - << std::endl; - std::cout << "\t\t\t\texps=(" << std::endl; - pretty_print_exp(if_statement->get_exps()); - std::cout << "\t\t\t\t)," << std::endl; - std::cout << "\t\t\t\tstmt1=(" << std::endl; - pretty_print_statement(if_statement->get_stmt1()); - std::cout << "\t\t\t\t)" << std::endl; - } break; - case ast::statementType::IFELSE: { - auto if_else_statement = - std::static_pointer_cast(statement); - std::cout << "\t\t\t\tlabels=(" - << if_else_statement->get_labels().first->get_value() << "," - << if_else_statement->get_labels().second->get_value() << ")," - << std::endl; - std::cout << "\t\t\t\texps=(" << std::endl; - pretty_print_exp(if_else_statement->get_exps()); - std::cout << "\t\t\t\t)," << std::endl; - std::cout << "\t\t\t\tstmt1=(" << std::endl; - pretty_print_statement(if_else_statement->get_stmt1()); - std::cout << "\t\t\t\t)," << std::endl; - std::cout << "\t\t\t\tstmt2=(" << std::endl; - pretty_print_statement(if_else_statement->get_stmt2()); - std::cout << "\t\t\t\t)" << std::endl; - } break; - case ast::statementType::WHILE: - case ast::statementType::DO_WHILE: { - auto while_statement = - std::static_pointer_cast(statement); - std::cout << "\t\t\t\tlabels=(" - << while_statement->get_labels().first->get_value() << "," - << while_statement->get_labels().second->get_value() << ")," - << std::endl; - std::cout << "\t\t\t\texps=(" << std::endl; - pretty_print_exp(while_statement->get_exps()); - std::cout << "\t\t\t\t)," << std::endl; - std::cout << "\t\t\t\tstmt=(" << std::endl; - pretty_print_statement(while_statement->get_stmt()); - std::cout << "\t\t\t\t)" << std::endl; - } break; - case ast::statementType::FOR: { - auto for_statement = - std::static_pointer_cast(statement); - std::cout << "\t\t\t\tlabels=(" - << for_statement->get_labels().first->get_value() << "," - << for_statement->get_labels().second->get_value() << ")," - << std::endl; - if (for_statement->get_for_init() != nullptr) { - std::cout << "\t\t\t\tfor_init=(" << std::endl; - if (for_statement->get_for_init()->get_declaration() != nullptr) { - pretty_print_declaration( - for_statement->get_for_init()->get_declaration()); - } else { - pretty_print_exp(for_statement->get_for_init()->get_exp()); - } - std::cout << "\t\t\t\t)," << std::endl; - } - std::cout << "\t\t\t\tcondition=(" << std::endl; - pretty_print_exp(for_statement->get_exps()); - std::cout << "\t\t\t\t)," << std::endl; - std::cout << "\t\t\t\tpost=(" << std::endl; - pretty_print_exp(for_statement->get_exp2()); - std::cout << "\t\t\t\t)," << std::endl; - std::cout << "\t\t\t\tstmt=(" << std::endl; - pretty_print_statement(for_statement->get_stmt()); - std::cout << "\t\t\t\t)" << std::endl; - } break; - case ast::statementType::BLOCK: { - auto block_statement = - std::static_pointer_cast(statement); - pretty_print_block(block_statement->get_block()); - } break; - case ast::statementType::GOTO: - case ast::statementType::LABEL: - case ast::statementType::CONTINUE: - case ast::statementType::BREAK: - std::cout << "\t\t\t\tlabel=(" << statement->get_labels().first->get_value() - << ")" << std::endl; - break; - case ast::statementType::EXP: - pretty_print_exp(statement->get_exps()); - break; - case ast::statementType::NULLSTMT: - break; - case ast::statementType::UNKNOWN: - UNREACHABLE() - } -} - -void parser::pretty_print_block(std::shared_ptr block) { - if (block == nullptr) - return; - std::cout << "\t\t\t" << "Block=(" << std::endl; - for (auto blockItem : block->get_blockItems()) { - if (blockItem->get_type() == ast::BlockItemType::DECLARATION) { - pretty_print_declaration(blockItem->get_declaration()); - } else { - pretty_print_statement(blockItem->get_statement()); - } - } - std::cout << "\t\t\t)" << std::endl; -} - void parser::pretty_print() { std::cout << "Program(" << std::endl; for (auto function : program.get_functions()) { diff --git a/parser/pretty_print/pretty_print_block.cc b/parser/pretty_print/pretty_print_block.cc new file mode 100644 index 0000000..944852c --- /dev/null +++ b/parser/pretty_print/pretty_print_block.cc @@ -0,0 +1,21 @@ +#include + +namespace scarlet { +namespace parser { + +void parser::pretty_print_block(std::shared_ptr block) { + if (block == nullptr) + return; + std::cout << "\t\t\t" << "Block=(" << std::endl; + for (auto blockItem : block->get_blockItems()) { + if (blockItem->get_type() == ast::BlockItemType::DECLARATION) { + pretty_print_declaration(blockItem->get_declaration()); + } else { + pretty_print_statement(blockItem->get_statement()); + } + } + std::cout << "\t\t\t)" << std::endl; +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/pretty_print/pretty_print_declaration.cc b/parser/pretty_print/pretty_print_declaration.cc new file mode 100644 index 0000000..75f0c14 --- /dev/null +++ b/parser/pretty_print/pretty_print_declaration.cc @@ -0,0 +1,22 @@ +#include + +namespace scarlet { +namespace parser { + +void parser::pretty_print_declaration( + std::shared_ptr declaration) { + if (declaration == nullptr) + return; + std::cout << "\t\t\tDeclaration=(" << std::endl; + std::cout << "\t\t\t\tidentifier=\"" + << declaration->get_identifier()->get_value() << "\"," << std::endl; + if (declaration->get_exp() != nullptr) { + std::cout << "\t\t\t\texp=(" << std::endl; + pretty_print_exp(declaration->get_exp()); + std::cout << "\t\t\t\t)," << std::endl; + } + std::cout << "\t\t\t)" << std::endl; +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/pretty_print/pretty_print_expression.cc b/parser/pretty_print/pretty_print_expression.cc new file mode 100644 index 0000000..a58f535 --- /dev/null +++ b/parser/pretty_print/pretty_print_expression.cc @@ -0,0 +1,57 @@ +#include + +namespace scarlet { +namespace parser { + +void parser::pretty_print_factor(std::shared_ptr factor) { + if (!factor->get_unop_nodes().empty()) { + std::cout << "Unop( "; + for (auto unop : factor->get_unop_nodes()) { + std::cout << unop::to_string(unop->get_op()) << ", "; + } + } + if (factor->get_exp_node() != nullptr) { + pretty_print_exp(factor->get_exp_node()); + } else if (factor->get_int_node() != nullptr) { + std::cout << factor->get_int_node()->get_AST_name() << "(" + << factor->get_int_node()->get_value() << ")"; + if (!factor->get_unop_nodes().empty()) { + std::cout << ")"; + } + } else { + std::cout << factor->get_identifier_node()->get_AST_name() << "(" + << factor->get_identifier_node()->get_value() << ")"; + if (!factor->get_unop_nodes().empty()) { + std::cout << ")"; + } + } +} + +void parser::pretty_print_exp(std::shared_ptr exp) { + if (exp == nullptr) + return; + pretty_print_exp(exp->get_left()); + if (exp->get_binop_node() != nullptr and + exp->get_binop_node()->get_op() != binop::BINOP::UNKNOWN) { + std::cout << "\t\t\t\t\tBinop(" + << binop::to_string(exp->get_binop_node()->get_op()) << " ,"; + if (exp->get_left() == nullptr) { + pretty_print_factor(exp->get_factor_node()); + } else { + std::cout << "Earlier, "; + } + if (exp->get_middle() != nullptr) { + pretty_print_exp(exp->get_middle()); + std::cout << ", "; + } + pretty_print_exp(exp->get_right()); + std::cout << ")" << std::endl; + } else { + std::cout << "\t\t\t\t\t"; + pretty_print_factor(exp->get_factor_node()); + std::cout << std::endl; + } +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/pretty_print/pretty_print_statement.cc b/parser/pretty_print/pretty_print_statement.cc new file mode 100644 index 0000000..28451f6 --- /dev/null +++ b/parser/pretty_print/pretty_print_statement.cc @@ -0,0 +1,147 @@ +#include + +namespace scarlet { +namespace parser { + +std::string to_string(ast::statementType type) { + switch (type) { + case ast::statementType::NULLSTMT: + return "NullStmt"; + case ast::statementType::RETURN: + return "Return"; + case ast::statementType::EXP: + return "Exp"; + case ast::statementType::IF: + return "If"; + case ast::statementType::IFELSE: + return "IfElse"; + case ast::statementType::GOTO: + return "Goto"; + case ast::statementType::LABEL: + return "Label"; + case ast::statementType::BLOCK: + return "Block"; + case ast::statementType::CONTINUE: + return "Continue"; + case ast::statementType::BREAK: + return "Break"; + case ast::statementType::WHILE: + return "While"; + case ast::statementType::DO_WHILE: + return "DoWhile"; + case ast::statementType::FOR: + return "For"; + case ast::statementType::UNKNOWN: + UNREACHABLE() + } + return ""; +} + +void parser::pretty_print_statement( + std::shared_ptr statement) { + if (statement == nullptr) + return; + std::cout << "\t\t\tStatement=(" << std::endl; + std::cout << "\t\t\t\ttype=" << to_string(statement->get_type()) << "," + << std::endl; + switch (statement->get_type()) { + case ast::statementType::RETURN: + pretty_print_exp(statement->get_exps()); + break; + case ast::statementType::IF: { + auto if_statement = + std::static_pointer_cast(statement); + std::cout << "\t\t\t\tlabels=(" + << if_statement->get_labels().first->get_value() << "," + << if_statement->get_labels().second->get_value() << ")," + << std::endl; + std::cout << "\t\t\t\texps=(" << std::endl; + pretty_print_exp(if_statement->get_exps()); + std::cout << "\t\t\t\t)," << std::endl; + std::cout << "\t\t\t\tstmt1=(" << std::endl; + pretty_print_statement(if_statement->get_stmt1()); + std::cout << "\t\t\t\t)" << std::endl; + } break; + case ast::statementType::IFELSE: { + auto if_else_statement = + std::static_pointer_cast(statement); + std::cout << "\t\t\t\tlabels=(" + << if_else_statement->get_labels().first->get_value() << "," + << if_else_statement->get_labels().second->get_value() << ")," + << std::endl; + std::cout << "\t\t\t\texps=(" << std::endl; + pretty_print_exp(if_else_statement->get_exps()); + std::cout << "\t\t\t\t)," << std::endl; + std::cout << "\t\t\t\tstmt1=(" << std::endl; + pretty_print_statement(if_else_statement->get_stmt1()); + std::cout << "\t\t\t\t)," << std::endl; + std::cout << "\t\t\t\tstmt2=(" << std::endl; + pretty_print_statement(if_else_statement->get_stmt2()); + std::cout << "\t\t\t\t)" << std::endl; + } break; + case ast::statementType::WHILE: + case ast::statementType::DO_WHILE: { + auto while_statement = + std::static_pointer_cast(statement); + std::cout << "\t\t\t\tlabels=(" + << while_statement->get_labels().first->get_value() << "," + << while_statement->get_labels().second->get_value() << ")," + << std::endl; + std::cout << "\t\t\t\texps=(" << std::endl; + pretty_print_exp(while_statement->get_exps()); + std::cout << "\t\t\t\t)," << std::endl; + std::cout << "\t\t\t\tstmt=(" << std::endl; + pretty_print_statement(while_statement->get_stmt()); + std::cout << "\t\t\t\t)" << std::endl; + } break; + case ast::statementType::FOR: { + auto for_statement = + std::static_pointer_cast(statement); + std::cout << "\t\t\t\tlabels=(" + << for_statement->get_labels().first->get_value() << "," + << for_statement->get_labels().second->get_value() << ")," + << std::endl; + if (for_statement->get_for_init() != nullptr) { + std::cout << "\t\t\t\tfor_init=(" << std::endl; + if (for_statement->get_for_init()->get_declaration() != nullptr) { + pretty_print_declaration( + for_statement->get_for_init()->get_declaration()); + } else { + pretty_print_exp(for_statement->get_for_init()->get_exp()); + } + std::cout << "\t\t\t\t)," << std::endl; + } + std::cout << "\t\t\t\tcondition=(" << std::endl; + pretty_print_exp(for_statement->get_exps()); + std::cout << "\t\t\t\t)," << std::endl; + std::cout << "\t\t\t\tpost=(" << std::endl; + pretty_print_exp(for_statement->get_exp2()); + std::cout << "\t\t\t\t)," << std::endl; + std::cout << "\t\t\t\tstmt=(" << std::endl; + pretty_print_statement(for_statement->get_stmt()); + std::cout << "\t\t\t\t)" << std::endl; + } break; + case ast::statementType::BLOCK: { + auto block_statement = + std::static_pointer_cast(statement); + pretty_print_block(block_statement->get_block()); + } break; + case ast::statementType::GOTO: + case ast::statementType::LABEL: + case ast::statementType::CONTINUE: + case ast::statementType::BREAK: + std::cout << "\t\t\t\tlabel=(" << statement->get_labels().first->get_value() + << ")" << std::endl; + break; + case ast::statementType::EXP: + pretty_print_exp(statement->get_exps()); + break; + case ast::statementType::NULLSTMT: + break; + case ast::statementType::UNKNOWN: + UNREACHABLE() + } +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/semantic_analysis/analyze_block.cc b/parser/semantic_analysis/analyze_block.cc new file mode 100644 index 0000000..4db93ac --- /dev/null +++ b/parser/semantic_analysis/analyze_block.cc @@ -0,0 +1,27 @@ +#include + +namespace scarlet { +namespace parser { + +// NOTE: symbol table here is a map from {variable_name, block_indx} -> +// temporary_variable_name(used as scar registers later) +void parser::analyze_block( + std::shared_ptr block, + std::map, std::string> &symbol_table, + int indx) { + if (block == nullptr) + return; + auto block_item = block->get_blockItems().begin(); + auto block_end = block->get_blockItems().end(); + while (block_item != block_end) { + if (((*block_item)->get_type()) == ast::BlockItemType::DECLARATION) { + analyze_declaration((*block_item)->get_declaration(), symbol_table, indx); + } else if ((*block_item)->get_type() == ast::BlockItemType::STATEMENT) { + analyze_statement((*block_item)->get_statement(), symbol_table, indx); + } + block_item++; + } +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/semantic_analysis/analyze_declaration.cc b/parser/semantic_analysis/analyze_declaration.cc new file mode 100644 index 0000000..377a945 --- /dev/null +++ b/parser/semantic_analysis/analyze_declaration.cc @@ -0,0 +1,25 @@ +#include + +namespace scarlet { +namespace parser { + +void parser::analyze_declaration( + std::shared_ptr declaration, + std::map, std::string> &symbol_table, + int indx) { + std::string var_name = declaration->get_identifier()->get_value(); + if (symbol_table.find({var_name, indx}) != symbol_table.end()) { + // the symbol has been declared twice which is illegal + success = false; + error_messages.emplace_back("Variable " + var_name + " already declared"); + } else { + symbol_table[{var_name, indx}] = get_temp_name(var_name); + declaration->get_identifier()->set_identifier( + symbol_table[{var_name, indx}]); + if (declaration->get_exp() != nullptr) + analyze_exp(declaration->get_exp(), symbol_table, indx); + } +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/semantic_analysis/analyze_expression.cc b/parser/semantic_analysis/analyze_expression.cc new file mode 100644 index 0000000..b22ff3a --- /dev/null +++ b/parser/semantic_analysis/analyze_expression.cc @@ -0,0 +1,153 @@ +#include + +namespace scarlet { +namespace parser { + +void parser::analyze_exp( + std::shared_ptr exp, + std::map, std::string> &symbol_table, + int indx) { + if (exp == nullptr) + return; + analyze_exp(exp->get_left(), symbol_table, indx); + // here we check that the factor of the expresssion is not an undeclared + // variable + if (exp->get_factor_node() != nullptr and + exp->get_factor_node()->get_identifier_node() != nullptr) { + std::string var_name = + exp->get_factor_node()->get_identifier_node()->get_value(); + int level = indx; + bool found = false; + while (level >= 0) { + if (symbol_table.find({var_name, level}) != symbol_table.end()) { + exp->get_factor_node()->get_identifier_node()->set_identifier( + symbol_table[{var_name, level}]); + found = true; + break; + } + level--; + } + if (!found) { + success = false; + error_messages.emplace_back("Variable " + var_name + " not declared"); + } + } + + // now we check that if the exp is of type assignment, then factor is an + // identifier + if (exp->get_binop_node() != nullptr and + (exp->get_binop_node()->get_op() == binop::BINOP::ASSIGN or + binop::is_compound(exp->get_binop_node()->get_op()))) { + // ERROR CONDITION: (no factor node) or (factor node is a constant, not a + // variable) or (factor node is a variable but has unary operators) Here we + // exploit the benefit of short circuiting power of the logical operator + // this means that as we proceed, we are ensured that the earlier checks + // must not be satisfied. Note that an identifier with unops makes it an + // rvalue. + if (exp->get_factor_node() == nullptr or + exp->get_factor_node()->get_identifier_node() == nullptr or + exp->get_factor_node()->get_unop_nodes().size() > 0) { + success = false; + error_messages.emplace_back("Expected a modifiable lvalue on the left " + "side of the assignment operator"); + } + } + // SEMANTIC ANALYSIS FOR INCREMENT AND DECREMENT OPERATOR + if (exp->get_factor_node() != nullptr) { + auto check_factor = exp->get_factor_node(); + bool has_i_d = false; + bool has_multiple_i_d = false; + // CHECK WHETHER INCREMENT OR DECREMENT OPERATOR IS PRESENT + for (auto it : check_factor->get_unop_nodes()) { + if (it->get_op() == unop::UNOP::PREINCREMENT or + it->get_op() == unop::UNOP::PREDECREMENT or + it->get_op() == unop::UNOP::POSTINCREMENT or + it->get_op() == unop::UNOP::POSTDECREMENT) { + if (has_i_d) { + has_multiple_i_d = true; + break; + } + has_i_d = true; + } + } + if (has_multiple_i_d) { + success = false; + error_messages.emplace_back( + "Expected an lvalue for the increment / decrement operator"); + } else if (has_i_d) { + // THE INCREMENT AND DECREMENT OPERATOR MUST BE APPLIED TO AN LVALUE + // THAT MEANS IT SHOULD BE THE LAST UNOP IN THE UNOPS VECTOR + if (check_factor->get_unop_nodes().back()->get_op() != + unop::UNOP::PREINCREMENT and + check_factor->get_unop_nodes().back()->get_op() != + unop::UNOP::PREDECREMENT and + check_factor->get_unop_nodes().back()->get_op() != + unop::UNOP::POSTINCREMENT and + check_factor->get_unop_nodes().back()->get_op() != + unop::UNOP::POSTDECREMENT) { + success = false; + error_messages.emplace_back( + "Expected an lvalue for the increment / decrement operator"); + } else { + // NOW THERE ARE ONLY TWO VALID CASES + // CASE 1: FACTOR HAS AN IDENTIFIER + // CASE 2: FACTOR HAS A DEEPLY NESTED EXPRESSION WHICH THEN + // CONTAINS THE IDENTIFIER (eg. ++(((((((a))))))) ) + // or ( (((((((a)))))))++ ) + if (check_factor->get_identifier_node() != nullptr) { + // EARLIER CHECKS ENSURE THAT THE IDENTIFIER IS ALREADY DECLARED + } else if (check_factor->get_exp_node() != nullptr) { + // NOW WE RECURSIVELY CHECK THAT THE EXPRESSION IS A SIMPLE IDENTIFIER + // AND NOT A COMPLEX EXPRESSION + auto check_exp = check_factor->get_exp_node(); + while (check_exp != nullptr) { + // ENSURE THAT BINOP FOR CHECK_EXP IS NULL + // ENSURE THAT LEFT FOR CHECK_EXP IS NULL + if (check_exp->get_binop_node() != nullptr or + check_exp->get_left() != nullptr) { + success = false; + error_messages.emplace_back( + "Expected an lvalue for the increment / decrement operator"); + break; + } + // ENSURE THAT THERE ARE NO UNOPS AS WELL + // WE ARE BASICALLY GUARANTEED THAT FACTOR IS NOT NULL + if (check_exp->get_factor_node()->get_unop_nodes().size() > 0) { + success = false; + error_messages.emplace_back( + "Expected an lvalue for the increment / decrement operator"); + break; + } + // NOW WE CHECK THAT THE FACTOR IS AN IDENTIFIER + if (exp->get_factor_node()->get_exp_node() == nullptr) { + if (exp->get_factor_node()->get_identifier_node() == nullptr) { + success = false; + error_messages.emplace_back("Expected an lvalue for the " + "increment / decrement operator"); + break; + } + } + check_exp = check_exp->get_factor_node()->get_exp_node(); + } + } else { + success = false; + error_messages.emplace_back( + "Expected an lvalue for the increment / decrement operator"); + } + } + } + } + // since the factor can have its own exp as well, we recursively check that + if (exp->get_factor_node() != nullptr) + analyze_exp(exp->get_factor_node()->get_exp_node(), symbol_table, indx); + // now we recursively check the right side of the expression + if (exp->get_right() != nullptr) + analyze_exp(exp->get_right(), symbol_table, indx); + // and a recursive check for the middle expression -> special case(ternary + // operator) + if (exp->get_middle() != nullptr) + analyze_exp(exp->get_middle(), symbol_table, indx); +} + +} // namespace parser +} // namespace scarlet diff --git a/parser/semantic_analysis/analyze_statement.cc b/parser/semantic_analysis/analyze_statement.cc new file mode 100644 index 0000000..7bb8660 --- /dev/null +++ b/parser/semantic_analysis/analyze_statement.cc @@ -0,0 +1,132 @@ +#include + +namespace scarlet { +namespace parser { + +void parser::analyze_statement( + std::shared_ptr statement, + std::map, std::string> &symbol_table, + int indx) { + + // every variable that is used in any of the statement should already + // have been declared. + + // We need to check that the labels used in goto statements are + // actually declared and we also need to make sure that there are no + // duplicate labels + + switch (statement->get_type()) { + case ast::statementType::RETURN: + analyze_exp(statement->get_exps(), symbol_table, indx); + break; + case ast::statementType::IF: { + auto if_statement = + std::static_pointer_cast(statement); + analyze_exp(if_statement->get_exps(), symbol_table, indx); + analyze_statement(if_statement->get_stmt1(), symbol_table, indx); + } break; + case ast::statementType::IFELSE: { + auto if_else_statement = + std::static_pointer_cast(statement); + analyze_exp(if_else_statement->get_exps(), symbol_table, indx); + analyze_statement(if_else_statement->get_stmt1(), symbol_table, indx); + analyze_statement(if_else_statement->get_stmt2(), symbol_table, indx); + } break; + case ast::statementType::WHILE: + case ast::statementType::DO_WHILE: { + auto while_statement = + std::static_pointer_cast(statement); + analyze_exp(while_statement->get_exps(), symbol_table, indx); + analyze_statement(while_statement->get_stmt(), symbol_table, indx); + } break; + case ast::statementType::FOR: + analyze_for_statement( + std::static_pointer_cast(statement), + symbol_table, indx); + break; + case ast::statementType::BLOCK: { + auto block_statement = + std::static_pointer_cast(statement); + std::map, std::string> proxy_symbol_table( + symbol_table); + analyze_block(block_statement->get_block(), proxy_symbol_table, indx + 1); + } break; + case ast::statementType::GOTO: { + std::string label = statement->get_labels().first->get_value(); + if (goto_labels.find(label) == goto_labels.end()) { + goto_labels[label] = false; + } + } break; + case ast::statementType::LABEL: { + std::string label = statement->get_labels().first->get_value(); + if (goto_labels.find(label) != goto_labels.end()) { + if (goto_labels[label] == false) { + goto_labels[label] = true; + } else { + success = false; + error_messages.emplace_back("Label " + label + " already declared"); + } + } else { + goto_labels[label] = true; + } + } break; + case ast::statementType::EXP: + analyze_exp(statement->get_exps(), symbol_table, indx); + break; + case ast::statementType::NULLSTMT: + case ast::statementType::CONTINUE: + case ast::statementType::BREAK: + break; + case ast::statementType::UNKNOWN: + UNREACHABLE() + } +} + +void parser::analyze_for_statement( + std::shared_ptr for_statement, + std::map, std::string> &symbol_table, + int indx) { + // When init is null or init is a simple expression, then + // we don't need to add another level to the symbol table + if (for_statement->get_for_init() == nullptr) { + analyze_exp(for_statement->get_exps(), symbol_table, indx); + analyze_exp(for_statement->get_exp2(), symbol_table, indx); + if (for_statement->get_stmt()->get_type() == ast::statementType::FOR) { + auto forstmt = std::static_pointer_cast( + for_statement->get_stmt()); + analyze_for_statement(forstmt, symbol_table, indx); + } else { + analyze_statement(for_statement->get_stmt(), symbol_table, indx); + } + } else if (for_statement->get_for_init()->get_declaration() == nullptr) { + analyze_exp(for_statement->get_for_init()->get_exp(), symbol_table, indx); + analyze_exp(for_statement->get_exps(), symbol_table, indx); + analyze_exp(for_statement->get_exp2(), symbol_table, indx); + if (for_statement->get_stmt()->get_type() == ast::statementType::FOR) { + auto forstmt = std::static_pointer_cast( + for_statement->get_stmt()); + analyze_for_statement(forstmt, symbol_table, indx); + } else { + analyze_statement(for_statement->get_stmt(), symbol_table, indx); + } + } else { + // Add another level to the symbol table + std::map, std::string> proxy_symbol_table( + symbol_table); + analyze_declaration(for_statement->get_for_init()->get_declaration(), + proxy_symbol_table, indx + 1); + analyze_exp(for_statement->get_exps(), proxy_symbol_table, indx + 1); + analyze_exp(for_statement->get_exp2(), proxy_symbol_table, indx + 1); + if (for_statement->get_stmt()->get_type() == ast::statementType::FOR) { + auto forstmt = std::static_pointer_cast( + for_statement->get_stmt()); + analyze_for_statement(forstmt, proxy_symbol_table, indx + 1); + } else { + analyze_statement(for_statement->get_stmt(), proxy_symbol_table, + indx + 1); + } + } +} + +} // namespace parser +} // namespace scarlet