我正在使用SLIME来调试我的Common Lisp函数。在函数内部,我已经人为地发出错误信号(尝试“调试” - 我可能会踩到),如下所示:
(define-condition unknown-zone (error)
((text :initarg :text :reader text)))
(defun parse-mime-date (date)
(let ((last-space (position #\Space date :from-end t)))
(let ((date-time (net.telent.date:parse-time (subseq date 0 last-space)))
(zone (subseq date (1+ last-space))))
(unless (or (char= (elt zone 0) #\+)
(char= (elt zone 0) #\-))
(error 'unknown-zone :text (format nil "Unknown timezone: ~a" zone)))
(let ((hours (parse-integer (subseq zone 0 3)))
(minutes (parse-integer
(concatenate 'string
(list (elt zone 0))
(subseq zone 3)))))
(error 'unknown-zone :text "LOL")
(let ((adjusted-date-time (- date-time (* 60 (+ minutes (* 60 hours))))))
(format t "date-time: ~a; zone: ~a~%" date-time zone)
(format t "adjusted: ~a" (net.telent.date:universal-time-to-http-date adjusted-date-time)))))))
我正试图解决net.telent.date:parse-time
中似乎存在缺陷的问题(虽然我现在还不是100%),但这似乎会破坏时区处理。
“LOL”unknown-zone
错误当然是人为断点。
当它遇到函数的这一部分时,SLDB忠实地打开了回溯:
Bad type argument:
NS-MAIL2ZD::UNKNOWN-ZONE
[Condition of type SIMPLE-TYPE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [REMOVE-FD-HANDLER] Remove #<SB-IMPL::HANDLER INPUT on descriptor 7: #<CLOSURE (LABELS SWANK-BACKEND::RUN :IN SWANK-BACKEND:ADD-FD-HANDLER) {10030AD9FB}>>
3: [ABORT] Exit debugger, returning to top level.
Backtrace:
0: (MAKE-CONDITION NS-MAIL2ZD::UNKNOWN-ZONE :TEXT "LOL")
1: (ERROR NS-MAIL2ZD::UNKNOWN-ZONE :TEXT "LOL")
2: (NS-MAIL2ZD:PARSE-MIME-DATE "Wed, 14 Mar 2012 06:59:36 +1100")
3: (SB-INT:SIMPLE-EVAL-IN-LEXENV (NS-MAIL2ZD:PARSE-MIME-DATE *LOL*) #<NULL-LEXENV>)
4: (EVAL (NS-MAIL2ZD:PARSE-MIME-DATE *LOL*))
--more--
然后我向下翻页到框架:
Backtrace:
0: (MAKE-CONDITION NS-MAIL2ZD::UNKNOWN-ZONE :TEXT "LOL")
1: (ERROR NS-MAIL2ZD::UNKNOWN-ZONE :TEXT "LOL")
Locals:
SB-KERNEL::ARGUMENTS = (:TEXT "LOL")
SB-KERNEL::DATUM = NS-MAIL2ZD::UNKNOWN-ZONE
2: (NS-MAIL2ZD:PARSE-MIME-DATE "Wed, 14 Mar 2012 06:59:36 +1100")
现在我点击 e 来调用sldb-eval-in-frame
并输入last-space
,因为在发出错误信号时应该可用。
这似乎不是工作的意思(?):
The variable LAST-SPACE is unbound.
[Condition of type UNBOUND-VARIABLE]
Restarts:
0: [ABORT] Return to sldb level 1.
1: [RETRY] Retry SLIME REPL evaluation request.
2: [*ABORT] Return to SLIME's top level.
3: [REMOVE-FD-HANDLER] Remove #<SB-IMPL::HANDLER INPUT on descriptor 7: #<CLOSURE (LABELS SWANK-BACKEND::RUN :IN SWANK-BACKEND:ADD-FD-HANDLER) {10030AD9FB}>>
4: [ABORT] Exit debugger, returning to top level.
Backtrace:
0: ((LAMBDA (#:G1144)) #<unavailable argument>)
--more--
有没有办法做我想要的?我是不是太复杂了?
谢谢!
附录:我尝试过使用(break)
(这似乎有点规范),但我仍然看不到let
- 绑定变量与 ë。 :其中
答案 0 :(得分:3)
尝试使用符号的完整名称(即package::symbol-name
)而不仅仅是符号名称(即symbol-name
)。在目前的情况下,可能是net.telent.date::last-space
。
还要确保编译时将调试支持设置为最大值(例如,尝试在函数前放置(declaim (optimize debug))
并重新编译文件 - C-c C-k )。
检查您尝试调试的代码是否有足够的调试信息:在sldb窗口中,将光标放在回溯中的相关行上并按 t - 这应该扩展框架和显示所有本地人的值。按 t 再次折叠本地帧信息。如果没有足够的调试信息,您将看不到局部变量,但有些组成了名称(例如SBCL下的SB-DEBUG:ARG-0
)。在sldb窗口内,如果你按 Enter 并将光标放在一个值上,它会将该值扩展到一个检查器窗口(如果值是一个显示为截断的长列表,则非常有用)。
此外,SLIME调试支持似乎随实现而变化。上面的建议适用于Linux下的SBCL,YMMV在不同的实现下。
答案 1 :(得分:3)
调试Lisp函数还有另一种选择:使用解释器(如果可用)。大多数实现可以在解释和编译代码之间切换。您可以运行所有已编译的代码,但您要调试的函数可能正在运行解释。在极端情况下,您甚至可以使用解释函数(如果可用)进入步进器。
请注意,根据您的要求定义默认优化设置是有意义的。
不要将安全设置得非常低。只在有用的代码部分中执行此操作。
不要将速度设置得非常高。只在有用的代码部分中执行此操作。
保留调试信息,使用2的设置。根据实现,高调试设置可能会关闭尾调用优化(TCO) - 这可能不适合执行并且需要调试。
< / LI>我会为:
提出不同的设置默认情况下,您应该使用对交互使用有用的设置:
范围从0到3.没有数字默认为3. 3更高。
根据实现情况,可能还有其他优化设置以及一些变量来配置编译器。
在速度关键部分,您可以设置高于安全和调试的速度。但要注意,在某些情况下,这会改变代码执行的语义(错误检测,溢出,......),并且缺少运行时检查可能会使您的代码破坏Lisp堆。
在某些交付情况下,调试设置非常低可能也很有用。但是如果你的Lisp编译器被设置为高速优化和低调试,那么通过查看堆栈的回溯来调试代码可能会变得更加困难。
答案 2 :(得分:2)
该变量似乎已被优化掉了。来自SBCL Manual:
由于以下原因,变量的值可能不可用:
- 调试优化质量的值可能省略了调试 确定变量是否可用所需的信息。 除非变量是参数,否则其值仅可用 当调试至少
时- 编译器进行了生命周期分析 确定不再需要该值,即使其范围 没有退出。调试时禁止生命周期分析 优化质量
- 变量的名称是未加工的 符号(gensym)。为节省空间,编译器仅转储调试 调试优化时有关未分隔变量的信息 质量是
- 框架的位置未知(参见第5.3.5节[未知位置和中断],第31页)因为输入了调试器 由于中断或意外的硬件错误。根据这些 条件参数的值可用,但可能是 不正确。这是上面提到的例外情况。
- 变量(或 引用它的代码)已经过优化。变量 没有读数总是被优化掉。程度 编译器删除变量将取决于值 编译速度优化质量,但大多数源级 优化在所有编译策略下完成。
- 永远不会设置变量,其定义如下
(LET ((var1 var2)) ...)
在这种情况下,var1
将替换为var2
。- 永远不会设置变量,只引用一次。在这种情况下,引用将替换为变量初始值
醇>
您可以使用 t 查看所有可用的局部变量。
如果在错误条件之后添加对变量的引用,可能您将能够在相应的调试框架中获取其值。