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'
|
desc 'Convert previous stage language into the current stage language'
|
||||||
task :convert do
|
task :convert do
|
||||||
File.open('boot/stage18/cl.elna', 'w') do |current_stage|
|
File.open('boot/stage19/cl.elna', 'w') do |current_stage|
|
||||||
File.readlines('boot/stage17/cl.elna').each do |line|
|
File.readlines('boot/stage18/cl.elna').each do |line|
|
||||||
|
current_stage << "\tf();\n" if line.include? "if _compile() then"
|
||||||
current_stage << line
|
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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -105,7 +142,10 @@ file 'build/build.ninja' => ['build'] do |t|
|
|||||||
build #{valid_stage}/cl: #{link} #{valid_stage}/cl.o
|
build #{valid_stage}/cl: #{link} #{valid_stage}/cl.o
|
||||||
NINJA
|
NINJA
|
||||||
end
|
end
|
||||||
f << "\ndefault build/valid/stage18/cl\n"
|
f << <<~NINJA
|
||||||
|
|
||||||
|
default build/valid/#{STAGES.last}/cl
|
||||||
|
NINJA
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -2707,7 +2707,15 @@ begin
|
|||||||
if parser_node^.kind = ElnaTreeKind.dereference_expression then
|
if parser_node^.kind = ElnaTreeKind.dereference_expression then
|
||||||
dereference_expression := parser_node;
|
dereference_expression := parser_node;
|
||||||
first_instruction := elna_tac_designator(dereference_expression^.pointer, symbol_table, is_address, operand_type, operand_value, operand_length);
|
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
|
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
|
||||||
field_access_expression := parser_node;
|
field_access_expression := parser_node;
|
||||||
expression_type := field_access_expression^.type_decoration;
|
expression_type := field_access_expression^.type_decoration;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ program;
|
|||||||
(* Stage 18 compiler. *)
|
(* Stage 18 compiler. *)
|
||||||
|
|
||||||
(* - Record fields can be aggregates themselves *)
|
(* - Record fields can be aggregates themselves *)
|
||||||
|
(* - Static arrays. *)
|
||||||
|
|
||||||
type
|
type
|
||||||
(**
|
(**
|
||||||
@@ -92,7 +93,8 @@ type
|
|||||||
pointer_type_expression,
|
pointer_type_expression,
|
||||||
array_type_expression,
|
array_type_expression,
|
||||||
null,
|
null,
|
||||||
trait_expression
|
trait_expression,
|
||||||
|
array_access_expression
|
||||||
);
|
);
|
||||||
ElnaTreeNode = record
|
ElnaTreeNode = record
|
||||||
kind: ElnaTreeKind
|
kind: ElnaTreeKind
|
||||||
@@ -196,6 +198,12 @@ type
|
|||||||
field: Word;
|
field: Word;
|
||||||
length: Word
|
length: Word
|
||||||
end;
|
end;
|
||||||
|
ElnaTreeArrayAccessExpression = record
|
||||||
|
kind: ElnaTreeKind;
|
||||||
|
type_decoration: ^ElnaType;
|
||||||
|
array: Word;
|
||||||
|
index: Word
|
||||||
|
end;
|
||||||
ElnaTreeEnumerationTypeExpression = record
|
ElnaTreeEnumerationTypeExpression = record
|
||||||
kind: ElnaTreeKind;
|
kind: ElnaTreeKind;
|
||||||
members: Word;
|
members: Word;
|
||||||
@@ -2114,6 +2122,9 @@ begin
|
|||||||
elsif token_kind = ElnaLexerKind.dot then
|
elsif token_kind = ElnaLexerKind.dot then
|
||||||
simple_expression := elna_parser_field_access_expression(simple_expression);
|
simple_expression := elna_parser_field_access_expression(simple_expression);
|
||||||
goto elna_parser_designator_loop
|
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
|
elsif token_kind = ElnaLexerKind.left_paren then
|
||||||
simple_expression := elna_parser_call(simple_expression);
|
simple_expression := elna_parser_call(simple_expression);
|
||||||
goto elna_parser_designator_loop
|
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);
|
first_instruction := elna_tac_designator(operand, symbol_table, @is_address, operand_type, operand_value, operand_length);
|
||||||
|
|
||||||
if operator = '@' then
|
if operator = '@' then
|
||||||
instruction := _elna_tac_instruction_create(ElnaTacOperator.get_address);
|
if is_address then
|
||||||
_elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
|
instruction := _elna_tac_instruction_create(ElnaTacOperator.copy);
|
||||||
_elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
|
_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
|
elsif operator = '-' then
|
||||||
instruction := _elna_tac_instruction_create(ElnaTacOperator.negate);
|
instruction := _elna_tac_instruction_create(ElnaTacOperator.negate);
|
||||||
_elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
|
_elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.pseudo, "$unary", 6);
|
||||||
@@ -2682,10 +2699,78 @@ begin
|
|||||||
return result
|
return result
|
||||||
end;
|
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);
|
proc elna_tac_designator(parser_node: ^ElnaTreeExpression, symbol_table: Word, is_address: Word, operand_type: Word, operand_value: Word, operand_length: Word);
|
||||||
var
|
var
|
||||||
field_access_expression: ^ElnaTreeFieldAccessExpression;
|
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;
|
field_type: ^ElnaType;
|
||||||
first_instruction: Word;
|
first_instruction: Word;
|
||||||
last_instruction: Word;
|
last_instruction: Word;
|
||||||
@@ -2694,55 +2779,81 @@ var
|
|||||||
field_count: Word;
|
field_count: Word;
|
||||||
current_field: ^ElnaTypeField;
|
current_field: ^ElnaTypeField;
|
||||||
field_offset: Word;
|
field_offset: Word;
|
||||||
|
is_address: Word;
|
||||||
begin
|
begin
|
||||||
if parser_node^.kind = ElnaTreeKind.dereference_expression then
|
designator_base := field_access_expression^.aggregate;
|
||||||
dereference_expression := parser_node;
|
aggregate_type := designator_base^.type_decoration;
|
||||||
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_designator(designator_base, symbol_table, @is_address, operand_type, operand_value, operand_length);
|
||||||
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);
|
|
||||||
|
|
||||||
field_count := aggregate_type^.length;
|
field_count := aggregate_type^.length;
|
||||||
current_field := aggregate_type^.members;
|
current_field := aggregate_type^.members;
|
||||||
field_offset := 0;
|
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
|
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_type := current_field^.field_type;
|
||||||
field_count := field_count - 1;
|
field_count := field_count - 1;
|
||||||
current_field := current_field + #size(ElnaTypeField);
|
current_field := current_field + #size(ElnaTypeField);
|
||||||
field_offset := field_offset + field_type^.size;
|
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);
|
|
||||||
_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
|
|
||||||
end;
|
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;
|
end;
|
||||||
|
|
||||||
proc elna_parser_assign_statement(assignee: Word);
|
proc elna_parser_assign_statement(assignee: Word);
|
||||||
@@ -4437,12 +4548,28 @@ begin
|
|||||||
parser_node^.type_decoration := base_type
|
parser_node^.type_decoration := base_type
|
||||||
end;
|
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);
|
proc elna_type_designator(parser_node: ^ElnaTreeNode, symbol_table: Word);
|
||||||
begin
|
begin
|
||||||
if parser_node^.kind = ElnaTreeKind.dereference_expression then
|
if parser_node^.kind = ElnaTreeKind.dereference_expression then
|
||||||
elna_type_dereference_expression(parser_node, symbol_table)
|
elna_type_dereference_expression(parser_node, symbol_table)
|
||||||
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
|
elsif parser_node^.kind = ElnaTreeKind.field_access_expression then
|
||||||
elna_type_field_access_expression(parser_node, symbol_table)
|
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
|
elsif parser_node^.kind = ElnaTreeKind.call then
|
||||||
elna_type_call(parser_node, symbol_table)
|
elna_type_call(parser_node, symbol_table)
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user