Conditions and condition traps

A condition is a specified event or state that CALL ON or SIGNAL ON can trap. A condition trap can modify the flow of execution in a REXX program.

How to enable condition traps

Condition traps are turned on or off using the ON or OFF subkeywords of the SIGNAL and CALL instructions (see CALL and SIGNAL).

Read syntax diagramSkip visual syntax diagramCALLSIGNALOFFconditionONconditionNAMEtrapname ;

condition and trapname are single symbols that are taken as constants. Following one of these instructions, a condition trap is set to either ON (enabled) or OFF (disabled). The initial setting for all condition traps is OFF.

If a condition trap is enabled and the specified condition occurs, control passes to the routine or label trapname if you have specified trapname. Otherwise, control passes to the routine or label condition. CALL or SIGNAL is used, depending on whether the most recent trap for the condition was set using CALL ON or SIGNAL ON, respectively.

Note: If you use CALL, the trapname can be an internal label, a built-in function, or an external routine. If you use SIGNAL, the trapname can be only an internal label.

Any ON or OFF reference to a condition trap replaces the previous state (ON, OFF, or DELAY, and any trapname) of that condition trap. Thus, a CALL ON HALT replaces any current SIGNAL ON HALT (and a SIGNAL ON HALT replaces any current CALL ON HALT), a CALL ON or SIGNAL ON with a new trap name replaces any previous trap name, any OFF reference disables the trap for CALL or SIGNAL, and so on.

Note: The state (ON, OFF, or DELAY, and any trapname) of each condition trap is saved on entry to a subroutine and is then restored on RETURN. This means that CALL ON, CALL OFF, SIGNAL ON, and SIGNAL OFF can be used in a subroutine without affecting the conditions set up by the caller. See the CALL instruction for details of other information that is saved during a subroutine call.

What can be trapped

The conditions and their corresponding events that can be trapped are as follows:

ERROR
An ERROR condition is raised if a command indicates an error condition upon return. It is also raised if any command indicates failure and neither CALL ON FAILURE nor SIGNAL ON FAILURE is active. The condition is raised at the end of the clause that called the command but is ignored if the ERROR condition trap is already in the delayed state. The delayed state is the state of a condition trap when the condition has been raised but the trap has not yet been reset to the enabled (ON) or disabled (OFF) state. See Note.

CALL ON ERROR and SIGNAL ON ERROR trap all positive return codes, and negative return codes only if CALL ON FAILURE and SIGNAL ON FAILURE are not set.

FAILURE
A FAILURE condition is raised if a command indicates a failure condition upon return. The condition is raised at the end of the clause that called the command but is ignored if the FAILURE condition trap is already in the delayed state.

CALL ON FAILURE and SIGNAL ON FAILURE trap all negative return codes from commands.

HALT
A HALT condition is raised if an external attempt is made to interrupt and end execution of the program. The condition is usually raised at the end of the clause that was being processed when the external interruption occurred.
NOVALUE
A NOVALUE condition is raised when any of the following occurs:
  • An uninitialized variable is used as a term in an expression.
  • An uninitialized variable is used as the name following the VAR subkeyword of a PARSE instruction.
  • An uninitialized variable is used as a variable reference in a parsing template, a PROCEDURE instruction, or a DROP instruction.

You can specify this condition only for SIGNAL ON.

Note: SIGNAL ON NOVALUE can trap any uninitialized variables except tails in compound variables.
/* The following does not raise NOVALUE. */
signal on novalue
a.=0
say a.z
say 'NOVALUE is not raised.'
exit

novalue:
say 'NOVALUE is raised.'
SYNTAX
A SYNTAX condition is raised if any language processing error is detected while the program is running. This includes all kinds of processing errors, including true syntax errors and runtime errors, such as attempting an arithmetic operation on nonnumeric terms. You can specify this condition only for SIGNAL ON.

What action is taken when a condition is not trapped

When a condition trap is currently disabled (OFF) and the specified condition occurs, the default action depends on the condition.

  • For HALT and SYNTAX, the processing of the program ends, and a message (see Error numbers and messages) describing the nature of the event that occurred usually indicates the condition.
  • For all other conditions, the condition is ignored and its state remains OFF.

What action is taken when a condition is trapped

When a condition trap is currently enabled (ON) and the specified condition occurs, instead of the usual flow of control, a CALL trapname or SIGNAL trapname instruction is processed automatically.

You can specify the trapname after the NAME subkeyword of the CALL ON or SIGNAL ON instruction. If you do not specify trapname, the name of the condition itself (ERROR, FAILURE, HALT, NOTREADY, NOVALUE, or SYNTAX) is used.

For example, the instruction call on error enables the condition trap for the ERROR condition. If the condition occurred, then a call to the routine identified by the name ERROR is made. The instruction call on error name commanderror would enable the trap and call the routine COMMANDERROR if the condition occurred.

The sequence of events, after a condition has been trapped, varies depending on whether a SIGNAL or CALL is processed.
Actions for SIGNAL
If the action taken is a SIGNAL, execution of the current instruction ceases immediately, the condition is disabled (set to OFF), and the SIGNAL takes place in exactly the same way as usual (see SIGNAL).

If any new occurrence of the condition is to be trapped, a new CALL ON or SIGNAL ON instruction for the condition is required to re-enable it when the label is reached. For example, if SIGNAL ON SYNTAX is enabled when a SYNTAX condition occurs, then, if the SIGNAL ON SYNTAX label name is not found, a usual syntax error termination occurs.

Actions for CALL

If the action taken is a CALL (which can occur only at a clause boundary), the CALL is made in the usual way except that the call does not affect the special variable RESULT. If the routine should RETURN any data, then the returned character string is ignored.

Because these conditions (ERROR, FAILURE, and HALT) can arise during execution of an INTERPRET instruction, execution of the INTERPRET may be interrupted and later resumed if CALL ON was used.

As the condition is raised, and before the CALL is made, the condition trap is put into a delayed state. This state persists until the RETURN from the CALL, or until an explicit CALL (or SIGNAL) ON (or OFF) is made for the condition. This delayed state prevents a premature condition trap at the start of the routine called to process a condition trap. When a condition trap is in the delayed state it remains enabled, but if the condition is raised again, it is either ignored (for ERROR, FAILURE, or NOTREADY) or (for the other conditions) any action (including the updating of the condition information) is delayed until one of the following events occurs:
  1. A CALL ON or SIGNAL ON, for the delayed condition, is processed. In this case a CALL or SIGNAL takes place immediately after the new CALL ON or SIGNAL ON instruction has been processed.
  2. A CALL OFF or SIGNAL OFF, for the delayed condition, is processed. In this case the condition trap is disabled and the default action for the condition occurs at the end of the CALL OFF or SIGNAL OFF instruction.
  3. A RETURN is made from the subroutine. In this case the condition trap is no longer delayed and the subroutine is called again immediately.

On RETURN from the CALL, the original flow of execution is resumed (that is, the flow is not affected by the CALL).

Note:
  1. You must be extra careful when you write a syntax trap routine. Where possible, put the routine near the beginning of the program. This is necessary because the trap routine label might not be found if there are certain scanning errors, such as a missing ending comment. Also, the trap routine should not contain any statements that might cause more of the program in error to be scanned. Examples of this are calls to built-in functions with no quotation marks around the name. If the built-in function name is in uppercase and is enclosed in quotation marks, REXX goes directly to the function, rather than searching for an internal label.
  2. In all cases, the condition is raised immediately upon detection. If SIGNAL ON traps the condition, the current instruction is ended, if necessary. Therefore, the instruction during which an event occurs may be only partly processed. For example, if SYNTAX is raised during the evaluation of the expression in an assignment, the assignment does not take place. Note that the CALL for ERROR, FAILURE, HALT, and NOTREADY traps can occur only at clause boundaries. If these conditions arise in the middle of an INTERPRET instruction, execution of INTERPRET may be interrupted and later resumed. Similarly, other instructions, for example, DO or SELECT, may be temporarily interrupted by a CALL at a clause boundary.
  3. The state (ON, OFF, or DELAY, and any trapname) of each condition trap is saved on entry to a subroutine and is then restored on RETURN. This means that CALL ON, CALL OFF, SIGNAL ON, and SIGNAL OFF can be used in a subroutine without affecting the conditions set up by the caller. See the CALL instruction for details of other information that is saved during a subroutine call.
  4. The state of condition traps is not affected when an external routine is called by a CALL, even if the external routine is a REXX program. On entry to any REXX program, all condition traps have an initial setting of OFF.
  5. While user input is processed during interactive tracing, all condition traps are temporarily set OFF. This prevents any unexpected transfer of control; for example, should the user accidentally use an uninitialized variable while SIGNAL ON NOVALUE is active. For the same reason, a syntax error during interactive tracing does not cause exit from the program but is trapped specially and then ignored after a message is given.
  6. The system interface detects certain execution errors either before execution of the program starts or after the program has ended. SIGNAL ON SYNTAX cannot trap these errors.

Note that a label is a clause consisting of a single symbol followed by a colon. Any number of successive clauses can be labels; therefore, multiple labels are allowed before another type of clause.

The condition information recorded

When any condition is trapped and causes a SIGNAL or CALL, this becomes the current trapped condition, and certain condition information associated with it is recorded.

You can inspect this information by using the CONDITION built-in function (see CONDITION).

The condition information includes:
  • The name of the current trapped condition
  • The name of the instruction processed as a result of the condition trap (CALL or SIGNAL)
  • The status of the trapped condition
  • Any descriptive string associated with that condition.

The current condition information is replaced when control is passed to a label as the result of a condition trap (CALL ON or SIGNAL ON). Condition information is saved and restored across subroutine or function calls, including one because of a CALL ON trap. Therefore, a routine called by a CALL ON can access the appropriate condition information. Any previous condition information is still available after the routine returns.

Descriptive strings

The descriptive string varies, depending on the condition trapped.
ERROR
The string that was processed and resulted in the error condition.
FAILURE
The string that was processed and resulted in the failure condition.
HALT
Any string associated with the halt request. This can be the null string if no string was provided.
NOVALUE
The derived name of the variable whose attempted reference caused the NOVALUE condition. The NOVALUE condition trap can be enabled only using SIGNAL ON.
SYNTAX
Any string the language processor associated with the error. This can be the null string if you did not provide a specific string. Note that the special variables RC and SIGL provide information on the nature and position of the processing error. You can enable the SYNTAX condition trap only by using SIGNAL ON.

How are special variables handled

A special variable is one that can be set automatically during processing of a REXX program. There are three special variables: RC, RESULT, and SIGL. None of these has an initial value, but the program can alter them. (For information about RESULT, see RETURN.)

RC

For ERROR and FAILURE, the REXX special variable RC is set to the command return code, as usual, before control is transferred to the condition label.

For SIGNAL ON SYNTAX, RC is set to the syntax error number.

SIGL

Following any transfer of control because of a CALL or SIGNAL, the program line number of the clause causing the transfer of control is stored in the special variable SIGL. Where the transfer of control is because of a condition trap, the line number assigned to SIGL is that of the last clause processed (at the current subroutine level) before the CALL or SIGNAL took place. This is especially useful for SIGNAL ON SYNTAX when the number of the line in error can be used, for example, to control a text editor. Typically, code following the SYNTAX label may PARSE SOURCE to find the source of the data, then call an editor to edit the source file positioned at the line in error. Note that in this case you may have to run the program again before any changes made in the editor can take effect.

Alternatively, SIGL can be used to help determine the cause of an error (such as the occasional failure of a function call) as in the following example:
signal on syntax
a = a + 1      /* This is to create a syntax error */
say 'SYNTAX error not raised'
exit

/* Standard handler for SIGNAL ON SYNTAX */
syntax:
  say 'REXX error' rc 'in line' sigl':' "ERRORTEXT"(rc)
  say "SOURCELINE"(sigl)
  trace ?r; nop

This code first displays the error code, line number, and error message. It then displays the line in error, and finally drops into debug mode to let you inspect the values of the variables used at the line in error.