Язык программирования Brainfuck БрайнфакBrainfuck (мозгоеб) является минималистским языком программирования созданным Урбан Мюллер где-то в 1993 году. Язык иногда называют brainf*ck, brainf***, или просто BF в приличном обществе. Программирование для начинающих. Достижением Мюллера было создание простого языка программирования Тьюринга, который может быть реализован с наименьшим из возможных компиляторов . Язык состоит из восьми управляющих операторов. Оригинальный компилятор 2-ой версии, написанный для Amiga , составлял 240 байт. Программирование для чайников. Как следует из названия, Brainfuck (мозгоебские) программы, как правило, трудно понять. Тем не менее, это машина Тьюринга , и поэтому Brainfuck, может выполнить любые вычислительные задачи. Пренебрегая очевидной трудностью в программировании определенных задач на языке Brainfuck, почти любая задача под силу этому языку/, не говоря уже про основы рограммирования. Язык основан на простой модели машины, состоящей, помимо программы, из массива обнуленных байтов, указателя на массив (инициализируется и указывает на первый байт массива), и два потока байт для ввода и вывода данных. Восемь управляющих операторов языка, каждый из которых состоит из одной буквы, являются следующие: Символ Смысл
> приращение указателя.
< декремент указателя.
+ приращение байт на указатель.
- декремента байтов на указатель.
. Выход из байта указателя (ASCII).
, вклад в байт по указателю (ASCII).
[ Перейти вперед на оператор после соответствующего ] , если байт на указатель равен нулю.
] Перейти обратно на оператор после соответствующего [ если байта на указатель не равно нулю.
(В качестве альтернативы оператор ] может быть интерпетирован как "перейти обратно к соответствующему [ ". Это краткоее, но менее симметричное и эффективное по времени. Обе версии эквивалентного поведения Brainfuck программы.) (Третья эквивалентная версия, мало употребляется, является: [ означает "скачок вперед в соответствующие ] ", и ] означает "возврат на заявление после соответствующего [ если байт на указателе отличный от нуля ".) Brainfuck программы могут быть переведены на язык C с помощью следующей замены, предполагая, ptr имеет тип char* : Brainfuck | C |
---|
> | ++ptr; | < | --ptr; | + | ++*ptr; | - | --*ptr; | . | putchar(*ptr); | , | *ptr = getchar(); | [ | while (*ptr) { | ] | } |
Примеры Привет мир! Программа, которая печатает "Hello World!" на экране:++++++++++[>+++++++>++++++++++>+++>+<<<<-]
>++.>+.+++++++..+++.>++.<<+++++++++++++++.
>.+++.------.--------.>+.>.
Нулевая текущая позиция [-]
Работа с символами (ввод-вывод) ,.
,[.,]
Непрерывный цикл, который принимает ввод с клавиатуры и отображает его на экране. Отметим, что это предполагает ввод 0 как сигнал конца ввода; в разных реализациях этот момент может изменяться. Версии для -1 и "никаких изменений", будут выглядеть как " ,+[-.,+] "и" ,[.[-],] ". Манипуляции с указателем >,[.>,]
Данная версия программы, также сохраняет все из потока входа в массиве для использования в будущем, путем перемещения указателя каждый раз на новую позицию в массиве.
Сложение [->+<]
Это добавляет значение текущего местоположения (разрушительно, он остается в нуле) к значению в следующей ячейке.
Условные операторы ,----------[----------------------.,----------] Этот код получает буквы в нижнем регистре при вводе с клавиатуры и переводит в верхний регистр. Для выхода нажмите клавишу ввода. Во-первых, для получения первого символа используется «,» и сразу же вычитается 10 от него. (Большинство, но не все, Brainfuck программы используют 10 для возвращения результата.) Если пользователь нажмет ввод, оператор цикла ( [ ) прыгнет в конец прошлого цикла, потому что мы установили значение первого байта в ноль. Если входной символ не был 10, мы смело предполагаем, что было введена строчная буква, и входим в цикл, в котором мы вычитаем еще 22 от него, в общей сложности 32, что представляет собой разницу между ASCII строчными и заглавными буквами. Следующим действием мы вывели на экран. Теперь ввод следующего символа, и снова вычесть 10. Если этот символ был перевод строки, мы выходим из цикла, в противном случае мы возвращаемся к началу цикла, вычитаем еще 22, выводим на экран, и так далее. Когда мы выходим из цикла, программа завершается, так как команд больше не осталось. Кроме того ,>++++++[<-------->-],,[<+>-],<.>.
Эта программа добавляет два однозначных числа и отображает результат правильно, если этот результат тоже имеет только одну цифру: 4 +3 7
(Теперь все становится немного сложнее. Мы можем также обратиться к байту в массив [0], [1], [2], и так далее.) Первый номер вводится в [0], и 48 из него вычитается, чтобы исправить его (ASCII коды для цифр 0-9 являются 48-57). Это делается, положив 6 в ячейку [1] и с помощью цикла вычесть 8 из [0] и повтоярется много раз. (. Это распространенный метод сложения или вычитания больших чисел) Далее, знак плюс вход в [1], затем второй номер на вход, перезаписи знаком плюс. Следующий цикл [<+>-] делает реальную работу, перемещение второго число на первое, сложив их вместе и обнуленив [1]. Каждый раз, он добавляет единицу к [0] и вычитает один из [1], так что к тому времени [1] обнуляется, так как многие были добавлены [0], как были удалены из [1]. Теперь возврат вклада в [1]. (Мы не проверяем ошибки входных данных во всех случаях.) Затем указатель перемещается обратно на [0], который затемвыводится. ([0] в настоящее время a + (b + 48), так как мы не правильно b, который совпадает с (a + b) + 48, которая является тем, что мы хотим получить.) Теперь указатель перемещается в [1] , в которой хранится значение окончания программы, введенного с клавиатуры, что приводит к завершению программы.
Умножения
,,>++++++++[<------<------>>-]
<<[>[>+>+<<-]>>[<<+>>-]<<<-]
>>>++++++[<++++++++>-],<.>.
Как и в предыдущем примере, но теперь умножаем, а не складываем. Первый номер вводится в [0], звездочки, а затем второй номер вводятся в [1], и оба номера исправляются с помощью вычитания 48. Теперь мы вступаем в основной цикл умножения. Основная идея в том, что каждый раз через него мы вычтем одно из [0] и добавить [1] , текущая сумма хранится в [2]. В частности: первый внутренний движется схема [1] на обе [2], [3], в то время как обнуление [1]. (Это основной способ, чтобы дублировать номер.) Следующего внутреннего движется схема [3] обратно в [1], обнуление [3]. Тогда вычитается из [0], а внешний цикл заканчивается. На выходе из этой петли, [0] равен нулю, [1] до сих пор второй номер в ней, и [2] произведения двух чисел. (Если бы мы заботились о сохранении первого числа, мы могли бы добавить от одного до [4] каждый раз через внешний цикл, а затем переместить значение из [4] к [0] позже.) Теперь мы добавляем 48 для завершения, вход возвращения в [3], выход ASCII, а затем выход возвращения мы просто сохраняем.
|