diff --git a/boot/ast.cc b/boot/ast.cc index 92e5bf5..5320522 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -223,9 +223,9 @@ namespace elna::boot return this; } - variable_declaration::variable_declaration(const struct position position, const std::string& identifier, - std::shared_ptr variable_type, const bool exported) - : definition(position, identifier, exported), m_variable_type(variable_type) + variable_declaration::variable_declaration(const struct position position, identifier_definition identifier, + std::shared_ptr variable_type) + : definition(position, identifier), m_variable_type(variable_type) { } @@ -239,14 +239,14 @@ namespace elna::boot return *m_variable_type; } - definition::definition(const struct position position, const std::string& identifier, const bool exported) - : node(position), identifier(identifier), exported(exported) + definition::definition(const struct position position, identifier_definition identifier) + : node(position), identifier(identifier) { } - constant_definition::constant_definition(const struct position position, const std::string& identifier, - const bool exported, expression *body) - : definition(position, identifier, exported), m_body(body) + constant_definition::constant_definition(const struct position position, identifier_definition identifier, + expression *body) + : definition(position, identifier), m_body(body) { } @@ -307,9 +307,9 @@ namespace elna::boot return this; } - procedure_definition::procedure_definition(const struct position position, const std::string& identifier, - const bool exported, procedure_type_expression *heading, block *body) - : definition(position, identifier, exported), m_heading(heading), body(body) + procedure_definition::procedure_definition(const struct position position, identifier_definition identifier, + procedure_type_expression *heading, block *body) + : definition(position, identifier), m_heading(heading), body(body) { } @@ -329,9 +329,9 @@ namespace elna::boot delete body; } - type_definition::type_definition(const struct position position, const std::string& identifier, - const bool exported, type_expression *body) - : definition(position, identifier, exported), m_body(body) + type_definition::type_definition(const struct position position, identifier_definition identifier, + type_expression *body) + : definition(position, identifier), m_body(body) { } @@ -811,8 +811,9 @@ namespace elna::boot } if_statement::if_statement(const struct position position, conditional_statements *body, + std::vector&& branches, std::vector *alternative) - : node(position), m_body(body), alternative(alternative) + : node(position), m_body(body), branches(std::move(branches)), alternative(alternative) { } @@ -848,14 +849,15 @@ namespace elna::boot } while_statement::while_statement(const struct position position, conditional_statements *body, - std::vector&& branches) - : node(position), m_body(body), branches(std::move(branches)) + std::vector&& branches, std::vector *alternative) + : node(position), m_body(body), branches(std::move(branches)), alternative(alternative) { } while_statement::while_statement(const struct position position, conditional_statements *body, - std::vector&& branches, const std::string& label) - : node(position), m_body(body), branches(std::move(branches)), label(label) + std::vector&& branches, const std::string& label, + std::vector *alternative) + : node(position), m_body(body), branches(std::move(branches)), label(label), alternative(alternative) { } diff --git a/boot/parser.yy b/boot/parser.yy index e4bc9c2..933c578 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -161,8 +161,8 @@ along with GCC; see the file COPYING3. If not see %type > elsif_then_statements elsif_do_statements; %type *> else_statements; %type cast_expression; -%type > identifier_definition; -%type >> identifier_definitions; +%type identifier_definition; +%type > identifier_definitions; %type > identifiers; %% program: @@ -187,14 +187,8 @@ block: constant_part variable_part "begin" statements "end" std::swap($$->body, $4); } identifier_definition: - IDENTIFIER "*" - { - $$ = std::make_pair($1, true); - } - | IDENTIFIER - { - $$ = std::make_pair($1, false); - } + IDENTIFIER "*" { $$ = boot::identifier_definition{ $1, true }; } + | IDENTIFIER { $$ = boot::identifier_definition{ $1, false }; } identifier_definitions: identifier_definition "," identifier_definitions { @@ -219,12 +213,12 @@ procedure_heading: procedure_definition: "proc" identifier_definition procedure_heading ";" block { - $$ = new boot::procedure_definition(boot::make_position(@1), $2.first, $2.second, $3.second, $5); + $$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second, $5); std::swap($3.first, $$->parameter_names); } | "proc" identifier_definition procedure_heading ";" "extern" { - $$ = new boot::procedure_definition(boot::make_position(@1), $2.first, $2.second, $3.second); + $$ = new boot::procedure_definition(boot::make_position(@1), std::move($2), $3.second); std::swap($3.first, $$->parameter_names); } procedure_definitions: @@ -243,9 +237,7 @@ call_expression: designator_expression actual_parameter_list std::swap($$->arguments, $2); } cast_expression: "cast" "(" expression ":" type_expression ")" - { - $$ = new boot::cast_expression(boot::make_position(@1), $5, $3); - } + { $$ = new boot::cast_expression(boot::make_position(@1), $5, $3); } elsif_do_statements: "elsif" expression "do" statements elsif_do_statements { @@ -258,15 +250,15 @@ else_statements: "else" statements { $$ = new std::vector(std::move($2)); } | { $$ = nullptr; } while_statement: - "while" expression "do" statements elsif_do_statements "end" + "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)); + $$ = new boot::while_statement(boot::make_position(@1), body, std::move($5), $6); } - | "while" expression "," IDENTIFIER "do" statements elsif_do_statements "end" + | "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); + $$ = new boot::while_statement(boot::make_position(@1), body, std::move($7), $4, $8); } elsif_then_statements: "elsif" expression "then" statements elsif_then_statements @@ -422,9 +414,7 @@ statement: | "if" expression "then" statements elsif_then_statements else_statements "end" { boot::conditional_statements *then = new boot::conditional_statements($2, std::move($4)); - auto result = new boot::if_statement(boot::make_position(@1), then, $6); - std::swap($5, result->branches); - $$ = result; + $$ = new boot::if_statement(boot::make_position(@1), then, std::move($5), $6); } | return_statement { $$ = $1; } | "break" IDENTIFIER @@ -512,32 +502,32 @@ variable_declaration: identifier_definitions ":" type_expression { std::shared_ptr shared_type{ $3 }; - for (const std::pair& identifier : $1) + for (boot::identifier_definition& identifier : $1) { boot::variable_declaration *declaration = new boot::variable_declaration( - boot::make_position(@2), identifier.first, shared_type, identifier.second); + boot::make_position(@2), std::move(identifier), shared_type); $$.push_back(declaration); } } variable_declarations: - variable_declaration ";" variable_declarations + /* no variable declarations */ {} + | variable_declaration variable_declarations { std::swap($$, $1); - $$.reserve($$.size() + $3.size()); - $$.insert(std::end($$), std::begin($3), std::end($3)); + $$.reserve($$.size() + $2.size()); + $$.insert(std::end($$), std::begin($2), std::end($2)); } - | /* no variable declarations */ {} variable_part: /* no variable declarations */ {} | "var" variable_declarations { std::swap($$, $2); } constant_definition: identifier_definition ":=" expression { - $$ = new boot::constant_definition(boot::make_position(@1), $1.first, $1.second, $3); + $$ = new boot::constant_definition(boot::make_position(@1), std::move($1), $3); } constant_definitions: - constant_definition ";" constant_definitions + constant_definition constant_definitions { - std::swap($$, $3); + std::swap($$, $2); $$.insert($$.cbegin(), $1); } | /* no constant definitions */ {} @@ -546,12 +536,12 @@ constant_part: | "const" constant_definitions { std::swap($$, $2); } type_definition: identifier_definition "=" type_expression { - $$ = new boot::type_definition(boot::make_position(@1), $1.first, $1.second, $3); + $$ = new boot::type_definition(boot::make_position(@1), std::move($1), $3); } type_definitions: - type_definition ";" type_definitions + type_definition type_definitions { - std::swap($$, $3); + std::swap($$, $2); $$.insert($$.cbegin(), $1); } | /* no type definitions */ {} diff --git a/boot/semantic.cc b/boot/semantic.cc index c7a41ee..f8dc1b4 100644 --- a/boot/semantic.cc +++ b/boot/semantic.cc @@ -77,10 +77,12 @@ namespace elna::boot { for (type_definition *const type : program->types) { - if (!this->unresolved.insert({ type->identifier, std::make_shared(type->identifier) }).second - || this->symbols->contains(type->identifier)) + const std::string& type_identifier = type->identifier.identifier; + + if (!this->unresolved.insert({ type_identifier, std::make_shared(type_identifier) }).second + || this->symbols->contains(type_identifier)) { - add_error(type->identifier, this->input_file, type->position()); + add_error(type->identifier.identifier, this->input_file, type->position()); } } for (type_definition *const type : program->types) @@ -109,7 +111,7 @@ namespace elna::boot void declaration_visitor::visit(type_definition *definition) { definition->body().accept(this); - auto unresolved_declaration = this->unresolved.at(definition->identifier); + auto unresolved_declaration = this->unresolved.at(definition->identifier.identifier); unresolved_declaration->reference = this->current_type; } @@ -193,7 +195,8 @@ namespace elna::boot { definition->body().accept(this); - this->symbols->enter(definition->identifier, std::make_shared(this->current_literal)); + this->symbols->enter(definition->identifier.identifier, + std::make_shared(this->current_literal)); } void declaration_visitor::visit(procedure_definition *definition) @@ -201,7 +204,7 @@ namespace elna::boot std::shared_ptr info = std::make_shared( build_procedure(definition->heading()), definition->parameter_names); - this->symbols->enter(definition->identifier, info); + this->symbols->enter(definition->identifier.identifier, info); if (definition->body != nullptr) { definition->body->accept(this); diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index ba4a96e..a2dee33 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -267,8 +267,8 @@ namespace elna::gcc void generic_visitor::declare_procedure(boot::procedure_definition *const definition) { tree declaration_type = build_procedure_type(definition->heading()); - tree fndecl = build_fn_decl(definition->identifier.c_str(), declaration_type); - this->symbols->enter(definition->identifier, fndecl); + tree fndecl = build_fn_decl(definition->identifier.identifier.c_str(), declaration_type); + this->symbols->enter(definition->identifier.identifier, fndecl); if (definition->heading().return_type.no_return) { @@ -296,7 +296,7 @@ namespace elna::gcc ++parameter_name; } DECL_ARGUMENTS(fndecl) = argument_chain; - TREE_PUBLIC(fndecl) = definition->exported; + TREE_PUBLIC(fndecl) = definition->identifier.exported; TREE_ADDRESSABLE(fndecl) = 1; DECL_EXTERNAL(fndecl) = definition->body == nullptr; } @@ -386,7 +386,7 @@ namespace elna::gcc { return; } - tree fndecl = this->symbols->lookup(definition->identifier); + tree fndecl = this->symbols->lookup(definition->identifier.identifier); push_struct_function(fndecl, false); DECL_STRUCT_FUNCTION(fndecl)->language = ggc_cleared_alloc(); @@ -778,15 +778,15 @@ namespace elna::gcc return; } tree definition_tree = build_decl(definition_location, CONST_DECL, - get_identifier(definition->identifier.c_str()), TREE_TYPE(this->current_expression)); - auto result = this->symbols->enter(definition->identifier, definition_tree); + get_identifier(definition->identifier.identifier.c_str()), TREE_TYPE(this->current_expression)); + auto result = this->symbols->enter(definition->identifier.identifier, definition_tree); if (result) { DECL_INITIAL(definition_tree) = this->current_expression; TREE_CONSTANT(definition_tree) = 1; TREE_READONLY(definition_tree) = 1; - TREE_PUBLIC(definition_tree) = definition->exported; + TREE_PUBLIC(definition_tree) = definition->identifier.exported; if (!lang_hooks.decls.global_bindings_p()) { @@ -798,7 +798,7 @@ namespace elna::gcc else { error_at(definition_location, "Variable '%s' already declared in this scope", - definition->identifier.c_str()); + definition->identifier.identifier.c_str()); } this->current_expression = NULL_TREE; } @@ -806,16 +806,16 @@ namespace elna::gcc void generic_visitor::visit(boot::type_definition *definition) { location_t definition_location = get_location(&definition->position()); - this->current_expression = this->unresolved.at(definition->identifier); + this->current_expression = this->unresolved.at(definition->identifier.identifier); definition->body().accept(this); tree definition_tree = build_decl(definition_location, TYPE_DECL, - get_identifier(definition->identifier.c_str()), this->current_expression); + get_identifier(definition->identifier.identifier.c_str()), this->current_expression); - TREE_PUBLIC(definition_tree) = definition->exported; - TYPE_NAME(this->current_expression) = get_identifier(definition->identifier.c_str()); + TREE_PUBLIC(definition_tree) = definition->identifier.exported; + TYPE_NAME(this->current_expression) = get_identifier(definition->identifier.identifier.c_str()); - auto result = this->symbols->enter(definition->identifier, definition_tree); + auto result = this->symbols->enter(definition->identifier.identifier, definition_tree); gcc_assert(result); this->current_expression = NULL_TREE; @@ -878,8 +878,8 @@ namespace elna::gcc location_t declaration_location = get_location(&declaration->position()); tree declaration_tree = build_decl(declaration_location, VAR_DECL, - get_identifier(declaration->identifier.c_str()), this->current_expression); - bool result = this->symbols->enter(declaration->identifier, declaration_tree); + get_identifier(declaration->identifier.identifier.c_str()), this->current_expression); + bool result = this->symbols->enter(declaration->identifier.identifier, declaration_tree); if (POINTER_TYPE_P(this->current_expression)) { @@ -889,7 +889,7 @@ namespace elna::gcc if (!result) { error_at(declaration_location, "variable '%s' already declared in this scope", - declaration->identifier.c_str()); + declaration->identifier.identifier.c_str()); } else if (lang_hooks.decls.global_bindings_p()) { @@ -1277,6 +1277,13 @@ namespace elna::gcc { make_if_branch(*branch, goto_check); } + if (statement->alternative != nullptr) + { + enter_scope(); + visit_statements(*statement->alternative); + tree mapping = leave_scope(); + append_statement(mapping); + } append_statement(branch_end_expression); this->current_expression = NULL_TREE; } diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index c2ae0ee..dd40164 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -175,17 +175,22 @@ namespace elna::boot virtual literal_expression *is_literal(); }; + struct identifier_definition + { + std::string identifier; + bool exported; + }; + /** * Symbol definition. */ class definition : public node { protected: - definition(const struct position position, const std::string& identifier, const bool exported); + definition(const struct position position, identifier_definition identifier); public: - const std::string identifier; - const bool exported; + const identifier_definition identifier; }; /** @@ -298,8 +303,8 @@ namespace elna::boot std::shared_ptr m_variable_type; public: - variable_declaration(const struct position position, const std::string& identifier, - std::shared_ptr variable_type, const bool exported = false); + variable_declaration(const struct position position, identifier_definition identifier, + std::shared_ptr variable_type); void accept(parser_visitor *visitor) override; @@ -326,8 +331,8 @@ namespace elna::boot expression *m_body; public: - constant_definition(const struct position position, const std::string& identifier, - const bool exported, expression *body); + constant_definition(const struct position position, identifier_definition identifier, + expression *body); void accept(parser_visitor *visitor) override; expression& body(); @@ -364,8 +369,8 @@ namespace elna::boot block *const body; std::vector parameter_names; - procedure_definition(const struct position position, const std::string& identifier, - const bool exported, procedure_type_expression *heading, block *body = nullptr); + procedure_definition(const struct position position, identifier_definition identifier, + procedure_type_expression *heading, block *body = nullptr); void accept(parser_visitor *visitor) override; procedure_type_expression& heading(); @@ -381,8 +386,8 @@ namespace elna::boot type_expression *m_body; public: - type_definition(const struct position position, const std::string& identifier, - const bool exported, type_expression *expression); + type_definition(const struct position position, identifier_definition identifier, + type_expression *expression); ~type_definition(); void accept(parser_visitor *visitor) override; @@ -595,10 +600,11 @@ namespace elna::boot conditional_statements *m_body; public: - std::vector branches; + const std::vector branches; const std::vector *alternative; if_statement(const struct position position, conditional_statements *body, + std::vector&& branches, std::vector *alternative = nullptr); void accept(parser_visitor *visitor) override; @@ -628,11 +634,13 @@ 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&& branches, std::vector *alternative = nullptr); while_statement(const struct position position, conditional_statements *body, - std::vector&& branches, const std::string& label); + 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 ff62def..e175cee 100644 --- a/source.elna +++ b/source.elna @@ -1,7 +1,7 @@ const - SEEK_SET* := 0; - SEEK_CUR* := 1; - SEEK_END* := 2; + SEEK_SET* := 0 + SEEK_CUR* := 1 + SEEK_END* := 2 type TokenKind* = ( @@ -65,27 +65,27 @@ type _defer, exclamation, arrow - ); + ) Position* = record line: Word; column: Word - end; + end Location* = record first: Position; last: Position - end; + end SourceFile* = record buffer: [1024]Char; handle: ^FILE; size: Word; index: Word - end; - FILE* = record end; + end + FILE* = record end StringBuffer* = record data: ^Byte; size: Word; capacity: Word - end; + end SourceCode = record position: Position; @@ -93,7 +93,7 @@ type empty: proc(^Byte) -> Bool; advance: proc(^Byte); head: proc(^Byte) -> Char - end; + end Token* = record kind: TokenKind; value: union @@ -103,12 +103,12 @@ type char_value: Char end; location: Location - end; + end CommandLine* = record input: ^Char; tokenize: Bool; syntax_tree: Bool - end; + end (* External procedures. @@ -171,9 +171,9 @@ end proc write_i(value: Int); var - digit: Int; - n: Word; - buffer: [10]Char; + digit: Int + n: Word + buffer: [10]Char begin n := 10u; @@ -230,7 +230,7 @@ end proc string_dup(origin: String) -> String; var - copy: ^Char; + copy: ^Char begin copy := cast(malloc(origin.length): ^Char); strncpy(copy, origin.ptr, origin.length); @@ -240,7 +240,7 @@ end proc string_buffer_new() -> StringBuffer; var - result: StringBuffer; + result: StringBuffer begin result.capacity := 64u; result.data := malloc(result.capacity); @@ -266,7 +266,7 @@ end proc string_buffer_clear(buffer: ^StringBuffer) -> String; var - result: String; + result: String begin result := String(cast(buffer^.data: ^Char), buffer^.size); buffer^.size := 0u; @@ -284,8 +284,8 @@ end proc read_source(filename: ^Char) -> ^SourceFile; var - result: ^SourceFile; - file_handle: ^FILE; + result: ^SourceFile + file_handle: ^FILE begin file_handle := fopen(filename, "rb\0".ptr); @@ -300,7 +300,7 @@ end proc escape_char(escape: Char, result: ^Char) -> Bool; var - successful: Bool; + successful: Bool begin if escape = 'n' then result^ := '\n'; @@ -346,7 +346,7 @@ end proc source_file_empty(source_input: ^Byte) -> Bool; var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); @@ -360,7 +360,7 @@ end proc source_file_head(source_input: ^Byte) -> Char; var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); @@ -369,7 +369,7 @@ end proc source_file_advance(source_input: ^Byte); var - source_file: ^SourceFile; + source_file: ^SourceFile begin source_file := cast(source_input: ^SourceFile); @@ -405,7 +405,7 @@ end proc skip_spaces(source_code: ^SourceCode); var - current: Char; + current: Char begin while ~source_code_empty(source_code), loop do current := source_code_head(source_code^); @@ -426,7 +426,7 @@ end proc lex_identifier(source_code: ^SourceCode, token_content: ^StringBuffer); var - content_length: Word; + content_length: Word begin while ~source_code_empty(source_code) & is_ident(source_code_head(source_code^)) do string_buffer_push(token_content, source_code_head(source_code^)); @@ -436,7 +436,7 @@ end proc lex_comment(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; var - trailing: Word; + trailing: Word begin trailing := 0u; @@ -459,7 +459,7 @@ end proc lex_character(source_code: ^SourceCode, token_content: ^Char) -> Bool; var - successful: Bool; + successful: Bool begin successful := ~source_code_empty(source_code); @@ -481,10 +481,10 @@ end proc lex_string(source_code: ^SourceCode, token_content: ^StringBuffer) -> Bool; var - token_end, constructed_string: ^Char; - token_length: Word; - is_valid: Bool; - next_char: Char; + token_end, constructed_string: ^Char + token_length: Word + is_valid: Bool + next_char: Char begin is_valid := true; @@ -517,8 +517,8 @@ end proc print_tokens(tokens: ^Token, tokens_size: Word); var - current_token: ^Token; - i: Word; + current_token: ^Token + i: Word begin i := 0u; while i < tokens_size do @@ -667,7 +667,7 @@ end proc categorize_identifier(token_content: String) -> Token; var - current_token: Token; + current_token: Token begin if "if" = token_content then current_token.kind := TokenKind._if @@ -737,9 +737,9 @@ end proc tokenize(source_code: SourceCode, tokens_size: ^Word) -> ^Token; var - tokens, current_token: ^Token; - first_char: Char; - token_buffer: StringBuffer; + tokens, current_token: ^Token + first_char: Char + token_buffer: StringBuffer begin tokens_size^ := 0u; tokens := nil; @@ -914,9 +914,9 @@ end proc parse_command_line*(argc: Int, argv: ^^Char) -> ^CommandLine; var - parameter: ^^Char; - i: Int; - result: ^CommandLine; + parameter: ^^Char + i: Int + result: ^CommandLine begin i := 1; result := cast(malloc(#size(CommandLine)): ^CommandLine); @@ -955,11 +955,11 @@ end proc process(argc: Int, argv: ^^Char) -> Int; var - tokens: ^Token; - tokens_size: Word; - source_code: SourceCode; - command_line: ^CommandLine; - return_code: Int; + tokens: ^Token + tokens_size: Word + source_code: SourceCode + command_line: ^CommandLine + return_code: Int begin return_code := 0;