#include "elna/gcc/elna-generic.h" #include "elna/gcc/elna-diagnostic.h" #include "input.h" #include "cgraph.h" #include "gimplify.h" #include "stringpool.h" #include "diagnostic.h" namespace elna { namespace gcc { void generic_visitor::visit(source::call_statement *statement) { empty_visitor::visit(statement); const char *format_integer = "%d\n"; tree args[] = { build_string_literal(strlen(format_integer) + 1, format_integer), this->current_expression }; tree fndecl_type_param[] = { build_pointer_type (build_qualified_type(char_type_node, TYPE_QUAL_CONST)) /* const char* */ }; tree fndecl_type = build_varargs_function_type_array(integer_type_node, 1, fndecl_type_param); tree printf_fn_decl = build_fn_decl("printf", fndecl_type); DECL_EXTERNAL (printf_fn_decl) = 1; tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), printf_fn_decl); tree stmt = build_call_array(integer_type_node, printf_fn, 2, args); append_to_statement_list(stmt, &this->current_statements); } void generic_visitor::visit(source::program *program) { tree main_fndecl_type_param[] = { integer_type_node, build_pointer_type(build_pointer_type (char_type_node)) }; tree main_fndecl_type = build_function_type_array(integer_type_node, 2, main_fndecl_type_param); tree main_fndecl = build_fn_decl("main", main_fndecl_type); tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); DECL_RESULT(main_fndecl) = resdecl; tree set_result = build2(INIT_EXPR, void_type_node, DECL_RESULT(main_fndecl), build_int_cst_type(integer_type_node, 0)); tree return_stmt = build1(RETURN_EXPR, void_type_node, set_result); this->current_statements = alloc_stmt_list(); empty_visitor::visit(program); append_to_statement_list(return_stmt, &this->current_statements); tree new_block = build_block(NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); tree bind_expr = build3(BIND_EXPR, void_type_node, NULL_TREE, this->current_statements, new_block); BLOCK_SUPERCONTEXT(new_block) = main_fndecl; DECL_INITIAL(main_fndecl) = new_block; DECL_SAVED_TREE(main_fndecl) = bind_expr; DECL_EXTERNAL(main_fndecl) = 0; DECL_PRESERVE_P(main_fndecl) = 1; gimplify_function_tree(main_fndecl); cgraph_node::finalize_function(main_fndecl, true); } void generic_visitor::visit(source::integer_literal *literal) { current_expression = build_int_cst_type(integer_type_node, literal->number()); } void generic_visitor::visit(source::boolean_literal *literal) { current_expression = build_int_cst_type(boolean_type_node, literal->boolean()); } void generic_visitor::visit(source::binary_expression *expression) { expression->lhs().accept(this); auto left = this->current_expression; expression->rhs().accept(this); auto right = this->current_expression; tree_code operator_code{}; switch (expression->operation()) { case source::binary_operator::sum: operator_code = PLUS_EXPR; break; case source::binary_operator::subtraction: operator_code = MINUS_EXPR; break; case source::binary_operator::division: operator_code = TRUNC_DIV_EXPR; break; case source::binary_operator::multiplication: operator_code = MULT_EXPR; break; default: gcc_unreachable(); } this->current_expression = build2(operator_code, integer_type_node, left, right); } void generic_visitor::visit(source::declaration *declaration) { if (declaration->type().base() != "Int" && declaration->type().base() != "Bool") { error_at(elna_gcc_location(&declaration->type().position()), "type '%s' not declared", declaration->type().base().c_str()); return; } auto declaration_location = elna_gcc_location(&declaration->position()); tree declaration_tree = build_decl(declaration_location, VAR_DECL, get_identifier(declaration->identifier().c_str()), integer_type_node); auto result = this->symbol_map.insert({ declaration->identifier(), declaration_tree }); if (result.second) { auto declaration_statement = build1_loc(declaration_location, DECL_EXPR, void_type_node, declaration_tree); append_to_statement_list(declaration_statement, &this->current_statements); } else { error_at(declaration_location, "variable '%s' already declared in this scope", declaration->identifier().c_str()); } } void generic_visitor::visit(source::variable_expression *expression) { auto symbol = this->symbol_map.find(expression->name()); if (symbol == this->symbol_map.end()) { error_at(elna_gcc_location(&expression->position()), "variable '%s' not declared in the current scope", expression->name().c_str()); this->current_expression = error_mark_node; return; } this->current_expression = symbol->second; } void generic_visitor::visit(source::assign_statement *statement) { auto lvalue = this->symbol_map.find(statement->lvalue()); auto statement_location = elna_gcc_location(&statement->position()); if (lvalue == this->symbol_map.end()) { error_at(statement_location, "variable '%s' not declared in the current scope", statement->lvalue().c_str()); return; } statement->rvalue().accept(this); if (TREE_TYPE(this->current_expression) != TREE_TYPE(lvalue->second)) { error_at(elna_gcc_location(&statement->position()), "cannot assign value of type %s to variable '%s' of type %s", elna_gcc_print_type(TREE_TYPE(this->current_expression)), statement->lvalue().c_str(), elna_gcc_print_type(TREE_TYPE(lvalue->second))); this->current_expression = error_mark_node; return; } auto assignment = build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue->second, this->current_expression); append_to_statement_list(assignment, &this->current_statements); this->current_expression = NULL_TREE; } } }