4

I have been working on a BF interpreter, trying to ensure it uses no external libraries, and works in a single function.

The issue I am running into is that some programs work perfectly well, and others don't. This is making it hard to debug and figure and what's going wrong.

The common factor seems to be it cannot handle a BF program with more then one set of brackets (although there are some exceptions, but then the programs work, just not completely).

The Code:

def interpret(code):
    array = [0]
    pointerLocation = 0
    i = 0
    c = 0
    print(code)
    while i < len(code):
        if code[i] == '<':
            if pointerLocation > 0:
                pointerLocation -= 1
        elif code[i] == '>':
            pointerLocation += 1
            if len(array) <= pointerLocation:
                array.append(0)
        elif code[i] == '+':
            array[pointerLocation] += 1
        elif code[i] == '-':
            if array[pointerLocation] > 0:
                array[pointerLocation] -= 1
        elif code[i] == '.':
            print(array[pointerLocation], chr(array[pointerLocation]))
        elif code[i] == ',':
            x = input("Input:")
            try:
                y = int(x)
            except ValueError:
                y = ord(x)
            array[pointerLocation] = y
        elif code[i] == '[':
            if array[pointerLocation] == 0:
                while code[i] != ']':
                    i += 1
        elif code[i] == ']':
            if array[pointerLocation] != 0:
                while code[i] != '[':
                    i -= 1
        i += 1
interpret("""
                     #This is where the BF code goes
""")

I know this is not the best Python code, I just thought I'd give it a go.

The programs that work:

,----------[----------------------.,----------]  

- Converts lowercase to uppercase

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

- Hello World!

The program I am currently trying to make work is:

++++++++[>+>++++<<-]>++>>+<[-[>>+<<-]+>>]>+[-<<<[->[+[-]+>++>>>-<<]<[<]>>++++++[<<+++++>>-]+<<++.[-]<<]>.>+[>>]>+]

It's designed to output a Sierpinski Triangle with *s.

I get no output, but if I output the array it appears to create and almost endless array of sequenced 0, 1, 0, 1.....etc. etc.

From running it through a proper interpreter I know that the array should only end up with a length of 120, and I am getting into the thousands within seconds.

Any help would be appreciated.

Thanks.

Freddie R
  • 377
  • 5
  • 15
  • Not all programs work for all brainfuck implementations. Some programs rely on wrapping behaviour that only some implementations provide. Brainfuck is a very poorly specified language. – Carcigenicate Jul 21 '17 at 15:00
  • Looking at your problem again though, you must have messed up the logic for braces somewhere. What debugging have you done? Also, why shove everything into a single function? You've intentionally made debugging harder. When I wrote a brainfuck interpreter it was spread over multiple files with at least 20 functions. That way, every piece can be tested independent of any other code. – Carcigenicate Jul 21 '17 at 15:01
  • Do you understand what this line `code[i] != ["<", ">", "+", "-", ".", ",", "[", "]"]` does? – Christian Dean Jul 21 '17 at 15:02
  • Ah, that was left in from an older version. It was designed to speed up skipping over alphanumeric characters, but I realised I put it inside the loop which doesn't speed up anything at all. – Freddie R Jul 21 '17 at 15:09
  • I replaced it with this: code = code.translate({ord(c): None for c in ''' :!@#$abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\/1234567890() '''}) – Freddie R Jul 21 '17 at 15:09
  • You can take a look here: https://github.com/MLavrentyev/Brainfuck-Interpreter – MLavrentyev Jul 21 '17 at 15:11
  • @Carcigenicate I did it in one function just to see if I can, and yeah I just put it on here to try and find where I messed up the brace logic. – Freddie R Jul 21 '17 at 15:11
  • 1
    @FreddieR A better challenge would have been making it modular and easy to test. Knowledge from that will serve you better down the road. This is to much code to go through though on my phone. Try going through it with a debugger. – Carcigenicate Jul 21 '17 at 15:19
  • @Carcigenicate I have, but I don't know how to use a debugger efficiently. I have used it to go through all the lines relating to the brackets, but it seemed to work fine. I understand this is not the best way to go about it, but I've started and I really want it to work. – Freddie R Jul 21 '17 at 15:26
  • @FreddieR Definitely practice using a debugger. It's your best tool at debugging potentially complicated problems. Try going through this program slowly, and really look at what's going on. A small toy project like this is the perfect way to practice its use. – Carcigenicate Jul 21 '17 at 16:31
  • @FreddieR For reference, you should look at [this very simple interpreter](https://github.com/pocmo/Python-Brainfuck) that seems to work well – Nelson Jul 21 '17 at 21:15

1 Answers1

5

There's a bug in your code at handling [ and ]: They don't match the correct braces, instead they match the closest brace which could fit if everything between is ignored including other braces!!! This means you cant nest your loops. I also wrote a bf interpreter in python and I used a counter variable open_braces which starts at 1 and gets incremented by braces open to the search direction and gets decremented by braces closed to the search direction. Fix your code as followed:

elif code[i] == '[':
    if array[pointerLocation] == 0:
        open_braces = 1
        while open_braces > 0:
            i += 1
            if code[i] == '[':
                open_braces += 1
            elif code[i] == ']':
                open_braces -= 1
elif code[i] == ']':
    # you don't need to check array[pointerLocation] because the matching '[' will skip behind this instruction if array[pointerLocation] is zero
    open_braces = 1
    while open_braces > 0:
        i -= 1
        if code[i] == '[':
            open_braces -= 1
        elif code[i] == ']':
            open_braces += 1
    # i still gets incremented in your main while loop
    i -= 1

Please notice that you may keep the if array[pointerLocation] == 0 in the elif code[i] == ']':-block if you care about performance. If you do so, you don't need to decrement i in the last line.

Aemyl
  • 1,501
  • 1
  • 19
  • 34
  • 1
    Thank you! However shouldn't the first open_braces INCREASE i to scan through the code? Other than that, thank you so much I'll implement this asap. – Freddie R Jul 27 '17 at 16:14
  • 1
    yes, you're right - the first loop should increase `i`. I'll fix it – Aemyl Jul 27 '17 at 18:45