The PrologJ interpreter's debugging facilities are based on facilities discussed
in [ Clocksin and Mellish 1994 ], but incorporate significant extensions beyond
what is discussed there. For efficiency's sake, the "hooks" used by these
mechanisms are not present in compiled code; however, these facilities can be
used on interpreted code that is called by compiled code (e.g. by
call/1
applied to a variable that is not instantiated until run time),
or, to a limited extent, when compiled code is called from interpreted code.
The intention, however, is that the interpreter will be used for code
development, with compilation being done for efficiency after errors are found
and removed.
All of the facilities described here are dependent on the setting of the
debug
flag. When this flag is on
, the facilities
described below are available. When this flag is turned off
, the
facilities described below are temporarily disabled. However, debugging status
information for various predicates (set by the means described below under
"Enabling/Disabling Tracing") remains recorded, and the
operations specified by those settings resume as soon as the flag is turned back
on
.
PrologJ's debugging facilities are based on the traditional "four event" model of Prolog goal execution. (These four events are called the "standard" events in the discussion which follows).
However, for user-defined predicates written in Prolog, PrologJ adds an
additional event which allow stepping through the clauses used to satisfy a
goal, and also stepping through their subgoals. The CLAUSE
event
occurs for each clause that can be used to satisfy the original goal
(i.e. whose head unifies with the goal).
A given goal is said to be traced if debugging applies to that goal. When one
of the four standard events occurs for a traced goal, a message is displayed
on standard output. (The message for the CLAUSE
event is more
voluminous and is discussed later.) This is true for any kind of predicate,
not just for predicates written in Prolog.
The message has one of the forms shown below.
[invocation number] CALL goal [invocation number] EXIT goal [invocation number] FAIL goal [invocation number] REDO goal
Where
invocation number
is a unique serial number assigned
to each goal that is traced - starting at "1" for the first goal traced
after a top-level goal, and increasing by 1 for each goal reported, with
the same number displayed at all events for a given goal. (Invocation
numbers always increase until control returns to the original top-level,
and start over at "1" for a new top-level goal).goal
is the goal being reported, with variable instantiations
created by the call at the EXIT
event, or the variable
instantiations from the last successful execution at the REDO
event, or with the variables uninstantiated at the CALL
and FAIL
events.
When a CLAUSE
event occurs, or when a leashed CALL
event occurs for a control-structure goal having subgoals, it is possible to
step through the execution of the clause or the subgoals of the control
structure - in which case each of the subgoals of the clause or control
structure is treated as leashed. The events for such a subgoal are reported as
described above, except that the event name includes _SUBGOAL
, so
the messages become
[invocation number] CALL_SUBGOAL goal [invocation number] EXIT_SUBGOAL goal [invocation number] FAIL_SUBGOAL goal [invocation number] REDO_SUBGOAL goal
Two different kinds of tracing are supported: leashed tracing, and unleashed
tracing. Leashed tracing is always specified on a predicate-by-predicate basis.
If leashed tracing is enabled for a predicate, then whether a given
event is leashed or merely traced is determined by the setting of the
leash
flag. If leashed tracing is
enabled for a predicate written in Prolog, the CLAUSE
event is always leashed. (Note that leashed tracing is possible for any kind
of predicate - but if the predicate is a built-in or is written in any language
other than Prolog, only the four "standard" events will occur.)
If leashed tracing is enabled for a given event, then after the message about
the event is printed, a "?"
prompt is printed and the system waits
for the user to issue one or more commands before proceeding. However, if the
event is not leashed, execution proceeds normally after displaying the message,
without waiting for a user-entered command.
Differing commands are recognized at different events, as listed on the pages limked to below. Commands may be abbreviated to any substring - even to their first letter. Debugger commands are not case sensitive.
Some commands cause execution to proceed to the next event. Others are executed and then await a further command at the same event.
If the user simply presses "enter" or "return" without typing a command at any event, execution proceeds normally as it would if the event were not leashed. That is, "enter" or "return" without a command is equivalent to the command noted as the default for the particular event.
CALL
event.
EXIT
event.
FAIL
event.
REDO
event.
CLAUSE
event.
CALL_SUBGOAL
event.
EXIT_SUBGOAL
event.
FAIL_SUBGOAL
event.
REDO_SUBGOAL
event.
When leashed tracing is enabled for a goal that calls a predicate written in
Prolog, it is possible to step through its CLAUSE
events by issuing
the step
command at its CALL
event. In this case,
a message like the following is printed at each CLAUSE
event:
[invocation number] CLAUSE clause-number head :- source location body ... Attempt this clause?
Where
invocation number
is the serial number assigned to the
goal at the CALL
event and used for all subsequent events for the
same goal.clause-number
is the relative number of the clause among the
clauses for its predicate (1 origin). Note that clauses whose head does
not unify with the goal do not cause a CLAUSE
event, but
are counted in the numbering of clauses.head
is the head of the clause, which has already successfully
unified with the goal, and whose variables reflect that fact.source-location
is the name of the source file and the line number in that
file where this clause was defined - omitted for clauses defined via
asserta/1
or assertz/1
.body
is the body of the clause, which will be pretty-printed.
All variables in the body will reflect the unification of the head with the
goal.
When stepping through the clauses for a predicate written in Prolog, it is
possible to request stepping through the events of the individual subgoals
by issuing the step
command at the CLAUSE
event.
Likewise, when at the CALL
event for a control structure goal
having subgoals, it is also possible to use step
to request
stepping through the subgoals. As noted above, in either case the events of
the subgoal will be reported, but with the event name having the suffix
_SUBGOAL
. The same debugger commands are available as are
available at the corresponding non-subgoal event.
Leashed or unleashed tracing can be initiated in one of three ways:
trace/0
or
notrace/0
builtin
predicates.spy/1
or
nospy/1
builtin predicates.
Unleashed tracing can be turned on or off for a specific predicate - or all
the predicates having a specific functor - by using the
trace/1
or
notrace/1
builtin
predicates.step
debugger command at the CLAUSE
event of a clause or the CALL
event of a control structure
goal. This causes the subgoal(s) to be leashed as well, but only applies
to that one call of the predicate.All of the builtin predicates for enabling/disabling tracing listed above are part of the Debug predicate set. This set also includes predicates for inquiring about the current state of tracing and for disabling tracing on all predicates.
Certain predicates cannot be traced. These are not reported when global tracing
is turned on, and are not printed in execution histories resulting from an error
or the history
command in the debugger. It is an error to
attempt to turn on unleashed or leashed tracing for any of these using
spy/1
or trace/1
. The step
command
cannot be used to leash a subgoal which uses one of these predicates.
','/2
fail/0
true/0