В этой статье есть несколько проблем. Помогите улучшить ее или обсудите эти проблемы на странице обсуждения . ( Узнайте, как и когда удалять эти сообщения )
|
Парадигма | Эзотерический , императивный , структурированный |
---|---|
Разработано | Урбан Мюллер |
Впервые появился | Сентябрь 1993 г. |
Дисциплина набора текста | Безтиповый |
Расширения имени файла | .б, .бф |
Веб-сайт | brainfuck.org |
Под влиянием | |
P′′ , ЛОЖЬ | |
Под влиянием | |
Мальболге |
Brainfuck — это эзотерический язык программирования, созданный в 1993 году швейцарским студентом Урбаном Мюллером. [1] Разработанный с целью быть максимально минималистичным, язык состоит всего из восьми простых команд, указателя данных и указателя инструкций . [2]
Brainfuck — пример так называемого Turing tarpit : его можно использовать для написания любой программы, но это непрактично, поскольку он обеспечивает так мало абстракций, что программы становятся очень длинными или сложными. Хотя Brainfuck полностью Turing-complete , он не предназначен для практического использования, а предназначен для того, чтобы бросать вызов и развлекать программистов . [3] [4] Brainfuck требует разбить команды на небольшие и простые инструкции.
Название языка происходит от сленгового термина brainfuck , который относится к вещам настолько сложным или необычным, что они выходят за рамки человеческого понимания, поскольку он не был предназначен и создан не для разработки реального программного обеспечения, а для того, чтобы бросить вызов границам компьютерного программирования .
Поскольку название языка содержит ненормативную лексику , используется множество заменителей, таких как brainfsck, branflakes, brainoof, brainfrick, BrainF и BF. [5]
Мюллер разработал Brainfuck с целью реализации наименьшего возможного компилятора , [6] вдохновленный 1024- байтовым компилятором для языка программирования FALSE . [7] [8] Оригинальный компилятор Мюллера был реализован в сборке Motorola 68000 на Commodore Amiga и скомпилирован в двоичный файл размером 296 байт. Он загрузил первый компилятор Brainfuck на Aminet в 1993 году. Программа поставлялась с файлом «Readme» , в котором кратко описывался язык и бросался вызов читателю: «Кто может запрограммировать что-нибудь полезное с его помощью? :)». Мюллер также включил интерпретатор и несколько примеров. Вторая версия компилятора использовала всего 240 байт. [9]
Язык состоит из восьми команд . Программа brainfuck — это последовательность этих команд, возможно, перемежающихся другими символами (которые игнорируются). Команды выполняются последовательно, за некоторыми исключениями: указатель инструкций начинается с первой команды, и каждая команда, на которую он указывает, выполняется, после чего он обычно перемещается вперед к следующей команде. Программа завершается, когда указатель инструкций проходит мимо последней команды.
Язык brainfuck использует простую машинную модель, состоящую из указателя программы и инструкций, а также одномерного массива из не менее 30 000 байтовых ячеек, инициализированных нулем; подвижного указателя данных (инициализированного так, чтобы он указывал на самый левый байт массива); и двух потоков байтов для ввода и вывода (чаще всего подключенных к клавиатуре и монитору соответственно и использующих кодировку символов ASCII ).
Каждая из восьми языковых команд состоит из одного символа:
Характер | Инструкция выполнена |
---|---|
> | Увеличить указатель данных на единицу (чтобы указать на следующую ячейку справа). |
< | Уменьшить указатель данных на единицу (чтобы указать на следующую ячейку слева). |
+ | Увеличить байт в указателе данных на единицу. |
- | Уменьшить байт в указателе данных на единицу. |
. | Вывести байт по указателю данных. |
, | Принять один байт входных данных, сохранив его значение в байте по указателю данных. |
[ | Если байт в указателе данных равен нулю, то вместо перемещения указателя инструкций вперед к следующей команде, переместите его вперед к команде, следующей за соответствующей ] командой. |
] | Если байт в указателе данных ненулевой, то вместо перемещения указателя инструкций вперед к следующей команде, переместите его обратно к команде после соответствующей [ команды. [a] |
[
и ]
сопоставляются так, как это обычно делают скобки: каждый [
соответствует ровно одному ]
и наоборот, идет первым, и между ними [
не может быть несовпадающих [
или .]
Программы Brainfuck обычно сложны для понимания. Отчасти это происходит потому, что любая не слишком сложная задача требует длинной последовательности команд, а отчасти потому, что текст программы не дает прямых указаний на состояние программы . Это, а также неэффективность Brainfuck и его ограниченные возможности ввода/вывода, являются некоторыми из причин, по которым он не используется для серьезного программирования. Тем не менее, как и любой полный по Тьюрингу язык, Brainfuck теоретически способен вычислять любую вычислимую функцию или моделировать любую другую вычислительную модель, если ему предоставить доступ к неограниченному объему памяти и времени. [10] Было написано множество программ Brainfuck. [11] Хотя программы Brainfuck, особенно сложные, сложно писать, довольно просто написать интерпретатор для Brainfuck на более типичном языке, таком как C, из-за его простоты. Интерпретаторы Brainfuck, написанные на самом языке Brainfuck, также существуют. [12] [13]
В качестве первого простого примера следующий фрагмент кода добавит значение текущей ячейки к следующей ячейке: Каждый раз, когда цикл выполняется, текущая ячейка уменьшается, указатель данных перемещается вправо, следующая ячейка увеличивается, а указатель данных снова перемещается влево. Эта последовательность повторяется до тех пор, пока начальная ячейка не станет равна 0.
[ - > + < ]
Это можно включить в простую программу сложения следующим образом:
++ Ячейка c0 = 2 > +++++ Ячейка c1 = 5 [ Начните циклы с указателя ячейки на счетчике циклов (в нашем случае c1) < + Добавьте 1 к c0 > - Вычтите 1 из c1 ] Завершите циклы с указателем ячейки на счетчике циклов На этом этапе наша программа прибавила 5 к 2, оставив 7 в c0 и 0 в c1, но мы не можем вывести это значение на терминал, так как оно не закодировано в ASCII.Чтобы отобразить символ ASCII «7», мы должны прибавить 48 к значению 7. Мы используем цикл для вычисления 48 = 6 * 8.++++ ++++ c1 = 8 и это снова будет наш счетчик цикла [ < +++ +++ Добавьте 6 к c0 > - Вычтите 1 из c1 ] < . Выведите c0, который имеет значение 55, что переводится как «7»!
Следующая программа выводит на экран «Hello World!» и новую строку:
[ Эта программа выводит на экран «Hello World!» и новую строку; ее длина составляет 106 активных командных символов . [ Она не самая короткая . ] Этот цикл является "начальным циклом комментариев" , простым способом добавления комментария в программу BF, так что вам не нужно беспокоиться о каких-либо символах команд . Любые символы " . " , " , " , " + " , " - " , " < " и " > " просто игнорируются , символы " [ " и " ] " просто должны быть сбалансированы . Этот цикл и содержащиеся в нем команды игнорируются, поскольку текущая ячейка по умолчанию имеет значение 0; значение 0 приводит к пропуску этого цикла . ] ++++++++ Установить ячейку № 0 на 8 [ > ++++ Добавить 4 к ячейке № 1; это всегда установит ячейку № 1 на 4 [ так как ячейка будет очищена циклом > ++ Добавить 2 к ячейке № 2 > +++ Добавить 3 к ячейке № 3 > +++ Добавить 3 к ячейке № 4 > + Добавить 1 к ячейке № 5 <<<< - Уменьшить счетчик цикла в ячейке № 1 ] Цикл, пока ячейка № 1 не станет равной нулю; количество итераций равно 4 > + Добавить 1 к ячейке № 2 > + Добавить 1 к ячейке № 3 > - Вычесть 1 из ячейки № 4 >> + Добавить 1 к ячейке № 6 [ < ] Вернуться к первой найденной нулевой ячейке; это будет ячейка № 1, очищенная предыдущим циклом < - Уменьшить счетчик цикла в ячейке № 0 ] Выполнять цикл до тех пор, пока ячейка № 0 не станет равной нулю; количество итераций равно 8 Результат: Номер ячейки: 0 1 2 3 4 5 6 Содержимое: 0 0 72 104 88 32 8 Указатель: ^>> . Ячейка № 2 имеет значение 72, что равно 'H' > --- . Вычтите 3 из ячейки № 3, чтобы получить 101, что равно 'e' +++++++ .. +++ . Аналогично для 'llo' из ячейки № 3 >> . Ячейка № 5 равна 32 для пробела < - . Вычтите 1 из ячейки № 4 для 87, чтобы получить 'W' < . Ячейка № 3 была установлена на 'o' из конца 'Hello' +++ . ------ . -------- . Ячейка № 3 для 'rl' и 'd' >> + . Добавьте 1 к ячейке № 5, чтобы получить восклицательный знак > ++ . И, наконец, новая строка из ячейки № 6
Для удобства чтения этот код был разнесен на много строк, а также были добавлены пробелы и комментарии. Brainfuck игнорирует все символы, кроме восьми команд, +-<>[],.
поэтому для комментариев не требуется никакого специального синтаксиса (при условии, что комментарии не содержат командных символов). Код можно было бы написать так:
++++++++ [ > ++++ [ > ++ > +++ > +++ > + <<<< - ] > + > + > - >> + [ < ] < - ] > > . > --- . +++++++ .. +++ . >> . < - . < . +++ . ------ . -------- . >> + . > ++ .
Эта программа шифрует свои входные данные с помощью шифра ROT13 . Для этого она должна преобразовать символы AM ( ASCII 65–77) в NZ (78–90) и наоборот. Также она должна преобразовать am (97–109) в nz (110–122) и наоборот. Она должна преобразовать все остальные символы в самих себя; она считывает символы по одному и выводит их зашифрованные эквиваленты, пока не прочтет EOF (здесь предполагается, что он представлен либо как -1, либо как «без изменений»), после чего программа завершается.
- , + [ Прочитать первый символ и начать внешний цикл чтения символов - [ Пропустить вперед, если символ равен 0 >> ++++ [ > ++++++++ < - ] Установить делитель (32) для цикла деления (РАСПОЛОЖЕНИЕ ПАМЯТИ: делимое копирование остаток делитель частное ноль ноль) < + < - [ Установить делимое (x минус 1) и войти в цикл деления > + > + > - [ >>> ] Увеличить копию и остаток / уменьшить делитель / Обычный случай: пропустить вперед < [[ > + < - ] >> + > ] Особый случай: переместить остаток обратно в делитель и увеличить частное <<<<< - Уменьшить делимое ] Завершить цикл деления ] >>> [ - ] + Завершить цикл пропуска; обнулить бывший делитель и повторно использовать пространство для флага > -- [ - [ < - > +++ [ - ]]] < [ Обнулить этот флаг, если частное не было равно 2 или 3; нулевое частное; проверить флаг ++++++++++++ < [ Если флаг, то установить делитель (13) для второго цикла деления (РАЗМЕТКА ПАМЯТИ: ноль копировать делимое делитель остаток частное ноль ноль) > - [ > + >> ] Уменьшить делитель; Обычный случай: увеличить остаток > [ + [ < + > - ] > + >> ] Особый случай:увеличить остаток / переместить его обратно в делитель / увеличить частное <<<<< - Уменьшить делимое ] Завершить цикл деления >> [ < + > - ] Добавить остаток обратно к делителю, чтобы получить полезное 13 > [ Пропустить вперед, если частное было 0 - [ Уменьшить частное и пропустить вперед, если частное было 1 - << [ - ] >> Нулевое частное и делитель, если частное было 2 ] << [ << - >> - ] >> Нулевой делитель и вычитание 13 из копии, если частное было 1 ] << [ << + >> - ] Нулевой делитель и добавление 13 к копии, если частное было 0 ] Завершение внешнего цикла пропуска (переход сюда, если ((символ минус 1)/32) не было 2 или 3) < [ - ] Очистка остатка от первого деления, если второе деление было пропущено < . [ - ] Вывод символа ROT13ed из копии и его очистка < - , + Прочтение следующего символа ] Завершение цикла чтения символа
В 2024 году исследовательский проект Google использовал слегка модифицированную версию Brainfuck из 7 команд в качестве основы искусственной цифровой среды. В этой среде они обнаружили, что репликаторы возникали естественным образом и конкурировали друг с другом за господство в среде. [14]
]
команда может быть переведена как безусловный переход к соответствующей [
команде или наоборот; программы будут вести себя так же, но будут работать медленнее из-за ненужного двойного поиска.