From 75a691134f98922ff375d855627c0cf2a4678274 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Mon, 30 Dec 2024 23:12:47 +0100 Subject: [PATCH] Support else in if then conditions --- config-lang.in | 4 +++ gcc/Make-lang.in | 23 ++++++++++++---- gcc/config-lang.in | 4 +-- gcc/elna-generic.cc | 55 ++++++++++++++++++++++++++++++++++----- include/elna/source/ast.h | 5 +++- source/ast.cc | 10 +++++-- source/lexer.ll | 3 +++ source/parser.yy | 10 ++++++- 8 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 config-lang.in diff --git a/config-lang.in b/config-lang.in new file mode 100644 index 0000000..5e58f8b --- /dev/null +++ b/config-lang.in @@ -0,0 +1,4 @@ +language="elna" +gcc_subdir="elna/gcc" + +. ${srcdir}/elna/gcc/config-lang.in diff --git a/gcc/Make-lang.in b/gcc/Make-lang.in index 5d4af02..fb36799 100644 --- a/gcc/Make-lang.in +++ b/gcc/Make-lang.in @@ -89,14 +89,27 @@ elna.stageprofile: stageprofile-start elna.stagefeedback: stagefeedback-start -mv elna/*$(objext) stagefeedback/elna -ELNA_INCLUDES = -I $(srcdir)/elna -I $(srcdir)/elna/generated +ELNA_INCLUDES = -I $(srcdir)/elna/include -I elna/generated -CFLAGS-elna/elna1.o += $(ELNA_INCLUDES) - -elna/%.o: elna/source/%.cc +elna/%.o: elna/source/%.cc elna/generated/parser.hh elna/generated/location.hh $(COMPILE) $(ELNA_INCLUDES) $< $(POSTCOMPILE) -elna/%.o: elna/generated/%.cc +elna/%.o: elna/generated/%.cc elna/generated/parser.hh elna/generated/location.hh $(COMPILE) $(ELNA_INCLUDES) $< $(POSTCOMPILE) + +elna/%.o: elna/gcc/%.cc elna/generated/parser.hh elna/generated/location.hh + $(COMPILE) $(ELNA_INCLUDES) $< + $(POSTCOMPILE) + +elna/generated/parser.cc: elna/source/parser.yy + mkdir -p $(dir $@) + $(BISON) -d -o $@ $< + +elna/generated/parser.hh elna/generated/location.hh: elna/generated/parser.cc + @touch $@ + +elna/generated/lexer.cc: elna/source/lexer.ll + mkdir -p $(dir $@) + $(FLEX) -o $@ $< diff --git a/gcc/config-lang.in b/gcc/config-lang.in index 4d69a75..2d9f57a 100644 --- a/gcc/config-lang.in +++ b/gcc/config-lang.in @@ -1,11 +1,11 @@ -# gcc-src/gcc/config/config-lang.in language="elna" +gcc_subdir="elna/gcc" compilers="elna1\$(exeext)" target_libs="" -gtfiles="\$(srcdir)/elna/elna1.cc" +gtfiles="\$(srcdir)/elna/gcc/elna1.cc" lang_requires_boot_languages=c++ diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index ac24dcd..74675a3 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -118,20 +118,25 @@ namespace gcc auto expression_location = get_location(&expression->position()); tree_code operator_code = ERROR_MARK; + tree target_type = error_mark_node; switch (expression->operation()) { case source::binary_operator::sum: operator_code = PLUS_EXPR; + target_type = integer_type_node; break; case source::binary_operator::subtraction: operator_code = MINUS_EXPR; + target_type = integer_type_node; break; case source::binary_operator::division: operator_code = TRUNC_DIV_EXPR; + target_type = integer_type_node; break; case source::binary_operator::multiplication: operator_code = MULT_EXPR; + target_type = integer_type_node; break; } if (operator_code != ERROR_MARK) // An arithmetic operation. @@ -150,21 +155,27 @@ namespace gcc { 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; break; case source::binary_operator::greater: operator_code = GT_EXPR; + target_type = boolean_type_node; break; case source::binary_operator::less_equal: operator_code = LE_EXPR; + target_type = boolean_type_node; break; case source::binary_operator::greater_equal: operator_code = GE_EXPR; + target_type = boolean_type_node; break; } if (left_type != right_type) @@ -176,8 +187,11 @@ namespace gcc this->current_expression = error_mark_node; return; } + gcc_assert(operator_code != ERROR_MARK); + gcc_assert(target_type != error_mark_node); + this->current_expression = build2_loc(expression_location, - operator_code, integer_type_node, left, right); + operator_code, target_type, left, right); } void generic_visitor::visit(source::constant_definition *definition) @@ -210,16 +224,25 @@ namespace gcc void generic_visitor::visit(source::declaration *declaration) { - if (declaration->type().base() != "Int" && declaration->type().base() != "Bool") + tree declaration_type = error_mark_node; + + if (declaration->type().base() == "Int") + { + declaration_type = integer_type_node; + } + else if (declaration->type().base() == "Bool") + { + declaration_type = boolean_type_node; + } + else { error_at(get_location(&declaration->type().position()), - "type '%s' not declared", - declaration->type().base().c_str()); + "type '%s' not declared", declaration->type().base().c_str()); return; } auto declaration_location = get_location(&declaration->position()); tree declaration_tree = build_decl(declaration_location, VAR_DECL, - get_identifier(declaration->identifier().c_str()), integer_type_node); + get_identifier(declaration->identifier().c_str()), declaration_type); auto result = this->symbol_map.insert({ declaration->identifier(), declaration_tree }); if (result.second) @@ -312,8 +335,21 @@ namespace gcc auto goto_endif = build1_loc(prerequisite_location, GOTO_EXPR, void_type_node, endif_label_decl); + tree else_label_decl = NULL_TREE; + tree goto_else_or_endif = NULL_TREE; + if (statement->alternative() != nullptr) + { + auto else_location = get_location(&statement->alternative()->position()); + else_label_decl = build_label_decl("else", else_location); + goto_else_or_endif = build1_loc(else_location, GOTO_EXPR, void_type_node, else_label_decl); + } + else + { + goto_else_or_endif = goto_endif; + } + auto cond_expr = build3_loc(prerequisite_location, COND_EXPR, - void_type_node, this->current_expression, goto_then, goto_endif); + void_type_node, this->current_expression, goto_then, goto_else_or_endif); append_to_statement_list(cond_expr, &this->current_statements); auto then_label_expr = build1_loc(then_location, LABEL_EXPR, @@ -322,6 +358,13 @@ namespace gcc statement->body().accept(this); + if (statement->alternative() != nullptr) + { + auto else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl); + append_to_statement_list(else_label_expr, &this->current_statements); + + statement->alternative()->accept(this); + } auto endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl); append_to_statement_list(endif_label_expr, &this->current_statements); diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index cc3188a..7fc3d7d 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -361,19 +361,22 @@ namespace source { std::unique_ptr m_prerequisite; std::unique_ptr m_body; + std::unique_ptr m_alternative; public: /** * \param position Source code position. * \param prerequisite Condition. * \param body Statement executed if the condition is met. + * \param alternative Statement executed if the condition is not met. */ if_statement(const struct position position, std::unique_ptr&& prerequisite, - std::unique_ptr&& body); + std::unique_ptr&& body, std::unique_ptr&& alternative = nullptr); virtual void accept(parser_visitor *visitor) override; expression& prerequisite(); statement& body(); + std::unique_ptr& alternative(); }; /** diff --git a/source/ast.cc b/source/ast.cc index cbca9fe..b74b64e 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -485,8 +485,9 @@ namespace source } if_statement::if_statement(const struct position position, std::unique_ptr&& prerequisite, - std::unique_ptr&& body) - : statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body)) + std::unique_ptr&& body, std::unique_ptr&& alternative) + : statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body)), + m_alternative(std::move(alternative)) { } @@ -505,6 +506,11 @@ namespace source return *m_body; } + std::unique_ptr& if_statement::alternative() + { + return m_alternative; + } + while_statement::while_statement(const struct position position, std::unique_ptr&& prerequisite, std::unique_ptr&& body) : statement(position), m_prerequisite(std::move(prerequisite)), m_body(std::move(body)) diff --git a/source/lexer.ll b/source/lexer.ll index 31ffecc..1b558b2 100644 --- a/source/lexer.ll +++ b/source/lexer.ll @@ -37,6 +37,9 @@ if { then { return yy::parser::make_THEN(this->location); } +else { + return yy::parser::make_ELSE(this->location); + } while { return yy::parser::make_WHILE(this->location); } diff --git a/source/parser.yy b/source/parser.yy index 6ae3965..be76e62 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -59,7 +59,7 @@ %token IDENTIFIER "identifier" %token NUMBER "number" %token BOOLEAN -%token IF THEN WHILE DO +%token IF WHILE DO %token CONST VAR PROCEDURE %token BEGIN_BLOCK END_BLOCK %token LEFT_PAREN RIGHT_PAREN SEMICOLON DOT COMMA @@ -67,6 +67,9 @@ %token PLUS MINUS MULTIPLICATION DIVISION %token ASSIGNMENT COLON HAT AT +%precedence THEN +%precedence ELSE + %type > integer_literal; %type > boolean_literal; %type > constant_definition; @@ -169,6 +172,11 @@ if_statement: $$ = std::make_unique(elna::source::make_position(@1), std::move($2), std::move($4)); } + | IF expression THEN statement ELSE statement + { + $$ = std::make_unique(elna::source::make_position(@1), + std::move($2), std::move($4), std::move($6)); + } pointer: integer_literal { $$ = std::move($1); } | boolean_literal { $$ = std::move($1); }