-
-
Save lyxal/c03a5d7e4a71fef523900e751bae3340 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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