summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Gemfile6
-rw-r--r--Gemfile.lock22
-rw-r--r--Rakefile10
-rw-r--r--boot/common-boot.s70
-rw-r--r--boot/stage1.s240
-rw-r--r--boot/stage2.elna350
7 files changed, 481 insertions, 218 deletions
diff --git a/.gitignore b/.gitignore
index 0ee919a..0f4ebfc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
/build/
a.out
+/vendor/
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..235744c
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'term-ansicolor', '~> 1.2'
+gem 'rake', '~> 13.2'
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..3521a74
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,22 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ bigdecimal (3.1.9)
+ rake (13.2.1)
+ sync (0.5.0)
+ term-ansicolor (1.11.2)
+ tins (~> 1.0)
+ tins (1.38.0)
+ bigdecimal
+ sync
+
+PLATFORMS
+ ruby
+ x86_64-linux
+
+DEPENDENCIES
+ rake (~> 13.2)
+ term-ansicolor (~> 1.2)
+
+BUNDLED WITH
+ 2.6.7
diff --git a/Rakefile b/Rakefile
index e04bff1..3fa065e 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,5 +1,8 @@
+# frozen_string_literal: true
+
require 'open3'
require 'rake/clean'
+require 'term/ansicolor'
CLOBBER.include 'build'
@@ -10,7 +13,7 @@ QEMU = 'qemu-riscv32'
def assemble_stage(output, compiler, source)
arguments = [QEMU, '-L', SYSROOT, *compiler]
- puts(arguments * ' ')
+ puts Term::ANSIColor.green(arguments * ' ')
puts
Open3.popen2(*arguments) do |qemu_in, qemu_out|
qemu_in.write File.read(*source)
@@ -27,7 +30,7 @@ task default: ['build/stage2b', 'build/stage2b.s', 'boot/stage2.elna'] do |t|
cat_arguments = ['cat', source]
compiler_arguments = [QEMU, '-L', SYSROOT, exe]
- diff_arguments = ['diff', '-Nur', previous_output, '-']
+ diff_arguments = ['diff', '-Nur', '--text', previous_output, '-']
Open3.pipeline(cat_arguments, compiler_arguments, diff_arguments)
end
@@ -70,7 +73,8 @@ task :statistics do
word.start_with?('(*') ||
word.start_with?('*)') ||
('A'..'Z').include?(word[0]) ||
- /^[[:alpha:]][[:digit:]]$/.match(word)
+ /^[[:alpha:]][[:digit:]]$/.match(word) ||
+ ['end', 'if'].include?(word)
end
lines = File.read('boot/stage2.elna')
diff --git a/boot/common-boot.s b/boot/common-boot.s
index c6fcb98..e8eba52 100644
--- a/boot/common-boot.s
+++ b/boot/common-boot.s
@@ -1,5 +1,6 @@
.global _is_alpha, _is_digit, _is_alnum, _is_upper, _is_lower
-.global _write_out, _read_file, exit, _memcmp, _write_error, _put_char
+.global _write_out, _read_file, _memcmp, _write_error, _put_char, _printi
+.global _divide_by_zero_error, _exit
.section .rodata
@@ -119,6 +120,13 @@ _is_alpha:
addi sp, sp, 16
ret
+# Detects whether the passed character is a digit
+# (a value between 0 and 9).
+#
+# Parameters:
+# a0 - Exemined value.
+#
+# Sets a0 to 1 if it is a digit, to 0 otherwise.
.type _is_digit, @function
_is_digit:
li t0, '0' - 1
@@ -201,10 +209,68 @@ _read_file:
ret
# Terminates the program. a0 contains the return code.
+#
+# Parameters:
+# a0 - Status code.
.type _exit, @function
-exit:
+_exit:
li a7, SYS_EXIT
ecall
+ # ret
+
+.type _divide_by_zero_error, @function
+_divide_by_zero_error:
+ addi a7, zero, 172 # getpid
+ ecall
+
+ addi a1, zero, 8 # SIGFPE
+ addi a7, zero, 129 # kill
+ ecall
+ ret
+
+# a0 - Whole number.
+# t1 - Constant 10.
+# a1 - Local buffer.
+# t2 - Current character.
+# t3 - Whether the number is negative.
+.type printi, @function
+_printi:
+ addi sp, sp, -16
+ sw s0, 0(sp)
+ sw ra, 4(sp)
+ addi s0, sp, 16
+ addi t1, zero, 10
+ addi a1, s0, -1
+
+ addi t3, zero, 0
+ bge a0, zero, .digit10
+ addi t3, zero, 1
+ sub a0, zero, a0
+
+.digit10:
+ rem t2, a0, t1
+ addi t2, t2, '0'
+ sb t2, 0(a1)
+ div a0, a0, t1
+ addi a1, a1, -1
+ bne zero, a0, .digit10
+
+ beq zero, t3, .write_call
+ addi t2, zero, '-'
+ sb t2, 0(a1)
+ addi a1, a1, -1
+
+.write_call:
+ addi a0, zero, 1
+ addi a1, a1, 1
+ sub a2, s0, a1
+ addi a7, zero, 64 # write
+ ecall
+
+ lw s0, 0(sp)
+ lw ra, 4(sp)
+ addi sp, sp, 16
+ ret
# Writes a character from a0 into the standard output.
.type _put_char, @function
diff --git a/boot/stage1.s b/boot/stage1.s
index 5989ac9..61dcdec 100644
--- a/boot/stage1.s
+++ b/boot/stage1.s
@@ -1,5 +1,8 @@
.global _start # Program entry point.
+
+# Global variables or registers.
# s1 - Contains the current position in the source text.
+# s2 - Label counter.
.equ SOURCE_BUFFER_SIZE, 81920
@@ -29,10 +32,17 @@ asm_add_a0_a1: .ascii "add a0, a0, a1\n"
.equ ASM_ADD_A0_A1_SIZE, . - asm_add_a0_a1
asm_sub_a0_a1: .ascii "sub a0, a0, a1\n"
.equ ASM_SUB_A0_A1_SIZE, . - asm_sub_a0_a1
+asm_mul_a0_a1: .ascii "mul a0, a0, a1\n"
+.equ ASM_MUL_A0_A1_SIZE, . - asm_mul_a0_a1
asm_seqz_a0: .ascii "seqz a0, a0\n"
.equ ASM_SEQZ_A0_SIZE, . - asm_seqz_a0
+asm_neg_a0: .ascii "neg a0, a0\n"
+.equ ASM_NEG_A0_SIZE, . - asm_neg_a0
asm_type: .ascii ".type "
.equ ASM_TYPE_SIZE, . - asm_type
+asm_restore_parameters:
+ .ascii "lw a0, 60(sp)\nlw a1, 56(sp)\nlw a2, 52(sp)\nlw a3, 48(sp)\nlw a4, 44(sp)\nlw a5, 40(sp)\n"
+.equ ASM_RESTORE_PARAMETERS_SIZE, . - asm_restore_parameters
.section .bss
.type source_code, @object
@@ -116,6 +126,14 @@ _build_binary_expression:
call _token_compare
beqz a0, .L_build_binary_expression_minus
+ li t0, '*'
+ sw t0, 16(sp)
+ mv a0, s1
+ lw a1, 20(sp)
+ addi a2, sp, 16
+ call _token_compare
+ beqz a0, .L_build_binary_expression_product
+
j .Lbuild_binary_expression_end
.L_build_binary_expression_equal:
@@ -172,6 +190,16 @@ _build_binary_expression:
j .Lbuild_binary_expression_end
+.L_build_binary_expression_product:
+ addi s1, s1, 1 # Skip *.
+ li a0, 1
+ call _build_expression
+ la a0, asm_mul_a0_a1
+ li a1, ASM_MUL_A0_A1_SIZE
+ call _write_out
+
+ j .Lbuild_binary_expression_end
+
.Lbuild_binary_expression_end:
# Epilogue.
lw ra, 28(sp)
@@ -198,18 +226,19 @@ _build_expression:
sw s1, 24(sp)
sw a0, 20(sp)
- addi a0, s1, 0
- lbu a0, (a0)
+ lbu a0, (s1)
+ li t0, '-'
+ beq a0, t0, .Lbuild_expression_negate
+
+ lbu a0, (s1)
li t0, '@'
beq a0, t0, .Lbuild_expression_address
- addi a0, s1, 0
- lbu a0, (a0)
+ lbu a0, (s1)
call _is_digit
bnez a0, .Lbuild_expression_literal
- addi a0, s1, 0
- lbu a0, (a0)
+ lbu a0, (s1)
li t0, '_'
beq a0, t0, .Lbuild_expression_call
@@ -241,6 +270,17 @@ _build_expression:
j .Lbuild_expression_advance
+.Lbuild_expression_negate:
+ addi s1, s1, 1 # Skip the -.
+ mv a0, zero
+ call _build_expression
+
+ la a0, asm_neg_a0
+ li a1, ASM_NEG_A0_SIZE
+ call _write_out
+
+ j .Lbuild_expression_advance
+
.Lbuild_expression_address:
lw t1, 28(sp)
li t0, 0x20 # _
@@ -464,26 +504,10 @@ _compile_call:
# Only 6 arguments are supported with a0-a5.
# 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, 60
- 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 a0, -4
+ mul a0, t0, a0
+ addi a0, a0, 60
+ call _printi
li t0, '\n'
sw t0, 8(sp)
@@ -511,52 +535,14 @@ _compile_call:
.Lcompile_call_restore:
# Just go through all a0-a5 registers and read them from stack.
# If this stack value contains garbage, the procedure just shouldn't use it.
- lw t0, 12(sp)
- li t1, 5
- bgt t0, t1, .Lcompile_call_perform
-
- li t0, 0x6120776c # lw a
- sw t0, 4(sp)
- addi a0, sp, 4
- li a1, 4
+ la a0, asm_restore_parameters
+ li a1, ASM_RESTORE_PARAMETERS_SIZE
call _write_out
- lw t0, 12(sp) # Argument count for a procedure call.
-
- li t1, -4
- mul t1, t0, t1
- addi t1, t1, 60
- 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, '\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
+ li t0, 0x6c6c6163 # call
sw t0, 4(sp)
addi a0, sp, 4
li a1, 5
@@ -566,11 +552,8 @@ _compile_call:
lw a1, 16(sp)
call _write_out
- li t0, '\n'
- sw t0, 8(sp)
- addi a0, sp, 8
- li a1, 1
- call _write_out
+ li a0, '\n'
+ call _put_char
call _skip_spaces
addi s1, s1, 1 # Skip the close paren.
@@ -633,6 +616,9 @@ _read_token:
li t1, '-'
beq t0, t1, .Ltoken_character_single
+ li t1, '*'
+ beq t0, t1, .Ltoken_character_single
+
li t1, '@'
beq t0, t1, .Ltoken_character_single
# Expect an identifier or a number.
@@ -1325,6 +1311,97 @@ _compile_return:
addi sp, sp, 16
ret
+.type _compile_if, @function
+_compile_if:
+ # Prologue.
+ addi sp, sp, -32
+ sw ra, 28(sp)
+ sw s0, 24(sp)
+ addi s0, sp, 32
+
+ addi s1, s1, 2 # Skip the if.
+ call _skip_spaces
+
+ call _build_binary_expression
+
+ call _skip_spaces
+ addi s1, s1, 4 # Skip the then.
+
+ # if end marker.
+ li t0, 0x00646e65 # end\0
+ sw t0, 20(sp)
+
+ # Label prefix.
+ li t0, 0x66694c2e # .Lif
+ sw t0, 16(sp)
+
+ li t0, 0x202c3061 # a0,_
+ sw t0, 12(sp)
+ li t0, 0x207a7165 # eqz_
+ sw t0, 8(sp)
+ li t0, 0x62626262 # bbbb
+ sb t0, 7(sp)
+
+ addi a0, sp, 7
+ li a1, 13
+ call _write_out
+
+ # Write the label counter.
+ mv a0, s2
+ call _printi
+
+ li a0, '\n'
+ call _put_char
+
+.Lcompile_if_loop:
+ /* DEBUG
+ mv a0, s1
+ li a1, 6
+ call _write_error
+ call _divide_by_zero_error */
+
+ call _skip_spaces
+ call _read_token
+
+ mv a1, a0
+ mv a0, s1
+ addi a2, sp, 20
+ call _token_compare
+
+ beqz a0, .Lcompile_if_end
+
+ call _read_line
+ li a1, 1
+ call _compile_line
+
+ j .Lcompile_if_loop
+
+.Lcompile_if_end:
+ # Write the label prefix.
+ addi a0, sp, 16
+ li a1, 4
+ call _write_out
+
+ # Write the label counter.
+ mv a0, s2
+ call _printi
+
+ # Finalize the label.
+ li t0, 0x0a3a0a3a # :\n:\n
+ sh t0, 12(sp)
+ addi a0, sp, 12
+ li a1, 2
+ call _write_out
+
+ addi s2, s2, 1 # Increment the label counter.
+ addi s1, s1, 4 # Skip the end with newline.
+
+ # Epilogue.
+ lw ra, 28(sp)
+ lw s0, 24(sp)
+ addi sp, sp, 32
+ ret
+
# Parameters:
# a0 - Line length.
# a1 - Whether the section header was already emitted. If not it should be
@@ -1442,6 +1519,14 @@ _compile_line:
call _memcmp
beqz a0, .Lcompile_line_return
+ li t0, 0x6669 # if
+ sw t0, 12(sp)
+ mv a0, s1
+ addi a1, sp, 12
+ li a2, 2
+ call _memcmp
+ beqz a0, .Lcompile_line_if
+
lbu t0, (s1)
li t1, '.'
beq t0, t1, .Lcompile_line_label
@@ -1450,16 +1535,16 @@ _compile_line:
j .Lcompile_line_unchanged # Else.
+.Lcompile_line_if:
+ call _compile_if
+ j .Lcompile_line_section
+
.Lcompile_line_label:
lw a0, 20(sp)
call _compile_label
j .Lcompile_line_section
.Lcompile_line_return:
- /* DEBUG
- mv a0, s1
- li a1, 6
- call _write_error */
call _compile_return
j .Lcompile_line_section
@@ -1659,9 +1744,10 @@ _start:
li a1, SOURCE_BUFFER_SIZE # Buffer size.
call _read_file
+ li s2, 1
la s1, source_code # s1 = Source code position.
call _compile
# Call exit.
li a0, 0 # Use 0 return code.
- call exit
+ call _exit
diff --git a/boot/stage2.elna b/boot/stage2.elna
index 3ee1f32..0eb713c 100644
--- a/boot/stage2.elna
+++ b/boot/stage2.elna
@@ -14,6 +14,9 @@ type checking.
hexadecimal format).
- Comments are accepted only at the end of a line.
+
+- Return can be used only as the last statement of a procedure. It
+doesn't actually return, but sets a0 to the appropriate value.
*)
program
@@ -36,7 +39,7 @@ begin
end
proc _build_binary_expression()
-var loca0, loca4, loca8: Word
+var loca0, loca4, loca8, loca20: Word
begin
_build_expression(0)
@@ -44,8 +47,7 @@ begin
loca8 := 0x0a316120 (* _a1\n *)
_skip_spaces()
- call _read_token
- sw a0, 20(sp)
+ loca20 := _read_token()
li t0, 0x26 # &
sw t0, 16(sp)
@@ -87,6 +89,14 @@ begin
call _token_compare
beqz a0, .L_build_binary_expression_minus
+ li t0, 0x2a # *
+ sw t0, 16(sp)
+ mv a0, s1
+ lw a1, 20(sp)
+ addi a2, sp, 16
+ call _token_compare
+ beqz a0, .L_build_binary_expression_product
+
goto .Lbuild_binary_expression_end
.L_build_binary_expression_equal
@@ -146,6 +156,19 @@ begin
_write_out(@loca4, 4)
_write_out(@loca8, 4)
+ goto .Lbuild_binary_expression_end
+
+ .L_build_binary_expression_product
+ _advance(1) (* Skip *. *)
+ _build_expression(1)
+ loca0 := 0x6c756d (* mul *)
+ _write_out(@loca0, 3)
+ _write_out(@loca4, 4)
+ _write_out(@loca4, 4)
+ _write_out(@loca8, 4)
+
+ goto .Lbuild_binary_expression_end
+
.Lbuild_binary_expression_end
end
@@ -156,28 +179,30 @@ a0 - X in aX, the register number to save the result.
*)
proc _build_expression()
var
- loca20, loca28, loca8: Word
- loca24: ^Byte
+ loca0, loca20, loca28, loca8: Word
+ loca24, loca4: ^Byte
begin
- addi a0, a0, '0' # Make the register number to a character.
- sw a0, 28(sp) # And save it.
+ (* Make the register number to a character and save it. *)
+ loca28 := loca84 + 0x30 (* 0 *)
_skip_spaces()
loca20 := _read_token()
loca24 := _current()
- addi a0, s1, 0
- lbu a0, (a0)
+ lbu a0, (s1)
+ li t0, '-'
+ beq a0, t0, .Lbuild_expression_negate
+
+ lbu a0, (s1)
li t0, '@'
beq a0, t0, .Lbuild_expression_address
- addi a0, s1, 0
- lbu a0, (a0)
- call _is_digit
- bnez a0, .Lbuild_expression_literal
+ loca0 := _front()
+ if _is_digit(loca0) then
+ goto .Lbuild_expression_literal
+ end
- addi a0, s1, 0
- lbu a0, (a0)
+ lbu a0, (s1)
li t0, '_'
beq a0, t0, .Lbuild_expression_call
@@ -200,6 +225,19 @@ begin
goto .Lbuild_expression_advance
+ .Lbuild_expression_negate
+ _advance(1) (* Skip the -. *)
+ _build_expression(0)
+
+ loca8 := 0x2067656e (* neg_ *)
+ _write_out(@loca8, 4)
+ loca8 := 0x202c3061 (* a0,_ *)
+ _write_out(@loca8, 4)
+ loca8 := 0x0a3061 (* a0,_ *)
+ _write_out(@loca8, 3)
+
+ goto .Lbuild_expression_advance
+
.Lbuild_expression_address
loca8 := 0x69646461 (* addi *)
_write_out(@loca8, 4)
@@ -216,40 +254,28 @@ begin
loca24 := _current()
loca20 := _read_token()
- lw a0, 24(sp)
- lw a1, 20(sp)
- addi a0, a0, 4 # Skip the "loca" variable prefix.
- addi a1, a1, -4 # Skip the "loca" variable prefix.
- call _write_out
+ (* Skip the "loca" variable prefix. *)
+ loca4 := loca24 + 4
+ loca0 := loca20 - 4
+ _write_out(loca4, loca0)
_put_char(0xa)
goto .Lbuild_expression_advance
.Lbuild_expression_identifier
- lw t1, 28(sp)
- li t0, 0x00202c00 # \0,_
- or t0, t0, t1
- sw t0, 8(sp)
- li t0, 0x6120776c # lw a
- sw t0, 4(sp)
- addi a0, sp, 4
- li a1, 7
- call _write_out
+ loca8 := 0x6120776c (* lw a *)
+ _write_out(@loca8, 4)
+ loca8 := 0x00202c00 or loca28 # \0,_
+ _write_out(@loca8, 3)
- lw a0, 24(sp)
- lw a1, 20(sp)
- addi a0, a0, 4 # Skip the "loca" variable prefix.
- addi a1, a1, -4 # Skip the "loca" variable prefix.
- call _write_out
+ loca4 := loca24 + 4
+ loca0 := loca20 - 4
+ _write_out(loca4, loca0) (* Skip the "loca" variable prefix. *)
- 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
+ loca8 := 0x29707328 (* (sp) *)
+ _write_out(@loca8, 4)
+ _put_char(0x0a) (* \n *)
goto .Lbuild_expression_advance
@@ -261,18 +287,13 @@ begin
goto .Lbuild_expression_end
.Lbuild_expression_literal
- lw t1, 28(sp)
- li t0, 0x00202c00 # \0,_
- or t0, t0, t1
- sw t0, 8(sp)
- li t0, 0x6120696c # li a
- sw t0, 4(sp)
- addi a0, sp, 4
- li a1, 7
- call _write_out
+ loca8 := 0x6120696c (* li a *)
+ _write_out(@loca8, 4)
+ loca8 := 0x00202c00 or loca28 (* \0,_ *)
+ _write_out(@loca8, 3)
_write_out(loca24, loca20)
- _put_char(0x0a) # \n
+ _put_char(0x0a) (* \n *)
goto .Lbuild_expression_advance
@@ -335,11 +356,9 @@ begin
loca0 := 0x202c30 (* 0,_ *)
_write_out(@loca0, 3)
- 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
+ loca20 := loca20 + 4
+ loca16 := loca16 - 4
+ _write_out(loca20, loca16)
loca0 := 0x29707328 (* (sp) *)
_write_out(@loca0, 4)
@@ -359,7 +378,7 @@ Returns the procedure result in a0.
*)
proc _compile_call(loca84: ^Byte, loca80: Word)
var
- loca0, loca12: Word
+ loca0, loca4, loca12: Word
begin
loca12 := 0 (* Argument count for a procedure call. *)
@@ -377,49 +396,24 @@ begin
loca0 := 0x202c30 (* 0,_ *)
_write_out(@loca0, 3)
- lw t0, 12(sp) # Argument count for a procedure call.
-
(*
Only 6 arguments are supported with a0-a5.
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, 60
- 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
+ loca0 := -4 * loca12
+ loca0 := loca0 + 60
+ _printi(loca0)
- 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
+ loca0 := 0x29707328 (* (sp) *)
+ _write_out(@loca0, 4)
+ _put_char(0x0a) (* \n *)
_skip_spaces()
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)
+ loca12 := loca12 + 1 (* Argument count for a procedure call. *)
_advance(1) (* Skip the comma between the arguments. *)
goto .Lcompile_call_argument
@@ -432,47 +426,62 @@ begin
Just go through all a0-a5 registers and read them from stack.
If this stack value contains garbage, the procedure just shouldn't use it.
*)
- lw t0, 12(sp)
- li t1, 5
- bgt t0, t1, .Lcompile_call_perform
+ loca0 := 0x6120776c (* lw a *)
+ (* lw a0, 60(sp) *)
+ _write_out(@loca0, 4)
+ loca4 := 0x36202c30 (* 0, 6 *)
+ _write_out(@loca4, 4)
+ loca4 := 0x70732830 (* 0(sp *)
+ _write_out(@loca4, 4)
+ loca4 := 0x0a29 (* )\n *)
+ _write_out(@loca4, 2)
- 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, 60
- 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
-
- loca12 := loca12 + 1
- goto .Lcompile_call_restore
-
- .Lcompile_call_perform
- loca0 := 0x6c6c6163
+ (* lw a1, 56(sp) *)
+ _write_out(@loca0, 4)
+ loca4 := 0x35202c31 (* 1, 5 *)
+ _write_out(@loca4, 4)
+ loca4 := 0x70732836 (* 6(sp *)
+ _write_out(@loca4, 4)
+ loca4 := 0x0a29 (* )\n *)
+ _write_out(@loca4, 2)
+
+ (* lw a2, 52(sp) *)
+ _write_out(@loca0, 4)
+ loca4 := 0x35202c32 (* 2, 5 *)
+ _write_out(@loca4, 4)
+ loca4 := 0x70732832 (* 2(sp *)
+ _write_out(@loca4, 4)
+ loca4 := 0x0a29 (* )\n *)
+ _write_out(@loca4, 2)
+
+ (* lw a3, 48(sp) *)
+ _write_out(@loca0, 4)
+ loca4 := 0x34202c33 (* 3, 4 *)
+ _write_out(@loca4, 4)
+ loca4 := 0x70732838 (* 8(sp *)
+ _write_out(@loca4, 4)
+ loca4 := 0x0a29 (* )\n *)
+ _write_out(@loca4, 2)
+
+ (* lw a4, 44(sp) *)
+ _write_out(@loca0, 4)
+ loca4 := 0x34202c34 (* 4, 4 *)
+ _write_out(@loca4, 4)
+ loca4 := 0x70732834 (* 4(sp *)
+ _write_out(@loca4, 4)
+ loca4 := 0x0a29 (* )\n *)
+ _write_out(@loca4, 2)
+
+ (* lw a5, 40(sp) *)
+ _write_out(@loca0, 4)
+ loca4 := 0x34202c35 (* 5, 4 *)
+ _write_out(@loca4, 4)
+ loca4 := 0x70732830 (* 0(sp *)
+ _write_out(@loca4, 4)
+ loca4 := 0x0a29 (* )\n *)
+ _write_out(@loca4, 2)
+
+ loca0 := 0x6c6c6163 (* call *)
_write_out(@loca0, 4)
_put_char(0x20) (* _ *)
@@ -532,6 +541,9 @@ begin
li t1, '-'
beq t0, t1, .Ltoken_character_single
+ li t1, '*'
+ beq t0, t1, .Ltoken_character_single
+
li t1, '@'
beq t0, t1, .Ltoken_character_single
(* Expect an identifier or a number. *)
@@ -1125,6 +1137,61 @@ begin
_build_binary_expression()
end
+proc _compile_if()
+var
+ loca8, loca12, loca16, loca20: Word
+ loca4: ^Byte
+begin
+ _advance(2) (* Skip the if. *)
+ _skip_spaces()
+
+ _build_binary_expression()
+
+ _skip_spaces()
+ _advance(4) (* Skip the then. *)
+
+ loca20 := 0x00646e65 (* if end marker and newline. *)
+ loca16 := 0x66694c2e (* Label prefix ".Lif". *)
+
+ loca12 := 0x7a716562 (* beqz *)
+ _write_out(@loca12, 4)
+ loca12 := 0x2c306120 (* _a0, *)
+ _write_out(@loca12, 4)
+ _put_char(0x20) (* _ *)
+
+ (* Write the label *)
+ _write_out(@loca16, 4)
+ mv a0, s2
+ call _printi
+
+ _put_char(0x0a) (* \n *)
+
+ .Lcompile_if_loop
+ _skip_spaces()
+ loca12 := _read_token()
+
+ loca4 := _current()
+ loca8 := _token_compare(loca4, loca12, @loca20)
+
+ if loca8 then
+ loca12 := _read_line()
+ _compile_line(loca12, 1)
+
+ goto .Lcompile_if_loop
+ end
+
+ (* Write the label *)
+ _write_out(@loca16, 4)
+ mv a0, s2
+ call _printi
+
+ loca12 := 0x0a3a0a3a (* :\n:\n *)
+ _write_out(@loca12, 2)
+
+ addi s2, s2, 1 # Increment the label counter.
+ _advance(4) (* Skip the end with newline. *)
+end
+
(*
Parameters:
a0 - Line length.
@@ -1234,6 +1301,14 @@ begin
call _memcmp
beqz a0, .Lcompile_line_return
+ li t0, 0x6669 # if
+ sw t0, 12(sp)
+ mv a0, s1
+ addi a1, sp, 12
+ li a2, 2
+ call _memcmp
+ beqz a0, .Lcompile_line_if
+
lbu t0, (s1)
li t1, '.'
beq t0, t1, .Lcompile_line_label
@@ -1242,6 +1317,10 @@ begin
goto .Lcompile_line_unchanged (* Else. *)
+ .Lcompile_line_if:
+ _compile_if()
+ goto .Lcompile_line_section
+
.Lcompile_line_label
_compile_label(loca84)
goto .Lcompile_line_section
@@ -1409,7 +1488,9 @@ begin
end
proc _compile()
-var loca0, loca4: Word
+var
+ loca0, loca4: Word
+ loca8: Bool
begin
loca4 := 0 (* Whether the text section header was already emitted. *)
@@ -1419,15 +1500,11 @@ begin
_skip_indentation()
loca0 := _read_line()
- lw a0, 0(sp)
- lw a1, 4(sp)
- call _compile_line
+ loca8 := _compile_line(loca0, loca4)
beqz a0, .Lcompile_do
(* Update whether the text section header was already emitted. *)
- lw t0, 4(sp)
- or t0, t0, a0
- sw t0, 4(sp)
+ loca4 := loca4 or loca8
goto .Lcompile_do
.Lcompile_end
@@ -1460,5 +1537,6 @@ begin
call _read_file
la s1, source_code # s1 = Source code position.
+ li s2, 1
_compile()
end.