Files
DSA/dsa_resources/bf.dsa
T

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