.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 .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_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 .size source_code, SOURCE_BUFFER_SIZE source_code: .zero SOURCE_BUFFER_SIZE .section .text # Ignores the import. .type _compile_import, @function _compile_import: # Prologue. addi sp, sp, -8 sw ra, 4(sp) sw s0, 0(sp) addi s0, sp, 8 addi s1, s1, 6 call _skip_spaces call _read_token add s1, s1, a0 # Skip the imported module name. # Epilogue. lw ra, 4(sp) lw s0, 0(sp) addi sp, sp, 8 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 call _skip_spaces call _read_token sw a0, 20(sp) 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_and li t0, 0x726f # or sw t0, 16(sp) mv a0, s1 lw a1, 20(sp) addi a2, sp, 16 call _token_compare beqz a0, .L_build_binary_expression_or 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_equal 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_plus 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_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: addi s1, s1, 1 # 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 .L_build_binary_expression_and: addi s1, s1, 1 # 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 .L_build_binary_expression_or: addi s1, s1, 2 # 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 .L_build_binary_expression_plus: addi s1, s1, 1 # 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 .L_build_binary_expression_minus: addi s1, s1, 1 # 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 .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) 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, -40 sw ra, 36(sp) sw s0, 32(sp) addi s0, sp, 40 addi a0, a0, '0' # Make the register number to a character. sw a0, 28(sp) # And save it. call _skip_spaces call _read_token sw s1, 24(sp) sw a0, 20(sp) lbu a0, (s1) li t0, '-' beq a0, t0, .Lbuild_expression_negate lbu a0, (s1) li t0, '@' beq a0, t0, .Lbuild_expression_address lbu a0, (s1) call _is_digit bnez a0, .Lbuild_expression_literal lbu a0, (s1) li t0, '_' beq a0, t0, .Lbuild_expression_call li t0, 0x61636f6c # loca sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 4 call _memcmp beqz a0, .Lbuild_expression_identifier # Named identifier. lw t1, 28(sp) li t0, 0x00202c00 # \0,_ or t0, t0, t1 sw t0, 8(sp) li t0, 0x6120616c # la a sw t0, 4(sp) addi a0, sp, 4 li a1, 7 call _write_out lw a0, 24(sp) lw a1, 20(sp) call _write_out li a0, '\n' call _put_char 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 # _ 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 addi s1, s1, 1 # Skip @. call _skip_spaces call _read_token sw s1, 24(sp) sw a0, 20(sp) 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 li a0, '\n' call _put_char j .Lbuild_expression_advance .Lbuild_expression_identifier: lw t1, 28(sp) li t0, 0x00202c00 # \0,_ or t0, t0, t1 sw t0, 16(sp) li t0, 0x6120776c # lw a sw t0, 12(sp) addi a0, sp, 12 li a1, 7 call _write_out 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 li t0, '\n' sw t0, 16(sp) li t0, 0x29707328 # (sp) sw t0, 12(sp) addi a0, sp, 12 li a1, 5 call _write_out j .Lbuild_expression_advance .Lbuild_expression_call: lw a0, 24(sp) lw a1, 20(sp) add s1, s1, a1 addi s1, s1, 1 call _compile_call j .Lbuild_expression_end .Lbuild_expression_literal: lw t1, 28(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, 24(sp) lw a1, 20(sp) call _write_out li a0, '\n' call _put_char j .Lbuild_expression_advance .Lbuild_expression_advance: lw a0, 20(sp) add s1, s1, a0 .Lbuild_expression_end: # Epilogue. lw ra, 36(sp) lw s0, 32(sp) addi sp, sp, 40 ret # Compiles a statement beginning with an identifier. # # Left values should be variables named "loca n", where n is the offset # of the variable on the stack, like loca8 or loca4. .type _compile_identifier, @function _compile_identifier: # Prologue. addi sp, sp, -32 sw ra, 28(sp) sw s0, 24(sp) addi s0, sp, 32 call _read_token # Save the pointer to the identifier and its length on the stack. sw s1, 20(sp) sw a0, 16(sp) add s1, s1, a0 call _skip_spaces call _read_token # Save the pointer and the length of the token following the identifier. sw s1, 12(sp) sw a0, 8(sp) add s1, s1, a0 # Skip that token. call _skip_spaces li t0, 0x3d3a # := sw t0, 4(sp) lw a0, 12(sp) lw a1, 8(sp) addi a2, sp, 4 call _token_compare beqz a0, .Lcompile_identifier_assign lw t0, 12(sp) lbu t0, (t0) li t1, 0x28 # ( beq t0, t1, .Lcompile_identifier_call j .Lcompile_identifier_end .Lcompile_identifier_call: lw a0, 20(sp) lw a1, 16(sp) call _compile_call j .Lcompile_identifier_end .Lcompile_identifier_assign: call _build_binary_expression li t0, 0x202c30 # 0,_ sw t0, 12(sp) li t0, 0x61207773 # sw a sw t0, 8(sp) addi a0, sp, 8 li a1, 7 call _write_out lw a0, 20(sp) lw a1, 16(sp) addi a0, a0, 4 # Skip the "loca" variable prefix. addi a1, a1, -4 # Skip the "loca" variable prefix. call _write_out li t0, '\n' sw t0, 12(sp) li t0, 0x29707328 # (sp) sw t0, 8(sp) addi a0, sp, 8 li a1, 5 call _write_out j .Lcompile_identifier_end .Lcompile_identifier_end: # Epilogue. lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret # Compiles a procedure call. Expects s1 to point to the first argument. # a0 - Pointer to the procedure name. # a1 - Length of the procedure name. # # Returns the procedure result in a0. .type _compile_call, @function _compile_call: # Prologue. addi sp, sp, -32 sw ra, 28(sp) sw s0, 24(sp) addi s0, sp, 32 sw a0, 20(sp) sw a1, 16(sp) sw zero, 12(sp) # Argument count for a procedure call. .Lcompile_call_paren: call _skip_spaces 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 call _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) 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 call _skip_spaces addi s1, s1, 1 # Skip the close paren. # Epilogue. lw ra, 28(sp) lw s0, 24(sp) addi sp, sp, 32 ret # Reads a token and returns its length in a0. # _read_token doesn't change s1, it finds the length of the token s1 is pointing to. .type _read_token, @function _read_token: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 lbu t0, (s1) # t0 = Current character. sw zero, 4(sp) li t1, '.' beq t0, t1, .Ltoken_character_single li t1, ',' beq t0, t1, .Ltoken_character_single li t1, ':' beq t0, t1, .Ltoken_character_colon li t1, ';' beq t0, t1, .Ltoken_character_single li t1, '(' beq t0, t1, .Ltoken_character_single li t1, ')' beq t0, t1, .Ltoken_character_single li t1, '[' beq t0, t1, .Ltoken_character_single li t1, ']' beq t0, t1, .Ltoken_character_single li t1, '^' beq t0, t1, .Ltoken_character_single li t1, '&' beq t0, t1, .Ltoken_character_single li t1, '=' beq t0, t1, .Ltoken_character_single li t1, '+' beq t0, t1, .Ltoken_character_single 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. .Ltoken_character_loop_do: lw t6, 4(sp) add t1, s1, t6 lbu a0, (t1) # a0 = Current character. call _is_alnum beqz a0, .Ltoken_character_end lw t6, 4(sp) addi t6, t6, 1 sw t6, 4(sp) j .Ltoken_character_loop_do .Ltoken_character_single: lw t6, 4(sp) addi t6, t6, 1 sw t6, 4(sp) j .Ltoken_character_end .Ltoken_character_colon: lbu t0, 1(s1) # t0 = The character after the colon. lw t6, 4(sp) addi t6, t6, 1 sw t6, 4(sp) li t1, '=' beq t0, t1, .Ltoken_character_single j .Ltoken_character_end .Ltoken_character_end: lw a0, 4(sp) # Epilogue. lw ra, 12(sp) lw s0, 8(sp) addi sp, sp, 16 ret # Skips the spaces till the next non space character. .type _skip_spaces, @function _skip_spaces: .Lspace_loop_do: lbu t0, (s1) # t0 = Current character. li t1, ' ' beq t0, t1, .Lspace_loop_repeat li t1, '\t' beq t0, t1, .Lspace_loop_repeat li t1, '\n' beq t0, t1, .Lspace_loop_repeat li t1, '\r' beq t0, t1, .Lspace_loop_repeat j .Lspace_loop_end .Lspace_loop_repeat: addi s1, s1, 1 j .Lspace_loop_do .Lspace_loop_end: ret # Skips tabs at the line beginning. .type _skip_indentation, @function _skip_indentation: .Lskip_indentation_do: lbu t0, (s1) li t1, '\t' beq t0, t1, .Lskip_indentation_skip j .Lskip_indentation_end .Lskip_indentation_skip: addi s1, s1, 1 j .Lskip_indentation_do .Lskip_indentation_end: ret # Parameters: # a0 - Line length. .type _skip_comment, @function _skip_comment: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 # Check whether this is a comment. li t0, 0x2a28 # (* sw t0, 4(sp) addi a0, sp, 4 mv a1, s1 li a2, 2 call _memcmp bnez a0, .Lskip_comment_end addi s1, s1, 2 # Skip (*. li t0, 0x292a # *) sw t0, 4(sp) .Lskip_comment_loop: addi a0, sp, 4 mv a1, s1 li a2, 2 call _memcmp beqz a0, .Lskip_comment_close addi s1, s1, 1 j .Lskip_comment_loop .Lskip_comment_close: addi s1, s1, 2 # Skip *). .Lskip_comment_end: # Epilogue. lw ra, 12(sp) lw s0, 8(sp) addi sp, sp, 16 ret # Parameters: # a0 - Line length. .type _compile_assembly, @function _compile_assembly: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 sw a0, 4(sp) # a0 - Line length. # Write the source to the standard output. mv a0, s1 lw a1, 4(sp) call _write_out lw t0, 4(sp) add s1, s1, t0 li a0, '\n' call _put_char addi s1, s1, 1 # Skip the new line. # Epilogue. lw ra, 12(sp) lw s0, 8(sp) addi sp, sp, 16 ret .type _compile_program, @function _compile_program: # Prologue. addi sp, sp, -8 sw ra, 4(sp) sw s0, 0(sp) addi s0, sp, 8 la a0, global_start li a1, GLOBAL_START_SIZE call _write_out addi s1, s1, 8 # program\n. # Epilogue. lw ra, 4(sp) lw s0, 0(sp) addi sp, sp, 8 ret .type _compile_constant_section, @function _compile_constant_section: # Prologue. addi sp, sp, -8 sw ra, 4(sp) sw s0, 0(sp) addi s0, sp, 8 la a0, section_rodata li a1, SECTION_RODATA_SIZE call _write_out addi s1, s1, 6 # const\n. .Lcompile_constant_section_item: call _skip_spaces lbu a0, (s1) call _is_upper beqz a0, .Lcompile_constant_section_end call _compile_constant j .Lcompile_constant_section_item .Lcompile_constant_section_end: # Epilogue. lw ra, 4(sp) lw s0, 0(sp) addi sp, sp, 8 ret .type _compile_constant, @function _compile_constant: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 call _read_token mv a1, a0 # The identifier length from _read_token should be in a1. mv a0, s1 # Save the identifier pointer before advancing it. add s1, s1, a1 call _write_out call _skip_spaces addi s1, s1, 2 # Skip the assignment sign. # : .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 call _skip_spaces call _read_token mv a1, a0 # The literal length from _read_token should be in a1. mv a0, s1 # Save the literal pointer before advancing it. add s1, s1, a1 call _write_out li a0, '\n' call _put_char # Epilogue. lw ra, 12(sp) lw s0, 8(sp) addi sp, sp, 16 ret .type _compile_variable_section, @function _compile_variable_section: # Prologue. addi sp, sp, -8 sw ra, 4(sp) sw s0, 0(sp) addi s0, sp, 8 la a0, section_bss li a1, SECTION_BSS_SIZE call _write_out addi s1, s1, 4 # var\n. .Lcompile_variable_section_item: call _skip_spaces lbu a0, (s1) call _is_lower beqz a0, .Lcompile_variable_section_end call _compile_variable j .Lcompile_variable_section_item .Lcompile_variable_section_end: # Epilogue. lw ra, 4(sp) lw s0, 0(sp) addi sp, sp, 8 ret .type _compile_variable, @function _compile_variable: # Prologue. addi sp, sp, -40 sw ra, 36(sp) sw s0, 32(sp) addi s0, sp, 40 call _read_token # Save the identifier on the stack since it should emitted multiple times. sw s1, 28(sp) sw a0, 24(sp) add s1, s1, a0 call _skip_spaces addi s1, s1, 1 # Skip the colon in front of the type. call _skip_spaces addi s1, s1, 1 # Skip the opening bracket. call _read_token # Save the array size on the stack since it has to be emitted multiple times. sw s1, 20(sp) sw a0, 16(sp) add s1, s1, a0 call _skip_spaces addi s1, s1, 1 # Skip the closing bracket. call _skip_spaces call _read_token add s1, s1, a0 # Skip the type. # .type identifier, @object la a0, asm_type li a1, ASM_TYPE_SIZE call _write_out lw a0, 28(sp) lw a1, 24(sp) call _write_out li t0, 0x0a74 # t\n sw t0, 12(sp) li t0, 0x63656a62 # bjec sw t0, 8(sp) li t0, 0x6f40202c # , @o sw t0, 4(sp) addi a0, sp, 4 li a1, 10 call _write_out # .size identifier, size li t0, 0x2065 # e_ sw t0, 12(sp) li t0, 0x7a69732e # .siz sw t0, 8(sp) addi a0, sp, 8 li a1, 6 call _write_out lw a0, 28(sp) lw a1, 24(sp) call _write_out li t0, 0x202c # ,_ sw t0, 12(sp) addi a0, sp, 12 li a1, 2 call _write_out lw a0, 20(sp) lw a1, 16(sp) call _write_out li a0, '\n' call _put_char # identifier: .zero size lw a0, 28(sp) lw a1, 24(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, 20(sp) lw a1, 16(sp) call _write_out li a0, '\n' call _put_char # Epilogue. lw ra, 36(sp) lw s0, 32(sp) addi sp, sp, 40 ret .type _compile_procedure, @function _compile_procedure: # Prologue. addi sp, sp, -32 sw ra, 28(sp) sw s0, 24(sp) addi s0, sp, 32 addi s1, s1, 5 # Skip proc_ call _read_token sw s1, 20(sp) sw a0, 16(sp) add s1, s1, a0 # .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 li t0, 0x0a6e6f69 # ion\n sw t0, 12(sp) li t0, 0x74636e75 # unct sw t0, 8(sp) li t0, 0x6640202c # , @f sw t0, 4(sp) addi a0, sp, 4 li a1, 12 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 call _skip_spaces addi s1, s1, 1 # Skip opening argument paren. call _skip_spaces addi s1, s1, 1 # Skip closing argument paren. li t0, 0x6e # n sw t0, 12(sp) li t0, 0x69676562 # begi sw t0, 8(sp) # Skip all declarations until we find the "begin" keyword, denoting the # beginning of the procedure body. .Lcompile_procedure_begin: call _skip_spaces call _read_token mv a1, a0 mv a0, s1 addi a2, sp, 8 add s1, s1, a1 call _token_compare bnez a0, .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. li t0, 0x0a29 # )\n sw t0, 12(sp) li t0, 0x70732834 # 4(sp sw t0, 8(sp) li t0, 0x38202c30 # 0, 8 sw t0, 4(sp) li t0, 0x61207773 # sw a sw t0, 0(sp) addi a0, sp, 0 li a1, 14 call _write_out li t0, '0' sb t0, 8(sp) li t0, 0x38202c31 # 1, 8 sw t0, 4(sp) addi a0, sp, 0 li a1, 14 call _write_out li t0, '6' sb t0, 8(sp) li t0, 0x37202c32 # 2, 7 sw t0, 4(sp) addi a0, sp, 0 li a1, 14 call _write_out li t0, '2' sb t0, 8(sp) li t0, 0x37202c33 # 3, 7 sw t0, 4(sp) addi a0, sp, 0 li a1, 14 call _write_out li t0, '8' sb t0, 8(sp) li t0, 0x36202c34 # 4, 6 sw t0, 4(sp) addi a0, sp, 0 li a1, 14 call _write_out li t0, '4' sb t0, 8(sp) li t0, 0x36202c35 # 5, 6 sw t0, 4(sp) addi a0, sp, 0 li a1, 14 call _write_out # Generate the body of the procedure. .Lcompile_procedure_body: call _skip_indentation call _read_line sw a0, 12(sp) li t0, 0x0a646e65 # end\n sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 4 call _memcmp beqz a0, .Lcompile_procedure_end lw a0, 12(sp) call _compile_line j .Lcompile_procedure_body .Lcompile_procedure_end: add s1, s1, 4 # Skip end\n. # 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 # Compares two string, which of one has a length, the other one is null-terminated. # # a0 - The address of the token string. # a1 - The length of the string in a0. # a2 - The address of the null-terminated string. # # If the strings match sets a0 to 0, otherwise sets it to 1. .type _token_compare, @function _token_compare: addi t0, a0, 0 addi t1, a1, 0 addi t2, a2, 0 .Ltoken_compare_loop: lbu t3, (t2) # Will only be 0 if the current character in the null terminated string is \0 and the remaining length of the # another string is 0. or t4, t3, t1 beqz t4, .Ltoken_compare_equal beqz t1, .Ltoken_compare_not_equal beqz t3, .Ltoken_compare_not_equal lbu t4, (t0) bne t3, t4, .Ltoken_compare_not_equal addi t0, t0, 1 addi t1, t1, -1 addi t2, t2, 1 j .Ltoken_compare_loop .Ltoken_compare_not_equal: li a0, 1 j .Ltoken_compare_end .Ltoken_compare_equal: li a0, 0 .Ltoken_compare_end: ret .type _compile_goto, @function _compile_goto: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 addi s1, s1, 4 # Skip the goto keyword. li t0, 0x206a # j_ sw t0, 8(sp) addi a0, sp, 8 li a1, 2 call _write_out call _skip_spaces sw s1, 8(sp) # We should be on dot the label is beginning with. addi s1, s1, 1 call _read_token add s1, s1, a0 addi a1, a0, 1 # Label length and the dot. lw a0, 8(sp) # Saved dot position. call _write_out addi s1, s1, 1 # Skip the new line. li a0, '\n' call _put_char # Epilogue. lw ra, 12(sp) lw s0, 8(sp) addi sp, sp, 16 ret # a0 - Line length. .type _compile_label, @function _compile_label: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 sw a0, 0(sp) # Save the line length. # Write the whole line as is. mv a0, s1 lw a1, 0(sp) call _write_out lw t0, 0(sp) # Line length. mv t1, s1 # Line start. add t1, t1, t0 addi t1, t1, -1 # Last character on the line. lbu t1, (t1) li t2, ':' beq t1, t2, .Lcompile_label_colon li t0, 0x3a # : sw t0, 4(sp) addi a0, sp, 4 li a1, 1 call _write_out .Lcompile_label_colon: li t0, '\n' sw t0, 4(sp) addi a0, sp, 4 li a1, 1 call _write_out lw a0, 0(sp) addi a0, a0, 1 # Skip the new line as well. add s1, s1, a0 # Skip the line. # Epilogue. lw ra, 12(sp) lw s0, 8(sp) addi sp, sp, 16 ret .type _compile_return, @function _compile_return: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 addi s1, s1, 6 # Skip return. call _skip_spaces call _build_binary_expression # Epilogue. lw ra, 12(sp) lw s0, 8(sp) 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 # emitted before any code is written. # # Returns 1 in a0 if the parsed line contained a text section element such a # procedure or the program entry point. Otherwise sets a0 to 0. .type _compile_line, @function _compile_line: # Prologue. addi sp, sp, -32 sw ra, 28(sp) sw s0, 24(sp) addi s0, sp, 32 # Preserve passed arguments. sw a0, 20(sp) sw a1, 16(sp) beqz a0, .Lcompile_line_empty # Skip an empty line. lbu t0, (s1) li t1, '(' beq t0, t1, .Lcompile_line_comment li t0, 0x0a6d6172 # ram\n sw t0, 12(sp) li t0, 0x676f7270 # prog sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 8 call _memcmp beqz a0, .Lcompile_line_program li t0, 0x0a74 # t\n sw t0, 12(sp) li t0, 0x736e6f63 # cons sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 6 call _memcmp beqz a0, .Lcompile_line_const li t0, 0x0a726176 # var\n sw t0, 12(sp) mv a0, s1 addi a1, sp, 12 li a2, 4 call _memcmp beqz a0, .Lcompile_line_var li t0, 0x20 # _ sw t0, 12(sp) li t0, 0x636f7270 # proc sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 5 call _memcmp beqz a0, .Lcompile_line_procedure li t0, 0x0a6e # n\n sw t0, 12(sp) li t0, 0x69676562 # begi sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 6 call _memcmp beqz a0, .Lcompile_line_begin li t0, 0x2e646e65 # end. sw t0, 12(sp) mv a0, s1 addi a1, sp, 12 li a2, 4 call _memcmp beqz a0, .Lcompile_line_exit li t0, 0x61636f6c # loca sw t0, 12(sp) mv a0, s1 addi a1, sp, 12 li a2, 4 call _memcmp beqz a0, .Lcompile_line_identifier li t0, 0x7472 # rt sw t0, 12(sp) li t0, 0x6f706d69 # impo sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 6 call _memcmp beqz a0, .Lcompile_line_import li t0, 0x6f746f67 # goto sw t0, 12(sp) mv a0, s1 addi a1, sp, 12 li a2, 4 call _memcmp beqz a0, .Lcompile_line_goto li t0, 0x6e72 # rn sw t0, 12(sp) li t0, 0x75746572 # retu sw t0, 8(sp) mv a0, s1 addi a1, sp, 8 li a2, 6 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 li t1, '_' beq t0, t1, .Lcompile_line_identifier 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: call _compile_return j .Lcompile_line_section .Lcompile_line_goto: call _compile_goto j .Lcompile_line_section .Lcompile_line_import: call _compile_import j .Lcompile_line_section .Lcompile_line_identifier: call _compile_identifier j .Lcompile_line_section .Lcompile_line_exit: call _compile_exit j .Lcompile_line_section .Lcompile_line_begin: lw a1, 16(sp) bnez a1, .Lcompile_line_compile_entry call _compile_text_section .Lcompile_line_compile_entry: call _compile_entry_point li a0, 1 j .Lcompile_line_end .Lcompile_line_const: call _compile_constant_section j .Lcompile_line_section .Lcompile_line_procedure: lw a1, 16(sp) bnez a1, .Lcompile_line_compile_procedure call _compile_text_section .Lcompile_line_compile_procedure: call _compile_procedure li a0, 1 j .Lcompile_line_end .Lcompile_line_var: call _compile_variable_section j .Lcompile_line_section .Lcompile_line_program: call _compile_program j .Lcompile_line_section .Lcompile_line_comment: lw a0, 20(sp) call _skip_comment j .Lcompile_line_section .Lcompile_line_empty: addi s1, s1, 1 j .Lcompile_line_section .Lcompile_line_unchanged: lw a0, 20(sp) call _compile_assembly j .Lcompile_line_section .Lcompile_line_section: mv a0, zero .Lcompile_line_end: sw a0, 12(sp) call _skip_spaces call _skip_comment lw a0, 12(sp) # 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, -8 sw ra, 4(sp) sw s0, 0(sp) addi s0, sp, 8 la a0, section_text li a1, SECTION_TEXT_SIZE call _write_out # Epilogue. lw ra, 4(sp) lw s0, 0(sp) addi sp, sp, 8 ret .type _compile_entry_point, @function _compile_entry_point: # Prologue. addi sp, sp, -8 sw ra, 4(sp) sw s0, 0(sp) addi s0, sp, 8 # .type _start, @function la a0, asm_start li a1, ASM_START_SIZE call _write_out addi s1, s1, 6 # Skip begin\n. # Epilogue. lw ra, 4(sp) lw s0, 0(sp) addi sp, sp, 8 ret .type _compile_exit, @function _compile_exit: # Prologue. addi sp, sp, -8 sw ra, 4(sp) sw s0, 0(sp) addi s0, sp, 8 la a0, asm_exit li a1, ASM_EXIT_SIZE call _write_out addi s1, s1, 4 # Skip end. call _skip_spaces # Read the possible new line at the end of the file. # Epilogue. lw ra, 4(sp) lw s0, 0(sp) addi sp, sp, 8 ret # Finds the end of the line and returns its length in a0. .type _read_line, @function _read_line: mv t0, s1 # Local position in the source text. .Lread_line_do: lbu t1, (t0) # t1 = Current character. beqz t1, .Lread_line_end # Exit the loop on the NUL character. li t2, '\n' beq t1, t2, .Lread_line_end # Exit the loop on the new line. addi t0, t0, 1 j .Lread_line_do .Lread_line_end: sub a0, t0, s1 # Return the line length. ret .type _compile, @function _compile: # Prologue. addi sp, sp, -16 sw ra, 12(sp) sw s0, 8(sp) addi s0, sp, 16 sw zero, 4(sp) # Whether the text section header was already emitted. .Lcompile_do: lbu t0, (s1) # t0 = Current character. beqz t0, .Lcompile_end # Exit the loop on the NUL character. call _skip_indentation call _read_line lw a1, 4(sp) call _compile_line 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) j .Lcompile_do .Lcompile_end: # 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 la s1, source_code # s1 = Source code position. call _compile # Call exit. li a0, 0 # Use 0 return code. call _exit