diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 0dccd6b..633a277 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -13,15 +13,40 @@ namespace gcc { void generic_visitor::visit(source::call_statement *statement) { - empty_visitor::visit(statement); + if (statement->name() != "writei") + { + error_at(elna_gcc_location(&statement->position()), + "procedure '%s' not declared", + statement->name().c_str()); + return; + } + if (statement->arguments().size() != 1) + { + error_at(elna_gcc_location(&statement->position()), + "procedure '%s' expects 1 argument, %i given", + statement->name().c_str(), statement->arguments().size()); + return; + } + auto& argument = statement->arguments().at(0); + argument->accept(this); + auto argument_type = TREE_TYPE(this->current_expression); + auto argument_tree = this->current_expression; + this->current_expression = NULL_TREE; - const char *format_integer = "%d\n"; + if (argument_type != integer_type_node) + { + error_at(elna_gcc_location(&argument->position()), + "invalid argument of type %s for procedure %s", + elna_gcc_print_type(argument_type), statement->name().c_str()); + return; + } + constexpr const char *format_integer = "%d\n"; tree args[] = { build_string_literal(strlen(format_integer) + 1, format_integer), - this->current_expression + argument_tree }; tree fndecl_type_param[] = { - build_pointer_type (build_qualified_type(char_type_node, TYPE_QUAL_CONST)) /* const char* */ + 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); @@ -84,11 +109,14 @@ namespace gcc { expression->lhs().accept(this); auto left = this->current_expression; + auto left_type = TREE_TYPE(left); expression->rhs().accept(this); auto right = this->current_expression; + auto right_type = TREE_TYPE(right); - tree_code operator_code{}; + auto expression_location = elna_gcc_location(&expression->position()); + tree_code operator_code = ERROR_MARK; switch (expression->operation()) { @@ -104,11 +132,51 @@ namespace gcc case source::binary_operator::multiplication: operator_code = MULT_EXPR; break; - default: - gcc_unreachable(); } - - this->current_expression = build2(operator_code, integer_type_node, left, right); + if (operator_code != ERROR_MARK) // An arithmetic operation. + { + if (left_type != integer_type_node || right_type != integer_type_node) + { + error_at(expression_location, + "invalid operands of type %s and %s for operator %s", + elna_gcc_print_type(left_type), elna_gcc_print_type(right_type), + elna::source::print_binary_operator(expression->operation())); + this->current_expression = error_mark_node; + return; + } + } + switch (expression->operation()) + { + case source::binary_operator::equals: + operator_code = PLUS_EXPR; + break; + case source::binary_operator::not_equals: + operator_code = MINUS_EXPR; + break; + case source::binary_operator::less: + operator_code = TRUNC_DIV_EXPR; + break; + case source::binary_operator::greater: + operator_code = MULT_EXPR; + break; + case source::binary_operator::less_equal: + operator_code = TRUNC_DIV_EXPR; + break; + case source::binary_operator::greater_equal: + operator_code = MULT_EXPR; + break; + } + if (left_type != right_type) + { + error_at(expression_location, + "invalid operands of type %s and %s for operator %s", + elna_gcc_print_type(left_type), elna_gcc_print_type(right_type), + elna::source::print_binary_operator(expression->operation())); + this->current_expression = error_mark_node; + return; + } + this->current_expression = build2_loc(expression_location, + operator_code, integer_type_node, left, right); } void generic_visitor::visit(source::declaration *declaration) diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index 1e6e797..cc3188a 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -486,5 +486,7 @@ namespace source expression& operand(); unary_operator operation() const noexcept; }; + + const char *print_binary_operator(const binary_operator operation); } } diff --git a/source/ast.cc b/source/ast.cc index 696569d..cbca9fe 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -525,5 +525,32 @@ namespace source { return *m_body; } + + const char *print_binary_operator(const binary_operator operation) + { + switch (operation) + { + case binary_operator::sum: + return "+"; + case binary_operator::subtraction: + return "-"; + case binary_operator::multiplication: + return "*"; + case binary_operator::division: + return "/"; + case binary_operator::equals: + return "="; + case binary_operator::not_equals: + return "/="; + case binary_operator::less: + return "<"; + case binary_operator::less_equal: + return "<="; + case binary_operator::greater: + return ">"; + case binary_operator::greater_equal: + return ">="; + } + }; } }