diff options
| author | Eugen Wissner <belka@caraus.de> | 2025-08-28 22:45:42 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2025-08-30 01:29:00 +0200 |
| commit | 627975775c941130975ce0f9dbef08c723e69794 (patch) | |
| tree | 0f7f4c2c6d83420262d89ff720e6435a67410c9a /boot/stage1.s | |
| parent | e614d43ea9af078301d538fcddb19e83eed7e879 (diff) | |
| download | elna-627975775c941130975ce0f9dbef08c723e69794.tar.gz | |
Start over
Diffstat (limited to 'boot/stage1.s')
| -rw-r--r-- | boot/stage1.s | 1850 |
1 files changed, 685 insertions, 1165 deletions
diff --git a/boot/stage1.s b/boot/stage1.s index a45d8ab..c81a7f8 100644 --- a/boot/stage1.s +++ b/boot/stage1.s @@ -2,586 +2,276 @@ # 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. -# s3 - Dynamic memory region. -# -# - 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 +.equ SYS_READ, 63 +.equ SYS_WRITE, 64 +.equ SYS_EXIT, 93 +.equ SYS_MMAP2, 222 +.equ STDIN, 0 +.equ STDOUT, 1 +.equ STDERR, 2 -.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 lex_next - li t0, TOKEN_IMPORT - lw t1, 0(sp) - bne t0, t1, .Lcompile_import_end - # a0 is set from the previous lex_next call. Skip the module name. - addi a1, sp, 0 - call lex_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 +.section .rodata -.type compile_binary_expression, @function -compile_binary_expression: - # Prologue. - addi sp, sp, -32 - sw ra, 28(sp) - sw s0, 24(sp) - addi s0, sp, 32 +.type keyword_equ, @object +keyword_equ: .ascii ".equ" +.equ KEYWORD_EQU_SIZE, 4 - li a0, 0 - call compile_expression +.type keyword_section, @object +keyword_section: .ascii ".section" +.equ KEYWORD_SECTION_SIZE, 8 - mv a0, s1 - addi a1, sp, 12 - call lex_next - lw t0, 12(sp) +.type keyword_type, @object +keyword_type: .ascii ".type" +.equ KEYWORD_TYPE_SIZE, 5 - li t1, TOKEN_AND - beq t0, t1, .Lcompile_binary_expression_and +.type keyword_type_object, @object +keyword_type_object: .ascii "object" +.equ KEYWORD_TYPE_OBJECT_SIZE, 6 - li t1, TOKEN_OR - beq t0, t1, .Lcompile_binary_expression_or +.type keyword_type_function, @object +keyword_type_function: .ascii "function" +.equ KEYWORD_TYPE_FUNCTION_SIZE, 8 - li t1, TOKEN_PLUS - beq t0, t1, .Lcompile_binary_expression_plus +.type keyword_ret, @object +keyword_ret: .ascii "ret" +.equ KEYWORD_RET_SIZE, 3 - li t1, TOKEN_EQUALS - beq t0, t1, .Lcompile_binary_expression_equal +.type keyword_global, @object +keyword_global: .ascii ".globl" +.equ KEYWORD_GLOBAL_SIZE, 6 - li t1, TOKEN_ASTERISK - beq t0, t1, .Lcompile_binary_expression_product +.type keyword_proc, @object +keyword_proc: .ascii "proc " +.equ KEYWORD_PROC_SIZE, 5 - li t1, TOKEN_MINUS - beq t0, t1, .Lcompile_binary_expression_minus +.type keyword_end, @object +keyword_end: .ascii "end" +.equ KEYWORD_END_SIZE, 3 - j .Lcompile_binary_expression_end +.type keyword_begin, @object +keyword_begin: .ascii "begin" +.equ KEYWORD_BEGIN_SIZE, 5 -.Lcompile_binary_expression_equal: - mv s1, a0 # Skip =. - li a0, 1 - call compile_expression - li a0, ASM_SUB_A0_A1_SIZE - la a1, asm_sub_a0_a1 - call _write_s +.type keyword_var, @object +keyword_var: .ascii "var" +.equ KEYWORD_VAR_SIZE, 3 - li a0, ASM_SEQZ_A0_SIZE - la a1, asm_seqz_a0 - call _write_s +.type asm_prologue, @object +asm_prologue: .string "\taddi sp, sp, -32\n\tsw ra, 28(sp)\n\tsw s0, 24(sp)\n\taddi s0, sp, 32\n" - j .Lcompile_binary_expression_end +.type asm_epilogue, @object +asm_epilogue: .string "\tlw ra, 28(sp)\n\tlw s0, 24(sp)\n\taddi sp, sp, 32\n\tret\n" -.Lcompile_binary_expression_and: - mv s1, a0 # Skip &. - li a0, 1 - call compile_expression - li a0, ASM_AND_A0_A1_SIZE - la a1, asm_and_a0_a1 - call _write_s +.type asm_type_directive, @object +asm_type_directive: .string ".type " - j .Lcompile_binary_expression_end +.type asm_type_function, @object +asm_type_function: .string ", @function\n" -.Lcompile_binary_expression_or: - mv s1, a0 # Skip or. - li a0, 1 - call compile_expression - li a0, ASM_OR_A0_A1_SIZE - la a1, asm_or_a0_a1 - call _write_s +.type asm_colon, @object +asm_colon: .string ":\n" - j .Lcompile_binary_expression_end +.type asm_call, @object +asm_call: .string "\tcall " -.Lcompile_binary_expression_plus: - mv s1, a0 # Skip +. - li a0, 1 - call compile_expression - li a0, ASM_ADD_A0_A1_SIZE - la a1, asm_add_a0_a1 - call _write_s +.section .bss - j .Lcompile_binary_expression_end +.type source_code, @object +source_code: .zero SOURCE_BUFFER_SIZE -.Lcompile_binary_expression_minus: - mv s1, a0 # Skip -. - li a0, 1 - call compile_expression - li a0, ASM_SUB_A0_A1_SIZE - la a1, asm_sub_a0_a1 - call _write_s +.type source_code_position, @object +source_code_position: .word 0 - j .Lcompile_binary_expression_end +.section .text -.Lcompile_binary_expression_product: - mv s1, a0 # Skip *. - li a0, 1 - call compile_expression - li a0, ASM_MUL_A0_A1_SIZE - la a1, asm_mul_a0_a1 - call _write_s +# Reads standard input into a buffer. +# a0 - Buffer pointer. +# a1 - Buffer size. +# +# Returns the amount of bytes written in a0. +.type _read_file, @function +_read_file: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - j .Lcompile_binary_expression_end + mv a2, a1 + mv a1, a0 + li a0, STDIN + li a7, SYS_READ + ecall -.Lcompile_binary_expression_end: # Epilogue. lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret -# Looks for a register that can be used to calculate a symbol address. Writes it -# as string, like sp or s0 into the provided buffer. -# -# Parameters: -# a0 - Symbol info pointer. -# a1 - Output buffer. -# -# Sets a0 to the length of register name written or 0. -.type take_address, @function -take_address: - beqz a0, .Ltake_address_undefined - lw t0, 0(a0) - - li t1, INFO_PARAMETER - beq t0, t1, .Ltake_address_parameter - - li t1, INFO_LOCAL - beq t0, t1, .Ltake_address_local - - j .Ltake_address_undefined - -.Ltake_address_parameter: - li t0, 0x3073 # s0 - sh t0, (a1) - - li a0, 2 - - j .Ltake_address_end - -.Ltake_address_local: - li t0, 0x7073 # (sp) - sh t0, (a1) - - li a0, 2 - - j .Ltake_address_end - -.Ltake_address_undefined: - li a0, 0 - -.Ltake_address_end: - ret - -# Parameters: -# a0 - Identifier length. -# a1 - Register number as character. -.type compile_identifier_expression, @function -compile_identifier_expression: +# Writes a character from a0 into the standard output. +.type _write_c, @function +_write_c: # 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. - - lw a0, 20(sp) - mv a1, s1 - call symbol_table_lookup - sw a0, 12(sp) - - beqz a0, .Lcompile_identifier_expression_by_name - lw t0, 0(a0) - - j .Lcompile_identifier_expression_by_address - -.Lcompile_identifier_expression_by_name: - # Global identifier. - lw t1, 16(sp) - li t0, 0x00202c00 # \0,_ - or t0, t0, t1 - sw t0, 8(sp) - li t0, 0x6120616c # la a - sw t0, 4(sp) - li a0, 7 - addi a1, sp, 4 - call _write_s - - lw a0, 20(sp) - mv a1, s1 - call _write_s - - li a0, '\n' - call _write_c - - 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, 8(sp) - li t0, 0x28202c00 # \0, ( - or t0, t0, t1 - sw t0, 4(sp) - li t0, 0x6120776c # lw a - sw t0, 0(sp) - li a0, 12 - addi a1, sp, 0 - call _write_s - - j .Lcompile_identifier_expression_end - -.Lcompile_identifier_expression_by_address: - lw t1, 16(sp) - li t0, 0x00202c00 # \0,_ - or t0, t0, t1 - sw t0, 8(sp) - li t0, 0x6120776c # lw a - sw t0, 4(sp) - li a0, 7 - addi a1, sp, 4 - call _write_s - - lw a0, 12(sp) - lw a0, 8(a0) - call _write_i - - li a0, '(' - call _write_c - - lw a0, 12(sp) - addi a1, sp, 4 - call take_address - addi a1, sp, 4 - call _write_s - - li a0, ')' - call _write_c - li a0, '\n' - call _write_c - - j .Lcompile_identifier_expression_end + sb a0, 20(sp) + li a0, STDOUT + addi a1, sp, 20 + li a2, 1 + li a7, SYS_WRITE + ecall -.Lcompile_identifier_expression_end: # Epilogue. lw ra, 28(sp) lw s0, 24(sp) - addi sp, sp, 32 + add sp, sp, 32 ret -# Evalutes an expression and saves the result in a0. +# Write null terminated string. # -# a0 - X in aX, the register number to save the result. -.type compile_expression, @function -compile_expression: +# Parameters: +# a0 - String. +.type _write_z, @function +_write_z: # 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. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - mv a0, s1 - addi a1, sp, 24 - call lex_next sw a0, 20(sp) - lw t0, 24(sp) - - li t1, TOKEN_MINUS - beq t0, t1, .Lcompile_expression_negate - - li t1, TOKEN_AT - beq t0, t1, .Lcompile_expression_address - - li t1, TOKEN_INTEGER - beq t0, t1, .Lcompile_expression_literal - - addi a1, sp, 8 - call lex_next - lw t0, 8(sp) - li t1, TOKEN_LEFT_PAREN - beq t0, t1, .Lcompile_expression_call - - lw s1, 32(sp) - lw a0, 28(sp) - lw a1, 36(sp) - call compile_identifier_expression +.write_z_loop: + # Check for 0 character. + lb a0, (a0) + beqz a0, .write_z_end - j .Lcompile_expression_advance - -.Lcompile_expression_negate: - lw s1, 20(sp) # Skip the -. - mv a0, zero - call compile_expression - - li a0, ASM_NEG_A0_SIZE - la a1, asm_neg_a0 - call _write_s - - j .Lcompile_expression_end + # Print a character. + li a0, STDOUT + lw a1, 20(sp) + li a2, 1 + li a7, SYS_WRITE + ecall -.Lcompile_expression_address: + # Advance the input string by one byte. lw a0, 20(sp) - mv s1, a0 # Skip @. - - lw a0, 36(sp) - call compile_at_expression + addi a0, a0, 1 + sw a0, 20(sp) - j .Lcompile_expression_end + j .write_z_loop -.Lcompile_expression_call: - mv s1, a0 +.write_z_end: + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret - lw a0, 32(sp) - lw a1, 28(sp) - call compile_call +# Detects if a0 is an uppercase character. Sets a0 to 1 if so, otherwise to 0. +.type _is_upper, @function +_is_upper: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - j .Lcompile_expression_end + li t0, 'A' - 1 + sltu t1, t0, a0 # t1 = a0 >= 'A' -.Lcompile_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) - li a0, 7 - addi a1, sp, 12 - call _write_s + sltiu t2, a0, 'Z' + 1 # t2 = a0 <= 'Z' + and a0, t1, t2 # t1 = a0 >= 'A' & a0 <= 'Z' - lw a0, 28(sp) - lw a1, 32(sp) - call _write_s + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret - li a0, '\n' - call _write_c +# Detects if a0 is an lowercase character. Sets a0 to 1 if so, otherwise to 0. +.type _is_lower, @function +_is_lower: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - j .Lcompile_expression_advance + li t0, 'a' - 1 + sltu t2, t0, a0 # t2 = a0 >= 'a' -.Lcompile_expression_advance: - lw s1, 20(sp) + sltiu t3, a0, 'z' + 1 # t3 = a0 <= 'z' + and a0, t2, t3 # t2 = a0 >= 'a' & a0 <= 'z' -.Lcompile_expression_end: # Epilogue. - lw ra, 44(sp) - lw s0, 40(sp) - addi sp, sp, 48 + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 ret -# Expression taking an identifier address. +# Detects if the passed character is a 7-bit alpha character or an underscore. # -# Parameters: -# a0 - Register number as character -.type compile_at_expression, @function -compile_at_expression: +# Paramters: +# a0 - Tested character. +# +# Sets a0 to 1 if the character is an alpha character or underscore, sets it to 0 otherwise. +.type _is_alpha, @function +_is_alpha: # Prologue. - addi sp, sp, -48 - sw ra, 44(sp) - sw s0, 40(sp) - addi s0, sp, 48 - - sw a0, 36(sp) - - mv a0, s1 - addi a1, sp, 24 - call lex_next - mv s1, a0 + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - lw a0, 28(sp) - lw a1, 32(sp) - call symbol_table_lookup sw a0, 20(sp) - li t0, 0x20 # _ - sb t0, 12(sp) - - # lw a0, 28(sp) - lw a1, 32(sp) - addi a1, sp, 13 - call take_address - - lw t1, 36(sp) - li t0, 0x2c006120 # _a\0, - sw t0, 8(sp) - sb t1, 10(sp) - li t0, 0x69646461 # addi - sw t0, 4(sp) - addi a0, a0, 9 # The length returned by take_address + the instruction. - addi a1, sp, 4 - call _write_s - - li a0, ',' - call _write_c - li a0, ' ' - call _write_c + call _is_upper + sw a0, 16(sp) lw a0, 20(sp) - lw a0, 8(a0) - call _write_i + call _is_lower - j .Lcompile_at_expression_end + lw t0, 20(sp) + xori t1, t0, '_' + seqz t1, t1 -.Lcompile_at_expression_end: - li a0, '\n' - call _write_c + lw t0, 16(sp) + or a0, a0, t0 + or a0, a0, t1 # Epilogue. - lw ra, 44(sp) - lw s0, 40(sp) - addi sp, sp, 48 + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 ret -# Compiles an lvalue. +# Detects whether the passed character is a digit +# (a value between 0 and 9). # # Parameters: -# a0 - Pointer to the identifier. -# a1 - Identifier length. -.type compile_designator_expression, @function -compile_designator_expression: +# a0 - Exemined value. +# +# Sets a0 to 1 if it is a digit, to 0 otherwise. +.type _is_digit, @function +_is_digit: # 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. + li t0, '0' - 1 + sltu t1, t0, a0 # t1 = a0 >= '0' - /* DEBUG - lw a0, 20(sp) - lw a1, 16(sp) - call _write_error */ + sltiu t2, a0, '9' + 1 # t2 = a0 <= '9' -.Lcompile_designator_expression_by_address: - lw a0, 16(sp) - lw a1, 20(sp) - call symbol_table_lookup - sw a0, 12(sp) - - li t0, 0x202c30 # 0,_ - sw t0, 8(sp) - li t0, 0x61207773 # sw a - sw t0, 4(sp) - li a0, 7 - addi a1, sp, 4 - call _write_s - - lw a0, 12(sp) - lw a0, 8(a0) - call _write_i - - li a0, '(' - call _write_c - - lw a0, 12(sp) - addi a1, sp, 4 - call take_address - addi a1, sp, 4 - call _write_s - - li a0, ')' - call _write_c - li a0, '\n' - call _write_c + and a0, t1, t2 # Epilogue. lw ra, 28(sp) @@ -589,624 +279,452 @@ compile_designator_expression: addi sp, sp, 32 ret -# Compiles a statement beginning with an identifier. +# Reads the next token. # -# 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: +# Returns token length in a0. +.type _read_token, @function +_read_token: # 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 lex_next - addi a1, sp, 0 - call lex_next - mv s1, a0 - - lw t0, 0(sp) + la t0, source_code_position # Token pointer. + lw t0, (t0) + sw t0, 20(sp) # Current token position. + sw zero, 16(sp) # Token length. - li t1, TOKEN_LEFT_PAREN - beq t0, t1, .Lcompile_identifier_call +.read_token_loop: + lb t0, (t0) # Current character. - li t1, TOKEN_ASSIGN - beq t0, t1, .Lcompile_identifier_assign + # First we try to read a derictive. + # A derictive can contain a dot and characters. + li t1, '.' + beq t0, t1, .read_token_next - j .Lcompile_identifier_end + lw a0, 20(sp) + lb a0, (a0) + call _is_alpha + bnez a0, .read_token_next -.Lcompile_identifier_call: lw a0, 20(sp) - lw a1, 16(sp) - call compile_call + lb a0, (a0) + call _is_digit + bnez a0, .read_token_next - j .Lcompile_identifier_end + j .read_token_end -.Lcompile_identifier_assign: - call compile_binary_expression - lw a0, 20(sp) - lw a1, 16(sp) - call compile_designator_expression +.read_token_next: + # Advance the source code position and token length. + lw t0, 16(sp) + addi t0, t0, 1 + sw t0, 16(sp) + + lw t0, 20(sp) + addi t0, t0, 1 + sw t0, 20(sp) - j .Lcompile_identifier_end + j .read_token_loop + +.read_token_end: + lw a0, 16(sp) -.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. +# a0 - First pointer. +# a1 - Second pointer. +# a2 - The length to compare. # -# Returns the procedure result in a0. -.type compile_call, @function -compile_call: +# Returns 0 in a0 if memory regions are equal. +.type _memcmp, @function +_memcmp: # 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: + mv t0, a0 li a0, 0 - call compile_expression - - li t0, 0x202c30 # 0,_ - sw t0, 8(sp) - li t0, 0x61207773 # sw a - sw t0, 4(sp) - li a0, 7 - addi a1, sp, 4 - call _write_s - - 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 _write_i - - li t0, '\n' - sw t0, 8(sp) - li t0, 0x29707328 # (sp) - sw t0, 4(sp) - li a0, 5 - addi a1, sp, 4 - call _write_s - - 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) +.Lmemcmp_loop: + beqz a2, .Lmemcmp_end -.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. - li a0, ASM_RESTORE_PARAMETERS_SIZE - la a1, asm_restore_parameters - call _write_s + lbu t1, (t0) + lbu t2, (a1) + sub a0, t1, t2 -.Lcompile_call_perform: - li t0, 0x20 - sw t0, 8(sp) - li t0, 0x6c6c6163 # call - sw t0, 4(sp) - li a0, 5 - addi a1, sp, 4 - call _write_s - - lw a0, 16(sp) - lw a1, 20(sp) - call _write_s + bnez a0, .Lmemcmp_end - li a0, '\n' - call _write_c + addi t0, t0, 1 + addi a1, a1, 1 + addi a2, a2, -1 - addi s1, s1, 1 # Skip the close paren. + j .Lmemcmp_loop +.Lmemcmp_end: # 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: +# Advances the token stream by a0 bytes. +.type _advance_token, @function +_advance_token: # 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 lex_next - li t0, TOKEN_PROC - lw t1, 4(sp) - bne t0, t1, .Lcompile_procedure_section_end - - call compile_procedure - - j .Lcompile_procedure_section_loop + # Skip the .equ directive. + la t0, source_code_position + lw t1, (t0) + add t1, t1, a0 + sw t1, (t0) -.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: +.type _compile_section, @function +_compile_section: # Prologue. - addi sp, sp, -24 - sw ra, 20(sp) - sw s0, 16(sp) - addi s0, sp, 24 + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - li a0, GLOBAL_START_SIZE - la a1, global_start - call _write_s + # Print the .section directive and a space after it. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + li a2, KEYWORD_SECTION_SIZE + 1 + li a7, SYS_WRITE + ecall - # Skip "program". - mv a0, s1 - addi a1, sp, 4 - call lex_next - mv s1, a0 + # Skip the .equ directive. + li a0, KEYWORD_SECTION_SIZE + 1 + call _advance_token + + # Read the section name. + call _read_token + sw a0, 16(sp) + + # Print the section name and newline. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 16(sp) + addi a2, a2, 1 + li a7, SYS_WRITE + ecall + + # Skip the section name. + lw a0, 16(sp) + addi a0, a0, 1 + call _advance_token # Epilogue. - lw ra, 20(sp) - lw s0, 16(sp) - addi sp, sp, 24 + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 ret -# Compiles global variable section. -.type compile_global_section, @function -compile_global_section: +# Prints and skips a line. +.type _skip_comment, @function +_skip_comment: # 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 lex_next - li t0, TOKEN_VAR - lw t1, 4(sp) - bne t0, t1, .Lcompile_global_section_end - mv s1, a0 - - li a0, SECTION_BSS_SIZE - la a1, section_bss - call _write_s + la t0, source_code_position + lw t1, (t0) -.Lcompile_global_section_item: - mv a0, s1 - addi a1, sp, 12 - call lex_next +.skip_comment_loop: + # Check for newline character. + lb t2, (t1) + li t3, '\n' + beq t2, t3, .skip_comment_end - lw t0, 12(sp) - li t1, TOKEN_IDENTIFIER + # Advance the input string by one byte. + addi t1, t1, 1 + sw t1, (t0) - bne t0, t1, .Lcompile_global_section_end - lw s1, 20(sp) # Advance to the beginning of the variable name. + j .skip_comment_loop - call compile_global - j .Lcompile_global_section_item +.skip_comment_end: + # Skip the newline. + addi t1, t1, 1 + sw t1, (t0) -.Lcompile_global_section_end: # Epilogue. lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret -# Compiles a global variable. -.type compile_global, @function -compile_global: +# Prints and skips a line. +.type _compile_line, @function +_compile_line: # 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 lex_next - addi a1, sp, 4 - call lex_next # Skip the colon in front of the type. - addi a1, sp, 4 - call lex_next # Skip the opening bracket. - addi a1, sp, 16 - call lex_next # Save the array size on the stack since it has to be emitted multiple times. - addi a1, sp, 4 - call lex_next # Skip the closing bracket. - addi a1, sp, 4 - call lex_next # Skip the type. - mv s1, a0 - - # .type identifier, @object - li a0, ASM_TYPE_SIZE - la a1, asm_type - call _write_s - - lw a0, 32(sp) - lw a1, 36(sp) - call _write_s - - li a0, ASM_TYPE_OBJECT_SIZE - la a1, asm_type_object - call _write_s - - # identifier: .zero size - lw a0, 32(sp) - lw a1, 36(sp) - call _write_s - - li t0, 0x206f7265 # ero_ - sw t0, 12(sp) - li t0, 0x7a2e203a # : .z - sw t0, 8(sp) - li a0, 8 - addi a1, sp, 8 - call _write_s - - lw a0, 20(sp) - lw a1, 24(sp) - call _write_s + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - li a0, '\n' - call _write_c + la a0, source_code_position + lw a1, (a0) + +.compile_line_loop: + # Check for newline character. + lb t0, (a1) + li t1, '\n' + beq t0, t1, .compile_line_end + + # Print a character. + li a0, STDOUT + li a2, 1 + li a7, SYS_WRITE + ecall + + # Advance the input string by one byte. + la a0, source_code_position + lw a1, (a0) + addi a1, a1, 1 + sw a1, (a0) + + j .compile_line_loop + +.compile_line_end: + # Print and skip the newline. + li a0, STDOUT + li a2, 1 + li a7, SYS_WRITE + ecall + + la a0, source_code_position + lw a1, (a0) + addi a1, a1, 1 + sw a1, (a0) # Epilogue. - lw ra, 44(sp) - lw s0, 40(sp) - addi sp, sp, 48 + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 ret -# Sets a0 to the type pointer. -.type compile_type_expression, @function -compile_type_expression: +.type _compile_object, @function +_compile_object: # 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 lex_next - mv s1, a0 - lw t0, 12(sp) - - li t1, TOKEN_HAT # Pointer type. - beq t0, t1, .Lcompile_type_expression_pointer - - # Named type. - lw a0, 16(sp) - lw a1, 20(sp) - call symbol_table_lookup - - j .Lcompile_type_expression_end + call _compile_line -.Lcompile_type_expression_pointer: - call compile_type_expression - mv a1, s3 - call symbol_table_make_pointer - add s3, s3, a0 - sub a0, s3, a0 - - j .Lcompile_type_expression_end - -.Lcompile_type_expression_end: # Epilogue. lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret -# Inserts local procedure variables into the symbol table. -.type compile_local_section, @function -compile_local_section: +.type _compile_function_statements, @function +_compile_function_statements: # Prologue. - addi sp, sp, -48 - sw ra, 44(sp) - sw s0, 40(sp) - addi s0, sp, 48 - - mv a0, s1 - addi a1, sp, 28 - call lex_next - - lw t0, 28(sp) - li t1, TOKEN_VAR - - bne t0, t1, .Lcompile_local_section_end - mv s1, a0 - - sw zero, 12(sp) # Variable offset counter. - -.Lcompile_local_section_variable: - mv a0, s1 - addi a1, sp, 28 - call lex_next - - lw t0, 28(sp) - li t1, TOKEN_IDENTIFIER - - bne t0, t1, .Lcompile_local_section_end - addi a1, sp, 16 - call lex_next - mv s1, a0 # Skip the ":" in front of the type. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - call compile_type_expression - # a0 - Variable type. - lw a1, 12(sp) - mv a2, s3 - call symbol_table_make_local +.compile_function_statements_loop: + la t0, source_code_position + lw t1, (t0) + addi t1, t1, 1 # Skip the tab. - mv a2, s3 - add s3, s3, a0 + mv a0, t1 + la a1, keyword_ret + li a2, KEYWORD_RET_SIZE + call _memcmp - lw a0, 32(sp) - lw a1, 36(sp) - call symbol_table_enter + beqz a0, .compile_function_statements_end - lw t0, 12(sp) - addi t0, t0, 4 - sw t0, 12(sp) + call _compile_line + j .compile_function_statements_loop - j .Lcompile_local_section_variable +.compile_function_statements_end: + call _compile_line -.Lcompile_local_section_end: # Epilogue. - lw ra, 44(sp) - lw s0, 40(sp) - addi sp, sp, 48 + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 ret -# Inserts procedure parameters into the symbol table. -.type compile_parameters, @function -compile_parameters: +.type _compile_call, @function +_compile_call: # Prologue. - addi sp, sp, -48 - sw ra, 44(sp) - sw s0, 40(sp) - addi s0, sp, 48 - - li t0, -12 - sw t0, 12(sp) # Parameter offset counter. - - mv a0, s1 - addi a1, sp, 28 - call lex_next - mv s1, a0 # Skip the opening paren. - - mv a0, s1 - addi a1, sp, 28 - call lex_next - - lw t0, 28(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, 16 - call lex_next - mv s1, a0 # Skip the ":" in front of the type. - - call compile_type_expression - # a0 - Parameter type. - lw a1, 12(sp) - mv a2, s3 - call symbol_table_make_parameter - - mv a2, s3 - add s3, s3, a0 - - lw a0, 32(sp) - lw a1, 36(sp) - call symbol_table_enter - - lw t0, 12(sp) - addi t0, t0, -4 - sw t0, 12(sp) + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 - # Read the comma between the parameters or a closing paren. - mv a0, s1 - addi a1, sp, 16 - call lex_next + call _read_token + sw a0, 20(sp) - lw t0, 16(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, 28 - call lex_next - mv s1, a0 + la a0, asm_call + call _write_z + + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 20(sp) + li a7, SYS_WRITE + ecall - j .Lcompile_parameters_parameter + # Skip parens, semicolon and newline. + lw a0, 20(sp) + addi a0, a0, 4 + call _advance_token -.Lcompile_parameters_end: - mv s1, a0 # Skip the closing paren. + li a0, '\n' + call _write_c # Epilogue. - lw ra, 44(sp) - lw s0, 40(sp) - addi sp, sp, 48 + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 ret -.type compile_procedure, @function -compile_procedure: +.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, 12 - call lex_next # Skip proc. - addi a1, sp, 12 - call lex_next - mv s1, a0 - - lw a0, 16(sp) - lw a1, 20(sp) - call write_procedure_head - - # Register the procedure in the symbol table. - mv a0, s3 - call symbol_table_make_procedure + # This is a call if the statement starts with an underscore. + la t0, source_code_position + lw t0, (t0) + # First character after alignment tab. + addi t0, t0, 1 + lb t0, (t0) + + li t1, '_' + beq t0, t1, .compile_statement_call - mv a2, s3 - add s3, s3, a0 + call _compile_line + j .compile_statement_end - lw a0, 16(sp) - lw a1, 20(sp) - call symbol_table_enter +.compile_statement_call: + li a0, 1 + call _advance_token + call _compile_call - # Save the state of the symbol table before we enter the procedure scope. - la t0, symbol_table - lw t0, (t0) - sw t0, 8(sp) - - call compile_parameters - call compile_local_section - - # Skip the "begin" keyword, denoting the beginning of the procedure body. - mv a0, s1 - addi a1, sp, 12 - call lex_next - mv s1, a0 - - # Generate the procedure prologue with a predefined stack size. - li a0, PROLOGUE_SIZE - la a1, prologue - call _write_s - - # Save passed arguments on the stack. - li a0, ASM_PRESERVE_PARAMETERS_SIZE - la a1, asm_preserve_parameters - call _write_s - - # Generate the body of the procedure. - call compile_statements - mv s1, a0 # Skip end. - - # Generate the procedure epilogue with a predefined stack size. - li a0, EPILOGUE_SIZE - la a1, epilogue - call _write_s - - # Restore the symbol table, removing symbols local to this procedure. - la t0, symbol_table - lw t1, 8(sp) - sw t1, (t0) + j .compile_statement_end +.compile_statement_end: # 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: +.type _compile_procedure_body, @function +_compile_procedure_body: # 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 lex_next # Skip the goto keyword. - addi a1, sp, 0 - call lex_next # We should be on dot the label is beginning with. - addi a1, sp, 0 - call lex_next# Save the label name. - mv s1, a0 +.compile_procedure_body_loop: + la a0, source_code_position + lw a0, (a0) + la a1, keyword_end + li a2, KEYWORD_END_SIZE + call _memcmp - li t0, 0x2e206a # j . - sw t0, 12(sp) - li a0, 3 - addi a1, sp, 12 - call _write_s + beqz a0, .compile_procedure_body_epilogue - lw a0, 4(sp) - lw a1, 8(sp) # Saved dot position. - call _write_s - - li a0, '\n' - call _write_c + call _compile_statement + j .compile_procedure_body_loop +.compile_procedure_body_epilogue: # 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: +.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, 8 - call lex_next # Dot starting the label. - addi a1, sp, 8 - call lex_next - mv s1, a0 + # Skip "proc ". + li a0, KEYWORD_PROC_SIZE + call _advance_token - li a0, '.' - call _write_c - lw a0, 12(sp) - lw a1, 16(sp) - call _write_s - li a0, ':' - call _write_c - li a0, '\n' - call _write_c + call _read_token + sw a0, 20(sp) # Save the procedure name length. + + # Write .type _procedure_name, @function. + la a0, asm_type_directive + call _write_z + + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 20(sp) + li a7, SYS_WRITE + ecall + + la a0, asm_type_function + call _write_z + + # Write procedure label, _procedure_name: + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 20(sp) + li a7, SYS_WRITE + ecall + + la a0, asm_colon + call _write_z + + # Skip the function name and trailing parens, semicolon, "begin" and newline. + lw a0, 20(sp) + addi a0, a0, KEYWORD_BEGIN_SIZE + 1 + 4 + call _advance_token + + la a0, asm_prologue + call _write_z + + call _compile_procedure_body + + # Write the epilogue. + la a0, asm_epilogue + call _write_z + + li a0, KEYWORD_END_SIZE + 2 + call _advance_token # Epilogue. lw ra, 28(sp) @@ -1214,21 +732,17 @@ compile_label: addi sp, sp, 32 ret -# Just skips the return keyword and evaluates the return expression. -.type compile_return, @function -compile_return: +.type _compile_function, @function +_compile_function: # 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 lex_next - mv s1, a0 # Skip return. - - call compile_binary_expression + # Write the function header. + call _compile_line + call _compile_function_statements # Epilogue. lw ra, 28(sp) @@ -1236,115 +750,151 @@ compile_return: addi sp, sp, 32 ret -.type compile_if, @function -compile_if: +.type _compile_type, @function +_compile_type: # 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 lex_next - mv s1, a0 # Skip the if. + # Print the .type directive and a space after it. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + li a2, KEYWORD_TYPE_SIZE + 1 + li a7, SYS_WRITE + ecall - call compile_binary_expression + # Skip the .type directive. + li a0, KEYWORD_TYPE_SIZE + 1 + call _advance_token - mv a0, s1 - addi a1, sp, 0 - call lex_next - mv s1, a0 # Skip the then. + # Read and print the symbol name. + call _read_token + sw a0, 20(sp) - # Label prefix. - li t0, 0x66694c2e # .Lif - sw t0, 20(sp) + # Print the symbol name, comma, space and @. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 20(sp) + addi a2, a2, 3 + li a7, SYS_WRITE + ecall - li t0, 0x202c3061 # a0,_ - sw t0, 16(sp) - li t0, 0x207a7165 # eqz_ + # Skip the constant name, comma, space and @. + lw a0, 20(sp) + addi a0, a0, 3 + call _advance_token + + # Read the symbol type. + call _read_token + sw a0, 16(sp) + la t0, source_code_position + lw t0, (t0) sw t0, 12(sp) - li t0, 0x62626262 # bbbb - sb t0, 11(sp) - li a0, 13 - addi a1, sp, 11 - call _write_s + # Print the symbol type and newline. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 16(sp) + addi a2, a2, 1 + li a7, SYS_WRITE + ecall - # Write the label counter. - mv a0, s2 - call _write_i + lw a0, 16(sp) + addi a0, a0, 1 + call _advance_token - li a0, '\n' - call _write_c + lw a0, 12(sp) + la a1, keyword_type_object + li a2, KEYWORD_TYPE_OBJECT_SIZE + call _memcmp - call compile_statements - mv s1, a0 # Skip end. + beqz a0, .compile_type_object - # Write the label prefix. - li a0, 4 - addi a1, sp, 20 - call _write_s + lw a0, 12(sp) + la a1, keyword_type_function + li a2, KEYWORD_TYPE_FUNCTION_SIZE + call _memcmp + + beqz a0, .compile_type_function - # Write the label counter. - mv a0, s2 - call _write_i + j .compile_type_end - # Finalize the label. - li t0, 0x0a3a # :\n - sh t0, 16(sp) - li a0, 2 - addi a1, sp, 16 - call _write_s +.compile_type_object: + call _compile_object - addi s2, s2, 1 # Increment the label counter. + j .compile_type_end +.compile_type_function: + call _compile_function + + j .compile_type_end + +.compile_type_end: # 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: +.type _compile_equ, @function +_compile_equ: # 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) + # Print the .equ directive and a space after it. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + li a2, KEYWORD_EQU_SIZE + 1 + li a7, SYS_WRITE + ecall - # .type identifier, @function - li a0, ASM_TYPE_SIZE - la a1, asm_type - call _write_s + # Skip the .equ directive. + li a0, KEYWORD_EQU_SIZE + 1 + call _advance_token - lw a0, 16(sp) - lw a1, 20(sp) - call _write_s + # Read and print the constant name. + call _read_token + sw a0, 20(sp) - li a0, ASM_TYPE_FUNCTION_SIZE - la a1, asm_type_function - call _write_s + # Print the constant name, comma and space. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 20(sp) + addi a2, a2, 2 + li a7, SYS_WRITE + ecall - lw a0, 16(sp) - lw a1, 20(sp) - call _write_s + # Skip the constant name, comma and the space after it. + lw a0, 20(sp) + addi a0, a0, 2 + call _advance_token - li t0, 0x0a3a # :\n - sw t0, 12(sp) - li a0, 2 - addi a1, sp, 12 - call _write_s + # Read the constant value. + call _read_token + sw a0, 16(sp) + + # Print the constant value and newline. + li a0, STDOUT + la a1, source_code_position + lw a1, (a1) + lw a2, 16(sp) + addi a2, a2, 1 + li a7, SYS_WRITE + ecall + + lw a2, 16(sp) + addi a2, a2, 1 + call _advance_token # Epilogue. lw ra, 28(sp) @@ -1352,193 +902,163 @@ write_procedure_head: 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: +.type _skip_newlines, @function +_skip_newlines: # 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 lex_next - lw t0, 0(sp) - li t1, TOKEN_END - - beq t0, t1, .Lcompile_statements_end + # Skip newlines. + la t0, source_code_position + lw t1, (t0) -.Lcompile_statements_body: - call compile_statement +.skip_newlines_loop: + lb t2, (t1) + li t3, '\n' + bne t2, t3, .skip_newlines_end + beqz t2, .skip_newlines_end - mv a0, s1 - addi a1, sp, 0 - call lex_next - lw t0, 0(sp) - li t1, TOKEN_SEMICOLON - - bne t0, t1, .Lcompile_statements_end - mv s1, a0 + addi t1, t1, 1 + sw t1, (t0) - j .Lcompile_statements_body + j .skip_newlines_loop -.Lcompile_statements_end: +.skip_newlines_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: +# Process the source code and print the generated code. +.type _compile, @function +_compile: # 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 lex_next - lw t0, 0(sp) +.compile_loop: + call _skip_newlines - li t1, TOKEN_IDENTIFIER - beq t0, t1, .Lcompile_statement_identifier + la t0, source_code_position + lw t0, (t0) + lb t0, (t0) + beqz t0, .compile_end + li t1, '#' + beq t0, t1, .compile_comment - li t1, TOKEN_GOTO - beq t0, t1, .Lcompile_statement_goto + la a0, source_code_position + lw a0, (a0) + la a1, keyword_equ + li a2, KEYWORD_EQU_SIZE + call _memcmp - li t1, TOKEN_RETURN - beq t0, t1, .Lcompile_statement_return + beqz a0, .compile_equ - li t1, TOKEN_IF - beq t0, t1, .Lcompile_statement_if + la a0, source_code_position + lw a0, (a0) + la a1, keyword_section + li a2, KEYWORD_SECTION_SIZE + call _memcmp - li t1, TOKEN_DOT - beq t0, t1, .Lcompile_statement_label + beqz a0, .compile_section - unimp # Else. + la a0, source_code_position + lw a0, (a0) + la a1, keyword_type + li a2, KEYWORD_TYPE_SIZE + call _memcmp -.Lcompile_statement_if: - call compile_if - j .Lcompile_statement_end + beqz a0, .compile_type -.Lcompile_statement_label: - call compile_label - j .Lcompile_statement_end + la a0, source_code_position + lw a0, (a0) + la a1, keyword_proc + li a2, KEYWORD_PROC_SIZE + call _memcmp -.Lcompile_statement_return: - call compile_return - j .Lcompile_statement_end + beqz a0, .compile_procedure -.Lcompile_statement_goto: - call compile_goto - j .Lcompile_statement_end + la a0, source_code_position + lw a0, (a0) + la a1, keyword_global + li a2, KEYWORD_GLOBAL_SIZE + call _memcmp -.Lcompile_statement_identifier: - call compile_identifier - j .Lcompile_statement_end + beqz a0, .compile_global -.Lcompile_statement_end: - # Epilogue. - lw ra, 28(sp) - lw s0, 24(sp) - addi sp, sp, 32 - ret + j .compile_end # Not a known token, exit. -# 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 +.compile_equ: + call _compile_equ - li a0, SECTION_TEXT_SIZE - la a1, section_text - call _write_s + j .compile_loop - # Epilogue. - lw ra, 12(sp) - lw s0, 8(sp) - addi sp, sp, 16 - ret +.compile_section: + call _compile_section -.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 + j .compile_loop - # .type _start, @function - li a0, ASM_START_SIZE - la a1, asm_start - call _write_s +.compile_type: + call _compile_type - mv a0, s1 - addi a1, sp, 4 - call lex_next - mv s1, a0 # Skip begin. + j .compile_loop - # Generate the body of the procedure. - call compile_statements - mv s1, a0 # Skip end. +.compile_global: + call _compile_line - li a0, ASM_EXIT_SIZE - la a1, asm_exit - call _write_s + j .compile_loop +.compile_comment: + call _skip_comment + + j .compile_loop + +.compile_procedure: + call _compile_procedure + + j .compile_loop + +.compile_end: # 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_global_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. +.globl _start .type _start, @function _start: + # Prologue. + addi sp, sp, -32 + sw ra, 28(sp) + sw s0, 24(sp) + addi s0, sp, 32 + # 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 _mmap - mv s3, a0 + # Save the pointer to the beginning of the source code in a global variable. + la t0, source_code + la t1, source_code_position + sw t0, (t1) - call symbol_table_build - call compile + call _compile # Call exit. - li a0, 0 # Use 0 return code. - call _exit + li a0, 0 # Use 0 return code. + li a7, SYS_EXIT + ecall + + # Epilogue. + lw ra, 28(sp) + lw s0, 24(sp) + addi sp, sp, 32 + ret |
