Сказ о том, как я интерпретатор Brainfuck'а писал
Вступление
Сидел я тут как-то вечером и думал, что можно такое интересное написать на Python«е и тут я вспомнил, что когда-то давно, ещё на C#, пытался написать интерпретатор какого-нибудь простого языка, того же BASIC например, но особо ничего не получалось. В момент этих попыток я наткнулся на такой язык, как Brainfuck. Сейчас я решил написать интерпретатор именно этого языка, так как он является одновременно простым для написания и сложным для понимания))
О самом языке
Brainfuck — по истине мозговыносящий (и это ещё мягко сказано) эзотерический язык программирования (нестандартный язык, который создаётся с целью развлечения или исследования особенностей программирования. Он обычно имеет необычный синтаксис и принципы работы, что делает его сложным для понимания и использования в реальных проектах).
Он имеет всего 8 простых команд:
Команда | Описание |
> | Следующая ячейка |
< | Предыдущая ячейка |
+ | Значение текущей ячейки увеличивает на 1 |
— | Значение текущей ячейки уменьшают на 1 |
. | Напечатать значение из текущей ячейки |
, | Ввести извне значение и сохранить в текущей ячейке |
[ | Начало цикла |
] | Конец цикла |
Как всё писалось?
Я начал смотреть видеоролики, просматривал статью на Википедии, чтобы понять, что это за язык и с чем его едят)) Это оказалось не таким уж лёгким занятием, но я справился.
Как только я создал проект, я начал с создания класса Pyfuck, в который добавлял следующие функции:
Функция инициализации:
def __init__(self):
self.memory = [0] * 30000 # Память для хранения данных
self.pointer = 0 # Указатель текущей ячейки памяти
self.output = "" # Результирующая строка
Интерпретатор имеет память под 30.000 однобайтовых ячеек с нулевыми начальными значениями (всё, как в оригинальном Brainfuck).
Имеется указатель текущей ячейки памяти (его переключение осуществляется с помощью команд > и < в коде программы) и результирующая строка (она выводит итоговый результат программы).
Следующей является функция интерпретации:
def interpret(self, program):
self.output = ""
for i in range(len(program)):
command = program[i]
if command == ">": # Следующая ячейка
self.pointer += 1
elif command == "<": # Предыдущая ячейка
self.pointer -= 1
elif command == "+": # Значение текущей ячейки увеличивает на 1
self.memory[self.pointer] += 1
elif command == "-": # Значение текущей ячейки уменьшают на 1
self.memory[self.pointer] -= 1
elif command == ".": # Напечатать значение из текущей ячейки
self.output += chr(self.memory[self.pointer])
elif command == ",": # Ввести извне значение и сохранить в текущей ячейке
input_value = input("Введите значение: ")
if len(input_value) <= 1:
self.memory[self.pointer] = ord(input_value)
else:
return
elif command == "[": # Начало цикла
if self.memory[self.pointer] == 0:
nested = 1
while nested > 0:
i += 1
if program[i] == "[":
nested += 1
elif program[i] == "]":
nested -= 1
elif command == "]": # Конец цикла
if self.memory[self.pointer] != 0:
nested = 1
while nested > 0:
i -= 1
if program[i] == "]":
nested += 1
elif program[i] == "[":
nested -= 1
else:
print("Ошибка: неизвестная команда!")
return self.output
В цикле for происходит итерация по каждой команде программы. В зависимости от команды выполняются различные действия: перемещение указателя на следующую или предыдущую ячейку памяти, увеличение или уменьшение значения текущей ячейки, печать символа из текущей ячейки памяти и считывание введённого значения в текущую ячейку.
Также реализована поддержка циклов: если значение текущей ячейки равно 0, программа пропускает все команды до соответствующей закрывающей скобки. Если же значение текущей ячейки памяти не равно 0, то происходит возврат к соответствующей открывающей скобке, чтобы продолжить выполнение цикла.
Как составляется программа?
Тут всё довольно интересно) Для составления программ удобно использовать таблицу символов ASCII:
Мы должны обратить внимание на Decimal (это число, которое соответствует определённому символу. Это десятичное представление числа символа в таблице ASCII. Например, символ «A» имеет значение 65 в ASCII). В Brainfuck это будет выглядеть, как 65 команд »+».
Вот пример программы, печатающая «Hello World!»:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+++++++++++++++++++++++++++++.+++++++..+++.>++++++++++++++++++++++++++++++++.<------------------------.++++++++++++++++++++++++.+++.------.--------.>+.
Результат программы
Заключение
Я хотел бы подчеркнуть, что написание данного интерпретатора было интересным и познавательным опытом. Это позволило мне лучше понять работу простых языков программирования и тонкости их реализации. Полученный интерпретатор может быть полезен для изучения и демонстрации возможностей Brainfuck, а также в качестве инструмента для выполнения простых задач на этом языке.
Полный код можно посмотреть на моём GitHub.
С вами был Yura_FX. Спасибо, что дочитали данную статью до конца. Не забывайте делиться своим мнением в комментариях :)