2021-11-19 09:52:27 -05:00
|
|
|
; initialize global_variables_end
|
|
|
|
C=:global_variables_end
|
|
|
|
D=:global_variables
|
|
|
|
8C=D
|
|
|
|
; initialize static_memory_end
|
|
|
|
C=:static_memory_end
|
|
|
|
D=x500000
|
2021-11-20 11:38:34 -05:00
|
|
|
8C=D
|
|
|
|
; initialize labels_end
|
|
|
|
C=:labels_end
|
|
|
|
D=:labels
|
|
|
|
8C=D
|
2021-11-19 09:52:27 -05:00
|
|
|
|
|
|
|
I=8S
|
|
|
|
A=d3
|
|
|
|
?I!A:usage_error
|
|
|
|
; open input file
|
|
|
|
J=S
|
|
|
|
; argv[1] is at *(rsp+16)
|
|
|
|
J+=d16
|
|
|
|
J=8J
|
|
|
|
I=d0
|
|
|
|
syscall x2
|
|
|
|
J=A
|
|
|
|
?J<0:input_file_error
|
|
|
|
; open output file
|
|
|
|
J=S
|
|
|
|
; argv[2] is at *(rsp+24)
|
|
|
|
J+=d24
|
|
|
|
J=8J
|
|
|
|
I=x241
|
|
|
|
D=x1ed
|
|
|
|
syscall x2
|
|
|
|
J=A
|
|
|
|
?J<0:output_file_error
|
|
|
|
|
2021-11-21 17:23:09 -05:00
|
|
|
:second_pass_starting_point
|
2021-11-19 23:27:08 -05:00
|
|
|
; write ELF header
|
|
|
|
J=d4
|
|
|
|
I=:ELF_header
|
|
|
|
D=x78
|
|
|
|
syscall x1
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
:read_line
|
|
|
|
; increment line number
|
|
|
|
D=:line_number
|
|
|
|
C=8D
|
|
|
|
C+=d1
|
|
|
|
8D=C
|
|
|
|
|
|
|
|
; use rbp to store line pointer
|
|
|
|
R=:line
|
|
|
|
:read_line_loop
|
|
|
|
; read 1 byte into rbp
|
|
|
|
J=d3
|
|
|
|
I=R
|
|
|
|
D=d1
|
|
|
|
syscall x0
|
|
|
|
D=A
|
|
|
|
?D=0:eof
|
|
|
|
|
|
|
|
; check if the character was a newline:
|
|
|
|
C=1R
|
|
|
|
D=xa
|
|
|
|
?C=D:read_line_loop_end
|
|
|
|
; check if the character was a tab:
|
|
|
|
D=x9
|
|
|
|
; if so, don't increment rbp
|
2021-11-19 23:27:08 -05:00
|
|
|
?C=D:read_line_loop
|
2021-11-19 09:52:27 -05:00
|
|
|
; check if the character was a semicolon:
|
|
|
|
D=';
|
|
|
|
; if so, it's a comment
|
|
|
|
?C=D:handle_comment
|
|
|
|
|
|
|
|
R+=d1
|
|
|
|
!:read_line_loop
|
|
|
|
|
|
|
|
:handle_comment
|
|
|
|
; read out rest of line from file
|
|
|
|
J=d3
|
|
|
|
I=R
|
|
|
|
D=d1
|
|
|
|
syscall x0
|
|
|
|
D=A
|
|
|
|
?D=0:eof
|
|
|
|
C=1R
|
|
|
|
D=xa
|
|
|
|
; if we didn't reach the end of the line, keep going
|
|
|
|
?C!D:handle_comment
|
|
|
|
|
|
|
|
!:read_line_loop_end
|
|
|
|
:read_line_loop_end
|
|
|
|
|
|
|
|
; remove whitespace (specifically, ' ' characters) at end of line
|
|
|
|
I=R
|
|
|
|
:remove_terminal_whitespace_loop
|
|
|
|
I-=d1
|
|
|
|
C=1I
|
|
|
|
D=x20
|
|
|
|
?C!D:remove_terminal_whitespace_loop_end
|
|
|
|
; replace ' ' with a newline
|
|
|
|
D=xa
|
|
|
|
1I=D
|
|
|
|
!:remove_terminal_whitespace_loop
|
|
|
|
:remove_terminal_whitespace_loop_end
|
|
|
|
|
|
|
|
; check if this is a blank line
|
|
|
|
C=:line
|
|
|
|
D=1C
|
|
|
|
C=xa
|
|
|
|
?C=D:read_line
|
|
|
|
|
2021-11-20 11:38:34 -05:00
|
|
|
C=':
|
|
|
|
?C=D:handle_label_definition
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
I=:line
|
|
|
|
J=:"global"
|
|
|
|
C=x20
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:handle_global
|
|
|
|
|
2021-11-19 23:27:08 -05:00
|
|
|
I=:line
|
|
|
|
J=:"local"
|
|
|
|
C=x20
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:handle_local
|
|
|
|
I=:line
|
|
|
|
J=:"argument"
|
|
|
|
C=x20
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:handle_local
|
|
|
|
|
|
|
|
I=:line
|
|
|
|
J=:"return"
|
|
|
|
C=x20
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:handle_return
|
|
|
|
|
|
|
|
C=xa
|
|
|
|
I=:line
|
|
|
|
J=:"function"
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:handle_function
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
|
|
|
|
!:read_line
|
|
|
|
|
|
|
|
:eof
|
2021-11-21 17:23:09 -05:00
|
|
|
C=:second_pass
|
|
|
|
D=1C
|
|
|
|
?D!0:exit_success
|
|
|
|
; set 2nd pass to 1
|
|
|
|
1C=d1
|
|
|
|
; seek both files back to start
|
|
|
|
J=d3
|
|
|
|
I=d0
|
|
|
|
D=d0
|
|
|
|
syscall x8
|
|
|
|
J=d4
|
|
|
|
I=d0
|
|
|
|
D=d0
|
|
|
|
syscall x8
|
|
|
|
|
|
|
|
!:second_pass_starting_point
|
|
|
|
|
|
|
|
:exit_success
|
2021-11-19 09:52:27 -05:00
|
|
|
J=d0
|
|
|
|
syscall x3c
|
|
|
|
|
2021-11-20 12:47:26 -05:00
|
|
|
align
|
|
|
|
:local_start
|
|
|
|
reserve d8
|
|
|
|
|
2021-11-19 23:27:08 -05:00
|
|
|
:handle_local
|
|
|
|
R=I
|
|
|
|
|
|
|
|
; emit sub rsp, 8
|
|
|
|
J=d4
|
|
|
|
I=:sub_rsp_8
|
|
|
|
D=d7
|
|
|
|
syscall x1
|
|
|
|
|
|
|
|
I=R
|
|
|
|
; skip ' '
|
|
|
|
I+=d1
|
|
|
|
call :read_type
|
|
|
|
R=A
|
|
|
|
I+=d1
|
2021-11-20 12:47:26 -05:00
|
|
|
|
|
|
|
; check if already defined
|
|
|
|
C=:local_start
|
|
|
|
8C=I
|
|
|
|
J=:local_variables
|
2021-11-21 17:23:09 -05:00
|
|
|
D=d5
|
2021-11-20 12:47:26 -05:00
|
|
|
call :ident_lookup
|
|
|
|
C=A
|
|
|
|
?C!0:local_redeclaration
|
|
|
|
C=:local_start
|
|
|
|
I=8C
|
|
|
|
|
2021-11-19 23:27:08 -05:00
|
|
|
J=:local_variables_end
|
|
|
|
J=8J
|
|
|
|
call :ident_copy
|
|
|
|
; store type
|
|
|
|
1J=R
|
|
|
|
J+=d1
|
2021-11-28 10:28:25 -05:00
|
|
|
; increase stack_end, store it in J
|
|
|
|
C=:stack_end
|
|
|
|
D=4C
|
|
|
|
D+=d8
|
|
|
|
4C=D
|
2021-11-21 17:23:09 -05:00
|
|
|
4J=D
|
|
|
|
J+=d4
|
2021-11-19 23:27:08 -05:00
|
|
|
; store null terminator
|
|
|
|
1J=0
|
|
|
|
; update :stack_end
|
|
|
|
D=:stack_end
|
|
|
|
C=8D
|
|
|
|
C+=d8
|
|
|
|
8D=C
|
|
|
|
; update :local_variables_end
|
|
|
|
I=:local_variables_end
|
|
|
|
8I=J
|
|
|
|
; read the next line
|
|
|
|
!:read_line
|
|
|
|
|
|
|
|
:sub_rsp_8
|
|
|
|
x48
|
|
|
|
x81
|
|
|
|
xec
|
|
|
|
x08
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
2021-11-20 12:47:26 -05:00
|
|
|
align
|
|
|
|
:global_start
|
|
|
|
reserve d8
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
:handle_global
|
2021-11-21 17:23:09 -05:00
|
|
|
; ignore if this is the second pass
|
|
|
|
C=:second_pass
|
|
|
|
C=1C
|
|
|
|
?C!0:read_line
|
|
|
|
|
2021-11-19 23:27:08 -05:00
|
|
|
; skip ' '
|
|
|
|
I+=d1
|
2021-11-19 09:52:27 -05:00
|
|
|
call :read_type
|
|
|
|
; put type in R
|
|
|
|
R=A
|
|
|
|
; skip ' ' after type
|
|
|
|
I+=d1
|
2021-11-20 12:47:26 -05:00
|
|
|
|
|
|
|
; check if already defined
|
|
|
|
C=:global_start
|
|
|
|
8C=I
|
|
|
|
J=:global_variables
|
2021-11-21 17:23:09 -05:00
|
|
|
D=d5
|
2022-01-05 18:19:28 -05:00
|
|
|
|
2021-11-20 12:47:26 -05:00
|
|
|
call :ident_lookup
|
|
|
|
C=A
|
|
|
|
?C!0:global_redeclaration
|
|
|
|
C=:global_start
|
|
|
|
I=8C
|
|
|
|
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
J=:global_variables_end
|
|
|
|
J=8J
|
|
|
|
call :ident_copy
|
|
|
|
; store type
|
|
|
|
1J=R
|
|
|
|
J+=d1
|
|
|
|
; store address
|
|
|
|
D=:static_memory_end
|
2021-11-21 17:23:09 -05:00
|
|
|
D=4D
|
|
|
|
4J=D
|
|
|
|
J+=d4
|
2021-11-19 23:27:08 -05:00
|
|
|
; store null terminator
|
|
|
|
1J=0
|
2021-11-19 09:52:27 -05:00
|
|
|
; update :static_memory_end
|
|
|
|
D=:static_memory_end
|
|
|
|
C=8D
|
|
|
|
C+=d8
|
|
|
|
8D=C
|
|
|
|
; update :global_variables_end
|
|
|
|
I=:global_variables_end
|
|
|
|
8I=J
|
|
|
|
; go read the next line
|
|
|
|
!:read_line
|
|
|
|
|
2021-11-19 23:27:08 -05:00
|
|
|
:handle_function
|
2021-11-21 17:23:09 -05:00
|
|
|
; emit prologue
|
2021-11-19 23:27:08 -05:00
|
|
|
J=d4
|
2021-11-21 17:23:09 -05:00
|
|
|
I=:function_prologue
|
|
|
|
D=d14
|
2021-11-19 23:27:08 -05:00
|
|
|
syscall x1
|
|
|
|
|
|
|
|
; reset local variable table
|
|
|
|
D=:local_variables
|
|
|
|
1D=0
|
|
|
|
C=:local_variables_end
|
|
|
|
8C=D
|
|
|
|
|
2021-11-28 10:28:25 -05:00
|
|
|
; reset stack_end
|
|
|
|
D=:stack_end
|
|
|
|
8D=0
|
|
|
|
|
2021-11-19 23:27:08 -05:00
|
|
|
; go read the next line
|
|
|
|
!:read_line
|
|
|
|
|
2021-11-21 17:23:09 -05:00
|
|
|
:function_prologue
|
|
|
|
; sub rsp, 8
|
|
|
|
x48
|
|
|
|
x81
|
|
|
|
xec
|
|
|
|
x08
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
; mov [rsp], rbp
|
|
|
|
x48
|
|
|
|
x89
|
|
|
|
x2c
|
|
|
|
x24
|
|
|
|
; mov rbp, rsp
|
2021-11-19 23:27:08 -05:00
|
|
|
R=S
|
2021-11-21 17:23:09 -05:00
|
|
|
; total length: 7 + 4 + 3 = 14 bytes
|
|
|
|
|
|
|
|
:function_epilogue
|
|
|
|
; mov rsp, rbp
|
|
|
|
S=R
|
|
|
|
; mov rbp, [rsp]
|
|
|
|
x48
|
|
|
|
x8b
|
|
|
|
x2c
|
|
|
|
x24
|
|
|
|
; add rsp, 8
|
|
|
|
x48
|
|
|
|
x81
|
|
|
|
xc4
|
|
|
|
x08
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
; ret
|
|
|
|
return
|
|
|
|
; total length = 15 bytes
|
2021-11-19 23:27:08 -05:00
|
|
|
|
2021-11-20 11:38:34 -05:00
|
|
|
:handle_label_definition
|
2021-11-21 17:23:09 -05:00
|
|
|
; ignore if this is the second pass
|
|
|
|
C=:second_pass
|
|
|
|
C=1C
|
|
|
|
?C!0:read_line
|
|
|
|
|
2021-11-20 11:38:34 -05:00
|
|
|
; make sure label only has identifier characters
|
|
|
|
I=:line
|
|
|
|
I+=d1
|
|
|
|
:label_checking_loop
|
|
|
|
C=1I
|
|
|
|
D=xa
|
|
|
|
?C=D:label_checking_loop_end
|
|
|
|
I+=d1
|
|
|
|
B=C
|
|
|
|
call :isident
|
|
|
|
D=A
|
|
|
|
?D!0:label_checking_loop
|
|
|
|
!:bad_label
|
|
|
|
:label_checking_loop_end
|
|
|
|
|
2021-11-20 12:47:26 -05:00
|
|
|
I=:line
|
|
|
|
I+=d1
|
|
|
|
J=:labels
|
|
|
|
D=d4
|
|
|
|
call :ident_lookup
|
|
|
|
C=A
|
|
|
|
?C!0:label_redefinition
|
2021-11-20 11:38:34 -05:00
|
|
|
|
|
|
|
J=:labels_end
|
|
|
|
J=8J
|
|
|
|
I=:line
|
|
|
|
I+=d1
|
|
|
|
call :ident_copy
|
|
|
|
R=J
|
|
|
|
|
|
|
|
J=d4
|
|
|
|
I=d0
|
|
|
|
D=d1
|
|
|
|
syscall x8
|
|
|
|
C=A
|
|
|
|
C+=x400000
|
|
|
|
J=R
|
|
|
|
4J=C
|
|
|
|
J+=d4
|
|
|
|
|
|
|
|
; update labels_end
|
|
|
|
C=:labels_end
|
|
|
|
8C=J
|
|
|
|
|
|
|
|
; read the next line
|
|
|
|
!:read_line
|
|
|
|
|
|
|
|
|
2021-11-19 23:27:08 -05:00
|
|
|
:handle_return
|
2021-11-28 10:28:25 -05:00
|
|
|
I=:line
|
|
|
|
; "return " is 7 chars long
|
|
|
|
I+=d7
|
|
|
|
|
|
|
|
call :set_rax_to_term
|
2021-11-19 23:27:08 -05:00
|
|
|
|
|
|
|
J=d4
|
2021-11-21 17:23:09 -05:00
|
|
|
I=:function_epilogue
|
|
|
|
D=d15
|
2021-11-19 23:27:08 -05:00
|
|
|
syscall x1
|
|
|
|
|
2021-11-28 10:28:25 -05:00
|
|
|
; go read the next line
|
2021-11-19 23:27:08 -05:00
|
|
|
!:read_line
|
|
|
|
|
|
|
|
:mov_rsp_rbp
|
|
|
|
S=R
|
|
|
|
|
|
|
|
:ret
|
|
|
|
return
|
2021-11-19 09:52:27 -05:00
|
|
|
|
|
|
|
; copy the newline-terminated identifier from rsi to rdi
|
|
|
|
:ident_copy
|
|
|
|
C=1I
|
|
|
|
B=C
|
|
|
|
call :isident
|
|
|
|
D=A
|
|
|
|
?D=0:bad_identifier
|
|
|
|
|
|
|
|
:ident_loop
|
|
|
|
C=1I
|
2021-11-20 11:38:34 -05:00
|
|
|
1J=C
|
|
|
|
I+=d1
|
|
|
|
J+=d1
|
2021-11-19 09:52:27 -05:00
|
|
|
D=xa
|
|
|
|
?C=D:ident_loop_end
|
|
|
|
B=C
|
|
|
|
call :isident
|
|
|
|
D=A
|
|
|
|
?D=0:bad_identifier
|
|
|
|
!:ident_loop
|
|
|
|
:ident_loop_end
|
|
|
|
return
|
|
|
|
|
2021-11-20 12:47:26 -05:00
|
|
|
align
|
|
|
|
:ident_lookup_i
|
|
|
|
reserve d8
|
|
|
|
:ident_lookup_sep
|
|
|
|
reserve d8
|
|
|
|
|
|
|
|
; look up identifier rsi in list rdi with separation rdx between entries
|
|
|
|
; returns address of whatever's right after the identifier in the list, or 0 if not found
|
|
|
|
:ident_lookup
|
|
|
|
C=:ident_lookup_sep
|
|
|
|
8C=D
|
|
|
|
C=:ident_lookup_i
|
|
|
|
8C=I
|
|
|
|
|
|
|
|
:ident_lookup_loop
|
2022-01-05 18:19:28 -05:00
|
|
|
; check if reached the end of the table
|
|
|
|
C=1J
|
|
|
|
?C=0:return_0
|
2021-11-20 12:47:26 -05:00
|
|
|
I=:ident_lookup_i
|
|
|
|
I=8I
|
|
|
|
call :ident=
|
|
|
|
C=A
|
2021-11-28 10:28:25 -05:00
|
|
|
; move past terminator of identifier in table
|
|
|
|
:ident_finish_loop
|
|
|
|
D=1J
|
|
|
|
J+=d1
|
|
|
|
A=xa
|
|
|
|
?D!A:ident_finish_loop
|
|
|
|
; check if this was it
|
2021-11-20 12:47:26 -05:00
|
|
|
?C!0:return_J
|
2021-11-28 10:28:25 -05:00
|
|
|
; nope. keep going
|
2021-11-20 12:47:26 -05:00
|
|
|
C=:ident_lookup_sep
|
|
|
|
C=8C
|
|
|
|
J+=C
|
|
|
|
!:ident_lookup_loop
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
; can the character in rbx appear in an identifier?
|
|
|
|
:isident
|
|
|
|
A='0
|
|
|
|
?B<A:return_0
|
|
|
|
; note: 58 = '9' + 1
|
|
|
|
A=d58
|
|
|
|
?B<A:return_1
|
|
|
|
A='A
|
|
|
|
?B<A:return_0
|
|
|
|
; note: 91 = 'z' + 1
|
|
|
|
A=d91
|
|
|
|
?B<A:return_1
|
|
|
|
A='z
|
|
|
|
?B>A:return_0
|
|
|
|
; 96 = 'a' - 1
|
|
|
|
A=d96
|
|
|
|
?B>A:return_1
|
|
|
|
A='_
|
|
|
|
?B=A:return_1
|
|
|
|
!:return_0
|
|
|
|
|
2021-11-21 17:23:09 -05:00
|
|
|
; set rax to the term in rsi
|
|
|
|
:set_rax_to_term
|
|
|
|
R=I
|
|
|
|
|
|
|
|
C=1I
|
|
|
|
D=''
|
|
|
|
?C=D:term_char
|
|
|
|
|
|
|
|
C=1I
|
|
|
|
D=d58
|
|
|
|
?C<D:term_number
|
|
|
|
|
|
|
|
; variable
|
|
|
|
J=:local_variables
|
2021-11-28 10:28:25 -05:00
|
|
|
xcc
|
2022-01-05 18:19:28 -05:00
|
|
|
D=d5
|
2021-11-21 17:23:09 -05:00
|
|
|
call :ident_lookup
|
|
|
|
C=A
|
|
|
|
?C=0:rax2term_try_global
|
|
|
|
; it's a local variable
|
|
|
|
; skip over its type
|
|
|
|
C+=d1
|
|
|
|
; read the offset from rbp
|
|
|
|
D=4C
|
|
|
|
; put negated offset in rcx
|
|
|
|
C=d0
|
|
|
|
C-=D
|
|
|
|
; store negated offset in :rax2term_addr
|
|
|
|
D=:rax2term_addr
|
|
|
|
4D=C
|
|
|
|
|
|
|
|
J=d4
|
|
|
|
I=:load_rbp_offset_prefix
|
|
|
|
D=d3
|
|
|
|
syscall x1
|
|
|
|
J=d4
|
|
|
|
I=:rax2term_addr
|
|
|
|
D=d4
|
|
|
|
syscall x1
|
|
|
|
|
|
|
|
|
|
|
|
:rax2term_try_global
|
|
|
|
J=:global_variables
|
|
|
|
D=d5
|
|
|
|
call :ident_lookup
|
|
|
|
C=A
|
|
|
|
?C=0:bad_term
|
|
|
|
; it's a global variable
|
|
|
|
; skip over its type
|
|
|
|
C+=d1
|
|
|
|
C=4C
|
|
|
|
D=:rax2term_addr
|
|
|
|
4D=C
|
|
|
|
|
|
|
|
; put address in rbx
|
|
|
|
J=d4
|
|
|
|
I=:mov_ebx_imm32_prefix
|
|
|
|
D=d1
|
|
|
|
syscall x1
|
|
|
|
J=d4
|
|
|
|
I=:rax2term_addr
|
|
|
|
D=d4
|
|
|
|
syscall x1
|
|
|
|
|
|
|
|
; now load [rbx] into rax
|
|
|
|
J=d4
|
|
|
|
I=:mov_rax_[rbx]
|
|
|
|
D=d3
|
|
|
|
syscall x1
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
:term_char
|
|
|
|
; @TODO
|
|
|
|
xcc
|
|
|
|
|
|
|
|
:term_number
|
|
|
|
; @TODO
|
|
|
|
xcc
|
|
|
|
|
|
|
|
align
|
|
|
|
:rax2term_addr
|
|
|
|
reserve d4
|
|
|
|
|
|
|
|
:mov_ebx_imm32_prefix
|
|
|
|
xbb
|
|
|
|
|
|
|
|
:mov_rax_[rbx]
|
|
|
|
x48
|
|
|
|
x8b
|
|
|
|
x03
|
|
|
|
|
|
|
|
; prefix for mov rax, [rbp+IMM32]
|
|
|
|
:load_rbp_offset_prefix
|
|
|
|
x48
|
|
|
|
x8b
|
|
|
|
x85
|
|
|
|
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
; read the space-terminated type from rsi, advance rsi, and set rax to the corresponding type number:
|
|
|
|
; 0 for non-pointer types
|
|
|
|
; 1 for pointer to char
|
|
|
|
; 2 for pointer to short
|
|
|
|
; 4 for pointer to int
|
|
|
|
; 8 for pointer to long
|
|
|
|
:read_type
|
|
|
|
C=1I
|
|
|
|
D='*
|
|
|
|
?C=D:read_pointer_type
|
|
|
|
; it's not a pointer
|
|
|
|
call :read_simple_type
|
|
|
|
A=d0
|
|
|
|
return
|
|
|
|
:read_pointer_type
|
|
|
|
; it's a pointer!
|
|
|
|
I+=d1
|
|
|
|
!:read_simple_type
|
|
|
|
|
|
|
|
; returns 1 for char, 2 for short, 4 for int, 8 for long
|
|
|
|
:read_simple_type
|
|
|
|
R=I
|
|
|
|
C=x20
|
|
|
|
I=R
|
|
|
|
J=:"char"
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:return_1
|
|
|
|
I=R
|
|
|
|
J=:"short"
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:return_2
|
|
|
|
I=R
|
|
|
|
J=:"int"
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:return_4
|
|
|
|
I=R
|
|
|
|
J=:"long"
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:return_8
|
|
|
|
!:bad_type
|
|
|
|
|
|
|
|
|
|
|
|
:usage_error
|
|
|
|
B=:usage_error_message
|
|
|
|
call :general_error
|
|
|
|
|
|
|
|
:usage_error_message
|
|
|
|
str Please provide an input and an output file.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:input_file_error
|
|
|
|
B=:input_file_error_message
|
|
|
|
!:general_error
|
|
|
|
|
|
|
|
:input_file_error_message
|
|
|
|
str Couldn't open input file.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:output_file_error
|
|
|
|
B=:output_file_error_message
|
|
|
|
!:general_error
|
|
|
|
|
|
|
|
:output_file_error_message
|
|
|
|
str Couldn't open output file.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:bad_identifier
|
|
|
|
B=:bad_identifier_error_message
|
|
|
|
!:program_error
|
|
|
|
|
|
|
|
:bad_identifier_error_message
|
|
|
|
str Bad identifier.
|
|
|
|
xa
|
|
|
|
x0
|
2021-11-20 11:38:34 -05:00
|
|
|
|
|
|
|
:bad_label
|
|
|
|
B=:bad_label_error_message
|
|
|
|
!:program_error
|
|
|
|
|
|
|
|
:bad_label_error_message
|
|
|
|
str Bad label.
|
|
|
|
xa
|
|
|
|
x0
|
2021-11-19 09:52:27 -05:00
|
|
|
|
|
|
|
:bad_type
|
|
|
|
B=:bad_type_error_message
|
|
|
|
!:program_error
|
|
|
|
|
|
|
|
:bad_type_error_message
|
|
|
|
str Bad type.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
2021-11-21 17:23:09 -05:00
|
|
|
:bad_term
|
|
|
|
B=:bad_term_error_message
|
|
|
|
!:program_error
|
|
|
|
|
|
|
|
:bad_term_error_message
|
|
|
|
str Bad term.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
2021-11-20 12:47:26 -05:00
|
|
|
:label_redefinition
|
|
|
|
B=:label_redefinition_error_message
|
|
|
|
!:program_error
|
|
|
|
|
|
|
|
:label_redefinition_error_message
|
|
|
|
str Label redefinition.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:global_redeclaration
|
|
|
|
B=:global_redeclaration_error_message
|
|
|
|
!:program_error
|
|
|
|
|
|
|
|
:global_redeclaration_error_message
|
|
|
|
str Global variable declared twice.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:local_redeclaration
|
|
|
|
B=:local_redeclaration_error_message
|
|
|
|
!:program_error
|
|
|
|
|
|
|
|
:local_redeclaration_error_message
|
|
|
|
str Local variable declared twice.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
:general_error
|
|
|
|
call :eputs
|
|
|
|
J=d1
|
|
|
|
syscall x3c
|
|
|
|
|
|
|
|
:program_error
|
|
|
|
R=B
|
|
|
|
|
|
|
|
B=:"Line"
|
|
|
|
call :eputs
|
|
|
|
|
|
|
|
D=:line_number
|
|
|
|
D=8D
|
|
|
|
B=D
|
|
|
|
call :eputn
|
|
|
|
|
|
|
|
B=:line_number_separator
|
|
|
|
call :eputs
|
|
|
|
|
|
|
|
B=R
|
|
|
|
call :eputs
|
|
|
|
J=d1
|
|
|
|
syscall x3c
|
|
|
|
|
|
|
|
:"Line"
|
|
|
|
str Line
|
|
|
|
x20
|
|
|
|
x0
|
|
|
|
|
|
|
|
:line_number_separator
|
|
|
|
str :
|
|
|
|
x20
|
|
|
|
x0
|
|
|
|
|
|
|
|
:strlen
|
|
|
|
I=B
|
|
|
|
D=B
|
|
|
|
:strlen_loop
|
|
|
|
C=1I
|
|
|
|
?C=0:strlen_ret
|
|
|
|
I+=d1
|
|
|
|
!:strlen_loop
|
|
|
|
:strlen_ret
|
|
|
|
I-=D
|
|
|
|
A=I
|
|
|
|
return
|
|
|
|
|
|
|
|
; check if strings in rdi and rsi are equal, up to terminator in rcx
|
|
|
|
:string=
|
|
|
|
D=1I
|
|
|
|
A=1J
|
|
|
|
?D!A:return_0
|
|
|
|
?D=C:return_1
|
|
|
|
I+=d1
|
|
|
|
J+=d1
|
|
|
|
!:string=
|
|
|
|
|
|
|
|
; check if strings in rdi and rsi are equal, up to the first non-identifier character
|
|
|
|
:ident=
|
|
|
|
D=1I
|
|
|
|
B=D
|
|
|
|
call :isident
|
|
|
|
; I ended
|
|
|
|
?A=0:ident=_I_end
|
|
|
|
|
|
|
|
D=1J
|
|
|
|
B=D
|
|
|
|
call :isident
|
|
|
|
; J ended, but I didn't
|
|
|
|
?A=0:return_0
|
|
|
|
|
|
|
|
; we haven't reached the end of either
|
|
|
|
D=1I
|
|
|
|
A=1J
|
|
|
|
?D!A:return_0
|
|
|
|
I+=d1
|
|
|
|
J+=d1
|
|
|
|
!:ident=
|
|
|
|
:ident=_I_end
|
|
|
|
D=1J
|
|
|
|
B=D
|
|
|
|
call :isident
|
|
|
|
; check if J also ended
|
|
|
|
?A=0:return_1
|
|
|
|
; J didn't end
|
|
|
|
!:return_0
|
|
|
|
|
|
|
|
:return_0
|
|
|
|
A=d0
|
|
|
|
return
|
|
|
|
:return_1
|
|
|
|
A=d1
|
|
|
|
return
|
|
|
|
:return_2
|
|
|
|
A=d2
|
|
|
|
return
|
|
|
|
:return_3
|
|
|
|
A=d3
|
|
|
|
return
|
|
|
|
:return_4
|
|
|
|
A=d4
|
|
|
|
return
|
|
|
|
:return_5
|
|
|
|
A=d5
|
|
|
|
return
|
|
|
|
:return_6
|
|
|
|
A=d6
|
|
|
|
return
|
|
|
|
:return_7
|
|
|
|
A=d7
|
|
|
|
return
|
|
|
|
:return_8
|
|
|
|
A=d8
|
|
|
|
return
|
2021-11-20 12:47:26 -05:00
|
|
|
:return_J
|
|
|
|
A=J
|
|
|
|
return
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
; write the character in rbx to the file in rdi.
|
|
|
|
:fputc
|
|
|
|
C=B
|
|
|
|
I=S
|
|
|
|
I-=d1
|
|
|
|
1I=C
|
|
|
|
D=d1
|
|
|
|
syscall x1
|
|
|
|
return
|
|
|
|
|
|
|
|
; write the string in rbx to stderr
|
|
|
|
:eputs
|
|
|
|
J=B
|
|
|
|
call :strlen
|
|
|
|
D=A
|
|
|
|
I=J
|
|
|
|
J=d2
|
|
|
|
syscall x1
|
|
|
|
return
|
|
|
|
|
|
|
|
; write rbx in decimal to stderr
|
|
|
|
:eputn
|
|
|
|
I=B
|
|
|
|
J=S
|
|
|
|
J-=d1
|
|
|
|
:eputn_loop
|
|
|
|
D=d0
|
|
|
|
; divide by 10
|
|
|
|
B=d10
|
|
|
|
A=I
|
|
|
|
div
|
|
|
|
; quotient is new number
|
|
|
|
I=A
|
|
|
|
; add remainder to string
|
|
|
|
D+='0
|
|
|
|
1J=D
|
|
|
|
J-=d1
|
|
|
|
?I!0:eputn_loop
|
|
|
|
D=S
|
|
|
|
D-=J
|
|
|
|
I=J
|
|
|
|
J=d2
|
|
|
|
syscall x1
|
|
|
|
return
|
|
|
|
|
|
|
|
; copy rdx bytes from rsi to rdi.
|
|
|
|
; this copies from the left: if you're doing an overlapped copy, rsi should be greater than rdi
|
|
|
|
:memcpy
|
|
|
|
?D=0:return_0
|
|
|
|
A=1I
|
|
|
|
1J=A
|
|
|
|
I+=d1
|
|
|
|
J+=d1
|
|
|
|
D-=d1
|
|
|
|
!:memcpy
|
2021-11-20 11:38:34 -05:00
|
|
|
|
|
|
|
; copy from rdi to rsi, until byte cl is reached
|
|
|
|
:memccpy
|
|
|
|
D=1I
|
|
|
|
1J=D
|
|
|
|
I+=d1
|
|
|
|
J+=d1
|
|
|
|
?D!C:memccpy
|
|
|
|
return
|
2021-11-19 23:27:08 -05:00
|
|
|
|
|
|
|
:"char"
|
|
|
|
str char
|
|
|
|
x20
|
|
|
|
:"short"
|
|
|
|
str short
|
|
|
|
x20
|
|
|
|
:"int"
|
|
|
|
str int
|
|
|
|
x20
|
|
|
|
:"long"
|
|
|
|
str long
|
|
|
|
x20
|
|
|
|
|
|
|
|
:"global"
|
|
|
|
str global
|
|
|
|
x20
|
|
|
|
:"argument"
|
|
|
|
str argument
|
|
|
|
x20
|
|
|
|
:"local"
|
|
|
|
str local
|
|
|
|
x20
|
|
|
|
:"return"
|
|
|
|
str return
|
|
|
|
x20
|
|
|
|
:"function"
|
|
|
|
str function
|
|
|
|
xa
|
|
|
|
|
2021-11-19 09:52:27 -05:00
|
|
|
; put a 0 byte before the line (this is important for removing whitespace at the end of the line,
|
|
|
|
; specifically, we don't want this to be a space character)
|
|
|
|
x0
|
|
|
|
:line
|
|
|
|
reserve d1000
|
|
|
|
|
|
|
|
align
|
|
|
|
:global_variables_end
|
|
|
|
reserve d8
|
|
|
|
:static_memory_end
|
|
|
|
reserve d8
|
2021-11-19 23:27:08 -05:00
|
|
|
:local_variables_end
|
|
|
|
reserve d8
|
|
|
|
:stack_end
|
|
|
|
reserve d8
|
2021-11-20 11:38:34 -05:00
|
|
|
:labels_end
|
|
|
|
reserve d8
|
2021-11-19 09:52:27 -05:00
|
|
|
:line_number
|
|
|
|
reserve d8
|
|
|
|
:global_variables
|
|
|
|
reserve d50000
|
2021-11-19 23:27:08 -05:00
|
|
|
:local_variables
|
|
|
|
reserve d20000
|
2021-11-20 11:38:34 -05:00
|
|
|
:labels
|
2021-11-19 23:27:08 -05:00
|
|
|
reserve d200000
|
2021-11-21 17:23:09 -05:00
|
|
|
:second_pass
|
|
|
|
reserve d1
|
2021-11-19 23:27:08 -05:00
|
|
|
|
|
|
|
:ELF_header
|
|
|
|
x7f
|
|
|
|
x45
|
|
|
|
x4c
|
|
|
|
x46
|
|
|
|
x02
|
|
|
|
x01
|
|
|
|
x01
|
|
|
|
|
|
|
|
reserve d9
|
|
|
|
|
|
|
|
x02
|
|
|
|
x00
|
|
|
|
|
|
|
|
x3e
|
|
|
|
x00
|
|
|
|
|
|
|
|
x01
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
x78
|
|
|
|
x00
|
|
|
|
x40
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
x40
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
reserve d12
|
|
|
|
|
|
|
|
x40
|
|
|
|
x00
|
|
|
|
x38
|
|
|
|
x00
|
|
|
|
x01
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
x01
|
|
|
|
x00
|
2021-11-19 09:52:27 -05:00
|
|
|
x00
|
2021-11-19 23:27:08 -05:00
|
|
|
x00
|
|
|
|
|
|
|
|
x07
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
x78
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
x78
|
|
|
|
x00
|
|
|
|
x40
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
reserve d8
|
|
|
|
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x20
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x20
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
x00
|
|
|
|
x10
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
x00
|
|
|
|
|
|
|
|
; NOTE: we shouldn't end the file with a reserve; we don't handle that properly
|