Implement array access expressions

This commit is contained in:
2026-01-14 19:48:28 +01:00
parent 30e18517ab
commit cfef0550ca
3 changed files with 227 additions and 52 deletions

View File

@@ -38,11 +38,48 @@ end
desc 'Convert previous stage language into the current stage language'
task :convert do
File.open('boot/stage18/cl.elna', 'w') do |current_stage|
File.readlines('boot/stage17/cl.elna').each do |line|
File.open('boot/stage19/cl.elna', 'w') do |current_stage|
File.readlines('boot/stage18/cl.elna').each do |line|
current_stage << "\tf();\n" if line.include? "if _compile() then"
current_stage << line
if line == "type\n"
current_stage << <<-RECORD
Pair = record
first: Word;
second: Word
end;
R1 = record
field1: Word;
field2: [4]Word;
field3: Word
end;
R2 = record
field1: Word;
field3: Word;
field4: Word;
field5: Word;
field6: Word;
field2: Word
end;
RECORD
end
end
current_stage << <<~EPILOGUE
proc f();
var
v1: Word;
r: ^R1;
begin
r := malloc(#size(R1));
v1 := r^.field2[2];
printf("# %i\\n\\0", v1)
end;
EPILOGUE
end
end
file "build/valid/#{STAGES.last}/cl" => 'build/build.ninja' do |t|
@@ -105,7 +142,10 @@ file 'build/build.ninja' => ['build'] do |t|
build #{valid_stage}/cl: #{link} #{valid_stage}/cl.o
NINJA
end
f << "\ndefault build/valid/stage18/cl\n"
f << <<~NINJA
default build/valid/#{STAGES.last}/cl
NINJA
end
end

View File

@@ -2707,7 +2707,15 @@ begin
if parser_node^.kind = ElnaTreeKind.dereference_expression then
dereference_expression := parser_node;
first_instruction := elna_tac_designator(dereference_expression^.pointer, symbol_table, is_address, operand_type, operand_value, operand_length);
if is_address^ = 1 then
last_instruction := _elna_tac_instruction_create(ElnaTacOperator.load);
_elna_tac_instruction_set_operand(last_instruction, 1, operand_type^, operand_value^, operand_length^);
_elna_tac_instruction_set_operand(last_instruction, 2, operand_type^, operand_value^, operand_length^);
first_instruction := elna_instruction_list_concatenate(first_instruction, last_instruction)
else
is_address^ := 1
end
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
field_access_expression := parser_node;
expression_type := field_access_expression^.type_decoration;

View File

@@ -8,6 +8,7 @@ program;
(* Stage 18 compiler. *)
(* - Record fields can be aggregates themselves *)
(* - Static arrays. *)
type
(**
@@ -92,7 +93,8 @@ type
pointer_type_expression,
array_type_expression,
null,
trait_expression
trait_expression,
array_access_expression
);
ElnaTreeNode = record
kind: ElnaTreeKind
@@ -196,6 +198,12 @@ type
field: Word;
length: Word
end;
ElnaTreeArrayAccessExpression = record
kind: ElnaTreeKind;
type_decoration: ^ElnaType;
array: Word;
index: Word
end;
ElnaTreeEnumerationTypeExpression = record
kind: ElnaTreeKind;
members: Word;
@@ -2114,6 +2122,9 @@ begin
elsif token_kind = ElnaLexerKind.dot then
simple_expression := elna_parser_field_access_expression(simple_expression);
goto elna_parser_designator_loop
elsif token_kind = ElnaLexerKind.left_square then
simple_expression := elna_parser_array_access_expression(simple_expression);
goto elna_parser_designator_loop
elsif token_kind = ElnaLexerKind.left_paren then
simple_expression := elna_parser_call(simple_expression);
goto elna_parser_designator_loop
@@ -2215,9 +2226,15 @@ begin
first_instruction := elna_tac_designator(operand, symbol_table, @is_address, operand_type, operand_value, operand_length);
if operator = '@' then
if is_address then
instruction := _elna_tac_instruction_create(ElnaTacOperator.copy);
_elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
_elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
else
instruction := _elna_tac_instruction_create(ElnaTacOperator.get_address);
_elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
_elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
end
elsif operator = '-' then
instruction := _elna_tac_instruction_create(ElnaTacOperator.negate);
_elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
@@ -2682,10 +2699,78 @@ begin
return result
end;
proc elna_parser_array_access_expression(array: Word);
var
token_kind: Word;
result: ^ElnaTreeArrayAccessExpression;
begin
_elna_lexer_skip_token();
result := malloc(#size(ElnaTreeArrayAccessExpression));
result^.kind := ElnaTreeKind.array_access_expression;
result^.type_decoration := nil;
result^.array := array;
result^.index := elna_parser_binary_expression();
_elna_lexer_read_token(@token_kind);
_elna_lexer_skip_token();
return result
end;
proc elna_tac_dereference_expression(dereference_expression: ^ElnaTreeDereferenceExpression, symbol_table: Word, operand_type: Word, operand_value: Word, operand_length: Word);
var
result_instructions: Word;
load_instruction: Word;
is_address: Word;
begin
result_instructions := elna_tac_designator(dereference_expression^.pointer, symbol_table, @is_address, operand_type, operand_value, operand_length);
if is_address = true then
load_instruction := _elna_tac_instruction_create(ElnaTacOperator.load);
_elna_tac_instruction_set_operand(load_instruction, 1, operand_type^, operand_value^, operand_length^);
_elna_tac_instruction_set_operand(load_instruction, 2, operand_type^, operand_value^, operand_length^);
result_instructions := elna_instruction_list_concatenate(result_instructions, load_instruction)
end;
return result_instructions
end;
proc elna_tac_designator(parser_node: ^ElnaTreeExpression, symbol_table: Word, is_address: Word, operand_type: Word, operand_value: Word, operand_length: Word);
var
field_access_expression: ^ElnaTreeFieldAccessExpression;
dereference_expression: ^ElnaTreeDereferenceExpression;
result_instructions: Word;
designator_base: ^ElnaTreeExpression;
begin
if parser_node^.kind = ElnaTreeKind.dereference_expression then
result_instructions := elna_tac_dereference_expression(parser_node, symbol_table, operand_type, operand_value, operand_length);
is_address^ := true
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
field_access_expression := parser_node;
designator_base := field_access_expression^.aggregate;
if designator_base^.type_decoration = nil then
result_instructions := elna_tac_enumeration_value(field_access_expression, operand_type, operand_value, operand_length);
is_address^ := false
else
result_instructions := elna_tac_field_access_expression(field_access_expression, symbol_table, operand_type, operand_value, operand_length);
is_address^ := true
end;
elsif parser_node^.kind = ElnaTreeKind.array_access_expression then
result_instructions := elna_tac_array_access_expression(parser_node, symbol_table, operand_type, operand_value, operand_length);
is_address^ := true
elsif parser_node^.kind = ElnaTreeKind.call then
result_instructions := elna_tac_call(parser_node, symbol_table, operand_type, operand_value, operand_length);
is_address^ := false
else
result_instructions := elna_tac_simple_expression(parser_node, symbol_table, operand_type, operand_value, operand_length);
is_address^ := false
end;
return result_instructions
end;
proc elna_tac_field_access_expression(field_access_expression: ^ElnaTreeFieldAccessExpression, symbol_table: Word, operand_type: Word, operand_value: Word, operand_length: Word);
var
field_type: ^ElnaType;
first_instruction: Word;
last_instruction: Word;
@@ -2694,34 +2779,25 @@ var
field_count: Word;
current_field: ^ElnaTypeField;
field_offset: Word;
is_address: Word;
begin
if parser_node^.kind = ElnaTreeKind.dereference_expression then
dereference_expression := parser_node;
first_instruction := elna_tac_designator(dereference_expression^.pointer, symbol_table, is_address, operand_type, operand_value, operand_length);
is_address^ := 1
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
field_access_expression := parser_node;
designator_base := field_access_expression^.aggregate;
aggregate_type := designator_base^.type_decoration;
if aggregate_type = nil then
first_instruction := elna_tac_enumeration_value(field_access_expression, operand_type, operand_value, operand_length);
is_address^ := 0
else
first_instruction := elna_tac_designator(designator_base, symbol_table, is_address, operand_type, operand_value, operand_length);
first_instruction := elna_tac_designator(designator_base, symbol_table, @is_address, operand_type, operand_value, operand_length);
field_count := aggregate_type^.length;
current_field := aggregate_type^.members;
field_offset := 0;
.elna_tac_designator_field;
.elna_tac_field_access_expression_field;
if string_compare(field_access_expression^.field, field_access_expression^.length, current_field^.name, current_field^.length) = 0 then
field_type := current_field^.field_type;
field_count := field_count - 1;
current_field := current_field + #size(ElnaTypeField);
field_offset := field_offset + field_type^.size;
goto elna_tac_designator_field
goto elna_tac_field_access_expression_field
end;
last_instruction := _elna_tac_instruction_create(ElnaTacOperator.add);
_elna_tac_instruction_set_operand(last_instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
@@ -2732,17 +2808,52 @@ begin
operand_value^ := "$unary";
operand_length^ := 6;
is_address^ := 1;
first_instruction := elna_instruction_list_concatenate(first_instruction, last_instruction)
return elna_instruction_list_concatenate(first_instruction, last_instruction)
end;
elsif parser_node^.kind = ElnaTreeKind.call then
first_instruction := elna_tac_call(parser_node, symbol_table, operand_type, operand_value, operand_length);
is_address^ := 0
else
first_instruction := elna_tac_simple_expression(parser_node, symbol_table, operand_type, operand_value, operand_length);
is_address^ := 0
end;
return first_instruction
proc elna_tac_array_access_expression(array_access_expression: ^ElnaTreeArrayAccessExpression, symbol_table: Word, operand_type: Word, operand_value: Word, operand_length: Word);
var
array_instructions: Word;
index_instructions: Word;
offset_instruction: Word;
add_instruction: Word;
is_address: Word;
offset_type: Word;
offset_value: Word;
offset_length: Word;
aggregate_type: ^ElnaTypeArray;
designator_base: ^ElnaTreeExpression;
element_type: ^ElnaType;
begin
designator_base := array_access_expression^.array;
aggregate_type := designator_base^.type_decoration;
element_type := aggregate_type^.base;
index_instructions := elna_tac_binary_expression(array_access_expression^.index, symbol_table, operand_type, operand_value, operand_length);
add_instruction := _elna_tac_instruction_create(ElnaTacOperator.subtract);
_elna_tac_instruction_set_operand(add_instruction, 1, ElnaTacOperand.pseudo, "$lhs", 4);
_elna_tac_instruction_set_operand(add_instruction, 2, operand_type^, operand_value^, operand_length^);
_elna_tac_instruction_set_operand(add_instruction, 3, ElnaTacOperand.immediate, 1, 0);
offset_instruction := _elna_tac_instruction_create(ElnaTacOperator.multiply);
_elna_tac_instruction_set_operand(offset_instruction, 1, ElnaTacOperand.pseudo, "$lhs", 4);
_elna_tac_instruction_set_operand(offset_instruction, 2, ElnaTacOperand.pseudo, "$lhs", 4);
_elna_tac_instruction_set_operand(offset_instruction, 3, ElnaTacOperand.immediate, element_type^.size, 0);
elna_instruction_list_concatenate(add_instruction, offset_instruction);
index_instructions := elna_instruction_list_concatenate(index_instructions, add_instruction);
array_instructions := elna_tac_designator(array_access_expression^.array, symbol_table, @is_address, operand_type, operand_value, operand_length);
add_instruction := _elna_tac_instruction_create(ElnaTacOperator.add);
_elna_tac_instruction_set_operand(add_instruction, 1, operand_type^, operand_value^, operand_length^);
_elna_tac_instruction_set_operand(add_instruction, 2, operand_type^, operand_value^, operand_length^);
_elna_tac_instruction_set_operand(add_instruction, 3, ElnaTacOperand.pseudo, "$lhs", 4);
elna_instruction_list_concatenate(offset_instruction, array_instructions);
return elna_instruction_list_concatenate(index_instructions, add_instruction)
end;
proc elna_parser_assign_statement(assignee: Word);
@@ -4437,12 +4548,28 @@ begin
parser_node^.type_decoration := base_type
end;
proc elna_type_array_access_expression(parser_node: ^ElnaTreeArrayAccessExpression, symbol_table: Word);
var
aggregate_type: ^ElnaTypeArray;
base_expression: ^ElnaTreeExpression;
begin
base_expression := parser_node^.array;
elna_type_designator(base_expression, symbol_table);
elna_type_binary_expression(parser_node^.index, symbol_table);
aggregate_type := base_expression^.type_decoration;
parser_node^.type_decoration := aggregate_type^.base
end;
proc elna_type_designator(parser_node: ^ElnaTreeNode, symbol_table: Word);
begin
if parser_node^.kind = ElnaTreeKind.dereference_expression then
elna_type_dereference_expression(parser_node, symbol_table)
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
elna_type_field_access_expression(parser_node, symbol_table)
elsif parser_node^.kind = ElnaTreeKind.array_access_expression then
elna_type_array_access_expression(parser_node, symbol_table)
elsif parser_node^.kind = ElnaTreeKind.call then
elna_type_call(parser_node, symbol_table)
else