From b358f8ba27d6e5e3b38c60c4aafe5e8346669414 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 15 Feb 2025 10:26:04 +0100 Subject: [PATCH] Allow multiple variable declarations with a single type --- boot/ast.cc | 52 ++++++---------------------------- boot/parser.yy | 61 ++++++++++++++++++++++++++++------------ gcc/elna-builtins.cc | 4 +-- gcc/elna-generic.cc | 10 +++---- gcc/elna-tree.cc | 22 ++++++++------- include/elna/boot/ast.h | 44 +++++++++++------------------ source.elna | 62 ++++++++++++++++++++--------------------- 7 files changed, 117 insertions(+), 138 deletions(-) diff --git a/boot/ast.cc b/boot/ast.cc index 0091962..103faec 100644 --- a/boot/ast.cc +++ b/boot/ast.cc @@ -300,8 +300,7 @@ namespace boot return this; } - array_type::array_type(const struct position position, top_type *base, - const std::uint32_t size) + array_type::array_type(const struct position position, std::shared_ptr base, const std::uint32_t size) : top_type(position), m_base(base), size(size) { } @@ -321,12 +320,7 @@ namespace boot return this; } - array_type::~array_type() - { - delete m_base; - } - - pointer_type::pointer_type(const struct position position, top_type *base) + pointer_type::pointer_type(const struct position position, std::shared_ptr base) : top_type(position), m_base(base) { } @@ -346,24 +340,11 @@ namespace boot return this; } - pointer_type::~pointer_type() - { - delete m_base; - } - composite_type::composite_type(const struct position position, fields_t&& fields) : top_type(position), fields(std::move(fields)) { } - composite_type::~composite_type() - { - for (auto& field_declaration : fields) - { - delete field_declaration.second; - } - } - record_type::record_type(const struct position position, fields_t&& fields) : composite_type(position, std::move(fields)) { @@ -395,16 +376,11 @@ namespace boot } variable_declaration::variable_declaration(const struct position position, const std::string& identifier, - const bool exported, top_type *type) + std::shared_ptr type, const bool exported) : definition(position, identifier, exported), m_type(type) { } - variable_declaration::~variable_declaration() - { - delete m_type; - } - void variable_declaration::accept(parser_visitor *visitor) { visitor->visit(this); @@ -442,7 +418,7 @@ namespace boot } procedure_definition::procedure_definition(const struct position position, const std::string& identifier, - const bool exported, top_type *return_type) + const bool exported, std::shared_ptr return_type) : definition(position, identifier, exported), m_return_type(return_type) { } @@ -463,7 +439,7 @@ namespace boot return this; } - top_type *procedure_definition::return_type() + std::shared_ptr procedure_definition::return_type() { return m_return_type; } @@ -481,7 +457,7 @@ namespace boot } type_definition::type_definition(const struct position position, const std::string& identifier, - const bool exported, top_type *body) + const bool exported, std::shared_ptr body) : definition(position, identifier, exported), m_body(body) { } @@ -496,11 +472,6 @@ namespace boot return *m_body; } - type_definition::~type_definition() - { - delete m_body; - } - block::block(const struct position position) : node(position) { @@ -772,7 +743,8 @@ namespace boot } } - cast_expression::cast_expression(const struct position position, top_type *target, expression *value) + cast_expression::cast_expression(const struct position position, + std::shared_ptr target, expression *value) : expression(position), m_target(target), m_value(value) { } @@ -794,11 +766,10 @@ namespace boot cast_expression::~cast_expression() { - delete m_target; delete m_value; } - type_expression::type_expression(const struct position position, top_type *body) + type_expression::type_expression(const struct position position, std::shared_ptr body) : expression(position), m_body(body) { } @@ -813,11 +784,6 @@ namespace boot return *m_body; } - type_expression::~type_expression() - { - delete m_body; - } - call_statement::call_statement(const struct position position, call_expression *body) : statement(position), m_body(body) { diff --git a/boot/parser.yy b/boot/parser.yy index 49f3af9..f1dc28b 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -98,10 +98,10 @@ along with GCC; see the file COPYING3. If not see %type literal; %type constant_definition; %type > constant_part constant_definitions; -%type variable_declaration; -%type > variable_declarations variable_part - formal_parameter_list; -%type type_expression; +%type > variable_declarations variable_part variable_declaration + formal_parameters formal_parameter_list; +%type formal_parameter +%type > type_expression; %type expression operand unary; %type > expressions actual_parameter_list; %type designator_expression; @@ -117,12 +117,13 @@ along with GCC; see the file COPYING3. If not see %type type_definition; %type > type_definitions type_part; %type block; -%type > field_declaration; -%type >> field_list; +%type field_declaration; +%type >>> field_list; %type > elsif_statement_list; %type cast_expression; %type defer_statement; %type > identifier_definition; +%type >> identifier_definitions; %% program: constant_part type_part variable_part procedure_part BEGIN_BLOCK optional_statements END_BLOCK DOT @@ -154,6 +155,13 @@ identifier_definition: { $$ = std::make_pair($1, false); } +identifier_definitions: + identifier_definition COMMA identifier_definitions + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | identifier_definition { $$.emplace_back(std::move($1)); } procedure_heading: PROCEDURE identifier_definition formal_parameter_list SEMICOLON { @@ -427,35 +435,41 @@ field_list: type_expression: ARRAY INTEGER OF type_expression { - $$ = new elna::boot::array_type(elna::boot::make_position(@1), $4, $2); + $$ = std::make_shared(elna::boot::make_position(@1), $4, $2); } | POINTER TO type_expression { - $$ = new elna::boot::pointer_type(elna::boot::make_position(@1), $3); + $$ = std::make_shared(elna::boot::make_position(@1), $3); } | RECORD field_list END_BLOCK { - $$ = new elna::boot::record_type(elna::boot::make_position(@1), std::move($2)); + $$ = std::make_shared(elna::boot::make_position(@1), std::move($2)); } | UNION field_list END_BLOCK { - $$ = new elna::boot::union_type(elna::boot::make_position(@1), std::move($2)); + $$ = std::make_shared(elna::boot::make_position(@1), std::move($2)); } | IDENTIFIER { - $$ = new elna::boot::basic_type(elna::boot::make_position(@1), $1); + $$ = std::make_shared(elna::boot::make_position(@1), $1); } -variable_declaration: identifier_definition COLON type_expression +variable_declaration: identifier_definitions COLON type_expression { - $$ = new elna::boot::variable_declaration(elna::boot::make_position(@2), $1.first, $1.second, $3); + for (const std::pair& identifier : $1) + { + elna::boot::variable_declaration *declaration = new elna::boot::variable_declaration( + elna::boot::make_position(@2), identifier.first, $3, identifier.second); + $$.push_back(declaration); + } } variable_declarations: - variable_declaration COMMA variable_declarations + variable_declaration variable_declarations { - std::swap($$, $3); - $$.emplace($$.cbegin(), $1); + std::swap($$, $1); + $$.reserve($$.size() + $2.size()); + $$.insert(std::end($$), std::begin($2), std::end($2)); } - | variable_declaration { $$.emplace_back(std::move($1)); } + | variable_declaration { std::swap($$, $1); } variable_part: /* no variable declarations */ {} | VAR variable_declarations { std::swap($$, $2); } @@ -489,9 +503,20 @@ type_part: /* no type definitions */ {} | TYPE {} | TYPE type_definitions { std::swap($$, $2); } +formal_parameter: IDENTIFIER COLON type_expression + { + $$ = new elna::boot::variable_declaration(elna::boot::make_position(@2), $1, $3); + } +formal_parameters: + formal_parameter COMMA formal_parameters + { + std::swap($$, $3); + $$.emplace($$.cbegin(), $1); + } + | formal_parameter { $$.emplace_back(std::move($1)); } formal_parameter_list: LEFT_PAREN RIGHT_PAREN {} - | LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); } + | LEFT_PAREN formal_parameters RIGHT_PAREN { std::swap($$, $2); } actual_parameter_list: LEFT_PAREN RIGHT_PAREN {} | LEFT_PAREN expressions RIGHT_PAREN { std::swap($$, $2); } diff --git a/gcc/elna-builtins.cc b/gcc/elna-builtins.cc index 22aba2c..3f67671 100644 --- a/gcc/elna-builtins.cc +++ b/gcc/elna-builtins.cc @@ -43,9 +43,9 @@ namespace gcc tree string_ptr_type = build_pointer_type_for_mode(elna_char_type_node, VOIDmode, true); elna_string_length_field_node = build_field(UNKNOWN_LOCATION, - elna_string_type_node, "length", elna_word_type_node); + elna_string_type_node, "length", build_qualified_type(elna_word_type_node, TYPE_QUAL_CONST)); elna_string_ptr_field_node = build_field(UNKNOWN_LOCATION, - elna_string_type_node, "ptr", string_ptr_type); + elna_string_type_node, "ptr", build_qualified_type(string_ptr_type, TYPE_QUAL_CONST)); TYPE_FIELDS(elna_string_type_node) = chainon(elna_string_ptr_field_node, elna_string_length_field_node); layout_type(elna_string_type_node); diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index cecfcee..c8761cd 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -108,7 +108,8 @@ namespace gcc break; } argument->accept(this); - if (!is_assignable_from(TREE_TYPE(record_fields), this->current_expression)) + tree unqualified_field = get_qualified_type(TREE_TYPE(record_fields), TYPE_UNQUALIFIED); + if (!is_assignable_from(unqualified_field, this->current_expression)) { error_at(argument_location, "cannot assign value of type '%s' to variable of type '%s'", @@ -548,11 +549,11 @@ namespace gcc { expression->lhs().accept(this); tree left = this->current_expression; - tree left_type = TREE_TYPE(left); + tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED); expression->rhs().accept(this); tree right = this->current_expression; - tree right_type = TREE_TYPE(right); + tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED); location_t expression_location = get_location(&expression->position()); @@ -1012,9 +1013,8 @@ namespace gcc error_at(statement_location, "cannot modify constant '%s'", statement->lvalue().is_variable()->name().c_str()); this->current_expression = error_mark_node; - return; } - if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression)) + else if (is_assignable_from(TREE_TYPE(lvalue), this->current_expression)) { tree assignment = build2_loc(statement_location, MODIFY_EXPR, void_type_node, lvalue, this->current_expression); diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index f36faf7..149539e 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -79,7 +79,7 @@ namespace gcc bool is_assignable_from(tree assignee, tree assignment) { - return TREE_TYPE(assignment) == assignee + return get_qualified_type(TREE_TYPE(assignment), TYPE_UNQUALIFIED) == assignee || are_compatible_pointers(assignee, assignment); } @@ -133,17 +133,19 @@ namespace gcc tree do_pointer_arithmetic(boot::binary_operator binary_operator, tree left, tree right) { + tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED); + tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED); if (binary_operator == boot::binary_operator::sum) { tree pointer{ NULL_TREE }; tree offset{ NULL_TREE }; - if (is_pointer_type(TREE_TYPE(left)) && is_integral_type(TREE_TYPE(right))) + if (is_pointer_type(left_type) && is_integral_type(right_type)) { pointer = left; offset = right; } - else if (is_integral_type(TREE_TYPE(left)) && is_pointer_type(TREE_TYPE(right))) + else if (is_integral_type(left_type) && is_pointer_type(right_type)) { pointer = right; offset = left; @@ -161,10 +163,10 @@ namespace gcc } else if (binary_operator == boot::binary_operator::subtraction) { - if (is_pointer_type(TREE_TYPE(left)) && is_integral_type(TREE_TYPE(right))) + if (is_pointer_type(left_type) && is_integral_type(right_type)) { - tree pointer_type = TREE_TYPE(left); - tree offset_type = TREE_TYPE(right); + tree pointer_type = left_type; + tree offset_type = right_type; tree size_exp = fold_convert(offset_type, size_in_bytes(TREE_TYPE(pointer_type))); tree convert_expression = fold_build2(MULT_EXPR, offset_type, right, size_exp); @@ -172,8 +174,8 @@ namespace gcc convert_expression = fold_build1(NEGATE_EXPR, sizetype, convert_expression); return fold_build2(POINTER_PLUS_EXPR, pointer_type, left, convert_expression); - } else if (is_pointer_type(TREE_TYPE(left)) && is_pointer_type(TREE_TYPE(right)) - && TREE_TYPE(left) == TREE_TYPE(right)) + } + else if (is_pointer_type(left_type) && is_pointer_type(right_type) && left_type == right_type) { return fold_build2(POINTER_DIFF_EXPR, ssizetype, left, right); } @@ -185,8 +187,8 @@ namespace gcc tree_code operator_code, tree left, tree right, tree target_type) { location_t expression_location = get_location(&expression->position()); - tree left_type = TREE_TYPE(left); - tree right_type = TREE_TYPE(right); + tree left_type = get_qualified_type(TREE_TYPE(left), TYPE_UNQUALIFIED); + tree right_type = get_qualified_type(TREE_TYPE(right), TYPE_UNQUALIFIED); if (condition) { diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index 06054e5..60bd64c 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -255,37 +255,33 @@ namespace boot class array_type : public top_type { - top_type *m_base; + std::shared_ptr m_base; public: const std::uint32_t size; - array_type(const struct position position, top_type*base, const std::uint32_t size); + array_type(const struct position position, std::shared_ptr base, const std::uint32_t size); virtual void accept(parser_visitor *visitor) override; top_type& base(); array_type *is_array() override; - - virtual ~array_type() override; }; class pointer_type : public top_type { - top_type *m_base; + std::shared_ptr m_base; public: - pointer_type(const struct position position, top_type *base); + pointer_type(const struct position position, std::shared_ptr base); virtual void accept(parser_visitor *visitor) override; top_type& base(); pointer_type *is_pointer() override; - - virtual ~pointer_type() override; }; - using field_t = std::pair; + using field_t = std::pair>; using fields_t = std::vector; class composite_type : public top_type @@ -295,8 +291,6 @@ namespace boot public: fields_t fields; - - virtual ~composite_type() override; }; class record_type : public composite_type @@ -322,16 +316,14 @@ namespace boot */ class variable_declaration : public definition { - top_type *m_type; + std::shared_ptr m_type; public: variable_declaration(const struct position position, const std::string& identifier, - const bool exported, top_type *type); + std::shared_ptr type, const bool exported = false); virtual void accept(parser_visitor *visitor) override; top_type& variable_type(); - - virtual ~variable_declaration() override; }; /** @@ -370,17 +362,17 @@ namespace boot */ class procedure_definition : public definition { - top_type *m_return_type{ nullptr }; + std::shared_ptr m_return_type{ nullptr }; block *m_body{ nullptr }; public: std::vector parameters; procedure_definition(const struct position position, const std::string& identifier, - const bool exported, top_type *return_type = nullptr); + const bool exported, std::shared_ptr return_type = nullptr); virtual void accept(parser_visitor *visitor) override; - top_type *return_type(); + std::shared_ptr return_type(); block *body(); procedure_definition *add_body(block *procedure_body); @@ -393,16 +385,14 @@ namespace boot */ class type_definition : public definition { - top_type *m_body; + std::shared_ptr m_body; public: type_definition(const struct position position, const std::string& identifier, - const bool exported, top_type *expression); + const bool exported, std::shared_ptr expression); virtual void accept(parser_visitor *visitor) override; top_type& body(); - - virtual ~type_definition() override; }; /** @@ -432,11 +422,11 @@ namespace boot */ class cast_expression : public expression { - top_type *m_target; + std::shared_ptr m_target; expression *m_value; public: - cast_expression(const struct position position, top_type *target, expression *value); + cast_expression(const struct position position, std::shared_ptr target, expression *value); virtual void accept(parser_visitor *visitor) override; top_type& target(); @@ -450,15 +440,13 @@ namespace boot */ class type_expression : public expression { - top_type *m_body; + std::shared_ptr m_body; public: - type_expression(const struct position position, top_type *body); + type_expression(const struct position position, std::shared_ptr body); virtual void accept(parser_visitor *visitor) override; top_type& body(); - - virtual ~type_expression() override; }; class call_statement : public statement diff --git a/source.elna b/source.elna index 3868369..065ef1b 100644 --- a/source.elna +++ b/source.elna @@ -30,8 +30,8 @@ const TOKEN_NOT* = 25 TOKEN_RETURN* = 26 TOKEN_CAST* = 27 - TOKEN_AS* = 28 - TOKEN_SIZEOF* = 29 + TOKEN_SHIFT_LEFT* = 28 + TOKEN_SHIFT_RIGHT* = 29 TOKEN_LEFT_PAREN* = 30 TOKEN_RIGHT_PAREN* = 31 TOKEN_LEFT_SQUARE* = 32 @@ -172,7 +172,8 @@ end proc write_i(value: Int); var - digit: Int, n: Word, + digit: Int + n: Word buffer: array 10 of Char begin n := 10u; @@ -243,16 +244,14 @@ end *) proc make_position() -> Position; -var - result: Position begin return Position(1u, 1u) end proc read_source(filename: pointer to Char, result: pointer to String) -> Bool; var - input_file: pointer to FILE, - source_size: Int, + input_file: pointer to FILE + source_size: Int input: pointer to Byte begin input_file := fopen(filename, "rb\0".ptr); @@ -276,8 +275,7 @@ begin if fread(input, cast(source_size: Word), 1u, input_file) <> 1u then return false end; - result^.length := cast(source_size: Word); - result^.ptr := cast(input: pointer to Char); + result^ := String(cast(input: pointer to Char), cast(source_size: Word)); return true end @@ -398,9 +396,8 @@ end proc lex_string(input: pointer to Char, current_token: pointer to Token) -> pointer to Char; var - token_end: pointer to Char, - constructed_string: pointer to Char, - token_length: Word, + token_end, constructed_string: pointer to Char + token_length: Word is_valid: Bool begin token_end := input; @@ -438,7 +435,7 @@ end proc print_tokens(tokens: pointer to Token, tokens_size: Word); var - current_token: pointer to Token, + current_token: pointer to Token i: Word begin i := 0u; @@ -499,10 +496,10 @@ begin write_s("RETURN") elsif current_token^.kind = TOKEN_CAST then write_s("CAST") - elsif current_token^.kind = TOKEN_AS then - write_s("AS") - elsif current_token^.kind = TOKEN_SIZEOF then - write_s("SIZEOF") + elsif current_token^.kind = TOKEN_SHIFT_LEFT then + write_s("<<") + elsif current_token^.kind = TOKEN_SHIFT_RIGHT then + write_s(">>") elsif current_token^.kind = TOKEN_IDENTIFIER then write_c('<'); write_s(current_token^.value.string); @@ -641,10 +638,6 @@ begin current_token.kind := TOKEN_RETURN elsif "cast" = token_content then current_token.kind := TOKEN_CAST - elsif "as" = token_content then - current_token.kind := TOKEN_AS - elsif "sizeof" = token_content then - current_token.kind := TOKEN_SIZEOF elsif "defer" = token_content then current_token.kind := TOKEN_DEFER else @@ -657,11 +650,10 @@ end proc tokenize(source_code: SourceCode, tokens_size: pointer to Word) -> pointer to Token; var - token_end: pointer to Char, - tokens: pointer to Token, - current_token: pointer to Token, - token_length: Word, - first_char: Char, + token_end: pointer to Char + tokens, current_token: pointer to Token + token_length: Word + first_char: Char token_content: String begin tokens_size^ := 0u; @@ -740,6 +732,9 @@ begin elsif source_code.text[1u] = '=' then current_token^.kind := TOKEN_GREATER_EQUAL; source_code := advance_source(source_code, 1u) + elsif source_code.text[1u] = '>' then + current_token^.kind := TOKEN_SHIFT_RIGHT; + source_code := advance_source(source_code, 1u) else current_token^.kind := TOKEN_GREATER_THAN end @@ -751,6 +746,9 @@ begin elsif source_code.text[1u] = '=' then current_token^.kind := TOKEN_LESS_EQUAL; source_code := advance_source(source_code, 1u) + elsif source_code.text[1u] = '<' then + current_token^.kind := TOKEN_SHIFT_LEFT; + source_code := advance_source(source_code, 1u) elsif source_code.text[1u] = '>' then current_token^.kind := TOKEN_NOT_EQUAL; source_code := advance_source(source_code, 1u) @@ -850,7 +848,7 @@ end proc parse_program(tokens: pointer to pointer to Token, tokens_size: pointer to Word) -> pointer to Program; var - result: pointer to Program, + result: pointer to Program current_constant: pointer to pointer to ConstantDefinition begin result := cast(calloc(1u, Program.size): pointer to Program); @@ -883,8 +881,8 @@ end proc parse_command_line*(argc: Int, argv: pointer to pointer to Char) -> pointer to CommandLine; var - parameter: pointer to pointer to Char, - i: Int, + parameter: pointer to pointer to Char + i: Int result: pointer to CommandLine begin i := 1; @@ -924,9 +922,9 @@ end proc process(argc: Int, argv: pointer to pointer to Char) -> Int; var - tokens: pointer to Token, - tokens_size: Word, - source_code: SourceCode, + tokens: pointer to Token + tokens_size: Word + source_code: SourceCode command_line: pointer to CommandLine begin command_line := parse_command_line(argc, argv);