О BrainFuck замолвим слово

Сравнительно недавно выучил BrainFuck и хотел бы с Вами поделиться его простотой и элегантностью. =)

Подробно о нём можно почитать в Википедии, а также в энциклопедии эзотерических языков программирования. IDE для BF качаем тут. Всё ниже сказанное относится именно к этой IDE, так как от разных реализаций языка может зависеть и поведение при выполнении программ, хотя этого мною замечено и не было.

Готовы узнать об одном из самых известных эзотерических языков программирования? Тогда читаем дальше!

Итак, язык имеет всего 8 команд и написание программы на нём является весьма даже интересной головоломкой. Вот эти команды:

+ Увеличить значение текущей ячейки на 1.
- Уменьшить значение текущей ячейки на 1.
[ Если значение текущей ячейки ненулевое, то перейти внутрь блока. После выполнения всех инструкций внутри блока снова запустить проверку. Простейшая реализация цикла.
] Закрывающая цикл команда.
> Перейти к следующей ячейке.
< Перейти к предыдущей ячейке.
. Вывод значения текущей ячейки. Вывод происходит в ASCII-кодах, запомните!
, Ввод с клавиатуры. Значение (код введённого ASCII-символа) заносится в текущую ячейку памяти.

Работать в BF приходится сразу с памятью. Всего 64K, то есть, 65536 ячеек - потенциальных переменных! - с разрядностью 8. То есть, максимальное число, которое Вы спожете записать, - 255. На оперировании этими ячейками и строится весь BF.

Теперь сразу немного практики. И для начала вывод банального “Hello, World!” с пояснениями:

>++++++++[<+++++++++>-]<.
>++++[<+++++++>-]<+.
+++++++.
.
+++.
>++++++[<----------->-]<-.
------------.
>+++++[<+++++++++++>-]<.
>++++[<++++++>-]<.
+++.
------.
--------.
>++++++[<----------->-]<-.

С самого начала у нас есть пустая память и указатель на первом байте. Смещаемся вправо ( > ) и устанавливаем значение счётчика (он нам понадобится для оптимизации) в 8 ( ++++++++ ). После этого запускаем цикл ( [ ). Если значение текущей ячейки не равно нулю, то перейти в блок. У нас значение равно 8, поэтому идём в блок.

В блоке мы возвращаемся на первый байт ( < ) и увеличиваем его значение на 9 единиц, затем возвращаемся в байт-счётчик и уменьшаем его на единицу ( >- ). Снова проверка на равенство нулю и снова цикл, пока счётчик не обнулится. В этот момент у нас в первом байте будет лежать значение 72, что соответствует ASCII-коду символа “H”. Нетрудно догадаться, что мы могли написать 72 плюса и получить тот же самый результат. Только код выглядел бы устрашающе! =) Для этого нам и нужен счётчик. Осталось вывести символ ( . ) и продолжить выполнение программы.

Надеюсь, принцип понятен, остальную часть разобрать следует по аналогии, ничего страшного там нет. =) Теперь пара трюков. В принципе, на BF можно написать что угодно: тут есть 64K памяти, циклы (они же ветвления), перемещения по памяти… Но делать это неудобно, на то BF и эзотерический язык! =) Для облегчения программирования на BF давно выведены некоторые конструкции, которые облегчают жизнь.

[-] - полная очистка (обнуление) текущей ячейки. Работает элементарно: если значение текущей ячейки ненулевое, то уменьшить её значение на 1. Рано или поздно ячейка приобретёт цвет нуля и цикл завершится. =) Также очевидно, что можно использовать конструкцию [+], которая творит то же самое.

[->+<] - перенос значения из одной ячейки памяти в другую.

[->+>+<<]>>[-<<+>>]<< - один из вариантов копирования. Используется третья ячейка.

Вот здесь Вы сможете найти реализации множества самых необходимых и полезных алгоритмов на языке BF, от сложения до псевдослучайных чисел. На этом можно далеко уехать. =)

Теперь разберём пример посложнее. Программа потребует ввод и выведет фразу: “Hello, [имя]!”.

; Ввод в память строки (оставляем две ячейки для вывода строки и счётчика
>>,———-[++++++++++>,———-]
; Возврат на первую ячейку (предшествующую первой непустой слева)
<[<]<
; Вывод "Hello, "
>++++++++[<+++++++++>-]<.
>++++[<+++++++>-]<+.
+++++++.
.
+++.
>++++++[<----------->-]<-.
------------.>>

.>[.>]

; Вывод “!”.
<[<]<+.

Код хорошо самодокументирован, разобраться не сложно. Для программирования на BF нужно уметь хорошо работать с памятью, не забывать, в какой ячейке что хранится. Trace и дамп памяти Вам в помощь. =)

В последней версии BrainFuck Developer 1.4.6 добавлена возможность Text Generator, которая позволяет автоматически генерировать код вводимых строк. До выпуска этой версии мне срочно нужна была такая функция и я её написал. Напоследок я выкладываю её Вам для самостоятельного разбора и изучения. Если кто сложет её оптимизировать и документировать, то я с радостью посмотрел бы результат! =)

,———-[++++++++++
[->———>+<[++++++++++>[-]]>[>>+<<[-]>]<<
<]
>>>>[->[-]+++++[>++++++++<-]>+++.[-]<<]<<
[-]+++++++++[>++++++++++<-]>+.[-]<
++++++[>++++++++++<-]>++.[-]<
++++++++++[>+++++[>++++++++<-]>+++.[-]<<-]
++++++[>++++++++++<-]>.[-]<
+++++[>+++++++++<-]>.[-]<
+++++++++[>++++++++++<-]>+++.[-]<
++++++[>++++++++++<-]>++.[-]<
<[->+++++[>++++++++<-]>+++.[-]<<]
[-]++++++[>++++++++<-]>–.[-]<
+++++++++[>++++++++++<-]>+.[-]<
++++++[>++++++++<-]>—.[-]<
+++++++++[>++++++++++<-]>+++.[-]<
++++++++++.[-]<
,----------]

Призываю Вас описать свой опыт работы с BF и примеры своих скриптов. Думаю, это будет познавательно! Если у Вас возникли вопросы, то пишите их в комментариях или мне на почту (контакты в меню справа).

Ссылки по теме:
http://ru.wikipedia.org/wiki/Brainfuck - Русская Википедия о BF.
http://en.wikipedia.org/wiki/Brainfuck - Английская версия. Как всегда, полнее.
http://esoteric.voxelperfect.net/wiki/Brainfuck_algorithms - Набор алгоритмов на все случаи жизни.
http://community.livejournal.com/ru_brainfucker - ЖЖ-сообщество о BF.

Комментариев: 4

  1. SHAman пишет:

    Наконец-то я нашел объяснение синтаксиса брейнфака! Пример этот видел много раз, но как-то не удосуживался сесть и подумать “а как это работает” - все ждал справочника. Примечательно то, что весь справочник поместился в одну статью:)

    Спасибо, очень интересно.

  2. huze пишет:

    =) А Вам спасибо за отзыв. =)

  3. SHAman пишет:

    Кстати, программирование на брейнфаке, наверняка прокачает мозг и даст возможность высокоуровневым программерам познакомиться с низким уровнем и с тем, как оно может быть и как оно устроено. Будет время - обязательно попрактикуюсь в создании программ на брейнфаке. Например, будет интересно взять log2(x)…

  4. huze пишет:

    В принципе, ничего сверхестественного в таком алгоритме нет. Единственная проблема состоит в дробном представлении значения функции… Но и она решается! =)