TRY / CATCH

TRY / CATCH

Top  Previous  Next

 

The TRY/CATCH construct allows creation of exception handlers in a manner broadly similar to that of some other programming languages.

 

 

Format

 

TRY {statement}

{statements}

CATCH exception {qualifiers}{, exception {qualifiers}...}

{statements}

CATCH exception {qualifiers}{, exception {qualifiers}...}

{statements}

END

 

where

 

statement(s)are any executable QMBasic statements.

 

exceptionis an exception name. The name may optionally be enclosed in quotes. If unquoted, the name must comply with QMBasic name format rules.

 

qualifiersare chosen from:
DUMPINGGenerates a process dump file when the exception is thrown.
SAVING.STACKSets @EXCEPTION.STACK to contain the stack history in the same form as use of SYSTEM(1002). This can also be set by default by use of the EXCEPTION.SAVE.STACK option of the $MODE compiler directive.

 

A single TRY construct may have multiple CATCH clauses.

 

 

An exception is a named event, typically an error, raised within an application by use of the THROW statement. The actual name has no significance to QM but should ideally relate to the situation that the exception handles. Exception names are case insensitive and may be up to 63 characters.

 

A TRY/CATCH construct executes the statement(s) in the TRY clause, monitoring for named exceptions being thrown.

 

On throwing an exception, the application exits from all lower level programs, subroutines, etc and continues execution in the CATCH clause that handles this exception. Where an object oriented programming object is discarded by an exception, the DESTROY.OBJECT subroutine will be executed in the normal way.

 

Whilst execution of subroutines that return is acceptable within the TRY clause, it is essential that programs do not jump into or out of this clause. Failure to follow this rule may have undesirable results.

 

A single CATCH clause may catch multiple exception names. On arrival in the CATCH clause, the @EXCEPTION variable will contain the name of the exception that has been caught and the @EXCEPTION.DATA variable will contain any data associated with this exception. The @EXCEPTION.ORIGIN variable is set to a dynamic array in which field 1 holds the program name from which the exception was thrown and field 2 holds the line number in that program. If the program has no cross-reference tables, the line number will be -1.

 

If the exception name in the CATCH clause is followed by the DUMPING or SAVING.STACK options, the additional diagnostic data is generated when the exception is thrown, before unwinding the call stack to the exception handler.

 

 

Examples

 

LOOP

  READNEXT ACC.ID ELSE EXIT

  TRY

     CALL PROCESS.ACCOUNT

  CATCH ACCOUNT.INVALID

     DISPLAY 'Account ' : ACC.ID : ' is invalid'

  END

REPEAT

 

The above rather simple example shows a program fragment that processes successive items from a select list. If the PROCESS.ACCOUNT subroutine, or any lower level action called from it, throws an ACCOUNT.INVALID exception, the program will continue execution at the DISPLAY statement.

 

 

TRY

  CALL MYSUB

CATCH TERMINATE DUMPING

  DISPLAY 'Process status dumped'

END

 

The above example establishes an exception handler around a call to MYSUB. If the user defined TERMINATE exception occurs, a process dump file will be created prior to arrival in the CATCH clause.

 

 

A useful report of the call stack can be produced with the code fragment below executed from the CATCH clause. This is also available as a standard catalogued QMBasic subroutine named !EXC.STACK.

 

IF @EXCEPTION.STACK # '' THEN

  DISPLAY '     Program name..................  Addr..  Line'

  LEVEL = 1

  FOR EACH PROG IN @EXCEPTION.STACK DELIMITER @FM

     NAME = FMT(PROG<1,1>, '30L')

     DISPLAY FMT(LEVEL, 'R%3  ') :

     SUBDATA = FIELD(PROG<1>, @VM , 2, *)

     SUBADDR = VSLICE(SUBDATA, 0, 1)

     SUBLINE = VSLICE(SUBDATA, 0, 2)

     LOOP

        DISPLAY FMT(REMOVE(NAME, MORE.NAME), '30L') : '  ' :

        DISPLAY DTX(REMOVE(SUBADDR, MORE.ADDR), 6) : '  ' :

        DISPLAY REMOVE(SUBLINE, MORE.LINE)

     WHILE MORE.NAME OR MORE.ADDR OR MORE.LINE

        DISPLAY '     ' :

     REPEAT

 

     LEVEL += 1

  NEXT PROG

END

 

See also:

Exception handling, CAUGHT(), !EXC.STACK, THROW