HP OpenVMS Systems Documentation

Content starts here

Guide to the DEC Text Processing Utility


Previous Contents Index

4.9.4.14 Error Handling

A block of code starting with ON_ERROR and ending with ENDON_ERROR defines the actions that are to be taken when a procedure fails to execute successfully. Such a block of code is called an error handler. An error handler is an optional part of a DECTPU procedure or program. An error handler traps WARNING and ERROR status values. (See SET (INFORMATIONAL) and SET (SUCCESS) in the DEC Text Processing Utility Reference Manual for information on handling informational and success status values.)

It is good programming practice to put an error handler in all but the simplest procedures. However, if you omit the error handler, DECTPU's default error handling behavior is as follows:

  • If you press Ctrl/C, DECTPU places an error message in the message buffer, exits from all currently active procedures (in their reverse calling order), and returns to the "wait for next key" loop.
  • If an error or warning is generated during a CALL_USER routine, ERROR is set to the keyword that represents the failure status of the routine, ERROR_LINE is set to the line number of the error, and ERROR_TEXT is set to the message associated with the error or warning. DECTPU places the message in the message buffer, then resumes execution at the statement after the statement that generated the error or warning.
  • For other errors and warnings, ERROR is set to the keyword that represents the error or warning, ERROR_LINE is set to the line number of the error, and ERROR_TEXT is set to the message associated with the error or warning. DECTPU places the message in the message buffer, then resumes execution at the statement after the statement that generated the error or warning.

In a procedure, the error handler must be placed at the beginning of a procedure---after the procedure parameter list, the LOCAL or CONSTANT declarations, if present, and before the body of the procedure. In a program, the ON_ERROR language statements must be placed after all the global declarations (PROCEDURE, CONSTANT, and VARIABLE) and before any executable statements. Error statements can contain any DECTPU language statements except other ON_ERROR statements.

There are three DECTPU lexical elements that are useful in an error handler: ERROR, ERROR_LINE, and ERROR_TEXT.

ERROR returns a keyword for the error or warning. The DEC Text Processing Utility Reference Manual includes information on the possible error and warning keywords that each built-in procedure can return.

ERROR_LINE returns the line number at which the error or warning occurs. If a procedure was compiled from a buffer or range, ERROR_LINE returns the line number within the buffer. (This may be different from the line number within the procedure.) If the procedure was compiled from a string, ERROR_LINE returns 1.

ERROR_TEXT returns the text of the error or warning, exactly as DECTPU would display it in the message buffer, with all parameters filled in.

After the execution of an error statement, you can choose where to resume execution of a program. The options are the following:

  • ABORT---This language statement causes an exit back to the DECTPU "wait for next key" loop.
  • RETURN---This language statement stops the execution of the procedure in which the error occurred but continues execution of the rest of the program.

If you do not specify ABORT or RETURN, the default is to continue executing the program from the point at which the error occurred.

DECTPU provides two forms of error handler: procedural and case style.

4.9.4.15 Procedural Error Handlers

If a WARNING status is trapped by an ON_ERROR statement, the warning message is suppressed. However, if an ERROR status is trapped, the message is displayed. With the ON_ERROR trap, you can do additional error handling after the DECTPU message is displayed.

Syntax


ON_ERROR statement_1; statement_2; . . . statement_n; ENDON_ERROR;

Example 4-10 shows error statements at the beginning of a procedure. These statements return control to the caller if the input on the command line of an interface is not correct. Any warning or error status returned by a statement in the body of the procedure causes the error statements to be executed.

Example 4-10 Procedure That Uses the ON_ERROR Statement

!
! Gold 7 emulation (command line processing)
!
PROCEDURE command_line

LOCAL
   line_read, X;

ON_ERROR
    MESSAGE ("Unrecognized command: " + line_read);
    RETURN;
ENDON_ERROR;
!
! Get the command(s) to execute
!
line_read := READ_LINE ("DECTPU Statement: "); ! get line from user
!
! compile them

!
IF line_read <> ""
THEN
    X := COMPILE (line_read);
ELSE
    RETURN
ENDIF;
!
! execute
!
IF X <> 0
THEN
    EXECUTE (X);
ENDIF;

ENDPROCEDURE;

The effects of a procedural error handler are as follows:

  • If you press Ctrl/C, DECTPU places an error message in the message buffer, exits from all currently active procedures (in their reverse calling order), and returns to the "wait for next key" loop.
  • If an error or warning is generated during a CALL_USER routine, ERROR is set to a keyword that represents the failure status of the routine, ERROR_LINE is set to the line number of the error, and ERROR_TEXT is set to a warning or error message that is placed in the message buffer. Finally, DECTPU runs the error handler code.
  • For other warnings and errors, ERROR is set to a keyword that represents the error or warning, ERROR_LINE is set to the line number of the error, and ERROR_TEXT is set to the error or warning message associated with the keyword. DECTPU places error messages in the message buffer but suppresses the display of warning messages. Finally, DECTPU runs the error handler code.

If an error or warning is generated during execution of a procedural error handler, DECTPU behaves as follows:

  • If you press Ctrl/C during the error handler, DECTPU puts an error message in the message buffer, exits from all currently active procedures (in their reverse calling order), and returns to the "wait for next key" loop.
  • For other errors and warnings, the appropriate error or warning message is written to the message buffer. DECTPU resumes execution at the next statement after the statement that generated the error.

4.9.4.16 Case-Style Error Handlers

Case-style error handlers provide a number of advantages over procedural error handlers. With case-style error handlers, you can do the following:

  • Suppress the automatic display of both warning and error status messages
  • Trap the TPU$_CONTROLC status
  • Write clearer code

Syntax

ON_ERROR [condition_1]: statement_1;... [condition_2]: statement_2;... . . .
[condition_n]: statement_n; ENDON_ERROR;

You can use the [OTHERWISE] selector alone in an error handler as a shortcut. For example, the following two error handlers have the same effect:


! This error handler uses [OTHERWISE] alone as a shortcut.

ON_ERROR
[OTHERWISE] : ;
ENDON_ERROR

! This error handler has the same effect as using
! [OTHERWISE] alone.

ON_ERROR
[OTHERWISE] :
   LEARN_ABORT;
   RETURN (FALSE);
ENDON_ERROR;

Example 4-11 from the EVE editor shows a procedure with a case-style error handler.

Example 4-11 Procedure with a Case-Style Error Handler

PROCEDURE eve$learn_abort

ON_ERROR
    [TPU$_CONTROLC]:
       MESSAGE (ERROR_TEXT);
       RETURN (LEARN_ABORT);
ENDON_ERROR;

IF LEARN_ABORT
THEN
    eve$message (EVE$_LEARNABORT);
    RETURN (TRUE);
ELSE
    RETURN (FALSE);
ENDIF;

ENDPROCEDURE;

If a program or procedure has a case-style error handler, DECTPU handles errors and warnings as follows:

  • If you press Ctrl/C, DECTPU determines whether the error handler contains a selector labeled TPU$_CONTROLC. If so, DECTPU sets ERROR to TPU$_CONTROLC, ERROR_LINE to the line that DECTPU was executing when Ctrl/C was pressed, and ERROR_TEXT to the message associated with TPU$_CONTROLC. DECTPU then executes the statements associated with the selector. If there is no TPU$_CONTROLC selector, DECTPU exits from the error handler and looks for a TPU$_CONTROLC selector in the procedures or program (if any) in which the current procedure is nested. If no TPU$_CONTROLC selector is found in the containing procedures or program, DECTPU places the message associated with TPU$_CONTROLC in the message buffer.
  • If an error or warning is generated during a CALL_USER routine, ERROR is set to a keyword that represents the failure status of the routine, ERROR_LINE is set to the line number of the error, and ERROR_TEXT is set to the warning or error message associated with the keyword. DECTPU then processes the error handler that trapped the CALL_USER error in the same way that DECTPU processes normal case-style error handlers.
  • For other warnings and errors, ERROR is set to a keyword that represents the error or warning, ERROR_LINE is set to the line number of the error, and ERROR_TEXT is set to the error or warning message associated with the keyword.
    The way a case-style error handler processes an error or warning depends on how the error handler traps the error. There are three possible ways, as follows:
    • The error handler can trap the error by using a selector that matches the error exactly (that is, using a selector other than OTHERWISE).
    • The error handler can trap the error by using the OTHERWISE selector.
    • The error handler can completely fail to trap the error.

    The following discussion explains how a case-style error handler processes an error or warning in each of these circumstances.
    If the error or warning is trapped by a selector other than OTHERWISE, DECTPU does not place the error or warning message in the message buffer unless the error handler code instructs it to do so. In this case, after setting ERROR, ERROR_LINE, and ERROR_TEXT, DECTPU executes the code associated with the selector. If the code does not return to the calling procedure or program, DECTPU checks whether one of the selectors associated with the code just executed is TPU$_CONTROLC or OTHERWISE. If so, DECTPU performs the equivalent of the following sequence:


    special_error_symbol := 0;
    LEARN_ABORT;
    RETURN (FALSE);
    

    If not, the error handler terminates and DECTPU resumes execution at the next statement after the statement that generated the error or warning.
    For more information on the special error symbol in DECTPU, see the description of the SET (SPECIAL_ERROR_SYMBOL) built-in procedure in the DEC Text Processing Utility Reference Manual.
    If the error or warning is trapped by the OTHERWISE selector, DECTPU writes the associated error or warning message in the message buffer. Next, DECTPU executes the code associated with the OTHERWISE selector. If the code does not return to the calling procedure or program, DECTPU performs the equivalent of the following sequence:


    special_error_symbol := 0;
    LEARN_ABORT;
    RETURN (FALSE);
    

    If the error or warning is not trapped by any selector, DECTPU writes the associated error or warning message in the message buffer. Next, DECTPU performs the equivalent of the following sequence:


    special_error_symbol := 0;
    LEARN_ABORT;
    RETURN (FALSE);
    

If an error or warning is generated during execution of a case-style error handler, DECTPU behaves as follows:

  • If you press Ctrl/C during the error handler, DECTPU sets ERROR to TPU$_CONTROLC, ERROR_LINE to the line being executed when Ctrl/C was pressed, and ERROR_TEXT to the message associated with TPU$_CONTROLC.
    If one of the case selectors in the error handler is TPU$_CONTROLC, DECTPU executes the code associated with the selector. If the code does not return to the calling procedure or program, DECTPU performs the equivalent of the following sequence:


    special_error_symbol := 0;
    LEARN_ABORT;
    RETURN (FALSE);
    

    If none of the selectors is TPU$_CONTROLC, then DECTPU exits from the error handler and looks for a TPU$_CONTROLC selector in the procedures or program (if any) in which the current procedure is nested. If DECTPU does not find a TPU$_CONTROLC selector in the containing procedures or program, DECTPU places the message associated with TPU$_CONTROLC in the message buffer.
  • If the error is not due to you pressing Ctrl/C, the error message is written to the message buffer and DECTPU performs the equivalent of the following sequence:


    special_error_symbol := 0;
    LEARN_ABORT;
    RETURN (FALSE);
    

In a procedure with a case-style error handler, an ABORT statement produces the same effect as the sequence Ctrl/C, with one exception: an ABORT statement in the TPU$_CONTROLC clause of a case-style error handler does not reinvoke the TPU$_CONTROLC clause, as is the case when Ctrl/C is pressed while TPU$_CONTROLC is executing. Instead, an ABORT statement causes DECTPU to exit from the error handler and look for a TPU$_CONTROLC selector in the procedures or program (if any) in which the current procedure is nested. If DECTPU does not find a TPU$_CONTROLC selector in the containing procedures or program, DECTPU places the message associated with TPU$_CONTROLC in the message buffer.

4.9.4.17 Ctrl/C Handling

The ability to trap a Ctrl/C in your DECTPU program is both powerful and dangerous. When you press Ctrl/C, you usually want the application that is running to prompt for a new command. The ability to trap the Ctrl/C is intended to allow a procedure to clean up and exit gracefully.

4.9.4.18 RETURN Statement

The RETURN statement causes a return to the procedure that called the current procedure or program. The return is to the statement that follows the statement that called the current procedure or program. You can specify an expression after the RETURN statement and the value of this expression is passed to the calling procedure.

Syntax


RETURN expression;

The expression is optional; if it is missing, DECTPU supplies a 0. Also, the RETURN statement itself is optional. That is, if DECTPU reaches the endprocedure of a procedure before encountering a RETURN statement, it will return 0.

Example 4-12 shows a sample procedure in which a value is returned to the calling procedure.

Example 4-12 Procedure That Returns a Value

PROCEDURE user_get_shift_key

LOCAL key_to_shift;  ! Keyword for key pressed after shift key

SET (SHIFT_KEY, LAST_KEY);
key_to_shift := KEY_NAME (READ_KEY, SHIFT_KEY);
RETURN key_to_shift;

ENDPROCEDURE;

In addition to using RETURN to pass a value, you can use a 1 (true) or a 0 (false) with the RETURN statement to indicate the status of a procedure. Example 4-13 shows this usage of the RETURN statement.

Example 4-13 Procedure That Returns a Status

PROCEDURE user_at_end_of_line

! This procedure returns a 1 (true) if user is at the end of a
! line, or a 0 (false) if the current character is not at the
! end of a line

ON_ERROR
! Suppress warning message
   RETURN (1);
ENDON_ERROR;

IF CURRENT_OFFSET = LENGTH (CURRENT_LINE)
THEN
    RETURN (1);
ELSE
    RETURN (0);
ENDIF;

ENDPROCEDURE;

You can use the RETURN statement in the ON_ERROR section of a procedure to specify a return to the calling procedure if an error occurs in the current procedure. Example 4-14 uses the RETURN statement in an ON_ERROR section.

Example 4-14 Using RETURN in an ON_ERROR Section

! Attach to the parent process.  Used when EVE is spawned
! from DCL and run in a subprocess ("kept DECTPU"). The
! ATTACH command can be used for more flexible process control.

PROCEDURE eve_attach

ON_ERROR
    IF ERROR = TPU$_NOPARENT
    THEN
        MESSAGE ("Not running DECTPU in a subprocess");
        RETURN;
    ENDIF;
ENDON_ERROR;

ATTACH;

ENDPROCEDURE;

4.9.4.19 ABORT Statement

The ABORT statement stops any executing procedures and causes DECTPU to wait for the next keystroke. ABORT is commonly used in error handlers. For additional information on using ABORT in error handlers, see Section 4.9.4.14.

Syntax


ABORT

Example 4-15 shows a simple error handler that contains an ABORT statement.

Example 4-15 Simple Error Handler

ON_ERROR
   MESSAGE ("Aborting procedure because of error.");
   ABORT;
ENDON_ERROR;

4.9.5 Miscellaneous Declarations

This section describes the following DECTPU language declarations:

  • EQUIVALENCE
  • LOCAL
  • CONSTANT
  • VARIABLE

4.9.5.1 EQUIVALENCE

With the EQUIVALENCE declaration, you can create synonyms. Equivalences work only when both real_name and synonym_name are defined at the same time. You cannot save a section file that contains real_name and then later use that section file to extend code that uses an EQUIVALENCE of the saved name. To avoid problems, include all EQUIVALENCE declarations in the same compilation unit where real_name is defined.

The equivalences can reside in different compilation units, but you must use all of the compilation units when building the section file from scratch. If you use a base section file that you extend interactively, you cannot make equivalences to procedures or variables defined in the base section file.

Syntax

EQUIVALENCE synonym_name1 = real_name1, synonym_name2 = real_name2,
...;

Elements of the EQUIVALENCE Statement

real_name

A user-defined global variable or procedure name. If real_name is undefined, DECTPU defines it as an ambiguous name. This ambiguous name can become a variable or procedure later.

synonym_name

A name to be defined as a synonym for the real_name.

4.9.5.2 LOCAL

With the LOCAL declaration, you can identify certain variables as local variables rather than global variables. All variables are considered to be global variables unless you explicitly use the LOCAL declaration to identify them as local variables. The LOCAL declaration in a procedure is optional. It must be specified after the PROCEDURE statement and before any ON_ERROR statement. LOCAL declarations and CONSTANT declarations can be intermixed.

The maximum number of local variables you can declare in a procedure is 255. Local variables are initialized to 0.

Syntax


LOCAL variable-name [[,...]];

Local variables may also be declared in unbound code. Such variables are accessible only within that unbound code.

Unbound code can occur in the following places:

  • Module initialization code
    This occurs after all procedure declarations within a module but before the ENDMODULE statement.
  • Executable code
    This occurs after all module and procedure declarations in a file but before the end of file.

The following example shows a complete compilation unit. This unit contains a module named mmm that, in turn, contains a procedure bat and some initialization code mmm_module_init, a procedure bar defined outside the module, and some unbound code at the end of the file. In each of these sections of code, a local variable X is defined. The variable is displayed using the MESSAGE built-in procedure.


MODULE mmm IDENT "mmm"

PROCEDURE bat;      ! Declare procedure "bat" in module "mmm"

LOCAL
    X;  ! "X" is local to procedure "bat"

    X := "Within procedure bat, within module mmm";
MESSAGE (X);

ENDPROCEDURE; ! End procedure "bat"

LOCAL
        X;                      ! "X" is local to
                                ! procedure "mmm_module_init"

X := "Starting or ending the module init code";
MESSAGE (X);
bat;
MESSAGE (X);

ENDMODULE;              ! End module "mmm"

PROCEDURE bar           ! Declare procedure "bar"

LOCAL
        X;                      ! "X" is local to procedure "bar"

X := "In procedure bar, which is outside all modules";
MESSAGE (X);

ENDPROCEDURE;           ! End procedure "bar"

LOCAL
        X;                      ! "X" is local to the unbound code...

X := "Starting or ending the unbound, non-init code";
MESSAGE (X);
mmm_module_init;
bat;
bar;
MESSAGE (X);
EXIT;

If this code is included in TEMP.TPU, the following command demonstrates the scope of the various local variables:


$
EDIT/TPU/NOSECTION/NOINITIALIZE/NODISPLAY/COMMAND=temp.tpu
Starting or ending the unbound, non-init code
Starting or ending the module init code
Within procedure bat, within module mmm
Starting or ending the module init code
Within procedure bat, within module mmm
In procedure bar, which is outside all modules
Starting or ending the unbound, non-init code


Previous Next Contents Index