Programovací jazyky z vývojářského pekla

28. 4. 2016
Doba čtení: 14 minut

Sdílet

Oblíbenou kratochvílí mnoha vývojářů jsou nekonečné debaty o tom, který jazyk je nejlepší či nejčitelnější. Co to ale obrátit? V jakých jazycích se vytváří nejhůře čitelný kód?

Obsah

1. Programovací jazyky z vývojářského pekla

2. FALSE

3. Brainfuck

4. Minifuck

5. Minifuck-2D

6. XMLfuck aneb příprava na invazi do enterprise světa

7. Befunge

8. Další šílené jazyky: Unlambda, Malbolge a Piet

9. Perlička na závěr pro všechny javascriptaře: JSFuck

10. Odkazy na Internetu

1. Programovací jazyky z vývojářského pekla

Kromě programovacích jazyků, které byly navrženy takovým způsobem, aby je bylo možné použít pro seriózní práci či pro výuku programování, dnes existuje již minimálně několik set programovacích jazyků, které jsou nějakým způsobem „šílené“. Jedná se například o jazyky, které obsahují jen naprosto minimální počet příkazů, k zápisu algoritmů se používají jednoznakové příkazy či dokonce jen takzvané bílé znaky, jazyky, kde je algoritmy nutné číst ve všech čtyřech směrech či naopak o jazyky založené čistě na principu Turingova stroje či Lambda kalkulu. Důvody vzniku podobných jazyků jsou různé – může se jednat o vtip, hračku, na které programátor pracuje, aby se odreagoval, výsledek snahy o vytvoření co nejkratšího překladače či interpretru či dokonce o výsledek nějakého seriózního výzkumu (takovými jazyky se ovšem dnes zabývat nebudeme).

Na Rootu jsme se již mohli seznámit s jedním z prvních esoterických programovacích jazyků. Jedná se o INTERCAL, který je známý především tím, že zcela odstranil příkaz GOTO (ten je přece špatný, ano?) a nahradil ho mnohem lepším příkazem COME FROM. Taktéž překladač tohoto jazyka je většinou implementován tak, aby programátora trošku napínal, protože přibližně každý desátý překlad skončí s chybou. Bližší informace o tomto projektu naleznete v již zmíněném článku http://www.root.cz/clanky/intercal-dostatecne-sileny-programovaci-jazyk/. My si ovšem stručně popíšeme jiné jazyky, především pak rodiny jazyků založených na Turingově stroji (Brainfuck), zásobníkovém automatu (FALSE), zápisu kódu do bitmap (Piet) či jazyku JSFuck, který do důsledků používá některé méně známé vlastnosti JavaScriptu.

2. FALSE

Autorem programovacího jazyka FALSE je Wouter van Oortmerssen, jehož jméno si pravděpodobně někteří čtenáři pamatují, protože stejný člověk vytvořil například ve své době velmi populární vyšší programovací jazyk nazvaný Amiga E. Kromě těchto dvou jazyků vytvořil Wouter van Oortmerssen i další jazyky, například Bla, Aardappel a SHEEP. Vraťme se však k jazyku FALSE. Ten vznikl pro Amigu a zajímavé je, že překladač tohoto jazyka měl velikost pouhých 1024 bajtů (ne kilobajtů). FALSE je založen na zásobníkovém virtuálním stroji, takže se výsledný program tvoří podobným způsobem, jako program v jazyce Forth, i když samotné příkazy (ve Forthu slova) jsou v případě FALSE zapisovány jediným znakem – každý znak je celým příkazem, podobně jako v případě dále zmíněného Brainfucku (i to je ostatně jeden z důvodů jednoduchosti interpretrů a překladačů těchto esoterických jazyků).

Pokud se ve zdrojovém programu vyskytuje číslo, je toto číslo uloženo na zásobník, opět podobně jako ve Forthu. Posléze lze s hodnotami uloženými na vrcholu zásobníku (popř. těsně pod jeho vrcholem) provádět mnoho operací – aritmetických, logických, atd. S obsahem zásobníku lze různým způsobem manipulovat, například je možné duplikovat hodnotu uloženou na jeho vrcholu atd. Programovací jazyk FALSE taktéž obsahuje podporu pro proměnné, které jsou pro jednoduchost pojmenovány ‚a‘ až ‚z‘. Zajímavá je podpora podprogramů (subrutin), které jsou tvořeny kódem umístěným mezi znaky [ a ]. Pro vyvolání subrutiny (uložené na vrcholu zásobníku) se používá příkaz ! (vykřičník). V následující tabulce jsou pro ilustraci vypsány některé příkazy jazyka FALSE a korespondující příkazy Forthu:

# FALSE Forth
1 $ dup
2 % pop
3 \ swap
4 @ rot
5 _ neg
6 + +
7 : ! (store, uložení hodnoty do proměnné)
8 ; @ (fetch, načtení hodnoty z proměnné)

Pro ilustraci zápisu „reálných“ programů se podívejme na zápis algoritmu pro výpočet prvočísel ležících v rozsahu od 0 do 100 (příklad je převzat přímo ze stránky autora tohoto jazyka):

99 9[1-$][\$@$@$@$@\/*=[1-$$[%\1-$@]?0=[\$.' ,\]?]?]#

Poznámka: tento jazyk je turingovsky úplný.

3. Brainfuck

Výše zmíněným jazykem FALSE se inspirovali i autoři dalších šílených programovacích jazyků (zejména těch, kteří taktéž vlastnili Amigu). Jedním z těchto autorů byl i Urban Müller. Toto jméno stojí za zapamatování, protože Urban v roce 1993 vytvořil slavný a velmi často zmiňovaný programovací jazyk Brainfuck. V tomto programovacím jazyku se pro zápis algoritmů používá pouze šest základních příkazů (podobných příkazům použitým u Turingova stroje), které jsou doplněny o dva příkazy pro vstup a výstup jednoho bajtu/ASCII znaku, přičemž každý příkaz byl reprezentován pouze jediným znakem. Pro počítače Amiga, který se stal „semeništěm“ mnoha podobných projektů, existovalo několik interpretrů a dokonce i překladače jazyka Brainfuck, přičemž některé implementace měly binární spustitelný soubor menší než pouhých 200 bajtů!

Programy zapisované v Brainfucku nemají pevně danou strukturu a mohou obsahovat prakticky všechny další znaky (včetně mezer a konců řádků), které jsou při interpretaci či kompilaci ignorovány. Rozeznává se pouze osm znaků vypsaných v následující tabulce. Tyto znaky slouží pro posun ukazatele po pásce rozdělené do políček, přičemž na každém políčku je uložena celočíselná hodnota. Páska je většinou reprezentována polem, jehož maximální velikost bývá omezena na 32000 buněk a celočíselné hodnoty ukládané do jednotlivých buněk mohou mít hodnotu v rozsahu 0..255 (některé implementace však mají velikost pásky/pole prakticky neomezenou):

# Příkaz Význam
1 > posun ukazatele na „pásce“ doprava na další políčko
2 < posun ukazatele na „pásce“ doleva na předchozí políčko
3 + zvýšení celočíselné hodnoty uložené v aktuálním políčku o 1
4 snížení celočíselné hodnoty uložené v aktuálním políčku o 1
5 . výpis číselné hodnoty (převedené na ASCII znak) uložené v aktuálním políčku
6 , načtení bajtu (znaku) a uložení jeho číselné hodnoty do aktuálního políčka (opět se většinou předpokládá použití ASCII)
7 [ v případě, že je hodnota v aktuálním políčku nulová, přesune se program za odpovídající ]
8 ] v případě, že je hodnota v aktuálním políčku nenulová, přesune se program na odpovídající [

Typickým demonstračním programem je „Hello world“, který v podání Brainfucku vypadá následovně:

++++++++++[>+>+++>++++>+++++++>++++++++>+++++++++>++
++++++++>+++++++++++>++++++++++++<<<<<<<<<-]>>>>+.>>>
>+..<.<++++++++.>>>+.<<+.<<<<++++.<++.>>>+++++++.>>>.+++.
<+++++++.--------.<<<<<+.<+++.---.

Dalším podobně nečitelným programem je program pro výpočet faktoriálu:

>++++++++++>>>+>+[>>>+[-[<<<<<[+<<<<<]>>[[-]>[<<+>+>-]<[>+<-]<[>+<-[>+<-[>
+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>[-]>>>>+>+<<<<<<-[>+<-]]]]]]]]]]]>[<+>-
]+>>>>>]<<<<<[<<<<<]>>>>>>>[>>>>>]++[-<<<<<]>>>>>>-]+>>>>>]<[>++<-]<<<<[<[
>+<-]<<<<]>>[->[-]++++++[<++++++++>-]>>>>]<<<<<[<[>+>+<<-]>.<<<<<]>.>>>>]

Poznámka: tento jazyk je turingovsky úplný za předpokladu, že páska/pole není omezeno.

4. Minifuck

Jazyk Brainfuck je poměrně populární, velmi pravděpodobně i z toho důvodu, že napsat pro něj interpret je značně jednoduché, protože celá interpretace spočívá ve zvyšování či snižování obsahu prvku pole, posunu indexu v poli, popř. v hledání odpovídající párové závorky. Není tedy divu, že vzniklo několik desítek různých dialektů tohoto jazyka. Někteří autoři se zaměřili na další zmenšení instrukčního souboru. Velmi dobrým příkladem tohoto přístupu může být jazyk nazvaný Minifuck, který obsahuje pouhé tři instrukce. Navíc se původní koncept pole (či pásky) obsahující celočíselné hodnoty taktéž zjednodušil, protože Minifuck pracuje s polem/páskou obsahující pouze binární hodnoty 0 či 1. To samozřejmě znamená, že programování v takovémto jazyce je mnohem komplikovanější, protože i tak základní operace, jakou je součet, nyní musí být explicitně naprogramovaná.

Podívejme se nyní, které operace jsou v Minifucku implementovány:

# Příkaz Význam
1 < posun ukazatele na „pásce“ doleva na předchozí políčko
2 . posun na další políčko s jeho inverzí. Současně se vypíše znak zapsaný v dalších osmi políčcích
3 [ posun na další políčko s jeho inverzí, pokud je bit nulový, další instrukce se přeskočí a invertuje se následující bit

Jak je z tabulky patrné, je sice příkazů skutečně méně, ovšem je nutné, aby každý příkaz prováděl větší množství operací. Kromě prvního příkazu < obsahují další dva příkazy podmínku, která vlastně nahrazuje funkci [ a ] z Brainfucku.

Poznámka: tento jazyk je pravděpodobně turingovsky úplný (za předpokladu zprava nekonečné pásky), ovšem důkaz pravděpodobně ještě nebyl vytvořen.

5. Minifuck-2D

Minifucku a částečně i z jazyka Minimal-2D byl odvozen další esoterický (a již skutečně dosti šílený) programovací jazyk nazvaný příznačně Minifuck-2D. Tento jazyk je zvláštní tím, že se programový kód nečte sekvenčně zleva doprava a po jednotlivých řádcích, ale interpret se musí pohybovat po 2D šachovnici obsahující jednoznakové příkazy. Samotný způsob tohoto pohybu trošku připomíná robota Karla, protože znak představující následující vykonávaný příkaz se může nacházet před, za, nad či pod aktuálně zpracovávaným znakem, a to v závislosti na aktuální orientaci. Stav programu je zapisován na pásku (do pole) obsahující binární hodnoty, což je stejný přístup, s jakým jsme se setkali už v případě Minifucku. Pro zajímavost se podívejme, jaké příkazy Minifuck-2D obsahuje. Jedná se o pouhé čtyři příkazy:

# Příkaz Význam
1 < posun ukazatele na „pásce“ dozadu
2 @ otočení doprava: změna orientace při čtení zdrojového kódu
3 . posun na další políčko s jeho inverzí. současně se vypíše znak zapsaný v dalších osmi políčcích
4 ! posun na další políčko s jeho inverzí, pokud je bit nulový, další instrukce se přeskočí

Příklad „programu“ – implementace nekonečné smyčky (schválně se zamyslete nad tím, proč prostě nestačí zapsat pouze čtyři znaky @ do čtverce):

!<!@@
   @@

Poznámka: tento jazyk je pravděpodobně turingovsky úplný.

6. XMLfuck aneb příprava na invazi do enterprise světa

V enterprise světě, ovšem nejenom tam, je pro přenos dat a někdy i pro serializaci programů populární používat značkovací jazyk XML. Aby bylo možné (samozřejmě zpočátku jen nenápadně) použít některý z dialektů programovacího jazyka Brainfuck i v takovém prostředí, byla vytvořena nová varianta tohoto jazyka, která je zapisována přímo v XML. Ovšem současně se samozřejmě jedná o plnohodnotnou serializaci původního zdrojového kódu. Otázkou zůstává, zda je možné interpretr napsat jen s použitím XML transformace.

Kořenový element vypadá takto (popravdě se jeho jméno do korporátního prostředí moc nehodí):

<fuck bits="" wrap="" signed=""></fuck>

Atributy obsahují specifikaci chování pásky/pole, na němž se uchovává stav programu. Většinou se používají osmibitové hodnoty s přetečením (wrap se nastavuje na „yes“) a se znaménkem (signed se nastavuje na „yes“)

Podobně je možné specifikovat parametry pásky, takže interpret nemusí hádat, jak má být páska dlouhá atd.:

<tape name="" type="" length="" start="" />

Šest původních příkazů má v XMLfucku přímý ekvivalent:

# Příkaz XMLFuck Význam
1 > <ptrinc> posun ukazatele na „pásce“ doprava na další políčko
2 < <ptrdec> posun ukazatele na „pásce“ doleva na předchozí políčko
3 + <inc> zvýšení celočíselné hodnoty uložené v aktuálním políčku o 1
4 <dec> snížení celočíselné hodnoty uložené v aktuálním políčku o 1
5 . <print> výpis číselné hodnoty (převedené na ASCII znak) uložené v aktuálním políčku
6 , <red> načtení bajtu (znaku) a uložení jeho číselné hodnoty do aktuálního políčka

Původní závorky [ a ] jsou nahrazeny uzavřením části kódu mezi značky <while> a </while>. Párovost zde není na škodu, protože i v původním Brainfucku musely být znaky [ a ] zpárovány.

Poznámka: ukázku přepisu zdrojového kódu pro výpočet faktoriálu zde nebudu uvádět, protože by tento kód byl delší než celý tento článek. Tady se jasně ukazuje, jak je původní Brainfuck úsporný :-

7. Befunge

Velmi zajímavým esoterickým jazykem, který se opět dočkal mnoha dalších dialektů, je jazyk nazvaný Befunge. Tento jazyk byl vytvořen (znovu!) v roce 1993 a jeho autorem je Chris Pressey. Befunge (tento název vznikl z typografické chyby) je považován za jeden z prvních „dvourozměrných“ programovacích jazyků. Jedinými datovými strukturami, s nimiž se zde pracuje, je zásobník a dvourozměrné pole, které na začátku programu obsahuje vlastní programový kód, kde opět každý znak odpovídá jednomu příkazu. Ovšem současně je možné obsah tohoto pole měnit samotným programem a tak v případě potřeby vytvářet samomodifikující se kód. Aby byl jazyk Befunge turingovsky úplný, muselo by být toto pole nekonečné (aspoň v jednom směru), ovšem klasické interpretry se většinou spolehnou na pole o velikosti 80×25 či 80×24 znaků. Tento rozměr samozřejmě není náhodný, protože přesně odpovídá rozměrům standardních textových režimů (programy psané v Befunge se totiž mohou ladit a krokovat).

Repertoár příkazů je v tomto programovacím jazyku dosti rozsáhlý, nejedná se tedy o minimalistický jazyk ve stylu FALSE či Brainfucku. Základem jsou příkazy pro změnu orientace čtení ve dvourozměrném poli. Tyto příkazy jsou zapisovány znaky připomínajícími šipky, tedy <, >, ^ a v. Aby toho nebylo málo, je možné použít i znak ?, kterým se směr změní náhodně. Nekonečnou smyčku lze naprogramovat takto:

>v
^<

Další příkazy pracují se zásobníkem (podobně jako ve Forthu): pomocí příkazů 0 až 9 se na zásobník uloží příslušná hodnota, příkazy +, -, *, / a % ze zásobníku získají dvě hodnoty, provedou naznačenou aritmetickou operaci a uloží výsledek zpět. Mezi další zásobníkové operace patří : (dup), \ (swap), $ (pop) doplněné o takzvané horizontální a vertikální „if“: změna orientace se provede jen ve chvíli, kdy je hodnota uložená na vrcholu zásobníku rovna nule.

Důležité jsou taktéž příkazy g (get) a p (put) sloužící pro vstup a výstup dat na obrazovku. V případě příkazu g (get) se ze zásobníku přečtou dvě hodnoty x a y, získá se ASCII hodnota znaku uloženého na souřadnicích [x,y] a tato hodnota se uloží na zásobník. Opakem je p (put), které ze zásobníku přečte tři hodnoty: x, y, ASCII kód a uloží daný kód na souřadnice [x,y].

8. Další šílené jazyky: Unlambda, Malbolge a Piet

Esoterických jazyků skutečně existuje nepřeberné množství, ovšem minimálně tři z nich si budou zasluhovat poněkud delší popis (a tím pádem pravděpodobně i samostatný článek). Jedná se o jazyky nazvané Unlambda, Malbolge a Piet. Každý z těchto jazyků je odlišný, protože Unlambda vznikl na základě obecného Lambda kalkulu, Malbolge (Melebolge je osmá úroveň pekla v Dantově Božské komedii) je navržen takovým způsobem, že většina programů pro něj vznikla procházením stavového prostoru a nikoli přímým naprogramováním a Piet je programovací jazyk, v němž se algoritmy nepíšou zápisem příkazů, ale vybarvováním bitmapy (barvy pixelů v bitmapě jsou dekódovány jako příkazy). Piet je v několika ohledech podobný již výše zmíněnému jazyku Befunge (založeno na 2D poli a zásobníku) a ještě před jeho podrobnějším popisem zkusím čtenáře nalákat na (integrované) vývojové prostředí, které pro tento jazyk vzniklo a je dostupné na stránce http://www.rapapaing.com/blog/?pa­ge_id=6.

9. Perlička na závěr pro všechny javascriptaře: JSFuck

Všechny doposud zmíněné programovací jazyky mají svoje vlastní interpretry a v některých případech i překladače. Jazyk (či spíše přesněji řečeno pseudojazyk) nazvaný JSFuck se nutnosti psaní vlastního interpretru elegantně vyhýbá, protože se vlastně jedná o podmnožinu dnes tak populárního programovacího jazyka JavaScript. Pokud však očekáváte, že se v JSFucku píšou programy běžným způsobem, pouze se vynechávají některé konstrukce (řekněme práce s prototypy), jste na omylu. Korektně zapsané programy v JSFucku totiž mohou obsahovat pouze těchto šest znaků:

( ) [ ] + !

Žádné další symboly se nepoužívají, takže například není možné přímo zapsat ani znaky a dokonce ani číselné hodnoty! Je však možné si v JavaScriptu skutečně vystačit s pouhými šesti znaky? Ukazuje se, že to možné je, záleží jen na námi zvolené reprezentaci. Například konstanta nula se může zapsat jako výraz:

+[]

což je sice možná poněkud překvapivé, ale unární + aplikované na prázdné pole skutečně vrátí nulu, a to díky zvláštnímu pojetí typového systému a konverze hodnot mezi různými datovými typy. Podobně jednička je výsledkem:

+!![]

nebo alternativně:

+!+[]

! je logická negace, přičemž True (negace nuly :-) se pro unární aritmetickou operaci + převede na 1. Podobně lze vytvořit další hodnoty, opět díky typovému systému JavaScriptu, kde platí True+True=2 atd.

ict ve školství 24

Pokud je zapotřebí pracovat se znaky (vytvořit například „Hello world“), je to poněkud složitější. Některé znaky lze získat relativně jednoduše indexováním z řetězců typu „true“, „undefined“, „NaN“ atd., další znaky se ovšem skládají složitějším způsobem, který lze vyčíst z následujícího zdrojového kódu: https://github.com/aemkei/jsfuc­k/blob/master/jsfuck.js

Pokud si chcete tento jazyk odzkoušet (nebo se jen přesvědčit, do jaké míry znáte všechna zákoutí JavaScriptu), stačí použít interaktivní prostředí dostupné na snadno zapamatovatelné adrese http://www.jsfuck.com/.

10. Odkazy na Internetu

  1. Esolang, the esoteric programming languages wiki
    https://esolangs.org/wiki/Main_Page
  2. Esoteric Topics in Computer Programming
    http://web.archive.org/web/20020609152409/www­.catseye.mb.ca/esoteric/in­dex.html
  3. Programming Languages designed by Wouter von Oortmerssen
    http://strlen.com/programming-languages
  4. Two-dimensional languages
    https://esolangs.org/wiki/Category:Two-dimensional_languages
  5. Piet (homepage)
    http://www.dangermouse.net/e­soteric/piet.html
  6. Piet (na Esolang)
    https://esolangs.org/wiki/Piet
  7. Piet IDE
    http://www.rapapaing.com/blog/?pa­ge_id=6
  8. JSFuck (homepage)
    http://www.jsfuck.com/
  9. JSFuck (na Esolang)
    https://esolangs.org/wiki/JSFuck
  10. JSFuck (na Wikipedii)
    https://en.wikipedia.org/wiki/JSFuck
  11. Malbolge (na Esolang)
    https://esolangs.org/wiki/Malbolge
  12. Malbolge (na Wikipedii)
    https://en.wikipedia.org/wi­ki/Malbolge
  13. Befunge (na Esolang)
    https://esolangs.org/wiki/Befunge
  14. Befunge (na Wikipedii)
    https://en.wikipedia.org/wiki/Befunge
  15. Minifuck
    https://esolangs.org/wiki/Minifuck
  16. XMLfuck
    https://esolangs.org/wiki/XMLfuck
  17. The False Programming Language
    http://strlen.com/false-language
  18. The FALSE Programming Language Manual
    http://strlen.com/false/false.txt
  19. Wouter van Oortmerssen
    http://esolangs.org/wiki/Wou­ter_van_Oortmerssen

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.