summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--04b/in03861
-rw-r--r--04b/in04b35
-rw-r--r--instructions.txt8
3 files changed, 806 insertions, 98 deletions
diff --git a/04b/in03 b/04b/in03
index 66bc3a6..985ad9b 100644
--- a/04b/in03
+++ b/04b/in03
@@ -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]
@@ -1272,13 +1747,156 @@ align
:mov_al_[rbx]
x8a
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
-align
+: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
@@ -1367,6 +1985,15 @@ align
str Bad number.
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
@@ -1376,6 +2003,15 @@ align
str Bad term.
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
@@ -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
diff --git a/04b/in04b b/04b/in04b
index caee4f0..57cc34b 100644
--- a/04b/in04b
+++ b/04b/in04b
@@ -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
diff --git a/instructions.txt b/instructions.txt
index 03b13cf..39bc1b6 100644
--- a/instructions.txt
+++ b/instructions.txt
@@ -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