diff --git a/boot/ast.cc b/boot/ast.cc index efaaad1..ad25adb 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -795,7 +795,7 @@ namespace elna::boot } return_statement::return_statement(const struct position position, expression *return_expression) - : node(position), return_expression(return_expression) + : node(position), m_return_expression(return_expression) { } @@ -804,9 +804,14 @@ namespace elna::boot visitor->visit(this); } + expression& return_statement::return_expression() + { + return *m_return_expression; + } + return_statement::~return_statement() { - delete this->return_expression; + delete m_return_expression; } case_statement::case_statement(const struct position position, @@ -914,13 +919,6 @@ namespace elna::boot { } - while_statement::while_statement(const struct position position, conditional_statements *body, - std::vector&& branches, const std::string& label, - std::vector *alternative) - : node(position), m_body(body), branches(std::move(branches)), label(label), alternative(alternative) - { - } - void while_statement::accept(parser_visitor *visitor) { visitor->visit(this); diff --git a/boot/parser.yy b/boot/parser.yy index e82a421..575d752 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -145,10 +145,9 @@ along with GCC; see the file COPYING3. If not see %type > expressions actual_parameter_list; %type designator_expression; %type call_expression; -%type while_statement; %type return_statement; %type statement; -%type > statements; +%type > required_statements optional_statements statement_part; %type procedure_definition; %type , elna::boot::procedure_type_expression *>> procedure_heading; %type return_declaration; @@ -158,7 +157,7 @@ along with GCC; see the file COPYING3. If not see %type > block; %type field_declaration formal_parameter; %type >> - optional_fields required_fields formal_parameters; + optional_fields required_fields formal_parameters formal_parameter_list; %type > elsif_then_statements elsif_do_statements; %type *> else_statements; %type cast_expression; @@ -168,7 +167,7 @@ along with GCC; see the file COPYING3. If not see %type > import_declarations import_part; %% program: - "program" import_part constant_part type_part variable_part procedure_part "begin" statements "end" "." + "program" import_part constant_part type_part variable_part procedure_part "begin" optional_statements "end" "." { auto tree = new boot::program(boot::make_position(@7)); @@ -193,9 +192,18 @@ program: driver.tree.reset(tree); } -block: constant_part variable_part "begin" statements "end" +block: constant_part variable_part statement_part "end" { - $$ = std::make_unique(std::move($1), std::move($2), std::move($4)); + $$ = std::make_unique(std::move($1), std::move($2), std::move($3)); + } +statement_part: + /* no statements */ {} + | "begin" required_statements { std::swap($$, $2); } + | return_statement { $$.push_back($1); } + | "begin" required_statements ";" return_statement + { + std::swap($$, $2); + $$.push_back($4); } identifier_definition: IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; } @@ -211,11 +219,10 @@ return_declaration: /* proper procedure */ {} | "->" "!" { $$ = boot::procedure_type_expression::return_t(std::monostate{}); } | "->" type_expression { $$ = boot::procedure_type_expression::return_t($2); } -procedure_heading: - "(" formal_parameters ")" return_declaration +procedure_heading: formal_parameter_list return_declaration { - $$.second = new boot::procedure_type_expression(boot::make_position(@1), std::move($4)); - for (auto& [name, type] : $2) + $$.second = new boot::procedure_type_expression(boot::make_position(@1), std::move($2)); + for (auto& [name, type] : $1) { $$.first.emplace_back(std::move(name)); $$.second->parameters.push_back(type); @@ -250,7 +257,7 @@ call_expression: designator_expression actual_parameter_list cast_expression: "cast" "(" expression ":" type_expression ")" { $$ = new boot::cast_expression(boot::make_position(@1), $5, $3); } elsif_do_statements: - "elsif" expression "do" statements elsif_do_statements + "elsif" expression "do" optional_statements elsif_do_statements { boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); std::swap($5, $$); @@ -258,36 +265,18 @@ elsif_do_statements: } | {} else_statements: - "else" statements { $$ = new std::vector(std::move($2)); } + "else" optional_statements { $$ = new std::vector(std::move($2)); } | { $$ = nullptr; } -while_statement: - "while" expression "do" statements elsif_do_statements else_statements "end" - { - boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4)); - $$ = new boot::while_statement(boot::make_position(@1), body, std::move($5), $6); - } - | "while" expression "," IDENTIFIER "do" statements elsif_do_statements else_statements "end" - { - boot::conditional_statements *body = new boot::conditional_statements($2, std::move($6)); - $$ = new boot::while_statement(boot::make_position(@1), body, std::move($7), $4, $8); - } elsif_then_statements: - "elsif" expression "then" statements elsif_then_statements + "elsif" expression "then" optional_statements elsif_then_statements { boot::conditional_statements *branch = new boot::conditional_statements($2, std::move($4)); std::swap($5, $$); $$.emplace($$.begin(), branch); } | {} -return_statement: - "return" expression - { - $$ = new boot::return_statement(boot::make_position(@1), $2); - } - | "return" - { - $$ = new boot::return_statement(boot::make_position(@1)); - } +return_statement: "return" expression + { $$ = new boot::return_statement(boot::make_position(@1), $2); } literal: INTEGER { $$ = new boot::literal(boot::make_position(@1), $1); } | WORD { $$ = new boot::literal(boot::make_position(@1), $1); } @@ -421,18 +410,23 @@ designator_expression: statement: designator_expression ":=" expression { $$ = new boot::assign_statement(boot::make_position(@1), $1, $3); } - | while_statement { $$ = $1; } - | "if" expression "then" statements elsif_then_statements else_statements "end" + | "while" expression "do" optional_statements elsif_do_statements else_statements "end" + { + boot::conditional_statements *body = new boot::conditional_statements($2, std::move($4)); + $$ = new boot::while_statement(boot::make_position(@1), body, std::move($5), $6); + } + | "if" expression "then" optional_statements elsif_then_statements else_statements "end" { boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4)); $$ = new boot::if_statement(boot::make_position(@1), then, std::move($5), $6); } - | return_statement { $$ = $1; } | call_expression { $$ = $1; } - | "defer" statements "end" { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } + | "defer" optional_statements "end" + { $$ = new boot::defer_statement(boot::make_position(@1), std::move($2)); } | "case" expression "of" switch_cases else_statements "end" { $$ = new boot::case_statement(boot::make_position(@1), $2, std::move($4), $5); } -switch_case: case_labels ":" statements { $$ = { .labels = std::move($1), .statements = std::move($3) }; } +switch_case: case_labels ":" optional_statements + { $$ = { .labels = std::move($1), .statements = std::move($3) }; } switch_cases: switch_case "|" switch_cases { @@ -447,13 +441,15 @@ case_labels: $$.emplace($$.cbegin(), $1); } | expression { $$.push_back($1); } -statements: - statement ";" statements +required_statements: + required_statements ";" statement { - std::swap($$, $3); - $$.insert($$.cbegin(), $1); + std::swap($$, $1); + $$.insert($$.cend(), $3); } | statement { $$.push_back($1); } +optional_statements: + required_statements { std::swap($$, $1); } | /* no statements */ {} field_declaration: IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } @@ -578,9 +574,11 @@ type_part: | "type" type_definitions { std::swap($$, $2); } formal_parameter: IDENTIFIER ":" type_expression { $$ = std::make_pair($1, $3); } +formal_parameter_list: + "(" ")" {} + | "(" formal_parameters ")" { std::swap($$, $2); } formal_parameters: - /* no formal parameters */ {} - | formal_parameter "," formal_parameters + formal_parameter "," formal_parameters { std::swap($$, $3); $$.emplace($$.cbegin(), std::move($1)); diff --git a/boot/semantic.cc b/boot/semantic.cc index bf086dd..b668f8e 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -252,10 +252,7 @@ namespace elna::boot void declaration_visitor::visit(return_statement *statement) { - if (statement->return_expression != nullptr) - { - statement->return_expression->accept(this); - } + statement->return_expression().accept(this); } void declaration_visitor::visit(defer_statement *statement) diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index 761344d..c96e28f 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -1297,13 +1297,12 @@ namespace elna::gcc void generic_visitor::visit(boot::while_statement *statement) { - std::string loop_identifier = statement->label.value_or("while"); location_t prerequisite_location = get_location(&statement->body().prerequisite().position()); - tree prerequisite_label_decl = build_label_decl(loop_identifier.c_str(), prerequisite_location); + tree prerequisite_label_decl = build_label_decl("while_do", prerequisite_location); auto prerequisite_label_expr = build1_loc(prerequisite_location, LABEL_EXPR, void_type_node, prerequisite_label_decl); auto goto_check = build1(GOTO_EXPR, void_type_node, prerequisite_label_decl); - tree branch_end_declaration = build_label_decl(loop_identifier.c_str(), UNKNOWN_LOCATION); + tree branch_end_declaration = build_label_decl("while_end", UNKNOWN_LOCATION); tree branch_end_expression = build1_loc(UNKNOWN_LOCATION, LABEL_EXPR, void_type_node, branch_end_declaration); append_statement(prerequisite_label_expr); @@ -1340,7 +1339,7 @@ namespace elna::gcc void generic_visitor::visit(boot::return_statement *statement) { - boot::expression *return_expression = statement->return_expression; + boot::expression *return_expression = &statement->return_expression(); location_t statement_position = get_location(&statement->position()); tree set_result{ NULL_TREE }; tree return_type = TREE_TYPE(TREE_TYPE(current_function_decl)); diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 4de7bbd..6ba29f7 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -466,11 +466,13 @@ namespace elna::boot class return_statement : public statement { public: - expression *const return_expression{ nullptr }; + expression *m_return_expression; - return_statement(const struct position position, expression *return_expression = nullptr); + return_statement(const struct position position, expression *return_expression); void accept(parser_visitor *visitor) override; + expression& return_expression(); + virtual ~return_statement() override; }; @@ -653,14 +655,10 @@ namespace elna::boot public: const std::vector branches; - const std::optional label; const std::vector *alternative; while_statement(const struct position position, conditional_statements *body, std::vector&& branches, std::vector *alternative = nullptr); - while_statement(const struct position position, conditional_statements *body, - std::vector&& branches, const std::string& label, - std::vector *alternative = nullptr); void accept(parser_visitor *visitor) override; conditional_statements& body(); diff --git a/source.elna b/source.elna index 4fb3d65..822f6b7 100644 --- a/source.elna +++ b/source.elna @@ -154,7 +154,6 @@ proc exit(code: Int) -> !; extern *) proc reallocarray(ptr: ^Byte, n: Word, size: Word) -> ^Byte; -begin return realloc(ptr, n * size) end @@ -212,32 +211,26 @@ begin end proc is_digit(c: Char) -> Bool; -begin return cast(c: Int) >= cast('0': Int) & cast(c: Int) <= cast('9': Int) end proc is_alpha(c: Char) -> Bool; -begin return cast(c: Int) >= cast('A': Int) & cast(c: Int) <= cast('z': Int) end proc is_alnum(c: Char) -> Bool; -begin return is_digit(c) or is_alpha(c) end proc is_space(c: Char) -> Bool; -begin return c = ' ' or c = '\n' or c = '\t' end proc substring(string: String, start: Word, count: Word) -> String; -begin return String(string.ptr + start, count) end proc open_substring(string: String, start: Word) -> String; -begin return substring(string, start, string.length - start) end @@ -339,12 +332,10 @@ begin end proc source_code_empty(source_code: ^SourceCode) -> Bool; -begin return source_code^.empty(source_code^.input) end proc source_code_head(source_code: SourceCode) -> Char; -begin return source_code.head(source_code.input) end @@ -361,7 +352,6 @@ begin end proc source_code_expect(source_code: ^SourceCode, expected: Char) -> Bool; -begin return ~source_code_empty(source_code) & source_code_head(source_code^) = expected end @@ -375,7 +365,7 @@ var begin if escape = 'n' then result^ := '\n'; - successful := true; + successful := true elsif escape = 'a' then result^ := '\a'; successful := true @@ -419,12 +409,10 @@ proc skip_spaces(source_code: ^SourceCode); var current: Char begin - while ~source_code_empty(source_code) do + while ~source_code_empty(source_code) & is_space(source_code_head(source_code^)) do current := source_code_head(source_code^); - if ~is_space(current) then - return - elsif current = '\n' then + if current = '\n' then source_code_break(source_code) end; source_code_advance(source_code) @@ -432,7 +420,6 @@ begin end proc is_ident(char: Char) -> Bool; -begin return is_alnum(char) or char = '_' end @@ -681,7 +668,7 @@ begin end; write_c(' '); - i := i + 1u; + i := i + 1u end; write_c('\n') end @@ -962,7 +949,7 @@ begin result^.parse := false; result^.input := nil; - while i < argc do + while i < argc & result <> nil do parameter := argv + i; if strcmp(parameter^, "--lex\0".ptr) = 0 then @@ -972,23 +959,24 @@ begin elsif parameter^^ <> '-' then if result^.input <> nil then write_s("Fatal error: Only one source file can be given.\n"); - return nil - end; - result^.input := parameter^ + result := nil + else + result^.input := parameter^ + end else write_s("Fatal error: Unknown command line options: "); write_z(parameter^); write_s(".\n"); - return nil + result := nil end; i := i + 1 end; - if result^.input = nil then + if result <> nil & result^.input = nil then write_s("Fatal error: no input files.\n"); - return nil + result := nil end; return result