summaryrefslogtreecommitdiff
path: root/boot/stage18/cl.elna
diff options
context:
space:
mode:
Diffstat (limited to 'boot/stage18/cl.elna')
-rw-r--r--boot/stage18/cl.elna221
1 files changed, 174 insertions, 47 deletions
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