Last active
April 2, 2020 16:24
-
-
Save tirinox/421742968f4dbf036fe40a9aa62b15cd to your computer and use it in GitHub Desktop.
Python brainfuck interpreter
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 run(code, mem_size=256): | |
# 1. этап составим карту скобок | |
# ключ и значения - индекс байта в коде | |
# по любой скобке находим ей пару | |
bracket_map = {} | |
stack = [] | |
for pos, symbol in enumerate(code): | |
# открыли скобку - положим на вершину стэка ее позицию | |
if symbol == '[': | |
stack.append(pos) | |
elif symbol == ']': | |
# вершина стэка - как раз наша парная скобка - была последней | |
# удалим ее с вершины | |
last_open_pos = stack.pop() | |
# создадим парные записи | |
bracket_map[pos] = last_open_pos | |
bracket_map[last_open_pos] = pos | |
# после прохода по коду - остались незакрытые скобки - это ошибка! | |
if stack: | |
raise ValueError("unclosed [") | |
# 2 этап: выполняем код | |
memory = [0] * mem_size # оперативная память программы | |
data_ptr = 0 # индекс текущей ячейки памяти (memory) | |
instr_ptr = 0 # индекс текущей инструкции кода (code) | |
# выполняем - пока не вылетели за пределы кода | |
while instr_ptr < len(code): | |
command = code[instr_ptr] # текущая команда | |
if command == '+': | |
memory[data_ptr] += 1 | |
elif command == '-': | |
memory[data_ptr] -= 1 | |
elif command == '>': | |
data_ptr = (data_ptr + 1) % mem_size # циклическая память | |
elif command == '<': | |
data_ptr = (data_ptr - 1) % mem_size # циклическая память | |
elif command == '.': | |
# печатаем символ с кодом = значения текущей ячейки | |
print(chr(memory[data_ptr]), end='') | |
elif command == ',': | |
# ввод - берем код первого символа или 0, если ввод пустой | |
inp = input() | |
memory[data_ptr] = ord(inp[0]) if inp else 0 | |
elif command == '[': | |
# начало цикла - проверка текущей ячейки | |
if not memory[data_ptr]: # == 0 | |
# значит надо перейти на ячейку за соответствующей ей закрывающей скобкой | |
instr_ptr = bracket_map[instr_ptr] | |
elif command == ']': | |
# проверяем тоже условие, если выполняется, то скачем на начало цилкаа | |
if memory[data_ptr]: # не ноль | |
# перемещаем на конец цикла | |
instr_ptr = bracket_map[instr_ptr] | |
instr_ptr += 1 # сдвигаеи к следующей команде | |
if __name__ == '__main__': | |
if len(sys.argv) == 2: | |
# один аргумент - имя файла, который надо выполнить | |
with open(sys.argv[1], 'r') as f: | |
code = f.read() | |
run(code) | |
else: | |
print(f'usage: python {sys.argv[0]} file.bf') |
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 | |
import os | |
PRELUDE = """// brainfuck generated: | |
#include <stdio.h> | |
int main() { | |
const int mem_size = 30000; | |
char mem[mem_size]; | |
memset(mem, 0, mem_size); | |
int cur = 0; | |
""" | |
ENDING = """ | |
return 0; | |
} | |
""" | |
def compile_to_c(bf_code): | |
instr_ptr = 0 # индекс текущей инструкции кода (code) | |
indent = 4 | |
c_code = PRELUDE | |
# выполняем - пока не вылетели за пределы кода | |
for command in bf_code: | |
content = '' | |
if command == '+': | |
content = 'mem[cur]++;' | |
elif command == '-': | |
content = 'mem[cur]--;' | |
elif command == '>': | |
content = 'cur++;' | |
elif command == '<': | |
content = 'cur--;' | |
elif command == '.': | |
content = 'putchar(mem[cur]);' | |
elif command == ',': | |
content = 'mem[cur] = getchar();' | |
elif command == '[': | |
content = 'while(mem[cur]) {' | |
elif command == ']': | |
content = '}' | |
instr_ptr += 1 # сдвигаеи к следующей команде | |
if content: | |
if command == ']': | |
indent -= 4 | |
c_code += ' ' * indent + content + '\n' | |
if command == '[': | |
indent += 4 | |
c_code += ENDING | |
return c_code | |
if __name__ == '__main__': | |
if len(sys.argv) == 2: | |
# один аргумент - имя файла, который надо выполнить | |
name = sys.argv[1] | |
with open(name, 'r') as f: | |
code = f.read() | |
c_code = compile_to_c(code) | |
c_file = f'{name}.c' | |
with open(c_file, 'w') as f: | |
f.write(c_code) | |
os.system(f'cc {c_file} -o {name}.out') | |
else: | |
print(f'usage: python {sys.argv[0]} file.bf') |
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
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++ | |
.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++. | |
------.--------.>+.>. |
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
>>+>,[ | |
<[ | |
[>>+<<-]>[<<+<[->>+[<]]>>>[>]<<-]<<< | |
]>>[<<+>>-]<[>+<-]>[>>]<, | |
]<<<[<+<]>[>.>] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment