Implement array access expressions
This commit is contained in:
46
Rakefile
46
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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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^);
|
||||
|
||||
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
|
||||
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;
|
||||
return first_instruction
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user