diff --git a/boot/stage15.elna b/boot/stage15.elna index 431ad6b..cf5c69b 100644 --- a/boot/stage15.elna +++ b/boot/stage15.elna @@ -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; + 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 + 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; (**