number terms!

This commit is contained in:
pommicket 2022-01-05 23:44:04 -05:00
parent 6a31b0560a
commit 9d43ebe2aa
2 changed files with 183 additions and 164 deletions

304
04b/in03
View file

@ -11,23 +11,14 @@ C=:labels_end
D=:labels D=:labels
8C=D 8C=D
I=8S
A=d3
?I!A:usage_error
; open input file ; open input file
J=S J=:input_filename
; argv[1] is at *(rsp+16)
J+=d16
J=8J
I=d0 I=d0
syscall x2 syscall x2
J=A J=A
?J<0:input_file_error ?J<0:input_file_error
; open output file ; open output file
J=S J=:output_filename
; argv[2] is at *(rsp+24)
J+=d24
J=8J
I=x241 I=x241
D=x1ed D=x1ed
syscall x2 syscall x2
@ -126,6 +117,7 @@ C=x20
call :string= call :string=
D=A D=A
?D!0:handle_local ?D!0:handle_local
; arguments are treated the same as local variables
I=:line I=:line
J=:"argument" J=:"argument"
C=x20 C=x20
@ -140,7 +132,9 @@ call :string=
D=A D=A
?D!0:handle_return ?D!0:handle_return
; set delimiter to newline
C=xa C=xa
I=:line I=:line
J=:"function" J=:"function"
call :string= call :string=
@ -173,7 +167,7 @@ D=A
syscall x3c syscall x3c
align align
:local_start :local_variable_name
reserve d8 reserve d8
:handle_local :handle_local
@ -188,27 +182,22 @@ align
I=R I=R
; skip ' ' ; skip ' '
I+=d1 I+=d1
call :read_type
R=A ; store away pointer to variable name
I+=d1 C=:local_variable_name
8C=I
; check if already defined ; check if already defined
C=:local_start
8C=I
J=:local_variables J=:local_variables
D=d5
call :ident_lookup call :ident_lookup
C=A C=A
?C!0:local_redeclaration ?C!0:local_redeclaration
C=:local_start C=:local_variable_name
I=8C I=8C
J=:local_variables_end J=:local_variables_end
J=8J J=8J
call :ident_copy call :ident_copy
; store type
1J=R
J+=d1
; increase stack_end, store it in J ; increase stack_end, store it in J
C=:stack_end C=:stack_end
D=4C D=4C
@ -218,11 +207,6 @@ align
J+=d4 J+=d4
; store null terminator ; store null terminator
1J=0 1J=0
; update :stack_end
D=:stack_end
C=8D
C+=d8
8D=C
; update :local_variables_end ; update :local_variables_end
I=:local_variables_end I=:local_variables_end
8I=J 8I=J
@ -241,7 +225,8 @@ align
align align
:global_start :global_start
reserve d8 reserve d8
:global_variable_name
reserve d8
:handle_global :handle_global
; ignore if this is the second pass ; ignore if this is the second pass
C=:second_pass C=:second_pass
@ -250,43 +235,33 @@ align
; skip ' ' ; skip ' '
I+=d1 I+=d1
call :read_type
; put type in R ; store away pointer to variable name
R=A C=:global_variable_name
; skip ' ' after type 8C=I
I+=d1
; check if already defined ; check if already defined
C=:global_start
8C=I
J=:global_variables J=:global_variables
D=d5
call :ident_lookup call :ident_lookup
C=A C=A
?C!0:global_redeclaration ?C!0:global_redeclaration
C=:global_start
I=8C
C=:global_variable_name
I=8C
J=:global_variables_end J=:global_variables_end
J=8J J=8J
call :ident_copy call :ident_copy
; store type
1J=R
J+=d1
; store address ; store address
D=:static_memory_end D=:static_memory_end
D=4D C=4D
4J=D 4J=C
J+=d4 J+=d4
; increase static_memory_end
C+=d8
4D=C
; store null terminator ; store null terminator
1J=0 1J=0
; update :static_memory_end
D=:static_memory_end
C=8D
C+=d8
8D=C
; update :global_variables_end ; update :global_variables_end
I=:global_variables_end I=:global_variables_end
8I=J 8I=J
@ -308,7 +283,7 @@ align
; reset stack_end ; reset stack_end
D=:stack_end D=:stack_end
8D=0 4D=0
; go read the next line ; go read the next line
!:read_line !:read_line
@ -374,8 +349,7 @@ align
I=:line I=:line
I+=d1 I+=d1
J=:labels J=:global_variables
D=d4
call :ident_lookup call :ident_lookup
C=A C=A
?C!0:label_redefinition ?C!0:label_redefinition
@ -387,6 +361,7 @@ align
call :ident_copy call :ident_copy
R=J R=J
; figure out where in the file we are
J=d4 J=d4
I=d0 I=d0
D=d1 D=d1
@ -394,6 +369,7 @@ align
C=A C=A
C+=x400000 C+=x400000
J=R J=R
; store address
4J=C 4J=C
J+=d4 J+=d4
@ -452,14 +428,10 @@ align
align align
:ident_lookup_i :ident_lookup_i
reserve d8 reserve d8
:ident_lookup_sep
reserve d8
; look up identifier rsi in list rdi with separation rdx between entries ; look up identifier rsi in list rdi
; returns address of whatever's right after the identifier in the list, or 0 if not found ; returns address of whatever's right after the identifier in the list, or 0 if not found
:ident_lookup :ident_lookup
C=:ident_lookup_sep
8C=D
C=:ident_lookup_i C=:ident_lookup_i
8C=I 8C=I
@ -480,9 +452,8 @@ align
; check if this was it ; check if this was it
?C!0:return_J ?C!0:return_J
; nope. keep going ; nope. keep going
C=:ident_lookup_sep ; skip over address:
C=8C J+=d4
J+=C
!:ident_lookup_loop !:ident_lookup_loop
; can the character in rbx appear in an identifier? ; can the character in rbx appear in an identifier?
@ -520,14 +491,10 @@ align
; variable ; variable
J=:local_variables J=:local_variables
xcc
D=d5
call :ident_lookup call :ident_lookup
C=A C=A
?C=0:rax2term_try_global ?C=0:rax2term_try_global
; it's a local variable ; it's a local variable
; skip over its type
C+=d1
; read the offset from rbp ; read the offset from rbp
D=4C D=4C
; put negated offset in rcx ; put negated offset in rcx
@ -546,16 +513,15 @@ align
D=d4 D=d4
syscall x1 syscall x1
return
:rax2term_try_global :rax2term_try_global
J=:global_variables J=:global_variables
D=d5
call :ident_lookup call :ident_lookup
C=A C=A
?C=0:bad_term ?C=0:bad_term
; it's a global variable ; it's a global variable
; skip over its type ; get its address
C+=d1
C=4C C=4C
D=:rax2term_addr D=:rax2term_addr
4D=C 4D=C
@ -579,12 +545,121 @@ align
return return
:term_char :term_char
; @TODO I+=d1
xcc I=1I
!:set_rax_to_immediate
:number_is_negative
reserve d1
:term_number :term_number
; @TODO C=1I
xcc D='-
; set rdx to 0 if number is positive, 1 if negative
?C=D:term_number_negative
D=d0
!:term_number_cont
:term_number_negative
D=d1
I+=d1
:term_number_cont
; store away negativity
C=:number_is_negative
1C=D
C=1I
D='0
?C=D:term_hex_number
; it's a decimal number
; rbp will store the number
R=d0
:decimal_number_loop
C=1I
D='9
?C>D:decimal_number_loop_end
D='0
?C<D:decimal_number_loop_end
C-=D
; multiply by 10
B=d10
A=R
mul
R=A
; add this digit
R+=C
I+=d1
!:decimal_number_loop
:decimal_number_loop_end
!:term_number_output
:term_hex_number
I+=d1
C=1I
D='x
; 0 followed by something other than x
?C!D:bad_term
I+=d1
; rbp will store the number
R=d0
:hex_number_loop
C=1I
D='0
?C<D:hex_number_loop_end
D=d58
?C<D:hex_number_0123456789
D='a
?C<D:hex_number_loop_end
D='f
?C>D:hex_number_loop_end
; one of the digits a-f
D=xffffffffffffffa9
!:hex_number_digit
:hex_number_0123456789
D=xffffffffffffffd0
:hex_number_digit
C+=D
; shift left by 4
R<=d4
; add digit
R+=C
I+=d1
!:hex_number_loop
:hex_number_loop_end
!:term_number_output
:term_number_output
; we now have the *unsigned* number in rbp. first, take the sign into consideration
C=:number_is_negative
D=1C
?D=0:number_not_negative
; R = -R
C=R
R=d0
R-=C
:number_not_negative
I=R
!:set_rax_to_immediate
; set <rax> to the immediate in rsi.
:set_rax_to_immediate
C=:imm64
8C=I
; write prefix
J=d4
D=d2
I=:mov_rax_imm64_prefix
syscall x1
; write immediate
J=d4
D=d8
I=:imm64
syscall x1
return
align align
:rax2term_addr :rax2term_addr
@ -593,6 +668,13 @@ align
:mov_ebx_imm32_prefix :mov_ebx_imm32_prefix
xbb xbb
:mov_rax_imm64_prefix
x48
xb8
align
:imm64
reserve d8
:mov_rax_[rbx] :mov_rax_[rbx]
x48 x48
x8b x8b
@ -604,60 +686,12 @@ align
x8b x8b
x85 x85
:input_filename
str in04b
x0
; read the space-terminated type from rsi, advance rsi, and set rax to the corresponding type number: :output_filename
; 0 for non-pointer types str out04b
; 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 x0
:input_file_error :input_file_error
@ -696,15 +730,6 @@ align
xa xa
x0 x0
:bad_type
B=:bad_type_error_message
!:program_error
:bad_type_error_message
str Bad type.
xa
x0
:bad_term :bad_term
B=:bad_term_error_message B=:bad_term_error_message
!:program_error !:program_error
@ -924,19 +949,6 @@ align
?D!C:memccpy ?D!C:memccpy
return return
:"char"
str char
x20
:"short"
str short
x20
:"int"
str int
x20
:"long"
str long
x20
:"global" :"global"
str global str global
x20 x20

View file

@ -1,3 +1,6 @@
:test
return -0x3874f
; declaration: ; declaration:
; global <type> <name> ; global <type> <name>
; local <type> <name> ; local <type> <name>
@ -10,8 +13,8 @@
; <lvalue> += <rvalue> ; <lvalue> += <rvalue>
; <lvalue> -= <rvalue> ; <lvalue> -= <rvalue>
; <function>(<term>, <term>, ...) ; <function>(<term>, <term>, ...)
; syscall <term> <term> ...
; return <rvalue> ; return <rvalue>
; string <str>
; byte <number> ; byte <number>
; term: ; term:
; <var> ; <var>
@ -22,17 +25,13 @@
; 0xabc ; 0xabc
; lvalue: ; lvalue:
; <var> ; <var>
; *<var> ; *1 <var> / *2 <var> / *4 <var> / *8 <var>
; <var>[<term>]
; rvalue: ; rvalue:
; `<string>`
; <var> ; <var>
; &<var> ; &<var>
; *1 <var> / *2 <var> / *4 <var> / *8 <var> ; *1 <var> / *2 <var> / *4 <var> / *8 <var>
; <var>[<term>]
; ~<var> ; ~<var>
; <function>(<term>, <term>, ...) ; <function>(<term>, <term>, ...)
; syscall <term>, <term>, ...
; <term> + <term> ; <term> + <term>
; <term> - <term> ; <term> - <term>
; NOTE: *, /, % are signed (imul and idiv) ; NOTE: *, /, % are signed (imul and idiv)
@ -51,6 +50,12 @@ global x
global y ;123 global y ;123
global z global z
:syscall
function
; ...
byte 0x0f
byte 0x05
:strlen :strlen
function function
argument s argument s
@ -72,7 +77,7 @@ function
argument c argument c
local p local p
p = &c p = &c
syscall 1 1 p 1 0 0 0 0 syscall(1, 1, p, 1)
return return
:puts :puts
@ -80,17 +85,17 @@ function
argument s argument s
local len local len
len = strlen(s) len = strlen(s)
syscall 1 1 s len 0 0 0 0 syscall(1, 1, s, len)
return return
:main :main
function function
local hello puts(str_hello_world)
hello = `Hello, world! syscall(0x3c, 0)
` :str_hello_world
puts(hello) string Hello, world!
syscall 0x3c 0 0 0 0 0 0 0 byte 10
byte 0
:f :f
function function
@ -103,6 +108,8 @@ function
*4p = v *4p = v
if v == 0 goto something if v == 0 goto something
*1p = v + 1 *1p = v + 1
return *2p v = *2p
return v
:something :something
return *4p v = *4p
return v