 |
Guide to the DEC Text Processing Utility
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
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
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
|
|