summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/common-boot.s45
-rw-r--r--boot/echo-boot.s449
-rw-r--r--boot/goto-boot.elna12
-rw-r--r--boot/stage2.elna491
4 files changed, 812 insertions, 185 deletions
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