Hogyan csináljátok szépen magaszintű nyelven?
2009-01-16T10:48:33+01:00
2009-01-17T08:52:36+01:00
2022-06-29T07:05:36+02:00
  • Találkoztam már ilyen jellegű megközelítéssel, és nagyon sok bajt okozott. Azóta ökölszabály nálam, hogy
    - a hívó CSAK a hívott paramétereit ismerheti, a működését nem
    - a hívott pedig SEMMIT nem tud a hívóról.
    Minden egyéb összekapcsolódás gyakorlatilag lehetetlenné teszi a rendszer elemeinek módosítását, hibajavítást, újrafelhasználást.

    Mondjuk, egy break(3) utasítást tartalmazó blokkot ciklusba szeretnél utólag tenni, és a break-nek most már négyet kellene felmennie. Meg minden hívott függvényben, minden break-et megnézni... Így nem lehet.
    Mutasd a teljes hozzászólást!
  • Es ha van egy függvény amit több helyröl hivok meg?
    Meg elég macerás volna fejben tartani, akkor már inkább a GOTO.

    Named event, try/catch, exception vegyités lesz.
    Mutasd a teljes hozzászólást!
  • Ha úgyis saját nyelv lesz, lehetne akár opcionális paramétere a break-nak, ami azt adná meg, hogy hány szintet lépjen vissza. pl.:
    break(3);
    Mutasd a teljes hozzászólást!
  • Az iskolák még nem tartanak itt szerintem, de ilyesmi feladatokra mi hierarchikus állapotgépet szoktunk használni:
    Machine Objects - Hierarchical state machines in C++
    Mutasd a teljes hozzászólást!
  • Most hirtelen csak a bash jut eszembe, az ugyan nem fordító, hanem értelmező, de van benne egy 120KB-s parse.y, az végzi az elemzést.

    Note: Én pl. az XML-elemzést is bison-nal szoktam csinálni.
    Mutasd a teljes hozzászólást!
  • A megvalósítással nincs gondom.


    Sejtettem - csak ha már filózok, igyekszem végigmenni rajta (még ha vicces is...)

    Tehát abszolút elviszintű a kérdésem.


    Akkor tehát: mint a java try/catch/finally, illetve throw. A "checked exception" játék viszont nálam nem jött be, nem ad annyit, mint amennyi szívás van vele.

    Szerintem amit érdemes:
    - a függvény elején kelljen deklarálni, hogy mit dobhat, és hibát jelezni, ha olyasmit akar dobni, amit nem deklarált - ezzel lokálisan kikényszeríthető egy szigorúbb hozzáállás. Viszont, szerintem az csak szívás, hogy a hívott függvények által dobott exception típusokat is kötelező legyen deklarálni (pl: mindenhol használt util fgv által dobható exception készlet egy új verzióban megnőhet, de a közbülső réteget ez egyáltalán nem érdekli). Ugyanakkor relatíve gyorsan kigyűjthető a forrásokból fejlesztés közben, hogy egy fgv mit dobhat.
    - az "elkapó oldalon" ellenőrizni, hogy deklarált-e az, amit el akar kapni. Javában ez egyszerű, mert osztály az Exception.
    - valami leszármaztatás-szerűség kifejezetten hasznos (egy szolgáltatás konkrét megvalósítója "kiterjeszti" a felette "deklarált" exception-t), az "elkapás" az ős típusa alapján is megtörténik.
    - az exception csak típusazonosítót és adatokat tartalmaz, egy külső deklaráció mondja meg, hogyan kell őt szöveggé formázni, illetve mi történik vele (logolás, értesítés, kijut-e a képernyőre). Így később könnyebb pl automatikus logolást, loglevelt, miegyebet piszkálni, fejlesztői és éles rendszert csinálni (minden exception full info-val a képernyőn / logfile-ba tartalom, képernyőre csak "Bibi!"), nyelvi verziót csinálni, stb.
    Mutasd a teljes hozzászólást!
  • ja... ha el nem rontottam, akkor én is feltaláltam most a meleg vizet - nade, a hello, world!-öt is megírták már néhányszor, és mindig új élményt jelent.

    Arról egyébként úgy látom egyelőre nincs szó, hogy mivel fordul a nyelv (azt csak én értettem félre) - ha jól értem, most a nyelv tervezése van soron.
    Mutasd a teljes hozzászólást!
  • Elhiszem. Nekem meg van. Publikus de szubjektív.
    Tudsz mondani gyakorlatban használt fordítóprogramot, amiket ezzel csináltak
    Mutasd a teljes hozzászólást!
  • Ha fizetős fordítót írok például? (Igen, utána lehet olvasni, de valahogy nincs gusztusom több oldalnyi jogi jellegű szöveget böngészni angol nyelven. Viszont a válasz érdekelne.)
    Mutasd a teljes hozzászólást!
  • Köszönöm az igen értékes hozzászolásaidat.
    A megvalósítással nincs gondom.
    Csupán szeretnék a mások (más nyelvek) által már jól kitalált dolgokra támaszkodni.
    Tehát abszolút elviszintű a kérdésem.

    Mutasd a teljes hozzászólást!
  • Note: Nagyon erős ok kell ahhoz, hogy a fordítóprogramot ne valamilyen compiler-compiler (pl. yacc, bison) segítségével csináljuk meg.
    Mutasd a teljes hozzászólást!
  • Aha, asszem ki is maradhat a közbülső (hívás továbbító) elem.
    A throw egy globális (pontosabban thread local) struktúrát tölt fel; ha arra van regisztrált feldolgozó, akkor arra a címre csinál egy jump-ot. A feldolgozó regisztrációja során meg kell jegyezni a stack állapotát, hogy el lehessen dobni a felesleget (de homályos emlékeim szerint ehhez elég az SS:SP megjegyzése).
    Nyilván a hívott kódokban lefoglalt erőforrásokkal bibi van - erre van kitalálva a finally kulcsszó, ami gyakorlatilag a try blokk végén mindenképpen meghívódik, akár volt belül exception, akár nem.
    A finally blokk közvetlenül a try végére fordul be, így a futás ott folytatódik, ha nem történt semmi; kezdete ugyanúgy regisztrálódik, mint a catch-eké a blokkba történő belépéskor, a hívása is ugyanolyan throw esetén - viszont a blokk végén, ha van "éles" exception, akkor úgy viselkedik, mintha ő maga dobta volna.
    Mutasd a teljes hozzászólást!
  • Hmmm...

    Amit mondasz, az nekem definíció szerint az Exception kezelést jelenti, ami az én fejemben kb. így néz ki:

    1: a hívott kód deklarálja, hogy milyen eseményeket generál. Nyilván "passzív szereplő" a játékban, hiszen nem tudhatja, hogy honnan hívják: nem "valahova tér vissza", hanem "valamilyen esemény bekövetkeztét" jelzi.

    2: a hívott kód forráskódja valamilyen saját nyelvi elemmel jelzi, hogy esemény bekövetkezésről van szó (megadja a típust, attributumokat).

    3: a hívó forráskódban try-catch-jellegű blokkok vannak, vagyis jelzi, hogy ha a hívott kódok nem normál módon fejeződtek be, akkor milyen eseményekre kívánja megkapni a vezérlést.

    Megvalósítás? Elsőre az ugrik be, hogy a hívást nem simán call-ra fordítom le, hanem a hívó meghív engem, majd én meghívom a célzott függvényt. A hívott oldalon a "throw" kitölt egy struktúrát, ami a sima return esetén üres marad, majd return-t csinál, visszatér hozzám. Én üres esetben sima ret-tel lépek ki, ha viszont az eseményre van regisztrált eseményfeldolgozó, akkor takarítom a saját adataimat a stack-ről, és jump-pal ugrok a regisztrált kódra. Ha a közvetlen hívóban nincs regisztrált feldolgozó, akkor a takarítás után beállítva marad a throw struktúra, és csinál egy ret-et, már a hívó fgv nevében. ... bár biztos van ennél jobb megoldás is. (szerk: meg az is lehet, hogy ez sem jó - nem vagyok nagy spíler ezen a szinten)
    Mutasd a teljes hozzászólást!
  • Akkor viszont teljesen egyértelműen a runtime exception a te embered. Gyakorlatilag pont az volt a motiváció amögött, hogy az exceptionök megjelentek a struktúrált nyelvekben, amit írsz: a közbülső kód a visszatérési értékes szenvedés helyett transzparensen engedje fel a vezérlést annak, aki elkapja az exception-t.
    Mutasd a teljes hozzászólást!
  • Igen fordítóprogramot írok.
    De nem a fordítás menetéhez kell, hanem szeretnék a programozónak nyelvi támogatást adni, egymásba ágyazott (egymásból hívott) eljárások gyors befejezésére.
    Vagyis ne keljen minden eljárást egyenként megszakítani (break) és visszatérni a hívóhoz és ott ismét feltételt vizsgálni, majd újra megszakítani.
    Mutasd a teljes hozzászólást!
  • A tudomány állása felől nincs komoly információm, amit írok, személyes vélemény, talán nem is tesz sokat a témához, azt is "konyha-szinten".

    "ferdítőhöz kell" - tehát egy fordítóprogramról vagyon szó?
    Ez az én olvasatomban egy olyan kód, ami egy struktúra leírást tartalmazó, de lineárisan elérhető forrást alakít át adatstruktúrává. A feldolgozás "állapotfüggő", vagyis az elfogadható elemek ("tokenek", események) halmaza adaptálódik a már beolvasott halmazhoz. A forrásban lehetnek szintaktikai (ismeretlen karakter vagy token), illetve tartalmi (a pillanatnyi állapotnak nem megfelelő, bár szintaktikailag helyes tartalom, "váratlan filevég") hibák. (A definíció nyilván általánosítható tetszőleges eseményvezérelt programra, melynek feladata egy rendszer állapotának reprezentációja, esetleg ennek megfelelő reakció.)

    Az általam legjobban ismert feladat, ami jól mutat két lehetséges megközelítést, az XML parse, ami lehet DOM illetve SAX jellegű (most egy pillanatra félretéve azt, hogy a DOM valójában beolvassa az XML file-t, és a feldolgozása egy "buta", de már hierarchikus tartalom végigkérdezése).

    A DOM megközelítés lényege, hogy az elvárt struktúrát egy az egyben lekódolom; a program állapotokat függvényeknek feleltetem meg valami

    readBookshelf() -> readShelf() -> readBook() -> readAuthor() -> readTitle() -> readBook() ... -> readShelf() ...

    formában, az egyes függvények ismerik a saját token készletüket és állapotukat. A lényeg ilyenkor, hogy a "pillanatnyi állapotot" gyakorlatilag a stack-en lehet megtalálni, a függvények hívási láncában és lokális változóikban.

    A SAX ezzel szemben arra épít, hogy a nyelv struktúrái szintaktikai szempontból azonosak

    <bookshelf att1="" att2=""> <shelf> <book author="Csipike" title=""> ... </book> ... </shelf> ... </bookshelf>

    ... ezért azt csinálja, hogy a szintaktikailag homogén stream teljesen általános olvasó kódja callback függvényeket hívogat, és átadja nekik azt, amit talált (openTag("bookshelf"), openTag("shelf"), openTag("book"), setAtt("author", "Csipike"), ... closeTag("book"), ...) - a "tudás" a tag feldolgozókban van. Itt a feldolgozás lineárisan fut, a callback függvények viszont egy globális hierarchikus adatstruktúrát építenek (vagy éppen bontanak), az "aktuális állapotot" ez reprezentálja; "végállapota" a beolvasott, feldolgozott kód.

    Mindkét megközelítés adja a "valid" tartalom rugalmas feldolgozását, míg a hibakezelés Exception-ök segítségével történik. (Exception-t használni "normál tevékenységre" erősen ellenjavallt...)

    A SAX legnagyobb előnye a modularitás, a tag-eket pluginek formájában is meg lehet valósítani, könnyebb változtatni, különböző komponenseket egy feldolgozóba összeépíteni. Hátránya, hogy függvénykészletében kötődik az XML "balta-szinten" egyszerű szintaktikájára - ha "normál" nyelvre kell alkalmazni, akkor a reader-ben cserélhetővé kell tenni a token felismerő kódot, ami aztán majd visszahívja a token feldolgozóját. Ugyanígy az esetleges Exception kezelése sem triviális, hiszen nincs ott a callstack és az "elkapás-kezelés-továbbdobás" történet, hanem valami ezt kiváltó, az adatszerkezetet használó kód kell.

    A DOM szerintem egy zárt, végleges nyelv kezelésénél lehet hatékonyabb megoldás - olyan nyelven megvalósítva, ami alapból kezeli az exception-öket. Bibi vele a korrekt állapotreprezentáció: gyakran kevés a szimpla visszatérési érték, jönnek a paraméterben lepasszolt-visszaadott objektumreferenciák - ez piszokul el tud kutyulódni, és a végén ugyanaz a globális adatstruktúra lesz, mint a SAX-nál...


    My 2 cents: egy SAX-jellegű megoldás, valami ilyen formában:
    - plugin-ezhető esemény generátor: ez az, ami a külvilág történéseit (fordítóprogram esetén a forrásfile karaktereit) figyeli, és belőlük a feldolgozó komponensnek szóló üzenetet generál. Azért kell a plugin, hogy a feldolgozó bele tudjon nyúlni az aktuális állapotban szintaktikailag elfogadható token halmazba
    - esemény fogadó komponens, ami meg tudja keresni az adott tokenhez tartozó feldolgozó függvényt (ez kb egy ugrótáblának felel meg, akár menet közbeni feltöltéssel
    - egy adatstruktúra, ami leírja a pillanatnyi állapotot - ide dolgoznak a feldolgozó komponensek
    - feldolgozó függvények, amik megkapják az eseményeket, annak megfelelően módosítják az adatstruktúrát, és esetleg az esemény generátor tokenfelismerő plugin-ját
    - hiba feldolgozó "exception handler" egy globális bejárattal - de akár handler-t lehet rendelni az adatstruktúra node-okhoz is, akkor már majdnem olyan, mint egy működő try-catch szerkezet.

    (szerintem hibakeresésnél is sokkal hatékonyabb tud lenni egy külső állapotreprezentáció, mint a stack értelmezése)
    Mutasd a teljes hozzászólást!
  • > Nyilván, csak így az összes eljárásban figyelni kell (visszafelé haladva) a visszatérési értéket vagy egy globális fleget.

    Persze.
    Mutasd a teljes hozzászólást!
  • Ilyesmi megoldható runtime exceptionnel (nem checked exceptionnel) pl. JAva-ban:

    fgv4-be ilyen kell:

    if(valami==valamennyi) { . . . } else throw new AlmaOccuredException();

    fgv1-be meg ilyesmi:

    while(true) { try { ... if(almaoccured) { fgv2(); ... } else { ... } almaoccured = false; } catch(AlmaOccuredException) { almaoccured = true; } }

    Amit fent írtam az ebben a formában ronda mint a bűn, de a lényeg az, hogy demonstrálni akartam, hogy esetleg exceptionnel ki lehet hekkelni.
    Mutasd a teljes hozzászólást!
  • 'hiba van; kezeld, vagy te is térj vissza ezzel a kóddal' jelentésben.


    Nyilván, csak így az összes eljárásban figyelni kell (visszafelé haladva) a visszatérési értéket vagy egy globális fleget.
    Mutasd a teljes hozzászólást!
  • Amire gondoltam nagyon pszeudokód:


    fgv1: Event "alma" call fgv2 else esemény elkezelése end Event end fgv1 fgv2: call fgv3 end fgv2 fgv3: call fgv4 end fgv3 fgv4: if valami=valamennyi . . . else DoEvent "alma" end if end fgv4
    Mutasd a teljes hozzászólást!
  • Nem nagyon hiszem, hogy mondjuk C-ben tudnál eljárások között goto-zni, inkább a setjmp-longjmp páros használható... bár szerintem ezek használata is ellenjavallt, elegánsabb lenne minden egyes függvénynek definiálni egy speciális visszaadott értéket, 'hiba van; kezeld, vagy te is térj vissza ezzel a kóddal' jelentésben.

    PS: Ha vannak exception-ök a kérdéses nyelvben, azokat is lehet ilyen célra használni.
    Mutasd a teljes hozzászólást!
  • Nem tudom mi a legiskolásabb módszer, mert igazából nem vagyok az a nagyon iskolás fajta.
    Szerintem nyelvi szinten ilyesmit nem támogatnak a mainstream nyelvek. Egy runtime exception mondjuk pont jó lenne arra, hogy tetszőleges mélységből 'fölgyere', de vissza már nem tudnál menni.

    Szóval én nem nyelvi szinten csinálnám, hanem úgymond interpretert írnék:

    Lenne egy 'Task' nevű osztályom. (aminek talán lenne execute metódusa, ehhez látnom kéne a pontos feladatot?)

    Namost lenne egy stack of Task-om: mindíg a legfelső elemen lenne a 'vezérlés'. Egy ilyen Stack of Task az végülis egy 'execution context', ilyenből akár több is lehet...

    Bármikor úgy dönthetnék, hogy törlöm az egész stacket.

    Szóval összefoglalva: szerintem nincs rá nyelvi támogatás, így 'felmennék a metaszintre' és valami 'interpreter' féleséget írnék...

    szerk.:
    Amúgy szerintem túl általános a kérdésed. Szerintem a konkrét feladat ismeretében az emberek jobban be tudnának egy tipikus 'iskolás' designt lőni, de ez így túl általános.
    Mutasd a teljes hozzászólást!
  • Van sok egymást hívó eljárás (>10 mélység) bizonyos események, állapotok bekövetkezésekor meg akarom akasztani az eljárások menetét és egy megadott pontra, lépni. Ezen a ponton mérlegelnem kellene, hogy folytatom az eredeti vonalon vagy egy teljesen új "címre" megyek.
    Természetesen meg tudom oldani. (gotoval és goto nélkül is )
    Az érdekelne, hogy a tudomány mostani állása mellett mi a legszakosabb, iskolásabb kivitelezés.
    Címszavak, példa érdekelne.
    /saját ferdítőhöz kell...
    Mutasd a teljes hozzászólást!
abcd