[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

D. Debugging

The Q interpreter includes a simple symbolic debugger which can be used to trace the reductions performed during an expression evaluation. In order to use this tool successfully, you should be familiar with the way the Q interpreter evaluates expressions; see, in particular, Performing Reductions on a Stack.

The debugger is subject to activation when one of the following conditions arises:

In the first case, the debugger is always invoked as soon as an evaluation is started. In the remaining cases the debugger is only invoked if the break flag is on. The break flag is an internal flag of the interpreter which can be controlled with the break command, cf. Command Language. If break is off then all kinds of exceptions normally cause evaluation to be aborted immediately with an appropriate error message, and invocations of the break function are simply ignored. (The break flag is off by default, so you must set it to on before you can catch any break points with the debugger.) Also note that if there is a pending catch (see Exception Handling) then the debugger will only be invoked for a call to the break function, if the break flag is on.

The break command can also be invoked with a list of function symbols as arguments, which sets breakpoints on the given symbols. When a breakpoint has been set on a function symbol, the debugger will be invoked, just as if the break function had been called, whenever the interpreter is about to reduce an application of that function employing a user-defined rule. When invoked without arguments, break prints the current status of the break flag and a list of currently active breakpoints. You can use the clear command to delete a breakpoint on the given function symbols (or all breakpoints if no argument is specified). Moreover, there also is a tbreak command which sets temporary breakpoints on the given symbols which will be removed automatically once they are hit. (In the breakpoint list produced with break, such temporary breakpoints are signaled by a trailing `*'.) All these commands can be used either from the debugger or on the interpreter's command line.

When active, the debugger prints each reduction by a built-in or user-defined rule performed during evaluation in the following format:

 
**  left-hand-side  ==>  right-hand-side

"Tail reductions" (see Tail Recursion) are signaled by a leading `++' instead of `**', global and local variable bindings (cf. Free Variables, and Local Variables) with a leading `--'.

Whenever a new rule is activated, and also after processing a qualifier, the debugger interrupts the evaluation and displays the current rule together with the corresponding source file name and line number in the following format:

 
level> source-file, line line-number: left-hand-side  ==>  right-hand-side qualifier

(To remove clutter, the debugger only prints one qualifier at a time, namely the condition or local definition which is currently being processed.)

The level number printed in front of the rule indicates the position of the printed rule on the reduction stack (the topmost rule is at level 0). At the `:' prompt, you may then enter one of the following commands:

?, help

Print a short help message which lists the debugger commands.

help options

Print a help message which briefly describes debugger options that can be set with the `.' command.

break [on|off|function …], tbreak function …, clear [function …]

Change the break flag and list, set or remove breakpoints (see above).

. [arg …]

Reprint the current rule (if invoked without arguments), or set debugger options.

l [offs] [lines]

List source lines of the current rule. You may specify the number of lines to be listed (the default is 1), as well as an offset taken relative to the line number of the current rule (this must be a signed number, with the default being +0).

p [arg]

Print stacked rules.

m

Print memory usage.

v

List the local variables of the current rule.

u [arg], d [arg]

Move up or down on the rule stack.

t, b

Move to the top or bottom of the stack.

<CR>

Step into the current reduction.

n

Next: step over the current reduction.

c

Continue: resume evaluation.

h

Halt: abort evaluation.

q, <EOF>

Quit: exit from the interpreter.

All other input is interpreted as an expression to be evaluated in the context of the current rule, with local variables bound to their current values. This lets you inspect the values of local variables and perform arbitrary calculations with these values. Note that debugging mode is suspended while the expression is evaluated, so only the result (or an error message) will be printed. As on the interpreter's main command line, you can use `? expression' to escape an expression which looks like a debugger command.

When evaluating an expression, the result is printed with custom pretty-printing (cf. Views) enabled, just like when evaluating an expression on the interpreter's command line. All other expressions are printed in the debugger with custom pretty-printing disabled, so that you can see exactly the "raw" data processed by the interpreter.

Command line editing works in the debugger as usual. Note, however, that the debugger maintains its own command history which is not remembered across different invocations of the interpreter.

With the debugger being activated, you can simply keep on hitting the carriage return key to go through an evaluation step by step. The `n' ("next" a.k.a. "step over") command causes the interpreter to finish the current rule and also step over any tail reductions; it then leaves you in the context from which the current rule was invoked (which might be the interpreter's command prompt, if you just stepped over the toplevel rule).

The `p' command can be used to print the stack of active rules. The optional integer argument of this command sets the maximum number of stacked rules to print. The `u', `d', `t' and `b' commands let you move around on the reduction stack; `u' and `d' move up and down the given number of levels (default: 1), while `t' and `b' take you to the top (i.e., topmost rule) and bottom (active rule) of the stack, respectively.

The `l' command lists the source of the current rule. By default, only the line at which the rule starts is printed. You can specify the number of lines to be listed; e.g., `l 5' causes five lines to be printed. To have some context of the rule printed, you can also specify a signed integer denoting the relative offset from the source line; e.g., `l -2 5' causes five lines to be printed, starting two lines above the current rule. (Both the line count and the offset are remembered across different invocations of the `l' command.)

The `v' command lists the local (i.e., "bound") variables of a rule. This comprises the variables which are bound by the left-hand side or have already been bound in a where clause while the rule is being processed. (Note that in the current implementation only those variables will be listed whose values are actually used somewhere on the right-hand side or in the qualifiers of the rule.)

At any point, you can use the `c', `h' and `q' commands to continue evaluation without the debugger, abort an evaluation and return to the interpreter's prompt, or quit the interpreter, respectively. The `m' command prints the current memory usage, i.e., the total number of allocated stack and heap expression cells, along with the corresponding numbers of cells which are actually in use. For the heap, it also prints the number of expression cells in the free list, i.e., temporarily unused expression cells below the current heap top. If limits are set on the maximum number of stack and heap cells, these figures are printed as well.

The current rule can be reprinted using the `.' command. Because Q expressions can get very large, the debugger usually only prints expression "outlines"; otherwise you could end up scrolling through pages and pages of printouts for each reduction and rule. The `.' command accepts some options which allow you to set the level of detail you want to see in the printed reductions and rules; these options will be remembered during an interpreter session. The options are generally specified in the format option=value and must not contain any whitespace (blanks or tabs). Multiple options can be specified with a single `.' command, separating different options with whitespace. Option values can also be specified in the same format on the interpreter's command line, using the debug command (see Command Language), or with the interpreter's --debug-options option (see Running Compiler and Interpreter). The following options are provided:

. detail=n

Set the maximum depth (a.k.a. levels of nested parentheses, 2 by default) up to which expressions are displayed. The debugger will omit all subexpressions below the current level. Level 1 (`. detail=1') means to just print the toplevel expression, level 2 adds the first-level parentheses, level 3 all second-level parentheses, etc. All omitted parts in the expression outline will be represented using an ellipsis `...'. If you set the level to zero, or specify the symbolic value all, all expressions will be printed to arbitrary depth.

. maxitems=n

Set the maximum number of elements to print for each list or tuple. The default is 3. A value of 0 or all causes all list and tuple elements to be printed.

. maxchars=n

Set the maximum number of characters to print for each string value. The default is 33. A value of 0 or all causes all characters to be printed.

. maxstack=n

Set the number of stack levels to print with the `p' command. The default is 6. A value of 0 or all causes the entire rule stack to be printed. This value is also modified when an argument is specified with `p'.

. pathnames=y|n

Print full pathnames of scripts (`y' = yes, `n' = no). The default value of this option is `n', i.e., only the basenames of scripts are printed. Change this value to `y' if you want to see the complete path of a script file when a rule is printed.

. options

Print the current settings. This option does not modify any settings, but simply prints all current option values on a single line.

Let us now take a look at a typical session with the debugger. For an example, we take the definition of the fac function from Writing a Script:

 
fac N                   = N*fac(N-1) if N>0;
                        = 1 otherwise;

The commented session with the debugger follows.

 
==> fac 1                                            evaluate fac 1
  0>  fac.q, line 1: fac 1  ==>  1*fac (1-1) if 1>0  try the first rule …
(type ? for help)
: <CR>
**  1>0  ==>  true                                   evaluate the qualifier
  0>  fac.q, line 1: fac 1  ==>  1*fac (1-1)
: <CR>
**  1-1  ==>  0                                      evaluate 1-1 argument
  1>  fac.q, line 1: fac 0  ==>  0*fac (0-1) if 0>0  try the first rule on fac 0
: p
stack size: 2                                        now two rules are on the stack
  0>  fac.q, line 1: fac 1  ==>  1*fac (1-1)
  1>  fac.q, line 1: fac 0  ==>  0*fac (0-1) if 0>0
: <CR>
**  0>0  ==>  false                                  qualifier fails
  1>  fac.q, line 2: fac 0  ==>  1                   try the second rule …
: <CR>
**  fac 0  ==>  1                                    bingo! reduce fac 0 to 1
  0>  fac.q, line 1: fac 1  ==>  1*fac (1-1)         return to the suspended rule
: <CR>
**  1*1  ==>  1
**  fac 1  ==>  1                                    final reduction …
1                                                    … and the result printed by the
                                                     interpreter
==>

[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Albert Gräf on February, 23 2008 using texi2html 1.76.