diff options
| author | Eugen Wissner <belka@caraus.de> | 2025-04-24 23:01:12 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2025-04-24 23:01:12 +0200 |
| commit | 2e0c958aa30e831ee766efd63f3d6dfa84069e1b (patch) | |
| tree | b3ff040c7327a6d01e5711c9bed8a3d2752768fa /boot/stage2.elna | |
| parent | f343296463f8271720cf1e9cb1d45f30c288d872 (diff) | |
| download | elna-2e0c958aa30e831ee766efd63f3d6dfa84069e1b.tar.gz | |
Compile procedure calls
Diffstat (limited to 'boot/stage2.elna')
| -rw-r--r-- | boot/stage2.elna | 491 |
1 files changed, 400 insertions, 91 deletions
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 |
