A Tcl programozási nyelv

Kivételkezelés


A hagyományos értelmezésben a kivétel olyan esemény, amelynek feldolgozását a pillanatnyilag aktív programrészlet nem vállalja (mert kivételes volta miatt nem oda tartozik), hanem futását megszakítva áthárítja azt a hívási-egymásbaágyazási láncban felette állóra. A kivétel ily módon egészen addig terjed tovább, amíg egy kivételkezelő el nem fogja, vagyis fel nem dolgozza.

A kivételt például gyakran az okozza, hogy valamely művelet végrehajtása meghiúsul (például hibás argumentumok vagy erőforráshiány miatt). Ezt hibának nevezzük.

A Tcl azonban nem csak a hibakezelésre veti be a kivételeket, hanem vezérlésátadások megvalósítására is. Egy kivétel kiváltása bújik meg például amögött, ahogyan a continue paranccsal a ciklusmagot megszakítjuk. Akármilyen mély vezérlőszerkezeti struktúrába is legyen ágyazva, a continue által kiváltott kivétel sorra megszakítja a vezérlőszerkezeti parancsok végrehajtását, és eljut a ciklust megvalósító parancsig, amely elfogja és értelmezi.

Kivételek keletkezése és terjedése

A Tcl parancsok a string típusú visszatérési érték mellett egy közvetlenül nem hozzáférhető befejezési kódot is visszaadnak. A parancs normális befejezését a nulla (TCL_OK), a kivétel miatti befejezést nullától különböző kód jelzi.

Amikor egy Tcl script valamely parancsa kivételkóddal tér vissza, a script végrehajtása megszakad, és a script továbbadja a parancs visszatérési értékét és a kivételkódját az ő végrehajtását kezdeményező hatalomnak. Ha a script végrehajtását egy parancs kezdeményezte, a parancs eldönti, hogy lekezeli-e a kivételt. Ha nem kezeli le, akkor a visszatérési értéket és a befejezési kódot átveszi a scripttől. Végül ha a script végrehajtását a felhasználó kezdeményezte (például interaktívan begépelte a Tcl shellnek, vagy a Tcl shell indításakor megadott egy Tcl scriptet tartalmazó fájlt), akkor a Tcl interpreter a kivétel típusának megfelelő hibaüzenetet ír ki.

Kivételek fajtái

A kivétel fajtáját a befejezési kód határozza meg.

TCL_ERROR (1)
Igazi hiba lépett fel, a visszatérési érték a hibaüzenetet tartalmazza. Csak explicit hibakezeléssel fogható el. Hiba típusú kivétel esetén a hibaüzenet mellett két globális változó ad további információt a hiba fellépésének helyéről okáról:

errorInfo Tartalma egy többsoros string, amely feltárja, hogy a hiba hol keletkezett, és milyen parancsok és scriptek végrehajtása szakadt meg miatta. A megszakított parancsok töltik fel, ahogyan a hiba kifelé gyűrűzik.
errorCode A hiba okát részletezi egy listában. A lista első eleme adja meg a hiba kategóriáját. Ha nincsenek részletek, ez az elem NONE. Ha vannak - például POSIX rendszerhívások során fellépett hibák esetén, amikoris a lista első eleme POSIX - akkor a lista további elemei a kategóriától függően tartalmaznak egyebeket - a POSIX példában ez a POSIX hibakód szimbolikus neve és egy szöveges leírás (mondjuk ENOENT és "No such file or directory").

TCL_RETURN (2)
A return parancs idézi elő, a visszatérési érték a return parancsban megadott, a befoglaló eljárásnak szánt visszatérési érték. A proc paranccsal létrehozott, az eljárástörzset meghívó parancs kezeli le azzal, hogy normálisan befejeződik, és visszaadja a TCL_RETURN mellett érkező visszatérési értéket.

TCL_BREAK (3)
A break parancs váltja ki. Normális esetben a legbelső befoglaló ciklus parancs kezeli le, és befejezi a ciklus végrehajtását. De elfogják a proc paranccsal létrhozott parancsok és a source parancs is, és hiba típusú kivételként terjesztik tovább, ezzel diagnosztizálva a break parancs ciklustörzsön kívüli használatát.

TCL_CONTINUE (4)
A continue parancs váltja ki. Normális esetben a legbelső befoglaló ciklus parancs kezeli le, és folytatja a ciklus végrehajtását a következő iterációval. De elfogják a proc paranccsal léterhozott parancsok és a source parancs is, és hiba típusú kivételként terjesztik tovább, ezzel diagnosztizálva a continue parancs ciklustörzsön kívüli használatát.

Egyéb érték
A programozó tetszőleges egyéb egész számot is használhat befejezési kódként. A megfelelő kivételek mindenen keresztül átterjednek, csak explicit módon foghatók el.

Kivételek explicit kiváltása

error hibaüzenet ?hely? ?ok?
Az error parancs TCL_ERROR kivételt vált ki, amelyhez a megadott hibaüzenetet mellékeli.

Ha a hely argumentum hiányzik, vagy üres string, az errorInfo változó első sorai dokumentálják, hogy error parancs okozta a kivételt. Ha a hely argumentum nem üres string, akkor az errorInfo változó vele inicializálódik, és nem említi az error parancsot.

Utóbbinak akkor van jelentősége, amikor elfogtunk egy kivételt, részben kezeltük, de úgy szeretnénk továbbterjeszteni, hogy a hiba fellépésének eredeti helyét jelöljük meg. Ilyen esetben ugyanis az errorInfo változó már tartalmazza a kivétel terjedésének útvonalát az elfogásig, ezt megadva az error parancs hely argumentumaként a kívánt hatást érjük el.

Az ok argumentumot az error parancs értékül adja az errorCode változónak. Ha nem szerepel, az errorCode változó értéke NONE lesz.

return ?-code befejezési kód? ?-errorinfo hely? ?-errorcode ok? ?érték?
A return parancs a legbelső befoglaló eljárás vagy source paranccsal meghívott script végrehajtásának befejezését eredményezi. A parancsban megadható a visszatérési érték (alapértelmezésben üres string) és a befejezési kód (alapértelmezésben nulla). A befejezési kódot a ok, error, return, break és continue stringek valamelyikével, vagy egész számmal jelölhetjük.

Az -errorinfo és -errorcode opcióban megadottakat a return parancs csak akkor veszi figyelembe, ha a befejezési kód TCL_ERROR. Ilyenkor a hely stringet értékül adja az errorInfo változónak, az ok listát pedig az errorCode-nak. Hely alapértelmezésben üres string, ok pedig NONE.

Felvetődhet valakiben a kérdés, hogy a Tcl hogyan választja szét azt a befejezési kódot, amelyet a return parancs ad vissza, hogy a kivétel hatására az eljárásnak adódjon át a vezérlés, és azt a befejezési kódot, amit ezek után maga az eljárás ad vissza. Sem a rendelkezésemre álló dokumentáció, de még kísérletezés útján sem sikerült erre választ kapnom. A Tcl forráskódjából megtudható, hogy a TCL_RETURN kivétel mellett a másik kód az interpreter állapotát reprezentáló C struktúrának egy mezőjében (tehát Tcl-ből hozzáférhetetlenül) utazik az eljárástörzsig.

Kivételek explicit kezelése

catch script ?változónév?
A catch parancs végrehajtja a megadott scriptet, és minden kivételt elfog. Visszatérési értéke a script befejezési kódja, azaz nulla, ha a script végrehajtása normálisan fejeződött be, és nullától különböző, ha futása kivétel miatt szakadt meg.

Ha megadjuk egy változó nevét is, a catch parancs abban helyezi el a script visszatérési értékét, vagyis az eredményt vagy a hibaüzenetet.

A return utasításnál taglalt kérdéshez kapcsolódik, hogy a catch parancs TCL_RETURN eredménnyel tér vissza, ha a scriptben, eljáráshíváson kívül return utasítást adunk ki. A return utasításban megadott befejezési kódhoz így sem tudunk hozzáférni.