summaryrefslogtreecommitdiff
path: root/boot
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2025-10-19 12:45:55 +0200
committerEugen Wissner <belka@caraus.de>2025-10-19 12:45:55 +0200
commit70eab55cdefafa877ef9488182fbf7d680902259 (patch)
tree56a1691c54adb13a26a0414a9546295554ba4c4d /boot
parentc6531ba3988d297e08ffa543686d68455b00b26d (diff)
downloadelna-70eab55cdefafa877ef9488182fbf7d680902259.tar.gz
Parse statement lists
Diffstat (limited to 'boot')
-rw-r--r--boot/stage14.elna6
-rw-r--r--boot/stage15.elna1208
2 files changed, 965 insertions, 249 deletions
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;
+proc _binary_expression_size();
+ return 16
+end;
+
+proc _binary_expression_get_lhs(this: 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);
+ this := this + 4;
+ return this^
+end;
- (* Load the left expression from the stack; *)
- _write_z("\tlw t1, 64(sp)\n\0")
+proc _binary_expression_set_lhs(this: Word, value: Word);
+begin
+ this := this + 4;
+ this^ := value
end;
-proc _compile_expression();
-var
- token_kind: Word;
- current_byte: Word;
- parser_node: Word;
+proc _binary_expression_get_rhs(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 + 8;
+ 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_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();
+ rhs_node := _parse_unary_expression()
+ end;
+ if rhs_node <> 0 then
+ memory_size := _binary_expression_size();
+ result := _allocate(memory_size);
- (* Execute the operation. *)
- _write_z("\tslt t0, t1, t0\n\txori t0, t0, 1\n\0")
+ _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_binary_expression(parser_node: Word);
+var
+ token_kind: Word;
+ expression_kind: Word;
+ operand_node: Word;
+begin
+ expression_kind := _node_get_kind(parser_node);
- .compile_expression_end;
+ 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_call();
+proc _compile_expression();
var
- name_length: Word;
- name: Word;
- argument_count: Word;
- stack_offset: Word;
+ 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
- _lexer_read_token(@token_kind);
- name := _lexer_global_get_start();
- name_length := _lexer_global_get_end();
- name_length := name_length - name;
- argument_count := 0;
+ 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);
- (* 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
+ _lexer_skip_token();
+ goto parse_call_end
end;
- .compile_call_loop;
- _compile_expression();
- (* Save the argument on the stack. *)
- _write_z("\tsw t0, \0");
+ .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();
- (* Calculate the stack offset: 116 - (4 * argument_counter) *)
- stack_offset := argument_count * 4;
- _write_i(116 - stack_offset);
+ if token_kind = LexerTokenKind.comma then
+ goto parse_call_loop
+ end;
- _write_z("(sp)\n\0");
+ .parse_call_end;
+ (* Set the trailing argument to nil. *)
+ _call_set_argument(result, argument_number, 0);
- (* Add one to the argument counter. *)
- argument_count := argument_count + 1;
+ return result
+end;
- _lexer_read_token(@token_kind);
+proc _compile_call(parsed_call: Word);
+var
+ name_length: Word;
+ name: Word;
+ argument_count: Word;
+ stack_offset: Word;
+ parsed_expression: Word;
+begin
+ 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;
+
+ .compile_call_loop;
- 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');
+ _write_c('\n')
+end;
- (* Skip the right paren. *)
- _lexer_read_token(@token_kind);
- _lexer_skip_token()
+(**
+ * 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 _compile_goto();
+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();
+proc _assignment_statement_size();
+ return 16
+end;
+
+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
- token_kind := _parse_designator();
- _compile_designator(token_kind);
+ statement_size := _assignment_statement_size();
+ result := _allocate(statement_size);
- (* Save the assignee address on the stack. *)
- _write_z("\tsw t0, 60(sp)\n\0");
+ _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);
+
+ 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;
- _compile_expression();
+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 ". *)
- _lexer_read_token(@token_kind);
- _lexer_skip_token();
+ this^ := value
+end;
- after_end_label := label_counter;
- label_counter := label_counter + 1;
+proc _conditional_statements_get_statements(this: Word);
+begin
+ this := this + 4;
+ return this^
+end;
- _compile_condition(after_end_label);
- .compile_if_loop;
+proc _conditional_statements_set_statements(this: Word, value: Word);
+begin
+ this := this + 4;
+ this^ := value
+end;
- _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);
+proc _conditional_statements_get_next(this: Word);
+begin
+ this := this + 8;
+ return this^
+end;
- goto compile_if_loop
- end;
- _lexer_skip_token();
+proc _conditional_statements_set_next(this: Word, value: Word);
+begin
+ this := this + 8;
+ this^ := value
+end;
- _write_label(after_end_label);
- _write_z(":\n\0")
+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 _compile_label_declaration();
+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
- label_token: Word;
+ current_node: Word;
+ result: Word;
+ object_size: Word;
token_kind: Word;
- name: Word;
+ previous_conditional: Word;
+ next_conditional: Word;
begin
- (* Skip the dot. *)
- _lexer_skip_token();
+ 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);
- 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()
+
+ 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 _compile_statement();
+proc _parse_statement();
var
- current_byte: Word;
token_kind: Word;
+ result : Word;
begin
+ result := 0;
_lexer_read_token(@token_kind);
if token_kind = LexerTokenKind._goto then
- _compile_goto()
+ result := _parse_goto_statement()
elsif token_kind = LexerTokenKind._if then
- _compile_if()
+ result := _parse_if_statement()
elsif token_kind = LexerTokenKind._return then
- _compile_return_statement()
+ result := _parse_return_statement()
elsif token_kind = LexerTokenKind.dot then
- _compile_label_declaration()
+ result := _parse_label_declaration()
elsif token_kind = LexerTokenKind.identifier then
- current_byte := _lexer_global_get_start();
- current_byte := _load_byte(current_byte);
+ result := _parse_designator();
- (* This is a call if the statement starts with an underscore. *)
- if current_byte = '_' then
- _compile_call()
- else
- _compile_assignment()
+ if _node_get_kind(result) <> NodeKind.call then
+ result := _parse_assignment_statement(result)
end
end;
- _write_c('\n')
+ return result
end;
-proc _compile_statement_list();
+proc _parse_statements();
var
token_kind: Word;
+ previous_statement: Word;
+ next_statement: Word;
+ first_statement: Word;
begin
_skip_empty_lines();
- _compile_statement();
+
+ 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();
- _compile_statement_list()
+ _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;
+
+ current_node := _if_statement_get_conditionals(parser_node);
+ _compile_conditional_statements(current_node, after_end_label);
+
+ .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;
- _skip_empty_lines()
+
+ _write_label(after_end_label);
+ _write_z(":\n\0")
+end;
+
+proc _compile_statement(parser_node: Word);
+var
+ statement_kind: Word;
+begin
+ statement_kind := _node_get_kind(parser_node);
+
+ 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 _compile_variable_declaration();
+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;
- token_kind: Word;
+ result: Word;
+ declaration_size: Word;
begin
_lexer_read_token(@token_kind);
+
name := _lexer_global_get_start();
- name_length := _lexer_global_get_end();
- name_length := name_length - name;
+ 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
+ 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