Vezérlőszerkezetek
A Tcl az imperatív programozási nyelvekben megszokott vezérlőszerkezeteket parancsok formájában biztosítja. A vezérlőszerkezet-parancsok argumentumai a vezérlést meghatározó kifejezések és a különböző esetekben végrehajtandó Tcl scriptek. Általában mind előbbieket, mind utóbbiakat kapcsos zárójelek közé zárva adjuk meg, hogy egyetlen argumentumnak számítsanak és több sorba is írhassuk őket:
if {$kor < 3} then {     set hely "bölcsi"     set etel "papi" } elseif {$kor < 6} then {     set hely "ovi"     set etel "kukoricapehely" } else {     set hely "egyeb"     set etel "nem válogat" }
A zárójelezés további (és többnyire kívánatos hatása), hogy a helyettesítések csak akkor történnek meg, amikor a parancs a feltételeket kiértékeli és a scripteket végrehajtja.

Elágazások

if feltétel1 ?then? törzs1     ?elseif feltétel2 ?then? törzs2 ...?     ??else? törzsN?
Az if parancs feltétel argumentumai logikai értéket eredményül adó kifejezések (a logikai érték egy szám, ahol a 0 felel meg a hamisnak, de lehet true, yes, false vagy no is), a törzsek Tcl scriptek. A parancs sorra értékeli ki a feltételeket, és az első teljesülő feltételhez tartozó törzset hajtja végre. Ha egyik feltétel sem teljesül, és van else-ág, végrehajtja annak törzsét. Az if parancs visszatérési értéke az üres string lesz, ha egyik feltétel sem teljesült és nincsen else-ág, egyébként a végrehajtott törzs visszatérési értéke (azaz a törzs utolsó utasításának visszatérési értéke) lesz a visszatérési érték.

A then és else argumentumokat nem kötelező megadni, de növelik az olvashatóságot. Tetszőleges számú elseif-ágat adhatunk meg, beleértve, hogy egyet sem.

switch ?kapcsolók? string minta törzs ?minta törzs ...? switch ?kapcsolók? {string minta törzs ?minta törzs ...?}
A switch parancs string és minta argumentumai stringek, törzs argumentumai Tcl scriptek. A parancs stringet rendre a mintákra illeszti, és az első illeszkedő mintához tartozó törzset hajtja végre. A végrehajtott törzs visszatérési értékét adja vissza. Ha az utolsó minta default, akkor az minden stringre illeszkedik. Ha string nem illeszkedik egyik mintára sem, a switch parancs üres stringgel tér vissza.

A parancsnevet közvetlenül követő, kötőjellel ('-') kezdődő argumentumok a switch parancs működését szabályozó kapcsolók. A következőket használhatjuk:

-exact
A stringnek azonosnak kell lennie a mintával. Ez az alapértelmezés.
-glob
A minta a string match parancsban megengedett minta, és az illesztés ennek értelmében történik.
-regexp
A minta egy reguláris kifejezés, és az illesztés a regexp parancsnak megfelelő.
--
A kapcsolók sorának végét jelzi. A következő argumentum már nem számít kapcsolónak, még ha kötőjellel kezdődik is.
A switch parancs használatakor választhatunk, hogy a mintákat és a törzseket külön-külön argumentumként, vagy egyetlen argumentumként, egy listában adjuk meg. Előbbit akkor célszerű alkalmazni, ha helyettesítésekre van szükség a minták vagy törzsek némelyikén. Utóbbinak előnye, hogy egyszerűen több sorba írható.

Ciklusok

while feltétel törzs
A wile parancs feltétel argumentuma logikai értéket adó kifejezés, törzs Tcl script. A parancs addig ismétli feltétel kiértékelését és törzs végrehajtását, amíg feltétel hamis értéket nem ad. Ekkor a ciklus végrehajtása befejeződik (törzs már nem hajtódik végre). A while parancs üres stringet ad vissza.
for inicializáció feltétel léptetés törzs
A for parancs feltétel argumentuma logikai értéket adó kifejezés, a többi Tcl script. A parancs kezdetben végrehajtja az inicializációt. Ezt követően addig ismétli rendre feltétel kiértékelését, törzs végrehajtását és léptetés végrehajtását, amíg feltétel hamis értéket nem ad. Ekkor a parancs végrehajtása befejeződik (törzs már nem hajtódik végre). A visszatérési érték üres string.
foreach változónév lista törzs
A foreach parancs argumentumai rendre egy változó neve, egy lista és egy Tcl script. A parancs a lista elemeit sorrend szerint értékül adja a megadott változónak és végrehajtja törzset. A visszatérési érték üres string.
break
A break parancs ciklusok törzsén belül adható ki. Hatására a ciklus végrehajtása azonnal befejeződik.

A break parancs valójában TCL_BREAK kivétellel tér vissza, amelyet normális esetben a ciklust megvalósító parancs kezel le. A kivételt azonban elfoghatja más is, például egy catch parancs vagy egy eljárás törzsének vége.

continue
A continue parancs szintén ciklusok törzsén belül adható ki. A ciklusmag hátrelevő részét átugorja (a végrehajtás while ciklusoknál a feltétel kiértékelésével, for ciklusoknál a léptetés végrehajtásával, foreach ciklusoknál a következő listaelemre állással folytatódik).

A continue parancs működése is kivételeken alapul, TCL_CONTINUE kivételt vált ki.

Stringben vagy fájlban adott scriptek végrehajtása

eval arg ?arg ...?
Az eval parancs argumentumait a concat parancsnak megfelelően konkatenálja, mint Tcl scriptet végrehajtja, és az eredményt (vagy kivételt) visszaadja.
uplevel ?szint? arg ?arg ...?
A megadott szinten hajtja végre a parancsot, amit az argumentumok konkatenációjából kap, és visszaadja az eredményt vagy a kivételt. Olyan, mintha az adott szinten eval arg-ot hajtottunk volna végre. Az alapértelmezett szint 1 (az eljárást hívó szintje). A szintek jelentését és leírását lásd az upvar parancsnál.
tcl8.0  
namespace eval namespace_neve arg ?arg ...?
A megadott namespace-ben értékeli ki. Hasonló az eval-hoz.
source fájlnév
A source parancs a megadott fájl tartalmát, mint Tcl scriptet végrehajtja, és az eredményt (vagy kivételt) visszaadja. A hullámmal ('~') kezdődő fájlneveket ugyanúgy kezeli, mint az open parancs.
Eljárások
A Tcl programozási nyelvben a proc paranccsal definiálhatunk eljárásokat.
proc név arg törzs
A proc név néven olyan parancsot hoz létre, amelynek végrehajtását a törzs script definiálja. Ha már létezik az adott néven parancs, az új definíció lép a régi helyébe. A proc parancs üres stringet ad vissza.

A formális paramétereket az arg argumentum specifikálja. Az arg egy lista, melynek minden eleme egy formális paramétert ír le. Egy formális paramétert egy egy- vagy kételemű lista ad meg. Az első listaelem a formális paraméter neve, az opcionális második pedig az alapértelmezés szerinti értéke. Az utolsó formális paraméter neve lehet a különleges jelentésű args, hozzá alapértelmezés nem adható meg.

Az eljárás meghívásakor a formális paraméterek lokális változóként jönnek létre, vagyis érték szerinti paraméterátadás valósul meg. Kezdőértékük a sorrendben nekik megfelelő aktuális paraméter, ennek híján az alapértelmezés szerinti érték lesz. Az aktuális paramétereknek le kell fedniük az alapértelmezéssel nem rendelkező formális paramétereket. Ha az utolsó formális paraméter az args, a formálisnál több aktuális paraméter is megadható, az args értéke ekkor olyan lista, amely a "maradék" aktuális paramétereket tartalmazza.

Az eljárástörzs végrehajtása során alapértelmezésben a globális változók nem láthatók, a hivatkozott változók lokálisak. Akkor jönnek létre, amikor először értéket adunk nekik, és az eljárás elhagyásakor automatikusan törlődnek. Nem lokális változókat a global és az upvar parancsok segítségével érhetünk el.

Az eljárás végrehajtása return paranccsal vagy a törzs utolsó parancsának végrehajtása után ér véget. A visszatérési érték előbbi esetben a return parancsban megadott string, utóbbi esetben pedig a törzs utolsó parancsának eredménye lesz.

global változónév ?változónév ...?
A global deklaráció jellegű parancs. Egy eljárástörzsben kiadva, a felsorolt változónevek az eljárás befejezéséig az azonos nevű globális változókra hivatkoznak. Visszatérési értéke üres string.
upvar ?szint? hivatkozott változónév ?hivatkozott változónév ...?
Az upvar parancs a global általánosítása, tetszőleges eljáráshívási szinten elhelyezkedő változóhoz rendelhetünk vele nevet. A relatív szintet nemnegatív egész szám adja meg, 0 az aktuális szintet, 1 az eljárást hívó szintjét, 2 a hívót hívó szintjét, és így tovább, jelenti. Abszolút szintre '#' karakterrel prefixelt számmal hivatkozhatunk, például #0 a globális szintet jelöli. A szint elhagyható, ha az első argumentum nem számjeggyel vagy kettőskereszt karakterrel kezdődik. Hivatkozott lehet egyszerű változó, tömb vagy tömbelem, de változónévnek egyszerű változónévnek kell lennie.

Az upvar-ral létrehozott változónév teljes értékű alternatívája az eredeti változónévnek. Például a hivatkozott változó (vagy tömbelem) az első értékadásnál jön létre, ha még nem létezik. Az unset parancs is magát a hivatkozott változót törli, nem a hivatkozást. A hivatkozás nem is szüntethető meg az eljárás elhagyása nélkül, legfeljebb átirányítható újabb upvar paranccsal.

Az upvar az egyetlen lehetőség, hogy hivatkozás szerinti paraméterátadást szimuláljunk Tcl-ben. Ehhez a hivatkozni kívánt változó nevét paraméterként átvesszük, majd egy upvar utasításban kapcsolatot teremtünk a változóval:

proc decr {name {value 1}} {     upvar 1 $name $name     incr $name [expr - $value] }
Nem okoz gondot - így fenti példában sem -, ha a hivatkozott változó neve a megadott szinten maga is global vagy upvar paranccsal létrehozott hivatkozás, hiszen ezek egyenértékűek a hivatkozott változó eredeti nevével.
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 felé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éterhozott 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 (alepé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.

Kiegészítések, módosítások: Sarlós Tamás, Nagy Viktor