[an error occurred while processing this directive]

HP OpenVMS Systems Documentation

Content starts here

HP BASIC for OpenVMS
User Manual


Previous Contents Index


Chapter 15
Handling Run-Time Errors

The process of detecting and correcting errors that occur when your program is running is called error handling. This chapter describes default error handling and how to handle HP BASIC run-time errors with your own error handlers.

Throughout this chapter, the term "error" is used to imply any OpenVMS exception, not only an exception of ERROR severity.

15.1 Default Error Handling

HP BASIC provides default run-time error handling for all programs. If you do not provide your own error handlers, the default error handling procedures remain in effect throughout program execution time.

When an error occurs in your program, HP BASIC diagnoses the error and displays a message telling you the nature and severity of the error. There are four severity levels of HP BASIC errors: SEVERE, ERROR, WARNING, and INFORMATIONAL. The severity of an error determines whether or not the program aborts if the error occurs when default error handling is in effect. When default error handling is in effect, ERROR and SEVERE errors always terminate program execution, but program execution continues when WARNING and INFORMATIONAL errors occur.

To override the default error handling procedures, you can provide your own error handlers, as described in the following sections. (Note that you should not call LIB$ESTABLISH from a HP BASIC program as this RTL routine overrides the default error handling procedures and might adversely affect program behavior.)

Only one error can be handled at a time. If an error has occurred but has not yet been handled completely, that error is said to be pending. When an error is pending and a second error occurs, program execution always terminates immediately. Therefore, one of the most important functions of an error handler is to clear the error so that subsequent errors can also be handled.

If you do not supply your own error handler, program control passes to the HP BASIC error handler when an error occurs. For example, when HP BASIC default error handling is in effect, a program will abort when division by zero is attempted because division by zero is an error of SEVERE severity. With an error handler, you can include an alternative set of instructions for the program to follow; if the zero was input at a terminal, a user-written error handler could display a "Try again" message and execute the program lines again requesting input.

15.2 User-Supplied Error Handlers

It is good programming practice to anticipate certain errors and provide your own error handlers for them. User-written error handlers allow you to handle errors for a specified block of program statements as well as complete program units. Any program module can contain one or more error handlers. These error handlers test the error condition and include statements to be executed if an error occurs.

To provide your own error handlers, you use WHEN ERROR constructs. A WHEN ERROR construct consists of two blocks of code: a protected region and a handler. A protected region is a block of code that is monitored by the compiler for the occurrence of an error. A handler is the block of code that receives program control when an error occurs during the execution of the statements in the protected region.

There are two forms of WHEN ERROR constructs; in both cases the protected region begins immediately after a WHEN ERROR statement. The following partial programs illustrate each form. In Example 1, the handler is attached to the protected region, while in Example 2, the handler catch_handler is detached and must be provided elsewhere in the program unit.

Example 1


WHEN ERROR IN
     protected_statement_1
     protected_statement_2
     .
     .
     .
 USE
     handler_statement_1
     handler_statement_2
     .
     .
     .
END WHEN

Example 2


WHEN ERROR USE catch_handler
     protected_statement_1
     protected_statement_2
     .
     .
     .
END WHEN

HANDLER catch_handler
     handler_statement_1
     handler_statement_2
     .
     .
     .
END HANDLER

The following sections further explain the concepts of protected regions and handlers.

15.2.1 Protected Regions

A protected region is a block of code that is monitored by the compiler for the occurrence of an error. The bounds of this region are determined by the actual ordering of the source code. Statements that are lexically between a WHEN ERROR statement and a USE or END WHEN statement are in the protected region.

If an error occurs inside the protected region, control passes to the error handler associated with the WHEN ERROR statement. When an error occurs beyond the limits of a protected region, default error handling is in effect unless other error handlers are provided. For more details about handler priorities, see Section 15.2.3 and Section 15.3.

The WHEN ERROR statement signals the start of a block of protected statements. The WHEN ERROR statement also specifies the handler to be used for any errors that occur inside the protected region. The keyword USE either explicitly names the associated handler for the protected region, or marks the start of the actual handler statements. The statements in the actual error handler receive control only if an error occurs in the protected region.

The following example prompts the user for two integer values and displays their sum. The WHEN ERROR block traps any invalid input values, displays a message telling the user that the input was invalid, and reprompts the user for input.


DECLARE INTEGER value_1, value_2

WHEN ERROR IN
     INPUT "PLEASE INPUT 2 INTEGERS"; value_1, value_2 !protected statement
USE
     PRINT "INVALID INPUT - PLEASE TRY AGAIN" !handler statement
     RETRY                                    !handler statement
END WHEN
PRINT "THEIR SUM IS"; value_1 + value_2

Protected regions can be nested; a protected region can be within the bounds of another protected region. However, WHEN ERROR statements cannot appear inside an error handler, and protected regions cannot cross over into other block structures. If you are using a WHEN ERROR block with a detached handler, that handler cannot exist within a protected region.

15.2.2 Handlers

A handler is the block of code containing instructions to be executed only when an error occurs during the execution of statements in the protected region. When an error occurs during the execution of a protected region, HP BASIC branches to the handler you have supplied. In turn, the handler processes the error. An error handler typically performs the following functions:

  • Determines which error occurred
  • Takes appropriate action based on the nature of the error
  • Clears the error condition with a RETRY, CONTINUE, END WHEN, or END HANDLER statement
  • Continues program execution when possible
  • Possibly identifies which program unit or statement caused the error
  • Resignals errors with EXIT HANDLER (when an error cannot be handled for some reason)

Handlers can be attached to, or detached from, the statements in the WHEN ERROR protected region.

An attached handler is delimited by a USE and an END WHEN statement. The attached handler immediately follows the protected region of a WHEN ERROR IN block. The following example shows an attached handler that traps errors on I/O statements, division by zero, and illegal numbers:


PROGRAM accident_prone
 DECLARE REAL age, accidents, rating
 WHEN ERROR IN
 Get_age:
      INPUT "Enter your age";age
      INPUT "How many serious accidents have you had";accidents
      rating = accidents/age
      PRINT "That's ";rating;" serious accidents per year!"
 USE
      SELECT ERR
         !Trap division by zero
         CASE = 61
                  PRINT "Please enter an age greater than 0"
                  CONTINUE Get_age
         !Trap illegal number
         CASE = 52
                  PRINT "Please enter a positive number"
                  RETRY
         CASE ELSE
              !Revert to default error handling
              EXIT HANDLER
      END SELECT
 END WHEN
END PROGRAM

A detached handler is defined separately in your program unit. It requires an identifier and must be delimited by a HANDLER and an END HANDLER statement. Handler names must be valid HP BASIC identifiers and cannot be the same as the identifier for any label, PROGRAM name, DEF or DEF* function, SUB, FUNCTION, or PICTURE subprogram. The main advantage of using a detached handler is that it can be referenced by more than one WHEN ERROR USE statement. The following example shows a simple detached handler:


 WHEN ERROR USE catcher
   KILL "INPUT.DAT"

 END WHEN
   .
   .
   .
 HANDLER catcher
   !Catch if file does not exist
   IF ERR = 5
      THEN CONTINUE
   END IF
 END HANDLER

The statements within a handler are never executed if an error does not occur or if no protected region exists for the statement that caused the exception.

When your program generates an error, control transfers to the specified handler. If the code in an error handler generates a second error, control returns to the default HP BASIC error handler and program execution ends, usually with the first error only partly processed. To avoid the possibility of your error handler causing a second error, you should keep handlers as simple as possible and keep operations that might cause errors outside the handler.

Your handler can include conditional expressions to test the error and branch accordingly, as shown in the following example:


PROGRAM Check_records
WHEN ERROR USE Global_handler
   .
   .
   .
END WHEN
HANDLER Global_handler
 SELECT ERR
        !Trap buffer overflow
        CASE = 161
            PRINT "Record too long"
            CONTINUE
        !Trap end of file on device
        CASE = 11
            PRINT "End of file"
            CONTINUE
        CASE ELSE
            EXIT HANDLER
 END SELECT
END HANDLER
CLOSE #1%
END PROGRAM

Note that ON ERROR statements are not allowed within protected regions or handlers. For compatibility issues related to ON ERROR statements, see Section 15.3.

15.2.3 Exiting from Handlers

After processing an error, a handler typically clears the error so that program execution can continue. HP BASIC provides the following statements that clear the error condition and exit from the handler:

RETRY
CONTINUE
END HANDLER
END WHEN

These statements differ from each other in that they revert control of program execution to different points in the program. Examples of these statements are included in the following sections.

An additional statement, EXIT HANDLER, is provided to allow you to exit from a handler with the error still pending.

The END HANDLER statement identifies the end of the block of statements in the handler. The END WHEN statement marks the end of the protected region when a detached handler is used; it marks the end of the handler when an attached handler is used. If the handler does not process an error with an EXIT HANDLER, RETRY, or CONTINUE statement, the error is cleared by the END HANDLER or END WHEN statement; however, processing continues with the statement immediately after the protected region (and the attached handler, if one exists) where the error occurred. These statements do not return control to the protected region. This is known as "falling out of the bottom of a handler." Be careful not to fall out of the bottom of a handler unintentionally.

Note that you cannot exit from a handler with the following statements:

  • EXIT PROGRAM
  • EXIT FUNCTION
  • EXIT SUB
  • EXIT DEF
  • GOSUB (with a target outside the handler)
  • GOTO (with a target outside the handler)

Also, you cannot exit from a handler with a RESUME statement. The RESUME statement is valid only in blocks of code referred to by ON ERROR statements. Section 15.3 describes the ON ERROR statements.

15.2.3.1 RETRY Statement

You use the RETRY statement to clear the error and to execute the statement again that caused the error again. Be sure to take corrective action before trying the protected statement again. For example:


DECLARE REAL radius

WHEN ERROR USE fix_it
     INPUT "Please supply the radius of the circle"; radius
END WHEN
HANDLER fix_it
     !trap overflow error
     IF ERR = 48
     PRINT "Please supply a smaller radius"
     RETRY
END HANDLER
PRINT "The circumference of the circle is "; 2*PI*radius

In FOR...NEXT loops, if the error occurs while HP BASIC is evaluating the limit or increment values, RETRY reexecutes the FOR statement; if the error occurs while HP BASIC is evaluating the index variable, RETRY reexecutes the NEXT statement. In UNTIL...NEXT and WHILE...NEXT loops, if the error occurs while HP BASIC is evaluating the relational expression, RETRY reexecutes the NEXT statement.

15.2.3.2 CONTINUE Statement

You can use the CONTINUE statement to clear the error and cause execution to continue at the statement immediately following the propagated error.

When the CONTINUE statement is within an attached handler, you can specify a target. The target can be a line number or label within the bounds of the associated protected region, in a surrounding protected region, or within an unprotected region; however, you must specify a target within the current program module. You cannot specify a target for the CONTINUE statement when it is in a detached handler. For example:


DIM LONG her_attributes(10),his_attributes(10)
DECLARE INTEGER counter
WHEN ERROR USE fix_it
  DATA 12,2,35,21,25.5,32,32,30,15,4
  FOR counter = 0 TO 12
      READ her_attributes(counter)
  NEXT counter
  MAT his_attributes = her_attributes
END WHEN
   .
   .
   .
HANDLER fix_it
    !Trap out of data
    IF ERR = 57
       THEN RESTORE
            CONTINUE
    ELSE EXIT HANDLER
    END IF
END HANDLER

When a DEF function is invoked from a protected region and an error occurs that has not been handled, a CONTINUE statement with no target causes execution to resume at the statement following the one that invoked the function.

Note that if an error occurs in a loop control statement or SELECT or CASE statement, the CONTINUE statement causes HP BASIC to resume execution at the statement following the end of the loop structure (the NEXT, END CASE, or END SELECT statements).

Note

When you use the RETRY or the CONTINUE statement without a target, the compiler builds read only tables in the generated object file with information about statements in the associated protected regions. Therefore, when space is extremely critical, do not protect large regions with handlers containing RETRY or CONTINUE without a specified target.

15.2.3.3 EXIT HANDLER Statement

Unlike RETRY and CONTINUE, the EXIT HANDLER statement does not clear the error; rather, it allows you to exit from the handler with the error pending. This allows you to pass an error to the handler associated with the next outer protected region, or back to HP BASIC default error handling, or to the calling procedure.

When an error occurs within a nested protected region, control passes to the handler associated with the innermost protected region in which the error occurred. If the innermost handler does not handle the error, the error is passed to the next outer handler with the EXIT HANDLER statement. All handlers for any outer WHEN ERROR blocks are processed before reverting to default error handling or resignaling the calling procedure.

The following example shows two nested protected regions. Neither handler traps division by zero. If division by zero occurs, the handler associated with the innermost protected region, inner_handler, does not clear the error; therefore, the error is passed to the handler associated with the next outer protected region. Outer_handler does not clear this error either, and so the error is passed to the default error handler. This error is fatal and the program ends abnormally. Output is specific to VAX BASIC.


PROGRAM nesting
 OPTION TYPE = EXPLICIT
 DECLARE LONG divisor
 DECLARE REAL dividend, quotient
 WHEN ERROR USE outer_handler
      INPUT "Enter divisor";Divisor
      INPUT "Enter dividend";Dividend

      WHEN ERROR USE inner_handler
           Quotient = Dividend/Divisor
           PRINT "The quotient is ";Quotient
      END WHEN

 END WHEN
 HANDLER outer_handler
         !Trap data format error
         IF ERR = 50
            THEN
            PRINT "Illegal input...try again"
            RETRY
            ELSE PRINT "In outer_handler"
                 PRINT "Reverting to default handling now"
                 EXIT HANDLER
         END IF
 END HANDLER
 HANDLER inner_handler
         !Trap overflow/decimal error
         IF ERR = 181
            THEN CONTINUE
            ELSE PRINT "Inside inner_handler"
                 PRINT "Reverting to outer handler now"
                 EXIT HANDLER
         END IF
 END HANDLER
END PROGRAM

For more information about exiting program units while an error is pending, see Section 15.2.6.

15.2.4 Selecting the Severity of Errors to Handle

The OPTION HANDLE statement lets you specify the severity level of errors that are to be handled by an error handler in addition to the BASIC errors that can normally be handled or trapped. You can specify any one of the following error severity levels: BASIC, SEVERE, ERROR, WARNING, or INFORMATIONAL.

OPTION HANDLE = BASIC is the default, which is in effect if you do not specify an alternative in the OPTION HANDLE statement. Only HP BASIC errors that can be trapped transfer control to the current error handler when this option is in effect. Refer to Appendix B to determine which BASIC errors cannot be trapped.

When you specify an error severity level other than BASIC in the OPTION HANDLE statement, the following errors will transfer control to the error handler:

  • All BASIC errors that can be trapped of this or lesser severity
  • All non-BASIC errors of this or lesser severity
  • BASIC errors of this or lesser severity that normally cannot be trapped

For example, if you specify OPTION HANDLE = ERROR, you can handle all BASIC and non-BASIC errors of ERROR severity (both those that can and those that cannot be trapped), and all WARNING and INFORMATIONAL errors, but no SEVERE errors.

15.2.5 Identifying Errors

HP BASIC provides several built-in functions that return information about an error. You can use these functions inside your error handlers to determine details about the error and conditionally handle these errors. These functions include:

ERR
ERL
ERN$
ERT$
VMSSTATUS
RMSSTATUS

Note that if an error occurs in your program that is not a HP BASIC error or does not map onto a HP BASIC error, it is signaled as NOTBASIC ("Not a BASIC error" (ERR=194). In this case, you can use the built-in function VMSSTATUS to determine what caused the error.

15.2.5.1 Determining the Error Number (ERR)

You use the ERR function to return the number of the last error that occurred. Appendix B lists the number of each HP BASIC run-time error---for example, ERR 153 is "RECALREXI, Record already exists."


OPTION HANDLE = ERROR
WHEN ERROR USE find_error
   .
   .
   .
END WHEN

HANDLER find_error
  SELECT ERR
        !Record already exists
        CASE = 153
                PRINT "Choose new record"
                CONTINUE
        CASE ELSE
                EXIT HANDLER
  END SELECT

END HANDLER

The results of ERR remain undefined until an error occurs. Although ERR remains defined as the number of the last error after control leaves the error handler, it is poor programming practice to refer to this variable outside the scope of an error handler.

15.2.5.2 Determining the Error Line Number (ERL)

After your program generates an error, the ERL function returns the BASIC line number of the signaled error. This function is valid only in line-numbered programs. The ERL function, like ERR, lets you set up branching to one of several paths in the code.

In the following example, the handler continues execution at different points in the program, depending on the value of ERL:


10 DECLARE INTEGER CONSTANT TRUE = -1
20 WHEN ERROR USE err_handler
   .
   .
   .
900 END WHEN
1000 HANDLER err_handler
       SELECT TRUE
           CASE (ERR = 11) AND (ERL = 790)
               !Is error end of file at line 790?
               PRINT "Completed"
               CONTINUE
           CASE (ERR = 149) AND (ERL = 80)
               !Is error not at end of file on line 80?
               PRINT "CHECK ACCESS MODE"
               CONTINUE
           CASE ELSE
               !Let BASIC handle any other errors
               EXIT HANDLER
1500   END SELECT
2000 END HANDLER
32000   CLOSE #5
32767   END

The results of ERL are undefined until an error occurs, or if the error occurs in a subprogram not written in HP BASIC. Although ERL remains defined as the line number of the last error even after control leaves the error handler, it is poor programming practice to refer to this variable outside the scope of an error handler.

If you reference ERL in a compilation unit with line numbers, code and data are included in your program to allow HP BASIC to determine ERL when an exception occurs. If you do not need to reference ERL, you can save program size and reduce execution time by compiling your program with the /NOLINE qualifier. Alpha BASIC uses the /NOLINE qualifier by default to compile programs. Even if you do not use any line numbers, you can reduce execution time by compiling with the /NOLINE qualifier.

If an error occurs in a subprogram containing line numbers, HP BASIC sets the ERL variable to the subprogram line number where the error was detected. If the subprogram also executes an EXIT HANDLER statement, control passes back to the outer procedure's handler. The error is assumed to occur on the statement where the call or invocation occurs.


Previous Next Contents Index