Implement if-else
This commit is contained in:
18
Rakefile
18
Rakefile
@@ -6,7 +6,9 @@
|
||||
require 'open3'
|
||||
require 'rake/clean'
|
||||
|
||||
STAGES = Dir.glob('boot/stage*.elna').collect { |stage| File.basename stage, '.elna' }.sort
|
||||
STAGES = Dir.glob('boot/stage*.elna')
|
||||
.collect { |stage| File.basename stage, '.elna' }
|
||||
.sort { |a, b| a.delete_prefix('stage').to_i <=> b.delete_prefix('stage').to_i }
|
||||
|
||||
CLEAN.include 'build/boot', 'build/valid'
|
||||
|
||||
@@ -39,17 +41,9 @@ end
|
||||
|
||||
desc 'Convert previous stage language into the current stage language'
|
||||
task :convert do
|
||||
File.open('boot/stage9.elna', 'w') do |current_stage|
|
||||
File.readlines('boot/stage8.elna').each do |line|
|
||||
comment_match = /^(\s*)#(.*)/.match line
|
||||
|
||||
if comment_match.nil?
|
||||
current_stage << line
|
||||
elsif comment_match[2].empty?
|
||||
current_stage << "\n"
|
||||
else
|
||||
current_stage << "#{comment_match[1]}(* #{comment_match[2].strip} *)\n"
|
||||
end
|
||||
File.open('boot/stage10.elna', 'w') do |current_stage|
|
||||
File.readlines('boot/stage9.elna').each do |line|
|
||||
current_stage << line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
1722
boot/stage10.elna
Normal file
1722
boot/stage10.elna
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,10 @@
|
||||
# - Procedure calls in expressions.
|
||||
# - Comments between (* and *) are supported. These are still single line
|
||||
# comments and they should be on a separate line.
|
||||
# - _syscall builtin. _syscall takes 7 arguments,
|
||||
# the 7th argument gets stored in a7 before invoking ecall.
|
||||
# Other arguments are saved in a0 through a5.
|
||||
# - New intrinsics: _load_byte, _load_word, _store_byte, _store_word.
|
||||
const
|
||||
symbol_builtin_name_int := "Int";
|
||||
symbol_builtin_name_word := "Word";
|
||||
@@ -1403,7 +1407,13 @@ begin
|
||||
_skip_empty_lines();
|
||||
_compile_var_part();
|
||||
|
||||
_write_z(".section .text\n\0");
|
||||
_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 _load_word, @function\n_load_word:\n\tlw a0, (a0)\nret\n\n\0");
|
||||
_write_z(".type _store_byte, @function\n_store_byte:\n\tsb a0, (a1)\nret\n\n\0");
|
||||
_write_z(".type _store_word, @function\n_store_word:\n\tsw a0, (a1)\nret\n\n\0");
|
||||
|
||||
.compile_module_loop:
|
||||
_skip_empty_lines();
|
||||
|
||||
|
191
boot/stage9.elna
191
boot/stage9.elna
@@ -2,11 +2,12 @@
|
||||
(* v. 2.0. If a copy of the MPL was not distributed with this file, You can *)
|
||||
(* obtain one at https://mozilla.org/MPL/2.0/. *)
|
||||
|
||||
(* Stage 8 compiler. *)
|
||||
(* Stage 9 compiler. *)
|
||||
|
||||
(* - Procedure calls in expressions. *)
|
||||
(* - Comments between (* and *) are supported. These are still single line *)
|
||||
(* comments and they should be on a separate line. *)
|
||||
(* - if-else statements. *)
|
||||
const
|
||||
symbol_builtin_name_int := "Int";
|
||||
symbol_builtin_name_word := "Word";
|
||||
@@ -45,6 +46,7 @@ var
|
||||
|
||||
compiler_strings_position: Pointer := @compiler_strings;
|
||||
compiler_strings_length: Word := 0;
|
||||
label_counter: Word := 0;
|
||||
source_code_position: Pointer := @source_code;
|
||||
|
||||
(* Calculates and returns the string token length between quotes, including the *)
|
||||
@@ -93,16 +95,12 @@ begin
|
||||
|
||||
beq t1, t2, .add_string_end
|
||||
|
||||
la t2, compiler_strings_position
|
||||
lw t3, (t2)
|
||||
sb t1, (t3)
|
||||
|
||||
addi t3, t3, 1
|
||||
sw t3, (t2)
|
||||
|
||||
addi t0, t0, 1
|
||||
sw t0, 0(sp)
|
||||
v8 := _load_byte(v0);
|
||||
_store_byte(v8, compiler_strings_position);
|
||||
_store_word(compiler_strings_position + 1, @compiler_strings_position);
|
||||
v0 := v0 + 1;
|
||||
|
||||
lb t1, 8(sp)
|
||||
li t2, '\\'
|
||||
bne t1, t2, .add_string_increment
|
||||
|
||||
@@ -127,13 +125,7 @@ end;
|
||||
(* Returns the amount of bytes written in a0. *)
|
||||
proc _read_file();
|
||||
begin
|
||||
mv a2, a1
|
||||
mv a1, a0
|
||||
(* STDIN. *)
|
||||
li a0, 0
|
||||
(* SYS_READ. *)
|
||||
li a7, 63
|
||||
ecall
|
||||
_syscall(0, v88, v84, 0, 0, 0, 63);
|
||||
end;
|
||||
|
||||
(* Writes to the standard output. *)
|
||||
@@ -143,13 +135,7 @@ end;
|
||||
(* a1 - Buffer length. *)
|
||||
proc _write_s();
|
||||
begin
|
||||
mv a2, a1
|
||||
mv a1, a0
|
||||
(* STDOUT. *)
|
||||
li a0, 1
|
||||
(* SYS_WRITE. *)
|
||||
li a7, 64
|
||||
ecall
|
||||
_syscall(1, v88, v84, 0, 0, 0, 64);
|
||||
end;
|
||||
|
||||
(* Writes a number to a string buffer. *)
|
||||
@@ -317,9 +303,8 @@ begin
|
||||
li t1, '.'
|
||||
beq t0, t1, .read_token_next
|
||||
|
||||
lw a0, 0(sp)
|
||||
lb a0, (a0)
|
||||
_is_alnum();
|
||||
v8 := _load_byte(v0);
|
||||
_is_alnum(v8);
|
||||
bnez a0, .read_token_next
|
||||
|
||||
goto .read_token_end;
|
||||
@@ -464,10 +449,8 @@ begin
|
||||
_advance_token(1);
|
||||
|
||||
.compile_character_literal_end:
|
||||
la t0, source_code_position
|
||||
lw t0, (t0)
|
||||
lb a0, (t0)
|
||||
_write_c();
|
||||
v0 := _load_byte(source_code_position);
|
||||
_write_c(v0);
|
||||
|
||||
_write_c('\'');
|
||||
_write_c('\n');
|
||||
@@ -523,10 +506,8 @@ end;
|
||||
|
||||
proc _compile_term();
|
||||
begin
|
||||
la t0, source_code_position
|
||||
lw t0, (t0)
|
||||
lb a0, (t0)
|
||||
sw a0, 0(sp)
|
||||
v0 := _load_byte(source_code_position);
|
||||
lb a0, 0(sp)
|
||||
|
||||
li t1, '\''
|
||||
beq a0, t1, .compile_term_character_literal
|
||||
@@ -925,13 +906,72 @@ begin
|
||||
_write_z("mv a0, t0\n\0");
|
||||
end;
|
||||
|
||||
(* Writes a label, .Ln, where n is a unique number. *)
|
||||
|
||||
(* Parameters: *)
|
||||
(* a0 - Label counter. *)
|
||||
proc _write_label();
|
||||
begin
|
||||
_write_z(".L\0");
|
||||
_write_i(v88);
|
||||
end;
|
||||
|
||||
proc _compile_if();
|
||||
begin
|
||||
(* Skip "if ". *)
|
||||
_advance_token(3);
|
||||
(* Compile condition. *)
|
||||
_compile_expression();
|
||||
(* Skip " then" with newline. *)
|
||||
_advance_token(6);
|
||||
|
||||
(* v0 is the label after the if statement. *)
|
||||
v0 := label_counter;
|
||||
_store_word(label_counter + 1, @label_counter);
|
||||
(* v4 is the label in front of the next elsif condition or end. *)
|
||||
v4 := label_counter;
|
||||
_store_word(label_counter + 1, @label_counter);
|
||||
|
||||
_write_z("\tbeqz t0, \0");
|
||||
_write_label(v4);
|
||||
_write_c('\n');
|
||||
|
||||
_compile_procedure_body();
|
||||
|
||||
_write_z("\tj \0");
|
||||
_write_label(v0);
|
||||
_write_c('\n');
|
||||
|
||||
_write_label(v4);
|
||||
_write_z(":\n\0");
|
||||
|
||||
_memcmp(source_code_position, "end", 3);
|
||||
beqz a0, .compile_if_end
|
||||
|
||||
_memcmp(source_code_position, "else", 3);
|
||||
beqz a0, .compile_if_else
|
||||
|
||||
.compile_if_else:
|
||||
(* Skip "else" and newline. *)
|
||||
_advance_token(5);
|
||||
_compile_procedure_body();
|
||||
|
||||
.compile_if_end:
|
||||
(* Skip "end". *)
|
||||
_advance_token(3);
|
||||
|
||||
_write_label(v0);
|
||||
_write_z(":\n\0");
|
||||
end;
|
||||
|
||||
proc _compile_statement();
|
||||
begin
|
||||
_skip_spaces();
|
||||
(* This is a call if the statement starts with an underscore. *)
|
||||
la t0, source_code_position
|
||||
lw t0, (t0)
|
||||
(* First character after alignment tab. *)
|
||||
addi t0, t0, 1
|
||||
(* addi t0, t0, 1 *)
|
||||
lb t0, (t0)
|
||||
|
||||
li t1, '_'
|
||||
@@ -943,33 +983,42 @@ begin
|
||||
li t1, 'v'
|
||||
beq t0, t1, .compile_statement_assignment
|
||||
|
||||
li t1, 'i'
|
||||
beq t0, t1, .compile_statement_if
|
||||
|
||||
(* keyword_ret contains "\tret", so it's 4 bytes long. *)
|
||||
_memcmp(source_code_position, "\treturn", 7);
|
||||
_memcmp(source_code_position, "return", 6);
|
||||
beqz a0, .compile_statement_return
|
||||
|
||||
_compile_line();
|
||||
goto .compile_statement_end;
|
||||
|
||||
.compile_statement_call:
|
||||
_advance_token(1);
|
||||
(* _advance_token(1); *)
|
||||
_compile_call();
|
||||
|
||||
goto .compile_statement_semicolon;
|
||||
|
||||
.compile_statement_goto:
|
||||
_advance_token(1);
|
||||
(* _advance_token(1); *)
|
||||
_compile_goto();
|
||||
|
||||
goto .compile_statement_semicolon;
|
||||
|
||||
.compile_statement_assignment:
|
||||
_advance_token(1);
|
||||
(* _advance_token(1); *)
|
||||
_compile_assignment();
|
||||
|
||||
goto .compile_statement_semicolon;
|
||||
|
||||
.compile_statement_if:
|
||||
(* _advance_token(1); *)
|
||||
_compile_if();
|
||||
|
||||
goto .compile_statement_semicolon;
|
||||
|
||||
.compile_statement_return:
|
||||
_advance_token(1);
|
||||
(* _advance_token(1); *)
|
||||
_compile_return_statement();
|
||||
_write_c('\n');
|
||||
|
||||
@@ -986,10 +1035,12 @@ proc _compile_procedure_body();
|
||||
begin
|
||||
.compile_procedure_body_loop:
|
||||
_skip_empty_lines();
|
||||
_skip_spaces();
|
||||
|
||||
(* 3 is "end" length. *)
|
||||
_memcmp(source_code_position, "end", 3);
|
||||
beqz a0, .compile_procedure_body_epilogue
|
||||
|
||||
_memcmp(source_code_position, "else", 4);
|
||||
beqz a0, .compile_procedure_body_epilogue
|
||||
|
||||
_compile_statement();
|
||||
@@ -1065,24 +1116,24 @@ begin
|
||||
_advance_token(5);
|
||||
end;
|
||||
|
||||
proc _skip_newlines();
|
||||
proc _skip_spaces();
|
||||
begin
|
||||
(* Skip newlines. *)
|
||||
la t0, source_code_position
|
||||
lw t1, (t0)
|
||||
|
||||
.skip_newlines_loop:
|
||||
.skip_spaces_loop:
|
||||
lb t2, (t1)
|
||||
li t3, '\n'
|
||||
bne t2, t3, .skip_newlines_end
|
||||
beqz t2, .skip_newlines_end
|
||||
li t3, '\t'
|
||||
bne t2, t3, .skip_spaces_end
|
||||
beqz t2, .skip_spaces_end
|
||||
|
||||
addi t1, t1, 1
|
||||
sw t1, (t0)
|
||||
|
||||
goto .skip_newlines_loop;
|
||||
goto .skip_spaces_loop;
|
||||
|
||||
.skip_newlines_end:
|
||||
.skip_spaces_end:
|
||||
end;
|
||||
|
||||
(* Prints and skips a line. *)
|
||||
@@ -1121,9 +1172,6 @@ begin
|
||||
lw t2, 0(sp)
|
||||
lb t0, (t2)
|
||||
|
||||
li t1, '#'
|
||||
beq t0, t1, .skip_empty_lines_comment
|
||||
|
||||
li t1, '\n'
|
||||
beq t0, t1, .skip_empty_lines_newline
|
||||
|
||||
@@ -1175,10 +1223,8 @@ begin
|
||||
li t1, '@'
|
||||
beq t0, t1, .compile_global_initializer_pointer
|
||||
|
||||
la a0, source_code_position
|
||||
lw a0, (a0)
|
||||
lb a0, (a0)
|
||||
_is_digit();
|
||||
v0 := _load_byte(source_code_position);
|
||||
_is_digit(v0);
|
||||
bnez a0, .compile_global_initializer_number
|
||||
|
||||
unimp
|
||||
@@ -1373,7 +1419,13 @@ begin
|
||||
_skip_empty_lines();
|
||||
_compile_var_part();
|
||||
|
||||
_write_z(".section .text\n\0");
|
||||
_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 _load_word, @function\n_load_word:\n\tlw a0, (a0)\nret\n\n\0");
|
||||
_write_z(".type _store_byte, @function\n_store_byte:\n\tsb a0, (a1)\nret\n\n\0");
|
||||
_write_z(".type _store_word, @function\n_store_word:\n\tsw a0, (a1)\nret\n\n\0");
|
||||
|
||||
.compile_module_loop:
|
||||
_skip_empty_lines();
|
||||
|
||||
@@ -1413,10 +1465,9 @@ begin
|
||||
lw t1, 4(sp)
|
||||
bge t0, t1, .compile_end
|
||||
|
||||
lb a0, (t0)
|
||||
addi t0, t0, 1
|
||||
sw t0, 0(sp)
|
||||
_write_c();
|
||||
v8 := _load_byte(v0);
|
||||
v0 := v0 + 1;
|
||||
_write_c(v8);
|
||||
|
||||
j .compile_loop
|
||||
|
||||
@@ -1431,8 +1482,7 @@ end;
|
||||
(* a0 - Status code. *)
|
||||
proc _exit();
|
||||
begin
|
||||
li a7, 93 # SYS_EXIT
|
||||
ecall
|
||||
_syscall(0, 0, 0, 0, 0, 0, 93);
|
||||
end;
|
||||
|
||||
(* Inserts a symbol into the table. *)
|
||||
@@ -1554,7 +1604,7 @@ begin
|
||||
sw t1, (t0)
|
||||
end;
|
||||
|
||||
proc _initialize_classification();
|
||||
proc _create_classification();
|
||||
begin
|
||||
_assign_at(@classification, 1, 15);
|
||||
_assign_at(@classification, 2, 1);
|
||||
@@ -1688,13 +1738,13 @@ begin
|
||||
v0 := 129;
|
||||
|
||||
(* Set the remaining 129 - 256 bytes to transitionClassOther. *)
|
||||
.initialize_classification_loop:
|
||||
.create_classification_loop:
|
||||
_assign_at(@classification, v0, 22);
|
||||
v0 := v0 + 1;
|
||||
|
||||
lw t0, 0(sp)
|
||||
li t1, 257
|
||||
blt t0, t1, .initialize_classification_loop
|
||||
blt t0, t1, .create_classification_loop
|
||||
end;
|
||||
|
||||
(* Parameters: *)
|
||||
@@ -1772,7 +1822,7 @@ end;
|
||||
(* - The next byte is the action that should be performed when transitioning. *)
|
||||
(* For the meaning of actions see labels in the lex_next function, which *)
|
||||
(* handles each action. *)
|
||||
proc _initialize_transitions();
|
||||
proc _create_transitions();
|
||||
begin
|
||||
(* Start state. *)
|
||||
_set_transition(1, 1, 1, 16);
|
||||
@@ -1896,8 +1946,7 @@ end;
|
||||
(* Gets pointer to the current source text. *)
|
||||
proc _lexer_get_current();
|
||||
begin
|
||||
_lexer_get_state();
|
||||
sw a0, 0(sp)
|
||||
v0 := _lexer_get_state();
|
||||
|
||||
return v0 + 4
|
||||
end;
|
||||
@@ -1925,8 +1974,8 @@ end;
|
||||
(* One time lexer initialization. *)
|
||||
proc _lexer_initialize();
|
||||
begin
|
||||
_initialize_classification();
|
||||
_initialize_transitions();
|
||||
_create_classification();
|
||||
_create_transitions();
|
||||
end;
|
||||
|
||||
(* Entry point. *)
|
||||
|
Reference in New Issue
Block a user