====== catch throw ======
Schritt für Schritt durch catch den throw.
Hier zunächst die Begriffsklärung.
''sp@ ( -- addr )'' Zeiger auf den obersten Datenstackeintrag.
''rp@ ( -- addr )'' Zeiger auf den obersten Returnstackeintrag.
''sp! ( addr -- )'' Stellt den Datenstackzeiger auf addr ein. Damit wird die Tiefe des Datenstack auf den selben Wert eingestellt, der bestand unmittelbar bevor sp@ ausgeführt wurde.
''rp! ( addr -- )'' Stellt den Returnstackzeiger auf addr ein. Damit wird die Tiefe des Returnstack auf den selben Wert eingestellt, der bestand unmittelbar bevor sp@ ausgeführt wurde.
Die Abkürzungen bedeuten:
* #exc = (exeption number) Nummer der Ausnahme.
* i*x = alle Werte auf dem Stack unterhalb von #exc
* i*adr = alle Werte auf dem Returnstack oberhalb des letzten Rahmens für die Ausnahmen (catchframe).
* xt = Ausführbares Zeichen (execution address) das im catch drinnen mittels EXECUTE ausgeführt wird.
* RS: = Abbild des Returnstack
===== Schritt für Schritt durchs CATCH =====
variable handler \ Variable für den letzten Ausnahmefall.
\ Leg den Ausnahmerahmen hier an.
\ v v
: CATCH ( xt -- exc# | 0 ) ( 1) ( 2)
sp@ >r ( -- xt) ( RS: -- sp ) ( 3)
handler @ >r ( -- xt) ( RS: -- sp hlr ) ( 4)
rp@ handler ! ( -- xt) ( RS: -- sp hlr ) ( 5)
execute ( -- ) ( RS: -- sp hlr ) ( 6)
r> handler ! ( -- ) ( RS: -- sp ) ( 7)
r> drop ( -- ) ( RS: -- ) ( 8)
0 ( -- 0 ) ( 9) ;
- Erzeugt einen Rahmen damit das throw auf Ausnahmen reagieren kann. Gibt die gerade erzeugte Ausnahmenummer weiter.
- Das Ausführungssysmbol XT liegt schon auf dem Stack.
- Rettet den Datenstackzeiger; ohne das aktuelle xt.
- Rettet den vorherigen Ausnahmefall.
- Speichert den aktuellen Ausnahmefall.
- Führe das Wort aus das auf dem Stack liegt. Es ist nun geschützt in deiner Ausnahmeregelung eingebettet, die du in dem Wort machst, das catch enthält.
- Restauriere den alten Ausnahmefall.
- Verwerfe den Datenstackzeiger.
- Ziege an, das alles normal verlaufen ist, indem eine 0 auf den Datenstack gelegt wird.
===== Schritt für Schritt durchs THROW =====
\ TROW springt zum gesicherten Rahmen falls #exc <> 0 ist.
: THROW ( i*x exc# -- i*x exc# | i*x exc# ) ( RS: -- sp hlr i*adr ) ( 1)
dup 0= ( -- i*x exc# f ) ( RS: -- sp hlr i*adr ) ( 2)
if drop exit then ( -- i*x ) ( RS: -- sp hlr i*adr ) ( 3)
handler @ rp! ( -- i*x exc# ) ( RS: -- sp hlr ) ( 4)
r> handler ! ( -- i*x exc# ) ( RS: -- sp ) ( 5)
r> ( -- i*x exc# sp ) ( RS: -- ) ( 6)
swap ( -- i*x sp exc# ) ( RS: -- ) ( 7)
>r ( -- i*x sp ) ( RS: -- exc# ) ( 8)
sp! ( -- xt ) ( RS: -- exc# ) ( 9)
drop r> ( -- exc# ) ( RS: -- ) ( 10) ;
- THROW erwartet die Ausnahmenummer auf dem Stack, gibt sie weiter oder lässt sie fallen, und sein Returnstack hat einen Ausnahmerahmen unter all den derzeitigen Returnadressen.
- Flag holen.
- Noop - die 0 wird nicht weitergegeben.
- Zum sicheren Ausnahmerahmen gehen.
- Den vorherigen Ausnahmerahmen wieder herstellen.
- Den gesicherten Datenstackzieger holen.
- Datenstackzeiger restaurieren.
- ebenso
- ebenso
- Ausnahmenummer übermitteln. Bereit die Ausnahmeregelungen auszuführen, die hinter dem aufrufenden catch angelegt wurden.
===== Beispiel: =====
\ Ermögliche dem "spam" eine Ausnahmenummer weiter zu geben.
: spam ( -- ) ... #exc THROW ;
\ Schließe "spam" in eine Ausnahmeregelung ein.
: spam-exc ( i*x -- )
...
['] spam CATCH ( -- #exc )
dup 0= IF drop exit then \ = NOOP
dup #exc = IF
... \ Bekannte Ausnahme handhaben.
else
... throw \ unvorhergesehene Ausnahme weitergeben an das Forthsystem.
then ;
===== Bildergeschichte =====
{{words:s5_catch_throw.zip| Catch und Throw als Bildergeschichte}}
S5 Slide Show - downloaden, auspacken und dann die datei ''index.html'' mit dem browser starten.
( finis)