HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

BF interpreter in Python that uses recursion to handle loops

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
interpreterrecursionhandleloopsusesthatpython

Problem

I wrote a Brainfuck interpreter in Python and I'm wondering how to simplify it.

I handle separately loop commands and the others. A recursive function deals with loops.

import sys    
array = [0] # byte array
ptr = 0 # data pointer


Read and execute commands except loop

def readNoLoop(char):
  global ptr
  # Increment/Decrement the byte at the data pointer
  if char=='+':
    array[ptr] += 1
  elif char=='-':
    array[ptr] -= 1
    if array[ptr] ':
    ptr += 1
    while(ptr>=len(array)-1):
      array.append(0)
  elif char=='<':
    ptr -= 1
    if ptr < 0:
      raise ValueError("Negative value of pointer")
  # Output the byte at the data pointer
  elif char=='.':
    sys.stdout.write(chr(array[ptr]))
  # Store one byte of input in the byte at the data pointer 
  elif char==',':
    array[ptr] = ord(sys.stdin.read(1))


Recursive function to deal with loops

def interpret(charChain):
  it = 0
  loopBegin = []
  while(it0):
        interpret(subChain)
      loopBegin.pop()
    else:
      readNoLoop(charChain[it])
    it+=1


Main

if __name__ == "__main__":
  # Brainfuck program to print "Hello World!"
  code = '++++++++[>++++[>++>+++>+++>++>+>->>+[>.>---.+++++++..+++.>>.>+.>++.'
  try:
    interpret(code)
  except:
    raise


My main concern is to know if it's possible to have a simpler code without recursion.

Solution

As you didn't mention what are you looking for in a review, I will make some general comments regarding your code.

Formatting and variables

Try to read PEP8

  • indent your code using 4-spaces TAB



  • try removing redundant parentheses from your while loop loops



  • function names should be lower case (so try renaming your def readNoLoop(). Perhaps something like read_no_loop().



  • variable in functions should also be lowercase



Name conventions

Try renaming you variables based on their usage. For example: it - what is it ? What is its purpose ? Think about this when you are naming your methods / variables.

For example, instead of making comments right beside the variables, rename them and remove the comments:

array = [0]  # byte array
ptr = 0  # data pointer


Will become:

byte_array = [0] 
data_pointer = 0


So far, we would have something like this:

import sys

byte_array = [0]
data_pointer = 0

def read_no_loop(char):
    global data_pointer
    # Increment/Decrement the byte at the data pointer
    if char == '+':
        byte_array[data_pointer] += 1
    elif char == '-':
        byte_array[data_pointer] -= 1
        if byte_array[data_pointer] ':
        data_pointer += 1
        while data_pointer >= len(byte_array) - 1:
            byte_array.append(0)
    elif char == ' 0:
                interpret(sub_chain)
            loop_begin.pop()
        else:
            read_no_loop(char_chain[it])
        it += 1

if __name__ == "__main__":
    # Brainfuck program to print "Hello World!"
    code = '++++++++[>++++[>++>+++>+++>++>+>->>+[>.>---.+++++++..+++.>>.>+.>++.'
    try:
        interpret(code)
    except:
        raise


Those elifs are bothering me, so you can try doing something like this:

instructions = {
  '+': increment,
  '-': decrement,
  # and so on
}


As per your code, I can't see much of improvement at the functionality level. Perhaps I will let others to do this.

More, I like how you used recursion in this code. In general, you have a nice structure.

Code Snippets

array = [0]  # byte array
ptr = 0  # data pointer
byte_array = [0] 
data_pointer = 0
import sys

byte_array = [0]
data_pointer = 0


def read_no_loop(char):
    global data_pointer
    # Increment/Decrement the byte at the data pointer
    if char == '+':
        byte_array[data_pointer] += 1
    elif char == '-':
        byte_array[data_pointer] -= 1
        if byte_array[data_pointer] < 0:
            raise ValueError("Negative value in byte_array")
    # Increment/Decrement the data pointer
    elif char == '>':
        data_pointer += 1
        while data_pointer >= len(byte_array) - 1:
            byte_array.append(0)
    elif char == '<':
        data_pointer -= 1
        if data_pointer < 0:
            raise ValueError("Negative value of pointer")
    # Output the byte at the data pointer
    elif char == '.':
        sys.stdout.write(chr(byte_array[data_pointer]))
    # Store one byte of input in the byte at the data pointer
    elif char == ',':
        byte_array[data_pointer] = ord(sys.stdin.read(1))


def interpret(char_chain):
    it = 0
    loop_begin = []
    while it < len(char_chain):
        if char_chain[it] == '[':
            loop_begin.append(it)
        elif char_chain[it] == ']':
            sub_chain = char_chain[loop_begin[-1] + 1:it]
            while byte_array[data_pointer] > 0:
                interpret(sub_chain)
            loop_begin.pop()
        else:
            read_no_loop(char_chain[it])
        it += 1


if __name__ == "__main__":
    # Brainfuck program to print "Hello World!"
    code = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.'
    try:
        interpret(code)
    except:
        raise
instructions = {
  '+': increment,
  '-': decrement,
  # and so on
}

Context

StackExchange Code Review Q#125611, answer score: 3

Revisions (0)

No revisions yet.