diff --git a/boot/common-boot.s b/boot/common-boot.s index 2228a57..9c5ebc4 100644 --- a/boot/common-boot.s +++ b/boot/common-boot.s @@ -1,4 +1,4 @@ -.global is_alpha, is_digit, is_alnum, is_upper, is_lower, write_out, read_file, exit, memcmp, write_error +.global _is_alpha, _is_digit, _is_alnum, _is_upper, _is_lower, _write_out, _read_file, exit, _memcmp, _write_error .section .rodata @@ -16,8 +16,8 @@ new_line: .ascii "\n" # Write the current token to stderr. # a0 - String pointer. # a1 - String length. -.type write_error, @function -write_error: +.type _write_error, @function +_write_error: mv t0, a0 mv t1, a1 @@ -40,8 +40,8 @@ write_error: # a2 - The length to compare. # # Returns 0 in a0 if memory regions are equal. -.type memcmp, @function -memcmp: +.type _memcmp, @function +_memcmp: mv t0, a0 li a0, 0 @@ -64,7 +64,8 @@ memcmp: ret # Detects if a0 is an uppercase character. Sets a0 to 1 if so, otherwise to 0. -is_upper: +.type _is_upper, @function +_is_upper: li t0, 'A' - 1 sltu t1, t0, a0 # t1 = a0 >= 'A' @@ -74,8 +75,8 @@ is_upper: ret # Detects if a0 is an lowercase character. Sets a0 to 1 if so, otherwise to 0. -.type is_lower, @function -is_lower: +.type _is_lower, @function +_is_lower: li t0, 'a' - 1 sltu t2, t0, a0 # t2 = a0 >= 'a' @@ -87,8 +88,8 @@ is_lower: # Detects if the passed character is a 7-bit alpha character or an underscore. # The character is passed in a0. # Sets a0 to 1 if the character is an alpha character or underscore, sets it to 0 otherwise. -.type is_alpha, @function -is_alpha: +.type _is_alpha, @function +_is_alpha: # Prologue. addi sp, sp, -16 sw ra, 12(sp) @@ -97,11 +98,11 @@ is_alpha: sw a0, 4(sp) - call is_upper + call _is_upper sw a0, 0(sp) lw a0, 4(sp) - call is_lower + call _is_lower lw t0, 4(sp) xori t1, t0, '_' @@ -117,8 +118,8 @@ is_alpha: addi sp, sp, 16 ret -.type is_digit, @function -is_digit: +.type _is_digit, @function +_is_digit: li t0, '0' - 1 sltu t1, t0, a0 # t1 = a0 >= '0' @@ -128,8 +129,8 @@ is_digit: ret -.type is_alnum, @function -is_alnum: +.type _is_alnum, @function +_is_alnum: # Prologue. addi sp, sp, -16 sw ra, 12(sp) @@ -138,11 +139,11 @@ is_alnum: sw a0, 4(sp) - call is_alpha + call _is_alpha sw a0, 0(sp) lw a0, 4(sp) - call is_digit + call _is_digit lw a1, 0(sp) or a0, a0, a1 @@ -153,8 +154,8 @@ is_alnum: addi sp, sp, 16 ret -.type write, @function -write_out: +.type _write_out, @function +_write_out: # Prologue. addi sp, sp, -8 sw ra, 4(sp) @@ -178,8 +179,8 @@ write_out: # a1 - Buffer size. # # Returns the result in a0. -.type read_file, @function -read_file: +.type _read_file, @function +_read_file: # Prologue. addi sp, sp, -8 sw ra, 4(sp) diff --git a/boot/echo-boot.s b/boot/echo-boot.s index 22d59d0..8256bbd 100644 --- a/boot/echo-boot.s +++ b/boot/echo-boot.s @@ -11,6 +11,325 @@ source_code: .zero 20480 .section .text +# Evalutes an expression and saves the result in a0. +.type _build_expression, @function +_build_expression: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 + + call _skip_spaces + call _read_token + sw s1, 20(sp) + sw a0, 16(sp) + + # Integer literal. + addi a0, s1, 0 + lb a0, (a0) + call _is_digit + bnez a0, .Lbuild_expression_number_literal + + # Named identifier. + li t0, 0x202c30 # 0,_ + sw t0, 12(sp) + li t0, 0x6120616c # la a + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 7 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + call _write_out + + li t0, 0x0a # \n + sw t0, 12(sp) + addi a0, sp, 12 + li a1, 1 + call _write_out + + j .Lbuild_expression_end + +.Lbuild_expression_number_literal: + li t0, 0x202c30 # 0,_ + sw t0, 12(sp) + li t0, 0x6120696c # li a + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 7 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + call _write_out + + li t0, 0x0a # \n + sw t0, 12(sp) + addi a0, sp, 12 + li a1, 1 + call _write_out + + j .Lbuild_expression_end + +.Lbuild_expression_end: + lw a0, 16(sp) + add s1, s1, a0 + + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret + +# 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. +.type _compile_identifier, @function +_compile_identifier: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 + + call _read_token + + # Save the pointer to the identifier and its length on the stack. + sw s1, 20(sp) + sw a0, 16(sp) + + add s1, s1, a0 + call _skip_spaces + call _read_token + + # Save the pointer and the length of the token following the identifier. + sw s1, 12(sp) + sw a0, 8(sp) + + add s1, s1, a0 # Skip that token. + call _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 + + /* DEBUG + mv a0, s1 + li a1, 4 + call _write_error */ + + lw t0, 12(sp) + lbu t0, (t0) + li t1, 0x28 # ( + beq t0, t1, .Lcompile_identifier_call + + j .Lcompile_identifier_end + +.Lcompile_identifier_call: + lw a0, 20(sp) + lw a1, 16(sp) + call _compile_call + + j .Lcompile_identifier_end + +.Lcompile_identifier_assign: + call _build_expression + + li t0, 0x202c30 # 0,_ + sw t0, 12(sp) + li t0, 0x61207773 # sw a + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 7 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + addi a0, a0, 4 # Skip the "loca" variable prefix. + addi a1, a1, -4 # Skip the "loca" variable prefix. + call _write_out + + li t0, 0x0a # \n + sw t0, 12(sp) + li t0, 0x29707328 # (sp) + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 5 + call _write_out + + j .Lcompile_identifier_end + +.Lcompile_identifier_end: + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret + +# 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. +.type _compile_call, @function +_compile_call: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 + + sw a0, 20(sp) + sw a1, 16(sp) + sw zero, 12(sp) # Argument count for a procedure call. + +.Lcompile_call_paren: + call _skip_spaces + call _read_token + lbu t0, (s1) + li t1, 0x29 # ) + beq t0, t1, .Lcompile_call_complete + +.Lcompile_call_argument: + call _build_expression + + li t0, 0x202c30 # 0,_ + sw t0, 8(sp) + li t0, 0x61207773 # sw a + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 7 + call _write_out + + lw t0, 12(sp) # Argument count for a procedure call. + + # Only 8 arguments are supported with a0-a7. + # Save all arguments on the stack so they aren't overriden afterwards. + # The offset on the stack always has two digits in this case. + li t1, -4 + mul t1, t0, t1 + addi t1, t1, 84 + li t2, 10 + div t3, t1, t2 + rem t4, t1, t2 + addi t3, t3, '0' + addi t4, t4, '0' + + sw t3, 8(sp) + sw t4, 4(sp) + + addi a0, sp, 8 + li a1, 1 + call _write_out + + addi a0, sp, 4 + li a1, 1 + call _write_out + + li t0, 0x0a # \n + sw t0, 8(sp) + li t0, 0x29707328 # (sp) + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 5 + call _write_out + + call _skip_spaces + call _read_token + lbu t0, (s1) + li t1, ',' + bne t0, t1, .Lcompile_call_paren + + lw t0, 12(sp) # Argument count for a procedure call. + addi t0, t0, 1 + sw t0, 12(sp) + + addi s1, s1, 1 # Skip the comma between the arguments. + j .Lcompile_call_argument + +.Lcompile_call_complete: + sw zero, 12(sp) + +.Lcompile_call_restore: + # Just go through all a0-a7 registers and read them from stack. + # If this stack value contains garbage, the procedure just shouldn't use it. + lw t0, 12(sp) + li t1, 7 + bgt t0, t1, .Lcompile_call_perform + + li t0, 0x6120776c # lw a + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 4 + call _write_out + + lw t0, 12(sp) # Argument count for a procedure call. + + li t1, -4 + mul t1, t0, t1 + addi t1, t1, 84 + li t2, 10 + div t3, t1, t2 + rem t4, t1, t2 + addi t3, t3, '0' + addi t4, t4, '0' + addi t0, t0, '0' + + li t5, 0x0a # \n + sb t5, 11(sp) + li t5, 0x29707328 # (sp) + sw t5, 7(sp) + sb t4, 6(sp) + sb t3, 5(sp) + li t5, 0x202c # ,_ + sh t5, 3(sp) + sb t0, 2(sp) + + addi a0, sp, 2 + li a1, 10 + call _write_out + + lw t0, 12(sp) # Increment. + addi t0, t0, 1 + sw t0, 12(sp) + + j .Lcompile_call_restore + +.Lcompile_call_perform: + li t0, 0x20 + sw t0, 8(sp) + li t0, 0x6c6c6163 + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 5 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + call _write_out + + li t0, 0x0a # \n + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 1 + call _write_out + + call _skip_spaces + addi s1, s1, 1 # Skip the close paren. + + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret + # 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. .type _read_token, @function @@ -53,7 +372,7 @@ _read_token: add t1, s1, t6 lbu a0, (t1) # a0 = Current character. - call is_alnum + call _is_alnum beqz a0, .Ltoken_character_end lw t6, 4(sp) @@ -150,7 +469,7 @@ _compile_assembly: # Write the source to the standard output. mv a0, s1 lw a1, 4(sp) - call write_out + call _write_out lw t0, 4(sp) add s1, s1, t0 @@ -159,7 +478,7 @@ _compile_assembly: sb t0, 0(sp) addi a0, sp, 0 li a1, 1 - call write_out + call _write_out addi s1, s1, 1 # Skip the new line. @@ -189,7 +508,7 @@ _compile_program: addi a0, sp, 8 li a1, 15 - call write_out + call _write_out addi s1, s1, 8 # program\n. @@ -221,14 +540,14 @@ _compile_constant_section: addi a0, sp, 4 li a1, 17 - call write_out + call _write_out addi s1, s1, 6 # const\n. .Lcompile_constant_section_item: call _skip_spaces lbu a0, (s1) - call is_upper + call _is_upper beqz a0, .Lcompile_constant_section_end call _compile_constant @@ -254,7 +573,7 @@ _compile_constant: mv a1, a0 # The identifier length from _read_token should be in a1. mv a0, s1 # Save the identifier pointer before advancing it. add s1, s1, a1 - call write_out + call _write_out call _skip_spaces call _read_token @@ -267,7 +586,7 @@ _compile_constant: sw t0, 0(sp) mv a0, sp li a1, 8 - call write_out + call _write_out call _skip_spaces call _read_token @@ -275,13 +594,13 @@ _compile_constant: mv a1, a0 # The literal length from _read_token should be in a1. mv a0, s1 # Save the literal pointer before advancing it. add s1, s1, a1 - call write_out + call _write_out li t0, '\n' sw t0, 4(sp) addi a0, sp, 4 li a1, 1 - call write_out + call _write_out # Epilogue. lw ra, 12(sp) @@ -309,14 +628,14 @@ _compile_variable_section: addi a0, sp, 0 li a1, 14 - call write_out + call _write_out addi s1, s1, 4 # var\n. .Lcompile_variable_section_item: call _skip_spaces lbu a0, (s1) - call is_lower + call _is_lower beqz a0, .Lcompile_variable_section_end call _compile_variable @@ -371,11 +690,11 @@ _compile_variable: sw t0, 8(sp) addi a0, sp, 8 li a1, 6 - call write_out + call _write_out lw a0, 28(sp) lw a1, 24(sp) - call write_out + call _write_out li t0, 0x0a74 # t\n sw t0, 12(sp) @@ -385,7 +704,7 @@ _compile_variable: sw t0, 4(sp) addi a0, sp, 4 li a1, 10 - call write_out + call _write_out # .size identifier, size li t0, 0x2065 # e_ @@ -394,32 +713,32 @@ _compile_variable: sw t0, 8(sp) addi a0, sp, 8 li a1, 6 - call write_out + call _write_out lw a0, 28(sp) lw a1, 24(sp) - call write_out + call _write_out li t0, 0x202c # , sw t0, 12(sp) addi a0, sp, 12 li a1, 2 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a # \n sw t0, 12(sp) addi a0, sp, 12 li a1, 1 - call write_out + call _write_out # identifier: .zero size lw a0, 28(sp) lw a1, 24(sp) - call write_out + call _write_out li t0, 0x206f7265 # ero_ sw t0, 12(sp) @@ -427,17 +746,17 @@ _compile_variable: sw t0, 8(sp) addi a0, sp, 8 li a1, 8 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a # \n sw t0, 12(sp) addi a0, sp, 12 li a1, 1 - call write_out + call _write_out # Epilogue. lw ra, 36(sp) @@ -466,11 +785,11 @@ _compile_procedure: sw t0, 8(sp) addi a0, sp, 8 li a1, 6 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a6e6f69 # ion\n sw t0, 12(sp) @@ -480,17 +799,17 @@ _compile_procedure: sw t0, 4(sp) addi a0, sp, 4 li a1, 12 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a3a # :\n sw t0, 12(sp) addi a0, sp, 12 li a1, 2 - call write_out + call _write_out call _skip_spaces addi s1, s1, 1 # Skip opening argument paren. @@ -521,24 +840,24 @@ _compile_procedure: sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x2c707320 # _sp, sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x0a36392d # -96\n sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x0a29 # )\n sw t0, 12(sp) @@ -550,7 +869,7 @@ _compile_procedure: sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x0a29 # )\n sw t0, 12(sp) @@ -562,7 +881,7 @@ _compile_procedure: sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x0a363920 # _96\n sw t0, 12(sp) @@ -574,7 +893,7 @@ _compile_procedure: sw t0, 0(sp) addi a0, sp, 0 li a1, 16 - call write_out + call _write_out # Generate the body of the procedure. .Lcompile_procedure_body: @@ -586,7 +905,7 @@ _compile_procedure: mv a0, s1 addi a1, sp, 8 li a2, 4 - call memcmp + call _memcmp beqz a0, .Lcompile_procedure_end @@ -608,7 +927,7 @@ _compile_procedure: sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x0a29 # )\n sw t0, 12(sp) @@ -620,36 +939,36 @@ _compile_procedure: sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x69646461 # addi sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x2c707320 # _sp, sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x0a3639 # 96\n sw t0, 12(sp) addi a0, sp, 12 li a1, 3 - call write_out + call _write_out li t0, 0x0a746572 # ret\n sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out # Epilogue. lw ra, 28(sp) @@ -726,7 +1045,7 @@ _compile_line: mv a0, s1 addi a1, sp, 12 li a2, 8 - call memcmp + call _memcmp beqz a0, .Lcompile_line_program li t0, 0x0a74 # t\n @@ -736,7 +1055,7 @@ _compile_line: mv a0, s1 addi a1, sp, 12 li a2, 6 - call memcmp + call _memcmp beqz a0, .Lcompile_line_const li t0, 0x0a726176 # var\n @@ -744,7 +1063,7 @@ _compile_line: mv a0, s1 addi a1, sp, 16 li a2, 4 - call memcmp + call _memcmp beqz a0, .Lcompile_line_var li t0, 0x20 # _ @@ -754,7 +1073,7 @@ _compile_line: mv a0, s1 addi a1, sp, 12 li a2, 5 - call memcmp + call _memcmp beqz a0, .Lcompile_line_procedure li t0, 0x0a6e # n\n @@ -764,7 +1083,7 @@ _compile_line: mv a0, s1 addi a1, sp, 12 li a2, 6 - call memcmp + call _memcmp beqz a0, .Lcompile_line_begin li t0, 0x2e646e65 # end. @@ -772,11 +1091,27 @@ _compile_line: mv a0, s1 addi a1, sp, 16 li a2, 4 - call memcmp + call _memcmp beqz a0, .Lcompile_line_exit + li t0, 0x61636f6c # loca + sw t0, 16(sp) + mv a0, s1 + addi a1, sp, 16 + li a2, 4 + call _memcmp + beqz a0, .Lcompile_line_identifier + + lbu t0, (s1) + li t1, '_' + beq t0, t1, .Lcompile_line_identifier + j .Lcompile_line_unchanged # Else. +.Lcompile_line_identifier: + call _compile_identifier + j .Lcompile_line_section + .Lcompile_line_exit: call _compile_exit j .Lcompile_line_section @@ -796,12 +1131,6 @@ _compile_line: j .Lcompile_line_end .Lcompile_line_var: - - /* DEBUG - mv a0, s1 - li a1, 20 - call write_error */ - call _compile_variable_section j .Lcompile_line_section @@ -853,7 +1182,7 @@ _compile_text_section: addi a0, sp, 0 li a1, 15 - call write_out + call _write_out # Epilogue. lw ra, 20(sp) @@ -888,7 +1217,7 @@ _compile_entry_point: sw t0, 24(sp) addi a0, sp, 24 li a1, 32 - call write_out + call _write_out addi s1, s1, 6 # Skip begin\n. @@ -925,7 +1254,7 @@ _compile_exit: sw t0, 28(sp) addi a0, sp, 28 li a1, 25 - call write_out + call _write_out addi s1, s1, 4 # Skip end. call _skip_spaces # Read the possible new line at the end of the file. @@ -986,7 +1315,7 @@ _start: la a0, source_code la a1, SOURCE_BUFFER_SIZE # Buffer size. lw a1, (a1) - call read_file + call _read_file la s1, source_code # s1 = Source code position. call _compile diff --git a/boot/goto-boot.elna b/boot/goto-boot.elna deleted file mode 100644 index c2fd69b..0000000 --- a/boot/goto-boot.elna +++ /dev/null @@ -1,12 +0,0 @@ -program - -import dummy - -var source_code: [2048]Byte - -begin - read_file(source_code, 2048); - - s1 := source_code; - -end. diff --git a/boot/stage2.elna b/boot/stage2.elna index e954762..e37b3e6 100644 --- a/boot/stage2.elna +++ b/boot/stage2.elna @@ -9,6 +9,293 @@ var .section .text +# Evalutes an expression and saves the result in a0. +proc _build_expression() +begin + _skip_spaces() + call _read_token + sw s1, 20(sp) + sw a0, 16(sp) + + # Integer literal. + addi a0, s1, 0 + lb a0, (a0) + call _is_digit + bnez a0, .Lbuild_expression_number_literal + + # Named identifier. + li t0, 0x202c30 # 0,_ + sw t0, 12(sp) + li t0, 0x6120616c # la a + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 7 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + call _write_out + + li t0, 0x0a # \n + sw t0, 12(sp) + addi a0, sp, 12 + li a1, 1 + call _write_out + + j .Lbuild_expression_end + +.Lbuild_expression_number_literal: + li t0, 0x202c30 # 0,_ + sw t0, 12(sp) + li t0, 0x6120696c # li a + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 7 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + call _write_out + + li t0, 0x0a # \n + sw t0, 12(sp) + addi a0, sp, 12 + li a1, 1 + call _write_out + + j .Lbuild_expression_end + +.Lbuild_expression_end: + lw a0, 16(sp) + add s1, s1, a0 +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() +begin + call _read_token + + # Save the pointer to the identifier and its length on the stack. + sw s1, 20(sp) + sw a0, 16(sp) + + add s1, s1, a0 + _skip_spaces() + call _read_token + + # Save the pointer and the length of the token following the identifier. + sw s1, 12(sp) + sw a0, 8(sp) + + add s1, s1, a0 # 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 + + /* DEBUG + mv a0, s1 + li a1, 4 + call _write_error */ + + lw t0, 12(sp) + lbu t0, (t0) + li t1, 0x28 # ( + beq t0, t1, .Lcompile_identifier_call + + j .Lcompile_identifier_end + +.Lcompile_identifier_call: + lw a0, 20(sp) + lw a1, 16(sp) + call _compile_call + + j .Lcompile_identifier_end + +.Lcompile_identifier_assign: + call _build_expression + + li t0, 0x202c30 # 0,_ + sw t0, 12(sp) + li t0, 0x61207773 # sw a + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 7 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + addi a0, a0, 4 # Skip the "loca" variable prefix. + addi a1, a1, -4 # Skip the "loca" variable prefix. + call _write_out + + li t0, 0x0a # \n + sw t0, 12(sp) + li t0, 0x29707328 # (sp) + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 5 + call _write_out + + j .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() +begin + sw a0, 20(sp) + sw a1, 16(sp) + sw zero, 12(sp) # Argument count for a procedure call. + +.Lcompile_call_paren: + _skip_spaces() + call _read_token + lbu t0, (s1) + li t1, 0x29 # ) + beq t0, t1, .Lcompile_call_complete + +.Lcompile_call_argument: + call _build_expression + + li t0, 0x202c30 # 0,_ + sw t0, 8(sp) + li t0, 0x61207773 # sw a + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 7 + call _write_out + + lw t0, 12(sp) # Argument count for a procedure call. + + # Only 8 arguments are supported with a0-a7. + # Save all arguments on the stack so they aren't overriden afterwards. + # The offset on the stack always has two digits in this case. + li t1, -4 + mul t1, t0, t1 + addi t1, t1, 84 + li t2, 10 + div t3, t1, t2 + rem t4, t1, t2 + addi t3, t3, '0' + addi t4, t4, '0' + + sw t3, 8(sp) + sw t4, 4(sp) + + addi a0, sp, 8 + li a1, 1 + call _write_out + + addi a0, sp, 4 + li a1, 1 + call _write_out + + li t0, 0x0a # \n + sw t0, 8(sp) + li t0, 0x29707328 # (sp) + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 5 + call _write_out + + _skip_spaces() + call _read_token + lbu t0, (s1) + li t1, ',' + bne t0, t1, .Lcompile_call_paren + + lw t0, 12(sp) # Argument count for a procedure call. + addi t0, t0, 1 + sw t0, 12(sp) + + _advance(1) # Skip the comma between the arguments. + j .Lcompile_call_argument + +.Lcompile_call_complete: + sw zero, 12(sp) + +.Lcompile_call_restore: + # Just go through all a0-a7 registers and read them from stack. + # If this stack value contains garbage, the procedure just shouldn't use it. + lw t0, 12(sp) + li t1, 7 + bgt t0, t1, .Lcompile_call_perform + + li t0, 0x6120776c # lw a + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 4 + call _write_out + + lw t0, 12(sp) # Argument count for a procedure call. + + li t1, -4 + mul t1, t0, t1 + addi t1, t1, 84 + li t2, 10 + div t3, t1, t2 + rem t4, t1, t2 + addi t3, t3, '0' + addi t4, t4, '0' + addi t0, t0, '0' + + li t5, 0x0a # \n + sb t5, 11(sp) + li t5, 0x29707328 # (sp) + sw t5, 7(sp) + sb t4, 6(sp) + sb t3, 5(sp) + li t5, 0x202c # ,_ + sh t5, 3(sp) + sb t0, 2(sp) + + addi a0, sp, 2 + li a1, 10 + call _write_out + + lw t0, 12(sp) # Increment. + addi t0, t0, 1 + sw t0, 12(sp) + + j .Lcompile_call_restore + +.Lcompile_call_perform: + li t0, 0x20 + sw t0, 8(sp) + li t0, 0x6c6c6163 + sw t0, 4(sp) + addi a0, sp, 4 + li a1, 5 + call _write_out + + lw a0, 20(sp) + lw a1, 16(sp) + call _write_out + + li t0, 0x0a # \n + sw t0, 8(sp) + addi a0, sp, 8 + li a1, 1 + call _write_out + + _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() @@ -45,7 +332,7 @@ begin add t1, s1, t6 lbu a0, (t1) # a0 = Current character. - call is_alnum + call _is_alnum beqz a0, .Ltoken_character_end lw t6, 4(sp) @@ -90,7 +377,7 @@ begin j .Lspace_loop_end .Lspace_loop_repeat: - addi s1, s1, 1 + _advance(1) j .Lspace_loop_do .Lspace_loop_end: @@ -108,7 +395,7 @@ begin j .Lskip_indentation_end .Lskip_indentation_skip: - addi s1, s1, 1 + _advance(1) j .Lskip_indentation_do .Lskip_indentation_end: @@ -119,7 +406,7 @@ end proc _skip_comment() begin add s1, s1, a0 - addi s1, s1, 1 # Skip the new line. + _advance(1) # Skip the new line. end # Parameters: @@ -131,7 +418,7 @@ begin # Write the source to the standard output. mv a0, s1 lw a1, 4(sp) - call write_out + call _write_out lw t0, 4(sp) add s1, s1, t0 @@ -140,9 +427,9 @@ begin sb t0, 0(sp) addi a0, sp, 0 li a1, 1 - call write_out + call _write_out - addi s1, s1, 1 # Skip the new line. + _advance(1) # Skip the new line. end proc _compile_program() @@ -159,9 +446,9 @@ begin addi a0, sp, 8 li a1, 15 - call write_out + call _write_out - addi s1, s1, 8 # program\n. + _advance(8) # program\n. end proc _compile_constant_section() @@ -180,14 +467,14 @@ begin addi a0, sp, 4 li a1, 17 - call write_out + call _write_out - addi s1, s1, 6 # const\n. + _advance(6) # const\n. .Lcompile_constant_section_item: - call _skip_spaces + _skip_spaces() lbu a0, (s1) - call is_upper + call _is_upper beqz a0, .Lcompile_constant_section_end call _compile_constant @@ -203,11 +490,11 @@ begin mv a1, a0 # The identifier length from _read_token should be in a1. mv a0, s1 # Save the identifier pointer before advancing it. add s1, s1, a1 - call write_out + call _write_out - call _skip_spaces + _skip_spaces() call _read_token - addi s1, s1, 2 # Skip the assignment sign. + _advance(2) # Skip the assignment sign. # : .long li t0, 0x20676e6f # ong_ @@ -216,21 +503,21 @@ begin sw t0, 0(sp) mv a0, sp li a1, 8 - call write_out + call _write_out - call _skip_spaces + _skip_spaces() call _read_token mv a1, a0 # The literal length from _read_token should be in a1. mv a0, s1 # Save the literal pointer before advancing it. add s1, s1, a1 - call write_out + call _write_out li t0, '\n' sw t0, 4(sp) addi a0, sp, 4 li a1, 1 - call write_out + call _write_out end proc _compile_variable_section() @@ -247,14 +534,14 @@ begin addi a0, sp, 0 li a1, 14 - call write_out + call _write_out - addi s1, s1, 4 # var\n. + _advance(4) # var\n. .Lcompile_variable_section_item: - call _skip_spaces + _skip_spaces() lbu a0, (s1) - call is_lower + call _is_lower beqz a0, .Lcompile_variable_section_end call _compile_variable @@ -272,11 +559,11 @@ begin sw a0, 24(sp) add s1, s1, a0 - call _skip_spaces - addi s1, s1, 1 # Skip the colon in front of the type. + _skip_spaces() + _advance(1) # Skip the colon in front of the type. - call _skip_spaces - addi s1, s1, 1 # Skip the opening bracket. + _skip_spaces() + _advance(1) # Skip the opening bracket. call _read_token @@ -285,10 +572,10 @@ begin sw a0, 16(sp) add s1, s1, a0 - call _skip_spaces - addi s1, s1, 1 # Skip the closing bracket. + _skip_spaces() + _advance(1) # Skip the closing bracket. - call _skip_spaces + _skip_spaces() call _read_token add s1, s1, a0 # Skip the type. @@ -299,11 +586,11 @@ begin sw t0, 8(sp) addi a0, sp, 8 li a1, 6 - call write_out + call _write_out lw a0, 28(sp) lw a1, 24(sp) - call write_out + call _write_out li t0, 0x0a74 # t\n sw t0, 12(sp) @@ -313,7 +600,7 @@ begin sw t0, 4(sp) addi a0, sp, 4 li a1, 10 - call write_out + call _write_out # .size identifier, size li t0, 0x2065 # e_ @@ -322,32 +609,32 @@ begin sw t0, 8(sp) addi a0, sp, 8 li a1, 6 - call write_out + call _write_out lw a0, 28(sp) lw a1, 24(sp) - call write_out + call _write_out li t0, 0x202c # , sw t0, 12(sp) addi a0, sp, 12 li a1, 2 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a # \n sw t0, 12(sp) addi a0, sp, 12 li a1, 1 - call write_out + call _write_out # identifier: .zero size lw a0, 28(sp) lw a1, 24(sp) - call write_out + call _write_out li t0, 0x206f7265 # ero_ sw t0, 12(sp) @@ -355,22 +642,22 @@ begin sw t0, 8(sp) addi a0, sp, 8 li a1, 8 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a # \n sw t0, 12(sp) addi a0, sp, 12 li a1, 1 - call write_out + call _write_out end proc _compile_procedure() begin - addi s1, s1, 5 # Skip proc_ + _advance(5) # Skip proc_ call _read_token sw s1, 20(sp) sw a0, 16(sp) @@ -383,11 +670,11 @@ begin sw t0, 8(sp) addi a0, sp, 8 li a1, 6 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a6e6f69 # ion\n sw t0, 12(sp) @@ -397,22 +684,22 @@ begin sw t0, 4(sp) addi a0, sp, 4 li a1, 12 - call write_out + call _write_out lw a0, 20(sp) lw a1, 16(sp) - call write_out + call _write_out li t0, 0x0a3a # :\n sw t0, 12(sp) addi a0, sp, 12 li a1, 2 - call write_out + call _write_out - call _skip_spaces - addi s1, s1, 1 # Skip opening argument paren. - call _skip_spaces - addi s1, s1, 1 # Skip closing argument paren. + _skip_spaces() + _advance(1) # Skip opening argument paren. + _skip_spaces() + _advance(1) # Skip closing argument paren. li t0, 0x6e # n sw t0, 12(sp) @@ -422,7 +709,7 @@ begin # Skip all declarations until we find the "begin" keyword, denoting the # beginning of the procedure body. .Lcompile_procedure_begin: - call _skip_spaces + _skip_spaces() call _read_token mv a1, a0 @@ -438,24 +725,24 @@ begin sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x2c707320 # _sp, sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x0a36392d # -96\n sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x0a29 # )\n sw t0, 12(sp) @@ -467,7 +754,7 @@ begin sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x0a29 # )\n sw t0, 12(sp) @@ -479,7 +766,7 @@ begin sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x0a363920 # _96\n sw t0, 12(sp) @@ -491,11 +778,11 @@ begin sw t0, 0(sp) addi a0, sp, 0 li a1, 16 - call write_out + call _write_out # Generate the body of the procedure. .Lcompile_procedure_body: - call _skip_indentation + _skip_indentation() call _read_line sw a0, 12(sp) li t0, 0x0a646e65 # end\n @@ -503,7 +790,7 @@ begin mv a0, s1 addi a1, sp, 8 li a2, 4 - call memcmp + call _memcmp beqz a0, .Lcompile_procedure_end @@ -525,7 +812,7 @@ begin sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x0a29 # )\n sw t0, 12(sp) @@ -537,36 +824,36 @@ begin sw t0, 0(sp) addi a0, sp, 0 li a1, 14 - call write_out + call _write_out li t0, 0x69646461 # addi sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x2c707320 # _sp, sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out addi a0, sp, 12 li a1, 4 - call write_out + call _write_out li t0, 0x0a3639 # 96\n sw t0, 12(sp) addi a0, sp, 12 li a1, 3 - call write_out + call _write_out li t0, 0x0a746572 # ret\n sw t0, 12(sp) addi a0, sp, 12 li a1, 4 - call write_out + call _write_out end # Compares two string, which of one has a length, the other one is null-terminated. @@ -632,7 +919,7 @@ begin mv a0, s1 addi a1, sp, 12 li a2, 8 - call memcmp + call _memcmp beqz a0, .Lcompile_line_program li t0, 0x0a74 # t\n @@ -642,7 +929,7 @@ begin mv a0, s1 addi a1, sp, 12 li a2, 6 - call memcmp + call _memcmp beqz a0, .Lcompile_line_const li t0, 0x0a726176 # var\n @@ -650,7 +937,7 @@ begin mv a0, s1 addi a1, sp, 16 li a2, 4 - call memcmp + call _memcmp; beqz a0, .Lcompile_line_var li t0, 0x20 # _ @@ -660,7 +947,7 @@ begin mv a0, s1 addi a1, sp, 12 li a2, 5 - call memcmp + call _memcmp beqz a0, .Lcompile_line_procedure li t0, 0x0a6e # n\n @@ -670,7 +957,7 @@ begin mv a0, s1 addi a1, sp, 12 li a2, 6 - call memcmp + call _memcmp beqz a0, .Lcompile_line_begin li t0, 0x2e646e65 # end. @@ -678,11 +965,27 @@ begin mv a0, s1 addi a1, sp, 16 li a2, 4 - call memcmp + call _memcmp beqz a0, .Lcompile_line_exit + li t0, 0x61636f6c # loca + sw t0, 16(sp) + mv a0, s1 + addi a1, sp, 16 + li a2, 4 + call _memcmp + beqz a0, .Lcompile_line_identifier + + lbu t0, (s1) + li t1, '_' + beq t0, t1, .Lcompile_line_identifier + j .Lcompile_line_unchanged # Else. +.Lcompile_line_identifier: + call _compile_identifier + j .Lcompile_line_section + .Lcompile_line_exit: call _compile_exit j .Lcompile_line_section @@ -702,12 +1005,6 @@ begin j .Lcompile_line_end .Lcompile_line_var: - - /* DEBUG - mv a0, s1 - li a1, 20 - call write_error */ - call _compile_variable_section j .Lcompile_line_section @@ -721,7 +1018,7 @@ begin j .Lcompile_line_section .Lcompile_line_empty: - addi s1, s1, 1 + _advance(1) j .Lcompile_line_section .Lcompile_line_unchanged: @@ -749,7 +1046,7 @@ begin addi a0, sp, 0 li a1, 15 - call write_out + call _write_out end proc _compile_entry_point() @@ -773,9 +1070,9 @@ begin sw t0, 24(sp) addi a0, sp, 24 li a1, 32 - call write_out + call _write_out - addi s1, s1, 6 # Skip begin\n. + _advance(6) # Skip begin\n. end proc _compile_exit() @@ -799,10 +1096,10 @@ begin sw t0, 28(sp) addi a0, sp, 28 li a1, 25 - call write_out + call _write_out - addi s1, s1, 4 # Skip end. - call _skip_spaces # Read the possible new line at the end of the file. + _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. @@ -829,7 +1126,7 @@ begin lbu t0, (s1) # t0 = Current character. beqz t0, .Lcompile_end # Exit the loop on the NUL character. - call _skip_indentation + _skip_indentation() call _read_line call _compile_line @@ -837,13 +1134,25 @@ begin .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 + # 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 + call _read_file la s1, source_code # s1 = Source code position. call _compile