Node:Exception Handling, Previous:Calls and returns, Up:Control Structures
If a word detects an error condition that it cannot handle, it can
throw an exception. In the simplest case, this will terminate
your program, and report an appropriate error.
throw y1 .. ym nerror -- y1 .. ym / z1 .. zn error exception ``throw''
If nerror is 0, drop it and continue. Otherwise, transfer
control to the next dynamically enclosing exception handler, reset
the stacks accordingly, and push nerror.
Throw consumes a cell-sized error number on the stack. There are
some predefined error numbers in ANS Forth (see errors.fs). In
Gforth (and most other systems) you can use the iors produced by various
words as error numbers (e.g., a typical use of allocate is
allocate throw). Gforth also provides the word exception
to define your own error numbers (with decent error reporting); an ANS
Forth version of this word (but without the error messages) is available
in compat/except.fs. And finally, you can use your own error
numbers (anything outside the range -4095..0), but won't get nice error
messages, only numbers. For example, try:
-10 throw \ ANS defined -267 throw \ system defined s" my error" exception throw \ user defined 7 throw \ arbitrary number
exception addr u -- n gforth ``exception''
n is a previously unused throw value in the range
(-4095...-256). Consecutive calls to exception return
consecutive decreasing numbers. Gforth uses the string
addr u as an error message.
A common idiom to THROW a specific error if a flag is true is
this:
( flag ) 0<> errno and throw
Your program can provide exception handlers to catch exceptions. An
exception handler can be used to correct the problem, or to clean up
some data structures and just throw the exception to the next exception
handler. Note that throw jumps to the dynamically innermost
exception handler. The system's exception handler is outermost, and just
prints an error and restarts command-line interpretation (or, in batch
mode (i.e., while processing the shell command line), leaves Gforth).
The ANS Forth way to catch exceptions is catch:
catch ... xt -- ... n exception ``catch''
The most common use of exception handlers is to clean up the state when
an error happens. E.g.,
base >r hex \ actually the hex should be inside foo, or we h ['] foo catch ( nerror|0 ) r> base ! ( nerror|0 ) throw \ pass it on
A use of catch for handling the error myerror might look
like this:
['] foo catch CASE myerror OF ... ( do something about it ) ENDOF dup throw \ default: pass other errors on, do nothing on non-errors ENDCASE
Having to wrap the code into a separate word is often cumbersome,
therefore Gforth provides an alternative syntax:
TRY code1 RECOVER \ optional code2 \ optional ENDTRY
This performs Code1. If code1 completes normally, execution
continues after the endtry. If Code1 throws, the stacks are
reset to the state during try, the throw value is pushed on the
data stack, and execution constinues at code2, and finally falls
through the endtry into the following code.
try compilation -- orig ; run-time -- gforth ``try''
recover compilation orig1 -- orig2 ; run-time -- gforth ``recover''
endtry compilation orig -- ; run-time -- gforth ``endtry''
The cleanup example from above in this syntax:
base >r TRY hex foo \ now the hex is placed correctly 0 \ value for throw RECOVER ENDTRY r> base ! throw
And here's the error handling example:
TRY
foo
RECOVER
CASE
myerror OF ... ( do something about it ) ENDOF
throw \ pass other errors on
ENDCASE
ENDTRY
Programming style note:
As usual, you should ensure that the stack depth is statically known at
the end: either after the throw for passing on errors, or after
the ENDTRY (or, if you use catch, after the end of the
selection construct for handling the error).
There are two alternatives to throw: Abort" is conditional
and you can provide an error message. Abort just produces an
"Aborted" error.
The problem with these words is that exception handlers cannot
differentiate between different abort"s; they just look like
-2 throw to them (the error message cannot be accessed by
standard programs). Similar abort looks like -1 throw to
exception handlers.
ABORT" compilation 'ccc"' -- ; run-time f -- core,exception-ext ``abort-quote''
If any bit of f is non-zero, perform the function of -2 throw,
displaying the string ccc if there is no exception frame on the
exception stack.
abort ?? -- ?? core,exception-ext ``abort''
-1 throw.