The debug facility permits interactively controlled execution of
a program.
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. Further TRACE instructions in the program are ignored,
and the language processor pauses after nearly all instructions that
are traced at the console (see the following for the exceptions).
When the language processor pauses, indicated by a READ in the lower
corner of the screen, three
debug actions are available:
- Entering a null line (with no characters, even 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 program.
- Entering an equal sign (=) with no blanks makes the language
processor rerun 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 rerun it.
Once the clause
has been rerun, 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 program). 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 run
(that is, are not affected by the prefix ! on TRACE instructions),
but the variable RC is not set.
Once 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). To alter
the tracing action (from All to Results, for example) and then rerun
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
program to be run 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 a program (say 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 (if tracing was off on entry to the subroutine) tracing (and interactive
debug) is turned off until the next entry to the subroutine.
Since any instructions may be run 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 program. */
exit /* stops execution of the program. */
Do i=1 to 10; say stem.i; end
/* displays ten elements of the array stem. */
Note: While in interactive debug, pauses may occur because
of PULL statements as well as because of interactive debug. For programs
containing PULL statements, it is important to be aware of the reason
for each pause. In programs, PULL statements are often paired with
SAY statements. The user should enter the data for the PULL at the
pause after the trace line for the PULL (the pause specifically for
entering data for the PULL). The user should not enter the data at
the pause after the corresponding SAY statement (this is an interactive
debug pause).
Exceptions: Some clauses cannot safely be re-run,
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 may be trapped by
SIGNAL ON SYNTAX, but cannot be re-run.)