diff --git a/example.elna b/example.elna index 318c87a..eeef53d 100644 --- a/example.elna +++ b/example.elna @@ -1,5 +1,4 @@ type - T = array 5 of Int, TokenValue = union intValue: Int; stringValue: String @@ -57,63 +56,58 @@ begin write(0, @value, 1) end; +proc write_i(value: Int); +var + digit: Int, n: Int, + buffer: array 10 of Char; +begin + n := 9; + buffer[9] := '0'; + + while value /= 0 do + digit := value % 10; + value := value / 10; + + buffer[n] := Char(Int('0') + digit); + n := n - 1 + end; + while n < 10 do + n := n + 1; + write_c(buffer[n]) + end +end; + +proc write_u(value: Word); +begin + write_i(value) +end; + -- -- End of standard procedures. -- -proc test_array(); -var a: T, x: Int; -begin - a[0] := 2; - a[1] := 5; - - writei(""); - writei("Test array:"); - - x := 0; - while x < 2 do - writei(a[x]); - x := x + 1 - end -end; - proc test_record(); var r: Token; begin - writei(""); - writei("Test record:"); + write_s("\nTest record:\n"); r.kind := 4; r.value.intValue := 8; - writei(r.value.intValue) + write_i(r.value.intValue) end; proc test_primitive(); -var u: Word, z: Float; begin - u := 25u; - z := 8.2; + write_s("\nTest primitives:\n"); + write_u(25u); + write_c('\n'); - writei(""); - writei("Test primitives:"); - writei(u); - writei(z) -end; + write_i(8); + write_c('\n'); -proc test_param(d: Int, e: Int); -begin - writei(""); - writei("Test param"); - writei(d); - writei(e) -end; - -proc test_return_int(): Int; -begin - writei(""); - writei("Test return int:"); - return 5 + write_b(true); + write_c('\n') end; proc read_source(filename: String): pointer to Char; @@ -153,15 +147,10 @@ begin end; begin - test_primitive(); - test_array(); - test_record(); - test_param(8, 7); - writei(test_return_int()); - write_b(true); - write_c('\n'); - compile(); + test_record(); + test_primitive(); + exit(0) end. diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 195c9e3..5dd740d 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -24,7 +24,8 @@ namespace gcc { auto symbol = this->symbol_map->lookup(statement->name()); - if (statement->name() == "writei") + if (statement->name() == "Int" || statement->name() == "Word" || statement->name() == "Bool" + || statement->name() == "Float" || statement->name() == "Char") { if (statement->arguments().size() != 1) { @@ -35,51 +36,10 @@ namespace gcc } auto& argument = statement->arguments().at(0); argument->accept(this); - auto argument_type = TREE_TYPE(this->current_expression); - - const char *format_number{ nullptr }; - if (argument_type == integer_type_node) - { - format_number = "%d\n"; - } - else if (argument_type == unsigned_type_node) - { - format_number = "%u\n"; - } - else if (argument_type == double_type_node) - { - format_number = "%f\n"; - } - else if (is_pointer_type(argument_type)) - { - format_number = "%p\n"; - } - else - { - error_at(get_location(&argument->position()), - "invalid argument of type %s for procedure %s", - print_type(argument_type), statement->name().c_str()); - this->current_expression = error_mark_node; - return; - } - tree args[] = { - build_string_literal(strlen(format_number) + 1, format_number), - 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); - this->current_expression = NULL_TREE; + tree argument_type = TREE_TYPE(this->current_expression); + + this->current_expression = build1_loc(get_location(&argument->position()), CONVERT_EXPR, + symbol->payload, this->current_expression); } else if (symbol) { @@ -733,70 +693,62 @@ namespace gcc void generic_visitor::visit(source::if_statement *statement) { - statement->body().prerequisite().accept(this); + tree endif_label_decl = build_label_decl("endif", UNKNOWN_LOCATION); + tree goto_endif = build1(GOTO_EXPR, void_type_node, endif_label_decl); - if (TREE_TYPE(this->current_expression) != boolean_type_node) + make_if_branch(statement->body(), goto_endif); + + for (const auto branch : statement->branches) { - error_at(get_location(&statement->body().prerequisite().position()), - "expected expression of boolean type but its type is %s", - print_type(TREE_TYPE(this->current_expression))); - this->current_expression = error_mark_node; - return; - } - auto then_location = get_location(&statement->position()); - auto prerequisite_location = get_location(&statement->body().prerequisite().position()); - - auto then_label_decl = build_label_decl("then", then_location); - auto endif_label_decl = build_label_decl("end_if", then_location); - - auto goto_then = build1_loc(prerequisite_location, GOTO_EXPR, - void_type_node, then_label_decl); - 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->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_else_or_endif); - append_to_statement_list(cond_expr, &this->current_statements); - - auto then_label_expr = build1_loc(then_location, LABEL_EXPR, - void_type_node, then_label_decl); - append_to_statement_list(then_label_expr, &this->current_statements); - - for (const auto body_statement : statement->body().statements) - { - body_statement->accept(this); + make_if_branch(*branch, goto_endif); } 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); - for (const auto body_statement : *statement->alternative()) { body_statement->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); + tree endif_label_expr = build1(LABEL_EXPR, void_type_node, endif_label_decl); + append_to_statement_list(endif_label_expr, &this->current_statements); this->current_expression = NULL_TREE; } + void generic_visitor::make_if_branch(source::conditional_statements& branch, tree goto_endif) + { + branch.prerequisite().accept(this); + + if (TREE_TYPE(this->current_expression) != boolean_type_node) + { + error_at(get_location(&branch.prerequisite().position()), + "expected expression of boolean type but its type is %s", + print_type(TREE_TYPE(this->current_expression))); + this->current_expression = error_mark_node; + return; + } + tree then_label_decl = build_label_decl("then", UNKNOWN_LOCATION); + tree goto_then = build1(GOTO_EXPR, void_type_node, then_label_decl); + + tree else_label_decl = build_label_decl("else", UNKNOWN_LOCATION); + tree goto_else = build1(GOTO_EXPR, void_type_node, else_label_decl); + + auto cond_expr = build3(COND_EXPR, void_type_node, this->current_expression, goto_then, goto_else); + append_to_statement_list(cond_expr, &this->current_statements); + + tree then_label_expr = build1(LABEL_EXPR, void_type_node, then_label_decl); + append_to_statement_list(then_label_expr, &this->current_statements); + + for (const auto body_statement : branch.statements) + { + body_statement->accept(this); + } + append_to_statement_list(goto_endif, &this->current_statements); + + tree else_label_expr = build1(LABEL_EXPR, void_type_node, else_label_decl); + append_to_statement_list(else_label_expr, &this->current_statements); + } + tree generic_visitor::build_label_decl(const char *name, location_t loc) { auto label_decl = build_decl(loc, diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 8169126..207041f 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -34,6 +34,8 @@ namespace gcc void build_binary_operation(bool condition, source::binary_expression *expression, tree_code operator_code, tree left, tree right, tree target_type); + void make_if_branch(source::conditional_statements& branch, tree goto_endif); + public: generic_visitor(std::shared_ptr> symbol_table); diff --git a/include/elna/source/ast.h b/include/elna/source/ast.h index 8c759c6..cb40570 100644 --- a/include/elna/source/ast.h +++ b/include/elna/source/ast.h @@ -617,6 +617,8 @@ namespace source std::vector *m_alternative; public: + std::vector branches; + if_statement(const struct position position, conditional_statements *body, std::vector *alternative = nullptr); virtual void accept(parser_visitor *visitor) override; diff --git a/source/ast.cc b/source/ast.cc index 385c5f8..3fbbf98 100644 --- a/source/ast.cc +++ b/source/ast.cc @@ -898,7 +898,10 @@ namespace source if_statement::~if_statement() { delete m_body; - + for (const auto branch : branches) + { + delete branch; + } if (m_alternative != nullptr) { delete m_alternative; diff --git a/source/parser.yy b/source/parser.yy index bbda45f..bf8cd09 100644 --- a/source/parser.yy +++ b/source/parser.yy @@ -96,6 +96,7 @@ %type block; %type > field_declaration; %type >> field_list; +%type > elsif_statement_list; %% program: type_part constant_part procedure_part variable_part BEGIN_BLOCK optional_statements END_BLOCK DOT @@ -121,7 +122,7 @@ program: { *value_definition++ = variable; } - auto tree = new elna::source::program(elna::source::position{}, + auto tree = new elna::source::program(elna::source::make_position(@5), std::move(definitions), std::move(value_definitions), std::move($6)); driver.tree.reset(tree); @@ -139,28 +140,28 @@ block: constant_part variable_part BEGIN_BLOCK optional_statements END_BLOCK { *definition++ = variable; } - $$ = new elna::source::block(elna::source::position{}, + $$ = new elna::source::block(elna::source::make_position(@3), std::move(definitions), std::move($4)); } procedure_definition: PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON block SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), nullptr, $5); } | PROCEDURE IDENTIFIER formal_parameter_list SEMICOLON EXTERN SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), nullptr, nullptr); } | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON block SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), $5, $7); } | PROCEDURE IDENTIFIER formal_parameter_list COLON type_expression SEMICOLON EXTERN SEMICOLON { - $$ = new elna::source::procedure_definition(elna::source::position{}, + $$ = new elna::source::procedure_definition(elna::source::make_position(@1), $2, std::move($3), $5, nullptr); } procedure_definitions: @@ -188,19 +189,30 @@ while_statement: WHILE expression DO optional_statements END_BLOCK std::swap($4, body->statements); $$ = new elna::source::while_statement(elna::source::make_position(@1), body); } +elsif_statement_list: + ELSIF expression THEN optional_statements elsif_statement_list + { + elna::source::conditional_statements *branch = new elna::source::conditional_statements($2); + std::swap(branch->statements, $4); + std::swap($5, $$); + $$.emplace($$.begin(), branch); + } + | {} if_statement: - IF expression THEN optional_statements END_BLOCK + IF expression THEN optional_statements elsif_statement_list END_BLOCK { auto then = new elna::source::conditional_statements($2); std::swap($4, then->statements); $$ = new elna::source::if_statement(elna::source::make_position(@1), then); + std::swap($5, $$->branches); } - | IF expression THEN optional_statements ELSE optional_statements END_BLOCK + | IF expression THEN optional_statements elsif_statement_list ELSE optional_statements END_BLOCK { auto then = new elna::source::conditional_statements($2); std::swap($4, then->statements); - auto _else = new std::vector(std::move($6)); + auto _else = new std::vector(std::move($7)); $$ = new elna::source::if_statement(elna::source::make_position(@1), then, _else); + std::swap($5, $$->branches); } return_statement: RETURN expression