summaryrefslogtreecommitdiff
path: root/boot/stage2.elna
diff options
context:
space:
mode:
Diffstat (limited to 'boot/stage2.elna')
-rw-r--r--boot/stage2.elna491
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