Implement interpreter

This commit is contained in:
2026-03-12 12:55:47 +00:00
commit d011453b4c

202
jitfuck.asm Normal file
View File

@@ -0,0 +1,202 @@
format ELF64 executable
RIGHT = 3Eh
LEFT = 3Ch
PLUS = 2Bh
MINUS = 2Dh
DOT = 2Eh
COMMA = 2Ch
LBRAC = 5Bh
RBRAC = 5Dh
CHUNK_MAX = 20h
CHUNK_SIZE = (CHUNK_MAX * 2)
CHUNK_MASK = (CHUNK_SIZE - 1)
MAX_CHUNKS = 20h
TRANSLATION_MAX = 40h
MEM = 100h
entry $
xor r12,r12 ; Initialize chunk start
.next_chunk:
xor r13,r13 ; Initialize chunk offset
.skip:
call key
.next_run:
cmp rax,0
je interpret ; EOF -> finished loading chunks
;; Dispatch on command
cmp rax,RIGHT
je .run_init
cmp rax,LEFT
je .run_init
cmp rax,PLUS
je .run_init
cmp rax,MINUS
je .run_init
cmp rax,DOT
je .run_init
cmp rax,COMMA
je .run_init
cmp rax,LBRAC
je .lbrac
cmp rax,RBRAC
je .rbrac
jmp .skip ; Skip non-command characters
.run_init:
mov r14,rax ; Save rax as run command
mov r15,1 ; Initialize run count to 1
.run:
call key
cmp rax,r14
jne .run_write ; Write run if different command
inc r15 ; Increment run count
jmp .run
.run_write:
mov rbx,r12
add rbx,r13
mov byte [chunks+rbx],r14b ; Write command
mov byte [chunks+rbx+1],r15b ; Write run count
add r13,2 ; Increment chunk offset
jmp .next_run
.lbrac:
mov rbx,r12
add rbx,CHUNK_SIZE
push rbx ; Push start of next chunk
mov rax,r12
add rax,r13
mov byte [chunks+rax],LBRAC ; Write command
mov byte [chunks+rax+1],0 ; Zero run count field
lea rbx,[chunks+rax+2]
push rbx ; Push address of dest field
jmp .end_chunk
.rbrac:
pop rax ; Pop address of lbrac's dest field
mov rbx,r12
add rbx,CHUNK_SIZE
mov word [rax],bx ; Write start of next chunk to lbrac's dest field
mov rax,r12
add rax,r13
mov byte [chunks+rax],RBRAC ; Write command
mov byte [chunks+rax+1],0 ; Zero run count field
pop rbx ; Pop start of chunk after lbrac
mov word [chunks+rax+2],bx ; Write to dest field
jmp .end_chunk
.end_chunk:
mov word [chunks+rax+4],0 ; Write chunk terminator
add r12,CHUNK_SIZE ; Bump chunk start to next chunk
jmp .next_chunk
interpret:
xor r12,r12 ; Initialize code offset
mov r13,mem ; Initialize head
.opcode_dispatch:
mov word ax,[chunks+r12]
movzx ebx,ah
cmp al,RIGHT
je .right
cmp al,LEFT
je .left
cmp al,PLUS
je .plus
cmp al,MINUS
je .minus
cmp al,DOT
je .dot
cmp al,COMMA
je .comma
cmp al,LBRAC
je .lbrac
cmp al,RBRAC
je .rbrac
jmp exit
.right:
add r13,rbx
jmp .next
.left:
sub r13,rbx
jmp .next
.plus:
add byte [r13],bl
jmp .next
.minus:
sub byte [r13],bl
jmp .next
.dot:
mov r14,rbx
.dot_loop:
cmp r14,0
je .next
call emit
dec r14
jmp .dot_loop
.comma: ; TODO
int3
jmp .next
.lbrac:
cmp byte [r13],0
jne .next_chunk
mov word r12w,[chunks+r12+2]
jmp .opcode_dispatch
.rbrac:
cmp byte [r13],0
je .next_chunk
mov word r12w,[chunks+r12+2]
jmp .opcode_dispatch
.next:
add r12,2
jmp .opcode_dispatch
.next_chunk:
and r12,(not CHUNK_MASK)
add r12,CHUNK_SIZE
jmp .opcode_dispatch
exit:
mov rdi,0
mov rax,60
syscall
key:
mov rdi,0
mov rsi,.ch
mov rdx,1
mov rax,0
syscall
cmp rax,0
je .eof
mov byte al,[.ch]
ret
.eof:
ret
.ch: rb 1
emit:
mov rdi,1
mov rsi,r13
mov rdx,1
mov rax,1
syscall
ret
chunks: rw (CHUNK_MAX * MAX_CHUNKS)
translations: rb (TRANSLATION_MAX * MAX_CHUNKS)
mem: db MEM dup 0