I am trying to create a program in Java that can read, compile and run brainfuck source files ( .bf ), I got this to work fine with the Wikipedia Hello World example, but it breaks down on the example of ROT13 (claims it reached unsurpassed ] , when it was actually matched).
The actual parser code is written to a single .JAVA file, but its heart (the actual brain analyzer and startup code) is located below, doNow(char) . Here's what the variables are: cells is an array of characters to be run ( char[] ); pointer is a Java workaround pointing to an address in an array ( short ); PC is the program counter ( int ), and loopStack is the address stack that matches [ (basically a short[] ). This is not a problem, as they work great in the Hello World test. The method that accepts the input automatically filters out the extra characters, and I confirmed that it works great with debugging checking.
Why doesn't this analyzer run ROT 13 code?
code
My java parser
/** The array of data */ private byte[] cells = new byte[Short.MAX_VALUE]; /** The pointer that is manipulated by the user or program */ private short pointer = 0; /** The program counter, to run compiled programs */ private int PC = 0; /** The compiled commands */ private ArrayPP<Character> commandBuffer = new ArrayPP<>(); /** The stack of locations of loop brackets ({@code [}) in the command buffer */ private ArrayPP<Short> loopStack = new ArrayPP<>();//ArrayPP is my proprietary augmented array object, which also functions as a perfectly working stack. public int doNow(char command) throws IOException { PC++; switch (command) { case '>': return ++pointer; case '<': return --pointer; case '+': return ++cells[pointer]; case '-': return --cells[pointer]; case '.': System.out.print((char)cells[pointer]); return 0; case ',': return cells[pointer] = (byte)System.in.read(); case '[': if (cells[pointer] == 0)//If we're ready to skip this conditional { int oldPC = PC; try { while (getCompiledCommand(PC) != ']')//Find the matching ] PC++; PC++;//Now that we're at the ], skip over it to the next command } catch (ArrayIndexOutOfBoundsException e) { throw new NullPointerException("Unmatched '[' at " + oldPC);//If we try to reference a command outside the buffer } } else//if we want to enter this conditional loopStack.push(PC - 1);//Add the location of this conditional to the list of conditionals which we are in return PC; case ']': try { return PC = loopStack.pop();//Move us to the matching [ and remove it from the list of conditionals we're in } catch (ArrayIndexOutOfBoundsException e) { throw new NullPointerException("Unmatched ] at " + PC);//If the loop stack is empty } default: throw new AssertionError(command + " is not a valid command."); } } public char getCompiledCommand(int commandIndex) { return commandBuffer.get(commandIndex);//Look into the buffer of precompiled commands and fetch the one at the given index }
Hello World example (works great)
+++++ +++++ initialize counter (cell #0) to 10 [ use loop to set the next four cells to 70/100/30/10 > +++++ ++ add 7 to cell #1 > +++++ +++++ add 10 to cell #2 > +++ add 3 to cell #3 > + add 1 to cell #4 <<<< - decrement counter (cell #0) ] > ++ . print 'H' > + . print 'e' +++++ ++ . print 'l' . print 'l' +++ . print 'o' > ++ . print ' ' << +++++ +++++ +++++ . print 'W' > . print 'o' +++ . print 'r' ----- - . print 'l' ----- --- . print 'd' > + . print '!' > . print '\n'
Example ROT 13 (my test console input is M ). Aborts command 54 after several iterations of the loop)
-,+[ Read first character and start outer character reading loop -[ Skip forward if character is 0 >>++++[>++++++++<-] Set up divisor (32) for division loop (MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero) <+<-[ Set up dividend (x minus 1) and enter division loop >+>+>-[>>>] Increase copy and remainder / reduce divisor / Normal case: skip forward <[[>+<-]>>+>] Special case: move remainder back to divisor and increase quotient <<<<<- Decrement dividend ] End division loop ]>>>[-]+ End skip loop; zero former divisor and reuse space for a flag >--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3; zero quotient; check flag ++++++++++++<[ If flag then set up divisor (13) for second division loop (MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero) >-[>+>>] Reduce divisor; Normal case: increase remainder >[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient <<<<<- Decrease dividend ] End division loop >>[<+>-] Add remainder back to divisor to get a useful 13 >[ Skip forward if quotient was 0 -[ Decrement quotient and skip forward if quotient was 1 -<<[-]>> Zero quotient and divisor if quotient was 2 ]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient was 1 ]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0 ] End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3) <[-] Clear remainder from first division if second division was skipped <.[-] Output ROT13ed character from copy and clear it <-,+ Read next character ] End character reading loop
to understand where it breaks:
>[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient ^