Всем привет.
Сегодня разберем как программировать на самом лучшем эзотерическим языке программирования, а именно BrainFuck.
Немного истории
BrainFuck дословно переводится как «еб**ь мозг» =) из за названия он не очень популярен, а так его можно было бы использвать в школах, дабы преподать людям основы основ.
BrainFuck придумал Урбаном Мюллером (нем) в 2003 году. Сейчас это самый популярный эзотерический язык программирования. BrainFuck предстовляет собой только 8 команд, и этого достаточно что бы написать любую программу как и на С++, это как раз минимальный набор для языка.
Об языке
Как говорилось ранее язык имеент всего лишь 8 комманд.
> ----------------перейти к следующей ячейке
< ----------------перейти к предыдущей ячейке
+ ----------------увеличить значение в текущей ячейке на 1
— ----------------уменьшить значение в текущей ячейке на 1
. ----------------напечатать значение из текущей ячейки
, ----------------ввести извне значение и сохранить в текущей ячейке
[ ----------------если значение текущей ячейки нуль, перейти вперёд по
тексту программы на ячейку, следующую за соответствующей
] (с учётом вложенности)
] ----------------если значение текущей ячейки не нуль, перейти назад по тексту
программы на символ [ (с учётом вложенности)
Пример программы
Программа печатающая Hello World!
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
------.--------.>+.>.
Разберем ее позже
Странное место статьи
Как вы уже заметили, что статья находится в разделе C++, не странно ли, нет, так как сдесь пойдет речь именно о С++, а именно написания интерпретатора к BrainFuck. Почему? Просто в BrainFuck всего лишь 8 комманд и пишется все это очень быстро.
Начнем
Нам потребуется только ввод-вывод и чтение исходника, для этого подойдут
iostream и fstream, так что подключаем их
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char** argv)
{
}
Теперь загрузим наш исходник
ifstream file(argv[1]);
Эти мы создадим поток с файлом в качестве параметра (programm source.bf)
Теперь объявим пару переменных, это:
массив чаров на 30000 элементов (ячейки),
адресную переменную
и переменную в которой будет лежать текущая команда
и того:
unsigned char a[30000];
unsigned char *b = a;
char c;
Еще надо обнулить массив ячеек
А теперь не будем замарачиваться какими то замудренными паттернами и тд а просто через switch перебираем наши комманды, читаем первую комманду и начинаем перебирать:
file >> c;
while(!(file.eof()))
{
switch©
{
case '>': break;
case '<': break;
case '+': break;
case '-': break;
case '.': break;
case ',': break;
case '[': break;
case ']': break;
default: break;
}
file >> c;
}
переменная b будет отвечать за выполнение комманд
переменная a хранит в себе ячейки значений
переменная c хранит в себе текущую комманду
переменная file содержит поток исходника
Теперь приступим к заполнению реакций на команду
> <
Этими командами мы перемещаемся в ячейках, реализуем их
b++;
и
b--;
все очень просто, b у нас держит адрес первого элемента массива, и если прибавить еденицу то он переместится к следующиму, а если отнять еденицу то переместся к предыдущей (я не делаю проверку на выход за массив, хотя вы можете реализовать)
+ -
Эти команды изменяют значение текущей ячейки, реализуется тоже очень просто
(*b)--;
и
(*b)++;
Сначало разименовываем а потом прибавляем к текущему значению еденицу. Скобочки нужны обязательно так как приоритет у инкрементов больше чем у разименовывания.
. ,
Вывод —
cout << *c;
Ввод —
cin >> *c;
тоже все просто, разименовываем и записываем в ячейку.
[ ]
ну и наконец то циклы, тоже ничего сложного не прелставляют, как они работают можно почитать выше
Итак, начало цикла —
int n = 1;
if((*b) == 0)
while(n != 0)
{
file >> c;
if(с == ']')
n--;
else if(с == '[')
n++;
}
тут мы смотрим, если значение равно 0 то пропускаем все что находится между []
n — уровень вложения
Конец цикла-
int n = 1;
if((*b) != 0)
while(n != 0)
{
int k = file.tellg();
file.seekg(k - 2);
file >> c;
if(c == ']')
n++;
else if(c == '[')
n--;
}
сдесь все тоже самое, нашли закрывающуюся скобку, перемещаямся на 2 позиции назад, читаем символ, если закрывающая скобка то прибавляем вложение если открывающаяся то убавляем
Вот и все, 8 комманд, теперь компилируем и смотрим выполнение примера
исходник:
http://codepaste.ru/9027/
Попишем
Итак давайте для начала разберем исходник вот этот
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
++++++++++++++++++++++++++++++++++++++++++++++.
------------------.
+++++++++++++++++++.
---------------.
-------------------------------------------------------.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
+++.
----------------------------------------------------------------------
-------------------------------------.
сдесь не применяются ячейки, про них может позже
стандартная ячейка стоит 0 и все изменения применяются к ней
вначале мы прибавляем 69 и выводим на экран, это получается большое E (69)
дальше прибавляем 46 и выводим получаем s(115), потом отнимаем от 115 18 и выводим получаем a(97) и так далее и получаем на выходе Esate.ru и новоя строчка (10)
таблицу можно посмотреть
тут
В примере выше, где hello world там используются ячейки, можете поизучать.
Заключение
Есть еще такой язык pbrain там все тоже самое только добавлены 3 комманды — ( ):
() — открытие закрытие функции: — вызов функции
Ну вот и все, жду ваших интересных программ на BrainFuck =)
Комментарии (2)
rss свернуть / развернутьНаверное пока не решусь воспользоваться), сильно сложно, лучше буду вводить команды ассемблера Нex-ами)))) так хоть мозг цел будет=))))
Супер!!!
+1 к статьи, только плиз мат убери=)
))
свернуть ветку
свернуть ветку