Files

225 lines
4.2 KiB
Plaintext

// a simple brainf##k interpreter,
// because I already wrote a compiler lol.
include print "./lib/io/print.dsa"
// "print hello world"
db program: "++++++++++++++++++++++++++++++++++++++++++++
>++++++++++++++++++++++++++++++++
>++++++++++++++++
>
>+
<<
[
>>
>
>++++++++++
<<
[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]
>[<+>-]
>[-]
>>
>++++++++++
<
[->-[>+>>]>[+[-<+>]>+>>]<<<<<]
>[-]
>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]
<[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]
<<<++++++++++++++++++++++++++++++++++++++++++++++++.[-]
<<<<<<<.>.
>>[>>+<<-]
>[>+<<+>-]
>[<+>-]
<<<-
]
<<++..."
db error: "Invalid Instruction!"
dw stack: 0x10000
dw input: 0x30000
resb data: 1024
// set up a stack so we can call functions
_init_stack:
ldw stack, bpr
mov bpr, spr
start:
// load the start of the program into rg0
lwi program, rg0
lwi data, rg1
// rg0 is our instruction pointer
// rg1 is our data pointer
// rg2 is the value at the data pointer
// rg3 stores the current instruction
// rg4 is the expression nesting level.
lli 43, rg8 // + = 43 increment
lli 45, rg9 // - = 45 decrement
lli 62, rga // > = 62 increment pointer
lli 60, rgb // < = 60 decrement pointer
lli 46, rgc // . = 46 output
lli 44, rgd // , = 44 input
lli 91, rge // [ = 91 loop start
lli 93, rgf // ] = 93 loop end
loop_start:
// load the current instruction into rg3
ldb rg0, rg3
// switch on the instruction
// all cases will return to either loop_start or loop_end
cmp rg3, rg8
jeq increment
cmp rg3, rg9
jeq decrement
cmp rg3, rga
jeq inc_ptr
cmp rg3, rgb
jeq dec_ptr
cmp rg3, rgc
jeq output
cmp rg3, rgd
jeq input
cmp rg3, rge
jeq expr_start
cmp rg3, rgf
jeq expr_end
cmp rg3, zero
jeq end
// if we get here, we don't know what the instruction is
lwi error, rg2
pusha 2
push rg2
call print::print
pop zero
popa 2
end:
hlt
loop_end:
inc rg0
jmp loop_start
// ------------------------------------------
// increment the current cell
increment:
inc rg2
jmp loop_end
// ------------------------------------------
// decrement the current cell
decrement:
dec rg2
jmp loop_end
// ------------------------------------------
// increment the pointer
inc_ptr:
stw rg2, rg1
addi rg1, 4
ldw rg1, rg2
jmp loop_end
// ------------------------------------------
// decrement the pointer
dec_ptr:
stw rg2, rg1
subi rg1, 4
ldw rg1, rg2
jmp loop_end
// ------------------------------------------
// print the byte in the current cell
output:
pusha 2
push rg2
call print::print_byte
pop zero
popa 2
jmp loop_end
// ------------------------------------------
// read a byte into the current cell
input:
ldw input, rg2
jmp loop_end
// ------------------------------------------
// handle an open bracket instruction
expr_start:
cmp rg2, zero
jne loop_end
_traverse_right_start:
// push a register that definitely has a nonzero value
// when we pop this value from the stack
// we know we've finished traversing.
push rg8
_traverse_right:
inc rg0
ldb rg0, rg3
cmp rg3, rge
jeq open_right
cmp rg3, rgf
jeq close_right
cmp rg3, zero
jeq end
jmp _traverse_right
open_right:
// push zero to the stack
push zero
jmp _traverse_right
close_right:
// check if we've reached the bottom of the stack
pop rg4
cmp rg4, zero
jeq _traverse_right
// go to next instruction after closing bracket
inc rg0
jmp loop_start
// ------------------------------------------
// handle the close bracket instruction
expr_end:
cmp rg2, zero
jeq loop_end
_traverse_left_start:
push rg8
_traverse_left:
dec rg0
ldb rg0, rg3
cmp rg3, rge
jeq open_left
cmp rg3, rgf
jeq close_left
cmp rg3, zero
jeq end
jmp _traverse_left
open_left:
// check if we've reached the bottom of the stack
pop rg4
cmp rg4, zero
jeq _traverse_left
// go to next instruction after open bracket
inc rg0
jmp loop_start
close_left:
// push zero to the stack
push zero
jmp _traverse_left