4

我在 Mac 上使用 CCL(1.8.1——撰写本文时可用的最新版本),想知道是否有任何可用的调试教程。

我特别感兴趣的是在我的代码中的某处设置断点,然后戳和刺激各种值,然后跨过下一行代码,检查更多值等。

编辑: 我已经阅读了 CCL 手册的调试部分(18.3 左右),但不太明白。我来自 C/Java/等。背景和基于 IDE 的源代码级调试器,对 gdb 有一点了解。

所以我想我正在寻找的是一个介绍/教程,它可以引导我完成一些更简单的步骤。

(我是 Lisp 的新手(当然还有 CCL),所以,如果我问的问题完全错误,或者处理事情的方式完全错误,请随时告诉我。)

谢谢!

4

3 回答 3

9

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.

于 2013-08-07T03:44:15.830 回答
4

您正在寻找的简单答案由 juanitofatas 给出。不幸的是,CCL 不支持步进,因此在调试方面很弱。到目前为止,最好的调试实现是 CLISP。

于 2013-08-25T10:45:02.890 回答
0

在 ccl 中,您可以使用cl-stepper:step而不是cl:step.

(ql:quickload "com.informatimago.common-lisp.lisp.stepper")

于 2014-10-13T05:06:42.270 回答