Brainfuck (někdy je také eufemisticky nazýván Brainf*ck nebo dokonce Brainf***) je extrémně minimalistický ezoterický programovací jazyk. Byl vytvořen pro pobavení a jako výzva programátorům, pro praktické účely není vhodný.
Jazyk Brainfuck vymyslel v roce 1993 švýcarský programátor Urban Müller. Překladač pro počítače Amiga s OS 2.0 má velikost pouhých 240 bajtů, některé další překladače jsou dokonce menší než 200 bajtů. Klasická Müllerova distribuce verze 2 obsahuje překladač pro počítače Amiga, interpret jazyka, zdrojové kódy ukázkových programů a soubor README se základními informacemi o této distribuci.
Jazyk obsahuje pouze osm příkazů (viz seznam dále). Interpretace příkazů se v Brainfucku provádí sekvenčně, všechny neznámé znaky jsou ignorovány – zdrojový kód lze tedy opatřit komentářem v libovolném místě (komentář pouze nesmí obsahovat klíčové znaky).
Provádění kódu si lze představit jako operace nad polem buněk o velikosti jednoho bajtu. Standardně se používá pole o velikosti 30 000 buněk. Hodnoty buněk jsou před spuštěním programu nastaveny na 0. Každá buňka může obsahovat hodnoty v intervalu 8 bitů (tedy 0-255). Nad těmito buňkami se „pohybuje“ ukazatel, který označuje aktuální buňku, se kterou jsou prováděny operace. Tento ukazatel je při spuštění programu nastaven nad první buňku a lze ho posouvat doleva či doprava.
Příkaz | Popis | Ekvivalent v C[1] | Ekvivalent v Delphi[2] |
---|---|---|---|
>
|
posun datového ukazatele o jednu buňku doprava | ++ptr;
|
Inc(Ptr);
|
<
|
posun datového ukazatele o jednu buňku doleva | --ptr;
|
Dec(Ptr);
|
+
|
zvýšení hodnoty aktivní buňky o 1 (buňky, nad kterou je ukazatel) | ++*ptr;
|
Inc(Ptr^);
|
-
|
snížení hodnoty aktivní buňky o 1 | --*ptr
|
Dec(Ptr^);
|
.
|
výpis hodnoty aktivní buňky na standardní výstup (v drtivé většině případů na obrazovku). Pro výpis se používá hodnota aktivní buňky převedená dle kódování ASCII na znak. |
putchar(*ptr);
|
Write(Char(Ptr^));
|
,
|
uložení hodnoty ze vstupu do aktivní buňky | *ptr=getchar();
|
Read(Char(Ptr^));
|
[
|
pokud je hodnota aktivní buňky rovna nule, provede přesun instrukčního ukazatele doprava za odpovídající ]
|
while (*ptr) {
|
while Ptr^ <> 0 do begin
|
]
|
pokud je hodnota aktivní buňky různá od nuly, provede přesun instrukčního ukazatele doleva na odpovídající [
|
}
|
end;
|
Za formálního předchůdce Brainfucku lze považovat jazyk vytvořený Corradem Böhmem v roce 1964. Brainfuck je, kromě dvou vstupních a výstupních (I/O) příkazů, menší obměnou tohoto jazyka.
Ve všech následujících příkladech jsou ve vysvětlení buňky označovány jako b[Index], kde Index je pořadí buňky. První buňka má index 0.
Jako při popisu každého jazyka, i zde se začíná typickou ukázkou – následující program vypíše Hello World! a skončí.
++++++++++[>+++++++>++++++++++>+++>+<<<< -]>++.>+.+++++++..+++.>++.<<++++++++++++ +++.>.+++.------.--------.>+.>.
Protože Brainfuck interpretuje pouze klíčové znaky, je v tomto příkladu komentář vložen přímo do zdrojového kódu a pro snadnější orientaci jsou očíslovány řádky.
1 ++++++++++ 2 [ 3 >+++++++ 4 >++++++++++ 5 >+++ 6 >+ 7 <<<<- 8 ] inicializační cyklus nastaví potřebné hodnoty buněk 9 >++. výpis 'H' 10 >+. výpis 'e' 11 +++++++. 'l' 12 . 'l' 13 +++. 'o' 14 >++. mezera 15 <<+++++++++++++++. 'W' 16 >. 'o' 17 +++. 'r' 18 ------. 'l' 19 --------. 'd' 20 >+. '!' 21 >. nová řádka
[-]
Tento fragment programu nastaví aktivní obsah buňky na 0 – hodnota buňky je v každém kroku cyklu snižována o jednu dokud není 0. Pak se cyklus ukončí.
,[.,]
Tento program dokola vypisuje na obrazovku vstup z klávesnice. V prvním příkazu je do b[0] načtena hodnota na vstupu. V následujícím cyklu je tato hodnota vypsána na obrazovku a znovu je načtena hodnota na vstupu. Tento cyklus je v podstatě nekonečný, protože z klávesnice nelze vložit znak s ASCII hodnotou 0. Jednoduchou modifikací lze zaručit, že program bude ukončen, když je z klávesnice vložena mezera:
+[,.--------------------------------]
V prvním kroku je hodnota b[0] nastavena na 1 pouze z důvodu, aby se následující cyklus ihned neukončil. V cyklu je pak do b[0] uložen vstup z klávesnice a následně je hodnota b[0] vypsána na obrazovku. Po výpisu je hodnota b[0] snížena o 32. Cyklus skončí, pokud je b[0] - 32 = 0
- na vstupu byla mezera, která ma ASCII hodnotu 32. (Program není ošetřen pro vstup menší než 32 - například pro tabulátor s ACSII hodnotou 9.)
[->+<]
V cyklu je snižována hodnota aktivní buňky o 1 a o 1 je zvyšována hodnota následující buňky - po ukončení cyklu (když hodnota aktivní buňky klesne na 0) je v následující buňce hodnota stejná jako byla před započetím cyklu v aktivní buňce. Tento cyklus nefunguje když je hodnota aktivní buňky rovna 0.
[->+>+<<]
Hodnota v aktivní buňce b[0] je pomocí cyklu zkopírována do buněk b[1] a b[2]. Hodnota v b[0] je po skončení cyklu nastavena na 0. Kopírovat hodnotu z buňky do buňky lze také beze ztráty hodnoty v původní buňce:
[->+>+<<]>>[-<<+>>]
V tomto příkladu je buňka b[2] použita pouze pro dočasné uložení hodnoty. Cyklus probíhá jako v předcházejícím příkladu a po jeho skončení je hodnota z b[2] opět cyklem vrácena do b[0].
,>++++++[<-------->-],[<+>-],<.>.
Tento program sečte číslice na vstupu a vypíše jejich součet pokud je výsledek jednociferný. V případě dvouciferného výsledku vypisuje znak, který má ASCII hodnotu výsledku.
Protože je jazyk Brainfuck jednoduchý, bylo vytvořeno několik dalších programovacích jazyků založených právě na něm.
Doublefuck je modifikací Brainfucku, který pracuje na dvou páskách. Kromě běžných příkazů Brainfucku zde existuje i druhá sada příkazů pro práci s druhou páskou a je možnost využít i ukazatele. Pro tento jazyk byla přijata zkratka DBF.
DBF pracuje se dvěma poli, z nichž každé disponuje svým ukazatelem. Oba ukazatelé jsou po spuštění programu nastaveny na prvním buňku ve svém poli. Hlavní příkazy jazyka jsou:
Příkaz | Popis příkazu | |
---|---|---|
Příkazy z Brainfucku | ||
>
|
Posun prvního datového ukazatele o jednu buňku doprava | |
<
|
Posun prvního datového ukazatele o jednu buňku doleva | |
+
|
Zvýšení hodnoty prvního pole, konkrétně aktivní buňky o 1 (buňky, nad kterou je první ukazatel) | |
-
|
Snížení hodnoty prvního pole, konkrétně aktivní buňky o 1 (buňky, nad kterou je první ukazatel) | |
.
|
Výpis hodnoty aktivní buňky (buňky, nad kterou je první ukazatel) na standardní výstup (v drtivé většině případů na obrazovku). | |
,
|
Uložení hodnoty ze vstupu do aktivní buňky (buňky, nad kterou je první ukazatel) | |
[
|
Skok za shodu – Pokud je hodnota aktivní buňky (buňky, nad kterou je první ukazatel) rovna nule, provede přesun instrukčního ukazatele doprava za odpovídající ] | |
]
|
Skok před shodu – Pokud je hodnota aktivní buňky (buňky, nad kterou je první ukazatel) různá od nuly, provede přesun instrukčního ukazatele doleva na odpovídající [ | |
Příkazy pro práci s druhou páskou | ||
v
|
Posun druhého datového ukazatele o jednu buňku doprava | |
^
|
Posun druhého datového ukazatele o jednu buňku doleva | |
/
|
Zvýšení hodnoty druhého pole, konkrétně aktivní buňky o 1 (buňky, nad kterou je druhý ukazatel) | |
\
|
Snížení hodnoty druhého pole, konkrétně aktivní buňky o 1 (buňky, nad kterou je druhý ukazatel) | |
:
|
Výpis hodnoty aktivní buňky (buňky, nad kterou je druhý ukazatel) na standardní výstup (v drtivé většině případů na obrazovku). | |
;
|
Uložení hodnoty ze vstupu do aktivní buňky (nad kterou je druhý ukazatel) | |
{
|
Skok za shodu – Pokud je hodnota aktivní buňky (buňky, nad kterou je druhý ukazatel) rovna nule, provede přesun instrukčního ukazatele doprava za odpovídající } | |
}
|
Skok před shodu – Pokud je hodnota aktivní buňky (buňky, nad kterou je druhý ukazatel) různá od nuly, provede přesun instrukčního ukazatele doleva na odpovídající { |
Hello world v jazyce Doublefuck:
v++++++++++[-///////v//////////v////v///v////////^^^]//:v/:///////::///:v////:v//: v///////:>+++.+++.------.--------.^/:
Na prvním řádku je vypsáno „Hello,
“, na druhém řádku je vypsáno „World!
“.
ptr
je deklarována jako unsigned char*
.
ptr
je deklarována jako typ ukazatel na Byte (^Byte
) a aplikace je překládána jako konzolová (pro funkce Write
a Read
).