// a simple brainf##k interpreter, // because I already wrote a compiler lol. include print "./lib/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