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

Basic Brainfuck interpreter (part 2)

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

Problem

I have this obsession with esoteric programming languages. So I decided to spiff up my previous Brainfuck interpreter.

# Simple BrainF*** interpreter

# Class that stores lang variables
class Lang(object):
    step = 0
    cell = [0] * 30000
    test_cell = [0] * 30000
    pos = 0
    test_pos = 0
    loop = False
    loop_ret = 0

# Main interpreter function
def interpreter():

    code_input = raw_input('Code: ')
    steps = len(code_input)

    while Lang.step ':
            if Lang.pos  30000:
                Lang.pos = 0

        elif code_input[Lang.step] == ' 0:
                Lang.cell_pos -= 1
            elif Lang.pos  30000:
                Lang.test_pos += 1
            elif Lang.test_pos  0:
                Lang.test_pos -= 1
            elif Lang.test_pos < 0:
                Lang.test_pos = 30000

        elif code_input[Lang.step] == "$":
            if Lang.test_cell[Lang.test_pos] == Lang.cell[Lang.pos]:
                print True 
            elif Lang.test_cell[Lang.test_pos] != Lang.cell[Lang.pos]:
                print False 

        Lang.step += 1

# Running the program
if __name__ == "__main__":
    interpreter()


If there are any issues, please mention them. All I'm looking for is any general improvements.

Solution

In a word: dictionaries.

You have a class that only has class attributes and lacks any methods; that could just be a dictionary:

lang = dict(
    step = 0,
    cell = [0] * 30000,
    test_cell = [0] * 30000,
    pos = 0,
    test_pos = 0,
    loop = False,
    loop_ret = 0
)


(Alternatively, if you really want attribute (foo.bar) rather than key (foo['bar']) access to the values, look into collections.namedtuple.)

You have a whole bunch of elifs; that could also be a dictionary (with some judiciously-named functions):

commands = {
    "+": increment_byte,
    "-": decrement_byte,
    ...
}


This makes your interpreter loop:

def interpreter():

    lang = dict(...)
    commands = {...}

    code_input = raw_input('Code: ')    
    steps = len(code_input)

    while lang['step'] < steps:           
        command = code_input[lang['step']]
        if command in commands:
            commands[command](lang)    
        lang['step'] += 1


along with e.g.:

def increment_byte(lang):
    """Increment the byte at the data pointer."""
    val = lang['cell'][lang['pos']]
    lang['cell'][lang['pos']] = ((val + 1) % 256)


(Note use of % per @user50399's answer.)

This has two advantages:

  • very simple loop in interpreter; and



  • commands acts as a syntax guide (covering @Dagg's comment).



You could also add some input validation:

def accept_input(lang):
    """Accept one char of input, storing its value in the byte at the data pointer."""
    while True:
        try:
            i = ord(raw_input("Enter char: "))
        except TypeError:
            pass
        else:
            if i in range(256):
                lang['cell'][lang['pos']] = i
                break
        print("Not a valid input.")


(Note switch to ord per @user50399's answer.)

Code Snippets

lang = dict(
    step = 0,
    cell = [0] * 30000,
    test_cell = [0] * 30000,
    pos = 0,
    test_pos = 0,
    loop = False,
    loop_ret = 0
)
commands = {
    "+": increment_byte,
    "-": decrement_byte,
    ...
}
def interpreter():

    lang = dict(...)
    commands = {...}

    code_input = raw_input('Code: ')    
    steps = len(code_input)

    while lang['step'] < steps:           
        command = code_input[lang['step']]
        if command in commands:
            commands[command](lang)    
        lang['step'] += 1
def increment_byte(lang):
    """Increment the byte at the data pointer."""
    val = lang['cell'][lang['pos']]
    lang['cell'][lang['pos']] = ((val + 1) % 256)
def accept_input(lang):
    """Accept one char of input, storing its value in the byte at the data pointer."""
    while True:
        try:
            i = ord(raw_input("Enter char: "))
        except TypeError:
            pass
        else:
            if i in range(256):
                lang['cell'][lang['pos']] = i
                break
        print("Not a valid input.")

Context

StackExchange Code Review Q#58873, answer score: 5

Revisions (0)

No revisions yet.