The debug facility permits interactively controlled execution of
a REXX exec.
Changing the TRACE action to one with a prefix ? (for example, TRACE
?A or the TRACE built-in function) turns on interactive debug
and indicates to the user that interactive debug is active. You can
interactively debug REXX execs in the TSO/E address space from your
terminal session.
Further TRACE instructions in the exec are ignored, and the language processor pauses
after nearly all instructions that are traced at the terminal (see
the following for exceptions). When the language processor pauses,
three debug actions are available:
- Entering a null line (with no characters, including no
blanks) makes the language processor continue
execution until the next pause for debug input. Repeatedly entering
a null line, therefore, steps from pause point to pause point. For TRACE
?A, for example, this is equivalent to single-stepping through
the exec.
- Entering an equal sign (=), with no blanks, makes the language processor re-execute
the clause last traced. For example: if an IF clause is about to
take the wrong branch, you can change the value of the variable(s)
on which it depends, and then re-execute it.
After the clause
has been re-executed, the language processor pauses
again.
- Anything else entered is treated as a line of one
or more clauses, and processed immediately (that is, as though DO;
line ; END; had been inserted in the exec). The same rules
apply as in the INTERPRET instruction (for example, DO-END constructs
must be complete). If an instruction has a syntax error in it, a
standard message is displayed and you are prompted for input again.
Similarly, all the other SIGNAL conditions are disabled while the
string is processed to prevent unintentional transfer of control.
During
execution of the string, no tracing takes place, except that nonzero
return codes from host commands are displayed. Host commands are
always executed (that is, they are not affected by the prefix ! on
TRACE instructions), but the variable RC is not set.
After
the string has been processed, the language processor pauses
again for further debug input, unless a TRACE instruction was entered.
In this latter case, the language processor immediately
alters the tracing action (if necessary) and then continues executing
until the next pause point (if any). Therefore, to alter the tracing
action (from All to Results, for example) and then re-execute the
instruction, you must use the built-in function TRACE (see TRACE). For example, CALL TRACE I changes
the trace action to "I" and allows re-execution of the statement
after which the pause was made. Interactive debug is turned off,
when it is in effect, if a TRACE instruction uses a prefix, or at
any time, when a TRACE O or TRACE with
no options is entered.
You can use the numeric form of the
TRACE instruction to allow sections of the exec to be executed without
pause for debug input. TRACE n (that is, positive
result) allows execution to continue, skipping the next n pauses
(when interactive debug is or becomes active). TRACE -n (that
is, negative result) allows execution to continue without pause and
with tracing inhibited for n clauses that would otherwise
be traced.
The trace action selected by a TRACE instruction is saved and restored
across subroutine calls. This means that if you are stepping through
an exec (for example, after using TRACE ?R to trace
Results) and then enter a subroutine in which you have no interest,
you can enter TRACE O to turn tracing off. No further
instructions in the subroutine are traced, but on return to the caller,
tracing is restored.
Similarly, if you are interested only in a subroutine, you can
put a TRACE ?R instruction at its start. Having
traced the routine, the original status of tracing is restored and,
therefore, (if tracing was off on entry to the subroutine) tracing
(and interactive debug) is turned off until the next entry to the
subroutine.
You can switch tracing on (without modifying an exec) using the
command EXECUTIL TS. You can also switch tracing on or off asynchronously,
(that is, while an exec is running) using the TS and TE immediate
commands. See Interrupting exec processing for the description
of these facilities.
Because you can execute any instructions in interactive debug,
you have considerable control over execution.
Some examples:
Say expr /* displays the result of evaluating the */
/* expression. */
name=expr /* alters the value of a variable. */
Trace O /* (or Trace with no options) turns off */
/* interactive debug and all tracing. */
Trace ?A /* turns off interactive debug but continues */
/* tracing all clauses. */
Trace L /* makes the language processor pause at labels */
/* only. This is similar to the traditional */
/* "breakpoint" function, except that you */
/* do not have to know the exact name and */
/* spelling of the labels in the exec. */
exit /* terminates execution of the exec. */
Do i=1 to 10; say stem.i; end /* displays ten elements of the */
/* array stem. */
Exceptions:
Some clauses cannot safely be re-executed, and therefore, the
language processor does not
pause after them, even if they are traced. These are:
- Any repetitive DO clause, on the second or subsequent time around
the loop
- All END clauses (not a useful place to pause in any case)
- All THEN, ELSE, OTHERWISE, or null clauses
- All RETURN and EXIT clauses
- All SIGNAL and CALL clauses (the language processor pauses
after the target label has been traced)
- Any clause that raises a condition that CALL ON or SIGNAL ON traps
(the pause takes place after the target label for the CALL or SIGNAL
has been traced)
- Any clause that causes a syntax error (These can be trapped by
SIGNAL ON SYNTAX, but cannot be re-executed.)