框架中的评估表达式仅产生UNBOUND-VARIABLE

时间:2012-03-13 08:10:15

标签: lisp common-lisp slime

我正在使用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 - 绑定变量与 ë。 :其中

3 个答案:

答案 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>

我会为:

提出不同的设置
  • 开发:安全+调试友好
  • 部署:安全
  • 优化数字代码,本地速度

默认情况下,您应该使用对交互使用有用的设置:

  • 速度1-2。速度有点重要
  • 安全2-3。安全非常重要。在运行时检查所有操作
  • 调试2-3。保存调试信息,调试器可以中断操作。
  • space 1.代码的大小并不重要。
  • 编译速度1.编译过程的速度并不那么重要。

范围从0到3.没有数字默认为3. 3更高。

根据实现情况,可能还有其他优化设置以及一些变量来配置编译器。

在速度关键部分,您可以设置高于安全和调试的速度。但要注意,在某些情况下,这会改变代码执行的语义(错误检测,溢出,......),并且缺少运行时检查可能会使您的代码破坏Lisp堆。

在某些交付情况下,调试设置非常低可能也很有用。但是如果你的Lisp编译器被设置为高速优化和低调试,那么通过查看堆栈的回溯来调试代码可能会变得更加困难。

答案 2 :(得分:2)

该变量似乎已被优化掉了。来自SBCL Manual

  

由于以下原因,变量的值可能不可用:

     
      
  1. 调试优化质量的值可能省略了调试   确定变量是否可用所需的信息。   除非变量是参数,否则其值仅可用   当调试至少
  2. 时   
  3. 编译器进行了生命周期分析   确定不再需要该值,即使其范围   没有退出。调试时禁止生命周期分析   优化质量
  4.   
  5. 变量的名称是未加工的   符号(gensym)。为节省空间,编译器仅转储调试   调试优化时有关未分隔变量的信息   质量是
  6.   
  7. 框架的位置未知(参见第5.3.5节[未知位置和中断],第31页)因为输入了调试器   由于中断或意外的硬件错误。根据这些   条件参数的值可用,但可能是   不正确。这是上面提到的例外情况。
  8.   
  9. 变量(或   引用它的代码)已经过优化。变量   没有读数总是被优化掉。程度   编译器删除变量将取决于值   编译速度优化质量,但大多数源级   优化在所有编译策略下完成。
  10.   
  11. 永远不会设置变量,其定义如下(LET ((var1 var2)) ...)在这种情况下,var1将替换为var2
  12.   
  13. 永远不会设置变量,只引用一次。在这种情况下,引用将替换为变量初始值
  14.   

您可以使用 t 查看所有可用的局部变量。

如果在错误条件之后添加对变量的引用,可能您将能够在相应的调试框架中获取其值。