1527 lines
28 KiB
ArmAsm
1527 lines
28 KiB
ArmAsm
# This Source Code Form is subject to the terms of the Mozilla Public License,
|
|
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
|
# obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
.global _start # Program entry point.
|
|
|
|
#
|
|
# Registers used as global variables:
|
|
# s1 - Contains the current position in the source text.
|
|
# s2 - Label counter.
|
|
#
|
|
# - The compiler expects valid input, otherwise it will generate invalid
|
|
# assembly or hang. There is no error checking, no semantic analysis, no
|
|
# type checking.
|
|
#
|
|
# - Imports with only a module name without package, e.g.
|
|
# "import dummy", can be parsed, but are ignored.
|
|
#
|
|
# - No loops. Only labels and goto.
|
|
#
|
|
# - Only unsigned number literals are supported (in decimal or
|
|
# 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.
|
|
#
|
|
# - The lvalue of an assignment can only be an identifier.
|
|
|
|
.include "boot/definitions.inc"
|
|
|
|
.equ SOURCE_BUFFER_SIZE, 81920
|
|
|
|
.section .rodata
|
|
section_rodata: .ascii ".section .rodata\n"
|
|
.equ SECTION_RODATA_SIZE, . - section_rodata
|
|
section_text: .ascii ".section .text\n"
|
|
.equ SECTION_TEXT_SIZE, . - section_text
|
|
section_bss: .ascii ".section .bss\n"
|
|
.equ SECTION_BSS_SIZE, . - section_bss
|
|
global_start: .ascii ".global _start\n"
|
|
.equ GLOBAL_START_SIZE, . - global_start
|
|
prologue: .ascii "addi sp, sp, -96\nsw ra, 92(sp)\nsw s0, 88(sp)\naddi s0, sp, 96\n"
|
|
.equ PROLOGUE_SIZE, . - prologue
|
|
epilogue: .ascii "lw ra, 92(sp)\nlw s0, 88(sp)\naddi sp, sp, 96\nret\n"
|
|
.equ EPILOGUE_SIZE, . - epilogue
|
|
|
|
asm_exit: .ascii "li a0, 0\nli a7, 93\necall\n"
|
|
.equ ASM_EXIT_SIZE, . - asm_exit
|
|
asm_start: .ascii ".type _start, @function\n_start:\n"
|
|
.equ ASM_START_SIZE, . - asm_start
|
|
asm_and_a0_a1: .ascii "and a0, a0, a1\n"
|
|
.equ ASM_AND_A0_A1_SIZE, . - asm_and_a0_a1
|
|
asm_or_a0_a1: .ascii "or a0, a0, a1\n"
|
|
.equ ASM_OR_A0_A1_SIZE, . - asm_or_a0_a1
|
|
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_type_function: .ascii ", @function\n"
|
|
.equ ASM_TYPE_FUNCTION_SIZE, . - asm_type_function
|
|
asm_type_object: .ascii ", @object\n"
|
|
.equ ASM_TYPE_OBJECT_SIZE, . - asm_type_object
|
|
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
|
|
asm_preserve_parameters:
|
|
.ascii "sw a0, 84(sp)\nsw a1, 80(sp)\nsw a2, 76(sp)\nsw a2, 76(sp)\nsw a3, 72(sp)\nsw a4, 68(sp)\nsw a5, 64(sp)\n"
|
|
.equ ASM_PRESERVE_PARAMETERS_SIZE, . - asm_preserve_parameters
|
|
|
|
.section .bss
|
|
.type source_code, @object
|
|
source_code: .zero SOURCE_BUFFER_SIZE
|
|
|
|
.section .text
|
|
|
|
# Ignores the import.
|
|
.type _compile_import, @function
|
|
_compile_import:
|
|
# Prologue.
|
|
addi sp, sp, -24
|
|
sw ra, 20(sp)
|
|
sw s0, 16(sp)
|
|
addi s0, sp, 24
|
|
|
|
.Lcompile_import_loop:
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
li t0, TOKEN_IMPORT
|
|
lw t1, 0(sp)
|
|
bne t0, t1, .Lcompile_import_end
|
|
# a0 is set from the previous _tokenize_next call. Skip the module name.
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
j .Lcompile_import_loop
|
|
|
|
.Lcompile_import_end:
|
|
# Epilogue.
|
|
lw ra, 20(sp)
|
|
lw s0, 16(sp)
|
|
addi sp, sp, 24
|
|
ret
|
|
|
|
.type _build_binary_expression, @function
|
|
_build_binary_expression:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
li a0, 0
|
|
call _build_expression
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
lw t0, 12(sp)
|
|
|
|
li t1, TOKEN_AND
|
|
beq t0, t1, .Lbuild_binary_expression_and
|
|
|
|
li t1, TOKEN_OR
|
|
beq t0, t1, .Lbuild_binary_expression_or
|
|
|
|
li t1, TOKEN_PLUS
|
|
beq t0, t1, .Lbuild_binary_expression_plus
|
|
|
|
li t1, TOKEN_EQUALS
|
|
beq t0, t1, .Lbuild_binary_expression_equal
|
|
|
|
li t1, TOKEN_ASTERISK
|
|
beq t0, t1, .Lbuild_binary_expression_product
|
|
|
|
li t1, TOKEN_MINUS
|
|
beq t0, t1, .Lbuild_binary_expression_minus
|
|
|
|
j .Lbuild_binary_expression_end
|
|
|
|
.Lbuild_binary_expression_equal:
|
|
mv s1, a0 # Skip =.
|
|
li a0, 1
|
|
call _build_expression
|
|
la a0, asm_sub_a0_a1
|
|
li a1, ASM_SUB_A0_A1_SIZE
|
|
call _write_out
|
|
|
|
la a0, asm_seqz_a0
|
|
li a1, ASM_SEQZ_A0_SIZE
|
|
call _write_out
|
|
|
|
j .Lbuild_binary_expression_end
|
|
|
|
.Lbuild_binary_expression_and:
|
|
mv s1, a0 # Skip &.
|
|
li a0, 1
|
|
call _build_expression
|
|
la a0, asm_and_a0_a1
|
|
li a1, ASM_AND_A0_A1_SIZE
|
|
call _write_out
|
|
|
|
j .Lbuild_binary_expression_end
|
|
|
|
.Lbuild_binary_expression_or:
|
|
mv s1, a0 # Skip or.
|
|
li a0, 1
|
|
call _build_expression
|
|
la a0, asm_or_a0_a1
|
|
li a1, ASM_OR_A0_A1_SIZE
|
|
call _write_out
|
|
|
|
j .Lbuild_binary_expression_end
|
|
|
|
.Lbuild_binary_expression_plus:
|
|
mv s1, a0 # Skip +.
|
|
li a0, 1
|
|
call _build_expression
|
|
la a0, asm_add_a0_a1
|
|
li a1, ASM_ADD_A0_A1_SIZE
|
|
call _write_out
|
|
|
|
j .Lbuild_binary_expression_end
|
|
|
|
.Lbuild_binary_expression_minus:
|
|
mv s1, a0 # Skip -.
|
|
li a0, 1
|
|
call _build_expression
|
|
la a0, asm_sub_a0_a1
|
|
li a1, ASM_SUB_A0_A1_SIZE
|
|
call _write_out
|
|
|
|
j .Lbuild_binary_expression_end
|
|
|
|
.Lbuild_binary_expression_product:
|
|
mv s1, a0 # 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)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Checks whether the given identifier starts with "loca".
|
|
# Parameters:
|
|
# a0 - Pointer to the identifier.
|
|
# a1 - Identifier length.
|
|
#
|
|
# Sets a0 to 1 if the identifier starts with "loca", otherwise to 0.
|
|
.type _is_local_identifier, @function
|
|
_is_local_identifier:
|
|
# Prologue.
|
|
addi sp, sp, -16
|
|
sw ra, 12(sp)
|
|
sw s0, 8(sp)
|
|
addi s0, sp, 16
|
|
|
|
li t0, 0x61636f6c # loca
|
|
sw t0, 4(sp)
|
|
# a0 is already set.
|
|
addi a1, sp, 4
|
|
li a2, 4
|
|
call _memcmp
|
|
seqz a0, a0
|
|
|
|
# Epilogue.
|
|
lw ra, 12(sp)
|
|
lw s0, 8(sp)
|
|
addi sp, sp, 16
|
|
ret
|
|
|
|
# Checks whether the given identifier is a saved register name, like s1 or s2.
|
|
# Parameters:
|
|
# a0 - Pointer to the identifier.
|
|
# a1 - Identifier length.
|
|
#
|
|
# Sets a0 to 1 if the identifier is a preserved register, otherwise to 0.
|
|
.type _is_register_identifier, @function
|
|
_is_register_identifier:
|
|
# Prologue.
|
|
addi sp, sp, -8
|
|
sw ra, 4(sp)
|
|
sw s0, 0(sp)
|
|
addi s0, sp, 8
|
|
|
|
lbu a0, (a0)
|
|
addi a1, a1, -2
|
|
seqz a1, a1
|
|
addi t0, a0, -'s'
|
|
seqz t0, t0
|
|
and a0, a1, t0
|
|
|
|
# Epilogue.
|
|
lw ra, 4(sp)
|
|
lw s0, 0(sp)
|
|
addi sp, sp, 8
|
|
ret
|
|
|
|
# Parameters:
|
|
# a0 - Identifier length.
|
|
# a1 - Register number as character.
|
|
.type _compile_identifier_expression, @function
|
|
_compile_identifier_expression:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
sw a0, 20(sp) # Identifier length.
|
|
sw a1, 16(sp) # Register number as character.
|
|
|
|
mv a0, s1
|
|
lw a1, 20(sp)
|
|
call _is_local_identifier
|
|
bnez a0, .Lcompile_identifier_expression_local
|
|
|
|
mv a0, s1
|
|
lw a1, 20(sp)
|
|
call _is_register_identifier
|
|
bnez a0, .Lcompile_identifier_expression_saved
|
|
|
|
# Global identifier.
|
|
lw t1, 16(sp)
|
|
li t0, 0x00202c00 # \0,_
|
|
or t0, t0, t1
|
|
sw t0, 12(sp)
|
|
li t0, 0x6120616c # la a
|
|
sw t0, 8(sp)
|
|
addi a0, sp, 8
|
|
li a1, 7
|
|
call _write_out
|
|
|
|
mv a0, s1
|
|
lw a1, 20(sp)
|
|
call _write_out
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
lbu a0, (s1)
|
|
call _is_upper
|
|
beqz a0, .Lcompile_identifier_expression_end
|
|
|
|
lw t1, 16(sp)
|
|
li t0, 0x0a290061 # a\0)\n
|
|
sll t2, t1, 8
|
|
or t0, t0, t2
|
|
sw t0, 12(sp)
|
|
li t0, 0x28202c00 # \0, (
|
|
or t0, t0, t1
|
|
sw t0, 8(sp)
|
|
li t0, 0x6120776c # lw a
|
|
sw t0, 4(sp)
|
|
addi a0, sp, 4
|
|
li a1, 12
|
|
call _write_out
|
|
|
|
j .Lcompile_identifier_expression_end
|
|
|
|
.Lcompile_identifier_expression_saved:
|
|
li t0, 0x00202c00 # \0,_
|
|
lw t1, 16(sp)
|
|
or t0, t0, t1
|
|
sw t0, 12(sp)
|
|
li t0, 0x6120766d # mv a
|
|
sw t0, 8(sp)
|
|
addi a0, sp, 8
|
|
li a1, 7
|
|
call _write_out
|
|
|
|
mv a0, s1
|
|
lw a1, 20(sp)
|
|
call _write_out
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
j .Lcompile_identifier_expression_end
|
|
|
|
.Lcompile_identifier_expression_local:
|
|
lw t1, 16(sp)
|
|
li t0, 0x00202c00 # \0,_
|
|
or t0, t0, t1
|
|
sw t0, 12(sp)
|
|
li t0, 0x6120776c # lw a
|
|
sw t0, 8(sp)
|
|
addi a0, sp, 8
|
|
li a1, 7
|
|
call _write_out
|
|
|
|
mv a0, s1
|
|
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
|
|
|
|
li t0, 0x29707328 # (sp)
|
|
sw t0, 12(sp)
|
|
addi a0, sp, 12
|
|
li a1, 4
|
|
call _write_out
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
j .Lcompile_identifier_expression_end
|
|
|
|
.Lcompile_identifier_expression_end:
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Evalutes an expression and saves the result in a0.
|
|
#
|
|
# a0 - X in aX, the register number to save the result.
|
|
.type _build_expression, @function
|
|
_build_expression:
|
|
# Prologue.
|
|
addi sp, sp, -48
|
|
sw ra, 44(sp)
|
|
sw s0, 40(sp)
|
|
addi s0, sp, 48
|
|
|
|
addi a0, a0, '0' # Make the register number to a character.
|
|
sw a0, 36(sp) # And save it.
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 24
|
|
call _tokenize_next
|
|
sw a0, 20(sp)
|
|
|
|
lw a0, 24(sp)
|
|
|
|
li t0, TOKEN_MINUS
|
|
beq a0, t0, .Lbuild_expression_negate
|
|
|
|
li t0, TOKEN_AT
|
|
beq a0, t0, .Lbuild_expression_address
|
|
|
|
li t0, TOKEN_INTEGER
|
|
beq a0, t0, .Lbuild_expression_literal
|
|
|
|
lw a0, 32(sp)
|
|
lbu a0, (a0)
|
|
li t0, '_'
|
|
beq a0, t0, .Lbuild_expression_call
|
|
|
|
lw s1, 32(sp)
|
|
lw a0, 28(sp)
|
|
lw a1, 36(sp)
|
|
call _compile_identifier_expression
|
|
|
|
j .Lbuild_expression_advance
|
|
|
|
.Lbuild_expression_negate:
|
|
lw s1, 20(sp) # 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_end
|
|
|
|
.Lbuild_expression_address:
|
|
lw t1, 36(sp)
|
|
li t0, 0x20 # _
|
|
sw t0, 16(sp)
|
|
li t0, 0x2c707320 # _sp,
|
|
sw t0, 12(sp)
|
|
li t0, 0x2c006120 # _a\0,
|
|
sw t0, 8(sp)
|
|
sb t1, 10(sp)
|
|
li t0, 0x69646461 # addi
|
|
sw t0, 4(sp)
|
|
addi a0, sp, 4
|
|
li a1, 13
|
|
call _write_out
|
|
|
|
lw a0, 20(sp) # Skip @.
|
|
addi a1, sp, 24
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
lw a0, 32(sp)
|
|
lw a1, 28(sp)
|
|
addi a0, a0, 4 # Skip the "loca" variable prefix.
|
|
addi a1, a1, -4 # Skip the "loca" variable prefix.
|
|
call _write_out
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
j .Lbuild_expression_end
|
|
|
|
.Lbuild_expression_call:
|
|
lw a0, 20(sp)
|
|
addi a1, sp, 8
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
lw a0, 32(sp)
|
|
lw a1, 28(sp)
|
|
call _compile_call
|
|
|
|
j .Lbuild_expression_end
|
|
|
|
.Lbuild_expression_literal:
|
|
lw t1, 36(sp)
|
|
li t0, 0x00202c00 # \0,_
|
|
or t0, t0, t1
|
|
sw t0, 16(sp)
|
|
li t0, 0x6120696c # li a
|
|
sw t0, 12(sp)
|
|
addi a0, sp, 12
|
|
li a1, 7
|
|
call _write_out
|
|
|
|
lw a0, 32(sp)
|
|
lw a1, 28(sp)
|
|
call _write_out
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
j .Lbuild_expression_advance
|
|
|
|
.Lbuild_expression_advance:
|
|
lw s1, 20(sp)
|
|
|
|
.Lbuild_expression_end:
|
|
# Epilogue.
|
|
lw ra, 44(sp)
|
|
lw s0, 40(sp)
|
|
addi sp, sp, 48
|
|
ret
|
|
|
|
# Compiles an lvalue.
|
|
#
|
|
# Parameters:
|
|
# a0 - Pointer to the identifier.
|
|
# a1 - Identifier length.
|
|
.type _compile_designator_expression, @function
|
|
_compile_designator_expression:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
sw a0, 20(sp) # Identifier pointer.
|
|
sw a1, 16(sp) # Identifier length.
|
|
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _is_local_identifier
|
|
bnez a0, .Lcompile_designator_expression_local
|
|
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _is_register_identifier
|
|
bnez a0, .Lcompile_designator_expression_saved
|
|
|
|
.Lcompile_designator_expression_local:
|
|
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, '\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_designator_expression_end
|
|
|
|
.Lcompile_designator_expression_saved:
|
|
li t0, 0x20766d # mv_
|
|
sw t0, 12(sp)
|
|
addi a0, sp, 12
|
|
li a1, 3
|
|
call _write_out
|
|
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _write_out
|
|
|
|
li t0, 0x0a # \n
|
|
sw t0, 12(sp)
|
|
li t0, 0x3061202c # , a0
|
|
sw t0, 8(sp)
|
|
addi a0, sp, 8
|
|
li a1, 5
|
|
call _write_out
|
|
|
|
j .Lcompile_designator_expression_end
|
|
|
|
.Lcompile_designator_expression_end:
|
|
|
|
# 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
|
|
|
|
# Save the pointer to the identifier and its length on the stack.
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
lw t0, 0(sp)
|
|
|
|
li t1, TOKEN_ASSIGN
|
|
beq t0, t1, .Lcompile_identifier_assign
|
|
|
|
li t1, TOKEN_LEFT_PAREN
|
|
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_binary_expression
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _compile_designator_expression
|
|
|
|
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:
|
|
lbu t0, (s1)
|
|
li t1, 0x29 # )
|
|
beq t0, t1, .Lcompile_call_complete
|
|
|
|
.Lcompile_call_argument:
|
|
li a0, 0
|
|
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 6 arguments are supported with a0-a5.
|
|
# Save all arguments on the stack so they aren't overriden afterwards.
|
|
li a0, -4
|
|
mul a0, t0, a0
|
|
addi a0, a0, 60
|
|
call _printi
|
|
|
|
li t0, '\n'
|
|
sw t0, 8(sp)
|
|
li t0, 0x29707328 # (sp)
|
|
sw t0, 4(sp)
|
|
addi a0, sp, 4
|
|
li a1, 5
|
|
call _write_out
|
|
|
|
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-a5 registers and read them from stack.
|
|
# If this stack value contains garbage, the procedure just shouldn't use it.
|
|
la a0, asm_restore_parameters
|
|
li a1, ASM_RESTORE_PARAMETERS_SIZE
|
|
call _write_out
|
|
|
|
.Lcompile_call_perform:
|
|
li t0, 0x20
|
|
sw t0, 8(sp)
|
|
li t0, 0x6c6c6163 # call
|
|
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 a0, '\n'
|
|
call _put_char
|
|
|
|
addi s1, s1, 1 # Skip the close paren.
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Walks through the procedure definitions.
|
|
.type _compile_procedure_section, @function
|
|
_compile_procedure_section:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
.Lcompile_procedure_section_loop:
|
|
mv a0, s1
|
|
addi a1, sp, 4
|
|
call _tokenize_next
|
|
li t0, TOKEN_PROC
|
|
lw t1, 4(sp)
|
|
bne t0, t1, .Lcompile_procedure_section_end
|
|
|
|
call _compile_procedure
|
|
|
|
j .Lcompile_procedure_section_loop
|
|
|
|
.Lcompile_procedure_section_end:
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
.type _compile_module_declaration, @function
|
|
_compile_module_declaration:
|
|
# Prologue.
|
|
addi sp, sp, -24
|
|
sw ra, 20(sp)
|
|
sw s0, 16(sp)
|
|
addi s0, sp, 24
|
|
|
|
la a0, global_start
|
|
li a1, GLOBAL_START_SIZE
|
|
call _write_out
|
|
|
|
# Skip "program".
|
|
mv a0, s1
|
|
addi a1, sp, 4
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
# Epilogue.
|
|
lw ra, 20(sp)
|
|
lw s0, 16(sp)
|
|
addi sp, sp, 24
|
|
ret
|
|
|
|
.type _compile_constant_section, @function
|
|
_compile_constant_section:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 4
|
|
call _tokenize_next
|
|
li t0, TOKEN_CONST
|
|
lw t1, 4(sp)
|
|
bne t0, t1, .Lcompile_constant_section_end
|
|
mv s1, a0
|
|
|
|
la a0, section_rodata
|
|
li a1, SECTION_RODATA_SIZE
|
|
call _write_out
|
|
|
|
.Lcompile_constant_section_item:
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
|
|
lw t0, 12(sp)
|
|
li t1, TOKEN_IDENTIFIER
|
|
|
|
bne t0, t1, .Lcompile_constant_section_end
|
|
lw s1, 20(sp)
|
|
|
|
call _compile_constant
|
|
j .Lcompile_constant_section_item
|
|
|
|
.Lcompile_constant_section_end:
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
.type _compile_constant, @function
|
|
_compile_constant:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
addi a1, sp, 0
|
|
call _tokenize_next # Skip the assignment sign.
|
|
mv s1, a0
|
|
# Write identifier the identifier.
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _write_out
|
|
|
|
# : .long
|
|
li t0, 0x20676e6f # ong_
|
|
sw t0, 4(sp)
|
|
li t0, 0x6c2e203a # : .l
|
|
sw t0, 0(sp)
|
|
mv a0, sp
|
|
li a1, 8
|
|
call _write_out
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
lw a0, 20(sp) # Save the literal pointer before advancing it.
|
|
lw a1, 16(sp) # The literal length.
|
|
call _write_out
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
.type _compile_variable_section, @function
|
|
_compile_variable_section:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 4
|
|
call _tokenize_next
|
|
li t0, TOKEN_VAR
|
|
lw t1, 4(sp)
|
|
bne t0, t1, .Lcompile_variable_section_end
|
|
mv s1, a0
|
|
|
|
la a0, section_bss
|
|
li a1, SECTION_BSS_SIZE
|
|
call _write_out
|
|
|
|
.Lcompile_variable_section_item:
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
lw t0, 12(sp)
|
|
li t1, TOKEN_IDENTIFIER
|
|
|
|
bne t0, t1, .Lcompile_variable_section_end
|
|
lw s1, 20(sp) # Advance to the beginning of the variable name.
|
|
|
|
call _compile_variable
|
|
j .Lcompile_variable_section_item
|
|
|
|
.Lcompile_variable_section_end:
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Compile a global variable.
|
|
.type _compile_variable, @function
|
|
_compile_variable:
|
|
# Prologue.
|
|
addi sp, sp, -48
|
|
sw ra, 44(sp)
|
|
sw s0, 40(sp)
|
|
addi s0, sp, 48
|
|
|
|
# Save the identifier on the stack since it should emitted multiple times.
|
|
mv a0, s1
|
|
addi a1, sp, 28
|
|
call _tokenize_next
|
|
addi a1, sp, 4
|
|
call _tokenize_next # Skip the colon in front of the type.
|
|
addi a1, sp, 4
|
|
call _tokenize_next # Skip the opening bracket.
|
|
addi a1, sp, 16
|
|
call _tokenize_next # Save the array size on the stack since it has to be emitted multiple times.
|
|
addi a1, sp, 4
|
|
call _tokenize_next # Skip the closing bracket.
|
|
addi a1, sp, 4
|
|
call _tokenize_next # Skip the type.
|
|
mv s1, a0
|
|
|
|
# .type identifier, @object
|
|
la a0, asm_type
|
|
li a1, ASM_TYPE_SIZE
|
|
call _write_out
|
|
|
|
lw a0, 36(sp)
|
|
lw a1, 32(sp)
|
|
call _write_out
|
|
|
|
la a0, asm_type_object
|
|
li a1, ASM_TYPE_OBJECT_SIZE
|
|
call _write_out
|
|
|
|
# identifier: .zero size
|
|
lw a0, 36(sp)
|
|
lw a1, 32(sp)
|
|
call _write_out
|
|
|
|
li t0, 0x206f7265 # ero_
|
|
sw t0, 12(sp)
|
|
li t0, 0x7a2e203a # : .z
|
|
sw t0, 8(sp)
|
|
addi a0, sp, 8
|
|
li a1, 8
|
|
call _write_out
|
|
|
|
lw a0, 24(sp)
|
|
lw a1, 20(sp)
|
|
call _write_out
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
# Epilogue.
|
|
lw ra, 44(sp)
|
|
lw s0, 40(sp)
|
|
addi sp, sp, 48
|
|
ret
|
|
|
|
.type _compile_type_expression, @function
|
|
_compile_type_expression:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
.Lcompile_type_expression_type:
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
lw t0, 12(sp)
|
|
|
|
# Skip the pointer designator and handle the rest of the type.
|
|
li t1, TOKEN_HAT
|
|
beq t0, t1, .Lcompile_type_expression_type
|
|
|
|
/* DEBUG */
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _write_error
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
.type _compile_parameters, @function
|
|
_compile_parameters:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
mv s1, a0 # Skip the opening paren.
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
|
|
lw t0, 12(sp)
|
|
li t1, TOKEN_RIGHT_PAREN
|
|
beq t0, t1, .Lcompile_parameters_end
|
|
# When this is not the right paren, it is an identifier.
|
|
mv s1, a0
|
|
|
|
.Lcompile_parameters_parameter:
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
mv s1, a0 # Skip the ":" in front of the type.
|
|
|
|
call _compile_type_expression
|
|
# Read the comma between the parameters or a closing paren.
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
|
|
lw t0, 0(sp)
|
|
li t1, TOKEN_COMMA
|
|
bne t0, t1, .Lcompile_parameters_end
|
|
# If it is a comma, read the name of the next parameter.
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
j .Lcompile_parameters_parameter
|
|
|
|
.Lcompile_parameters_end:
|
|
mv s1, a0 # Skip the closing paren.
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
.type _compile_procedure, @function
|
|
_compile_procedure:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next # Skip proc.
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
lw a0, 16(sp)
|
|
lw a1, 20(sp)
|
|
call _write_procedure_head
|
|
|
|
call _compile_parameters
|
|
# Skip all declarations until we find the "begin" keyword, denoting the
|
|
# beginning of the procedure body.
|
|
.Lcompile_procedure_begin:
|
|
mv a0, s1
|
|
addi a1, sp, 4
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
lw t0, 4(sp)
|
|
li t1, TOKEN_BEGIN
|
|
bne t0, t1, .Lcompile_procedure_begin
|
|
|
|
# Generate the procedure prologue with a predefined stack size.
|
|
la a0, prologue
|
|
li a1, PROLOGUE_SIZE
|
|
call _write_out
|
|
|
|
# Save passed arguments on the stack.
|
|
la a0, asm_preserve_parameters
|
|
li a1, ASM_PRESERVE_PARAMETERS_SIZE
|
|
call _write_out
|
|
|
|
# Generate the body of the procedure.
|
|
call _compile_statements
|
|
mv s1, a0 # Skip end.
|
|
|
|
# Generate the procedure epilogue with a predefined stack size.
|
|
la a0, epilogue
|
|
li a1, EPILOGUE_SIZE
|
|
call _write_out
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Compiles a goto statement to an uncoditional jump.
|
|
.type _compile_goto, @function
|
|
_compile_goto:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next # Skip the goto keyword.
|
|
addi a1, sp, 0
|
|
call _tokenize_next # We should be on dot the label is beginning with.
|
|
addi a1, sp, 0
|
|
call _tokenize_next# Save the label name.
|
|
mv s1, a0
|
|
|
|
li t0, 0x2e206a # j .
|
|
sw t0, 12(sp)
|
|
addi a0, sp, 12
|
|
li a1, 3
|
|
call _write_out
|
|
|
|
lw a0, 8(sp) # Saved dot position.
|
|
lw a1, 4(sp)
|
|
call _write_out
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Rewrites a label to assembly.
|
|
.type _compile_label, @function
|
|
_compile_label:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 8
|
|
call _tokenize_next # Dot starting the label.
|
|
addi a1, sp, 8
|
|
call _tokenize_next
|
|
mv s1, a0
|
|
|
|
li a0, '.'
|
|
call _put_char
|
|
lw a0, 16(sp)
|
|
lw a1, 12(sp)
|
|
call _write_out
|
|
li a0, ':'
|
|
call _put_char
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Just skips the return keyword and evaluates the return expression.
|
|
.type _compile_return, @function
|
|
_compile_return:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 12
|
|
call _tokenize_next
|
|
mv s1, a0 # Skip return.
|
|
|
|
call _build_binary_expression
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
.type _compile_if, @function
|
|
_compile_if:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
mv s1, a0 # Skip the if.
|
|
|
|
call _build_binary_expression
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
mv s1, a0 # Skip the then.
|
|
|
|
# Label prefix.
|
|
li t0, 0x66694c2e # .Lif
|
|
sw t0, 20(sp)
|
|
|
|
li t0, 0x202c3061 # a0,_
|
|
sw t0, 16(sp)
|
|
li t0, 0x207a7165 # eqz_
|
|
sw t0, 12(sp)
|
|
li t0, 0x62626262 # bbbb
|
|
sb t0, 11(sp)
|
|
|
|
addi a0, sp, 11
|
|
li a1, 13
|
|
call _write_out
|
|
|
|
# Write the label counter.
|
|
mv a0, s2
|
|
call _printi
|
|
|
|
li a0, '\n'
|
|
call _put_char
|
|
|
|
call _compile_statements
|
|
mv s1, a0 # Skip end.
|
|
|
|
# Write the label prefix.
|
|
addi a0, sp, 20
|
|
li a1, 4
|
|
call _write_out
|
|
|
|
# Write the label counter.
|
|
mv a0, s2
|
|
call _printi
|
|
|
|
# Finalize the label.
|
|
li t0, 0x0a3a # :\n
|
|
sh t0, 16(sp)
|
|
addi a0, sp, 16
|
|
li a1, 2
|
|
call _write_out
|
|
|
|
addi s2, s2, 1 # Increment the label counter.
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Writes:
|
|
# .type identifier, @function
|
|
# identifier:
|
|
#
|
|
# Parameters:
|
|
# a0 - Identifier length.
|
|
# a0 - Identifier pointer.
|
|
.type _write_procedure_head, @function
|
|
_write_procedure_head:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
sw a0, 16(sp)
|
|
sw a1, 20(sp)
|
|
|
|
# .type identifier, @function
|
|
la a0, asm_type
|
|
li a1, ASM_TYPE_SIZE
|
|
call _write_out
|
|
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _write_out
|
|
|
|
la a0, asm_type_function
|
|
li a1, ASM_TYPE_FUNCTION_SIZE
|
|
call _write_out
|
|
|
|
lw a0, 20(sp)
|
|
lw a1, 16(sp)
|
|
call _write_out
|
|
|
|
li t0, 0x0a3a # :\n
|
|
sw t0, 12(sp)
|
|
addi a0, sp, 12
|
|
li a1, 2
|
|
call _write_out
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Compiles a list of statements delimited by semicolons.
|
|
#
|
|
# Sets a0 to the end of the token finishing the list
|
|
# (should be the "end" token in a valid program).
|
|
.type _compile_statements, @function
|
|
_compile_statements:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
# Generate the body of the procedure.
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
lw t0, 0(sp)
|
|
li t1, TOKEN_END
|
|
|
|
beq t0, t1, .Lcompile_statements_end
|
|
|
|
.Lcompile_statements_body:
|
|
call _compile_statement
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
lw t0, 0(sp)
|
|
li t1, TOKEN_SEMICOLON
|
|
|
|
bne t0, t1, .Lcompile_statements_end
|
|
mv s1, a0
|
|
|
|
j .Lcompile_statements_body
|
|
|
|
.Lcompile_statements_end:
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Checks for the type of the current statement and compiles it.
|
|
.type _compile_statement, @function
|
|
_compile_statement:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 0
|
|
call _tokenize_next
|
|
lw t0, 0(sp)
|
|
|
|
li t1, TOKEN_IDENTIFIER
|
|
beq t0, t1, .Lcompile_statement_identifier
|
|
|
|
li t1, TOKEN_GOTO
|
|
beq t0, t1, .Lcompile_statement_goto
|
|
|
|
li t1, TOKEN_RETURN
|
|
beq t0, t1, .Lcompile_statement_return
|
|
|
|
li t1, TOKEN_IF
|
|
beq t0, t1, .Lcompile_statement_if
|
|
|
|
li t1, TOKEN_DOT
|
|
beq t0, t1, .Lcompile_statement_label
|
|
|
|
unimp # Else.
|
|
|
|
.Lcompile_statement_if:
|
|
call _compile_if
|
|
j .Lcompile_statement_end
|
|
|
|
.Lcompile_statement_label:
|
|
call _compile_label
|
|
j .Lcompile_statement_end
|
|
|
|
.Lcompile_statement_return:
|
|
call _compile_return
|
|
j .Lcompile_statement_end
|
|
|
|
.Lcompile_statement_goto:
|
|
call _compile_goto
|
|
j .Lcompile_statement_end
|
|
|
|
.Lcompile_statement_identifier:
|
|
call _compile_identifier
|
|
j .Lcompile_statement_end
|
|
|
|
.Lcompile_statement_end:
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
# Prints ".section .text" and exits.
|
|
.type _compile_text_section, @function
|
|
_compile_text_section:
|
|
# Prologue.
|
|
addi sp, sp, -16
|
|
sw ra, 12(sp)
|
|
sw s0, 8(sp)
|
|
addi s0, sp, 16
|
|
|
|
la a0, section_text
|
|
li a1, SECTION_TEXT_SIZE
|
|
call _write_out
|
|
|
|
# Epilogue.
|
|
lw ra, 12(sp)
|
|
lw s0, 8(sp)
|
|
addi sp, sp, 16
|
|
ret
|
|
|
|
.type _compile_entry_point, @function
|
|
_compile_entry_point:
|
|
# Prologue.
|
|
addi sp, sp, -32
|
|
sw ra, 28(sp)
|
|
sw s0, 24(sp)
|
|
addi s0, sp, 32
|
|
|
|
# .type _start, @function
|
|
la a0, asm_start
|
|
li a1, ASM_START_SIZE
|
|
call _write_out
|
|
|
|
mv a0, s1
|
|
addi a1, sp, 4
|
|
call _tokenize_next
|
|
mv s1, a0 # Skip begin.
|
|
|
|
# Generate the body of the procedure.
|
|
call _compile_statements
|
|
mv s1, a0 # Skip end.
|
|
|
|
la a0, asm_exit
|
|
li a1, ASM_EXIT_SIZE
|
|
call _write_out
|
|
|
|
# Epilogue.
|
|
lw ra, 28(sp)
|
|
lw s0, 24(sp)
|
|
addi sp, sp, 32
|
|
ret
|
|
|
|
.type _compile, @function
|
|
_compile:
|
|
# Prologue.
|
|
addi sp, sp, -16
|
|
sw ra, 12(sp)
|
|
sw s0, 8(sp)
|
|
addi s0, sp, 16
|
|
|
|
call _compile_module_declaration
|
|
call _compile_import
|
|
call _compile_constant_section
|
|
call _compile_variable_section
|
|
call _compile_text_section
|
|
call _compile_procedure_section
|
|
call _compile_entry_point
|
|
|
|
# Epilogue.
|
|
lw ra, 12(sp)
|
|
lw s0, 8(sp)
|
|
addi sp, sp, 16
|
|
ret
|
|
|
|
# Entry point.
|
|
.type _start, @function
|
|
_start:
|
|
# Read the source from the standard input.
|
|
la a0, source_code
|
|
li a1, SOURCE_BUFFER_SIZE # Buffer size.
|
|
call _read_file
|
|
|
|
li s2, 1
|
|
call symbol_table_build
|
|
call _compile
|
|
|
|
# Call exit.
|
|
li a0, 0 # Use 0 return code.
|
|
call _exit
|