Občas je to spíš hlavolam než asembler - když člověk potřebuje nějakou složitější operaci na zásobníku, tak mi to přijde jako takové ty hlavolamy s posouváním vláčků na různě dlouhé slepé koleje. Třeba je to tím, že člověk z jiných jazyků není zvyklý takto uvažovat, ale nemyslím si - i v dobách, kdy jsem psal programy v PostScriptu, jsem si musel ty zásobníkové operace stále kreslit. Naštěstí jsou málokdy potřeba nějaké složitosti. Ale schválně si zkuste (bez tužky a papíru) přijít na to, co dělá tento primitivní program, resp slovo .D v něm, a posuďte čitelnost :)
: .D SWAP DUP ROT DUP ROT SWAP ;
( test )
2 1 .D .D .D
+ . - . * . / .
Já jsem si FORTH po počátečním WTF? někdy v 15 letech zamiloval o 10 let později a už mě to nepustilo. Má naprosto nedostižný poměr mezi nároky (na HW, na implementaci) a tím, co nabízí. Jakmile člověk zažije ten aha!-moment, zjistí, jak neuvěřitelně mocný nástroj to je a začne si doprogramovávat hromadu dalších věcí - objektové programování à la C++, objektové programování à la Smalltalk, objektové programování à la CLOS, FP aritmetiku, infixovou notaci, lokální proměnné, pojmenované parametry, datové typy, GUI slovník... Když se dostatečně vyblbne, tak si uvědomí, že ten jazyk je dokonalý tak, jak je, že všechny ty blbiny, co mají jiné jazyky, on nepotřebuje, protože ty blbiny řeší něco, co se dá ve FORTHu vyřešit elegantněji ad-hoc řešením. A někdy v mezičase si během pár hodin napíše v Assembleru, jen tak mimochodem, vlastní FORTH, aby si ověřil, že je to opravdu tak jednoduché a vážně to funguje a dá se to naprosto plnohodnotně používat.
Dobře napsaný program ve FORTHu se pozná tak, že od druhé úrovně výše se čte jako vyprávění mistra Yody. Špatně napsaných programů moc není, protože by se v tom autor velice brzy sám zamotal.
Na PC v MS-DOSu jsem používal F-PC, i když jsem si cvičně napsal i vlastní pak později pro Linux (v GAS). Ale já jsem FORTH používal spíše pro non-PC platformy, zejména vlastní implementace pro DSP řady ADSP-21xx, nakonec i vlastní 16bitový zásobníkový CPU na FPGA (tyto dvě věci v rámci podnikání, STC implementace).
Pokud by měl někdo nutkání napsat si vlastní FORTH, tak doporučuji sérii článků "Moving Forth" od Brada Rodrigueze. Pro Linux existuje SmithForth - zajímavostí této implementace je, že je napsaná přímo ve strojovém kódu x86-64! A nutno podotknout, že velmi hezky a přehledně, se spoustou komentářů. K "překladu" stačí jen standardní utilita xxd. Čímž chci poznamenat, že FORTH se přirozeně nejlépe píše v Assembleru a níž (a nebo přímo ve FORTHu jako cross-compiler, nebo - což je ještě zajímavější - jako meta-cross-compiler, který přeloží sám sebe pro jinou platformu - zde se využívá toho, že většina FORTHu se stejně píše ve FORTHu).
A pokud by někdo chtěl vyzkoušet zvládnutí tohoto jazyka, tak klasika "Starting Forth" a "Thinking Forth" od Leo Brodie - posledně jmenovaná je podle mě užitečná, i když člověk u FORTHu nezůstane.
Prekladac me z toho udelal vnitrne 2 tokeny OVER_SWAP a TUCK. Coz je vlasnte 2DUP.
Davam prednost kdyz se slovo 2DUP definuje jako OVER OVER, je to jasnejsi a bude to asi i rychlejsi v kazde implementaci.
Ta svoboda co dostanes ve forthu nakonec neco stoji.
Ne kazdy to zvladne.
Chces jezdit na koni bez sedla? Tak bez do toho, kdyz chces. Jen si mozna zlomis vaz.
Nebude na tebe kricet ze tohle je rezervovane slovo... klidne si to predefinuj. A pak zase vrat puvodni definici pozdeji.
To ze nemusis pozna ani co je slovo nebo hex cislo je dan za to ze nemas zadne ohradky typu 0x... nebo [_a-zA-Z][_a-zA-Z0-9]*. To ze slova jsou takove vyrazy nebo filtry a ze dokazi brat kdykoliv promenlivy pocet parametru a vracet to same. Dokonce to mohou menit i podle vstupu nebo nejakeho bocniho kanalu. Jen to pak budes muset nejak ustat aby ten program neskoncil v chaosu.
Ta volnost pak konci tim, ze kdyz to budes brat vazne tak zjistis ze standard dela banda idi*tu a ze az kdyz si to cele udelas po svem ti narostou kridla a v ten moment se to take stane jazyk jen pro tebe a nikoho dalsiho...
A taky to uplne neni vhodny jazyk napriklad pokud chces neco delat nad bajty. Je to pak trosku nepohodlne, protoze zakladni jednotky jsou o sirce cell nebo dvojite. Pripadne nejaky float pravdepodobne nad vlastnim zasobnikem.
Ano slo by to nejak rozsirit ze bys udelal emulovany dalsi zasobnik ciste pro bajty a konverzni slova atd.
Postfixova notace neni problem, ale kdyz pak pises ( a b -- a+b ) tak uz michas postfix a infix a pri infixu to obcas chce i zavorky a ty ted nemuzes napsat protoze koncova zavorka ukonci komentar.
Slozitejsi algoritmy co maji vic jak 3 promenne :D uz pravdepodobne budou vyzadovat bud zvolit jiny algoritmus, rozdelit to na podulohy, nebo si neco ulozit do pameti a pak to radsi cist pres @ (Programator bude vedet ze to neni rekurze a muze to pouzit, jeho starost). Ppripadne pouzit lokalni promenne v modernich verzich. Protoze cteni z pameti bude rychlejsi nez to tahat z hlubokeho zasobniku.
Ten zpusob mit to na zasobniku je strasne efektivni, protoze je to virtualni masina, kde programator sam resi vhodne rozmisteni v registrech na skutecnem hw. TOS bys mel pokud to jde mit v registru, mozna i NOS. Ale proste ne vzdy to jde tak minimalizovat.
Navic forth muze byt i docela slozity jakmile zjistis, ze ma veci jako DOES>. To fakt uz neni pro kazdeho kdyz zjisti ze tohle otvira dalsi slozitosti (nebo prilezitosti jezdit i na medvedovi).
Problem forthu je i to ze se daval na veci kde by proste BASIC selhal. Mala ROM a 1Kb RAM a tady to mas! Je to superpocitac s forth... :D
PS: Ja si zasobnik kreslim v tech schematech. Protoze tohle splete i AI. Ale nejsem nejaky forth progamator.
Tak tohle je podle mě soupis výhod a nevýhod Forthu v kostce - to by se mohlo tesat, kdyby to bylo kratší :)
Ano: zkusil jsem si naimplementovat 2DUP bez OVER. Jen tak, přišlo mi, že přeci pomocí ROT a DUP to musí být snadné :)
Nemám ve Forhu žádné zkušenosti, pracoval jsem kdysi jen v PostScriptu a ten umí dát na zásobník i struktury (ukazatel na ně), takže se 2DUP nepotřebuje, ale ve Forthu jsem (zatím) nic takového neviděl, tak mi přišlo, že si člověk musí sám napsat 2DUP, 4DUP, 6DUP...
Ohledně Forthu: já považuju také za neuvěřitelné, z jak malého základu lze vybudovat celý jazyk, jak si člověk může předefinovat úplně cokoliv. A má téměř absolutní svobodu, jak kdyby si zároveň tvořil jazyk, kompilátor i vlastní program naráz. Ale bojím se, že právě proto to v praxi vede ke znovuvynalézání miliónů různě šišatých kol pořád dokola, protože než pochopit cizí knihovnu, každý stejně usoudí, že si to raději napíše odznova sám - a určitě "líp" ve smyslu optimalizace zrovna pro toto konkrétní použití. Kdo to ale pak všechno přečte a vyzná se v tom? Včetně autora samotného po delší době? To nevím. Mám málo zkušeností na to to odhadnout, ale tak intuitivně za ta léta v IT mi přijde, že takhle pojatá ta svoboda je právě zároveň největší výhoda a zároveň Achilova pata Forthu...
Ohledně míchání notací v popisech typu ( a b --- a+b ) : přijde mi, že je to i v originální dokumentaci ještě zákeřnější, stačí vzít jejich značení a k tomu nekomutativní operaci, aby to bylo vidět: ( n1 n2 --- n1/n2 ). Když si to zkusíte, zjistíte, že n1 fakt není na vrcholu zásobníku, jak by jeden čekal. Na vrcholu je vždycky ten poslední zmiňovaný parametr na vstupu. Takže n1 je tady druhé od vrcholu, zatímco u popisu ROT je třetí od vrcholu...
A také to znamená, že když chcete testovat svoje nové slovo porovnáním stavu zásobníku před a po pomocí .S , tak si to musíte (minimálně v hlavě) přerovnat, pokud to chcete porovnat s tou definicí/popisem.
Ja prisel ze lepsi je to znacit \ ( n1 n0 -- n3 ) n3: n1/n0
Nulou to zacina kvuli tomu jak se chova PICK (ten zvolil pri definici nulu spravne).
Ale to ze se tam micha ten infix v komentarich je trosku problem.
Oboje samostatne neni problem, i kdyz u infixu si musis pamatovat poradi operaci atd a postfix je uz optimalizovany by design, stejne jako mas uz optimalizovany jak mas rozmistit hodnoty v regisrech.
Ale na tom stretu to zacne o sebe drit.
2DUP jde udelat spoustou zpusobu SWAP TUCK SWAP TUCK.
Podle odkazu od p. Tisnovskeho to ale neumi nektere "zakladni" casto pouzivna slova jako
: NIP ( b a -- a ) SWAP DROP ; : -ROT ( c b a -- a c b ) ROT ROT ; : TUCK ( b a -- a b a ) DUP -ROT ;
Ale tech kombinaci je prirozene stejne mnohem vic nez forth bezne nabizi. Protoze zabiraji misto ve slovniku.
Premyslel jsem ze ty nazvy by sli udelat i jako ACB misto -ROT. _A misto NIP. ABA misto TUCK.
on právě FORTH nějak nezapadá do škatulek "assembler", "překladač", "vyšší programovací jazyk". Má od každého něco. Jinak zajímavé je, že v assembleru vůbec nemám problém číst nebo psát "nudle" dlouhé přes několik obrazovek, ale ve FORTHu už slovo obsahující deset dalších slov je problém a musí se dělat refaktoring. Ten je navíc tak jednoduchý, že to k tomu svádí pořád. Kdežto v assembleru radostně pokračuju s nudlemi a špagetami :)
No jo, ale k tomu je pár otázek od laika - pardon, asi jsou fakt laické:
1. co vím, tak ve forthu jsou všechna slova globální, takže vznikne obří nezapamatovatelný slovník alias maglajz. Leda nějak prefixovat jako v dřevních dobách... Nebo jak se to řeší?
(ve svém programu potřebuju všechny části programu, takže dělením na obrazovky si nepomůžu)
2. přeložený/interpretovaný kód teda obsahuje cca z 50% instrukce skoku nebo jak se to optimalizuje? Je něco jako 'inline'?
3. ty "obrazovky" jsou další performance killer: např. obrazovka 18 ve fig-forthu obsahuje de facto jen tři skoky do dalších obrazovek, to je celý její obsah. Zabírá (jako každá obazovka, z definice) KILOBAJT! To se nějak kompresí za běhu? Ostatně jak jinak by se vešlo do Atari 88 kilobajtových obrazovek (a ještě místo na vlastní kód programu)...
Trošku mi to připomíná, jak jsem se dozvěděl, že ve forthu je programovaná grafika v mých oblíbených textovkách typu Price of Magik, Collosal Adventure apod. Tam než se ta grafika na cca třetině obrazovky vykreslí, tak jsem většinou už zase o obrazovku dál... Zatímco ten ošklivě špagetový assembler např. ve Spindizzy rozbalí ze zkompreseného archívu a vykreslí 3D scénu přes celou obrazovku rychleji než obnovovací čas mezi dvěma TV snímky...
Jenže to může být použitým algoritmem, nechci jen kvůli tomu na forth nasazovat. Spíš se mi to jen vybavilo :) Obecně mě zajímá, že z definice jazyka podle mě musí plynout tyhle základní laické otázky o performance každému, tak jak se to v praxi řeší?
ad 1.: Ne. FORTH má slovníky. Navolíte si, do kterého přidáváte nové definice a kde se vyhledávají ty stávající. Volíte i pořadí slovníků, ve kterém se začne vyhledávat, ve kterém se bude pokračovat při neúspěchu atd.
ad 2.: Ano, může se optimalizovat přes inlinování.
ad 3.: Screeny se obvykle nekomprimují*, preferuje se taková štábní kultura, která co nejlépe využívá celou plochu screen. Screena zabírá právě jeden blok, kompresí by se to zkomplikovalo. I tak je průměrné plýtvání místem od konce řádku do okraje screeny asi tak 40-60 % bloku, takže to není zrovna úsporný způsob ukládání zdrojového textu programu.
* latinsky comprimere = stlačovat, odv. komprimovat; supinum je compressum, odtud nomen actionis compressio = stlačování, odv. komprese. Jinými slovy - "kompresovat" zní hodně divně. ;)