0

I am a beginning programmer in Python, trying to practice by building a BF interpreter. However, it will not work with the Hello, World! program:

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

giving a RuntimeError: maximum recursion depth exceeded in cmp. My code is below.

import sys

script, file = sys.argv


tape, tapeslct, cmdslct = [0], 0, 0
code = open(file)
program = filter(lambda x: x in ['.', ',', '[', ']', '<', '>', '+', '-'], code.read())
print(str(program))
program = list(program)

def execute(cmd):
    global tape
    global tapeslct
    global cmdslct
    if cmd == "+":
        tape[tapeslct] += 1
    if cmd == "-":
        tape[tapeslct] -= 1
    if cmd == ">":
        tapeslct += 1
        if tapeslct == len(tape):
            tape.append(0)
    if cmd == "<":
        tapeslct -= 1
    if cmd == ".":
        print(chr(tape[tapeslct]))
    if cmd == ",":
        tape[tapeslct] = ord(input())
    if cmd == "[":
        if tape[tapeslct] >= 1:
            loopend = 0
            testfor = cmdslct
            while loopend == 0:
                testfor += 1
                if program[testfor] == "]" and tape[tapeslct] >= 0:
                    testfor = cmdslct + 1
                    execute(program[testfor])
                elif program[testfor] == "]" and tape[tapeslct] == 0:
                    loopend = 1
                    cmdslct = testfor + 1
                else:
                    execute(program[testfor])
        else:
            while loopend == 0:
                testfor += 1
                if program[testfor] == "]":
                    loopend = 1
while len(program) > cmdslct:
    execute(program[cmdslct])
    cmdslct += 1

The lambda snippet was taken from another BF interpreter in Python, found here.

I've missed something, most likely.

4
  • I don't think you need to use recursion here. Try rewriting without the recursive calls. A loop, instead? Commented Aug 24, 2015 at 1:17
  • You don't need recursion, and you should really avoid global variables. Commented Aug 24, 2015 at 1:21
  • It has already been said that this would serve fine as an iterative method but if you do end up needing recursion (i.e. you are switching to multiple calls), Stackless python allows infinite recursive calls Commented Aug 24, 2015 at 1:23
  • The problem is a bug - the second [ will jump to the first [, which should not happen. (Investigating why) Commented Aug 24, 2015 at 1:26

1 Answer 1

1

From what I see, your [ and ] implementation is wonky. You start using a different instruction pointer (testfor instead of cmdslct) while inside a subroutine; but when you hit another [, you start your next loop from cmdslct instead of the current testfor, which makes nested loops impossible.

I suggest you don't treat your loops as special. When [ comes, just push the current location into a stack; when ] comes, pop it, then either jump or ignore depending on the tape. This way, you don't even need recursion.

Alternately, pass the instruction pointer, not cmd, into the recursion.

if cmd == "[":
    # remember loop start
    stack.append(cmdslct)
    if tape[tapeslct] == 0:
        # end of loop; find the matching loop end
        loops = 1
        while not (program[cmdslct] == ']' and loops > 0):
            cmdslct += 1
            if program[cmdslct] == '[':
                loops += 1
            elif program[cmdslct] == ']':
                loops -= 1
if cmd == ']':
    if tape[tapeslct] != 0:
        # jump back
        cmdslct = stack[-1]
    else:
        # forget about this loop and move on
        stack.pop()
Sign up to request clarification or add additional context in comments.

1 Comment

Amazing, thank you. Works well now, as far as I can tell.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.