Azon is elgondolkoztam, hogy hogyan legyen a rekurzió, bal- vagy jobboldalasan:
#1 program: utasítás | utasításprogram
#2
program: utasítás | programutasítás
Először naivan azt hittem, hogy az első a jobb módszer, de most a második felé hajlok.
Olyasmi tesztet végeztem, ahol az input 'változó=érték' utasításokból áll; ha különböző változókról van szó, akkor az értékadások sorrendje nem számít, de ha ugyanannak a változónak adok értéket kétszer (többször), akkor azt várnám, hogy az utolsó hajtódjon végre utolsónak (vagyis az jusson érvényre, ne az első).
A teszt szerint #1 esetén az első értékadás 'nyer', vagyis a végrehajtási sorrend fordított.
#2 esetén az utolsó értékadás jut érvényre, vagyis a végrehajtás sorrendje megegyezik az utasítás sorrendjével.
További érdekesség ezügyben, hogy a fejlődés során az YYPARSE_PARAM megszűnt létezni... valahogy azért sikerült egy kompatibilis állapotot létrehozni 3.0.2 és 2.5 között
Nyilván ha átírom s/%pure-parser/%pure_parser/ akkor szépen minden más gépen is bison-verziót kell növelnem, mert azok meg az opció új formáját nem ismerik még.
A lényeg: a $$ a szabály végén lévő kód esetén a szabály kimenetét jelenti, a szabály belsejében lévő kód esetén egy lokális értéket a vermen. Maga a bison doksi is hoz egy példát, épp most leltem:
Itt az ötös elem (vagyis a $5) az a beágyazott kódrészlet, ami értékőrzőül szolgál (saját magán belül $$ az érték, a továbbiakban meg $5 -- szerintem nem egészen intuitív, talán jobb lenne, ha önmagában is menne a $5 (de nem megy)).
És mivel nincs neve, nem lehet %type-ot se mondani rá, ezért ezzel a furcsa szintaxissal kell típuskényszeríteni (ha egyáltalán használunk %type-ot, az én előző példámban épp nem használtunk))
Ahhoz még nem éreztél kedvet, hogy ilyen feladatokra a .NET-et használd (vagy Monót, ha Linux?). Jó, tudom, fujj, Microsoft, elvileg egyetértek, de muszáj bevallani, hogy ezt véletlenül nagyon jól megcsinálták.
De rég volt itt bármi is... annyir mondanék, hogy azóta is használom XML-parsolásra a yacc-ot (bisont, pontosabban), főleg azóta lett még szebb az élet, hogy a lexikális elemzővel megbeszéltem, hogy az ilyeneket egy lexikális egységként adja vissza: input: <valami:tag valami:fld="value"/> output: <valami:tag valami:fld = "value" />
Nem, mint mondtam, a Yacc egy programozási nyelv, amit a yacc nevű program C-re fordít. Nem általános célú nyelv, kifejezetten csak egy dologra jó: fordítóprogramokat lehet benne/vele készíteni.
Az slx és sly nekem nem mond semmit, nézz bele text-editorral, esetleg pasztézz be részleteket.
A fordítóprogramoknak a beérkezô forrásszöveget lexikálisan (mi egy azonosító, mi egy szám, satöbbi) elemezniük kell, majd az így felismert lexikai elemeket a lefordítani kívánt nyelv szintaktikai szabályai szerint fel kell dolgozniuk. Ez utóbbi lépés során azt is fel kell ismerniük, hogy milyen lexikai elemek milyen sorrendben és milyen összefüggések szerint következhetnek egymás után.
A lex-yacc-flex-bison és hasonló programok arra szolgálnak, hogy ha egy elemzendô programozási nyelv lexikai és szintaktikai szabályait formálisan leírod, akkor ebbôl ôk el tudják készíteni az adott nyelvet elemzô programot. Azaz, ezek programot generáló programok, és arra használják ôket, hogy a fordítóprogramok ilyen elemzéssel foglalkozó részét ne kézzel kelljen megírni. Több oka is van, hogy ez miért elônyös (túl a nyilvánvaló munkamegtakarításon), de ez már messze vezetne.
Köszi a gyors választ. A meghatározásából ítélve (parser generator - nyelvelemző) tovább tökéletesíti a c kódot? Egyébként a projekthez tartozik egy y fájl, meg egy slx és egy sly kiterjesztésű. Gondolom ezek is a bisonhoz tartozik, mert egymás mellett vannak azonos névvel (macro). Ők mire valók?
Kérlek tisztelettel, a yacc (bison) egy fordítóprogram, amely yacc nyelvű forrásprogramból (.y kiterjesztés), C-nyelvű output-ot (.c kiterjesztés) állít elő. (Nevezhetjük előfordítónak (precompiler) is.)
Tehát a lényeg: nem helyettesíthető se C-fordítóval, se Assembler-rel, se Text-editorral, önálló program, önálló feladattal.
Hinnye, nem szeretném elrontani a monológodat (remélem, azóta rájöttél a helyes megoldásra), viszont szakértőnek nézel ki a témában:
Tegnapelőtt futottam bele életemben először a Bisonba, le kellett töltenem és telepítenem, hogy az xHarbour fordító buildjét lefuttathassam. Néhány órát ugyan eltöltöttem a dokumentációk értelmezésével, de a kulcsproblémára nem jöttem rá: mi a túrót is csinál még pluszban, miért nem elég a Borland C fordító? Ha néhány keresetlen mondatban felvilágosítnál a lényegről...
Naná hogy 0 (azaz $0) sikerem volt... viszont a következő működik:
dekl: type { $$.type = lasttype /* save old value */; lasttype = $1.type}
vars { lasttype = $2.value; /* restore old value */}
közben a vars-t teszteléshez kibővítettem:
vars: var more_vars {CreateVar($1.name,lasttype);}
'(' dekl ')' more_vars;
more_vars: | ',' vars;
tesztadat:
NUMBER I,(STRING S,T,(NUMBER K,L)),J;
Mondjuk azt nem állítom, hogy ennek a beágyazott deklarációnak így lenne értelme,
de tesztelésre jó... egyébként C-ben van valami hasonló: int i,j,f(int (*g)(int k)))
type: NUMBER {lasttype= P_NUMBER} | STRING {lasttype=P_STRING};
vars: var {CreateVar($1.name,lasttype)} | var ',' vars {CreateVar($1.name,lasttype)}
tehát változókat akarok deklarálni,
"NUMBER i,j,k;" avagy "STRING s,t;" formában.
Az egyes változókat a CreateVar hozza létre, paramétere a név és a típus.
Itt a gondom: honnan tudom hogy mi volt a tipus? Azt találtam ki, hogy beleteszem
a globalis 'lasttype' valtozóba, de ez nem igazán elegáns, inkább egy vermet kellene használni erre... csakhogy már amúgy is az elemzőnek verme... kérdés, hogy hozzáférek-e a kérdéses elemhez $0 vagy $-1 vagy valami ilyesmi módszerrel?
type: NUMBER {$$.type= P_NUMBER} | STRING {$$.type=P_STRING};
vars: var {CreateVar($1.name,$-1.type)} | var ',' vars {CreateVar($1.name,$-1.type)}