Provide record initialization syntax

This commit is contained in:
Eugen Wissner 2025-02-13 22:54:47 +01:00
parent 62d9398772
commit c564847c6b
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
7 changed files with 115 additions and 56 deletions

View File

@ -69,6 +69,9 @@ namespace :boot do
end end
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 => ['source.elna']
file (TMP + 'elna').to_path => [(HOST_INSTALL + 'bin/gelna').to_path] do |task| 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 sh (HOST_INSTALL + 'bin/gelna').to_path, '-o', task.name, task.prerequisites.first

View File

@ -444,7 +444,7 @@ variable_declarations:
variable_part: variable_part:
/* no variable declarations */ {} /* no variable declarations */ {}
| VAR variable_declarations SEMICOLON { std::swap($$, $2); } | 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); $$ = 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); $$ = new elna::boot::type_definition(elna::boot::make_position(@1), $1.first, $1.second, $3);
} }
type_definitions: type_definitions:
type_definition COMMA type_definitions type_definition type_definitions
{ {
std::swap($$, $3); std::swap($$, $2);
$$.emplace($$.cbegin(), std::move($1)); $$.emplace($$.cbegin(), std::move($1));
} }
| type_definition { $$.emplace_back(std::move($1)); } | type_definition { $$.emplace_back(std::move($1)); }
type_part: type_part:
/* no type definitions */ {} /* no type definitions */ {}
| TYPE type_definitions SEMICOLON { std::swap($$, $2); } | TYPE {}
| TYPE type_definitions { std::swap($$, $2); }
formal_parameter_list: formal_parameter_list:
LEFT_PAREN RIGHT_PAREN {} LEFT_PAREN RIGHT_PAREN {}
| LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); } | LEFT_PAREN variable_declarations RIGHT_PAREN { std::swap($$, $2); }

View File

@ -56,20 +56,17 @@ namespace gcc
} }
else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol))) else if (DECL_P(symbol) && is_procedure_type(TREE_TYPE(symbol)))
{ {
tree return_type = TREE_TYPE(TREE_TYPE(symbol)); vec<tree, va_gc> *arguments = nullptr;
tree fndecl_type = build_function_type(return_type, TYPE_ARG_TYPES(symbol));
tree printf_fn = build1(ADDR_EXPR, build_pointer_type(fndecl_type), symbol);
std::vector<tree> arguments(expression->arguments().size()); vec_alloc(arguments, expression->arguments().size());
for (std::size_t i = 0; i < expression->arguments().size(); ++i) for (boot::expression *const argument : expression->arguments())
{ {
expression->arguments().at(i)->accept(this); argument->accept(this);
arguments[i] = this->current_expression; arguments->quick_push(this->current_expression);
} }
tree stmt = build_call_array_loc(get_location(&expression->position()), tree stmt = build_call_expr_loc_vec(get_location(&expression->position()), symbol, arguments);
return_type, printf_fn, arguments.size(), arguments.data());
if (return_type == void_type_node) if (TREE_TYPE(TREE_TYPE(symbol)) == void_type_node)
{ {
append_statement(stmt); append_statement(stmt);
this->current_expression = NULL_TREE; this->current_expression = NULL_TREE;
@ -79,6 +76,18 @@ namespace gcc
this->current_expression = stmt; this->current_expression = stmt;
} }
} }
else if (TYPE_P(symbol) && is_record_type(symbol))
{
vec<constructor_elt, va_gc> *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 else
{ {
error_at(call_location, "'%s' cannot be called, it is neither a procedure nor record", 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, integer_zero_node, NULL_TREE, NULL_TREE);
string_literal = build1(ADDR_EXPR, string_type, string_literal); string_literal = build1(ADDR_EXPR, string_type, string_literal);
vec<constructor_elt, va_gc> *elms = NULL; vec<constructor_elt, va_gc> *elms = nullptr;
CONSTRUCTOR_APPEND_ELT(elms, elna_string_ptr_field_node, string_literal); CONSTRUCTOR_APPEND_ELT(elms, elna_string_ptr_field_node, string_literal);
CONSTRUCTOR_APPEND_ELT(elms, elna_string_length_field_node, index_constant); CONSTRUCTOR_APPEND_ELT(elms, elna_string_length_field_node, index_constant);
@ -851,7 +860,7 @@ namespace gcc
else else
{ {
error_at(statement_location, 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(this->current_expression)).c_str(),
print_type(TREE_TYPE(lvalue)).c_str()); print_type(TREE_TYPE(lvalue)).c_str());
this->current_expression = error_mark_node; this->current_expression = error_mark_node;

View File

@ -62,6 +62,11 @@ namespace gcc
return type == NULL_TREE || type == void_type_node; 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) bool are_compatible_pointers(tree lhs, tree rhs)
{ {
tree lhs_type = TREE_TYPE(lhs); tree lhs_type = TREE_TYPE(lhs);

View File

@ -39,6 +39,7 @@ namespace gcc
bool is_array_type(tree type); bool is_array_type(tree type);
bool is_procedure_type(tree type); bool is_procedure_type(tree type);
bool is_void_type(tree type); bool is_void_type(tree type);
bool is_record_type(tree type);
/** /**
* \param lhs Left hand value. * \param lhs Left hand value.

View File

@ -1,68 +1,113 @@
const 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_IDENTIFIER* = 1
TOKEN_WHILE* = 6; TOKEN_DO* = 7; TOKEN_PROC* = 8; TOKEN_BEGIN* = 9; TOKEN_END* = 10; TOKEN_IF* = 2
TOKEN_EXTERN* = 11; TOKEN_CONST* = 12; TOKEN_VAR* = 13; TOKEN_ARRAY* = 14; TOKEN_OF* = 15; TOKEN_THEN* = 3
TOKEN_TYPE* = 16; TOKEN_RECORD* = 17; TOKEN_UNION* = 18; TOKEN_POINTER* = 19; TOKEN_TO* = 20; TOKEN_ELSE* = 4
TOKEN_BOOLEAN* = 21; TOKEN_NIL* = 22; TOKEN_AND* = 23; TOKEN_OR* = 24; TOKEN_NOT* = 25; TOKEN_ELSIF* = 5
TOKEN_RETURN* = 26; TOKEN_CAST* = 27; TOKEN_AS* = 28; TOKEN_SIZEOF* = 29; TOKEN_WHILE* = 6
TOKEN_LEFT_PAREN* = 30; TOKEN_RIGHT_PAREN* = 31; TOKEN_LEFT_SQUARE* = 32; TOKEN_DO* = 7
TOKEN_RIGHT_SQUARE* = 33; TOKEN_GREATER_EQUAL* = 34; TOKEN_LESS_EQUAL* = 35; TOKEN_PROC* = 8
TOKEN_GREATER_THAN* = 36; TOKEN_LESS_THAN* = 37; TOKEN_NOT_EQUAL* = 38; TOKEN_EQUAL* = 39; TOKEN_BEGIN* = 9
TOKEN_SEMICOLON* = 40; TOKEN_DOT* = 41; TOKEN_COMMA* = 42; TOKEN_END* = 10
TOKEN_PLUS* = 43; TOKEN_MINUS* = 44; TOKEN_MULTIPLICATION* = 45; TOKEN_DIVISION* = 46; TOKEN_EXTERN* = 11
TOKEN_REMAINDER* = 47; TOKEN_ASSIGNMENT* = 48; TOKEN_COLON* = 49; TOKEN_HAT* = 50; TOKEN_CONST* = 12
TOKEN_AT* = 51; TOKEN_COMMENT* = 52; TOKEN_INTEGER* = 53; TOKEN_WORD* = 54; TOKEN_VAR* = 13
TOKEN_CHARACTER* = 55; TOKEN_STRING* = 56; TOKEN_DEFER* = 57; 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 type
Position* = record Position* = record
line: Word; line: Word;
column: Word column: Word
end, end
Location* = record Location* = record
first: Position; first: Position;
last: Position last: Position
end, end
SourceCode = record SourceCode = record
position: Position; position: Position;
text: String text: String
end, end
TokenValue* = union TokenValue* = union
int_value: Int; int_value: Int;
string_value: pointer to Char; string_value: pointer to Char;
string: String; string: String;
boolean_value: Bool; boolean_value: Bool;
char_value: Char char_value: Char
end, end
Token* = record Token* = record
kind: Int; kind: Int;
value: TokenValue; value: TokenValue;
location: Location location: Location
end, end
FILE* = record FILE* = record
dummy: Int dummy: Int
end, end
CommandLine* = record CommandLine* = record
input: pointer to Char; input: pointer to Char;
tokenize: Bool; tokenize: Bool;
syntax_tree: Bool syntax_tree: Bool
end, end
Literal* = record Literal* = record
value: Int value: Int
end, end
ConstantDefinition* = record ConstantDefinition* = record
name: pointer to Char; name: pointer to Char;
body: pointer to Literal body: pointer to Literal
end, end
ConstantPart* = record ConstantPart* = record
elements: pointer to pointer to ConstantDefinition; elements: pointer to pointer to ConstantDefinition;
count: Word count: Word
end, end
Program* = record Program* = record
constants: ConstantPart constants: ConstantPart
end; end
(* (*
External procedures. External procedures.
@ -173,18 +218,14 @@ begin
return c = ' ' or c = '\n' or c = '\t' return c = ' ' or c = '\n' or c = '\t'
end 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; proc substring(string: String, start: Word, count: Word) -> String;
begin begin
string.ptr := string.ptr + start; return String(string.ptr + start, count)
string.length := count; end
return string
proc open_substring(string: String, start: Word) -> String;
begin
return substring(string, start, string.length - start)
end end
proc string_dup(origin: String) -> String; proc string_dup(origin: String) -> String;
@ -193,9 +234,8 @@ var
begin begin
copy := cast(malloc(origin.length) as pointer to Char); copy := cast(malloc(origin.length) as pointer to Char);
strncpy(copy, origin.ptr, origin.length); strncpy(copy, origin.ptr, origin.length);
origin.ptr := copy;
return origin return String(copy, origin.length)
end end
(* (*

View File

@ -15,7 +15,7 @@ class BuildTarget
attr_accessor(:build, :gcc, :sysroot, :tmp) attr_accessor(:build, :gcc, :sysroot, :tmp)
def initialize def initialize
@sysroot = '/' @sysroot = Pathname.new '/'
end end
def gxx def gxx
@ -55,7 +55,7 @@ def find_build_target(gcc_version)
end end
end end
result.tmp = TMP result.tmp = TMP
result.sysroot = sdk result.sysroot = sdk unless sdk.nil?
result result
end end