elna/boot/stage2.elna

1543 lines
30 KiB
Plaintext

(*
s1 - Contains the current position in the source text.
- The compiler expects valid input, otherwise it will generate invalid
assembly or hang. There is no error checking, no semantic analysis, no
type checking.
- Imports with only a module name without package, e.g.
"import dummy", can be parsed, but are ignored.
- No loops. Only labels and goto.
- Only unsigned number literals are supported (in decimal or
hexadecimal format).
- Comments are accepted only at the end of a line.
- Return can be used only as the last statement of a procedure. It
doesn't actually return, but sets a0 to the appropriate value.
*)
program
import dummy
const
SOURCE_BUFFER_SIZE := 81920
var
source_code: [81920]Byte
(* Ignores the import. *)
proc _compile_import()
var loca0: Word
begin
_advance(6)
_skip_spaces()
loca0 := _read_token()
_advance(loca0) (* Skip the imported module name. *)
end
proc _build_binary_expression()
var loca0, loca4, loca8, loca20: Word
begin
_build_expression(0)
loca4 := 0x2c306120 (* _a0, *)
loca8 := 0x0a316120 (* _a1\n *)
_skip_spaces()
loca20 := _read_token()
li t0, 0x26 # &
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_and
li t0, 0x726f # or
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_or
li t0, 0x3d # =
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_equal
li t0, 0x2b # +
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_plus
li t0, 0x2d # -
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_minus
li t0, 0x2a # *
sw t0, 16(sp)
mv a0, s1
lw a1, 20(sp)
addi a2, sp, 16
call _token_compare
beqz a0, .L_build_binary_expression_product
goto .Lbuild_binary_expression_end
.L_build_binary_expression_equal
_advance(1) (* Skip =. *)
_build_expression(1)
_write_out(@loca0, 3)
_write_out(@loca4, 4)
_write_out(@loca4, 4)
_write_out(@loca8, 4)
loca0 := 0x7a716573 (* seqz *)
_write_out(@loca0, 4)
_write_out(@loca4, 4)
_write_out(@loca4, 4)
goto .Lbuild_binary_expression_end
.L_build_binary_expression_and
_advance(1) (* Skip &. *)
_build_expression(1)
loca0 := 0x646e61 (* and *)
_write_out(@loca0, 3)
_write_out(@loca4, 4)
_write_out(@loca4, 4)
_write_out(@loca8, 4)
goto .Lbuild_binary_expression_end
.L_build_binary_expression_or
_advance(2) (* Skip or. *)
_build_expression(1)
loca0 := 0x726f (* or *)
_write_out(@loca0, 2)
_write_out(@loca4, 4)
_write_out(@loca4, 4)
_write_out(@loca8, 4)
goto .Lbuild_binary_expression_end
.L_build_binary_expression_plus
_advance(1) (* Skip +. *)
_build_expression(1)
loca0 := 0x646461 (* add *)
_write_out(@loca0, 3)
_write_out(@loca4, 4)
_write_out(@loca4, 4)
_write_out(@loca8, 4)
goto .Lbuild_binary_expression_end
.L_build_binary_expression_minus
_advance(1) (* Skip -. *)
_build_expression(1)
loca0 := 0x627573 (* sub *)
_write_out(@loca0, 3)
_write_out(@loca4, 4)
_write_out(@loca4, 4)
_write_out(@loca8, 4)
goto .Lbuild_binary_expression_end
.L_build_binary_expression_product
_advance(1) (* Skip *. *)
_build_expression(1)
loca0 := 0x6c756d (* mul *)
_write_out(@loca0, 3)
_write_out(@loca4, 4)
_write_out(@loca4, 4)
_write_out(@loca8, 4)
goto .Lbuild_binary_expression_end
.Lbuild_binary_expression_end
end
(*
Evalutes an expression and saves the result in a0.
a0 - X in aX, the register number to save the result.
*)
proc _build_expression()
var
loca0, loca20, loca28, loca8: Word
loca24, loca4: ^Byte
begin
(* Make the register number to a character and save it. *)
loca28 := loca84 + 0x30 (* 0 *)
_skip_spaces()
loca20 := _read_token()
loca24 := _current()
lbu a0, (s1)
li t0, '-'
beq a0, t0, .Lbuild_expression_negate
lbu a0, (s1)
li t0, '@'
beq a0, t0, .Lbuild_expression_address
loca0 := _front()
if _is_digit(loca0) then
goto .Lbuild_expression_literal
end
lbu a0, (s1)
li t0, '_'
beq a0, t0, .Lbuild_expression_call
li t0, 0x61636f6c # loca
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 4
call _memcmp
beqz a0, .Lbuild_expression_identifier
(* Named identifier. *)
loca8 := 0x6120616c (* la a *)
_write_out(@loca8, 4)
loca8 := 0x00202c00 or loca28
_write_out(@loca8, 3)
_write_out(loca24, loca20)
_put_char(0x0a)
goto .Lbuild_expression_advance
.Lbuild_expression_negate
_advance(1) (* Skip the -. *)
_build_expression(0)
loca8 := 0x2067656e (* neg_ *)
_write_out(@loca8, 4)
loca8 := 0x202c3061 (* a0,_ *)
_write_out(@loca8, 4)
loca8 := 0x0a3061 (* a0,_ *)
_write_out(@loca8, 3)
goto .Lbuild_expression_advance
.Lbuild_expression_address
loca8 := 0x69646461 (* addi *)
_write_out(@loca8, 4)
loca8 := 0x6120 (* _a *)
_write_out(@loca8, 2)
_put_char(loca28)
loca8 := 0x7073202c (* , sp *)
_write_out(@loca8, 4)
loca8 := 0x202c (* ,_ *)
_write_out(@loca8, 2)
_advance(1) (* Skip @. *)
_skip_spaces()
loca24 := _current()
loca20 := _read_token()
(* Skip the "loca" variable prefix. *)
loca4 := loca24 + 4
loca0 := loca20 - 4
_write_out(loca4, loca0)
_put_char(0xa)
goto .Lbuild_expression_advance
.Lbuild_expression_identifier
loca8 := 0x6120776c (* lw a *)
_write_out(@loca8, 4)
loca8 := 0x00202c00 or loca28 # \0,_
_write_out(@loca8, 3)
loca4 := loca24 + 4
loca0 := loca20 - 4
_write_out(loca4, loca0) (* Skip the "loca" variable prefix. *)
loca8 := 0x29707328 (* (sp) *)
_write_out(@loca8, 4)
_put_char(0x0a) (* \n *)
goto .Lbuild_expression_advance
.Lbuild_expression_call
_advance(loca20)
_advance(1)
_compile_call(loca24, loca20)
goto .Lbuild_expression_end
.Lbuild_expression_literal
loca8 := 0x6120696c (* li a *)
_write_out(@loca8, 4)
loca8 := 0x00202c00 or loca28 (* \0,_ *)
_write_out(@loca8, 3)
_write_out(loca24, loca20)
_put_char(0x0a) (* \n *)
goto .Lbuild_expression_advance
.Lbuild_expression_advance
_advance(loca20)
.Lbuild_expression_end
end
(*
Compiles a statement beginning with an identifier.
Left values should be variables named "loca n", where n is the offset
of the variable on the stack, like loca8 or loca4.
*)
proc _compile_identifier()
var
loca0, loca16, loca8: Word
loca20, loca12: ^Byte
begin
(* Save the pointer to the identifier and its length on the stack. *)
loca20 := _current()
loca16 := _read_token()
_advance(loca16)
_skip_spaces()
(* Save the pointer and the length of the token following the identifier. *)
loca12 := _current()
loca8 := _read_token()
_advance(loca8) # Skip that token.
_skip_spaces()
li t0, 0x3d3a # :=
sw t0, 4(sp)
lw a0, 12(sp)
lw a1, 8(sp)
addi a2, sp, 4
call _token_compare
beqz a0, .Lcompile_identifier_assign
lw t0, 12(sp)
lbu t0, (t0)
li t1, 0x28 # (
beq t0, t1, .Lcompile_identifier_call
goto .Lcompile_identifier_end
.Lcompile_identifier_call
_compile_call(loca20, loca16)
goto .Lcompile_identifier_end
.Lcompile_identifier_assign
_build_binary_expression()
loca0 := 0x61207773 (* sw a *)
_write_out(@loca0, 4)
loca0 := 0x202c30 (* 0,_ *)
_write_out(@loca0, 3)
loca20 := loca20 + 4
loca16 := loca16 - 4
_write_out(loca20, loca16)
loca0 := 0x29707328 (* (sp) *)
_write_out(@loca0, 4)
_put_char(0x0a) (* \n *)
goto .Lcompile_identifier_end
.Lcompile_identifier_end
end
(*
Compiles a procedure call. Expects s1 to point to the first argument.
a0 - Pointer to the procedure name.
a1 - Length of the procedure name.
Returns the procedure result in a0.
*)
proc _compile_call(loca84: ^Byte, loca80: Word)
var
loca0, loca4, loca12: Word
begin
loca12 := 0 (* Argument count for a procedure call. *)
.Lcompile_call_paren
_skip_spaces()
lbu t0, (s1)
li t1, 0x29 # )
beq t0, t1, .Lcompile_call_complete
.Lcompile_call_argument
_build_expression(0)
loca0 := 0x61207773 (* sw a *)
_write_out(@loca0, 4)
loca0 := 0x202c30 (* 0,_ *)
_write_out(@loca0, 3)
(*
Only 6 arguments are supported with a0-a5.
Save all arguments on the stack so they aren't overriden afterwards.
*)
loca0 := -4 * loca12
loca0 := loca0 + 60
_printi(loca0)
loca0 := 0x29707328 (* (sp) *)
_write_out(@loca0, 4)
_put_char(0x0a) (* \n *)
_skip_spaces()
lbu t0, (s1)
li t1, ','
bne t0, t1, .Lcompile_call_paren
loca12 := loca12 + 1 (* Argument count for a procedure call. *)
_advance(1) (* Skip the comma between the arguments. *)
goto .Lcompile_call_argument
.Lcompile_call_complete
loca12 := 0
.Lcompile_call_restore
(*
Just go through all a0-a5 registers and read them from stack.
If this stack value contains garbage, the procedure just shouldn't use it.
*)
loca0 := 0x6120776c (* lw a *)
(* lw a0, 60(sp) *)
_write_out(@loca0, 4)
loca4 := 0x36202c30 (* 0, 6 *)
_write_out(@loca4, 4)
loca4 := 0x70732830 (* 0(sp *)
_write_out(@loca4, 4)
loca4 := 0x0a29 (* )\n *)
_write_out(@loca4, 2)
(* lw a1, 56(sp) *)
_write_out(@loca0, 4)
loca4 := 0x35202c31 (* 1, 5 *)
_write_out(@loca4, 4)
loca4 := 0x70732836 (* 6(sp *)
_write_out(@loca4, 4)
loca4 := 0x0a29 (* )\n *)
_write_out(@loca4, 2)
(* lw a2, 52(sp) *)
_write_out(@loca0, 4)
loca4 := 0x35202c32 (* 2, 5 *)
_write_out(@loca4, 4)
loca4 := 0x70732832 (* 2(sp *)
_write_out(@loca4, 4)
loca4 := 0x0a29 (* )\n *)
_write_out(@loca4, 2)
(* lw a3, 48(sp) *)
_write_out(@loca0, 4)
loca4 := 0x34202c33 (* 3, 4 *)
_write_out(@loca4, 4)
loca4 := 0x70732838 (* 8(sp *)
_write_out(@loca4, 4)
loca4 := 0x0a29 (* )\n *)
_write_out(@loca4, 2)
(* lw a4, 44(sp) *)
_write_out(@loca0, 4)
loca4 := 0x34202c34 (* 4, 4 *)
_write_out(@loca4, 4)
loca4 := 0x70732834 (* 4(sp *)
_write_out(@loca4, 4)
loca4 := 0x0a29 (* )\n *)
_write_out(@loca4, 2)
(* lw a5, 40(sp) *)
_write_out(@loca0, 4)
loca4 := 0x34202c35 (* 5, 4 *)
_write_out(@loca4, 4)
loca4 := 0x70732830 (* 0(sp *)
_write_out(@loca4, 4)
loca4 := 0x0a29 (* )\n *)
_write_out(@loca4, 2)
loca0 := 0x6c6c6163 (* call *)
_write_out(@loca0, 4)
_put_char(0x20) (* _ *)
_write_out(loca84, loca80)
_put_char(0x0a) (* \n *)
_skip_spaces()
_advance(1) (* Skip the close paren. *)
end
(*
Reads a token and returns its length in a0.
_read_token doesn't change s1, it finds the length of the token s1 is pointing to.
*)
proc _read_token()
var loca4: Word
begin
lbu t0, (s1) # t0 = Current character.
loca4 := 0
li t1, '.'
beq t0, t1, .Ltoken_character_single
li t1, ','
beq t0, t1, .Ltoken_character_single
li t1, ':'
beq t0, t1, .Ltoken_character_colon
li t1, ';'
beq t0, t1, .Ltoken_character_single
li t1, '('
beq t0, t1, .Ltoken_character_single
li t1, ')'
beq t0, t1, .Ltoken_character_single
li t1, '['
beq t0, t1, .Ltoken_character_single
li t1, ']'
beq t0, t1, .Ltoken_character_single
li t1, '^'
beq t0, t1, .Ltoken_character_single
li t1, '&'
beq t0, t1, .Ltoken_character_single
li t1, '='
beq t0, t1, .Ltoken_character_single
li t1, '+'
beq t0, t1, .Ltoken_character_single
li t1, '-'
beq t0, t1, .Ltoken_character_single
li t1, '*'
beq t0, t1, .Ltoken_character_single
li t1, '@'
beq t0, t1, .Ltoken_character_single
(* Expect an identifier or a number. *)
.Ltoken_character_loop_do
lw t6, 4(sp)
add t1, s1, t6
lbu a0, (t1) # a0 = Current character.
call _is_alnum
beqz a0, .Ltoken_character_end
loca4 := loca4 + 1
goto .Ltoken_character_loop_do
.Ltoken_character_single
loca4 := loca4 + 1
goto .Ltoken_character_end
.Ltoken_character_colon
lbu t0, 1(s1) # t0 = The character after the colon.
loca4 := loca4 + 1
li t1, '='
beq t0, t1, .Ltoken_character_single
goto .Ltoken_character_end
.Ltoken_character_end
lw a0, 4(sp)
end
(* Skips the spaces till the next non space character. *)
proc _skip_spaces()
begin
.Lspace_loop_do
lbu t0, (s1) # t0 = Current character.
li t1, ' '
beq t0, t1, .Lspace_loop_repeat
li t1, '\t'
beq t0, t1, .Lspace_loop_repeat
li t1, '\n'
beq t0, t1, .Lspace_loop_repeat
li t1, '\r'
beq t0, t1, .Lspace_loop_repeat
goto .Lspace_loop_end
.Lspace_loop_repeat
_advance(1)
goto .Lspace_loop_do
.Lspace_loop_end
end
(* Skips tabs at the line beginning. *)
proc _skip_indentation()
begin
.Lskip_indentation_do
lbu t0, (s1)
li t1, '\t'
beq t0, t1, .Lskip_indentation_skip
goto .Lskip_indentation_end
.Lskip_indentation_skip
_advance(1)
goto .Lskip_indentation_do
.Lskip_indentation_end
end
(*
Parameters:
a0 - Line length.
*)
proc _skip_comment(loca84: Word)
begin
(* Check whether this is a comment. *)
li t0, 0x2a28 # (*
sw t0, 4(sp)
addi a0, sp, 4
mv a1, s1
li a2, 2
call _memcmp
bnez a0, .Lskip_comment_end
_advance(2) (* Skip (*. *)
li t0, 0x292a # *)
sw t0, 4(sp)
.Lskip_comment_loop
addi a0, sp, 4
mv a1, s1
li a2, 2
call _memcmp
beqz a0, .Lskip_comment_close
_advance(1)
goto .Lskip_comment_loop
.Lskip_comment_close
_advance(2) (* Skip "*" and ")". *)
.Lskip_comment_end
end
(*
Parameters:
a0 - Line length.
*)
proc _compile_assembly(loca84: Word)
var loca0: ^Byte
begin
(* Write the source to the standard output. *)
loca0 := _current()
_write_out(loca0, loca84)
_advance(loca84)
_put_char(0xa) (* \n *)
_advance(1) (* Skip the new line. *)
end
proc _compile_program()
var loca0: Word
begin
(* .global _start *)
loca0 := 0x6f6c672e (* .glo *)
_write_out(@loca0, 4)
loca0 := 0x206c6162 (* bal_ *)
_write_out(@loca0, 4)
loca0 := 0x6174735f (* _sta *)
_write_out(@loca0, 4)
loca0 := 0x0a7472 (* rt\n *)
_write_out(@loca0, 3)
_advance(8) (* program\n. *)
end
proc _compile_constant_section()
var loca0: Word
begin
(* .section .rodata *)
loca0 := 0x6365732e (* .sec *)
_write_out(@loca0, 4)
loca0 := 0x6e6f6974 (* tion *)
_write_out(@loca0, 4)
loca0 := 0x6f722e20 (* _.ro *)
_write_out(@loca0, 4)
loca0 := 0x61746164 (* data *)
_write_out(@loca0, 4)
loca0 := 0x0a (* \n *)
_write_out(@loca0, 1)
_advance(6) (* const\n. *)
.Lcompile_constant_section_item
_skip_spaces()
lbu a0, (s1)
call _is_upper
beqz a0, .Lcompile_constant_section_end
_compile_constant()
goto .Lcompile_constant_section_item
.Lcompile_constant_section_end
end
proc _compile_constant()
var
loca0, loca4: Word
loca8: ^Byte
begin
loca4 := _read_token()
loca8 := _current() (* Save the identifier pointer before advancing it. *)
_write_out(loca8, loca4)
_advance(loca4)
_skip_spaces()
_advance(2) (* Skip the assignment sign. *)
(* : .long *)
loca0 := 0x6c2e203a (* : .l *)
_write_out(@loca0, 4)
loca0 := 0x20676e6f (* ong_ *)
_write_out(@loca0, 4)
_skip_spaces()
loca4 := _read_token()
loca8 := _current() (* Save the literal pointer before advancing it. *)
_write_out(loca8, loca4)
_advance(loca4)
_put_char(0x0a) (* \n *)
end
proc _compile_variable_section()
var loca0: Word
begin
(* .section .bss *)
loca0 := 0x6365732e (* .sec *)
_write_out(@loca0, 4)
loca0 := 0x6e6f6974 (* tion *)
_write_out(@loca0, 4)
loca0 := 0x73622e20 (* _.bs *)
_write_out(@loca0, 4)
loca0 := 0x0a73 (* s\n *)
_write_out(@loca0, 2)
_advance(4) (* var\n. *)
.Lcompile_variable_section_item
_skip_spaces()
lbu a0, (s1)
call _is_lower
beqz a0, .Lcompile_variable_section_end
_compile_variable()
goto .Lcompile_variable_section_item
.Lcompile_variable_section_end
end
proc _compile_variable()
var
loca28, loca16: ^Byte
loca0, loca24, loca20: Word
begin
(* Save the identifier on the stack since it should emitted multiple times. *)
loca24 := _read_token()
loca28 := _current()
_advance(loca24)
_skip_spaces()
_advance(1) (* Skip the colon in front of the type. *)
_skip_spaces()
_advance(1) (* Skip the opening bracket. *)
(* Save the array size on the stack since it has to be emitted multiple times. *)
loca16 := _read_token()
loca20 := _current()
_advance(loca16)
_skip_spaces()
_advance(1) (* Skip the closing bracket. *)
_skip_spaces()
loca0 := _read_token()
_advance(loca0) (* Skip the type. *)
(* .type identifier, @object *)
loca0 := 0x7079742e (* .typ *)
_write_out(@loca0, 4)
loca0 := 0x2065 (* e_ *)
_write_out(@loca0, 2)
_write_out(loca28, loca24)
loca0 := 0x6f40202c (* , @o *)
_write_out(@loca0, 4)
loca0 := 0x63656a62 (* bjec *)
_write_out(@loca0, 4)
loca0 := 0x0a74 (* t\n *)
_write_out(@loca0, 2)
(* .size identifier, size *)
loca0 := 0x7a69732e (* .siz *)
_write_out(@loca0, 4)
loca0 := 0x2065 (* e_ *)
_write_out(@loca0, 2)
_write_out(loca28, loca24)
loca0 := 0x202c (* ,_ *)
_write_out(@loca0, 2)
_write_out(loca20, loca16)
_put_char(0x0a) (* \n *)
(* identifier: .zero size *)
_write_out(loca28, loca24)
loca0 := 0x7a2e203a (* : .z *)
_write_out(@loca0, 4)
loca0 := 0x206f7265 (* ero_ *)
_write_out(@loca0, 4)
_write_out(loca20, loca16)
_put_char(0x0a) (* \n *)
end
proc _compile_procedure()
var
loca0, loca4, loca8, loca12, loca16: Word
loca20: ^Char
begin
_advance(5) (* Skip proc_ *)
loca16 := _read_token()
loca20 := _current()
_advance(loca16)
(* .type identifier, @function *)
loca0 := 0x7079742e (* .typ *)
_write_out(@loca0, 4)
loca0 := 0x2065 (* e_ *)
_write_out(@loca0, 2)
_write_out(loca20, loca16)
loca0 := 0x6640202c (* , @f *)
_write_out(@loca0, 4)
loca0 := 0x74636e75 (* unct *)
_write_out(@loca0, 4)
loca0 := 0x0a6e6f69 (* ion\n *)
_write_out(@loca0, 4)
_write_out(loca20, loca16)
loca0 := 0x0a3a (* :\n *)
_write_out(@loca0, 2)
_skip_spaces()
_advance(1) (* Skip opening argument paren. *)
_skip_spaces()
_advance(1) (* Skip closing argument paren. *)
loca12 := 0x6e (* n *)
loca8 := 0x69676562 (* begi *)
(*
Skip all declarations until we find the "begin" keyword, denoting the
beginning of the procedure body.
*)
.Lcompile_procedure_begin
_skip_spaces()
call _read_token
mv a1, a0
mv a0, s1
addi a2, sp, 8
add s1, s1, a1
call _token_compare
bnez a0, .Lcompile_procedure_begin
(* Generate the procedure prologue with a predefined stack size. *)
loca0 := 0x69646461 (* addi *)
_write_out(@loca0, 4)
loca0 := 0x2c707320 (* _sp, *)
_write_out(@loca0, 4)
_write_out(@loca0, 4)
loca0 := 0x0a36392d (* -96\n *)
_write_out(@loca0, 4)
loca0 := 0x72207773 (* sw r *)
_write_out(@loca0, 4)
loca0 := 0x39202c61 (* a, 9 *)
_write_out(@loca0, 4)
loca0 := 0x70732832 (* 2(sp *)
_write_out(@loca0, 4)
loca0 := 0x0a29 (* )\n *)
_write_out(@loca0, 2)
loca0 := 0x73207773 (* sw s *)
_write_out(@loca0, 4)
loca0 := 0x38202c30 (* 0, 8 *)
_write_out(@loca0, 4)
loca0 := 0x70732838 (* 8(sp *)
_write_out(@loca0, 4)
loca0 := 0x0a29 (* )\n *)
_write_out(@loca0, 2)
loca0 := 0x69646461 (* addi *)
_write_out(@loca0, 4)
loca0 := 0x2c307320 (* _s0, *)
_write_out(@loca0, 4)
loca0 := 0x2c707320 (* _sp, *)
_write_out(@loca0, 4)
loca0 := 0x0a363920 (* _96\n *)
_write_out(@loca0, 4)
(* Save passed arguments on the stack. *)
loca0 := 0x61207773 (* sw a *)
_write_out(@loca0, 4)
loca4 := 0x38202c30 (* 0, 8 *)
_write_out(@loca4, 4)
loca8 := 0x70732834 (* 4(sp *)
_write_out(@loca8, 4)
loca12 := 0x0a29 (* )\n *)
_write_out(@loca12, 2)
_write_out(@loca0, 4)
loca4 := 0x38202c31 (* 1, 8 *)
_write_out(@loca4, 4)
loca8 := 0x70732830 (* 0(sp *)
_write_out(@loca8, 4)
_write_out(@loca12, 2)
_write_out(@loca0, 4)
loca4 := 0x37202c32 (* 2, 7 *)
_write_out(@loca4, 4)
loca8 := 0x70732836 (* 6(sp *)
_write_out(@loca8, 4)
_write_out(@loca12, 2)
_write_out(@loca0, 4)
loca4 := 0x37202c33 (* 3, 7 *)
_write_out(@loca4, 4)
loca8 := 0x70732832 (* 2(sp *)
_write_out(@loca8, 4)
_write_out(@loca12, 2)
_write_out(@loca0, 4)
loca4 := 0x36202c34 (* 4, 6 *)
_write_out(@loca4, 4)
loca8 := 0x70732838 (* 8(sp *)
_write_out(@loca8, 4)
_write_out(@loca12, 2)
_write_out(@loca0, 4)
loca4 := 0x36202c35 (* 5, 6 *)
_write_out(@loca4, 4)
loca8 := 0x70732838 (* 4(sp *)
_write_out(@loca8, 4)
_write_out(@loca12, 2)
(* Generate the body of the procedure. *)
.Lcompile_procedure_body
_skip_indentation()
call _read_line
sw a0, 12(sp)
li t0, 0x0a646e65 # end\n
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 4
call _memcmp
beqz a0, .Lcompile_procedure_end
lw a0, 12(sp)
call _compile_line
goto .Lcompile_procedure_body
.Lcompile_procedure_end
_advance(4) (* Skip end\n. *)
(* Generate the procedure epilogue with a predefined stack size. *)
loca0 := 0x7220776c # lw r
_write_out(@loca0, 4)
loca0 := 0x39202c61 # a, 9
_write_out(@loca0, 4)
loca0 := 0x70732832 # 2(sp
_write_out(@loca0, 4)
loca0 := 0x0a29 # )\n
_write_out(@loca0, 2)
loca0 := 0x7320776c (* lw s *)
_write_out(@loca0, 4)
loca0 := 0x38202c30 (* 0, 8 *)
_write_out(@loca0, 4)
loca0 := 0x70732838 (* 8(sp *)
_write_out(@loca0, 4)
loca0 := 0x0a29 (* )\n *)
_write_out(@loca0, 2)
loca0 := 0x69646461 (* addi *)
_write_out(@loca0, 4)
loca0 := 0x2c707320 (* _sp, *)
_write_out(@loca0, 4)
_write_out(@loca0, 4)
loca0 := 0x0a3639 (* 96\n *)
_write_out(@loca0, 4)
loca0 := 0x0a746572 (* ret\n *)
_write_out(@loca0, 4)
end
(*
Compares two string, which of one has a length, the other one is null-terminated.
a0 - The address of the token string.
a1 - The length of the string in a0.
a2 - The address of the null-terminated string.
If the strings match sets a0 to 0, otherwise sets it to 1.
*)
proc _token_compare()
begin
addi t0, a0, 0
addi t1, a1, 0
addi t2, a2, 0
.Ltoken_compare_loop
lbu t3, (t2)
(*
Will only be 0 if the current character in the null terminated string is \0 and the remaining length of the
another string is 0.
*)
or t4, t3, t1
beqz t4, .Ltoken_compare_equal
beqz t1, .Ltoken_compare_not_equal
beqz t3, .Ltoken_compare_not_equal
lbu t4, (t0)
bne t3, t4, .Ltoken_compare_not_equal
addi t0, t0, 1
addi t1, t1, -1
addi t2, t2, 1
goto .Ltoken_compare_loop
.Ltoken_compare_not_equal
li a0, 1
goto .Ltoken_compare_end
.Ltoken_compare_equal
li a0, 0
.Ltoken_compare_end
end
proc _compile_goto()
var
loca0: Word
loca8: ^Byte
begin
_advance(4) (* Skip the goto keyword. *)
loca0 := 0x206a (* j_ *)
_write_out(@loca0, 2)
_skip_spaces()
loca8 := _current() (* We should be on dot the label is beginning with. *)
_advance(1)
loca0 := _read_token()
_advance(loca0)
loca0 := loca0 + 1 (* Label length and the dot. *)
_write_out(loca8, loca0)
_advance(1) (* Skip the new line. *)
_put_char(0x0a) (* \n *)
end
(* a0 - Line length. *)
proc _compile_label(loca84: Word)
var
loca0: Word
begin
(* Write the whole line as is. *)
loca0 := _current()
_write_out(loca0, loca84)
lw t0, 84(sp) # Line length.
mv t1, s1 # Line start.
add t1, t1, t0
addi t1, t1, -1 # Last character on the line.
lbu t1, (t1)
li t2, ':'
beq t1, t2, .Lcompile_label_colon
_put_char(0x3a) (* : *)
.Lcompile_label_colon
_put_char(0x0a) (* \n *)
_advance(loca84)
end
proc _compile_return()
begin
_advance(6) (* Skip return. *)
_skip_spaces()
_build_binary_expression()
end
proc _compile_if()
var
loca8, loca12, loca16, loca20: Word
loca4: ^Byte
begin
_advance(2) (* Skip the if. *)
_skip_spaces()
_build_binary_expression()
_skip_spaces()
_advance(4) (* Skip the then. *)
loca20 := 0x00646e65 (* if end marker and newline. *)
loca16 := 0x66694c2e (* Label prefix ".Lif". *)
loca12 := 0x7a716562 (* beqz *)
_write_out(@loca12, 4)
loca12 := 0x2c306120 (* _a0, *)
_write_out(@loca12, 4)
_put_char(0x20) (* _ *)
(* Write the label *)
_write_out(@loca16, 4)
mv a0, s2
call _printi
_put_char(0x0a) (* \n *)
.Lcompile_if_loop
_skip_spaces()
loca12 := _read_token()
loca4 := _current()
loca8 := _token_compare(loca4, loca12, @loca20)
if loca8 then
loca12 := _read_line()
_compile_line(loca12, 1)
goto .Lcompile_if_loop
end
(* Write the label *)
_write_out(@loca16, 4)
mv a0, s2
call _printi
loca12 := 0x0a3a0a3a (* :\n:\n *)
_write_out(@loca12, 2)
addi s2, s2, 1 # Increment the label counter.
_advance(4) (* Skip the end with newline. *)
end
(*
Parameters:
a0 - Line length.
a1 - Whether the section header was already emitted. If not it should be
emitted before any code is written.
Returns 1 in a0 if the parsed line contained a text section element such a
procedure or the program entry point. Otherwise sets a0 to 0.
*)
proc _compile_line(loca84: Word, loca80: Bool)
begin
beqz a0, .Lcompile_line_empty # Skip an empty line.
lbu t0, (s1)
li t1, '('
beq t0, t1, .Lcompile_line_comment
li t0, 0x0a6d6172 # ram\n
sw t0, 12(sp)
li t0, 0x676f7270 # prog
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 8
call _memcmp
beqz a0, .Lcompile_line_program
li t0, 0x0a74 # t\n
sw t0, 12(sp)
li t0, 0x736e6f63 # cons
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_const
li t0, 0x0a726176 # var\n
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_var
li t0, 0x20 # _
sw t0, 12(sp)
li t0, 0x636f7270 # proc
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 5
call _memcmp
beqz a0, .Lcompile_line_procedure
li t0, 0x0a6e # n\n
sw t0, 12(sp)
li t0, 0x69676562 # begi
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_begin
li t0, 0x2e646e65 # end.
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_exit
li t0, 0x61636f6c # loca
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_identifier
li t0, 0x7472 # rt
sw t0, 12(sp)
li t0, 0x6f706d69 # impo
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_import
li t0, 0x6f746f67 # goto
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 4
call _memcmp
beqz a0, .Lcompile_line_goto
li t0, 0x6e72 # rn
sw t0, 12(sp)
li t0, 0x75746572 # retu
sw t0, 8(sp)
mv a0, s1
addi a1, sp, 8
li a2, 6
call _memcmp
beqz a0, .Lcompile_line_return
li t0, 0x6669 # if
sw t0, 12(sp)
mv a0, s1
addi a1, sp, 12
li a2, 2
call _memcmp
beqz a0, .Lcompile_line_if
lbu t0, (s1)
li t1, '.'
beq t0, t1, .Lcompile_line_label
li t1, '_'
beq t0, t1, .Lcompile_line_identifier
goto .Lcompile_line_unchanged (* Else. *)
.Lcompile_line_if:
_compile_if()
goto .Lcompile_line_section
.Lcompile_line_label
_compile_label(loca84)
goto .Lcompile_line_section
.Lcompile_line_return
(* DEBUG
mv a0, s1
li a1, 8
call _write_error *)
_compile_return()
goto .Lcompile_line_section
.Lcompile_line_goto
_compile_goto()
goto .Lcompile_line_section
.Lcompile_line_import
_compile_import()
goto .Lcompile_line_section
.Lcompile_line_identifier
_compile_identifier()
goto .Lcompile_line_section
.Lcompile_line_exit
_compile_exit()
goto .Lcompile_line_section
.Lcompile_line_begin
lw a1, 80(sp)
bnez a1, .Lcompile_line_compile_entry
_compile_text_section()
.Lcompile_line_compile_entry
_compile_entry_point()
li a0, 1
goto .Lcompile_line_end
.Lcompile_line_const
_compile_constant_section()
goto .Lcompile_line_section
.Lcompile_line_procedure
lw a1, 80(sp)
bnez a1, .Lcompile_line_compile_procedure
_compile_text_section()
.Lcompile_line_compile_procedure
_compile_procedure()
li a0, 1
goto .Lcompile_line_end
.Lcompile_line_var
_compile_variable_section()
goto .Lcompile_line_section
.Lcompile_line_program
_compile_program()
goto .Lcompile_line_section
.Lcompile_line_comment
_skip_comment(loca84)
goto .Lcompile_line_section
.Lcompile_line_empty
_advance(1)
goto .Lcompile_line_section
.Lcompile_line_unchanged
_compile_assembly(loca84)
goto .Lcompile_line_section
.Lcompile_line_section
mv a0, zero
.Lcompile_line_end
sw a0, 12(sp)
_skip_spaces()
_skip_comment()
lw a0, 12(sp)
end
(* Prints ".section .text" and exits. *)
proc _compile_text_section()
var loca0: Word
begin
(* .section .text *)
loca0 := 0x6365732e (* .sec *)
_write_out(@loca0, 4)
loca0 := 0x6e6f6974 (* tion *)
_write_out(@loca0, 4)
loca0 := 0x65742e20 (* _.te *)
_write_out(@loca0, 4)
loca0 := 0x0a7478 (* xt\n *)
_write_out(@loca0, 3)
end
proc _compile_entry_point()
var loca0: Word
begin
(* .type _start, @function *)
loca0 := 0x7079742e (* .typ *)
_write_out(@loca0, 4)
loca0 := 0x735f2065 (* e _s *)
_write_out(@loca0, 4)
loca0 := 0x74726174 (* tart *)
_write_out(@loca0, 4)
loca0 := 0x6640202c (* , @f *)
_write_out(@loca0, 4)
loca0 := 0x74636e75 (* unct *)
_write_out(@loca0, 4)
loca0 := 0x0a6e6f69 (* ion\n *)
_write_out(@loca0, 4)
loca0 := 0x6174735f (* _sta *)
_write_out(@loca0, 4)
loca0 := 0x0a3a7472 (* rt:\n *)
_write_out(@loca0, 4)
_advance(6) (* Skip begin\n. *)
end
proc _compile_exit()
var loca0: Word
begin
(*
li a0, 0
li a7, SYS_EXIT
ecall
*)
loca0 := 0x6120696c (* li a *)
_write_out(@loca0, 4)
loca0 := 0x30202c30 (* 0, 0 *)
_write_out(@loca0, 4)
loca0 := 0x20696c0a (* \nli_ *)
_write_out(@loca0, 4)
loca0 := 0x202c3761 (* a7,_ *)
_write_out(@loca0, 4)
loca0 := 0x650a3339 (* 93\ne *)
_write_out(@loca0, 4)
loca0 := 0x6c6c6163 (* call *)
_write_out(@loca0, 4)
loca0 := 0x0a (* \n *)
_write_out(@loca0, 1)
_advance(4) (* Skip end. *)
_skip_spaces() (* Read the possible new line at the end of the file. *)
end
(* Finds the end of the line and returns its length in a0. *)
proc _read_line()
begin
loca0 := _current() (* Local position in the source text. *)
.Lread_line_do
lw t0, 0(sp)
lbu t1, (t0) # t1 = Current character.
beqz t1, .Lread_line_end # Exit the loop on the NUL character.
li t2, '\n'
beq t1, t2, .Lread_line_end # Exit the loop on the new line.
loca0 := loca0 + 1
goto .Lread_line_do
.Lread_line_end
loca4 := _current()
return loca0 - loca4 (* Return the line length. *)
end
proc _compile()
var
loca0, loca4: Word
loca8: Bool
begin
loca4 := 0 (* Whether the text section header was already emitted. *)
.Lcompile_do
lbu t0, (s1) # t0 = Current character.
beqz t0, .Lcompile_end # Exit the loop on the NUL character.
_skip_indentation()
loca0 := _read_line()
loca8 := _compile_line(loca0, loca4)
beqz a0, .Lcompile_do
(* Update whether the text section header was already emitted. *)
loca4 := loca4 or loca8
goto .Lcompile_do
.Lcompile_end
end
(* Returns the pointer to the current position in the source text in a0. *)
proc _current()
begin
mv a0, s1
end
(* a0 is the number of bytes to advance in the source text. *)
proc _advance()
begin
add s1, s1, a0
end
(* Returns the first character in the remaining source text. *)
proc _front()
begin
lbu a0, (s1)
end
(* Entry point. *)
begin
(* Read the source from the standard input. *)
la a0, source_code
la a1, SOURCE_BUFFER_SIZE # Buffer size.
lw a1, (a1)
call _read_file
la s1, source_code # s1 = Source code position.
li s2, 1
_compile()
end.