[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
GNU Emacsには2つのデバッガ、debug
とedebug
がある。 最初のものは、Emacs内部に組み込まれていていつでも使える。 2番目のものはEmacsに対する拡張であり、 第19版で標準ディストリビューションの一部になった。
どちらのデバッガも節 `Debugging Lisp Programs' in
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
debug
debug
"へのコメント(無し)
1から指定した数までの総和を求める関数定義を書いたとしよう (まえに説明した関数triangle
である。 説明は、See 節 減少カウンタの例)。
しかし、関数定義にはバグがある。 `1-'を`1='とタイプミスした。 まちがった定義はつぎのとおりである。
(defun triangle-bugged (number) "Return sum of numbers 1 through NUMBER inclusive." (let ((total 0)) (while (> number 0) (setq total (+ total number)) (setq number (1= number))) ; ここがエラー total)) |
Infoで読んでいる場合には、いつものようにこの定義を評価できる。 エコー領域にtriangle-bugged
と表示される。
引数4で関数triangle-bugged
を評価してみる。
(triangle-bugged 4) |
つぎのようなエラーメッセージが出る。 Symbol's function definition is void: 1= |
実際、このような単純なバグならば、このエラーメッセージから 定義を修正するために必要なことがらがわかる。 しかし、何が起こっているのかわからなかったとしよう。
debug-on-error
の値をt
に設定してデバッガを有効にする。
(setq debug-on-error t) |
これは、Emacsにつぎにエラーを検出したらデバッガに入るように指示する。
debug-on-error
にnil
を設定すればデバッガを無効にできる。
(setq debug-on-error nil) |
debug-on-error
にt
を設定し、つぎの式を評価する。
(triangle-bugged 4) |
こんどは、Emacsは、つぎのようなバッファ`*Backtrace*'を作成する。
---------- Buffer: *Backtrace* ---------- Signalling: (void-function 1=) (1= number)) (setq number (1= number))) (while (> number 0) (setq total (+ total number)) (setq number (1= number)))) (let ((total 0)) (while (> number 0) (setq total ...) (setq number ...)) total)) triangle-bugged(4) eval((triangle-bugged 4)) eval-last-sexp(nil) * call-interactively(eval-last-sexp) ---------- Buffer: *Backtrace* ---------- |
(この例は少々整形してある。 デバッガは長い行を折り畳まない。)
バッファ`*Backtrace*'は、下から上へ向けて読む。 Emacsが何を行ってエラーに至ったかを教えてくれる。 この場合は、EmacsはC-x C-e(eval-last-sexp
)を対話的に呼び出し、 これはtriangle-bugged
式の評価につながった。 各行はLispインタープリタが、つぎに何を評価したのかを教えてくれる。
バッファの先頭から3行目はつぎのとおりである。
(setq number (1= number)) |
Emacsはこの式を評価しようとした。 そのために、先頭から2行目に示されたもっとも内側の式を評価しようとした。
(1= number) |
これがエラーを起こした場所であり、 先頭の行にはつぎのように表示されている。
Signalling: (void-function 1=) |
この誤りを修正して、関数定義を再評価し、再度試せばよい。
Infoで読んでいる場合には、 debug-on-error
にnil
を設定してデバッガを無効にする。
(setq debug-on-error nil) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
debug-on-entry
debug-on-entry
"へのコメント(無し)
関数に対してdebug
を起動する2番目の方法は、 関数を呼び出したときにデバッガに入ることである。 これにはdebug-on-entry
を呼ぶ。
つぎのようにタイプする。
M-x debug-on-entry RET triangle-bugged RET |
続いて、つぎの式を評価する。
(triangle-bugged 5) |
Emacsはバッファ`*Backtrace*'を作成し、 関数triangle-bugged
を評価し始めたことを伝える。
---------- Buffer: *Backtrace* ---------- Entering: * triangle-bugged(5) eval((triangle-bugged 5)) eval-last-sexp(nil) * call-interactively(eval-last-sexp) ---------- Buffer: *Backtrace* ---------- |
バッファ`*Backtrace*'の中で、dとタイプする。 Emacsはtriangle-bugged
の最初の式を評価し、 バッファはつぎのようになる。
---------- Buffer: *Backtrace* ---------- Beginning evaluation of function call form: * (let ((total 0)) (while (> number 0) (setq total ...) (setq number ...)) total)) triangle-bugged(5) * eval((triangle-bugged 5)) eval-last-sexp(nil) * call-interactively(eval-last-sexp) ---------- Buffer: *Backtrace* ---------- |
さらにdをゆっくりと8回タイプする。 dをタイプするたびに、Emacsは関数定義内の別の式を評価する。 最終的に、バッファはつぎのようになる。
---------- Buffer: *Backtrace* ---------- Beginning evaluation of function call form: * (setq number (1= number))) * (while (> number 0) (setq total (+ total number)) (setq number (1= number)))) * (let ((total 0)) (while (> number 0) (setq total ...) (setq number ...)) total)) triangle-bugged(5) * eval((triangle-bugged 5)) eval-last-sexp(nil) * call-interactively(eval-last-sexp) ---------- Buffer: *Backtrace* ---------- |
最後にさらにdを2回タイプすると、 Emacsはエラーに到達し、バッファ`*Backtrace*'の先頭の2行には つぎのように表示される。
---------- Buffer: *Backtrace* ---------- Signalling: (void-function 1=) * (1= number)) ... ---------- Buffer: *Backtrace* ---------- |
dをタイプすることで、関数を順を追って実行することができるのである。
バッファ`*Backtrace*'を終えるには、qとタイプする。 これは、関数の追跡を止めるが、debug-on-entry
を取り消さない。
debug-on-entry
の効果を無効にするには、 つぎのように、cancel-debug-on-entry
を呼んで関数名を与える。
M-x cancel-debug-on-entry RET triangle-debugged RET |
(Infoで読んでいる場合には、ここでdebug-on-entry
を取り消す。)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
debug-on-quit
と(debug)
debug-on-quit
と(debug)
"へのコメント(無し)
debug-on-error
を設定したりdebug-on-entry
を呼んだりすることに 加えて、debug
を起動するには別に2つの方法がある。
変数debug-on-quit
をt
に設定すると、 C-g(keyboard-quit
)とタイプすると いつでもdebug
を起動できる。 これは、無限ループのデバッグに役立つ。
あるいは、つぎのように、コード内のデバッガを起動したい場所に(debug)
を 入れておくことである。
(defun triangle-bugged (number) "Return sum of numbers 1 through NUMBER inclusive." (let ((total 0)) (while (> number 0) (setq total (+ total number)) (debug) ; デバッガを起動 (setq number (1= number))) ; ここがエラー total)) |
関数debug
は、節 `The Lisp Debugger' in
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
edebug
edebug
"へのコメント(無し)
Edebugはデバッグ中のソースコードを表示して、 現在評価中の行の左端に矢印を表示する。
関数の実行を行ごとに制御したり、実行を停止する ブレークポイント(breakpoint)まで素早く実行させたりできる。
Edebugは、節 `Edebug' in
バグのあるtriangle-recursively
の関数定義をつぎに示す。 復習するには、See 節 11.2.2 カウンタの代用としての再帰。 以下で説明するが、この例ではdefun
の字下げを書いてない。
(defun triangle-recursively-bugged (number) "Return sum of numbers 1 through NUMBER inclusive. Uses recursion." (if (= number 1) 1 (+ number (triangle-recursively-bugged (1= number))))) ; ここがエラー |
この定義をインストールするには、普通は、関数の閉じ括弧の直後にカーソルを 置いてC-x C-e(eval-last-sexp
)とタイプするか、 あるいは、定義の途中にカーソルを置いてC-M-x(eval-defun
) とタイプする (デフォルトでは、コマンドeval-defun
は、Emacs Lispモードか Lisp Interactiveモードのみで使える)。
しかし、この関数定義をEdebugで使うには準備する必要があり、 別のコマンドを使ってコードを処置する必要がある。 Emacs第19版では、定義の途中にカーソルを置いてつぎのようにタイプする。
M-x edebug-defun RET |
これにより、Emacsは必要ならばEdebugを自動的にロードし、 関数を正しく処置する (Edebugをロードしたあとは、C-u C-M-x (前置引数を指定したeval-defun
)などの標準的なキーバインドで edebug-defun
を呼び出せる)。
Emacs第18版では、読者自身がEdebugをロードする必要がある。 `.emacs'ファイルに適切なload
コマンドを入れておく。
Infoで読んでいる場合には、上に示した関数triangle-recursively-bugged
を 処置できる。 edebug-defun
は、defun
の行が字下げされていると 定義の切れ目を検出できない。 そのために、例ではdefun
の左側の空白を取ってある。
関数を処置したら、つぎの式の直後にカーソルを置いて C-x C-e(eval-last-sexp
)とタイプする。
(triangle-recursively-bugged 3) |
triangle-recursively-bugged
のソースに戻り、 カーソルが関数のif
の行の先頭に位置付けされる。 さらに、その行の左端に`=>'のような矢印が表示される。 矢印は、関数のどの行を実行中かを示す。
=>-!-(if (= number 1) |
In the example, the location of point is displayed as `-!-' (in a printed book, it is displayed with a five pointed star).
SPCを押すと、ポイントはつぎに実行すべき式へ移動し、 つぎのようになる。
=>(if -!-(= number 1) |
SPCを押し続けると、ポイントは式のあいだを移動する。 同時に、式が値を返すと、その値がエコー領域に表示される。 たとえば、number
のあとにポイントが移動したときには、 つぎのように表示される。
Result: 3 = C-c |
これは、number
の値は3であり、ASCIIコードではCTL-C (アルファベットの3番目の文字)であることを意味する。
エラーに達するまで、コードの中を移動できる。 評価するまえには、その行はつぎのようである。
=> -!-(1= number))))) ; ここがエラー |
もう一度SPCを押すと、つぎのようなエラーメッセージが表示される。
Symbol's function definition is void: 1= |
これがバグである。
`q'を押してEdebugを終了する。
処置した関数定義を削除するには、 単に処置しない普通のコマンドで関数定義を再評価すればよい。 たとえば、関数定義の閉じ括弧の直後にカーソルを 移動してC-x C-eとタイプする。
Edebugでは、関数の中を動き廻るよりも多くのことができる。 エラーを検出したり指定した停止位置に達した場合だけ停止するとか、 さまざまな式の値の変化を表示したり、 関数が何回呼ばれたかを調べたりなどである。
Edebugは節 `Edebug' in
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
count-words-region
をインストールし、 これを呼び出すと組み込みのデバッガを起動するようにせよ。 2つの単語を含んだリージョンに対してこのコマンドを実行せよ。 dを何度も押す必要がある。 読者のシステムでは、コマンドが終了したあとに「フック」が呼ばれるか? (フックについて詳しくは、節 `Command Loop Overview' in
count-words-region
をバッファ`*scratch*'にコピーし、 defun
の行のまえの空白を取り去ってから、 Edebug用に関数を処置し、実行を追ってみよ。 この関数にはバグはないはずであるが、必要ならばバグを入れてみよ。 関数にバグがなければ、何の問題にも出会わずに実行を完了する。
global-edebug-prefix
は、普通、C-x Xである。 つまり、CTL-xに続けて大文字のXである。 Edebugのバッファ以外でこのキー列を試してみよ)。
count-words-region
がバッファのどのリージョンで 動作しているかをコマンドp(edebug-bounce-point
)を 使って調べてみよ。
edebug-goto-here
)と タイプしてその場所へジャンプしてみよ。
edebug-trace-mode
)コマンドを使ってみよ。 edebug-Trace-fast-mode
を使うには大文字のTを使う。
[ << ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |