User:1hals/brainfuck

From Esolang
Jump to navigation Jump to search

This is my brainfuck interpreter implementation in Python 3

#!/usr/bin/env python3

import sys
EOF = 0
NUM_DEBUG_CELLS = 10
MEMORY_STEP = 1024

if len(sys.argv) != 2:
    print('Usage:')
    print(sys.argv[0], '[filename or -]')
    sys.exit()

filename = sys.argv[1]
if filename == '-': 
    # Take program from standard input
    # With program input starting with '!'
    program_file = 'stdin'
    stdin = input()
    parts = stdin.split('!')
    if len(parts) == 2:
        program, input_text = parts
    else:
        program = parts[0]
        input_text = ''
else:
    # Take program from given file
    # With program input from standard input
    program_file = open(filename, 'r')
    program = program_file.read()
    input_text = input()

input_x = list(ord(x) for x in reversed(input_text)) 
program_len = len(program) 
memory = bytearray([0 for x in range(MEMORY_STEP)])
memory_len = len(memory)

pointer = 0
program_counter = 0
cycles = 0

while program_counter < program_len:
    char = program[program_counter]
    if char == '>':
        # Move the pointer to the right
        pointer += 1
        if pointer >= memory_len:
            # Get more memory
            self.memory += bytearray([0 for x in range(MEMORY_STEP)])
            self.memory_len = len(memory)
    elif char == '<':
        # Move the pointer to the left
        pointer -= 1
    elif char == '+':
        # Increment the memory cell at the pointer
        memory[pointer] += 1
        if memory[pointer] > 255:
            memory[pointer] = 0
    elif char == '-':
        # Decrement the memory cell at the pointer
        memory[pointer] -= 1
        if memory[pointer] < 0:
            memory[pointer] = 255
        program_counter += 1
    elif char == '.':
        # Output the character signified by the cell at the pointer
        print(end=chr(memory[pointer]))
    elif char == ',':
        # Input a character and store it in the cell at the pointer
        try:
            memory[pointer] = input_x.pop()
        except IndexError:
            memory[pointer] = EOF
    elif char == '[':
        # Jump past the matching ] if the cell at the pointer is 0
        if memory[pointer] == 0: 
            index = None
            depth = 1
            for i in range(program_counter + 1, program_len):
                char = program[i]
                if '[' == char:
                    depth += 1
                elif ']' == char:
                    depth -= 1
                    if depth == 0:
                        index = i
                        break
            program_counter = index
    elif char == ']':
        # Jump back to the matching [ if the cell at the pointer is nonzero
        if memory[pointer] != 0:
            index = None
            depth = 1
            for i in range(program_counter - 1, 0, -1):
                char = program[i]
                if ']' == char:
                    depth += 1
                elif '[' == char:
                    depth -= 1
                    if depth == 0:
                        index = i
                        break
            program_counter = index
    elif '#' == char:
        # Debug: print first 10 cells 
        print('#[%s...]' % ', '.join(str(x) for x in memory[:NUM_DEBUG_CELLS]))
    elif '$' == char:
        # Debug: print program counter
        print('$%d' % program_counter)
    elif '^' == char:
        # Debug: print pointer
        print('^%d' % pointer)
    elif '@' == char:
        # Debug: print cycle number
        print('@%d' % cycles)
    program_counter += 1
    cycles += 1