< The optional Double-Number word set
The optional Facility word set >


9 The optional Exception word set

9.1 Introduction

9.2 Additional terms and notation

None.

9.3 Additional usage requirements

9.3.1 THROW values

The THROW values {-255...-1} shall be used only as assigned by this standard. The values {-4095...-256} shall be used only as assigned by a system.

Programs shall not define values for use with THROW in the range {-4095...-1}.

9.3.2 Exception frame

An exception frame is the implementation-dependent set of information recording the current execution state necessary for the proper functioning of CATCH and THROW. It often includes the depths of the data stack and return stack.

9.3.3 Exception stack

A stack used for the nesting of exception frames by CATCH and THROW. It may be, but need not be, implemented using the return stack.

9.3.4 Possible actions on an ambiguous condition

A system choosing to execute THROW when detecting one of the ambiguous conditions listed in table 9.1 shall use the throw code listed there.

See: 3.4.4 Possible actions on an ambiguous condition.

Table 9.1: THROW code assignments

Code Reserved for Code Reserved for

-1ABORT
-2ABORT"
-3stack overflow
-4stack underflow
-5return stack overflow
-6return stack underflow
-7do-loops nested too deeply during execution
-8dictionary overflow
-9invalid memory address
-10division by zero
-11result out of range
-12argument type mismatch
-13undefined word
-14interpreting a compile-only word
-15invalid FORGET
-16attempt to use zero-length string as a name
-17pictured numeric output string overflow
-18parsed string overflow
-19definition name too long
-20write to a read-only location
-21unsupported operation
(e.g., AT-XY on a too-dumb terminal)
-22control structure mismatch
-23address alignment exception
-24invalid numeric argument
-25return stack imbalance
-26loop parameters unavailable
-27invalid recursion
-28user interrupt
-29compiler nesting
-30obsolescent feature
-31>BODY used on non-CREATEd definition
-32invalid name argument (e.g., TO name)
-33block read exception
-34block write exception
-35invalid block number
-36invalid file position
-37file I/O exception
-38non-existent file
-39unexpected end of file
-40invalid BASE for floating point conversion
-41loss of precision
-42floating-point divide by zero
-43floating-point result out of range
-44floating-point stack overflow
-45floating-point stack underflow
-46floating-point invalid argument
-47compilation word list deleted
-48invalid POSTPONE
-49search-order overflow
-50search-order underflow
-51compilation word list changed
-52control-flow stack overflow
-53exception stack overflow
-54floating-point underflow
-55floating-point unidentified fault
-56QUIT
-57exception in sending or receiving a character
-58[IF], [ELSE], or [THEN] exception
-59ALLOCATE
-60FREE
-61RESIZE
-62CLOSE-FILE
-63CREATE-FILE
-64DELETE-FILE
-65FILE-POSITION
-66FILE-SIZE
-67FILE-STATUS
-68FLUSH-FILE
-69OPEN-FILE
-70READ-FILE
-71READ-LINE
-72RENAME-FILE
-73REPOSITION-FILE
-74RESIZE-FILE
-75WRITE-FILE
-76WRITE-LINE
-77Malformed xchar
-78SUBSTITUTE
-79REPLACES

9.3.5 Exception handling

There are several methods of coupling CATCH and THROW to other procedural nestings. The usual nestings are the execution of definitions, use of the return stack, use of loops, instantiation of locals and nesting of input sources (i.e., with LOAD, EVALUATE, or INCLUDE-FILE).

When a THROW returns control to a CATCH, the system shall un-nest not only definitions, but also, if present, locals and input source specifications, to return the system to its proper state for continued execution past the CATCH.

9.4 Additional documentation requirements

9.4.1 System documentation

9.4.1.1 Implementation-defined options

9.4.1.2 Ambiguous conditions

9.4.1.3 Other system documentation

9.4.2 Program documentation

9.5 Compliance and labeling

9.5.1 Forth-2012 systems

The phrase "Providing the Exception word set" shall be appended to the label of any Standard System that provides all of the Exception word set.

The phrase "Providing name(s) from the Exception Extensions word set" shall be appended to the label of any Standard System that provides portions of the Exception Extensions word set.

The phrase "Providing the Exception Extensions word set" shall be appended to the label of any Standard System that provides all of the Exception and Exception Extensions word sets.

9.5.2 Forth-2012 programs

The phrase "Requiring the Exception word set" shall be appended to the label of Standard Programs that require the system to provide the Exception word set.

The phrase "Requiring name(s) from the Exception Extensions word set" shall be appended to the label of Standard Programs that require the system to provide portions of the Exception Extensions word set.

The phrase "Requiring the Exception Extensions word set" shall be appended to the label of Standard Programs that require the system to provide all of the Exception and Exception Extensions word sets.

9.6 Glossary

9.6.1 Exception words

9.6.1.0875
CATCH
 
EXCEPTION
 
( i×x xt -- j×x 0 | i×x n )

Push an exception frame on the exception stack and then execute the execution token xt (as with EXECUTE) in such a way that control can be transferred to a point just after CATCH if THROW is executed during the execution of xt.

If the execution of xt completes normally (i.e., the exception frame pushed by this CATCH is not popped by an execution of THROW) pop the exception frame and return zero on top of the data stack, above whatever stack items would have been returned by xt EXECUTE. Otherwise, the remainder of the execution semantics are given by THROW.

See
This sample implementation of CATCH uses the non-standard words described below. They or their equivalents are available in many systems. Other implementation strategies, including directly saving the value of DEPTH, are possible if such words are not available.

SP@
( -- addr )
returns the address corresponding to the top of data 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 )
returns the address corresponding to the top of return stack.

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@.

VARIABLE HANDLER 0 HANDLER ! \ last exception handler

: CATCH ( xt -- exception# | 0 \ return addr on stack
   SP@ >R             ( xt )       \ save data stack pointer
   HANDLER @ >R       ( xt )       \ and previous handler
   RP@ HANDLER !      ( xt )       \ set current handler
   EXECUTE            ( )          \ execute returns if no THROW
   R> HANDLER !       ( )          \ restore previous handler
   R> DROP            ( )          \ discard saved stack ptr
    0                 ( 0 )        \ normal completion
;

In a multi-tasking system, the HANDLER variable should be in the per-task variable area (i.e., a user variable).

This sample implementation does not explicitly handle the case in which CATCH has never been called (i.e., the ABORT behavior). One solution would be to execute a CATCH within QUIT, so that there is always an "exception handler of last resort" present, as shown in E.6.1.2050 QUIT.

9.6.1.2275
THROW
 
EXCEPTION
 
( k×x n -- k×x | i×x n )

If any bits of n are non-zero, pop the topmost exception frame from the exception stack, along with everything on the return stack above that frame. Then restore the input source specification in use before the corresponding CATCH and adjust the depths of all stacks defined by this standard so that they are the same as the depths saved in the exception frame (i is the same number as the i in the input arguments to the corresponding CATCH), put n on top of the data stack, and transfer control to a point just after the CATCH that pushed that exception frame.

If the top of the stack is non zero and there is no exception frame on the exception stack, the behavior is as follows:

If n is minus-one (-1), perform the function of 6.1.0670 ABORT (the version of ABORT in the Core word set), displaying no message.

If n is minus-two, perform the function of 6.1.0680 ABORT" (the version of ABORT" in the Core word set), displaying the characters ccc associated with the ABORT" that generated the THROW.

Otherwise, the system may display an implementation-dependent message giving information about the condition associated with the THROW code n. Subsequently, the system shall perform the function of 6.1.0670 ABORT (the version of ABORT in the Core word set).

See
If THROW is executed with a non zero argument, the effect is as if the corresponding CATCH had returned it. In that case, the stack depth is the same as it was just before CATCH began execution. The values of the i×x stack arguments could have been modified arbitrarily during the execution of xt. In general, nothing useful may be done with those stack items, but since their number is known (because the stack depth is deterministic), the application may DROP them to return to a predictable stack state.

Typical use:

: could-fail ( -- char )
   KEY DUP [CHAR] Q = IF 1 THROW THEN ;

: do-it ( a b -- c) 2DROP could-fail ;

: try-it ( --)
   1 2 ['] do-it CATCH IF
   ( x1 x2 ) 2DROP ." There was an exception" CR
   ELSE ." The character was " EMIT CR
   THEN
;

; retry-it ( -- )
   BEGIN 1 2 ['] do-it CATCH WHILE
   ( x1 x2) 2DROP ." Exception, keep trying" CR
   REPEAT ( char )
   ." The character was " EMIT CR
;

This is the counter part to E.9.6.1.0875 CATCH.

: THROW ( ??? exception# -- ??? exception# )
    ?DUP IF          ( exc# )     \ 0 THROW is no-op
      HANDLER @ RP!   ( exc# )     \ restore prev return stack
      R> HANDLER !    ( exc# )     \ restore prev handler
      R> SWAP >R      ( saved-sp ) \ exc# on return stack
      SP! DROP R>     ( exc# )     \ restore stack
      \ Return to the caller of CATCH because return
      \ stack is restored to the state that existed
       \ when CATCH began execution
    THEN
;
DECIMAL

: t1 9 ;
: c1 1 2 3 ['] t1 CATCH ;
T{ c1 -> 1 2 3 9 0 }T    \ No THROW executed

: t2 8 0 THROW ;
: c2 1 2 ['] t2 CATCH ;
T{ c2 -> 1 2 8 0 }T    \ 0 THROW does nothing

: t3 7 8 9 99 THROW ;
: c3 1 2 ['] t3 CATCH ;
T{ c3 -> 1 2 99 }T    \ Restores stack to CATCH depth

: t4 1- DUP 0> IF RECURSE ELSE 999 THROW -222 THEN ;
: c4 3 4 5 10 ['] t4 CATCH -111 ;
T{ c4 -> 3 4 5 0 999 -111 }T        \ Test return stack unwinding

: t5 2DROP 2DROP 9999 THROW ;
: c5 1 2 3 4 ['] t5 CATCH           \ Test depth restored correctly
   DEPTH >R DROP 2DROP 2DROP R> ;    \ after stack has been emptied
T{ c5 -> 5 }T

9.6.2 Exception extension words

9.6.2.0670
ABORT
 
EXCEPTION EXT
 
Extend the semantics of 6.1.0670 ABORT to be: ( i×x -- ) ( R: j×x -- )

Perform the function of -1 THROW.

See
: ABORT -1 THROW ;

9.6.2.0680
ABORT"
abort-quote
EXCEPTION EXT
 
Extend the semantics of 6.1.0680 ABORT" to be:
Interpretation
Interpretation semantics for this word are undefined.

Compilation
( "ccc<quote>" -- )

Parse ccc delimited by a " (double-quote). Append the run-time semantics given below to the current definition.

Run-time
( i×x x1 -- | i×x ) ( R: j×x -- | j×x )

Remove x1 from the stack. If any bit of x1 is not zero, perform the function of -2 THROW, displaying ccc if there is no exception frame on the exception stack.

See
DECIMAL
-1 CONSTANT exc_abort
-2 CONSTANT exc_abort"
-13 CONSTANT exc_undef
: t6 ABORT ;

The 77 in t10 is necessary for the second ABORT" test as the data stack is restored to a depth of 2 when THROW is executed. The 77 ensures the top of stack value is known for the results check.

: t10 77 SWAP ABORT" This should not be displayed" ;
: c6 CATCH
   CASE exc_abort OF 11 ENDOF
        exc_abort" OF 12 ENDOF
        exc_undef OF 13 ENDOF
   ENDCASE
;

T{ 1 2 '  t6 c6 -> 1 2 11  }T    \ Test that ABORT is caught
T{ 3 0 ' t10 c6 -> 3 77    }T    \ ABORT" does nothing
T{ 4 5 ' t10 c6 -> 4 77 12 }T    \ ABORT" caught, no message



< The optional Double-Number word set
The optional Facility word set >