User Tools

Site Tools


en:words:catch_throw

catch throw

sp@ ( – addr ) returns the address corresponding to the top of data stack.

rp@ ( – addr ) returns the address corresponding to the top of return stack.

sp! ( addr – ) sets the stack pointer to addr, thus restoring the stack depth to the same depth that existed just before addr was acquired by executing sp@.

rp! ( addr – ) sets the return stack pointer to addr. thus restoring the return stack depth to the same depth that existed just before addr was acquired by executing rp@.

Legend:

  • #exc = exeption number
  • i*x = any stack items underneath #exc
  • i*adr = any returnstack items above last catchframe
  • xt = execution address used inside of catch by EXECUTE
  • RS: = Return Stack Picture

Step by step explanation of CATCH

variable handler \ Most recent exception handler

\                                    Put catchframe on return stack.
\                                    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)  ;
  1. Build a catchframe for throw. Pass the exception number of the word executeted.
  2. Execution token XT is already on the stack.
  3. Save data stack pointer; exclude current xt on data stack.
  4. Save previous handler.
  5. Set current handler to this one. sp, hlr and handler are current catchframe now.
  6. Now execute the word passed in on the stack. It is now wrapped by your own exception handler, created with the word where you put your catch in.
  7. Execution comes back without exception. So restore previous handler.
  8. Discard saved data stack pointer.
  9. Signify normal completion by 0 on data stack.

Step by step explanation of THROW

\ TROW exits to saved context if exc# <> 0 
: 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) ;
  1. throw expects an exception numer on the stack, passing or dropping it, and its returnstack picture has a catchframe underneath the current returnaddresses.
  2. Get flag.
  3. Noop, don't throw 0.
  4. Return to saved return stack context.
  5. Restore previous handler.
  6. Get saved stack pointer.
  7. Ready to save #exc on return stack for use in step ( 9).
  8. Now save it
  9. Return to saved data stack context; we can see XT again now, but it's no use, so drop it.
  10. Pass exception number. We are ready to proceed error handling words compiled behind CATCH in calling word. The caling word is that which has the CATCH phrase in its compilat.

Intended use is:

\ enable "spam" to THROW an exeption number in case of exeption.
: spam ( -- ) ... #exc THROW ;

\ put "spam" into exception handling frame using CATCH
: sapm-exc ( i*x -- )
  ...
  ['] spam CATCH  ( -- #exc )
  dup 0= IF drop exit then \ = NOOP
  dup #exc = IF
    ...  \ known error code, do execption handling 
  else
    ... throw  \ unknown error code; re-throw system code
  then ;            

( finis)

en/words/catch_throw.txt · Last modified: 2013-06-06 21:26 (external edit)