Вступление
Сидел я тут как-то вечером и думал, что можно такое интересное написать на 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. Спасибо, что дочитали данную статью до конца. Не забывайте делиться своим мнением в комментариях :)
Комментарии (9)
Alexandroppolus
28.11.2023 11:11+3На кодоварсах есть сумасшедшая ката с компиляцией "ассемблера" в код на брейнфаке.
evgeniya_oku53
28.11.2023 11:11Друг мой, статья оказалась очень интересной и познавательной. Я узнала много нового о данном языке программирования. Оказывается, вот оно как, язык, имеющий всего 8 команд, которые позволяют написать что-то простенькое. Мне особенно понравилось, как легко можно читать и понимать ваш исходный код. Как будет свободное время, скачаю ваш интерпретатор и начну пытаться что-то на нём писать.
andruino99Reg
28.11.2023 11:11У меня где то лежала старенькая Raspberry Pi 3 с Ubuntu, может попробую, так сказать, портировать туда вашу прогу. Авось, что то и получится
includedlibrary
28.11.2023 11:11В смысле портировать, код же платформонезависимый, он итак будет работать без всяких усилий с вашей стороны? Можно портировать на малинку какой-нибудь компилятор brainfuck.
Yura_FX Автор
28.11.2023 11:11Извиняюсь, но я особо за Raspberry не шарю, так что могу только пожелать Вам удачи в этом деле.
bfDeveloper
Очень рекомендую что-нибудь написать на самом Brainfuck и запустить в вашем эмуляторе. Мне в своё время очень помогло получить ощущение контроля:
память это ячейки, интерпретируй как хочешь,
алгоритмы это про логику, а не конструкции языка
в программировании есть свой юмор
Yura_FX Автор
Спасибо за совет, обязательно попробую написать что-нибудь на Brainfuck'е и запустить в моём интерпретаторе (оговорочка: не эмулятор). Согласен с вами, контроль над программой - это очень важная вещь в программировании)