Brainfuck, 1993 թվականին Ուրբան Մյուլերի (գերմ.՝ Urban Müller) կողմից ստեղծված ամենահայտնի էզոտերիկ ծրագրաբորման լեզուներից մեկը, որը հայտնի է իր մինիմալիզմով: Լեզվի անվանումը հայերեն կարելի է թարգմանել՝ որպես ուղեղի բռնաբարում, ինչը ուղղակիորեն ծագել է անգլերեն brainfuck (brain՝ ուղեղ, fuck՝ սեռական հարաբերություն ունենալ) արտահայտությունից, այսինքն՝ անհեթեթությամբ զբաղվել: Լեզուն ունի ութ հրաման, որոնցից յուրաքանչյուրը գրառվում է մեկ սիմվոլով: Brainfuck-ի ելքային կոդը իրենից ներկայացնում է այդ սիմվոլների հերթականությունը՝ առանց որևէ լրացուցիչ շարահյուսության։

Ուրբան Մյուլերի հիմնական դրդապատճառներից մեկը եղել է հնարավորինս փոքր կոմպիլյատորով ծրագրավորման լեզվի ստեղծումը։ Մասամբ նա ոգեշնչված է եղել FALSE ծրագրավորման լեզվով, որի համար գոյություն ուներ 1024 բայթ չափսով կոմպիլյատոր։ Brainfuck-ի համար գոյություն ունեն 200 բայթից ավելի քիչ չափսով կոմպիլյատորներ[1]։ Brainfuck լեզվով դժվար է ծրագրեր գրել, ինչի համար երբեմն այն անվանում են մազոխիստների լեզու։ Միևնույն ժամանակ պետք է նշել, որ Brainfuck-ը բոլորովին բնական, լիակատար ու հասարակ լեզու է և կարող է օգտագործվել հաշվարկվածության հասկացության սահնանման համար։

Մեքենան, որը կառավարում են Brainfuck-ի հրամանները, բաղկացած է Թյուրինգի մեքենայի ժապավենն ու գլխիկը հիշեցնող բջիջների կարգավորված հավաքածույից և տվյալ բջջի ցուցիչից: Բացի այդ, ենթադրվում է ներմուծման և արտածման հոսքերի միջոցով արտաքին աշխարհի հետ շփման սարք:

Brainfuck լեզուն կարելի է նկարագրել C լեզվի համարժեքների միջոցով՝

Brainfuck-ի հրաման C-ի համարժեք Հրամանի նկարագրում
Ծրագրի սկիզբ int i = 0;
char arr[30000];
memset(arr, 0, sizeof(arr));
выделяется память под 30 000 ячеек с нулевыми начальными значениями
> i++; անցնել հաջորդ բջջին
< i--; անցնել նախորդ բջջին
+ arr[i]++; տվյալ բջջի արժեքը ավելացնել մեկով
- arr[i]--; տվյալ բջջի արժեքը նվազեցնել մեկով
. putchar(arr[i]); տպել տվյալ բջջի արժեքը
, arr[i] = getchar(); ввести извне значение и сохранить в текущей ячейке
[ while(arr[i]){ если значение текущей ячейки ноль, перейти вперёд по тексту программы на ячейку, следующую за соответствующей ] (с учётом вложенности)
] } если значение текущей ячейки не нуль, перейти назад по тексту программы на символ [ (с учётом вложенности)

Չնայած արտաքին պարզությանը՝ բջիջների անսահման թվով Brainfuck-ը ունի Թյուրինգի լիություն, հետևաբար՝ Несмотря на внешнюю примитивность, Brainfuck с бесконечным набором ячеек имеет тьюринговскую полноту, а, следовательно, по потенциальным возможностям не уступает «настоящим» языкам, подобным Си, Паскалю или Java.

Brainfuck подходит для экспериментов по генетическому программированию из-за простоты синтаксиса, и, соответственно, генерации исходного кода.

В «классическом» Brainfuck, описанном Мюллером, размер ячейки — один байт, количество ячеек 30 000. В начальном состоянии указатель находится в крайней левой позиции, а все ячейки заполнены нулями. Увеличение/уменьшение значений ячеек происходит по модулю 256. Ввод-вывод также происходит побайтно, с учётом кодировки ASCII (то есть в результате операции ввода (,) символ 1 будет записан в текущую ячейку как число 0x31 (49), а операция вывода (.), совершённая над ячейкой, содержащей 0x41 (65), напечатает латинскую А). В других вариантах языка размер и количество ячеек может быть другим (бо́льшим). Есть версии, где значение ячеек не целочисленно (с плавающей точкой).

Ծրագրի օրինակ

խմբագրել
Brainfuck֊ով գրված ծրագիր, որն արտածում է «Hello World!»՝
 ++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
 .>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
 ------.--------.>+.>.

Разбор программы:

Подготовка в памяти (с ячейки 1) массива значений, близких к ASCII-кодам символов, которые необходимо вывести (70, 100, 30, 10), через повторение 10 раз приращения ячеек на 7, 10, 3 и 1, соответственно
++++++++++ присваивание ячейке 0 (счетчику) значения 10
[ повторять, пока значение текущей ячейки (ячейки 0) больше нуля
>+++++++ приращение ячейки 1 на 7
>++++++++++ приращение ячейки 2 на 10
>+++ приращение ячейки 3 на 3
>+ приращение ячейки 4 на 1
<<<<- возврат к ячейке 0 (счетчику), и его уменьшение на 1
] вернуться к началу цикла
Տառերի կոդերի ստացում և դրանց արտածում
>++. Вывод «Н». Получение кода «H» (72) из 70 в ячейке 1 и вывод
>+. Вывод «e». Получение кода «e» (101) из 100 в ячейке 2 и вывод
+++++++.. Вывод «ll». Получение кода «l» (108) из 101 в ячейке 2 и вывод дважды
+++. Вывод «o». Получение кода «o» (111) из 108 в ячейке 2 и вывод
>++. Вывод пробела. Получение кода пробела (32) из 30 в ячейке 3 и вывод
<<+++++++++++++++. Вывод «W». Получение кода «W» (87) из 72 в ячейке 1 и вывод
>. Вывод «o». Код «o» (111) уже находится в ячейке 2, просто его выводим
+++. Вывод «r». Получение кода «r» (114) из 111 в ячейке 2 и вывод
------. Вывод «l». Получение кода «l» (108) из 114 в ячейке 2 и вывод
--------. Вывод «d». Получение кода «d» (100) из 108 в ячейке 2 и вывод
>+. Вывод «!». Получение кода «!» (33) из 32 в ячейке 3 и вывод
>. Вывод кода перевода строки (10) из ячейки 4

В принципе, печать «Hello World!» можно реализовать проще, но программа будет в три с лишним раза больше, чем приведённый выше оптимизированный вариант:

 +++++++++++++++++++++++++++++++++++++++++++++
 +++++++++++++++++++++++++++.+++++++++++++++++
 ++++++++++++.+++++++..+++.-------------------
 ---------------------------------------------
 ---------------.+++++++++++++++++++++++++++++
 ++++++++++++++++++++++++++.++++++++++++++++++
 ++++++.+++.------.--------.------------------
 ---------------------------------------------
 ----.-----------------------.

Brainfuck֊ի ինտերպրետատոր

խմբագրել

Пример интерпретатора Brainfuck, написанный на языке Perl

#!/usr/bin/perl
open F, shift;
@code = grep {/[+-\.,\[\]><]/} split '', <F>;
for (my $_ = 0; $_ < @code; ++$_) {
  ++$cpu[$i] if $code[$_] eq '+';
  --$cpu[$i] if $code[$_] eq '-';
  --$i if $code[$_] eq '<';
  ++$i if $code[$_] eq '>';
  print chr $cpu[$i] if $code[$_] eq '.';
  $cpu[$i] = ord <STDIN> if $code[$_] eq ',';
  if ($code[$_] eq '[') {
    if (!$cpu[$i]) {
      ++$brc;
      while ($brc) {
        ++$_;
        ++$brc if $code[$_] eq '[';
        --$brc if $code[$_] eq ']';
      }
    } else {
      next;
    }
  } elsif ($code[$_] eq ']') {
    if (!$cpu[$i]) {
      next;
    } else {
      ++$brc if $code[$_] eq ']';
      while ($brc) {
        --$_;
        --$brc if $code[$_] eq '[';
        ++$brc if $code[$_] eq ']';
      }
    --$_;
    }
  }
}

Пример интерпретатора Brainfuck, написанный на языке C++

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

static char cpu[30000];

int main(int argc, char **argv) {
    vector<char> acc;
    char ch;
    ifstream infile(argv[1]);
    while (infile) {
        infile.get(ch);
        acc.push_back(ch);
    }
    infile.close();
    unsigned int j = 0;
    int brc = 0;
    for (int i = 0; i < acc.size(); ++i) {
        if (acc[i] == '>')
            j++;
        if (acc[i] == '<')
            j--;
        if (acc[i] == '+')
            cpu[j]++;
        if (acc[i] == '-')
            cpu[j]--;
        if (acc[i] == '.')
            cout << cpu[j];
        if (acc[i] == ',')
            cin >> cpu[j];
        if (acc[i] == '[') {
            if (!cpu[j]) {
                ++brc;
                while (brc) {
                    ++i;
                    if (acc[i] == '[')
                        ++brc;
                    if (acc[i] == ']')
                        --brc;
                }
            } else
                continue;
        } else if (acc[i] == ']') {
            if (!cpu[j])
                continue;
            else {
                if (acc[i] == ']')
                    brc++;
                while (brc) {
                    --i;
                    if (acc[i] == '[')
                        brc--;
                    if (acc[i] == ']')
                        brc++;
                }
                --i;
            }
        }
    }
}

Программирование на языке Brainfuck

խմբագրել

Каждый начинающий программировать на Brainfuck немедленно сталкивается со следующими проблемами:

Эти проблемы могут быть решены.

 Обозначим через @(k) сдвиг на k ячеек вправо, если k>0, и влево, если k<0
 Соответственно, @(k) = >…k раз…> либо <…-k раз…<  
zero(): обнуление текущей ячейки: [-] = [+]
add(k): прибавление значения ячейки n (текущей) к значению ячейки n+k: [ — @(k) + @(-k) ] при этом значение ячейки n теряется (обнуляется).
mov(k): копирование значения ячейки n (текущей) в ячейку n+k с потерей (обнулением) значения ячейки n: @(k) zero() @(-k) add(k) = @(k) [-] @(-k) [ — @(k) + @(-k) ]
copy(k,t): копирование значения ячейки n (текущей) в ячейку n+k c использованием промежуточной ячейки n+k+t, благодаря чему значение ячейки n не теряется (сохраняется). @(k) zero() @(t) zero() @(-k-t) [ — @(k) + @(t) + @(-k-t) ] @(k+t) mov(-k-t) = @(k) [-] @(t) [-] @(-k-t) [ — @(k) + @(t) + @(-k-t) ] @(k+t) [ — @(-k-t) + @(k+t) ]
ifelse(t): если текущая ячейка>0, то выполняется условие true если текущая ячейка=0, то выполняется условие false t-относительный номер вспомогательной ячейки: @(t)[-]+@(-t) устанавливаем флаг 1 для случая else [ здесь действия ветки true @(t)[-]@(-t) устанавливаем флаг 0 для случая else [-] выход из цикла ] @(t) [@(-t) здесь действия ветки false @(t)[-] выход из цикла ] @(-t-1)

Brainfuck почти не используется для практического программирования (за исключением работ отдельных энтузиастов), а используется преимущественно для головоломок и задач для соревнований.

Brainfuck֊ի հիման վրա ստեղծված լեզուներ

խմբագրել
Կաղապար:Highlight1 |Ook! Կաղապար:Highlight1 |COW Կաղապար:Highlight1 |Brainfuck Կաղապար:Highlight1 |Описание
Ook. Ook. MoO + Значение текущей ячейки увеличивает на 1
Ook! Ook! MOo - Значение текущей ячейки уменьшают на 1
Ook. Ook? moO > Следующая ячейка
Ook? Ook. mOo < Предыдущая ячейка
Ook! Ook? moo [ Начало цикла
Ook? Ook! MOO ] Конец цикла
Ook! Ook. OOM . Вывод значения текущей ячейки
Ook. Ook! oom , Запрос значения текущей ячейки
mOO отсутствует Выполняет инструкцию с номером, который берётся из текущей ячейки (если значение в текущей ячейке равно 3, то это приводит к бесконечному циклу).
Moo отсутствует Если значение текущей ячейки равно нулю, то ввести его с клавиатуры; если же значение текущей ячейки — не ноль, то вывести его на экран.
OOO [-] Обнуляет значение в текущей ячейке
MMM отсутствует

Տես նաև

խմբագրել

Диалекты и реализации

խմբագրել

Ещё описание множества диалектов этого языка можно найти в вики-энциклопедии эзотерических языков[2]

Ծանոթաագրություններ

խմբագրել
  1. Например, «исходник компилятора размером 166 байт». Արխիվացված է օրիգինալից 2011-08-25-ին. Վերցված է 2010-08-18-ին. {{cite web}}: Unknown parameter |deadurl= ignored (|url-status= suggested) (օգնություն)
  2. Category:Brainfuck_derivatives, esolangs.org

Արտաքին հղումներ

խմբագրել