- PVSM.RU - https://www.pvsm.ru -
++++++++[->++++>+++++++++>+++++++++++++<<<]>>.>[->+>+<<]>---.>++++..+++.<<<<.>.>>----.+.>+++.<<<<+.
Или, говоря по человечески, здравствуй Хабр!
Сегодня я хотел бы предложить сообществу инструмент, который может помочь понять брейнфак тем кто с ним не знаком, сосчитать за Вас количество плюсов и минусов(например для меня это неиссякаемый источник кучи ошибок), ну и упростить понимание простых программ на брейнфаке вроде неоптимизированного HelloWorld'a.
Данная статья в первую очередь ориентирована на людей, которые только начинают открывать для себя этот замечательный язык. Если вы один из них — добро пожаловать под хабракат.
Итак, приступим.
Brainfuck — эзотерический язык, предназначенный для разминки
Знакомство с ним будет вестись на примере простенького транслятора на язык С++.
Программа на брейнфаке похожа на машину Тьюринга. Мы так же имеем бесконечную(или конечную, в зависимости от реализации) ленту ячеек, каждая из которых имеет размер в 1 байт. И по этой ленте передвигается взад-вперед один указатель.
Следовательно если мы хотим что бы выходной поток нашего транслятора мог компилироваться и исполняться, нам придется в первую очередь позаботиться о такой ленте.
Я решил реализовать её на базе массива, т.к. это был самый простой путь, хотя вариант с двусвязным списком максимально приблизил бы к бесконечности ячеек. Соответственно указатель является индексом текущего элемента.
//outFile - выходной .cpp файл
outFile<<"#include <iostream>"<<endl;
outFile<<"int main(){"<<endl;
outFile<<"char mas[256]={0}; int i=0;"<<endl;
Размер массива я взял 256, этого достаточно для большинства программ. При надобности легко изменить на любое другое значение.
Brainfuck простой язык! Brainfuck просто замечательный язык для начинающих, ведь он содержит всего 8 команд, каждая длиной в 1 символ, а значит Вы можете выучить его синтаксис за 15 минут! К сожалению это же является и его основной бедой, писать используя столь скудный запас очень и очень трудно.
Позвольте представить, ваши будущие друзья:
"+" — увеличение значения ячейки на 1.
"-" — уменьшение ячейки на 1.
"." — вывод содержимого ячейки на экран в соответствии с таблицей ASCII.
"," — считывание ввода пользователя в соответствии с таблицей ASCII.
"<" — сдвиг указателя на одну ячейку влево.
">" — сдвиг указателя на одну ячейку вправо.
"[" — начало цикла, который выполняется до тех пор, пока в текущей ячейке значение отличное от 0.
"]" — конец цикла.
Добавим их всех в наш транслятор:
switch (inputChar)
{
case '+': add();
break;
case '-': sub();
break;
case ',': scan();
break;
case '.': print();
break;
case '[': whileOpen();
break;
case ']': whileClose();
break;
case '<': prev();
break;
case '>': next();
break;
}
Прежде чем переходить к детальному рассмотрению функций, вынужден признаться, что я слегка обманул Вас в вышестоящем коде. Нетрудно догадаться что функция add(); должна реализовывать что то вроде mas[i]++;, но я обещал подсчитать за вас количество подряд идущих плюсов(да и минусов тоже). Обещание придется сдержать и поэтому функция add() будет заменена на другой кусок кода.
А теперь все по порядку:
Для реализации подсчета будем использовать переменные inc и dec
case '+': inc++;
break;
case '-': dec++;
break;
Для вставки результата вставим следующий код над конструкцией switch
if (inc && inputChar!='+') {op(inc,'+');inc=0;}
if (dec && inputChar!='-') {op(dec,'-');dec=0;}
И реализуем функцию op(int,char);
void op(int n, char c)
{
elem();
outFile<<c<<"="<<n<<";";
outFile<<"t//";
for (int i=0; i<n; i++) outFile<<c;
outFile<<endl;
}
Где elem(); подставляет в выходной файл конструкцию mas[i] (вынесено на всякий случай, если реализация массивом не удовлетворит каким либо нуждам).
void next()
{
outFile<<"i++;";
outFile<<"t//t >"<<endl;
}
void prev()
{
outFile<<"i--;";
outFile<<"t//t<"<<endl;
}
void scan()
{
outFile<<"std::cin>>";
elem();
outFile<<";";
outFile<<"t//t,";
outFile<<endl;
}
void print()
{
outFile<<"std::cout<<";
elem();
outFile<<";";
outFile<<"t//t.";
outFile<<endl;
}
void whileOpen( )
{
outFile<<"while(";
elem();
outFile<<"){";
outFile<<"t//t]"<<endl;
}
void whileClose()
{
outFile<<"}";
outFile<<"t//t["<<endl;
}
В каждой функции в конце вставляется комментарий, содержащий исходную команду.
Внесем наш switch в цикл, наведем красоты(вроде вставки в результирующий код return'a) и получим готовый транслятор.
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <fstream>
using namespace std;
ifstream inFile;
ofstream outFile;
void elem()
{
outFile<<"mas[i]";
}
void next()
{
outFile<<"i++;";
outFile<<"t//t >"<<endl;
}
void prev()
{
outFile<<"i--;";
outFile<<"t//t<"<<endl;
}
void op(int n, char c)
{
elem();
outFile<<c<<"="<<n<<";";
outFile<<"t//";
for (int i=0; i<n; i++) outFile<<c;
outFile<<endl;
}
void scan()
{
outFile<<"std::cin>>";
elem();
outFile<<";";
outFile<<"t//t,";
outFile<<endl;
}
void print()
{
outFile<<"std::cout<<";
elem();
outFile<<";";
outFile<<"t//t.";
outFile<<endl;
}
void whileOpen( )
{
outFile<<"while(";
elem();
outFile<<"){";
outFile<<"t//t]"<<endl;
}
void whileClose()
{
outFile<<"}";
outFile<<"t//t["<<endl;
}
void main() {
setlocale (LC_ALL,"RUS");
bool komment = 0;
outFile.open("out.cpp");
inFile.open("in.bf");
outFile<<"#include <iostream>"<<endl;
outFile<<"int main(){"<<endl;
outFile<<"char mas[256]={0}; int i=0;"<<endl;
char inputChar;
int dec=0;
int inc =0;
while (inFile>>inputChar)
{
if (inc && inputChar!='+') {op(inc,'+');inc=0;}
if (dec && inputChar!='-') {op(dec,'-');dec=0;}
switch (inputChar)
{
case '+': inc++; if(komment) {outFile<<"*/"<<endl; komment =0;}
break;
case '-': dec++;if(komment) {outFile<<"*/"<<endl; komment =0;}
break;
case ',': if(komment) {outFile<<"*/"<<endl; komment =0;}scan();
break;
case '.': if(komment) {outFile<<"*/"<<endl; komment =0;}print();
break;
case '[': if(komment) {outFile<<"*/"<<endl; komment =0;}whileOpen();
break;
case ']': if(komment) {outFile<<"*/"<<endl; komment =0;}whileClose();
break;
case '<': if(komment) {outFile<<"*/"<<endl; komment =0;}prev();
break;
case '>': if(komment) {outFile<<"*/"<<endl; komment =0;} next();
break;
default: if(!komment) {outFile<<"/*"<<endl; komment =1;}
outFile<<inputChar;
}
}
if(komment) {outFile<<"*/"<<endl; komment =0;}
outFile<<"return 0;}"<<endl;
return;
}
Внимательный читатель заметит кучу плохо смотрящегося кода в котором фигурирует переменная komment.
Это я на скорою руку пытался прикрутить перенос комментариев из исходного кода в результирующий. И на первый взгляд даже получилось.
Hello World+++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++.+++++++++++++++++
++++++++++++.+++++++..+++.-------------------
---------------------------------------------
---------------.komment+++++++++++++++++++++++++++++
++++++++++++++++++++++++++.++++++++++++++++++
++++++.+++.------.--------.------------------
---------------------------------------------
----.-----------------------.
#include <iostream>
int main(){
char mas[256]={0}; int i=0;
/*
HelloWorld*/
mas[i]+=72; //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
std::cout<<mas[i]; // .
mas[i]+=29; //+++++++++++++++++++++++++++++
std::cout<<mas[i]; // .
mas[i]+=7; //+++++++
std::cout<<mas[i]; // .
std::cout<<mas[i]; // .
mas[i]+=3; //+++
std::cout<<mas[i]; // .
mas[i]-=79; //-------------------------------------------------------------------------------
std::cout<<mas[i]; // .
/*
komment*/
mas[i]+=55; //+++++++++++++++++++++++++++++++++++++++++++++++++++++++
std::cout<<mas[i]; // .
mas[i]+=24; //++++++++++++++++++++++++
std::cout<<mas[i]; // .
mas[i]+=3; //+++
std::cout<<mas[i]; // .
mas[i]-=6; //------
std::cout<<mas[i]; // .
mas[i]-=8; //--------
std::cout<<mas[i]; // .
mas[i]-=67; //-------------------------------------------------------------------
std::cout<<mas[i]; // .
mas[i]-=23; //-----------------------
std::cout<<mas[i]; // .
return 0;}
На этом я завершу статью. И если после её прочтения хоть кто-то вобьет в поисковой строке слово brainfuck, то она была написана не зря.
Автор: WYCOR
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/brainfuck/27779
Ссылки в тексте:
[1] мозга: http://www.braintools.ru
[2] Источник: http://habrahabr.ru/post/170335/
Нажмите здесь для печати.