(* 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, loca16, loca20: Word loca12: ^Byte loca24: Bool begin _build_expression(0) loca4 := 0x2c306120 (* _a0, *) loca8 := 0x0a316120 (* _a1\n *) _skip_spaces() loca20 := _read_token() loca12 := _current() loca16 := 0x26 (* & *) loca24 := _token_compare(loca12, loca20, @loca16) if loca24 = 0 then goto .L_build_binary_expression_and end loca16 := 0x726f (* or *) loca24 := _token_compare(loca12, loca20, @loca16) if loca24 = 0 then goto .L_build_binary_expression_or end loca16 := 0x3d (* = *) loca24 := _token_compare(loca12, loca20, @loca16) if loca24 = 0 then goto .L_build_binary_expression_equal end loca16 := 0x2b (* + *) loca24 := _token_compare(loca12, loca20, @loca16) if loca24 = 0 then goto .L_build_binary_expression_plus end loca16 := 0x2d (* - *) loca24 := _token_compare(loca12, loca20, @loca16) if loca24 = 0 then goto .L_build_binary_expression_minus end loca16 := 0x2a (* * *) loca24 := _token_compare(loca12, loca20, @loca16) if loca24 = 0 then goto .L_build_binary_expression_product end goto .Lbuild_binary_expression_end .L_build_binary_expression_equal _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) loca0 := 0x7a716573 (* seqz *) _write_out(@loca0, 4) _write_out(@loca4, 4) _write_out(@loca4, 3) _put_char(0x0a) (* \n *) 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 proc _build_identifier_expression(loca84: Word, loca80: Byte) begin loca24 := _current() loca0 := 0x61636f6c (* loca *) loca0 := _memcmp(@loca0, loca24, 4) if loca0 = 0 then loca8 := 0x6120776c (* lw a *) _write_out(@loca8, 4) loca8 := 0x00202c00 or loca80 (* \0,_ *) _write_out(@loca8, 3) loca4 := loca24 + 4 loca0 := loca84 - 4 _write_out(loca4, loca0) (* Skip the "loca" variable prefix. *) loca8 := 0x29707328 (* (sp) *) _write_out(@loca8, 4) _put_char(0x0a) (* \n *) goto .Lbuild_identifier_expression_end end loca0 := _front(loca24) loca8 := loca84 = 2 loca12 := loca0 = 0x73 if loca8 & loca12 then loca8 := 0x6120766d (* mv a *) _write_out(@loca8, 4) loca8 := 0x00202c00 or loca80 (* \0,_ *) _write_out(@loca8, 3) _write_out(loca24, loca84) _put_char(0x0a) (* \n *) goto .Lbuild_identifier_expression_end end (* Global identifier. *) loca8 := 0x6120616c (* la a *) _write_out(@loca8, 4) loca8 := 0x00202c00 or loca80 _write_out(@loca8, 3) _write_out(loca24, loca84) _put_char(0x0a) if _is_upper(loca0) then loca8 := 0x6120776c (* lw a *) _write_out(@loca8, 4) loca8 := 0x28202c00 or loca28 (* \0, ( *) _write_out(@loca8, 4) _put_char(0x61) (* a *) _put_char(loca28) _put_char(0x29) (* ) *) _put_char(0x0a) (* \n *) goto .Lbuild_identifier_expression_end end .Lbuild_identifier_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() loca0 := _front(loca24) (* - *) if loca0 = 0x2d then goto .Lbuild_expression_negate end (* @ *) if loca0 = 0x40 then goto .Lbuild_expression_address end if _is_digit(loca0) then goto .Lbuild_expression_literal end (* _ *) if loca0 = 0x5f then goto .Lbuild_expression_call end _build_identifier_expression(loca20, loca28); 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_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 loca4: Bool 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() loca0 := 0x3d3a (* := *) loca4 := _token_compare(loca12, loca8, @loca0) if loca4 = 0 then goto .Lcompile_identifier_assign end if _front(loca12) = 0x28 then goto .Lcompile_identifier_call end 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 loca8: ^Byte begin loca12 := 0 (* Argument count for a procedure call. *) .Lcompile_call_paren _skip_spaces() loca8 := _current() if _front(loca8) = 0x29 then goto .Lcompile_call_complete end .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() loca8 := _current() loca0 := _front(loca8) = 0x2c if loca0 = 0 then goto .Lcompile_call_paren end 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 loca0, loca4: Word loca8: ^Byte begin loca8 := _current() loca0 := _front(loca8) (* t0 = Current character. *) loca4 := 0 (* . *) if loca0 = 0x2e then goto .Ltoken_character_single end (* , *) if loca0 = 0x2c then goto .Ltoken_character_single end (* : *) if loca0 = 0x3a then goto .Ltoken_character_colon end (* ; *) if loca0 = 0x3b then goto .Ltoken_character_single end (* ( *) if loca0 = 0x28 then goto .Ltoken_character_single end (* ) *) if loca0 = 0x29 then goto .Ltoken_character_single end (* [ *) if loca0 = 0x5b then goto .Ltoken_character_single end (* ] *) if loca0 = 0x5d then goto .Ltoken_character_single end (* ^ *) if loca0 = 0x5e then goto .Ltoken_character_single end (* & *) if loca0 = 0x26 then goto .Ltoken_character_single end (* = *) if loca0 = 0x3d then goto .Ltoken_character_single end (* + *) if loca0 = 0x2b then goto .Ltoken_character_single end (* - *) if loca0 = 0x2d then goto .Ltoken_character_single end (* * *) if loca0 = 0x2a then goto .Ltoken_character_single end (* @ *) if loca0 = 0x40 then goto .Ltoken_character_single end (* Expect an identifier or a number. *) .Ltoken_character_loop_do loca0 := loca8 + loca4 loca0 := _front(loca0) if _is_alnum(loca0) = 0 then goto .Ltoken_character_end end loca4 := loca4 + 1 goto .Ltoken_character_loop_do .Ltoken_character_single loca4 := loca4 + 1 goto .Ltoken_character_end .Ltoken_character_colon loca0 := loca8 + 1 loca0 := _front(loca0) (* t0 = The character after the colon. *) loca4 := loca4 + 1 (* = *) if loca0 = 0x3d then goto .Ltoken_character_single end goto .Ltoken_character_end .Ltoken_character_end return loca4 end (* Skips the spaces till the next non space character. *) proc _skip_spaces() var loca0: Byte loca4: ^Byte begin .Lspace_loop_do loca4 := _current() loca0 := _front(loca4) (* t0 = Current character. *) (* _ *) if loca0 = 0x20 then goto .Lspace_loop_repeat end (* \t *) if loca0 = 0x09 then goto .Lspace_loop_repeat end (* \n *) if loca0 = 0x0a then goto .Lspace_loop_repeat end (* \r *) if loca0 = 0x0d then goto .Lspace_loop_repeat end goto .Lspace_loop_end .Lspace_loop_repeat _advance(1) goto .Lspace_loop_do .Lspace_loop_end end (* Parameters: a0 - Line length. *) proc _skip_comment(loca84: Word) var loca0: ^Byte loca4: Word loca8: Int begin loca0 := _current() (* Check whether this is a comment. *) loca4 := 0x2a28 (* ( and * *) loca8 := _memcmp(loca0, @loca4, 2) if loca8 = 0 then goto .Lskip_comment_continue end goto .Lskip_comment_end .Lskip_comment_continue _advance(2) (* Skip (*. *) loca4 := 0x292a (* ( and * *) .Lskip_comment_loop loca0 := _current() loca8 := _memcmp(loca0, @loca4, 2) if loca8 = 0 then goto .Lskip_comment_close end _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 loca4: ^Byte 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() loca4 := _current() loca0 := _front(loca4) if _is_upper(loca0) = 0 then goto .Lcompile_constant_section_end 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 loca4: ^Byte 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() loca4 := _current() loca0 := _front(loca4) if _is_lower(loca0) = 0 then goto .Lcompile_variable_section_end 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, loca24: ^Byte 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() loca0 := _read_token() loca24 := _current() _advance(loca0) loca0 := _token_compare(loca24, loca0, @loca8) if loca0 = 1 then goto .Lcompile_procedure_begin end (* 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_spaces() loca12 := _read_line() loca8 := 0x0a646e65 (* end\n *) loca24 := _current() loca8 := _memcmp(loca24, @loca8, 4) if loca8 = 0 then goto .Lcompile_procedure_end end _compile_line(loca12) 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(loca84: ^Byte, loca80: Word, loca76: ^Byte) var loca0: Bool loca4, loca12: Byte loca8: Word begin .Ltoken_compare_loop loca4 := _front(loca76) (* 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. *) loca8 := loca4 or loca80 if loca8 = 0 then goto .Ltoken_compare_equal end if loca80 = 0 then goto .Ltoken_compare_not_equal end if loca4 = 0 then goto .Ltoken_compare_not_equal end loca12 := _front(loca84) if loca4 = loca12 then goto .Ltoken_compare_continue end goto .Ltoken_compare_not_equal .Ltoken_compare_continue loca84 := loca84 + 1 loca80 := loca80 - 1 loca76 := loca76 + 1 goto .Ltoken_compare_loop .Ltoken_compare_not_equal loca0 := 1 goto .Ltoken_compare_end .Ltoken_compare_equal loca0 := 0 .Ltoken_compare_end return loca0 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) loca0 := loca0 + loca84 loca0 := loca0 - 1 (* Last character on the line. *) loca0 := _front(loca0) if loca0 = 0x3a then goto .Lcompile_label_colon end _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) _printi(s2) _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) _printi(s2) loca12 := 0x0a3a0a3a (* :\n:\n *) _write_out(@loca12, 2) (* Increment the label counter. *) addi s2, s2, 1 _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) var loca0: Char loca4: Int loca8: Bool loca12: Word loca16: ^Byte begin if loca84 = 0 then goto .Lcompile_line_empty (* Skip an empty line. *) end loca16 := _current() loca0 := _front(loca16) (* ( *) if loca0 = 0x28 then goto .Lcompile_line_comment end loca16 := _current() loca12 := 0x676f7270 (* prog *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_program end loca12 := 0x736e6f63 (* cons *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_const end loca12 := 0x0a726176 (* var\n *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_var end loca12 := 0x636f7270 (* proc *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_procedure end loca12 := 0x69676562 (* begi *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_begin end loca12 := 0x2e646e65 (* end. *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_exit end loca12 := 0x61636f6c (* loca *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_identifier end loca12 := 0x6f706d69 (* impo *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_import end loca12 := 0x6f746f67 (* goto *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_goto end loca12 := 0x75746572 (* retu *) loca4 := _memcmp(loca16, @loca12, 4) if loca4 = 0 then goto .Lcompile_line_return end loca12 := 0x6669 (* if *) loca4 := _memcmp(loca16, @loca12, 2) if loca4 = 0 then goto .Lcompile_line_if end (* . *) if loca0 = 0x2e then goto .Lcompile_line_label end (* _ *) if loca0 = 0x5f then goto .Lcompile_line_identifier end 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 _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 if loca80 = 1 then goto .Lcompile_line_compile_entry end _compile_text_section() .Lcompile_line_compile_entry _compile_entry_point() loca8 := 1 goto .Lcompile_line_end .Lcompile_line_const _compile_constant_section() goto .Lcompile_line_section .Lcompile_line_procedure if loca80 = 1 then goto .Lcompile_line_compile_procedure end _compile_text_section() .Lcompile_line_compile_procedure _compile_procedure() loca8 := 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 loca8 := 0 .Lcompile_line_end _skip_spaces() _skip_comment() return loca8 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() var loca0: ^Byte loca4: Byte begin loca0 := _current() (* Local position in the source text. *) .Lread_line_do loca4 := _front(loca0) (* t1 = Current character. *) if loca4 = 0 then goto .Lread_line_end (* Exit the loop on the NUL character. *) end if loca4 = 0x0a then goto .Lread_line_end (* Exit the loop on the new line. *) end 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 loca12: Char loca16: ^Byte begin loca4 := 0 (* Whether the text section header was already emitted. *) .Lcompile_do loca16 := _current() loca12 := _front(loca16) (* t0 = Current character. *) if loca12 = 0 then goto .Lcompile_end (* Exit the loop on the NUL character. *) end _skip_spaces() loca0 := _read_line() loca8 := _compile_line(loca0, loca4) if loca8 = 0 then goto .Lcompile_do end (* 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 return s1 end (* a0 is the number of bytes to advance in the source text. *) proc _advance(loca84: Word) begin add s1, s1, a0 end (* a0 - Pointer to an array to get the first element. Returns the first character in the remaining source text. *) proc _front(loca84: ^Word) begin return _get(loca84) & 0xff end proc _main() begin (* Read the source from the standard input. *) _read_file(source_code, SOURCE_BUFFER_SIZE) addi s2, zero, 1 end (* Entry point. *) begin _main() _compile() end.