I'm using CCL on Mac (1.8.1 -- the latest available at this writing), and wondering if there's any sort of debugging tutorial available.
The thing I'm particularly interested in is setting a breakpoint somewhere in my code, then poking & prodding various values, then stepping over the next line of code, checking more values, etc.
EDIT:
I've read the debugging section of the CCL manual (18.3 and thereabouts), but can't quite make sense of it. I'm coming from a C/Java/etc. background and IDE-based source level debuggers, with just a little exposure to gdb.
So I guess what I'm looking for is an introduction/tutorial that walks me through a few of the simpler steps.
(I'm new to Lisp (and CCL, of course) so, if I'm asking completely the wrong question or going about things completely the wrong way, feel free to let me know.)
Thanks!
I am sure a CCL user might point you to the Debugging section in the CCL manual, but, in fact, the ANSI Common Lisp standard includes excellent debugging facilities, including break
and step
you asked about (except for step
's granularity is not based on a line of code but rather a form).
In fact, the whole Condition System is worth examining.
There are a few tutorials too.
The most important thing to remember that the debugging tools give you the normal Lisp REPL (Read-Eval-Print Loop) where you can do just about anything you can do with the initial REPL: define functions and variables, examine the existing variable (including those defined in the functions in which the debugger was entered) et al. Additionally, you might be able to issue additional commands, like step
and next
(often abbreviated :s
and :n
) in the stepper or continue
(often abbreviated :c
) in a continuable error.
One difference you need to watch for is that in gdb
you examine a variable x
using print x
(abbreviated p x
) while in Lisp you just type x
and it is evaluated.
Here are some simple examples:
Step
Here ?
gives help on available commands; try help
or :h
if your lisp barfs.
> (defun factorial (n) (if (zerop n) 1 (* n (factorial (1- n)))))
FACTORIAL
> (step (factorial 3))
step 1 --> (FACTORIAL 3)
Step 1 > ?
Commands may be abbreviated as shown in the second column.
COMMAND ABBR DESCRIPTION
Help :h, ? print this command list
Error :e print the last error message
Inspect :i inspect the last error
Abort :a abort to the next recent input loop
Unwind :uw abort to the next recent input loop
Reset :re toggle *PACKAGE* and *READTABLE* between the
local bindings and the sane values
Quit :q quit to the top-level input loop
Where :w inspect this frame
Up :u go up one frame, inspect it
Top :t go to top frame, inspect it
Down :d go down one frame, inspect it
Bottom :b go to bottom (most recent) frame, inspect it
Mode mode :m set stack mode for Backtrace: 1=all the stack elements
2=all the frames 3=only lexical frames
4=only EVAL and APPLY frames (default) 5=only APPLY frames
Frame-limit n :fl set the frame-limit for Backtrace. This many frames
will be printed in a backtrace at most.
Backtrace [mode [limit]] :bt inspect the stack
Break+ :br+ set breakpoint in EVAL frame
Break- :br- disable breakpoint in EVAL frame
Redo :rd re-evaluate form in EVAL frame
Return value :rt leave EVAL frame, prescribing the return values
Step :s step into form: evaluate this form in single step mode
Next :n step over form: evaluate this form at once
Over :o step over this level: evaluate at once up to the next return
Continue :c switch off single step mode, continue evaluation
-- Step-until :su, Next-until :nu, Over-until :ou, Continue-until :cu --
same as above, specify a condition when to stop
Step 1 > :s
step 2 --> 3
Step 2 > :n
step 2 ==> value: 3
step 2 --> (IF (ZEROP N) 1 (* N (FACTORIAL #)))
Step 2 > :s
step 3 --> (ZEROP N)
Step 3 > :n
step 3 ==> value: NIL
step 3 --> (* N (FACTORIAL (1- N)))
Step 3 > :s
step 4 --> N
Step 4 > :n
step 4 ==> value: 3
step 4 --> (FACTORIAL (1- N))
Step 4 > :s
step 5 --> (1- N)
Step 5 > :n
step 5 ==> value: 2
step 5 --> (IF (ZEROP N) 1 (* N (FACTORIAL #)))
Step 5 > :c
step 5 ==> value: 2
step 4 ==> value: 2
step 3 ==> value: 6
step 2 ==> value: 6
step 1 ==> value: 6
6
Note that the prompt inside the stepper is step <level>
where level
is the nesting level.
Break
> (defun assert-0 (x) (unless (eql x 0) (break "Bad x: ~S" x)) 0)
ASSERT-0
> (assert-0 0)
0
> (assert-0 'assert-0)
** - Continuable Error
Bad x: ASSERT-0
If you continue (by typing 'continue'): Return from BREAK loop
The following restarts are also available:
ABORT :R1 Abort main loop
Break 1 > x
ASSERT-0
Break 1 > :c
0
Here the prompt is Break <level>
.
Assert
> (defun my+1 (x) (assert (numberp x) (x) "must be a number: ~S" x) (1+ x))
MY+1
> (my+1 5)
6
> (my+1 'my+1)
** - Continuable Error
must be a number: MY+1
If you continue (by typing 'continue'): Input a new value for X.
The following restarts are also available:
ABORT :R1 Abort main loop
Break 1 > :c
New X> 'foo
** - Continuable Error
must be a number: FOO
If you continue (by typing 'continue'): Input a new value for X.
The following restarts are also available:
ABORT :R1 Abort main loop
Break 1 > :c
New X> 6
7
assert
uses the same prompt as break
.
The simple answer you are looking for is given by juanitofatas. Unfortunately CCL does not support step and hence is weak in debugging. Until now the best implementation to debug is CLISP.
in ccl, you can use cl-stepper:step
instead of cl:step
.
(ql:quickload "com.informatimago.common-lisp.lisp.stepper")