Created
June 26, 2017 22:56
-
-
Save SonOfLilit/67f1b35973be90b6d721d3e08fe6556b to your computer and use it in GitHub Desktop.
Live coded during my "Virtual Machines and Brainfuck" talk at PyConIL 2017
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
import sys | |
def parse_parens(code): | |
result = {} | |
stack = [] | |
for i, c in enumerate(code): | |
if c == '[': | |
stack.append(i) | |
elif c == ']': | |
match = stack.pop() | |
result[i] = match | |
result[match] = i | |
return result | |
assert parse_parens('') == {} | |
assert parse_parens('[]') == {0: 1, 1: 0} | |
assert parse_parens('[+]') == {0: 2, 2: 0} | |
assert parse_parens('[+[]]') == {0: 4, 4: 0, 2: 3, 3: 2} | |
def bf(code, input=''): | |
def get(): | |
if get.i >= len(input): | |
return '' | |
char = input[get.i] | |
get.i += 1 | |
return char | |
get.i = 0 | |
output = [] | |
def put(char): | |
output.append(char) | |
brainfuck(code, getchar=get, putchar=put) | |
return ''.join(output) | |
def brainfuck(code, getchar=lambda: sys.stdin.read(1), putchar=sys.stdout.write): | |
matched_parens = parse_parens(code) | |
memory = [0] * 40000 | |
cursor = 0 | |
instruction_pointer = 0 | |
while instruction_pointer < len(code): | |
instruction = code[instruction_pointer] | |
if instruction == '+': | |
memory[cursor] = (memory[cursor] + 1) % 255 | |
elif instruction == '-': | |
memory[cursor] = (memory[cursor] - 1) % 255 | |
elif instruction == '<': | |
cursor = (cursor - 1) % len(memory) | |
elif instruction == '>': | |
cursor = (cursor + 1) % len(memory) | |
elif instruction == '[': | |
if memory[cursor] == 0: | |
instruction_pointer = matched_parens[instruction_pointer] | |
elif instruction == ']': | |
instruction_pointer = matched_parens[instruction_pointer] | |
continue | |
elif instruction == ',': | |
char = getchar() | |
if char == '': | |
break | |
memory[cursor] = ord(char) | |
elif instruction == '.': | |
putchar(chr(memory[cursor])) | |
else: | |
# everything else is a comment | |
pass | |
instruction_pointer += 1 | |
#print instruction_pointer, memory[:10] | |
assert bf('') == '' | |
assert bf('++++++++++.') == '\n' | |
assert bf('+++++++++++++.---.') == '\r\n' | |
assert bf('++++++++[>++++++++<-]>+.') == 'A' | |
assert bf('+++[>,.<-]', 'abcde') == 'abc' | |
assert bf('+[>,.<]', 'abcde') == 'abcde' | |
assert bf(bf('+++++++++[<+++++>-],[[-<--.++<+>>]<+.-<[->.<]>>,]', 'hello, world!')) == 'hello, world!' | |
def main(): | |
assert len(sys.argv) == 2, 'usage: bf.py <code>' | |
_, code = sys.argv | |
brainfuck(code) | |
return 0 | |
if __name__ == '__main__': | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment