diff --git a/boot/stage14.elna b/boot/stage14.elna index 9a6e18b..e7e8811 100644 --- a/boot/stage14.elna +++ b/boot/stage14.elna @@ -1598,8 +1598,8 @@ begin _lexer_read_token(@token_kind); if token_kind <> _lexer_token_kind_assignment() then - (* Else we assume this is a zeroed 102400 bytes big array. *) - _write_z(" .zero 102400\0") + (* Else we assume this is a zeroed 819200 bytes big array. *) + _write_z(" .zero 819200\0") else (* Skip the assignment sign with surrounding whitespaces. *) _lexer_skip_token(); @@ -3038,7 +3038,7 @@ begin .start_read; (* Second argument is buffer size. Modifying update the source_code definition. *) - last_read := _read_file(offset, 102400); + last_read := _read_file(offset, 819200); if last_read > 0 then offset := offset + last_read; goto .start_read diff --git a/boot/stage15.elna b/boot/stage15.elna index 3d05d1b..d85d95e 100644 --- a/boot/stage15.elna +++ b/boot/stage15.elna @@ -135,7 +135,16 @@ type variable_expression, field_access_expression, dereference_expression, - unary_expression + unary_expression, + binary_expression, + call, + goto_statement, + label_declaration, + return_statement, + assign_statement, + if_statement, + procedure_declaration, + variable_declaration ); const @@ -554,7 +563,7 @@ begin integer_token := _lexer_global_get_start(); integer_length := _lexer_global_get_end(); - integer_length := integer_length - integer_token; + integer_length := integer_length - integer_token; _lexer_skip_token(); _node_set_kind(result, NodeKind.integer_literal); @@ -580,21 +589,27 @@ begin end; proc _character_literal_node_get_value(this: Word); - return _load_word(this + 4) +begin + this := this + 4; + return this^ end; proc _character_literal_node_set_value(this: Word, value: Word); begin - _store_word(value, this + 4) + this := this + 4; + this^ := value end; proc _character_literal_node_get_length(this: Word); - return _load_word(this + 8) +begin + this := this + 8; + return this^ end; proc _character_literal_node_set_length(this: Word, value: Word); begin - _store_word(value, this + 8) + this := this + 8; + this^ := value end; proc _parse_character_literal(); @@ -624,11 +639,11 @@ var character_length: Word; begin character := _character_literal_node_get_value(character_literal_node); - character_length := _character_literal_node_get_length(character_literal_node);; + character_length := _character_literal_node_get_length(character_literal_node); _write_z("\tli t0, \0"); _write_s(character, character_length); - _write_c('\n'); + _write_c('\n') end; proc _variable_expression_size(); @@ -712,21 +727,27 @@ proc _string_literal_node_size(); end; proc _string_literal_node_get_value(this: Word); - return _load_word(this + 4) +begin + this := this + 4; + return this^ end; proc _string_literal_node_set_value(this: Word, value: Word); begin - _store_word(value, this + 4) + this := this + 4; + this^ := value end; proc _string_literal_node_get_length(this: Word); - return _load_word(this + 8) +begin + this := this + 8; + return this^ end; proc _string_literal_node_set_length(this: Word, value: Word); begin - _store_word(value, this + 8) + this := this + 8; + this^ := value end; proc _parse_string_literal(); @@ -785,13 +806,7 @@ begin elsif token_kind = LexerTokenKind.string then parser_node := _parse_string_literal() elsif token_kind = LexerTokenKind.identifier then - current_character := _lexer_global_get_start(); - current_character := _load_byte(current_character); - - (* This is a call if the statement starts with an underscore. *) - if current_character <> '_' then - parser_node := _parse_variable_expression() - end + parser_node := _parse_variable_expression() end; return parser_node end; @@ -840,6 +855,8 @@ begin simple_expression := _parse_dereference_expression(simple_expression) elsif token_kind = LexerTokenKind.dot then simple_expression := _parse_field_access_expression(simple_expression) + elsif token_kind = LexerTokenKind.left_paren then + simple_expression := _parse_call(simple_expression) end; return simple_expression end; @@ -905,14 +922,14 @@ begin operator := 0; if token_kind = LexerTokenKind.at then - operator := '@'; + operator := '@' elsif token_kind = LexerTokenKind.minus then - operator := '-'; + operator := '-' elsif token_kind = LexerTokenKind.not then - operator := '~'; + operator := '~' end; if operator <> 0 then - _lexer_skip_token(); + _lexer_skip_token() end; result := _parse_designator(); @@ -961,177 +978,288 @@ begin end end; -proc _compile_binary_rhs(); -var - parser_node: Word; -begin - (* Save the value of the left expression on the stack. *) - _write_z("\tsw t0, 64(sp)\n\0"); - parser_node := _parse_unary_expression(); - _compile_unary_expression(parser_node); - - (* Load the left expression from the stack; *) - _write_z("\tlw t1, 64(sp)\n\0") +proc _binary_expression_size(); + return 16 end; -proc _compile_expression(); -var - token_kind: Word; - current_byte: Word; - parser_node: Word; +proc _binary_expression_get_lhs(this: Word); begin - _lexer_read_token(@token_kind); - if token_kind = LexerTokenKind.identifier then - current_byte := _lexer_global_get_start(); - current_byte := _load_byte(current_byte); + this := this + 4; + return this^ +end; - if current_byte = '_' then - _compile_call(); - _write_z("\tmv t0, a0\n\0"); - goto compile_expression_end - end - end; - parser_node := _parse_unary_expression(); - _compile_unary_expression(parser_node); +proc _binary_expression_set_lhs(this: Word, value: Word); +begin + this := this + 4; + this^ := value +end; +proc _binary_expression_get_rhs(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _binary_expression_set_rhs(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _binary_expression_get_operator(this: Word); +begin + this := this + 12; + return this^ +end; + +proc _binary_expression_set_operator(this: Word, value: Word); +begin + this := this + 12; + this^ := value +end; + +proc _parse_binary_expression(); +var + lhs_node: Word; + rhs_node: Word; + token_kind: Word; + memory_size: Word; + result: Word; +begin + lhs_node := _parse_unary_expression(); + rhs_node := 0; _lexer_read_token(@token_kind); if token_kind = LexerTokenKind.plus then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tadd t0, t0, t1\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.minus then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tsub t0, t1, t0\n\0"); + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.multiplication then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tmul t0, t0, t1\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.and then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tand t0, t0, t1\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind._or then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tor t0, t0, t1\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind._xor then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\txor t0, t0, t1\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.equals then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\txor t0, t0, t1\n\tseqz t0, t0\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.remainder then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\trem t0, t1, t0\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.division then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tdiv t0, t1, t0\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.less_than then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tslt t0, t1, t0\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.greater_than then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tslt t0, t0, t1\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.less_equal then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tslt t0, t0, t1\n\txori t0, t0, 1\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.not_equal then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\txor t0, t0, t1\n\tsnez t0, t0\n\0") + rhs_node := _parse_unary_expression() elsif token_kind = LexerTokenKind.greater_equal then _lexer_skip_token(); - _compile_binary_rhs(); - - (* Execute the operation. *) - _write_z("\tslt t0, t1, t0\n\txori t0, t0, 1\n\0") + rhs_node := _parse_unary_expression() end; + if rhs_node <> 0 then + memory_size := _binary_expression_size(); + result := _allocate(memory_size); - .compile_expression_end; + _node_set_kind(result, NodeKind.binary_expression); + _binary_expression_set_lhs(result, lhs_node); + _binary_expression_set_rhs(result, rhs_node); + _binary_expression_set_operator(result, token_kind) + else + result := lhs_node + end; + return result end; -proc _compile_call(); +proc _compile_binary_expression(parser_node: Word); +var + token_kind: Word; + expression_kind: Word; + operand_node: Word; +begin + expression_kind := _node_get_kind(parser_node); + + if expression_kind <> NodeKind.binary_expression then + _compile_unary_expression(parser_node) + else + token_kind := _binary_expression_get_operator(parser_node); + + operand_node := _binary_expression_get_lhs(parser_node); + _compile_unary_expression(operand_node); + (* Save the value of the left expression on the stack. *) + _write_z("\tsw t0, 64(sp)\n\0"); + + operand_node := _binary_expression_get_rhs(parser_node); + _compile_unary_expression(operand_node); + (* Load the left expression from the stack; *) + _write_z("\tlw t1, 64(sp)\n\0"); + + if token_kind = LexerTokenKind.plus then + _write_z("\tadd t0, t0, t1\n\0") + elsif token_kind = LexerTokenKind.minus then + _write_z("\tsub t0, t1, t0\n\0"); + elsif token_kind = LexerTokenKind.multiplication then + _write_z("\tmul t0, t0, t1\n\0") + elsif token_kind = LexerTokenKind.and then + _write_z("\tand t0, t0, t1\n\0") + elsif token_kind = LexerTokenKind._or then + _write_z("\tor t0, t0, t1\n\0") + elsif token_kind = LexerTokenKind._xor then + _write_z("\txor t0, t0, t1\n\0") + elsif token_kind = LexerTokenKind.equals then + _write_z("\txor t0, t0, t1\n\tseqz t0, t0\n\0") + elsif token_kind = LexerTokenKind.remainder then + _write_z("\trem t0, t1, t0\n\0") + elsif token_kind = LexerTokenKind.division then + _write_z("\tdiv t0, t1, t0\n\0") + elsif token_kind = LexerTokenKind.less_than then + _write_z("\tslt t0, t1, t0\n\0") + elsif token_kind = LexerTokenKind.greater_than then + _write_z("\tslt t0, t0, t1\n\0") + elsif token_kind = LexerTokenKind.less_equal then + _write_z("\tslt t0, t0, t1\n\txori t0, t0, 1\n\0") + elsif token_kind = LexerTokenKind.not_equal then + _write_z("\txor t0, t0, t1\n\tsnez t0, t0\n\0") + elsif token_kind = LexerTokenKind.greater_equal then + _write_z("\tslt t0, t1, t0\n\txori t0, t0, 1\n\0") + end + end +end; + +proc _compile_expression(); +var + parser_node: Word; +begin + parser_node := _parse_binary_expression(); + _compile_binary_expression(parser_node) +end; + +(* 4 bytes node kind + 4 byte pointer to variable expression + 4 * 7 for arguments. *) +proc _call_size(); + return 44 +end; + +proc _call_get_name(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _call_set_name(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _call_get_argument(this: Word, n: Word); +begin + n := n * 4; + this := this + 8; + this := this + n; + return this^ +end; + +proc _call_set_argument(this: Word, n: Word, value: Word); +begin + n := n * 4; + this := this + 8; + this := this + n; + this^ := value +end; + +proc _parse_call(callee: Word); +var + parsed_expression: Word; + result: Word; + argument_number: Word; + token_kind: Word; + call_size: Word; +begin + call_size := _call_size(); + result := _allocate(call_size); + _node_set_kind(result, NodeKind.call); + _statement_set_next(result, 0); + + argument_number := 1; + _call_set_name(result, callee); + + _lexer_read_token(@token_kind); + _lexer_skip_token(); + _lexer_read_token(@token_kind); + + if token_kind = LexerTokenKind.right_paren then + _lexer_skip_token(); + goto parse_call_end + end; + + .parse_call_loop; + parsed_expression := _parse_binary_expression(); + _call_set_argument(result, argument_number, parsed_expression); + argument_number := argument_number + 1; + _lexer_read_token(@token_kind); + _lexer_skip_token(); + + if token_kind = LexerTokenKind.comma then + goto parse_call_loop + end; + + .parse_call_end; + (* Set the trailing argument to nil. *) + _call_set_argument(result, argument_number, 0); + + return result +end; + +proc _compile_call(parsed_call: Word); var name_length: Word; name: Word; argument_count: Word; stack_offset: Word; - token_kind: Word; + parsed_expression: Word; begin - _lexer_read_token(@token_kind); - name := _lexer_global_get_start(); - name_length := _lexer_global_get_end(); - name_length := name_length - name; + parsed_expression := _call_get_name(parsed_call); + name := _variable_expression_get_name(parsed_expression); + name_length := _variable_expression_get_length(parsed_expression); argument_count := 0; - (* Skip the identifier and left paren. *) - _lexer_skip_token(); - _lexer_read_token(@token_kind); - _lexer_skip_token(); - - _lexer_read_token(@token_kind); - if token_kind = LexerTokenKind.right_paren then - goto compile_call_finalize - end; .compile_call_loop; - _compile_expression(); - (* Save the argument on the stack. *) - _write_z("\tsw t0, \0"); - - (* Calculate the stack offset: 116 - (4 * argument_counter) *) - stack_offset := argument_count * 4; - _write_i(116 - stack_offset); - - _write_z("(sp)\n\0"); - - (* Add one to the argument counter. *) - argument_count := argument_count + 1; - - _lexer_read_token(@token_kind); - - if token_kind <> LexerTokenKind.comma then + parsed_expression := _call_get_argument(parsed_call, argument_count + 1); + if parsed_expression = 0 then goto compile_call_finalize + else + _compile_binary_expression(parsed_expression); + + (* Save the argument on the stack. *) + _write_z("\tsw t0, \0"); + + stack_offset := argument_count * 4; + _write_i(116 - stack_offset); + _write_z("(sp)\n\0"); + + argument_count := argument_count + 1; + goto compile_call_loop end; - _lexer_skip_token(); - goto compile_call_loop; .compile_call_finalize; + (* Load the argument from the stack. *) if argument_count <> 0 then (* Decrement the argument counter. *) @@ -1151,37 +1279,159 @@ begin goto compile_call_finalize end; - .compile_call_end; _write_z("\tcall \0"); _write_s(name, name_length); - _write_c('\n'); - - (* Skip the right paren. *) - _lexer_read_token(@token_kind); - _lexer_skip_token() + _write_c('\n') end; -proc _compile_goto(); +(** + * All statements are chained into a list. Next contains a pointer to the next + * statement in the statement list. + *) +proc _statement_get_next(this: Word); +begin + this := this + 4; + return this^ +end; + +proc _statement_set_next(this: Word, value: Word); +begin + this := this + 4; + this^ := value +end; + +proc _goto_statement_size(); + return 16 +end; + +proc _goto_statement_get_label(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _goto_statement_set_label(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _goto_statement_get_length(this: Word); +begin + this := this + 12; + return this^ +end; + +proc _goto_statement_set_length(this: Word, value: Word); +begin + this := this + 12; + this^ := value +end; + +proc _parse_goto_statement(); var - next_token: Word; - next_length: Word; token_kind: Word; + label_name: Word; + label_length: Word; + statement_size: Word; + result: Word; begin _lexer_skip_token(); _lexer_read_token(@token_kind); - if token_kind = LexerTokenKind.dot then - _lexer_skip_token(); - _lexer_read_token(@token_kind) - end; - next_token := _lexer_global_get_start(); - next_length := _lexer_global_get_end(); - next_length := next_length - next_token; + label_name := _lexer_global_get_start(); + label_length := _lexer_global_get_end() - label_name; + _lexer_skip_token(); + + statement_size := _goto_statement_size(); + result := _allocate(statement_size); + + _node_set_kind(result, NodeKind.goto_statement); + _statement_set_next(result, 0); + _goto_statement_set_label(result, label_name); + _goto_statement_set_length(result, label_length); + + return result +end; + +proc _compile_goto_statement(parser_node: Word); +var + label_name: Word; + label_length: Word; +begin + label_name := _goto_statement_get_label(parser_node); + label_length := _goto_statement_get_length(parser_node); _write_z("\tj .\0"); + _write_s(label_name, label_length); + _write_c('\n') +end; - _write_s(next_token, next_length); - _lexer_skip_token() +proc _label_declaration_size(); + return 16 +end; + +proc _label_declaration_get_label(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _label_declaration_set_label(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _label_declaration_get_length(this: Word); +begin + this := this + 12; + return this^ +end; + +proc _label_declaration_set_length(this: Word, value: Word); +begin + this := this + 12; + this^ := value +end; + +proc _parse_label_declaration(); +var + token_kind: Word; + label_name: Word; + label_length: Word; + statement_size: Word; + result: Word; +begin + _lexer_skip_token(); + _lexer_read_token(@token_kind); + + label_name := _lexer_global_get_start(); + label_length := _lexer_global_get_end() - label_name; + _lexer_skip_token(); + + statement_size := _label_declaration_size(); + result := _allocate(statement_size); + + _node_set_kind(result, NodeKind.label_declaration); + _statement_set_next(result, 0); + _goto_statement_set_label(result, label_name); + _goto_statement_set_length(result, label_length); + + return result +end; + +proc _compile_label_declaration(parser_node: Word); +var + label_name: Word; + label_length: Word; +begin + label_name := _label_declaration_get_label(parser_node); + label_length := _label_declaration_get_length(parser_node); + + _write_c('.'); + _write_s(label_name, label_length); + _write_z(":\n\0") end; proc _compile_local_designator(symbol: Word); @@ -1341,42 +1591,131 @@ begin elsif node_kind = NodeKind.field_access_expression then _compile_enumeration_value(parser_node); is_address := 0 + elsif node_kind = NodeKind.call then + _compile_call(parser_node); + _write_z("\tmv t0, a0\n\0"); + is_address := 0 else is_address := _compile_simple_expression(parser_node) end; return is_address end; -proc _compile_assignment(); -var - token_kind: Word; -begin - token_kind := _parse_designator(); - _compile_designator(token_kind); +proc _assignment_statement_size(); + return 16 +end; - (* Save the assignee address on the stack. *) - _write_z("\tsw t0, 60(sp)\n\0"); +proc _assignment_statement_get_assignee(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _assignment_statement_set_assignee(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _assignment_statement_get_assignment(this: Word); +begin + this := this + 12; + return this^ +end; + +proc _assignment_statement_set_assignment(this: Word, value: Word); +begin + this := this + 12; + this^ := value +end; + +proc _parse_assignment_statement(assignee: Word); +var + statement_size: Word; + result: Word; + token_kind: Word; + assignment_node: Word; +begin + statement_size := _assignment_statement_size(); + result := _allocate(statement_size); + + _node_set_kind(result, NodeKind.assignment_statement); + _statement_set_next(result, 0); + _assignment_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); + + return result +end; + +proc _compile_assignment_statement(parser_tree: Word); +var + current_expression: Word; +begin + current_expression := _assignment_statement_get_assignee(parser_tree); + _compile_designator(current_expression); + + (* Save the assignee address on the stack. *) + _write_z("\tsw t0, 60(sp)\n\0"); + (* Compile the assignment. *) - _lexer_read_token(@token_kind); - _compile_expression(); + current_expression := _assignment_statement_get_assignment(parser_tree); + _compile_binary_expression(current_expression); _write_z("\tlw t1, 60(sp)\n\tsw t0, (t1)\n\0") end; -proc _compile_return_statement(); +proc _return_statement_size(); + return 12 +end; + +proc _return_statement_get_returned(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _return_statement_set_returned(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _parse_return_statement(); var token_kind: Word; + returned: Word; + label_length: Word; + statement_size: Word; + result: Word; begin (* Skip "return" keyword and whitespace after it. *) - _lexer_read_token(@token_kind); _lexer_skip_token(); + _lexer_read_token(@token_kind); - _compile_expression(); + returned := _parse_binary_expression(); + + statement_size := _return_statement_size(); + result := _allocate(statement_size); + + _node_set_kind(result, NodeKind.return_statement); + _statement_set_next(result, 0); + _return_statement_set_returned(result, returned); + + return result +end; + +proc _compile_return_statement(parser_node: Word); +var + return_expression: Word; +begin + return_expression := _return_statement_get_returned(parser_node); + _compile_binary_expression(return_expression); _write_z("\tmv a0, t0\n\0") end; @@ -1392,17 +1731,42 @@ begin _write_i(counter) end; -proc _compile_condition(after_end_label: Word); +proc _parse_conditional_statements(); var - condition_label: Word; + conditional_size: Word; token_kind: Word; + current_node: Word; + result: Word; begin - (* Compile condition. *) - _compile_expression(); - (* Skip " then" with newline. *) + conditional_size := _conditional_statements_size(); + result := _allocate(conditional_size); + + (* Skip "if", "while" or "elsif". *) + _lexer_skip_token(); + + current_node := _parse_binary_expression(); + _conditional_statements_set_condition(result, current_node); + + (* Skip "then" or "do". *) _lexer_read_token(@token_kind); _lexer_skip_token(); + current_node := _parse_statements(); + _conditional_statements_set_statements(result, current_node); + + _conditional_statements_set_next(result, 0); + return result +end; + +proc _compile_conditional_statements(parser_node: Word, after_end_label: Word); +var + condition_label: Word; + current_node: Word; +begin + (* Compile condition. *) + current_node := _conditional_statements_get_condition(parser_node); + _compile_binary_expression(current_node); + (* condition_label is the label in front of the next elsif condition or end. *) condition_label := label_counter; label_counter := label_counter + 1; @@ -1411,7 +1775,8 @@ begin _write_label(condition_label); _write_c('\n'); - _compile_statement_list(); + current_node := _conditional_statements_get_statements(parser_node); + _compile_statements(current_node); _write_z("\tj \0"); _write_label(after_end_label); @@ -1421,98 +1786,237 @@ begin _write_z(":\n\0") end; -proc _compile_if(); -var - after_end_label: Word; - condition_label: Word; - token_kind: Word; +(** + * Conditional statements is a list of pairs: condition and statements. + * Used for example to represent if and elsif blocks with beloning statements. + *) +proc _conditional_statements_size(); + return 12 +end; + +proc _conditional_statements_get_condition(this: Word); + return this^ +end; + +proc _conditional_statements_set_condition(this: Word, value: Word); begin - (* Skip "if ". *) + this^ := value +end; + +proc _conditional_statements_get_statements(this: Word); +begin + this := this + 4; + return this^ +end; + +proc _conditional_statements_set_statements(this: Word, value: Word); +begin + this := this + 4; + this^ := value +end; + +proc _conditional_statements_get_next(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _conditional_statements_set_next(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _if_statement_size(); + return 16 +end; + +proc _if_statement_get_conditionals(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _if_statement_set_conditionals(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _if_statement_get_else(this: Word); +begin + this := this + 12; + return this^ +end; + +proc _if_statement_set_else(this: Word, value: Word); +begin + this := this + 12; + this^ := value +end; + +proc _parse_if_statement(); +var + current_node: Word; + result: Word; + object_size: Word; + token_kind: Word; + previous_conditional: Word; + next_conditional: Word; +begin + object_size := _if_statement_size(); + result := _allocate(object_size); + + _node_set_kind(result, NodeKind.if_statement); + _statement_set_next(result, 0); + + previous_conditional := _parse_conditional_statements(); + _if_statement_set_conditionals(result, previous_conditional); + + .parse_if_statement_loop; _lexer_read_token(@token_kind); + + if token_kind = LexerTokenKind._elsif then + next_conditional := _parse_conditional_statements(); + _conditional_statements_set_next(previous_conditional, next_conditional); + previous_conditional = next_conditional; + + goto parse_if_statement_loop + elsif token_kind = LexerTokenKind._else then + _lexer_skip_token(); + + current_node := _parse_statements(); + _if_statement_set_else(result, current_node) + else + _if_statement_set_else(result, 0) + end; _lexer_skip_token(); + return result +end; + +proc _parse_statement(); +var + token_kind: Word; + result : Word; +begin + result := 0; + _lexer_read_token(@token_kind); + + if token_kind = LexerTokenKind._goto then + result := _parse_goto_statement() + elsif token_kind = LexerTokenKind._if then + result := _parse_if_statement() + elsif token_kind = LexerTokenKind._return then + result := _parse_return_statement() + elsif token_kind = LexerTokenKind.dot then + result := _parse_label_declaration() + elsif token_kind = LexerTokenKind.identifier then + result := _parse_designator(); + + if _node_get_kind(result) <> NodeKind.call then + result := _parse_assignment_statement(result) + end + end; + return result +end; + +proc _parse_statements(); +var + token_kind: Word; + previous_statement: Word; + next_statement: Word; + first_statement: Word; +begin + _skip_empty_lines(); + + first_statement := _parse_statement(); + previous_statement := first_statement; + if previous_statement = 0 then + goto parse_statements_end + end; + + .parse_statement_loop; + _lexer_read_token(@token_kind); + + if token_kind = LexerTokenKind.semicolon then + _lexer_skip_token(); + _skip_empty_lines(); + next_statement := _parse_statement(); + _statement_set_next(previous_statement, next_statement); + previous_statement := next_statement; + + if previous_statement <> 0 then + goto parse_statement_loop + end + end; + .parse_statements_end; + _skip_empty_lines(); + + return first_statement +end; + +proc _compile_statements(parser_node: Word); +var + current_statement: Word; +begin + current_statement := parser_node; + + .compile_statements_loop; + if current_statement <> 0 then + _compile_statement(current_statement); + current_statement := _statement_get_next(current_statement); + goto compile_statements_loop + end +end; + +proc _compile_if_statement(parser_node: Word); +var + current_node: Word; + after_end_label: Word; + condition_label: Word; +begin after_end_label := label_counter; label_counter := label_counter + 1; - _compile_condition(after_end_label); - .compile_if_loop; + current_node := _if_statement_get_conditionals(parser_node); + _compile_conditional_statements(current_node, after_end_label); - _lexer_read_token(@token_kind); - if token_kind = LexerTokenKind._else then - _lexer_skip_token(); - _compile_statement_list() - elsif token_kind = LexerTokenKind._elsif then - _lexer_skip_token(); - _compile_condition(after_end_label); - - goto compile_if_loop + .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); + goto compile_if_statement_loop + end; + current_node := _if_statement_get_else(parser_node); + + if current_node <> 0 then + _compile_statements(current_node) end; - _lexer_skip_token(); _write_label(after_end_label); _write_z(":\n\0") end; -proc _compile_label_declaration(); +proc _compile_statement(parser_node: Word); var - label_token: Word; - token_kind: Word; - name: Word; + statement_kind: Word; begin - (* Skip the dot. *) - _lexer_skip_token(); - _lexer_read_token(@token_kind); - name := _lexer_global_get_start(); - label_token := _lexer_global_get_end(); - label_token := label_token - name; - _write_c('.'); - _write_s(name, label_token); - _write_z(":\n\0"); - _lexer_skip_token() -end; + statement_kind := _node_get_kind(parser_node); -proc _compile_statement(); -var - current_byte: Word; - token_kind: Word; -begin - _lexer_read_token(@token_kind); - - if token_kind = LexerTokenKind._goto then - _compile_goto() - elsif token_kind = LexerTokenKind._if then - _compile_if() - elsif token_kind = LexerTokenKind._return then - _compile_return_statement() - elsif token_kind = LexerTokenKind.dot then - _compile_label_declaration() - elsif token_kind = LexerTokenKind.identifier then - current_byte := _lexer_global_get_start(); - current_byte := _load_byte(current_byte); - - (* This is a call if the statement starts with an underscore. *) - if current_byte = '_' then - _compile_call() - else - _compile_assignment() - end - end; - _write_c('\n') -end; - -proc _compile_statement_list(); -var - token_kind: Word; -begin - _skip_empty_lines(); - _compile_statement(); - _lexer_read_token(@token_kind); - - if token_kind = LexerTokenKind.semicolon then - _lexer_skip_token(); - _compile_statement_list() - end; - _skip_empty_lines() + if statement_kind = NodeKind.goto_statement then + _compile_goto_statement(parser_node) + elsif statement_kind = NodeKind.if_statement then + _compile_if_statement(parser_node) + elsif statement_kind = NodeKind.return_statement then + _compile_return_statement(parser_node) + elsif statement_kind = NodeKind.label_declaration then + _compile_label_declaration(parser_node) + elsif statement_kind = NodeKind.call then + _compile_call(parser_node) + elsif statement_kind = NodeKind.assignment_statement then + _compile_assignment_statement(parser_node) + end end; (** @@ -1534,34 +2038,43 @@ end; proc _type_set_kind(this: Word, value: Word); begin - _store_word(value, this) + this^ := value end; proc _type_get_size(this: Word); - return _load_word(this + 4) +begin + this := this + 4; + return this^ end; proc _type_set_size(this: Word, value: Word); begin - _store_word(value, this + 4) + this := this + 4; + this^ := value end; proc _enumeration_type_get_members(this: Word); - return _load_word(this + 8) +begin + this := this + 8; + return this^ end; proc _enumeration_type_set_members(this: Word, value: Word); begin - _store_word(value, this + 8) + this := this + 8; + this^ := value end; proc _enumeration_type_get_length(this: Word); - return _load_word(this + 12) +begin + this := this + 12; + return this^ end; proc _enumeration_type_set_length(this: Word, value: Word); begin - _store_word(value, this + 12) + this := this + 12; + this^ := value end; (** @@ -1861,23 +2374,182 @@ begin end end; +proc _declaration_get_next(this: Word); +begin + this := this + 4; + return this^ +end; + +proc _declaration_set_next(this: Word, value: Word); +begin + this := this + 4; + this^ := value +end; + +proc _declaration_get_name(this: Word); +begin + this := this + 8; + return this^ +end; + +proc _declaration_set_name(this: Word, value: Word); +begin + this := this + 8; + this^ := value +end; + +proc _declaration_get_length(this: Word); +begin + this := this + 12; + return this^ +end; + +proc _declaration_set_length(this: Word, value: Word); +begin + this := this + 12; + this^ := value +end; + +(* Kind + next declaration pointer + 7 * 4 arguments + procedure name + statement list pointer + temporary list pointer. *) +proc _procedure_declaration_size(); + return 108 +end; + +proc _procedure_declaration_get_body(this: Word); +begin + this := this + 16; + return this^ +end; + +proc _procedure_declaration_set_body(this: Word, value: Word); +begin + this := this + 16; + this^ := value +end; + +proc _procedure_declaration_get_temporaries(this: Word); +begin + this := this + 20; + return this^ +end; + +proc _procedure_declaration_set_temporaries(this: Word, value: Word); +begin + this := this + 20; + this^ := value +end; + +proc _procedure_declaration_get_parameter(this: Word, n: Word, field: Word); +begin + field := field * 4; + n := n * 12; + this := this + 12; + this := this + n; + this := this + field; + return this^ +end; + +proc _procedure_declaration_set_parameter(this: Word, n: Word, name: Word, length: Word, type_expression: Word); +begin + n := n * 12; + this := this + 24; + this := this + n; + this := this - 4; + this^ := type_expression; + this := this - 4; + this^ := length; + this := this - 4; + this^ := name +end; + +proc _parse_procedure_declaration(); +var + name_pointer: Word; + name_length: Word; + token_kind: Word; + result: Word; + declaration_size: Word; + parameter_counter: Word; +begin + declaration_size := _procedure_declaration_size(); + result := _allocate(declaration_size); + + _node_set_kind(result, NodeKind.procedure_declaration); + _declaration_set_next(result, 0); + + (* Skip "proc ". *) + _lexer_skip_token(); + + _lexer_read_token(@token_kind); + name_pointer := _lexer_global_get_start(); + name_length := _lexer_global_get_end() - name_pointer; + + _declaration_set_name(result, name_pointer); + _declaration_set_length(result, name_length); + (* Skip procedure name. *) + _lexer_skip_token(); + + (* Skip open paren. *) + _lexer_read_token(@token_kind); + _lexer_skip_token(); + parameter_counter := 0; + + _lexer_read_token(@token_kind); + if token_kind = LexerTokenKind.right_paren then + goto parse_procedure_declaration_parameters + end; + .parse_procedure_declaration_parameter; + + parameter_counter := parameter_counter + 1; + name_pointer := _lexer_global_get_start(); + name_length := _lexer_global_get_end() - name_pointer; + + _lexer_skip_token(); + (* Skip colon in front of the type expression and the type itself. *) + _lexer_read_token(@token_kind); + _lexer_skip_token(); + _lexer_read_token(@token_kind); + _lexer_skip_token(); + + _procedure_declaration_set_parameter(result, parameter_counter, name_pointer, name_length, 0); + _lexer_read_token(@token_kind); + + if token_kind = LexerTokenKind.comma then + goto parse_procedure_declaration_parameter + end; + + .parse_procedure_declaration_parameters; + (* Skip right paren and semicolon. *) + _lexer_skip_token(); + _lexer_read_token(@token_kind); + _lexer_skip_token(); + + _lexer_read_token(@token_kind); + + return result +end; + +proc _compile_procedure_declaration(); +begin +end; + proc _compile_procedure(); var name_pointer: Word; name_length: Word; token_kind: Word; + parser_node: Word; begin (* Skip "proc ". *) _lexer_read_token(@token_kind); _lexer_skip_token(); (* Clear local symbol table. *) - _store_word(0, @symbol_table_local); + symbol_table_local := 0; _lexer_read_token(@token_kind); name_pointer := _lexer_global_get_start(); - name_length := _lexer_global_get_end(); - name_length := name_length - name_pointer; + name_length := _lexer_global_get_end() - name_pointer; (* Write .type _procedure_name, @function. *) _write_z(".type \0"); @@ -1903,9 +2575,11 @@ begin _lexer_read_token(@token_kind); if token_kind = LexerTokenKind._begin then _lexer_skip_token(); - _compile_statement_list() + parser_node := _parse_statements(); + _compile_statements(parser_node) elsif token_kind = LexerTokenKind._return then - _compile_return_statement() + parser_node := _parse_return_statement(parser_node); + _compile_return_statement(parser_node) end; (* Write the epilogue. *) @@ -2116,16 +2790,64 @@ begin .compile_const_part_end end; +proc _variable_declaration_size(); + return 20 +end; + +proc _variable_declaration_get_type(this: Word); +begin + this := this + 16; + return this^ +end; + +proc _variable_declaration_set_type(this: Word, value: Word); +begin + this := this + 16; + this^ := value +end; + +proc _parse_variable_declaration(); +var + token_kind: Word; + name: Word; + name_length: Word; + result: Word; + declaration_size: Word; +begin + _lexer_read_token(@token_kind); + + name := _lexer_global_get_start(); + name_length := _lexer_global_get_end() - name; + + (* Skip the variable name and colon with the type. *) + _lexer_skip_token(); + _lexer_read_token(@token_kind); + _lexer_skip_token(); + _lexer_read_token(@token_kind); + _lexer_skip_token(); + + declaration_size := _variable_declaration_size(); + result := _allocate(declaration_size); + + _node_set_kind(result, NodeKind.variable_declaration); + _declaration_set_next(result, 0); + _declaration_set_name(result, name); + _declaration_set_length(result, name_length); + _variable_declaration_set_type(result, 0); + + return result +end; + proc _compile_variable_declaration(); var name: Word; name_length: Word; token_kind: Word; + parser_tree: Word; begin - _lexer_read_token(@token_kind); - name := _lexer_global_get_start(); - name_length := _lexer_global_get_end(); - name_length := name_length - name; + parser_tree := _parse_variable_declaration(); + name := _declaration_get_name(parser_tree); + name_length := _declaration_get_length(parser_tree); _write_z(".type \0"); _write_s(name, name_length); @@ -2134,17 +2856,11 @@ begin _write_s(name, name_length); _write_c(':'); - (* Skip the variable name and colon with space before the type. *) - _lexer_skip_token(); - _lexer_read_token(@token_kind); - _lexer_skip_token(); - _read_type_expression(); - _lexer_read_token(@token_kind); if token_kind <> LexerTokenKind.assignment then - (* Else we assume this is a zeroed 102400 bytes big array. *) - _write_z(" .zero 102400\0") + (* Else we assume this is a zeroed 819200 bytes big array. *) + _write_z(" .zero 819200\0") else (* Skip the assignment sign with surrounding whitespaces. *) _lexer_skip_token(); @@ -2367,7 +3083,7 @@ begin target := target * 4; target := array + target; - _store_word(data, target) + target^ := data end; proc _get_at(array: Word, index: Word); @@ -3130,7 +3846,7 @@ begin .start_read; (* Second argument is buffer size. Modifying update the source_code definition. *) - last_read := _read_file(offset, 102400); + last_read := _read_file(offset, 819200); if last_read > 0 then offset := offset + last_read; goto start_read