This commit is contained in:
pommicket 2022-01-06 17:37:02 -05:00
parent db552a4dca
commit 6f1a085586
3 changed files with 806 additions and 98 deletions

859
04b/in03
View file

@ -147,6 +147,20 @@ call :string=
D=A
?D!0:handle_string
I=:line
J=:"goto"
C=x20
call :string=
D=A
?D!0:handle_goto
I=:line
J=:"if"
C=x20
call :string=
D=A
?D!0:handle_if
; set delimiter to newline
C=xa
@ -162,6 +176,18 @@ call :string=
D=A
?D!0:handle_return
; check if this is an assignment
I=:line
:assignment_check_loop
C=1I
D=xa
?C=D:assignment_check_loop_end
D='=
?C=D:handle_assignment
I+=d1
!:assignment_check_loop
:assignment_check_loop_end
; check if this is a function call (where we discard the return value)
I=:line
; (check for an opening bracket not preceded by a space)
@ -458,7 +484,7 @@ align
call :ident_copy
R=J
; figure out where in the file we are
; figure out where in the file we are (using lseek)
J=d4
I=d0
D=d1
@ -477,6 +503,496 @@ align
; read the next line
!:read_line
:handle_goto
J=d4
I=:jmp_prefix
D=d1
syscall x1
I=:line
; 5 = length of "goto "
I+=d5
call :emit_label_jump_address
!:read_line
:jmp_prefix
xe9
:handle_if
I=:line
I+=d3
; skip term 1
call :go_to_space
I+=d1
; skip operator
call :go_to_space
I+=d1
; put second operand in rsi
call :set_rax_to_term
call :set_rsi_to_rax
I=:line
; length of "if "
I+=d3
; put first operand in rax
call :set_rax_to_term
; put second operand in rbx
call :set_rbx_to_rsi
; emit cmp rax, rbx
J=d4
I=:cmp_rax_rbx
D=d3
syscall x1
I=:line
I+=d3
call :go_to_space
I+=d1
R=I
C=x20
I=R
J=:"=="
call :string=
I=A
?I!0:write_je
I=R
J=:"!="
call :string=
I=A
?I!0:write_jne
I=R
J=:">"
call :string=
I=A
?I!0:write_jg
I=R
J=:"<"
call :string=
I=A
?I!0:write_jl
I=R
J=:">="
call :string=
I=A
?I!0:write_jge
I=R
J=:"<="
call :string=
I=A
?I!0:write_jle
I=R
J=:"]"
call :string=
I=A
?I!0:write_ja
I=R
J=:"["
call :string=
I=A
?I!0:write_jb
I=R
J=:"]="
call :string=
I=A
?I!0:write_jae
I=R
J=:"[="
call :string=
I=A
?I!0:write_jbe
!:bad_jump
:write_je
J=d4
I=:je_prefix
D=d2
syscall x1
!:if_continue
:write_jne
J=d4
I=:jne_prefix
D=d2
syscall x1
!:if_continue
:write_jl
J=d4
I=:jl_prefix
D=d2
syscall x1
!:if_continue
:write_jg
J=d4
I=:jg_prefix
D=d2
syscall x1
!:if_continue
:write_jle
J=d4
I=:jle_prefix
D=d2
syscall x1
!:if_continue
:write_jge
J=d4
I=:jge_prefix
D=d2
syscall x1
!:if_continue
:write_jb
J=d4
I=:jb_prefix
D=d2
syscall x1
!:if_continue
:write_ja
J=d4
I=:ja_prefix
D=d2
syscall x1
!:if_continue
:write_jbe
J=d4
I=:jbe_prefix
D=d2
syscall x1
!:if_continue
:write_jae
J=d4
I=:jae_prefix
D=d2
syscall x1
!:if_continue
:if_continue
I=:line
I+=d3
; skip term 1
call :go_to_space
I+=d1
; skip operator
call :go_to_space
I+=d1
; skip term 2
call :go_to_space
I+=d1
J=:"goto"
C=x20
call :string=
C=A
; make sure word after term 2 is "goto"
?C=0:bad_jump
I+=d1
call :emit_label_jump_address
!:read_line
:je_prefix
x0f
x84
:jne_prefix
x0f
x85
:jl_prefix
x0f
x8c
:jg_prefix
x0f
x8f
:jle_prefix
x0f
x8e
:jge_prefix
x0f
x8d
:jb_prefix
x0f
x82
:ja_prefix
x0f
x87
:jbe_prefix
x0f
x86
:jae_prefix
x0f
x83
:cmp_rax_rbx
x48
x39
xd8
align
:reladdr
reserve d4
; emit relative address (for jumping) of label in rsi
:emit_label_jump_address
; address doesn't matter for first pass
C=:second_pass
C=1C
?C=0:jump_ignore_address
; look up label; store address in rbp
J=:labels
call :ident_lookup
C=A
?C=0:bad_label
R=4C
:jump_ignore_address
; first, figure out current address
J=d4
I=d0
D=d1
syscall x8
C=A
; add an additional 4 because the relative address is 4 bytes long
C+=x400004
; compute relative address
D=d0
D-=C
D+=R
; store in :reladdr
C=:reladdr
4C=D
; output
J=d4
I=:reladdr
D=d4
syscall x1
return
align
:assignment_type
reserve d8
:handle_assignment
I-=d1
C=:assignment_type
8C=I
I+=d2
C=1I
D=x20
; check for space after =
?C!D:bad_assignment
I+=d1
; set rdi to right-hand side of assignment
call :set_rax_to_rvalue
call :set_rdi_to_rax
J=:assignment_type
J=8J
C=1J
; put newline after lvalue to make parsing easier
D=xa
1J=D
D=x20
?C=D:handle_assignment_cont
J-=d1
D=xa
1J=D
:handle_assignment_cont
D=x20
?C=D:handle_plain_assignment
D='+
?C=D:handle_+=
D='-
?C=D:handle_-=
D='*
?C=D:handle_*=
D='/
?C=D:handle_/=
D='%
?C=D:handle_%=
D='&
?C=D:handle_&=
D='|
?C=D:handle_|=
D='^
?C=D:handle_^=
D='<
?C=D:handle_<=
D='>
?C=D:handle_>=
!:bad_assignment
:handle_plain_assignment
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_+=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_add_rax_rbx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_-=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_sub_rax_rbx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_*=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_imul_rbx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_/=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_zero_rdx_idiv_rbx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_%=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_zero_rdx_idiv_rbx
call :set_rax_to_rdx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_&=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_and_rax_rbx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_|=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_or_rax_rbx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_^=
I=:line
call :set_rax_to_rvalue
call :set_rbx_to_rdi
call :emit_xor_rax_rbx
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_<=
I=:line
call :set_rax_to_rvalue
call :set_rcx_to_rdi
call :emit_shl_rax_cl
I=:line
call :set_lvalue_to_rax
!:read_line
:handle_>=
I=:line
call :set_rax_to_rvalue
call :set_rcx_to_rdi
call :emit_shr_rax_cl
I=:line
call :set_lvalue_to_rax
!:read_line
align
:lvalue
reserve d8
; set the lvalue in rsi to <rax>
:set_lvalue_to_rax
C=:lvalue
8C=I
; first, store away <rax> value in <rdi>
R=I
call :set_rdi_to_rax
I=R
C=:lvalue
I=8C
C=1I
D='*
?C=D:lvalue_deref
; not a dereference; just a variable
C=:lvalue
I=8C
call :set_rax_to_address_of_variable
call :set_rbx_to_rax
call :set_rax_to_rdi
call :set_[rbx]_to_rax
return
:lvalue_deref
C=:lvalue
I=8C
I+=d2
call :set_rax_to_address_of_variable
call :set_rbx_to_rax
call :set_rax_to_[rbx]
call :set_rbx_to_rax
call :set_rax_to_rdi
C=:lvalue
I=8C
I+=d1
C=1I
D='1
?C=D:lvalue_deref1
D='2
?C=D:lvalue_deref2
D='4
?C=D:lvalue_deref4
D='8
?C=D:lvalue_deref8
!:bad_assignment
:lvalue_deref1
!:set_[rbx]_to_al
:lvalue_deref2
!:set_[rbx]_to_ax
:lvalue_deref4
!:set_[rbx]_to_eax
:lvalue_deref8
!:set_[rbx]_to_rax
:handle_return
I=:line
@ -819,122 +1335,45 @@ align
:rvalue_add
call :set_rbx_to_rsi
J=d4
I=:add_rax_rbx
D=d3
syscall x1
return
:add_rax_rbx
x48
x01
xd8
!:emit_add_rax_rbx
:rvalue_sub
call :set_rbx_to_rsi
J=d4
I=:sub_rax_rbx
D=d3
syscall x1
return
:sub_rax_rbx
x48
x29
xd8
!:emit_sub_rax_rbx
:rvalue_mul
call :set_rbx_to_rsi
J=d4
I=:imul_rbx
D=d3
syscall x1
return
:imul_rbx
x48
xf7
xeb
!:emit_imul_rbx
:rvalue_div
call :set_rbx_to_rsi
call :zero_rdx
J=d4
I=:idiv_rbx
D=d3
syscall x1
return
:idiv_rbx
x48
xf7
xfb
!:emit_zero_rdx_idiv_rbx
:rvalue_rem
call :set_rbx_to_rsi
call :zero_rdx
J=d4
I=:idiv_rbx
D=d3
syscall x1
call :emit_zero_rdx_idiv_rbx
call :set_rax_to_rdx
return
:rvalue_and
call :set_rbx_to_rsi
J=d4
I=:and_rax_rbx
D=d3
syscall x1
return
:and_rax_rbx
x48
x21
xd8
!:emit_and_rax_rbx
:rvalue_or
call :set_rbx_to_rsi
J=d4
I=:or_rax_rbx
D=d3
syscall x1
return
:or_rax_rbx
x48
x09
xd8
!:emit_or_rax_rbx
:rvalue_xor
call :set_rbx_to_rsi
J=d4
I=:xor_rax_rbx
D=d3
syscall x1
return
:xor_rax_rbx
x48
x31
xd8
!:emit_xor_rax_rbx
:rvalue_shl
call :set_rcx_to_rsi
J=d4
I=:shl_rax_cl
D=d3
syscall x1
return
:shl_rax_cl
x48
xd3
xe0
!:emit_shl_rax_cl
:rvalue_shr
call :set_rcx_to_rsi
J=d4
I=:shr_rax_cl
D=d3
syscall x1
return
:shr_rax_cl
x48
xd3
xe8
!:emit_shr_rax_cl
:rvalue_addressof
I+=d1
@ -1204,6 +1643,15 @@ align
:mov_rbx_rsi
B=I
:set_rbx_to_rdi
J=d4
I=:mov_rbx_rdi
D=d3
syscall x1
return
:mov_rbx_rdi
B=J
:set_rcx_to_rsi
J=d4
I=:mov_rcx_rsi
@ -1213,6 +1661,15 @@ align
:mov_rcx_rsi
C=I
:set_rcx_to_rdi
J=d4
I=:mov_rcx_rdi
D=d3
syscall x1
return
:mov_rcx_rdi
C=J
:set_rax_to_rdx
J=d4
I=:mov_rax_rdx
@ -1222,6 +1679,15 @@ align
:mov_rax_rdx
A=D
:set_rax_to_rdi
J=d4
I=:mov_rax_rdi
D=d3
syscall x1
return
:mov_rax_rdi
A=J
:set_rsi_to_rax
J=d4
I=:mov_rsi_rax
@ -1231,6 +1697,15 @@ align
:mov_rsi_rax
I=A
:set_rdi_to_rax
J=d4
I=:mov_rdi_rax
D=d3
syscall x1
return
:mov_rdi_rax
J=A
:set_rax_to_[rbx]
J=d4
I=:mov_rax_[rbx]
@ -1274,10 +1749,153 @@ align
x03
:set_[rbx]_to_rax
J=d4
I=:mov_[rbx]_rax
D=d3
syscall x1
return
:mov_[rbx]_rax
x48
x89
x03
:set_[rbx]_to_eax
J=d4
I=:mov_[rbx]_eax
D=d2
syscall x1
return
:mov_[rbx]_eax
x89
x03
:set_[rbx]_to_ax
J=d4
I=:mov_[rbx]_ax
D=d3
syscall x1
return
:mov_[rbx]_ax
x66
x89
x03
:set_[rbx]_to_al
J=d4
I=:mov_[rbx]_al
D=d2
syscall x1
return
:mov_[rbx]_al
x88
x03
:mov_rax_imm64_prefix
x48
xb8
:emit_add_rax_rbx
J=d4
I=:add_rax_rbx
D=d3
syscall x1
return
:add_rax_rbx
x48
x01
xd8
:emit_sub_rax_rbx
J=d4
I=:sub_rax_rbx
D=d3
syscall x1
return
:sub_rax_rbx
x48
x29
xd8
:emit_and_rax_rbx
J=d4
I=:and_rax_rbx
D=d3
syscall x1
return
:and_rax_rbx
x48
x21
xd8
:emit_or_rax_rbx
J=d4
I=:or_rax_rbx
D=d3
syscall x1
return
:or_rax_rbx
x48
x09
xd8
:emit_xor_rax_rbx
J=d4
I=:xor_rax_rbx
D=d3
syscall x1
return
:xor_rax_rbx
x48
x31
xd8
:emit_shl_rax_cl
J=d4
I=:shl_rax_cl
D=d3
syscall x1
return
:shl_rax_cl
x48
xd3
xe0
:emit_shr_rax_cl
J=d4
I=:shr_rax_cl
D=d3
syscall x1
return
:shr_rax_cl
x48
xd3
xe8
:emit_imul_rbx
J=d4
I=:imul_rbx
D=d3
syscall x1
return
:imul_rbx
x48
xf7
xeb
:emit_zero_rdx_idiv_rbx
call :zero_rdx
J=d4
I=:idiv_rbx
D=d3
syscall x1
return
:idiv_rbx
x48
xf7
xfb
align
:imm64
reserve d8
@ -1368,6 +1986,15 @@ align
xa
x0
:bad_assignment
B=:bad_assignment_error_message
!:program_error
:bad_assignment_error_message
str Bad assignment.
xa
x0
:bad_term
B=:bad_term_error_message
!:program_error
@ -1377,6 +2004,15 @@ align
xa
x0
:bad_jump
B=:bad_jump_error_message
!:program_error
:bad_jump_error_message
str Bad jump.
xa
x0
:bad_call
B=:bad_call_error_message
!:program_error
@ -1596,6 +2232,16 @@ align
?D!C:memccpy
return
; advance rsi to the next space or newline character
:go_to_space
C=1I
D=xa
?C=D:return_0
D=x20
?C=D:return_0
I+=d1
!:go_to_space
:"global"
str global
x20
@ -1617,9 +2263,46 @@ align
:"string"
str string
x20
:"goto"
str goto
x20
:"if"
str if
x20
:"function"
str function
xa
:"=="
str ==
x20
:"!="
str !=
x20
:">"
str >
x20
:"<"
str <
x20
:"<="
str <=
x20
:">="
str >=
x20
:"["
str [
x20
:"]"
str ]
x20
:"[="
str [=
x20
:"]="
str ]=
x20
:zero
x0

View file

@ -3,9 +3,10 @@
; local <name>
; argument <name>
; :<label>
; .<label> (local label)
; statement:
; <declaration>
; if <term> <==/</>/>=/<=/!=> <term> goto <label> NOTE: this uses signed comparisons
; if <term> <==/</>/>=/<=/!=/[/]/[=/]=> <term> goto <label> NOTE: this uses signed comparisons
; goto <label>
; <lvalue> = <rvalue>
; <lvalue> += <rvalue>
@ -43,8 +44,24 @@
; <term> < <term> (left shift)
; <term> > <term> (unsigned right shift)
syscall(1, 1, .str_hw, 14)
syscall(0x3c, 42)
if 0 > -1 goto main
syscall(0x3c, 0)
:main
function
global str
global strp
local offset
strp = &str
*8strp = .str_hw
offset = 2
offset &= offset
offset %= 2
*8strp += offset
syscall(1, 1, str, 14)
syscall(0x3c, 42)
:str_hw
string Hello, world!
@ -173,8 +190,8 @@ function
len = 0
:strlen_loop
p = s + len
c = *1 p
if c == 0 goto strlen_loop_end
c = *1p
; if c == 0 goto strlen_loop_end
len += 1
goto strlen_loop
:strlen_loop_end
@ -196,7 +213,7 @@ function
syscall(1, 1, s, len)
return
:main
:main2
function
puts(.str_hello_world)
syscall(0x3c, 0)
@ -213,9 +230,9 @@ function
local p
v = *4x
p = *8y
*4p = v
if v == 0 goto something
*1p = v + 1
;*4p = v
;if v == 0 goto something
;*1p = v + 1
v = *2p
return v
:something

View file

@ -105,10 +105,18 @@ jl rel32
>0f 8c REL32
jg rel32
>0f 8f REL32
jle rel32
>0f 8e REL32
jge rel32
>0f 8d REL32
jb rel32
>0f 82 REL32
ja rel32
>0f 87 REL32
jbe rel32
>0f 86 REL32
jae rel32
>0f 83 REL32
call rax
>ff d0
ret