2021-11-16 11:02:45 -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-17 22:37:31 -05:00
|
|
|
; initialize :definitions_end
|
|
|
|
J=:definitions_end
|
|
|
|
D=:definitions
|
|
|
|
8J=D
|
|
|
|
|
|
|
|
:read_line
|
|
|
|
; 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
|
|
|
|
R+=d1
|
|
|
|
!:read_line_loop
|
|
|
|
:read_line_loop_end
|
|
|
|
|
|
|
|
; check if line = "#define " up to a terminator of ' '.
|
|
|
|
C=x20
|
|
|
|
I=:#define
|
|
|
|
J=:line
|
|
|
|
call :string=
|
|
|
|
D=A
|
|
|
|
?D!0:handle_#define
|
|
|
|
|
|
|
|
; handle a normal line
|
|
|
|
; R will store a pointer to the current character
|
|
|
|
R=:line
|
|
|
|
:process_line_loop
|
|
|
|
C=1R
|
|
|
|
B=C
|
|
|
|
call :isident
|
|
|
|
?A!0:process_ident
|
|
|
|
; if *R is not an identifier character, just output it to the file.
|
|
|
|
J=d4
|
|
|
|
B=C
|
|
|
|
call :fputc
|
|
|
|
; check if we reached the end of the line
|
|
|
|
C=1R
|
|
|
|
D=xa
|
2021-11-17 22:58:17 -05:00
|
|
|
?C=D:read_line
|
2021-11-17 22:37:31 -05:00
|
|
|
; increment R, keep looping
|
|
|
|
R+=d1
|
|
|
|
!:process_line_loop
|
|
|
|
:process_ident
|
|
|
|
; if *R is an ident char. look up this identifier in :definitions.
|
|
|
|
; use C to keep pointer to definition
|
|
|
|
C=:definitions
|
|
|
|
:lookup_loop
|
|
|
|
D=1C
|
|
|
|
; check if we reached end of definition table
|
|
|
|
?D=0:lookup_loop_end
|
|
|
|
; check if this entry matches our identifier
|
|
|
|
I=R
|
|
|
|
J=C
|
|
|
|
call :ident=
|
|
|
|
?A!0:perform_substitution
|
|
|
|
; if not, skip over this entry
|
|
|
|
:skip_definition_loop
|
|
|
|
D=1C
|
|
|
|
I=xa
|
|
|
|
C+=d1
|
|
|
|
?I!D:skip_definition_loop
|
|
|
|
!:lookup_loop
|
|
|
|
:lookup_loop_end
|
|
|
|
; this identifier doesn't match anything in the definitions table; just write it.
|
|
|
|
; first, figure out how long it is
|
|
|
|
J=R
|
|
|
|
:length_loop
|
|
|
|
C=1J
|
|
|
|
B=C
|
|
|
|
call :isident
|
|
|
|
?A=0:length_loop_end
|
|
|
|
J+=d1
|
|
|
|
!:length_loop
|
|
|
|
:length_loop_end
|
|
|
|
; now write it.
|
|
|
|
I=R
|
|
|
|
R=J
|
|
|
|
J-=I
|
|
|
|
D=J
|
|
|
|
J=d4
|
|
|
|
syscall x1
|
|
|
|
; keep looping
|
|
|
|
!:process_line_loop
|
|
|
|
|
|
|
|
:perform_substitution
|
|
|
|
; right now, I is a pointer to the end of the identifier in :line,
|
|
|
|
; and J is a pointer to the end of the identifier in :definitions.
|
|
|
|
|
|
|
|
; advance :line pointer for next loop iteration
|
|
|
|
R=I
|
|
|
|
|
|
|
|
J+=d1
|
|
|
|
; J now points to the definition. let's write it
|
|
|
|
I=J
|
|
|
|
:definition_end_loop
|
|
|
|
C=1I
|
|
|
|
D=xa
|
|
|
|
?C=D:definition_end_loop_end
|
|
|
|
I+=d1
|
|
|
|
!:definition_end_loop
|
|
|
|
:definition_end_loop_end
|
|
|
|
D=I
|
|
|
|
D-=J
|
|
|
|
I=J
|
|
|
|
J=d4
|
|
|
|
syscall x1
|
|
|
|
; process the rest of this line
|
|
|
|
!:process_line_loop
|
|
|
|
|
|
|
|
:eof
|
|
|
|
J=d0
|
|
|
|
syscall x3c
|
|
|
|
|
|
|
|
; 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
|
|
|
|
|
|
|
|
|
|
|
|
:handle_#define
|
|
|
|
J=:definitions_end
|
|
|
|
J=8J
|
|
|
|
; start copy from after "#define"
|
|
|
|
I=:line
|
|
|
|
I+=d8
|
|
|
|
|
|
|
|
:#define_copy_loop
|
|
|
|
D=1I
|
|
|
|
1J=D
|
|
|
|
I+=d1
|
|
|
|
J+=d1
|
|
|
|
A=xa
|
|
|
|
?D=A:#define_copy_loop_end
|
|
|
|
!:#define_copy_loop
|
|
|
|
:#define_copy_loop_end
|
|
|
|
|
|
|
|
; update end of definitions
|
|
|
|
D=:definitions_end
|
|
|
|
8D=J
|
|
|
|
; emit newline so we don't screw up line numbers
|
|
|
|
J=d4
|
|
|
|
I=:newline
|
|
|
|
D=d1
|
|
|
|
syscall x1
|
|
|
|
|
|
|
|
!:read_line
|
|
|
|
|
|
|
|
:newline
|
|
|
|
xa
|
|
|
|
|
2021-11-16 11:02:45 -05:00
|
|
|
|
|
|
|
:usage_error
|
|
|
|
B=:usage_error_message
|
|
|
|
call :error
|
|
|
|
|
|
|
|
:usage_error_message
|
|
|
|
str Please provide an input and an output file.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:input_file_error
|
|
|
|
B=:input_file_error_message
|
|
|
|
!:error
|
|
|
|
|
|
|
|
:input_file_error_message
|
|
|
|
str Couldn't open input file.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:output_file_error
|
|
|
|
B=:output_file_error_message
|
|
|
|
!:error
|
|
|
|
|
|
|
|
:output_file_error_message
|
|
|
|
str Couldn't open output file.
|
|
|
|
xa
|
|
|
|
x0
|
|
|
|
|
|
|
|
:error
|
|
|
|
J=B
|
|
|
|
call :strlen
|
|
|
|
D=A
|
|
|
|
I=J
|
|
|
|
J=d2
|
|
|
|
syscall x1
|
|
|
|
J=d1
|
|
|
|
syscall x3c
|
|
|
|
|
|
|
|
:strlen
|
|
|
|
I=B
|
|
|
|
D=B
|
|
|
|
:strlen_loop
|
|
|
|
C=1I
|
|
|
|
?C=0:strlen_ret
|
|
|
|
I+=d1
|
|
|
|
!:strlen_loop
|
|
|
|
:strlen_ret
|
|
|
|
I-=D
|
|
|
|
A=I
|
|
|
|
return
|
2021-11-17 22:37:31 -05:00
|
|
|
|
|
|
|
:#define
|
|
|
|
str #define
|
|
|
|
x20
|
|
|
|
x0
|
|
|
|
|
|
|
|
; 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
|
|
|
|
|
|
|
|
; write the character in rbx to the file in rdi.
|
|
|
|
:fputc
|
|
|
|
C=B
|
|
|
|
I=S
|
|
|
|
I-=d1
|
|
|
|
1I=C
|
|
|
|
D=d1
|
|
|
|
syscall x1
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
align
|
|
|
|
:definitions_end
|
|
|
|
reserve d8
|
|
|
|
:line
|
|
|
|
reserve d1000
|
|
|
|
:definitions
|
|
|
|
reserve d200000
|
|
|
|
|
|
|
|
; we shouldn't end the file with a reserve; we don't handle that properly
|
|
|
|
x00
|