Сказ о том, как я интерпретатор 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:

8683f94734e632493b3302fae53aa98a.jpg

Мы должны обратить внимание на Decimal (это число, которое соответствует определённому символу. Это десятичное представление числа символа в таблице ASCII. Например, символ «A» имеет значение 65 в ASCII). В Brainfuck это будет выглядеть, как 65 команд »+».

Вот пример программы, печатающая «Hello World!»:

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.+++++++++++++++++++++++++++++.+++++++..+++.>++++++++++++++++++++++++++++++++.<------------------------.++++++++++++++++++++++++.+++.------.--------.>+.

Результат программы

Результат программы

Заключение

Я хотел бы подчеркнуть, что написание данного интерпретатора было интересным и познавательным опытом. Это позволило мне лучше понять работу простых языков программирования и тонкости их реализации. Полученный интерпретатор может быть полезен для изучения и демонстрации возможностей Brainfuck, а также в качестве инструмента для выполнения простых задач на этом языке.

Полный код можно посмотреть на моём GitHub.

С вами был Yura_FX. Спасибо, что дочитали данную статью до конца. Не забывайте делиться своим мнением в комментариях :)

© Habrahabr.ru