What's wrong with my brainfuck parser code? - java

I'm trying to make a program in Java that can read, compile, and run brainfuck source files (.bf). I've gotten it to work just fine with Wikipedia's Hello World example, but it breaks on the ROT13 example (claims it reached an unmatched ] when it was actually matched).
The actual parser code is all written in one .JAVA file, but the heart of it (the actual brainfuck parser and running code) is in the below method, doNow(char). Here are what the variables are: cells is the array of characters to be run (char[]); pointer is the Java workaround to point to an address in the array (short); PC is the program counter (int), and loopStack is a stack of addresses which correspond to [s (basically a short[]). These are not the problem, as they work just fine in the Hello World test. The method that takes input automatically filters out excess characters, and I confirmed it to work perfectly from debug inspection.
Why doesn't this parser run the ROT 13 code?
Code
My parser, written in Java
/** 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
}
The Hello World example (works perfectly)
+++++ +++++ 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'
ROT 13 example (My test console input is M. Breaks on command 54 after several loop iterations)
-,+[ 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 make it clear, here's where it breaks:
>[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient
^

You should keep track of '[]' nestedness in the '[' case branch: now, the match for the first '[' in [+++[----]+] is the first ']', which is not good.

Problem
It seems the problem lies in this line:
while (getCompiledCommand(PC) != ']')//Find the matching ]
This works fine in the Hello World program because it has no nested loops. However, with nested loops, we run into the problem that it hits the first encountered ], which is not always the matching ].
Fix
One possible fix is to introduce a variable before the while loop, say loopCount, and increment it every time a [ is encountered, then decrement it when a ] is encountered and loopCount is greater than 0. For instance:
int loopCount = 0;
while ((command = getCompiledCommand(PC)) != ']' && loopCount == 0)//Find the matching ]. We can save the return in command because we're done using it.
{
if (command == '[')//If we run into a nested loop
loopCount++;
else if (command == ']')//If we run into the end of a nested loop
loopCount--;
PC++;
}

Related

Why does Java integer act erroneously at values near 2^31-1?

I'm trying to write a Java program to calculate the square root of an integer x, without using in-built functions like Math.pow() . This is the approach I tried -
class Solution {
public int mySqrt(int x) {
if(x==0 || x==1)
return x;
// if(x>=2147395600)
// return 46340;
int i;
for(i=1 ; i*i<=x ; i++) {}
return i-1;
}
}
Without the commented part, I start getting errors if x is in the range 2147395600 <= x <= 2^31-1 (which is the upper limit of an int's value range in Java). For instance, for the input x=2147395600, the expected output is 46340 but the actual output is 289398. Why is this happening? Thanks to all in advance.
PS - I am aware there are other (better) methods to solve this problem, but I'd really like to know why this code behaves this way.
Since 46340 * 46340 = 2147395600, when i=46340, x=2147395600 and you reach the condition i*i<=x it evaluates to true since 2147395600 = 2147395600. So the loop counter will incremnet by 1 and in the next iteration we will get i=46341 and i * i will cause an overflow - 46341*46341 = -2147479015.
The loop condition will still be true, since -2147479015 <= 2147395600, and the loop will not stop.
You can replace the <= with =, and check for edge cases that may occur now.

1-bit and 2-bit Characters

We have two special characters. The first character can be represented by one bit 0. The second character can be represented by two bits (10 or 11).
Now given a string represented by several bits. Return whether the last character must be a one-bit character or not. The given string will always end with a zero.
Example 1:
Input:
bits = [1, 0, 0]
Output: True
Input:
bits = [1, 1, 1, 0]
Output: False
class Solution {
public boolean isOneBitCharacter(int[] bits) {
int n = bits.length-1;
int count = 0;
for(int i=n;i<=n;i--){
if(bits[i]==1){
count++;
}else break;
}return count%2==0;
}
}
this code is not working for some test cases
my 2nd example test case is not working
Try this:
public boolean isOneBitCharacter(int[] bits) {
int n = bits.length - 1;
int count = 0;
while (count < n) {
count += bits[count] + 1;
}
return count == n;
}
Explanation:
You start reading from left to right, if you encounter bits[i] == 0, it means that the next character will have 1 bit. And if bits[i] == 1 it means that the next character will have 2 bits. You keep incrementing the count to the start of each next character. In the end, if count is equals to n, it would mean that the last character is 1 bit.
For long bitstreams would be much faster to investigate the bit-stream from the end... However its a bit more harder to detect the cases. When we look at the ending bits:
.....00 // 1 bit
.....01 // error
.....10 // 1/2 bit
.....11 // 2 bit
we can determine answer right away unless the .....10 case is present in which case we need to investigate one more bit:
....110 // 1/2 bit
....010 // 2 bit
and again:
....1110 // 1/2 bit
....0110 // 1 bit
and again:
...11110 // 1/2 bit
...01110 // 2 bit
As you can see the consequent ones count determine if the last word is 1 or 2 bit (it is alternating) for odd count its 1 and for even its 2 bit word.
So simply detect which case it is and throw answe right away or count consequent ones before last zero and determine answer from that.
This way you do not need to process whole stream just the end until zero is encountered.
So:
.....11 // 2 bit or error
.....01 // error
.....00 // 1 bit
....010 // 2 bit
...0110 // 1 bit
..01110 // 2 bit
.011110 // 1 bit
0111110 // 2 bit
only in case you hit the start of stream (no zero at start) its needed to process whole array but that is improbable ... as its just a single case where the stream look like this:
111.....111X
so no or just single zero at the end but the count of ones before last bit will still tell you if the ending is 1 or 2 bits long... for that you can do:
last_word_bit_length= 1 + (consequent_ones_count&1)
I do not code in JAVA so here a C++ example instead (should not be hard to port it):
int last_word_bits(int *bits,int n)
{
int i=0;
if (n<1) return 0; // empty
if (n>=1) i|=bits[n-1];
if (n>=2) i|=bits[n-2]<<1;
if (i==1) return 0; // ...00 or ...0 -> error
if (i==0) return 1; // ...01 -> 1
if (i==3) return 2; // ...11 -> 2 or error
// count consequent ones
for (i=0,n-=2;n>=0;n--,i++)
if (bits[n]==0) break;
return 1+(i&1);
}
giving answers:
{1,0,0} -> 1
{1,1,1,0} -> 2
I am expecting bitstream does not contain errors otherwise the special case i==3 need to count the ones too... to determine if it is error or not
Given all the issues with your loop (before and after your edit), it's hard to say which code you actually tried.
Either way, your logic is wrong. You have to iterate over the "bits" the String from left to right, and keep some state variables that tell you if the last character encountered was a 1-bit or 2-bit character.
For example:
boolean started2bit = false;
boolean last1bit = false;
for(int i=0;i<bits.length;i++) {
if (started2bit) { // previous bit was the start of a 2-bit character and current
// bit (either 1 or 0) ends that character
started2bit = false;
last1bit = false;
} else if (bits[i]==1) { // 1 starts a 2-bit character
started2bit = true;
last1bit = false;
} else { // current bit is 0, and it represents a 1-bit character
last1bit = true;
}
}
return last1bit; // the last character we read was a 1-bit character
Or, even simpler, as Hans suggested:
boolean last1bit = false;
for(int i=0;i<bits.length;i++) {
if (bits[i]==1) { // 1 starts a 2-bit character
i++; // the next bit finishes a 2-bit character, so we can skip it
last1bit = false;
} else { // current bit is 0, and it represents a 1-bit character
last1bit = true;
}
}
return last1bit; // the last character we read was a 1-bit character
Python3 code based on #Spektre 's solution above. Any suggestions to improve the code are welcome.
class Solution:
def isOneBitCharacter(self, bits: List[int]) -> bool:
# if it's only 1 bit
if len(bits) == 1:
if bits[0] == 0:
return True
else:
# throwInvalidInputException
return False
# if it ends in 1 then error
if bits[-1] == 1:
# throwInvalidInputException
return False
# if it ends in 00 then True
if bits[-2:] == [0, 0]:
return True
# if it ends in 10 then ??
if bits[-2:] == [1, 0]:
i = len(bits)
while i > 0:
i -= 1
if bits[i-1:i+1] == [0, 1]: break
# in case the loop completes - need to check the first character
if bits[i-1] == 1: i -= 1
# i is now pointing to the first 1 in ....11110
if len(bits[i:]) % 2 == 1:
return True
else:
return False
This will help understand the 'ending in 10' case:
"""
Assuming no invalid input is received.
F 10
F 010
T 110
F 0010
T 0110
F 1010
F 1110
111111110 - len odd True
11111110 - len even false
"""

Drawing a program graph: What line is visited after a conditional or loop is not called?

Just wanted to check whether the way I am thinking is correct.
Here is an example method:
1 public static boolean isCircle (int M, int m) {
2 boolean result = false;
3 if (M == m & M > 0 & m > 0) {
4 result = true;
5 }
6 return result;
7 }
If I was to draw a program graph of this method (each line being a node, their path being edges) with variables that do not satisfy the conditional e.g. M = 1, m = 0. Would the program go from line 3 -> line 6, or from line 3 -> line 5 (end of the conditional).
I would think line 3 to line 6 but am unsure.
It would jump to 6 since that is the next instruction.
the closing } isn't literally part of the program, but closes
a block, so it doesn't do anything on it's own.
See this post for the bytecode that might make it clear.
http://blog.jamesdbloom.com/JavaCodeToByteCode_PartOne.html#if_else
As you can see there, the closing bracket doesn't get translated, so it doesn't exist. It signals end of block, but isn't part of execution.
It depends. Most debuggers in IDE's put the execution marker at the beginning of the line that it's about to execute. After executing the conditional in line 3 which evaluates to false, the next meaningful line to execute is line 6.
However, consider this code:
1 public static boolean isCircle (int M, int m) {
2 boolean result = false;
3 if (M == m & M > 0 & m > 0) {
4 result = true;
5 } else printf("false!");
6 return result;
7 }
If execution jumped to 6, that would imply that the printf was executed as part of the conditional, which would be frustrating for debugging.
You can verify this behavior with the debugger in any IDE. You may find one or two IDE's that put the execution at the beginning of the next statement (line 6), but in the case where there is something else to execute on line 5 besides the }, I'd hope it'd pause the execution before jumping over that line.
Any debugger worth its salt will ignore lines that don't have any meaning (whitespace, comments, open/close brackets), but pause at the beginning of each meaningful line so you can evaluate variables, set new breakpoints, etc.

Gate XOR logic in java

folks... the XOR Gate is still giving me a hard time. I'm really close to finishing it but some of the test cases are failing. My specs say that if I have more than two of 1 (High Signals) such as:
111100 or 111 or 11 or 00 or 0000 so the output should be 0 (Low Signal).
Else if any input signal is 'X' the output is also X such as
XX00111 or XX10 or 0X01 then the output should also be X
Else if all the input signals are known (no X signals) and there is EXACTLY one 1 signal then the output is 1 such as
000001 or 10000 or 01 or 10 then the output should be 1
Note: All of the getters and setter methods are correct (tested) and Signal.HI ==1, Signal.LO = 0 and Signal.X = X.
Could smb help me with this method? When the inputs signals are 011 the output should be 0 when Im getting 1. Secondly, when the inputs are XX Im getting 0 when it should be X. Could smb please hint me or help me? Thanks in advance!
#Override
public boolean propagate()
{
Signal inputSignal;
int countHI = 0;
List<Wire> inputs = getInputs();
Signal temp = getOutput().getSignal();
for(int i = 0; i < inputs.size(); i++)
{
inputSignal = inputs.get(i).getSignal();
if(inputSignal == Signal.X)
{
getOutput().setSignal(Signal.X);
break;
}
else if(inputSignal == Signal.HI)
countHI++;
else if(inputSignal == Signal.LO)
getOutput().setSignal(Signal.HI);
}
if(countHI > 2 || countHI == 0)
getOutput().setSignal(Signal.LO);
....................................further unnecessary code for this problem
Here is what is happening:
When you are detecting an input signal of X, you are setting the output as X, and breaking out of the loop... but the last IF statement is still being executed, and so because your input is 'XX', countHI is zero, and so the last if condition is satisfied and you end up overriding the output signal by setting it to 0 at the end of your code. The break only breaks out of the loop it is currently in.
Your code only checks if hiCount is greater than 2 in the last if statement, but you expect it to be false when there are two or more 1's, so when you have exactly two 1's, you do not enter that if condition.
You need to think about your solution logically and run through it yourself and then you will realize why it is not working as you expect.
Here's how I would code it. Note that I only set the signal when I'm sure that it's the correct value: after the loop.
Also note that I make all the cases mutually exclusive.
boolean hasX = false;
boolean hiCount = 0;
for (Wire wire : inputs) {
Signal inputSignal = wire.getSignal();
if (inputSignal == Signal.X) {
hasX = true;
// optimization: break out of the loop early since we know
// that, whatever the number of HI and LO, if there is one
// X, the result is X
break;
}
else if (inputSignal == Signal.HI)
hiCount++;
}
}
if (hasX) {
getOutput().setSignal(Signal.X);
}
else if (hiCount == 1) {
getOutput().setSignal(Signal.HI);
}
else {
getOutput().setSignal(Signal.LO);
}

How to generate random numbers in my situation

I generate randomly this expression [0-9*]. The symbol '*' is end line symbol. When it is generated, I jump to next line and fill it until '*' is generated again and so on. But in some cases, my first generated symbol is '*' and then jump to next line. for example:
116165464*
56465*
*
654*
64*
*
14*
and so on
...
..
.
As you can see, end line symbol like in 3 line is not suitable and useful. So I want to avoid this. How can I generate numbers and prevent to generate like 3 line and 6 line in my example? In other words, I want to generate lines which must to contain numbers ( there cannot be like 3 and 6 lines showed in my example)
(Assume that I will delete all '*' symbols in the future, and if there will be lines like 3 and 6 in my example, there will be only empty space.)
My code looks like this: (it will generate symbols, c - char type)
for(int i = 1;i<max;i++){
if(i == max-1)
c = '*';
c = numbers.charAt(rnd.nextInt(numbers.length()));
listChar.add(c);
Thanks
I think I solved my problem by doing this:
I add additional char temp;
I stored my previous symbol in my temp;
And check this condition:
temp = c;
c = generate symbol;
...
if(temp == c)
continue;
if not equal
add(c)
(It is kind of pseudo to get an idea)
One from my results:
123355666778999
98631
112339
7
8
88877431
169
99988765544443211
112444456788999
981
1345
98876655543211
334667899
85431
34569
876521
1112334556678
88764333211
With small change to your code what you wanted may be achieved.
I'm assuming that number = "0123456789*" based on your logic. If you want to achieve a non zero
// Next line will generate one number from 0 to 9 as we are ignoring last character.
listChar.add(numbers.charAt(rnd.nextInt(numbers.length()-1)));
for(int i = 2;i<max;i++){
c = numbers.charAt(rnd.nextInt(numbers.length()));
listChar.add(c);
if(c == '*')
break;
}
System.out.println(listChar);
Below code will ensure you can avoid adding an asterisk.
// Next line will generate one number from 0 to 9 as we are ignoring last character.
listChar.add(numbers.charAt(rnd.nextInt(numbers.length()-1)));
for(int i = 2;i<max;i++){
c = numbers.charAt(rnd.nextInt(numbers.length()));
if(c == '*')
{
break;
}
else
{
listChar.add(c);
}
}
System.out.println(listChar);
However there can always be a better algorithm to generate what you wanted. But this will work.
public void genLine(){
int random = Math.random()*10;
System.out.print(random);
while (random!=10)
random = Math.random()*11;
if (random == 10) System.out.print('*');
else System.out.print(random);
}
}
This will generate one line for you. The first character is a special case because it cannot be a '*' so I just hard coded it. In every other case generate a random number with one more possibility. If that extra possibility is chosen, print '*'.

Categories

Resources