如何在[Clozure] Common Lisp中进行调试?

4
我正在Mac上使用CCL(1.8.1 - 此编写时最新版本),想知道是否有任何调试教程可用。我特别关注的是在我的代码中设置断点,然后探查各种值,接着跨过下一行代码,检查更多值等等。 编辑: 我已经阅读了CCL手册的调试部分(约18.3),但无法完全理解其中内容。我以前主要使用基于IDE的源代码级调试器,对gdb也只有一点了解。 因此,我希望能够找到一个介绍/教程,能够引导我完成一些简单的步骤。 (我对Lisp(和CCL)还很新,所以如果我问错问题或者走弯路,请随时告诉我。) 谢谢!
3个回答

9
我确定CCL用户会指向您CCL手册中的调试部分,但实际上,ANSI Common Lisp标准包括出色的调试工具,包括您所问及的breakstep(除了step的粒度不是基于代码行而是表单)。
事实上,整个条件系统值得研究。
还有一些教程可供参考
请记住,调试工具提供了普通的Lisp REPL(Read-Eval-Print Loop),您可以在其中执行与初始REPL相同的任何操作:定义函数和变量,检查现有变量(包括在进入调试器的函数中定义的变量)等。 此外,您可能能够发出其他命令,例如步进(step)和下一步(next)(通常缩写为:s和n)或继续(continue)(通常缩写为:c),以处理可连续错误。需要注意的一个区别是,在gdb中,您可以使用print x(缩写为p x)来检查变量x,而在Lisp中,只需键入x即可进行评估。以下是一些简单的示例:在此,?给出了有关可用命令的帮助;如果您的lisp barfs,请尝试help或:h。
> (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

请注意,步进器内的提示为step <level>,其中level是嵌套级别。

中断

> (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

这里的提示是Break <level>

断言

> (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 使用与 break 相同的提示。


CCL手册和Hyperspec都是优秀的参考资料,但我正在寻找更多的指导,这就是为什么我在寻求教程的原因。谢谢! - Olie
对于一个非常详细的答案给予加1。然而,当我在我的CCL(无论是1.8还是1.9)中键入“(step(factorial 3))”时,我得到了响应“6”(3!的答案)--没有步进。 - Olie
@Olie:最好在专门的CCL邮件列表上提出这个与CCL相关的问题。我猜测要么CCL仅支持对解释函数进行步进,而你的“阶乘”是已编译的;要么这是CCL中的一个错误。 - sds
2
CCL 不支持 STEP。根据此 Stack Overflow:https://dev59.com/questions/-WDVa4cB1Zd3GeqPgsdG#13211050 - Juanito Fatas
上面的回答应该被删除,因为它是误导性的。CCL不支持STEP。 - user2587965
显示剩余2条评论

4
你需要的简单答案由juanitofatas提供。不幸的是,CCL不支持step指令,因此在调试方面较弱。到目前为止,最好的实现方式是使用CLISP进行调试。

CCL不支持步骤。那个踩我的人是出于恶意而不是基于证据。下面得到6个赞的答案是错误的。 - user2587965

0
在CCL中,您可以使用cl-stepper:step代替cl:step(ql:quickload "com.informatimago.common-lisp.lisp.stepper")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接