The PrologJ Debugging Facilities

Overview

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).

Diagram showing traditional four event model

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).

Diagram showing PrologJ five event model

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

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

Leashed and Unleashed Tracing

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.

Commands Recognized During Leashed Tracing

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.

Stepping through Clauses Written in Prolog

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.

Stepping through Subgoals

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.

Enabling and Disabling Tracing

Leashed or unleashed tracing can be initiated in one of three ways:

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.
 

Copyright © 2009 - Russell C. Bjork. See the file See file COPYING in the root directory for copyright information.