We first give a somewhat simplified sketch of how the debugger treats the breakpoints. This description will be refined in the sequel.
The debugger allows us to prescribe some activities to be performed at certain points of execution, namely at the ports of procedure boxes. In principle, the debugger is entered at each port of each procedure invocation. It then considers the current breakpoints one by one, most recent first. The first breakpoint for which the evaluation of the test part succeeds is then activated, and the execution continues according to its action part. The activated breakpoint “hides” the remaining (older) ones, i.e. those are not tried here. If none of the current breakpoints is activated, the debugger behaves according to the actual debugging mode (trace, debug or zip).
Both the test and the action part can be simple or composite. Evaluating
a simple test amounts to checking whether it holds in the current state
of execution, e.g. pred(foo/2)
holds if the debugger is at a
port of predicate foo/2
.
Composite conditions can be built from simple ones by forming lists, or
using the ‘,’, ‘;’, ‘->’, and ‘\+’ operators,
with the usual meaning of conjunction, disjunction,
if-then-else and negation. A list of conditions is equivalent to a
conjunction of the same conditions. For example, the condition
[pred(foo/2), \+port(fail)]
will hold for all ports of
foo/2
, except for the Fail port.