From 3bd4c3af6ffb1634ce0363006a4b878caa072b2e Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 13 Jan 2025 11:55:19 +0100 Subject: [PATCH] Don't append return to void procedures --- example.elna | 20 ++++++- gcc/elna-generic.cc | 102 ++++++++++++++++++++++---------- include/elna/gcc/elna-generic.h | 3 + include/elna/source/ast.h | 7 ++- source/ast.cc | 13 ++++ source/lexer.ll | 9 +++ source/parser.yy | 30 +++++++--- 7 files changed, 138 insertions(+), 46 deletions(-) diff --git a/example.elna b/example.elna index d248d47..3d04501 100644 --- a/example.elna +++ b/example.elna @@ -79,17 +79,30 @@ begin end; proc test_if(); -var y: Bool; +var x: Bool, y: Bool; begin + x := true; y := false; writei(""); - if y then + if x and y then writei("Test if: True") else writei("Test if: False") end; +proc test_not(); +var x: Bool; +begin + x := false; + + writei(""); + if not x then + writei("Test not true.") + else + writei("Test not false") +end; + begin test_primitive(); test_string(); @@ -97,5 +110,6 @@ begin test_pointer(); test_record(); test_const(); - test_if() + test_if(); + test_not() end. diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index cc7990d..0cfbf47 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -160,16 +160,13 @@ namespace gcc this->symbol_map->enter(definition->identifier(), source::make_info(this->main_fndecl)); - tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, integer_type_node); + tree resdecl = build_decl(UNKNOWN_LOCATION, RESULT_DECL, + NULL_TREE, TREE_TYPE(TREE_TYPE(this->main_fndecl))); DECL_CONTEXT(resdecl) = this->main_fndecl; DECL_RESULT(this->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); enter_scope(); definition->body().accept(this); - append_to_statement_list(return_stmt, &this->current_statements); tree_symbol_mapping mapping = leave_scope(); @@ -240,6 +237,28 @@ namespace gcc this->current_expression = build_string_literal(string->string().size() + 1, string->string().c_str()); } + void generic_visitor::build_binarary_operation(bool condition, source::binary_expression *expression, + tree_code operator_code, tree left, tree right, tree target_type) + { + auto expression_location = get_location(&expression->position()); + auto left_type = TREE_TYPE(left); + auto right_type = TREE_TYPE(right); + + if (condition) + { + this->current_expression = build2_loc(expression_location, + operator_code, target_type, left, right); + } + else + { + error_at(expression_location, + "invalid operands of type %s and %s for operator %s", + print_type(left_type), print_type(right_type), + elna::source::print_binary_operator(expression->operation())); + this->current_expression = error_mark_node; + } + } + void generic_visitor::visit(source::binary_expression *expression) { expression->lhs().accept(this); @@ -281,31 +300,6 @@ namespace gcc operator_code = MULT_EXPR; target_type = left_type; break; - default: - break; - } - if (operator_code != ERROR_MARK) // An arithmetic operation. - { - if (target_type != integer_type_node && target_type != double_type_node) - { - error_at(expression_location, - "invalid operands of type %s and %s for operator %s", - print_type(left_type), 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 = EQ_EXPR; - target_type = boolean_type_node; - break; - case source::binary_operator::not_equals: - operator_code = NE_EXPR; - target_type = boolean_type_node; - break; case source::binary_operator::less: operator_code = LT_EXPR; target_type = boolean_type_node; @@ -325,6 +319,44 @@ namespace gcc default: break; } + if (operator_code != ERROR_MARK) // An arithmetic operation. + { + build_binarary_operation(left_type == integer_type_node || left_type == double_type_node, + expression, operator_code, left, right, target_type); + return; + } + switch (expression->operation()) + { + case source::binary_operator::conjunction: + operator_code = TRUTH_ANDIF_EXPR; + target_type = boolean_type_node; + break; + case source::binary_operator::disjunction: + operator_code = TRUTH_ORIF_EXPR; + target_type = boolean_type_node; + break; + default: + break; + } + if (operator_code != ERROR_MARK) // A logical operation. + { + build_binarary_operation(left_type == boolean_type_node, + expression, operator_code, left, right, target_type); + return; + } + switch (expression->operation()) + { + case source::binary_operator::equals: + operator_code = EQ_EXPR; + target_type = boolean_type_node; + break; + case source::binary_operator::not_equals: + operator_code = NE_EXPR; + target_type = boolean_type_node; + break; + default: + break; + } gcc_assert(operator_code != ERROR_MARK); gcc_assert(target_type != error_mark_node); @@ -334,15 +366,19 @@ namespace gcc void generic_visitor::visit(source::unary_expression *expression) { + expression->operand().accept(this); + switch (expression->operation()) { case source::unary_operator::reference: - expression->operand().accept(this); - this->current_expression = build1_loc(get_location(&expression->position()), ADDR_EXPR, build_pointer_type_for_mode(TREE_TYPE(this->current_expression), VOIDmode, true), this->current_expression); break; + case source::unary_operator::negation: + this->current_expression = build1_loc(get_location(&expression->position()), TRUTH_NOT_EXPR, + boolean_type_node, this->current_expression); + break; } } @@ -674,6 +710,8 @@ namespace gcc if (statement->alternative() != nullptr) { + append_to_statement_list(goto_endif, &this->current_statements); + auto else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl); append_to_statement_list(else_label_expr, &this->current_statements); diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 28a469d..7019bc9 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -31,6 +31,9 @@ namespace gcc void enter_scope(); tree_symbol_mapping leave_scope(); + void build_binarary_operation(bool condition, source::binary_expression *expression, + tree_code operator_code, tree left, tree right, tree target_type); + public: generic_visitor(); diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index cbd7ede..b30ccb0 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -24,12 +24,15 @@ namespace source less, greater, less_equal, - greater_equal + greater_equal, + disjunction, + conjunction }; enum class unary_operator { - reference + reference, + negation }; class variable_declaration; diff --git a/source/ast.cc b/source/ast.cc index 50fca7e..015ed21 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -672,6 +672,12 @@ namespace source case 'g': this->m_operator = binary_operator::greater_equal; break; + case 'o': + this->m_operator = binary_operator::disjunction; + break; + case 'a': + this->m_operator = binary_operator::conjunction; + break; default: __builtin_unreachable(); } @@ -712,6 +718,9 @@ namespace source case '@': this->m_operator = unary_operator::reference; break; + case '!': + this->m_operator = unary_operator::negation; + break; default: __builtin_unreachable(); } @@ -923,6 +932,10 @@ namespace source return ">"; case binary_operator::greater_equal: return ">="; + case binary_operator::conjunction: + return "and"; + case binary_operator::disjunction: + return "or"; } __builtin_unreachable(); }; diff --git a/source/lexer.ll b/source/lexer.ll index 5704750..c429c12 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -79,6 +79,15 @@ true { false { return yy::parser::make_BOOLEAN(false, this->location); } +and { + return yy::parser::make_AND(this->location); + } +or { + return yy::parser::make_OR(this->location); + } +not { + return yy::parser::make_NOT(this->location); + } [A-Za-z_][A-Za-z0-9_]* { return yy::parser::make_IDENTIFIER(yytext, this->location); } diff --git a/source/parser.yy b/source/parser.yy index 60de2dc..6cf86b0 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -66,6 +66,7 @@ %token CONST VAR PROCEDURE ARRAY OF TYPE RECORD %token BEGIN_BLOCK END_BLOCK %token LEFT_PAREN RIGHT_PAREN LEFT_SQUARE RIGHT_SQUARE SEMICOLON DOT COMMA +%token AND OR NOT %token GREATER_EQUAL LESS_EQUAL LESS_THAN GREATER_THAN NOT_EQUAL EQUALS %token PLUS MINUS MULTIPLICATION DIVISION %token ASSIGNMENT COLON HAT AT @@ -84,7 +85,7 @@ %type > variable_declarations variable_part formal_parameter_list; %type type_expression; -%type expression pointer summand factor comparand; +%type expression pointer summand factor comparand logical_operand; %type > expressions actual_parameter_list; %type designator_expression; %type compound_statement; @@ -239,6 +240,10 @@ factor: { $$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '@'); } + | NOT pointer + { + $$ = new elna::source::unary_expression(elna::source::make_position(@1), $2, '!'); + } | pointer { $$ = $1; } comparand: summand PLUS summand @@ -250,7 +255,7 @@ comparand: $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '-'); } | summand { $$ = std::move($1); } -expression: +logical_operand: comparand EQUALS comparand { $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '='); @@ -265,20 +270,27 @@ expression: } | comparand GREATER_THAN comparand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, '>'); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '>'); } | comparand LESS_EQUAL comparand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, '<'); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '<'); } | comparand GREATER_EQUAL comparand { - $$ = new elna::source::binary_expression(elna::source::make_position(@1), - $1, $3, '>'); + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, '>'); } - | comparand { $$ = std::move($1); } + | comparand { $$ = $1; } +expression: + logical_operand AND logical_operand + { + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'a'); + } + | logical_operand OR logical_operand + { + $$ = new elna::source::binary_expression(elna::source::make_position(@1), $1, $3, 'o'); + } + | logical_operand { $$ = $1; } expressions: expression COMMA expressions {