summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-01-14 19:48:28 +0100
committerEugen Wissner <belka@caraus.de>2026-01-14 19:48:28 +0100
commitcfef0550ca814ea3cb5740aab662c6cfd9288139 (patch)
tree4ba9a4883b4734ce30a3f29a4594720afc2158ee
parent30e18517abf7bfabdedcb62400e2fd148a414a92 (diff)
downloadelna-cfef0550ca814ea3cb5740aab662c6cfd9288139.tar.gz
Implement array access expressions
-rw-r--r--Rakefile46
-rw-r--r--boot/stage17/cl.elna10
-rw-r--r--boot/stage18/cl.elna221
3 files changed, 226 insertions, 51 deletions
diff --git a/Rakefile b/Rakefile
index 743fc21..ae7f27f 100644
--- a/Rakefile
+++ b/Rakefile
@@ -38,10 +38,47 @@ 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
@@ -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
diff --git a/boot/stage17/cl.elna b/boot/stage17/cl.elna
index 70c0348..ec0f656 100644
--- a/boot/stage17/cl.elna
+++ b/boot/stage17/cl.elna
@@ -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);
- is_address^ := 1
+ 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;
diff --git a/boot/stage18/cl.elna b/boot/stage18/cl.elna
index 4783700..dc9fdb5 100644
--- a/boot/stage18/cl.elna
+++ b/boot/stage18/cl.elna
@@ -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
- 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^)
+ 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,55 +2779,81 @@ 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;
+ 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;
+ 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
- end;
- last_instruction := _elna_tac_instruction_create(ElnaTacOperator.add);
- _elna_tac_instruction_set_operand(last_instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
- _elna_tac_instruction_set_operand(last_instruction, 2, ElnaTacOperand.immediate, field_offset, 0);
- _elna_tac_instruction_set_operand(last_instruction, 3, operand_type^, operand_value^, operand_length^);
+ 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_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);
+ _elna_tac_instruction_set_operand(last_instruction, 2, ElnaTacOperand.immediate, field_offset, 0);
+ _elna_tac_instruction_set_operand(last_instruction, 3, operand_type^, operand_value^, operand_length^);
- operand_type^ := ElnaTacOperand.pseudo;
- operand_value^ := "$unary";
- operand_length^ := 6;
+ operand_type^ := ElnaTacOperand.pseudo;
+ operand_value^ := "$unary";
+ operand_length^ := 6;
- is_address^ := 1;
- first_instruction := 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
+ return elna_instruction_list_concatenate(first_instruction, last_instruction)
+end;
+
+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