Skip to content

Instantly share code, notes, and snippets.

@lyxal

lyxal/bf.py Secret

Created August 16, 2021 23:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lyxal/c03a5d7e4a71fef523900e751bae3340 to your computer and use it in GitHub Desktop.
Save lyxal/c03a5d7e4a71fef523900e751bae3340 to your computer and use it in GitHub Desktop.
# Brainfuck interpreter in python
#
# @author: Maxence 'pepibumur' De Saint <contact@pepibumur.me>
# @license: Free for any use
# @since: 2012-04-04
# @version: 0.1
# A few things to note :
# - To make it more readable, I've chosen to add a line break before each '[' or ']'.
# This way, it's easier to see the program structure without needing to scroll.
# - I could have used the '^' (caret) to mark the position of the pointer in the code,
# but I feel like it's overkill, and not really what I wanted to do.
# - The '<' and '>' characters are replaced by '-' and '+' for easier coding.
# The original characters can be accessed with the 'bf_inc' and 'bf_dec' functions.
# - The ',' character is replaced by 'bf_getchar', and the '.' character by 'bf_putchar'.
# The original characters can be accessed with the 'bf_getc' and 'bf_putc' functions.
# - The 'bf_getchar' and 'bf_putchar' functions return the original characters,
# but they can also be overriden to return whatever you want.
# - Printing a character on stdout will use the 'bf_putc' function by default,
# but it can be overriden to use whatever you want.
# - All non-ASCII characters are replaced by their ASCII equivalents.
# This includes characters from the Unicode Supplementary Plane (U+10000 to U+10FFFF).
# This is done because the font I've used to display the program (Inconsolata)
# doesn't support Unicode characters higher than U+FFFF.
# - The most important reason why I've chosen to write a Brainfuck interpreter, is
# because I wanted to learn Python.
# The original project I've found online was in PHP, and I didn't like it,
# so I've decided to rewrite it in Python.
# It's been a good way to learn the language.
# - If you want to contribute (and correct my French if you speak it),
# feel free to fork the project at https://github.com/pepibumur/brainfuck.py
# and to send me a pull request.
# I'm pretty bad at coding, so just be nice and help me make it better.
# You will also learn a lot if you do so.
import sys
from time import sleep
# The '<', '>', '+' and '-' characters
bf_inc = '+'
bf_dec = '-'
bf_next = '>'
bf_prev = '<'
# The ',' and '.' characters
bf_getc = ','
bf_putc = '.'
# The character used to print the ASCII character corresponding to an integer
bf_printchar = '$'
# The program itself
prog = ""
# The input buffer and pointer
input_buffer = [0]
input_ptr = 0
# The output buffer
output_buffer = []
# The function used to print the ASCII character corresponding to an integer
def bf_printascii(char):
sys.stdout.write(chr(char))
# The function used to print an ASCII character
bf_printc = bf_printascii
# The function used to get a character from stdin
def bf_getchar():
return ord(sys.stdin.read(1))
# The function used to put a character on stdout
def bf_putchar(char):
sys.stdout.write(chr(char))
# The tape
tape = [0]
tape_ptr = 0
# The program pointer
prog_ptr = 0
# The execution step counter
step_cnt = 0
# The main execution loop
while prog_ptr < len(prog):
if prog[prog_ptr] == bf_inc:
# Increase cell value
tape[tape_ptr] = (tape[tape_ptr] + 1) % 256
elif prog[prog_ptr] == bf_dec:
# Decrease cell value
tape[tape_ptr] = (tape[tape_ptr] - 1) % 256
elif prog[prog_ptr] == bf_next:
# Move the tape pointer to the next cell
tape_ptr += 1
if tape_ptr >= len(tape):
# If the tape pointer is out of bounds, add a new cell to the tape
tape.append(0)
elif prog[prog_ptr] == bf_prev:
# Move the tape pointer to the previous cell
if tape_ptr > 0:
tape_ptr -= 1
elif prog[prog_ptr] == bf_getc:
# Get a character from stdin
input_buffer[input_ptr] = bf_getchar()
elif prog[prog_ptr] == bf_putc:
# Put an ASCII character on stdout
bf_printc(input_buffer[input_ptr])
elif prog[prog_ptr] == bf_printchar:
# Put an integer on stdout
bf_printc(tape[tape_ptr])
elif prog[prog_ptr] == '[':
# If the current cell value is null, jump to the instruction after the ']'
if tape[tape_ptr] == 0:
prog_ptr = prog.find(']', prog_ptr)
elif prog[prog_ptr] == ']':
# If the current cell value is different from null, jump to the instruction after the '['
if tape[tape_ptr] != 0:
prog_ptr = prog.rfind('[', 0, prog_ptr)
else:
# The current instruction is an empty cell
pass
prog_ptr += 1
step_cnt += 1
# Print the execution step counter
print("\nExecuted {0} steps".format(step_cnt))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment