
// 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
