From c564847c6b458b8b36267ca278ce769cb7ab5332 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Thu, 13 Feb 2025 22:54:47 +0100 Subject: [PATCH] Provide record initialization syntax --- Rakefile | 3 + boot/parser.yy | 9 +-- gcc/elna-generic.cc | 33 ++++++---- gcc/elna-tree.cc | 5 ++ include/elna/gcc/elna-tree.h | 1 + source.elna | 116 +++++++++++++++++++++++------------ tools/support.rb | 4 +- 7 files changed, 115 insertions(+), 56 deletions(-) diff --git a/Rakefile b/Rakefile index 98596ee..d9f08a9 100644 --- a/Rakefile +++ b/Rakefile @@ -69,6 +69,9 @@ namespace :boot do end end +desc 'Build the bootstrap compiler' +task boot: %w[boot:configure boot:make] + file (TMP + 'elna').to_path => ['source.elna'] file (TMP + 'elna').to_path => [(HOST_INSTALL + 'bin/gelna').to_path] do |task| sh (HOST_INSTALL + 'bin/gelna').to_path, '-o', task.name, task.prerequisites.first diff --git a/boot/parser.yy b/boot/parser.yy index 7f324f3..f59f8ab 100644 --- a/boot/parser.yy +++ b/boot/parser.yy @@ -444,7 +444,7 @@ variable_declarations: variable_part: /* no variable declarations */ {} | VAR variable_declarations SEMICOLON { std::swap($$, $2); } -constant_definition: identifier_definition EQUALS literal SEMICOLON +constant_definition: identifier_definition EQUALS literal { $$ = new elna::boot::constant_definition(elna::boot::make_position(@1), $1.first, $1.second, $3); } @@ -464,15 +464,16 @@ type_definition: identifier_definition EQUALS type_expression $$ = new elna::boot::type_definition(elna::boot::make_position(@1), $1.first, $1.second, $3); } type_definitions: - type_definition COMMA type_definitions + type_definition type_definitions { - std::swap($$, $3); + std::swap($$, $2); $$.emplace($$.cbegin(), std::move($1)); } | type_definition { $$.emplace_back(std::move($1)); } type_part: /* no type definitions */ {} - | TYPE type_definitions SEMICOLON { std::swap($$, $2); } + | TYPE {} + | TYPE type_definitions { std::swap($$, $2); } formal_parameter_list: LEFT_PAREN RIGHT_PAREN {} | LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); } diff --git a/gcc/elna-generic.cc b/gcc/elna-generic.cc index d6d2709..bd704bc 100644 --- a/gcc/elna-generic.cc +++ b/gcc/elna-generic.cc @@ -56,20 +56,17 @@ namespace gcc } else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol))) { - tree return_type = TREE_TYPE(TREE_TYPE(symbol)); - tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(symbol)); - tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol); + vec *arguments = nullptr; - std::vector arguments(expression->arguments().size()); - for (std::size_t i = 0; i < expression->arguments().size(); ++i) + vec_alloc(arguments, expression->arguments().size()); + for (boot::expression *const argument : expression->arguments()) { - expression->arguments().at(i)->accept(this); - arguments[i] = this->current_expression; + argument->accept(this); + arguments->quick_push(this->current_expression); } - tree stmt = build_call_array_loc(get_location(&expression->position()), - return_type, printf_fn, arguments.size(), arguments.data()); + tree stmt = build_call_expr_loc_vec(get_location(&expression->position()), symbol, arguments); - if (return_type == void_type_node) + if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node) { append_statement(stmt); this->current_expression = NULL_TREE; @@ -79,6 +76,18 @@ namespace gcc this->current_expression = stmt; } } + else if (TYPE_P(symbol) && is_record_type(symbol)) + { + vec *arguments = nullptr; + tree record_fields = TYPE_FIELDS(symbol); + for (boot::expression *const argument : expression->arguments()) + { + argument->accept(this); + CONSTRUCTOR_APPEND_ELT(arguments, record_fields, this->current_expression); + record_fields = TREE_CHAIN(record_fields); + } + this->current_expression = build_constructor(symbol, arguments); + } else { error_at(call_location, "'%s' cannot be called, it is neither a procedure nor record", @@ -360,7 +369,7 @@ namespace gcc string_literal, integer_zero_node, NULL_TREE, NULL_TREE); string_literal = build1(ADDR_EXPR, string_type, string_literal); - vec *elms = NULL; + vec *elms = nullptr; CONSTRUCTOR_APPEND_ELT(elms, elna_string_ptr_field_node, string_literal); CONSTRUCTOR_APPEND_ELT(elms, elna_string_length_field_node, index_constant); @@ -851,7 +860,7 @@ namespace gcc else { error_at(statement_location, - "cannot assign value of type %s to variable of type %s", + "cannot assign value of type '%s' to variable of type '%s'", print_type(TREE_TYPE(this->current_expression)).c_str(), print_type(TREE_TYPE(lvalue)).c_str()); this->current_expression = error_mark_node; diff --git a/gcc/elna-tree.cc b/gcc/elna-tree.cc index 17d3db2..a51b540 100644 --- a/gcc/elna-tree.cc +++ b/gcc/elna-tree.cc @@ -62,6 +62,11 @@ namespace gcc return type == NULL_TREE || type == void_type_node; } + bool is_record_type(tree type) + { + return TREE_CODE(type) == RECORD_TYPE; + } + bool are_compatible_pointers(tree lhs, tree rhs) { tree lhs_type = TREE_TYPE(lhs); diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index bb10911..d1970e9 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -39,6 +39,7 @@ namespace gcc bool is_array_type(tree type); bool is_procedure_type(tree type); bool is_void_type(tree type); + bool is_record_type(tree type); /** * \param lhs Left hand value. diff --git a/source.elna b/source.elna index 6981e38..51c6e9c 100644 --- a/source.elna +++ b/source.elna @@ -1,68 +1,113 @@ const - SEEK_SET* = 0; SEEK_CUR* = 1; SEEK_END* = 2; + SEEK_SET* = 0 + SEEK_CUR* = 1 + SEEK_END* = 2 - TOKEN_IDENTIFIER* = 1; TOKEN_IF* = 2; TOKEN_THEN* = 3; TOKEN_ELSE* = 4; TOKEN_ELSIF* = 5; - TOKEN_WHILE* = 6; TOKEN_DO* = 7; TOKEN_PROC* = 8; TOKEN_BEGIN* = 9; TOKEN_END* = 10; - TOKEN_EXTERN* = 11; TOKEN_CONST* = 12; TOKEN_VAR* = 13; TOKEN_ARRAY* = 14; TOKEN_OF* = 15; - TOKEN_TYPE* = 16; TOKEN_RECORD* = 17; TOKEN_UNION* = 18; TOKEN_POINTER* = 19; TOKEN_TO* = 20; - TOKEN_BOOLEAN* = 21; TOKEN_NIL* = 22; TOKEN_AND* = 23; TOKEN_OR* = 24; TOKEN_NOT* = 25; - TOKEN_RETURN* = 26; TOKEN_CAST* = 27; TOKEN_AS* = 28; TOKEN_SIZEOF* = 29; - TOKEN_LEFT_PAREN* = 30; TOKEN_RIGHT_PAREN* = 31; TOKEN_LEFT_SQUARE* = 32; - TOKEN_RIGHT_SQUARE* = 33; TOKEN_GREATER_EQUAL* = 34; TOKEN_LESS_EQUAL* = 35; - TOKEN_GREATER_THAN* = 36; TOKEN_LESS_THAN* = 37; TOKEN_NOT_EQUAL* = 38; TOKEN_EQUAL* = 39; - TOKEN_SEMICOLON* = 40; TOKEN_DOT* = 41; TOKEN_COMMA* = 42; - TOKEN_PLUS* = 43; TOKEN_MINUS* = 44; TOKEN_MULTIPLICATION* = 45; TOKEN_DIVISION* = 46; - TOKEN_REMAINDER* = 47; TOKEN_ASSIGNMENT* = 48; TOKEN_COLON* = 49; TOKEN_HAT* = 50; - TOKEN_AT* = 51; TOKEN_COMMENT* = 52; TOKEN_INTEGER* = 53; TOKEN_WORD* = 54; - TOKEN_CHARACTER* = 55; TOKEN_STRING* = 56; TOKEN_DEFER* = 57; + TOKEN_IDENTIFIER* = 1 + TOKEN_IF* = 2 + TOKEN_THEN* = 3 + TOKEN_ELSE* = 4 + TOKEN_ELSIF* = 5 + TOKEN_WHILE* = 6 + TOKEN_DO* = 7 + TOKEN_PROC* = 8 + TOKEN_BEGIN* = 9 + TOKEN_END* = 10 + TOKEN_EXTERN* = 11 + TOKEN_CONST* = 12 + TOKEN_VAR* = 13 + TOKEN_ARRAY* = 14 + TOKEN_OF* = 15 + TOKEN_TYPE* = 16 + TOKEN_RECORD* = 17 + TOKEN_UNION* = 18 + TOKEN_POINTER* = 19 + TOKEN_TO* = 20 + TOKEN_BOOLEAN* = 21 + TOKEN_NIL* = 22 + TOKEN_AND* = 23 + TOKEN_OR* = 24 + TOKEN_NOT* = 25 + TOKEN_RETURN* = 26 + TOKEN_CAST* = 27 + TOKEN_AS* = 28 + TOKEN_SIZEOF* = 29 + TOKEN_LEFT_PAREN* = 30 + TOKEN_RIGHT_PAREN* = 31 + TOKEN_LEFT_SQUARE* = 32 + TOKEN_RIGHT_SQUARE* = 33 + TOKEN_GREATER_EQUAL* = 34 + TOKEN_LESS_EQUAL* = 35 + TOKEN_GREATER_THAN* = 36 + TOKEN_LESS_THAN* = 37 + TOKEN_NOT_EQUAL* = 38 + TOKEN_EQUAL* = 39 + TOKEN_SEMICOLON* = 40 + TOKEN_DOT* = 41 + TOKEN_COMMA* = 42 + TOKEN_PLUS* = 43 + TOKEN_MINUS* = 44 + TOKEN_MULTIPLICATION* = 45 + TOKEN_DIVISION* = 46 + TOKEN_REMAINDER* = 47 + TOKEN_ASSIGNMENT* = 48 + TOKEN_COLON* = 49 + TOKEN_HAT* = 50 + TOKEN_AT* = 51 + TOKEN_COMMENT* = 52 + TOKEN_INTEGER* = 53 + TOKEN_WORD* = 54 + TOKEN_CHARACTER* = 55 + TOKEN_STRING* = 56 + TOKEN_DEFER* = 57 type Position* = record line: Word; column: Word - end, + end Location* = record first: Position; last: Position - end, + end SourceCode = record position: Position; text: String - end, + end TokenValue* = union int_value: Int; string_value: pointer to Char; string: String; boolean_value: Bool; char_value: Char - end, + end Token* = record kind: Int; value: TokenValue; location: Location - end, + end FILE* = record dummy: Int - end, + end CommandLine* = record input: pointer to Char; tokenize: Bool; syntax_tree: Bool - end, + end Literal* = record value: Int - end, + end ConstantDefinition* = record name: pointer to Char; body: pointer to Literal - end, + end ConstantPart* = record elements: pointer to pointer to ConstantDefinition; count: Word - end, + end Program* = record constants: ConstantPart - end; + end (* External procedures. @@ -173,18 +218,14 @@ begin return c = ' ' or c = '\n' or c = '\t' end -proc open_substring(string: String, start: Word) -> String; -begin - string.ptr := string.ptr + start; - string.length := string.length - start; - return string -end - proc substring(string: String, start: Word, count: Word) -> String; begin - string.ptr := string.ptr + start; - string.length := count; - return string + return String(string.ptr + start, count) +end + +proc open_substring(string: String, start: Word) -> String; +begin + return substring(string, start, string.length - start) end proc string_dup(origin: String) -> String; @@ -193,9 +234,8 @@ var begin copy := cast(malloc(origin.length) as pointer to Char); strncpy(copy, origin.ptr, origin.length); - origin.ptr := copy; - return origin + return String(copy, origin.length) end (* diff --git a/tools/support.rb b/tools/support.rb index 945580a..c7d8d78 100644 --- a/tools/support.rb +++ b/tools/support.rb @@ -15,7 +15,7 @@ class BuildTarget attr_accessor(:build, :gcc, :sysroot, :tmp) def initialize - @sysroot = '/' + @sysroot = Pathname.new '/' end def gxx @@ -55,7 +55,7 @@ def find_build_target(gcc_version) end end result.tmp = TMP - result.sysroot = sdk + result.sysroot = sdk unless sdk.nil? result end