\begin{document}
\begin{Introduction}{Debugging}
The package \name{RDEBUG} helps you to find bugs in algebraic
REDUCE programs by making the functions of the PSL package
\name{DEBUG} available for algebraic mode.
The following facilities are available:
Entry-exit trace (\nameref{tr}, \nameref{untr}):
visualize every call of
explicitly declared functions, printing their arguments and
results.
Assignment trace (\nameref{trst}, \nameref{untrst}):
report all assignments which
are executed inside explicitly declared functions. This facility
is not available for compiled functions.
Breakpoint (\nameref{br}, \nameref{unbr}):
interrupt the program execution at
entry and exit of explicitly declared functions, invoking
a \nameref{breakloop}.
Conditional trace (\nameref{trwhen}, \nameref{untrwhen})
or break (\nameref{brwhen},\nameref{unbrwhen}).
Rule trace (\nameref{trrl}, \nameref{untrrl}):
report the arguments and results of a rule whenever it fires.
You can control the debug output using the operator \nameref{trout}
and the variable \nameref{trlimit}.
\end{Introduction}
%=============================================================
\begin{Concept}{breakloop}
\index{debug}
A \name{break loop} is an interrupt of the program execution
where control is given temporarily to the terminal for
entering commands in a standard command - evaluate - print loop.
When a break occurs, you can inspect the current
environment or even alter it, and the
interrupted computation may be terminated or continued.
A break can be caused
- by an internal error when the switch \nameref{break} is on,
- by an explicit call of \name{lisp break()},
- at entry and exit time of a procedure which has been
declared by \nameref{br}.
In a break situation the evaluation is stopped temporarily
and the control returns to the terminal with a special prompt:
\name{break[1]1:}.
The number in square brackets counts the break level - it is
increased when a break occurs inside a break; the normal
REDUCE statement counter follows. Each break loop supports its
own statement numbers and input and output buffers.
After terminating of a break loop the
previous statement counters and buffers are restored.
In a break loop all REDUCE commands can be
entered. Additionally, there is a set of single character commands
which allow you to control the break environment. All these
begin with an underscore character:
\name{\_a;} terminate break and return to the top REDUCE level
\name{\_c;} continue execution of interrupted procedure
\name{\_i;} print a backtrace (list of procedures in the
call hierarchy)
\name{\_l} \meta{var}; (local) read the content of the local variable
\meta{var}
\name{\_m;} print the last (LISP-) error message
\name{\_q;} terminate the break loop and return to the next
higher level.
Global variables can be accessed as usual in the REDUCE language.
They can also be set to different values in the break loop.
The inspect values assigned to dummy arguments and scalar variables of
procedures in the actual call hierarchy, you need a special command
\name{\_l}. These values cannot be altered in the break loop.
\begin{Examples}
procedure p1(x); \\
begin scalar y1; y1:=x^2; return p2(y1); end;\\
procedure p2(q); q^2;\\
br p2;\\
x:=22;\\
p1(alpha);\\
p2 being entered\\
q: alpha**2$\\
Break before entering `p2'\\
break[1]1: x; & 22\\
break[1]2: _l x; & alpha\\
break[1]3: _l y1; & alpha^2 \\
break[1]4: _l q;& alpha^2 \\
break[1]6: _c;\\
Break after call `p2', value `(expt (expt alpha 2) 2)'\\
break[1]1: _c;\\
&alpha^4\\
\end{Examples}
In the corresponding break loop caused by calling \name{p2}
indirectly via \name{p1}, you can access the global \name{x}, the
locals \name{x} and \name{y1} of \name{p1} and the \name{q} of
\name{p2}.
\end{Concept}
%=========================================================
\begin{Operator}{tr}
\index{trace}\index{debug}
The command \name{tr} puts one or several procedures to
under trace. Every time such a function is executed, a message
is printed during the procedure entry and another one is generated
at the return time. The entry message records the
actual procedure arguments equated to the dummy parameter
names, and at the exit time the procedure value is printed.
Recursive calls are marked by an indentation and a level number.
\begin{Syntax}
\name{tr}\meta{proc1},\meta{proc2},...,\meta{procn};
\end{Syntax}
Here \meta{proc1},\meta{proc2},...,\meta{procn}
are names of procedures
to be added to the set of traced procedures. See also
\nameref{trst},\nameref{trwhen}.
\end{Operator}
\begin{Operator}{untr}
\index{trace}\index{debug}
Tracing is stopped for one or several functions by the
command \name{untr}:
\begin{Syntax}
\name{untr}\meta{proc1},\meta{proc2},...,\meta{procn};
\end{Syntax}
\end{Operator}
%========================================================
\begin{Operator}{trst}
\index{trace}\index{assignment-trace}\index{debug}
Sometimes one needs detailed information about the inner behavior of
a procedure, especially if it is a longer piece of code.
For a procedure declared in a \name{trst} command
an extended trace is performed:
all executed explicit assignments and all passed labels
are reported at run time.
\begin{Syntax}
\name{trst}\meta{proc1},\meta{proc2},...,\meta{procn};
\end{Syntax}
Here \meta{proc1},\meta{proc2},...,\meta{procn}
are names of procedures
to be added to the set of traced procedures.
When your program contains a \nameref{for} loop,
REDUCE translates this to a sequential piece of
LISP instructions. When using \name{trst}, the printout
is driven by the unfolded code. When the code contains a
\name{for-each-in} statement, the name of the control variable is
internally used to keep the remainder of the list during the loop
control, and you will see the corresponding assignments
in the printout rather than the individual values in the
loop steps.
\end{Operator}
\begin{Operator}{untrst}
\index{trace}\index{assignment-trace}\index{debug}
Extended tracing is stopped for one or several functions by the
command \name{untrst}:
\begin{Syntax}
\name{untrst}\meta{proc1},\meta{proc2},...,\meta{procn};
\end{Syntax}
\end{Operator}
%=========================================================
\begin{Operator}{trwhen}
\index{trace}\index{debug}
The trace output can be tunrned on or off automatically by
a boolean expression which is linked to a traced procedure
by the command \name{trwhen}:
\begin{Syntax}
trwhen \meta{name},\meta{booleanexpr};
\end{Syntax}
The boolean expression must follow
standard REDUCE syntax. It may contain references
to global values and to
the actual parameters of the procedure. As long as the
procedure is not compiled, the original names of the dummy arguments
are used. For a compiled procedure the original names
are not available; instead the names \name{a1}, \name{a2}, ...
must be used. Example: the following procedure produces trace
output only if the main variable of its argument is \name{x}:
\begin{Examples}
procedure hugo(u); otto(u);\\
tr hugo;\\
trwhen hugo,mainvar(u)=x;\\
\end{Examples}
Note: for a symbolic procedure, the \name{trwhen} command
must be given in symbolic mode or with prefix $symbolic$.
\end{Operator}
\begin{Operator}{untrwhen}
\index{trace}\index{debug}
Conditional trace is stopped for a procedure by calling
\begin{Syntax}
untrwhen \meta{name};
\end{Syntax}
\end{Operator}
%========================================================
\begin{Switch}{break}
\index{debug}
When the switch \name{break} is set on, every
evaluation error causes a \nameref{breakloop}. Most of these
breaks are non-continuable; however, you have the
opportunity to read the actual values of local variables
in the environment which caused the error.
\end{Switch}
%=========================================================
\begin{Operator}{br}
\index{break}\index{debug}
The command \name{br} declares one or several procedures
as breakpoints. When executing such a function, the
computation is interrupted by a \nameref{breakloop}
at function enter and return times.
\begin{Syntax}
\name{br}\meta{proc1},\meta{proc2},...,\meta{procn};
\end{Syntax}
Here \meta{proc1},\meta{proc2},...,\meta{procn}
are names of procedures
to be added to the set of break points.
See also \nameref{brwhen}.
\end{Operator}
\begin{Operator}{unbr}
\index{break}\index{debug}
The break property
can be removed by the command \name{unbr}:
\begin{Syntax}
\name{unbr}\meta{proc1},\meta{proc2},...,\meta{procn};
\end{Syntax}
\end{Operator}
% =============================================================
\begin{Operator}{brwhen}
\index{break}\index{debug}
The break point (see \nameref{br})
can be tunrned on or off automatically by
a boolean expression which is linked to a breakpoint procedure
by the command \name{brwhen}:
\begin{Syntax}
brwhen \meta{name},\meta{booleanexpr};
\end{Syntax}
The boolean expression must follow
standard REDUCE syntax. It may contain references
to global values and to
the actual parameters of the procedure. As long as the
procedure is not compiled, the original names of the dummy arguments
are used. For a compiled procedure the original names
are not available; instead the names \name{a1}, \name{a2}, ...
must be used. Example: the following procedure is broken
only if the main variable of its argument is \name{x}:
\begin{Examples}
procedure hugo(u); otto(u);\\
br hugo;\\
brwhen hugo,mainvar(u)=x;\\
\end{Examples}
Note: for a symbolic procedure, the \name{brwhen} command
must be given in symbolic mode or with prefix $symbolic$.
\end{Operator}
\begin{Operator}{unbrwhen}
\index{break}\index{debug}
Conditional break is removed for a procedure by calling
\begin{Syntax}
unbrwhen \meta{name};
\end{Syntax}
\end{Operator}
% ==============================================================
\begin{Operator}{trrl}
\index{debug}\index{rule}\index{ruleset}
The command \name{trrl} allows you to trace individual rules
or rule sets when they fire.
\begin{Syntax}
trrl \meta{rs1},\meta{rs2},...,\meta{rsn};
\end{Syntax}
where each of the \meta{rsi} is
- a rule or a rule set,
- a name of a rule or rule set (that is a non--indexed variable which
is bound to a rule or rule list),
- an operator name, representing the rules assigned to this
operator.
The specified rules are (re-) activated in REDUCE in
a style that each of them prints a report every time if fires.
The report is composed of the name or the rule or the
name of the rule set plus the number of the rule in the set,
the form matching the left hand side and the
resulting right hand side.
For an explicitly given rule, \name{trrl} assigns a generated name.
\end{Operator}
\begin{Operator}{untrrl}
\index{debug}\index{rule}\index{ruleset}
With \name{untrrl} you can remove the tracing from rules
\begin{Syntax}
untrrl \meta{rs1},\meta{rs2},...,\meta{rsn};
\end{Syntax}
The rules are reactivated in their original form. Alternatively
you can use the command \nameref{clearrules} to remove the
rules totally from the system. Please do not modify the
rules between \name{trrl} and \name{untrrl} -- the result
may be unpredictable.
\end{Operator}
%==============================================================
\begin{Operator}{trout}
\index{debug}\index{io}
The trace output can be redirected to a separate file
by using the command \name{trout}, followed
by a file name in string quotes. A second call of \name{trout}
closes the actual output file and assigns a new one.
The file name NIL (without string quotes) causes the trace output
to be redirected to the standard output device.
Remark: under Windows a file name starting with "win:" causes
a new window to be opened which receives the complete
output of the debugging services.
\end{Operator}
%==============================================================
\begin{Variable}{trlimit}
\index{debug}\index{io}
The integer valued share variable \name{trlimit} defines
an upper limit for the number of items printed in formula
collections. The
initial value is 5. A different value can be assigned to
increase or lower the output size.
\begin{Examples}
trlimit:=7;\\
\end{Examples}
\end{Variable}
%==============================================================
\begin{Variable}{trprinter}
\index{debug}\index{io}
If you want to select LISP style printing instead of
algebraic printing during trace, set \name{trprinter!*}
to \name{printx}:
\begin{Syntax}
lisp(trprinter!* := 'printx);
\end{syntax}
\end{Variable}