2012-03-13 78 views
2

我用泥調試我Common Lisp的功能未綁定變量。在函數內部,我將它人爲地發出錯誤信號(試圖「調試」 -perhaps我應該踩着),像這樣:評估表達式僅產生

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

現在我打Ë到調用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

嘗試使用符號的完整名稱(即package::symbol-name)而不是僅使用符號名稱(即symbol-name)。在目前的情況下,可能是net.telent.date::last-space

另外,還要確保你與調試支持設置爲最高(例如,試着將一個(declaim (optimize debug))之前,你的功能和重新編譯文件 - C-C C-K)編制。

檢查你要調試的代碼有足夠的調試信息:在SLDB窗口,把光標放在相關線路的回溯,按 - 這應該擴大爲所有的幀,並顯示值當地人。按t再次摺疊本地幀信息。如果沒有足夠的調試信息,則不會看到局部變量,但有些組成了名稱(如SBCL下的SB-DEBUG:ARG-0)。裏面的SLDB窗口,如果按把光標放在第一個值輸入,它將(如果該值是表示截斷了一長串有用)展開值到檢查器窗口。

此外,泥調試支持似乎與實施而有所不同。上述建議適用於Linux下的SBCL,YMMV在不同的實現下。

+0

在試圖評估調試器中的東西時使用'package :: symbol-name'的另一種方法是使用'in-package'在REPL中選擇相關的包。 – 2012-03-13 08:53:58

+0

謝謝! '(聲明(優化調試))'是我錯過的咒語。之後,所有當地人都列在「t」列表中(可通過「e」訪問)。我也剛剛瞭解到'package :: not-necessary-exported-symbol'語法 - 謝謝! – Ashe 2012-03-13 10:43:11

+3

您也可以使用'C-u'' C-c'' C-k'來編譯最大的調試設置。 – Daimrod 2012-03-13 10:43:58

2

變量似乎被優化掉。從SBCL Manual

變量的值可能由於這些原因不可用:

  1. 調試優化質量的值可以省略調試,以確定變量是否可用需要 信息。 除非變量是一個參數,它的價值將只提供 當調試至少
  2. 編譯器做了一輩子的分析和 確定該值已經不再需要,即使其範圍 尚未退出。當調試 優化質量爲
  3. 時,生命週期分析被禁止變量的名稱是一個未中斷的 符號(gensym)。爲了節省空間,當調試優化 質量爲
  4. 因爲輸入了調試器,因此幀的位置未知(請參見第5.3.5節[未知位置和中斷],第31頁),因此編譯器僅轉儲有關未中斷變量的調試 信息由於中斷或意外的硬件錯誤導致的 。在這些 條件下,參數值將可用,但可能是 不正確。這是上面提到的例外。
  5. 變量(或引用它的代碼 )已經過優化。沒有讀取的變量 總是被優化掉。 編譯器刪除變量的程度取決於編譯速度優化質量的值,但大多數源代碼級優化是在所有編譯策略下完成的。
  6. 該變量從未設置且其定義看起來像(LET ((var1 var2)) ...)在這種情況下,var1被替換爲var2
  7. 該變量從不設置,並且只被引用一次。在這種情況下,基準取代有可變初始值

你可以看到所有可用的本地變量與

如果您在之後添加了對變量的引用,那麼您的錯誤條件可能會在相應的調試幀中得到它的值。

+1

感謝您的參考!在這種情況下,它確實是導致我的問題的第一個問題,解決方案是「(聲明(優化調試))」等。 – Ashe 2012-03-13 10:48:03

3

還有另一個選項可用於調試Lisp函數:如果可用,請使用解釋器。大多數實現可以在解釋和編譯代碼之間切換。你可以運行編譯的所有代碼,但是你想要調試的函數可以運行解釋。在極端情況下,您甚至可以闖入解析函數的步進器(如果可用)。

請注意,根據您的要求定義默認優化設置是有意義的。

  • 不設置安全很低全球。只在代碼段中做到這一點很有用。

  • 不設置速度全球範圍內非常高。只在代碼段中做到這一點很有用。

  • 保持調試信息,使用2.根據實現方式的設置高調試設置可能會關閉尾調用優化(TCO) - 這可能是不可取的執行和理想的調試。

我會爲提出不同的設置:

  • 發展:安全+調試友好
  • 部署:的數字代碼安全
  • 優化,本地速度

通過默認情況下,您應該使用對交互式使用有用的設置:

  • 速度1-2。速度有點重要
  • 安全2-3。安全非常重要。在運行時檢查所有操作
  • debug 2-3。調試信息被保留,操作應該可以被調試器中斷。
  • 空間1.代碼的大小並不重要。
  • 編譯速度1.編譯過程的速度並不那麼重要。

範圍從0到3.沒有數字默認爲3. 3更高。

根據實施情況,可能會有額外的優化設置以及配置編譯器的一些變量。

在速度臨界區域,您可以設置高於安全和調試的速度。但請注意,在某些情況下,這會更改代碼執行的語義(錯誤檢測,溢出等),並且缺少運行時檢查可能會導致代碼破壞Lisp堆。

在某些交付情況下,調試設置非常低也可能有用。但是,如果你的Lisp編譯器設置爲高速優化和低調試,那麼通過查看堆棧的回溯來調試代碼可能會變得更加困難。