Make TAC generation stage
This commit is contained in:
@@ -177,7 +177,10 @@ type
|
||||
jump,
|
||||
beqz,
|
||||
ret,
|
||||
label
|
||||
label,
|
||||
procedure,
|
||||
variable,
|
||||
_module
|
||||
);
|
||||
ElnaGeneratorOperand = (register, immediate, symbol, offset);
|
||||
ElnaGeneratorRegister = (
|
||||
@@ -587,7 +590,14 @@ end;
|
||||
|
||||
proc _elna_generator_instruction_set_next(this: Word, value: Word);
|
||||
begin
|
||||
.elna_generator_instruction_set_next_loop;
|
||||
this := this + 4;
|
||||
if value <> 0 then
|
||||
if this^ <> 0 then
|
||||
this := this^;
|
||||
goto elna_generator_instruction_set_next_loop
|
||||
end
|
||||
end;
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
@@ -651,6 +661,67 @@ begin
|
||||
return result
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_size();
|
||||
return 20
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_get_kind(this: Word);
|
||||
return this^
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_set_kind(this: Word, value: Word);
|
||||
begin
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_get_next(this: Word);
|
||||
begin
|
||||
this := this + 4;
|
||||
return this^
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_set_next(this: Word, value: Word);
|
||||
begin
|
||||
this := this + 4;
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_get_name(this: Word);
|
||||
begin
|
||||
this := this + 8;
|
||||
return this^
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_set_name(this: Word, value: Word);
|
||||
begin
|
||||
this := this + 8;
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_get_length(this: Word);
|
||||
begin
|
||||
this := this + 12;
|
||||
return this^
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_set_length(this: Word, value: Word);
|
||||
begin
|
||||
this := this + 12;
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_get_body(this: Word);
|
||||
begin
|
||||
this := this + 16;
|
||||
return this^
|
||||
end;
|
||||
|
||||
proc _elna_generator_procedure_set_body(this: Word, value: Word);
|
||||
begin
|
||||
this := this + 16;
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
proc _elna_generator_load_immediate(target_register: Word, source_immediate: Word, immediate_length: Word);
|
||||
var
|
||||
result: Word;
|
||||
@@ -1110,6 +1181,102 @@ begin
|
||||
end
|
||||
end;
|
||||
|
||||
proc _elna_writer_procedure(procedure: Word);
|
||||
var
|
||||
name_pointer: Word;
|
||||
name_length: Word;
|
||||
body_statements: Word;
|
||||
begin
|
||||
.elna_writer_procedure_loop;
|
||||
name_pointer := _elna_generator_procedure_get_name(procedure);
|
||||
name_length := _elna_generator_procedure_get_length(procedure);
|
||||
body_statements := _elna_generator_procedure_get_body(procedure);
|
||||
|
||||
(* Write .type _procedure_name, @function. *)
|
||||
_write_z(".type \0");
|
||||
|
||||
_write_s(name_pointer, name_length);
|
||||
_write_z(", @function\n\0");
|
||||
|
||||
(* Write procedure label, _procedure_name: *)
|
||||
_write_s(name_pointer, name_length);
|
||||
_write_z(":\n\0");
|
||||
|
||||
_elna_writer_instructions(body_statements);
|
||||
procedure := _elna_generator_procedure_get_next(procedure);
|
||||
if procedure <> 0 then
|
||||
goto elna_writer_procedure_loop
|
||||
end
|
||||
end;
|
||||
|
||||
proc _elna_writer_variable(variable: Word);
|
||||
var
|
||||
name: Word;
|
||||
name_length: Word;
|
||||
size: Word;
|
||||
begin
|
||||
.elna_writer_variable_loop;
|
||||
if variable <> 0 then
|
||||
name := _elna_generator_procedure_get_name(variable);
|
||||
name_length := _elna_generator_procedure_get_length(variable);
|
||||
size := _elna_generator_procedure_get_body(variable);
|
||||
|
||||
_write_z(".type \0");
|
||||
_write_s(name, name_length);
|
||||
_write_z(", @object\n\0");
|
||||
|
||||
_write_s(name, name_length);
|
||||
_write_c(':');
|
||||
|
||||
_write_z(" .zero \0");
|
||||
_write_i(size);
|
||||
|
||||
_write_c('\n');
|
||||
variable := _elna_generator_procedure_get_next(variable);
|
||||
|
||||
goto elna_writer_variable_loop
|
||||
end
|
||||
end;
|
||||
|
||||
proc _elna_writer_module(pair: Word);
|
||||
var
|
||||
compiler_strings_copy: Word;
|
||||
compiler_strings_end: Word;
|
||||
current_byte: Word;
|
||||
current_part: Word;
|
||||
begin
|
||||
_write_z(".globl _start\n\n\0");
|
||||
_write_z(".section .data\n\0");
|
||||
|
||||
current_part := _elna_generator_procedure_get_name(pair);
|
||||
_elna_writer_variable(current_part);
|
||||
|
||||
_write_z(".section .text\n\n\0");
|
||||
_write_z(".type _syscall, @function\n_syscall:\n\tmv a7, a6\n\tecall\n\tret\n\n\0");
|
||||
_write_z(".type _load_byte, @function\n_load_byte:\n\tlb a0, (a0)\nret\n\n\0");
|
||||
_write_z(".type _store_byte, @function\n_store_byte:\n\tsb a0, (a1)\nret\n\n\0");
|
||||
|
||||
current_part := _elna_generator_procedure_get_body(pair);
|
||||
_elna_writer_procedure(current_part);
|
||||
|
||||
_write_z(".section .rodata\n.type strings, @object\nstrings: .ascii \0");
|
||||
_write_c('"');
|
||||
|
||||
compiler_strings_copy := @compiler_strings;
|
||||
compiler_strings_end := compiler_strings_position;
|
||||
|
||||
.compile_module_declaration_loop;
|
||||
if compiler_strings_copy < compiler_strings_end then
|
||||
current_byte := _load_byte(compiler_strings_copy);
|
||||
compiler_strings_copy := compiler_strings_copy + 1;
|
||||
_write_c(current_byte);
|
||||
|
||||
goto compile_module_declaration_loop
|
||||
end;
|
||||
_write_c('"');
|
||||
_write_c('\n');
|
||||
end;
|
||||
|
||||
proc _node_set_kind(this: Word, kind: Word);
|
||||
begin
|
||||
this^ := kind
|
||||
@@ -1477,7 +1644,7 @@ begin
|
||||
instruction := _compile_variable_expression(parser_node, symbol_table);
|
||||
is_address^ := 1
|
||||
end;
|
||||
_elna_writer_instructions(instruction)
|
||||
return instruction
|
||||
end;
|
||||
|
||||
proc _unary_expression_size();
|
||||
@@ -1552,6 +1719,7 @@ var
|
||||
operator: Word;
|
||||
operand: Word;
|
||||
is_address: Word;
|
||||
first_instruction: Word;
|
||||
instruction: Word;
|
||||
begin
|
||||
operator := 0;
|
||||
@@ -1567,21 +1735,22 @@ begin
|
||||
end;
|
||||
|
||||
if operator = '@' then
|
||||
_compile_designator(operand, symbol_table, @is_address)
|
||||
first_instruction := _compile_designator(operand, symbol_table, @is_address)
|
||||
else
|
||||
_compile_designator(operand, symbol_table, @is_address);
|
||||
first_instruction := _compile_designator(operand, symbol_table, @is_address);
|
||||
if is_address then
|
||||
instruction := _elna_generator_load_word(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, 0);
|
||||
_elna_writer_instruction(instruction)
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction)
|
||||
end
|
||||
end;
|
||||
if operator = '-' then
|
||||
instruction := _elna_generator_neg(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0);
|
||||
_elna_writer_instruction(instruction)
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction)
|
||||
elsif operator = '~' then
|
||||
instruction := _elna_generator_not(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0);
|
||||
_elna_writer_instruction(instruction)
|
||||
end
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction)
|
||||
end;
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
proc _binary_expression_size();
|
||||
@@ -1700,65 +1869,94 @@ var
|
||||
operand_node: Word;
|
||||
first_instruction: Word;
|
||||
instruction: Word;
|
||||
current_instruction: Word;
|
||||
begin
|
||||
expression_kind := _node_get_kind(parser_node);
|
||||
|
||||
if expression_kind <> NodeKind.binary_expression then
|
||||
_compile_unary_expression(parser_node, symbol_table)
|
||||
first_instruction := _compile_unary_expression(parser_node, symbol_table)
|
||||
else
|
||||
token_kind := _binary_expression_get_operator(parser_node);
|
||||
|
||||
operand_node := _binary_expression_get_lhs(parser_node);
|
||||
_compile_unary_expression(operand_node, symbol_table);
|
||||
first_instruction := _compile_unary_expression(operand_node, symbol_table);
|
||||
|
||||
(* Save the value of the left expression on the stack. *)
|
||||
instruction := _elna_generator_store_word(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.sp, 64);
|
||||
_elna_writer_instruction(instruction);
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
operand_node := _binary_expression_get_rhs(parser_node);
|
||||
_compile_unary_expression(operand_node, symbol_table);
|
||||
instruction := _compile_unary_expression(operand_node, symbol_table);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
(* Load the left expression from the stack; *)
|
||||
instruction := _elna_generator_load_word(ElnaGeneratorRegister.t1, ElnaGeneratorRegister.sp, 64);
|
||||
_elna_writer_instruction(instruction);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
if token_kind = LexerTokenKind.plus then
|
||||
first_instruction := _elna_generator_add(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1)
|
||||
instruction := _elna_generator_add(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.minus then
|
||||
first_instruction := _elna_generator_sub(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0)
|
||||
instruction := _elna_generator_sub(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.multiplication then
|
||||
first_instruction := _elna_generator_mul(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1)
|
||||
instruction := _elna_generator_mul(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.and then
|
||||
first_instruction := _elna_generator_and(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1)
|
||||
instruction := _elna_generator_and(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind._or then
|
||||
first_instruction := _elna_generator_or(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1)
|
||||
instruction := _elna_generator_or(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind._xor then
|
||||
first_instruction := _elna_generator_xor(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1)
|
||||
instruction := _elna_generator_xor(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.equals then
|
||||
first_instruction := _elna_generator_xor(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
instruction := _elna_generator_xor(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
instruction := _elna_generator_seqz(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0);
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction)
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.remainder then
|
||||
first_instruction := _elna_generator_rem(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0)
|
||||
instruction := _elna_generator_rem(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.division then
|
||||
first_instruction := _elna_generator_div(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0)
|
||||
instruction := _elna_generator_div(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.less_than then
|
||||
first_instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0)
|
||||
instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.greater_than then
|
||||
first_instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1)
|
||||
instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.less_equal then
|
||||
first_instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
instruction := _elna_generator_xor_immediate(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, 1);
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction)
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.not_equal then
|
||||
first_instruction := _elna_generator_xor(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
instruction := _elna_generator_xor(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
instruction := _elna_generator_snez(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0);
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction)
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
elsif token_kind = LexerTokenKind.greater_equal then
|
||||
first_instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0);
|
||||
instruction := _elna_generator_slt(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, ElnaGeneratorRegister.t0);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
instruction := _elna_generator_xor_immediate(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, 1);
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction)
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
end;
|
||||
_elna_writer_instructions(first_instruction)
|
||||
end
|
||||
end;
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
(* 4 bytes node kind + 4 byte pointer to variable expression + 4 * 7 for arguments. *)
|
||||
@@ -1860,19 +2058,25 @@ begin
|
||||
if parsed_expression = 0 then
|
||||
goto compile_call_finalize
|
||||
else
|
||||
_compile_binary_expression(parsed_expression, symbol_table);
|
||||
instruction := _compile_binary_expression(parsed_expression, symbol_table);
|
||||
if first_instruction = 0 then
|
||||
first_instruction := instruction
|
||||
else
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
end;
|
||||
current_instruction := instruction;
|
||||
|
||||
(* Save the argument on the stack. *)
|
||||
stack_offset := argument_count * 4;
|
||||
|
||||
instruction := _elna_generator_store_word(ElnaGeneratorRegister.t0,
|
||||
ElnaGeneratorRegister.sp, 116 - stack_offset);
|
||||
_elna_writer_instruction(instruction);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
argument_count := argument_count + 1;
|
||||
goto compile_call_loop
|
||||
end;
|
||||
|
||||
.compile_call_finalize;
|
||||
|
||||
(* Load the argument from the stack. *)
|
||||
@@ -1884,11 +2088,7 @@ begin
|
||||
(* Calculate the stack offset: 116 - (4 * argument_counter) *)
|
||||
instruction := _elna_generator_load_word(ElnaGeneratorRegister.a0 + argument_count,
|
||||
ElnaGeneratorRegister.sp, 116 - stack_offset);
|
||||
if first_instruction = 0 then
|
||||
first_instruction := instruction
|
||||
else
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
end;
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
goto compile_call_finalize
|
||||
@@ -1899,7 +2099,7 @@ begin
|
||||
else
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
end;
|
||||
_elna_writer_instructions(first_instruction)
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
(**
|
||||
@@ -2147,22 +2347,22 @@ begin
|
||||
name_length := _field_access_expression_get_length(field_access_expression);
|
||||
counter := 1;
|
||||
|
||||
instruction := 0;
|
||||
.compile_enumeration_value_members;
|
||||
if members_length > 0 then
|
||||
member_name := members^;
|
||||
member_length := members + 4;
|
||||
member_length := member_length^;
|
||||
|
||||
if _lexer_compare_keyword(value_name, name_length, member_name, member_length) then
|
||||
else
|
||||
if _lexer_compare_keyword(value_name, name_length, member_name, member_length) = 0 then
|
||||
members_length := members_length - 1;
|
||||
members := members + 8;
|
||||
counter := counter + 1;
|
||||
goto compile_enumeration_value_members
|
||||
end;
|
||||
instruction := _elna_generator_load_immediate(ElnaGeneratorRegister.t0, counter, 0);
|
||||
_elna_writer_instructions(instruction)
|
||||
end
|
||||
instruction := _elna_generator_load_immediate(ElnaGeneratorRegister.t0, counter, 0)
|
||||
end;
|
||||
return instruction
|
||||
end;
|
||||
|
||||
proc _parse_field_access_expression(aggregate: Word);
|
||||
@@ -2199,103 +2399,109 @@ var
|
||||
token_kind: Word;
|
||||
parser_node: Word;
|
||||
node_kind: Word;
|
||||
first_instruction: Word;
|
||||
instruction: Word;
|
||||
begin
|
||||
node_kind := _node_get_kind(parser_node);
|
||||
|
||||
if node_kind = NodeKind.dereference_expression then
|
||||
parser_node := _dereference_expression_get_pointer(parser_node);
|
||||
_compile_simple_expression(parser_node, symbol_table, is_address);
|
||||
first_instruction := _compile_simple_expression(parser_node, symbol_table, is_address);
|
||||
instruction := _elna_generator_load_word(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t0, 0);
|
||||
_elna_writer_instructions(instruction)
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction);
|
||||
elsif node_kind = NodeKind.field_access_expression then
|
||||
_compile_enumeration_value(parser_node);
|
||||
first_instruction := _compile_enumeration_value(parser_node);
|
||||
is_address^ := 0
|
||||
elsif node_kind = NodeKind.call then
|
||||
_compile_call(parser_node, symbol_table);
|
||||
first_instruction := _compile_call(parser_node, symbol_table);
|
||||
instruction := _elna_generator_move(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.a0);
|
||||
_elna_writer_instructions(instruction);
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction);
|
||||
is_address^ := 0
|
||||
else
|
||||
_compile_simple_expression(parser_node, symbol_table, is_address)
|
||||
first_instruction := _compile_simple_expression(parser_node, symbol_table, is_address)
|
||||
end;
|
||||
return is_address
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
proc _assignment_statement_size();
|
||||
proc _assign_statement_size();
|
||||
return 16
|
||||
end;
|
||||
|
||||
proc _assignment_statement_get_assignee(this: Word);
|
||||
proc _assign_statement_get_assignee(this: Word);
|
||||
begin
|
||||
this := this + 8;
|
||||
return this^
|
||||
end;
|
||||
|
||||
proc _assignment_statement_set_assignee(this: Word, value: Word);
|
||||
proc _assign_statement_set_assignee(this: Word, value: Word);
|
||||
begin
|
||||
this := this + 8;
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
proc _assignment_statement_get_assignment(this: Word);
|
||||
proc _assign_statement_get_assignment(this: Word);
|
||||
begin
|
||||
this := this + 12;
|
||||
return this^
|
||||
end;
|
||||
|
||||
proc _assignment_statement_set_assignment(this: Word, value: Word);
|
||||
proc _assign_statement_set_assignment(this: Word, value: Word);
|
||||
begin
|
||||
this := this + 12;
|
||||
this^ := value
|
||||
end;
|
||||
|
||||
proc _parse_assignment_statement(assignee: Word);
|
||||
proc _parse_assign_statement(assignee: Word);
|
||||
var
|
||||
statement_size: Word;
|
||||
result: Word;
|
||||
token_kind: Word;
|
||||
assignment_node: Word;
|
||||
begin
|
||||
statement_size := _assignment_statement_size();
|
||||
statement_size := _assign_statement_size();
|
||||
result := _allocate(statement_size);
|
||||
|
||||
_node_set_kind(result, NodeKind.assignment_statement);
|
||||
_node_set_kind(result, NodeKind.assign_statement);
|
||||
_statement_set_next(result, 0);
|
||||
_assignment_statement_set_assignee(result, assignee);
|
||||
_assign_statement_set_assignee(result, assignee);
|
||||
|
||||
(* Skip the assignment sign (:=) with surrounding whitespaces. *)
|
||||
_lexer_read_token(@token_kind);
|
||||
_lexer_skip_token();
|
||||
|
||||
assignment_node := _parse_binary_expression();
|
||||
_assignment_statement_set_assignment(result, assignment_node);
|
||||
_assign_statement_set_assignment(result, assignment_node);
|
||||
|
||||
return result
|
||||
end;
|
||||
|
||||
proc _compile_assignment_statement(parser_tree: Word, symbol_table: Word);
|
||||
proc _compile_assign_statement(parser_tree: Word, symbol_table: Word);
|
||||
var
|
||||
current_expression: Word;
|
||||
is_address: Word;
|
||||
first_instruction: Word;
|
||||
instruction: Word;
|
||||
current_instruction: Word;
|
||||
begin
|
||||
current_expression := _assignment_statement_get_assignee(parser_tree);
|
||||
_compile_designator(current_expression, symbol_table, @is_address);
|
||||
current_expression := _assign_statement_get_assignee(parser_tree);
|
||||
first_instruction := _compile_designator(current_expression, symbol_table, @is_address);
|
||||
|
||||
(* Save the assignee address on the stack. *)
|
||||
instruction := _elna_generator_store_word(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.sp, 60);
|
||||
_elna_writer_instructions(instruction);
|
||||
current_instruction := _elna_generator_store_word(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.sp, 60);
|
||||
_elna_generator_instruction_set_next(first_instruction, current_instruction);
|
||||
|
||||
(* Compile the assignment. *)
|
||||
current_expression := _assignment_statement_get_assignment(parser_tree);
|
||||
_compile_binary_expression(current_expression, symbol_table);
|
||||
current_expression := _assign_statement_get_assignment(parser_tree);
|
||||
instruction := _compile_binary_expression(current_expression, symbol_table);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
|
||||
current_instruction := _elna_generator_load_word(ElnaGeneratorRegister.t1, ElnaGeneratorRegister.sp, 60);
|
||||
_elna_generator_instruction_set_next(instruction, current_instruction);
|
||||
|
||||
first_instruction := _elna_generator_load_word(ElnaGeneratorRegister.t1, ElnaGeneratorRegister.sp, 60);
|
||||
instruction := _elna_generator_store_word(ElnaGeneratorRegister.t0, ElnaGeneratorRegister.t1, 0);
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction);
|
||||
_elna_writer_instructions(first_instruction)
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
proc _return_statement_size();
|
||||
@@ -2341,12 +2547,14 @@ end;
|
||||
proc _compile_return_statement(parser_node: Word, symbol_table: Word);
|
||||
var
|
||||
return_expression: Word;
|
||||
first_instruction: Word;
|
||||
instruction: Word;
|
||||
begin
|
||||
return_expression := _return_statement_get_returned(parser_node);
|
||||
_compile_binary_expression(return_expression, symbol_table);
|
||||
first_instruction := _compile_binary_expression(return_expression, symbol_table);
|
||||
instruction := _elna_generator_move(ElnaGeneratorRegister.a0, ElnaGeneratorRegister.t0);
|
||||
_elna_writer_instructions(instruction)
|
||||
_elna_generator_instruction_set_next(first_instruction, instruction);
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
(**
|
||||
@@ -2403,26 +2611,34 @@ var
|
||||
condition_label: Word;
|
||||
current_node: Word;
|
||||
instruction: Word;
|
||||
current_instruction: Word;
|
||||
first_instruction: Word;
|
||||
begin
|
||||
(* Compile condition. *)
|
||||
current_node := _conditional_statements_get_condition(parser_node);
|
||||
_compile_binary_expression(current_node, symbol_table);
|
||||
first_instruction := _compile_binary_expression(current_node, symbol_table);
|
||||
|
||||
(* condition_label is the label in front of the next elsif condition or end. *)
|
||||
condition_label := label_counter;
|
||||
label_counter := label_counter + 1;
|
||||
|
||||
instruction := _elna_generator_beqz(ElnaGeneratorRegister.t0, condition_label, 0);
|
||||
_elna_writer_instructions(instruction);
|
||||
current_instruction := _elna_generator_beqz(ElnaGeneratorRegister.t0, condition_label, 0);
|
||||
_elna_generator_instruction_set_next(first_instruction, current_instruction);
|
||||
|
||||
current_node := _conditional_statements_get_statements(parser_node);
|
||||
_compile_statements(current_node, symbol_table);
|
||||
instruction := _compile_statements(current_node, symbol_table);
|
||||
if instruction <> 0 then
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction
|
||||
end;
|
||||
|
||||
instruction := _elna_generator_jump(after_end_label, 0);
|
||||
_elna_writer_instructions(instruction);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
|
||||
instruction := _elna_generator_label(condition_label, 0);
|
||||
_elna_writer_instructions(instruction)
|
||||
current_instruction := _elna_generator_label(condition_label, 0);
|
||||
_elna_generator_instruction_set_next(instruction, current_instruction);
|
||||
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
(**
|
||||
@@ -2554,7 +2770,7 @@ begin
|
||||
result := _parse_designator();
|
||||
|
||||
if _node_get_kind(result) <> NodeKind.call then
|
||||
result := _parse_assignment_statement(result)
|
||||
result := _parse_assign_statement(result)
|
||||
end
|
||||
end;
|
||||
return result
|
||||
@@ -2598,15 +2814,29 @@ end;
|
||||
proc _compile_statements(parser_node: Word, symbol_table: Word);
|
||||
var
|
||||
current_statement: Word;
|
||||
instruction: Word;
|
||||
first_instruction: Word;
|
||||
current_instruction: Word;
|
||||
begin
|
||||
current_statement := parser_node;
|
||||
first_instruction := 0;
|
||||
|
||||
.compile_statements_loop;
|
||||
if current_statement <> 0 then
|
||||
_compile_statement(current_statement, symbol_table);
|
||||
instruction := _compile_statement(current_statement, symbol_table);
|
||||
current_statement := _statement_get_next(current_statement);
|
||||
if instruction = 0 then
|
||||
goto compile_statements_loop
|
||||
end
|
||||
end;
|
||||
if first_instruction = 0 then
|
||||
first_instruction := instruction
|
||||
else
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
end;
|
||||
current_instruction := instruction;
|
||||
goto compile_statements_loop
|
||||
end;
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
proc _compile_if_statement(parser_node: Word, symbol_table: Word);
|
||||
@@ -2614,27 +2844,38 @@ var
|
||||
current_node: Word;
|
||||
after_end_label: Word;
|
||||
condition_label: Word;
|
||||
first_instruction: Word;
|
||||
instruction: Word;
|
||||
current_instruction: Word;
|
||||
begin
|
||||
after_end_label := label_counter;
|
||||
label_counter := label_counter + 1;
|
||||
|
||||
current_node := _if_statement_get_conditionals(parser_node);
|
||||
_compile_conditional_statements(current_node, after_end_label, symbol_table);
|
||||
first_instruction := _compile_conditional_statements(current_node, after_end_label, symbol_table);
|
||||
current_instruction := first_instruction;
|
||||
|
||||
.compile_if_statement_loop;
|
||||
current_node := _conditional_statements_get_next(current_node);
|
||||
if current_node <> 0 then
|
||||
_compile_conditional_statements(current_node, after_end_label, symbol_table);
|
||||
instruction := _compile_conditional_statements(current_node, after_end_label, symbol_table);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
goto compile_if_statement_loop
|
||||
end;
|
||||
current_node := _if_statement_get_else(parser_node);
|
||||
|
||||
if current_node <> 0 then
|
||||
_compile_statements(current_node, symbol_table)
|
||||
instruction := _compile_statements(current_node, symbol_table);
|
||||
if instruction <> 0 then
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction
|
||||
end
|
||||
end;
|
||||
instruction := _elna_generator_label(after_end_label, 0);
|
||||
_elna_writer_instructions(instruction)
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
|
||||
return first_instruction
|
||||
end;
|
||||
|
||||
proc _compile_statement(parser_node: Word, symbol_table: Word);
|
||||
@@ -2645,20 +2886,21 @@ begin
|
||||
statement_kind := _node_get_kind(parser_node);
|
||||
|
||||
if statement_kind = NodeKind.goto_statement then
|
||||
instruction := _compile_goto_statement(parser_node);
|
||||
_elna_writer_instructions(instruction)
|
||||
instruction := _compile_goto_statement(parser_node)
|
||||
elsif statement_kind = NodeKind.if_statement then
|
||||
_compile_if_statement(parser_node, symbol_table)
|
||||
instruction := _compile_if_statement(parser_node, symbol_table)
|
||||
elsif statement_kind = NodeKind.return_statement then
|
||||
_compile_return_statement(parser_node, symbol_table)
|
||||
instruction := _compile_return_statement(parser_node, symbol_table)
|
||||
elsif statement_kind = NodeKind.label_declaration then
|
||||
instruction := _compile_label_declaration(parser_node);
|
||||
_elna_writer_instructions(instruction)
|
||||
instruction := _compile_label_declaration(parser_node)
|
||||
elsif statement_kind = NodeKind.call then
|
||||
_compile_call(parser_node, symbol_table)
|
||||
elsif statement_kind = NodeKind.assignment_statement then
|
||||
_compile_assignment_statement(parser_node, symbol_table)
|
||||
end
|
||||
instruction := _compile_call(parser_node, symbol_table)
|
||||
elsif statement_kind = NodeKind.assign_statement then
|
||||
instruction := _compile_assign_statement(parser_node, symbol_table)
|
||||
else
|
||||
instruction := 0
|
||||
end;
|
||||
return instruction
|
||||
end;
|
||||
|
||||
(**
|
||||
@@ -3269,23 +3511,24 @@ var
|
||||
instruction: Word;
|
||||
first_instruction: Word;
|
||||
current_instruction: Word;
|
||||
result: Word;
|
||||
result_size: Word;
|
||||
begin
|
||||
result_size := _elna_generator_procedure_size();
|
||||
result := _allocate(result_size);
|
||||
|
||||
_elna_generator_procedure_set_kind(result, ElnaGeneratorKind.procedure);
|
||||
_elna_generator_procedure_set_next(result, 0);
|
||||
|
||||
name_pointer := _declaration_get_name(parser_node);
|
||||
name_length := _declaration_get_length(parser_node);
|
||||
|
||||
_elna_generator_procedure_set_name(result, name_pointer);
|
||||
_elna_generator_procedure_set_length(result, name_length);
|
||||
|
||||
symbol_info := _symbol_table_lookup(@symbol_table_global, name_pointer, name_length);
|
||||
new_symbol_table := _procedure_info_get_symbol_table(symbol_info);
|
||||
|
||||
(* Write .type _procedure_name, @function. *)
|
||||
_write_z(".type \0");
|
||||
|
||||
_write_s(name_pointer, name_length);
|
||||
_write_z(", @function\n\0");
|
||||
|
||||
(* Write procedure label, _procedure_name: *)
|
||||
_write_s(name_pointer, name_length);
|
||||
_write_z(":\n\0");
|
||||
|
||||
(* Write the prologue. *)
|
||||
first_instruction := _elna_generator_add_immediate(ElnaGeneratorRegister.sp, ElnaGeneratorRegister.sp, -128);
|
||||
current_instruction := _elna_generator_store_word(ElnaGeneratorRegister.ra, ElnaGeneratorRegister.sp, 124);
|
||||
@@ -3307,11 +3550,7 @@ begin
|
||||
|
||||
instruction := _elna_generator_store_word(ElnaGeneratorRegister.a0 + parameter_counter,
|
||||
ElnaGeneratorRegister.sp, symbol_info);
|
||||
if first_instruction = 0 then
|
||||
first_instruction := instruction
|
||||
else
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction)
|
||||
end;
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction;
|
||||
|
||||
(* _read_procedure_parameter(current_parameter, parameter_counter, new_symbol_table); *)
|
||||
@@ -3320,19 +3559,28 @@ begin
|
||||
current_parameter := _declaration_get_next(current_parameter);
|
||||
goto compile_procedure_declaration_parameters
|
||||
end;
|
||||
_elna_writer_instructions(first_instruction);
|
||||
current_parameter := _procedure_declaration_get_body(parser_node);
|
||||
_compile_statements(current_parameter, new_symbol_table);
|
||||
|
||||
instruction := _compile_statements(current_parameter, new_symbol_table);
|
||||
if instruction <> 0 then
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := instruction
|
||||
end;
|
||||
|
||||
(* Write the epilogue. *)
|
||||
first_instruction := _elna_generator_load_word(ElnaGeneratorRegister.ra, ElnaGeneratorRegister.sp, 124);
|
||||
instruction := _elna_generator_load_word(ElnaGeneratorRegister.ra, ElnaGeneratorRegister.sp, 124);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
|
||||
current_instruction := _elna_generator_load_word(ElnaGeneratorRegister.s0, ElnaGeneratorRegister.sp, 120);
|
||||
_elna_generator_instruction_set_next(first_instruction, current_instruction);
|
||||
_elna_generator_instruction_set_next(instruction, current_instruction);
|
||||
instruction := _elna_generator_add_immediate(ElnaGeneratorRegister.sp, ElnaGeneratorRegister.sp, 128);
|
||||
_elna_generator_instruction_set_next(current_instruction, instruction);
|
||||
current_instruction := _elna_generator_instruction_create(ElnaGeneratorKind.ret);
|
||||
_elna_generator_instruction_set_next(instruction, current_instruction);
|
||||
_elna_writer_instructions(first_instruction)
|
||||
|
||||
_elna_generator_procedure_set_body(result, first_instruction);
|
||||
|
||||
return result
|
||||
end;
|
||||
|
||||
proc _parse_procedures();
|
||||
@@ -3369,16 +3617,28 @@ end;
|
||||
proc _compile_procedures(parser_node: Word);
|
||||
var
|
||||
result: Word;
|
||||
current_procedure: Word;
|
||||
first_procedure: Word;
|
||||
begin
|
||||
first_procedure := 0;
|
||||
|
||||
.compile_procedures_loop;
|
||||
if parser_node = 0 then
|
||||
goto compile_procedures_end
|
||||
end;
|
||||
_compile_procedure_declaration(parser_node);
|
||||
result := _compile_procedure_declaration(parser_node);
|
||||
if first_procedure = 0 then
|
||||
first_procedure := result
|
||||
else
|
||||
_elna_generator_procedure_set_next(current_procedure, result)
|
||||
end;
|
||||
current_procedure := result;
|
||||
|
||||
parser_node := _declaration_get_next(parser_node);
|
||||
goto compile_procedures_loop;
|
||||
|
||||
.compile_procedures_end
|
||||
.compile_procedures_end;
|
||||
return first_procedure
|
||||
end;
|
||||
|
||||
(**
|
||||
@@ -3551,31 +3811,33 @@ proc _compile_variable_declaration(parser_tree: Word);
|
||||
var
|
||||
name: Word;
|
||||
name_length: Word;
|
||||
token_kind: Word;
|
||||
variable_type: Word;
|
||||
result: Word;
|
||||
result_size: Word;
|
||||
begin
|
||||
result_size := _elna_generator_procedure_size();
|
||||
result := _allocate(result_size);
|
||||
|
||||
_elna_generator_procedure_set_kind(result, ElnaGeneratorKind.variable);
|
||||
_elna_generator_procedure_set_next(result, 0);
|
||||
|
||||
name := _declaration_get_name(parser_tree);
|
||||
name_length := _declaration_get_length(parser_tree);
|
||||
variable_type := _variable_declaration_get_type(parser_tree);
|
||||
|
||||
_write_z(".type \0");
|
||||
_write_s(name, name_length);
|
||||
_write_z(", @object\n\0");
|
||||
_elna_generator_procedure_set_name(result, name);
|
||||
_elna_generator_procedure_set_length(result, name_length);
|
||||
|
||||
_write_s(name, name_length);
|
||||
_write_c(':');
|
||||
|
||||
_lexer_read_token(@token_kind);
|
||||
name := _named_type_expression_get_name(variable_type);
|
||||
name_length := _named_type_expression_get_length(variable_type);
|
||||
|
||||
if _lexer_compare_keyword("Array", 5, name, name_length) then
|
||||
(* Else we assume this is a zeroed 4096 bytes big array. *)
|
||||
_write_z(" .zero 4096\0")
|
||||
_elna_generator_procedure_set_body(result, 4096)
|
||||
else
|
||||
_write_z(" .word 0\n\0")
|
||||
_elna_generator_procedure_set_body(result, 4)
|
||||
end;
|
||||
_write_c('\n')
|
||||
return result
|
||||
end;
|
||||
|
||||
proc _parse_var_part();
|
||||
@@ -3619,21 +3881,32 @@ begin
|
||||
end;
|
||||
|
||||
proc _compile_var_part(parser_node: Word);
|
||||
var
|
||||
node: Word;
|
||||
current_variable: Word;
|
||||
first_variable: Word;
|
||||
begin
|
||||
first_variable := 0;
|
||||
if parser_node = 0 then
|
||||
goto compile_var_part_end
|
||||
end;
|
||||
_write_z(".section .data\n\0");
|
||||
|
||||
.compile_var_part_loop;
|
||||
_compile_variable_declaration(parser_node);
|
||||
node := _compile_variable_declaration(parser_node);
|
||||
if first_variable = 0 then
|
||||
first_variable := node
|
||||
else
|
||||
_elna_generator_procedure_set_next(current_variable, node)
|
||||
end;
|
||||
current_variable := node;
|
||||
|
||||
parser_node := _declaration_get_next(parser_node);
|
||||
if parser_node <> 0 then
|
||||
goto compile_var_part_loop
|
||||
end;
|
||||
|
||||
.compile_var_part_end
|
||||
.compile_var_part_end;
|
||||
return first_variable
|
||||
end;
|
||||
|
||||
proc _module_declaration_size();
|
||||
@@ -3705,39 +3978,24 @@ end;
|
||||
proc _compile_module_declaration(parser_node: Word);
|
||||
var
|
||||
current_part: Word;
|
||||
compiler_strings_copy: Word;
|
||||
compiler_strings_end: Word;
|
||||
current_byte: Word;
|
||||
result: Word;
|
||||
result_size: Word;
|
||||
begin
|
||||
_write_z(".globl _start\n\n\0");
|
||||
result_size := _elna_generator_procedure_size();
|
||||
result := _allocate(result_size);
|
||||
|
||||
_elna_generator_procedure_set_kind(result, ElnaGeneratorKind._module);
|
||||
_elna_generator_procedure_set_next(result, 0);
|
||||
|
||||
current_part := _module_declaration_get_globals(parser_node);
|
||||
_compile_var_part(current_part);
|
||||
|
||||
_write_z(".section .text\n\n\0");
|
||||
_write_z(".type _syscall, @function\n_syscall:\n\tmv a7, a6\n\tecall\n\tret\n\n\0");
|
||||
_write_z(".type _load_byte, @function\n_load_byte:\n\tlb a0, (a0)\nret\n\n\0");
|
||||
_write_z(".type _store_byte, @function\n_store_byte:\n\tsb a0, (a1)\nret\n\n\0");
|
||||
current_part := _compile_var_part(current_part);
|
||||
_elna_generator_procedure_set_name(result, current_part);
|
||||
|
||||
current_part := _module_declaration_get_procedures(parser_node);
|
||||
_compile_procedures(current_part);
|
||||
current_part := _compile_procedures(current_part);
|
||||
_elna_generator_procedure_set_body(result, current_part);
|
||||
|
||||
_write_z(".section .rodata\n.type strings, @object\nstrings: .ascii \0");
|
||||
_write_c('"');
|
||||
|
||||
compiler_strings_copy := @compiler_strings;
|
||||
compiler_strings_end := compiler_strings_position;
|
||||
|
||||
.compile_module_declaration_loop;
|
||||
if compiler_strings_copy < compiler_strings_end then
|
||||
current_byte := _load_byte(compiler_strings_copy);
|
||||
compiler_strings_copy := compiler_strings_copy + 1;
|
||||
_write_c(current_byte);
|
||||
|
||||
goto compile_module_declaration_loop
|
||||
end;
|
||||
_write_c('"');
|
||||
_write_c('\n')
|
||||
return result
|
||||
end;
|
||||
|
||||
proc _read_procedure_declaration(parser_node: Word);
|
||||
@@ -3798,10 +4056,12 @@ end;
|
||||
proc _compile();
|
||||
var
|
||||
parser_node: Word;
|
||||
tac: Word;
|
||||
begin
|
||||
parser_node := _parse_module_declaration();
|
||||
_read_module_declaration(parser_node);
|
||||
_compile_module_declaration(parser_node)
|
||||
tac := _compile_module_declaration(parser_node);
|
||||
_elna_writer_module(tac)
|
||||
end;
|
||||
|
||||
(**
|
||||
|
||||
Reference in New Issue
Block a user