From d011453b4c0812e7ecb1945a09994d5f91d1031d Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Thu, 12 Mar 2026 12:55:47 +0000 Subject: [PATCH] Implement interpreter --- jitfuck.asm | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 jitfuck.asm diff --git a/jitfuck.asm b/jitfuck.asm new file mode 100644 index 0000000..4c89e66 --- /dev/null +++ b/jitfuck.asm @@ -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