273 lines
5.2 KiB
Plaintext
273 lines
5.2 KiB
Plaintext
// a simple brainf##k interpreter,
|
|
// because I already wrote a compiler lol.
|
|
|
|
include print "./print.dsa"
|
|
|
|
// "prints first 16 fibonacci numbers"
|
|
db program: "++++++++++++++++++++++++++++++++++++++++++++
|
|
>++++++++++++++++++++++++++++++++
|
|
>++++++++++++++++
|
|
>
|
|
>+
|
|
<<
|
|
[
|
|
>>
|
|
>
|
|
>++++++++++
|
|
<<
|
|
[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<]
|
|
>[<+>-]
|
|
>[-]
|
|
>>
|
|
>++++++++++
|
|
<
|
|
[->-[>+>>]>[+[-<+>]>+>>]<<<<<]
|
|
>[-]
|
|
>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]
|
|
<[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]
|
|
<<<++++++++++++++++++++++++++++++++++++++++++++++++.[-]
|
|
<<<<<<<.>.
|
|
>>[>>+<<-]
|
|
>[>+<<+>-]
|
|
>[<+>-]
|
|
<<<-
|
|
]
|
|
<<++..."
|
|
|
|
db error: "Invalid Instruction!"
|
|
dh counter: 0xFF
|
|
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
|
|
|
|
init:
|
|
ldw counter, rg7
|
|
|
|
start:
|
|
call bf_reset
|
|
|
|
// 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
|
|
ieq rg3, rg8, rg4
|
|
jnz rg4, increment
|
|
ieq rg3, rg9, rg4
|
|
jnz rg4, decrement
|
|
ieq rg3, rga, rg4
|
|
jnz rg4, inc_ptr
|
|
ieq rg3, rgb, rg4
|
|
jnz rg4, dec_ptr
|
|
ieq rg3, rgc, rg4
|
|
jnz rg4, output
|
|
ieq rg3, rgd, rg4
|
|
jnz rg4, input
|
|
ieq rg3, rge, rg4
|
|
jnz rg4, expr_start
|
|
ieq rg3, rgf, rg4
|
|
jnz rg4, expr_end
|
|
ieq rg3, zero, rg4
|
|
jnz rg4, end
|
|
|
|
// if we get here, we don't know what the instruction is
|
|
lwi error, rg2
|
|
push rg0
|
|
push rg1
|
|
push rg2
|
|
call print::print
|
|
pop zero
|
|
pop rg1
|
|
pop rg0
|
|
|
|
db success: "Success!"
|
|
end:
|
|
call print::newline
|
|
lwi success, rg0
|
|
push rg0
|
|
call print::print
|
|
pop zero
|
|
|
|
subi rg7, 1
|
|
jnz rg7, start
|
|
hlt
|
|
|
|
loop_end:
|
|
addi rg0, 1, rg0
|
|
jmp loop_start
|
|
|
|
// ------------------------------------------
|
|
// increment the current cell
|
|
increment:
|
|
addi rg2, 1, rg2
|
|
jmp loop_end
|
|
|
|
// ------------------------------------------
|
|
// decrement the current cell
|
|
decrement:
|
|
subi rg2, 1, 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:
|
|
push rg0
|
|
push rg1
|
|
push rg2
|
|
call print::print_byte
|
|
pop zero
|
|
pop rg1
|
|
pop rg0
|
|
jmp loop_end
|
|
|
|
// ------------------------------------------
|
|
// read a byte into the current cell
|
|
input:
|
|
ldw input, rg2
|
|
jmp loop_end
|
|
|
|
// ------------------------------------------
|
|
// handle an open bracket instruction
|
|
expr_start:
|
|
ieq rg2, zero, rg4
|
|
jez rg4, 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:
|
|
addi rg0, 1, rg0
|
|
ldb rg0, rg3
|
|
|
|
ieq rg3, rge, rg4
|
|
jnz rg4, open_right
|
|
ieq rg3, rgf, rg4
|
|
jnz rg4, close_right
|
|
ieq rg3, zero, rg4
|
|
jnz rg4, 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
|
|
ieq rg4, zero, rg5
|
|
jnz rg5, _traverse_right
|
|
|
|
// go to next instruction after closing bracket
|
|
addi rg0, 1, rg0
|
|
jmp loop_start
|
|
|
|
// ------------------------------------------
|
|
// handle the close bracket instruction
|
|
expr_end:
|
|
ieq rg2, zero, rg4
|
|
jnz rg4, loop_end
|
|
|
|
_traverse_left_start:
|
|
push rg8
|
|
|
|
_traverse_left:
|
|
subi rg0, 1, rg0
|
|
ldb rg0, rg3
|
|
|
|
ieq rg3, rge, rg4
|
|
jnz rg4, open_left
|
|
ieq rg3, rgf, rg4
|
|
jnz rg4, close_left
|
|
ieq rg3, zero, rg4
|
|
jnz rg4, end
|
|
jmp _traverse_left
|
|
|
|
open_left:
|
|
// check if we've reached the bottom of the stack
|
|
pop rg4
|
|
ieq rg4, zero, rg5
|
|
jnz rg5, _traverse_left
|
|
|
|
// go to next instruction after open bracket
|
|
addi rg0, 1, rg0
|
|
jmp loop_start
|
|
|
|
close_left:
|
|
// push zero to the stack
|
|
push zero
|
|
jmp _traverse_left
|
|
|
|
|
|
// ------------------------------------------
|
|
// reset interpreter
|
|
// clears screen, resets cursor and clears data buffer.
|
|
bf_reset: func
|
|
push rg0
|
|
push rg1
|
|
|
|
// clear screen and reset cursor
|
|
call print::clear
|
|
call print::reset
|
|
|
|
// clear data buffer (resb data: 1024 = 256 words)
|
|
lli 256, rg0
|
|
lwi data, rg1
|
|
_bf_reset_clear_data:
|
|
subi rg0, 1, rg0
|
|
stw zero, rg1
|
|
addi rg1, 4, rg1
|
|
igt rg0, zero, rg4
|
|
jnz rg4, _bf_reset_clear_data
|
|
|
|
pop rg1
|
|
pop rg0
|
|
|
|
// reload interpreter state
|
|
lwi program, rg0
|
|
lwi data, rg1
|
|
lli 0, rg2
|
|
return
|