Implement if statements

This commit is contained in:
Eugen Wissner 2025-04-29 00:55:20 +02:00
parent 963d32e8d1
commit 9c66cec171
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
7 changed files with 476 additions and 213 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/build/
a.out
/vendor/

6
Gemfile Normal file
View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
source 'https://rubygems.org'
gem 'term-ansicolor', '~> 1.2'
gem 'rake', '~> 13.2'

22
Gemfile.lock Normal file
View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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'
loca0 := -4 * loca12
loca0 := loca0 + 60
_printi(loca0)
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
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 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 t0, 12(sp) # Argument count for a procedure call.
(* 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)
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'
(* 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)
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)
(* 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)
addi a0, sp, 2
li a1, 10
call _write_out
(* 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)
loca12 := loca12 + 1
goto .Lcompile_call_restore
.Lcompile_call_perform
loca0 := 0x6c6c6163
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.