Lispプログラムのデバッグ
**************

Emacs Lispプログラムの問題点を調べるには、問題が発生したときにどのようにプログラムを使っているかに依存して、 3つの方法があります。

  * プログラムを実行したときに問題が発生した場合には、実行中に何が起こっているかを調べるためにLispデバッガを使える。通常のデバッガに加えて、Emacsにはソースレベルデバッガedebugもある。本章では両者について述べる。

  * 構文的な問題があるためにLispがプログラムを読み取れないときには、 EmacsのLisp編集機能を使ってその場所を特定する。

  * プログラムをバイトコンパイラでコンパイルするときに問題が発生するときには、コンパイラの入力バッファの調べ方を知る必要がある。

他の有用なデバッグツールは、ドリブルファイルです。ドリブルファイルをオープンしてあると、 Emacsはすべてのキーボード入力をこのファイルにコピーします。あとでこのファイルを調べれば、どんな入力があったかわかります。 See Terminal Input。

端末設定に関した問題を解決するには、関数open-termscriptが有用です。 See Terminal Output。

Lispデバッガ
========

通常のLispデバッガは、フォームの評価を一時停止する機能を提供します。評価を一時停止しているあいだ（ブレーク（break）と呼ばれる状態）は、実行時スタックを調べたり、ローカルやグローバル変数の値を調べたり、それらの値を変更できます。ブレークは再帰編集なので、Emacsの通常の編集機能すべてを使えます。デバッガを再帰的に起動するようなプログラムを実行することさえできます。 See Recursive Editing。

エラーによるデバッガの起動
-------------

デバッガへ入るもっとも重要な時期は、Lispエラーが発生したときです。これにより、エラーの直接原因を調べることができます。

しかし、デバッガに入るのは、エラーの通常の帰結ではありません。多くのコマンドは（バッファの末尾でC-fを使うなどの）不適切に起動されるとしばしばLispエラーを生じますが、通常の編集ではそのたびにデバッガに入ったのではとても不便です。そのため、エラーによってデバッガに入りたい場合には、変数debug-on-errorにnil以外を設定します。（コマンドtoggle-debug-on-errorはこれを簡単に行う。）

 -- User Option: debug-on-error
     この変数は、エラーが通知され処理されないときにデバッガを呼び出すかどうか決定する。 debug-on-errorがtであると、すべての種類のエラー（debug-ignored-errorsに指定したものを除く）はデバッガを呼び出す。 nilであるとデバッガを呼び出さない。

     その値はデバッガを呼び出すエラー条件のリストでもよい。たとえば、リスト(void-variable)にすると、「値を持たない変数に関したエラー」のみがデバッガを起動する。

     この変数がnil以外であると、 Emacsはプロセスのフィルタ関数や番兵に対してエラーハンドラを作成しない。したがって、これらの関数でのエラーもデバッガを起動する。 see Processes。

 -- User Option: debug-ignored-errors
     この変数は、デバッガに入らないエラーの種類を指定する。その値はエラー条件シンボルや正規表現のリストである。エラーにこれらの条件シンボルが含まれるかエラーメッセージが正規表現の1つに一致する場合には、 debug-on-errorの値に関わらず当該エラーではデバッガに入らない。

     この変数の通常の値は、編集ではしばしば発生するが、Lispプログラムのバグではほとんど発生しないようなエラー群のリストである。しかし、『ほとんど』は『けっして』ではない。このリストに一致するようなエラーで読者のプログラムが失敗する場合、エラーをデバッグするにはこのリストを変更する必要がある。もっとも簡単な方法は、debug-ignored-errorsにnilを設定することである。

 -- User Option: debug-on-signal
     通常、condition-caseで捕捉したエラーは、たとえdebug-on-errorがnil以外であっても、けっしてデバッガを起動しない。いいかえれば、デバッガを起動するまえに、 condition-caseはエラー処理の機会を得るのである。

     debug-on-signalにnil以外の値を設定すると、各エラーごとにデバッガがまず機会を得る。 debug-on-errorとdebug-ignored-errorsの値で指定される条件に一致すれば、condition-caseに関わらずエラーはデバッガを起動する。

     警告：この変数は強力な処方である！ Emacsのさまざまな部分では通常の動作としてエラーを処理し、読者にはエラーが発生したことさえわからない。 debug-on-signalにnil以外の値を設定するとそれらのエラーでデバッガに入る。

     警告： debug-on-errorがnilであると、 debug-on-signalは意味を持たない。

ファイル.emacsをロード中に発生するエラーをデバッグするには、オプション--debug-initを使います。これにより、.emacsのロード中はdebug-on-errorをtに束縛し、初期化ファイルでのエラーを捕捉するcondition-caseを迂回します。

読者のファイル.emacsでdebug-on-errorを設定しても、その効果は.emacsのロードを終ると持続しません。（これはコマンド行オプション--debug-initの実装における好ましくない特性である。） .emacsでdebug-on-errorを恒久的に設定する最良の方法は、つぎのように、after-init-hookを用いることです。

     (add-hook 'after-init-hook
               '(lambda () (setq debug-on-error t)))

無限ループのデバッグ
----------

プログラムが無限にループし戻ってこないときには、まず、ループを停止する必要があります。ほとんどのオペレーティングシステムでは、中断を意味するC-gを使います。

普通に中断したのでは、プログラムが無限ループした理由に関する情報は得られません。より詳しい情報を得るには、変数debug-on-quitにnil以外を設定します。 C-gによる中断はエラーとは扱わないため、 C-gの処理に関してdebug-on-errorはなんの効果もありません。同様に、debug-on-quitはエラーに関してなんの効果もありません。

無限ループの途中でデバッガを起動できれば、デバッガでステップ実行コマンドを使って先へ進めます。ループひとまわりをステップ実行すれば、問題を解決するに十分な情報を得られるはずです。

 -- User Option: debug-on-quit
     この変数は、quitが通知され処理されなかった場合に、デバッガを呼び出すかどうかを決定する。 debug-on-quitがnil以外である場合、（C-gを打って）中断するとデバッガを呼び出す。 debug-on-quitがnilであると、中断してもデバッガを呼び出さない。 see Quitting。

関数呼び出し時のデバッガの起動
---------------

プログラムの途中で発生する問題点を調べるための1つの有用な技法は、ある関数を呼び出すたびにデバッガに入ることです。問題を生じる関数に対してこのようにしておき、当該関数をステップ実行するか、あるいは、問題が発生する直前に呼ばれる関数に対してこのようにしておき、その関数の呼び出しを終えてから、呼び出し側をステップ実行します。

 -- コマンド: debug-on-entry function-name
     この関数は、FUNCTION-NAMEが呼び出されるたびにデバッガを起動するようにする。当該関数の定義の最初のフォームとしてフォーム(debug 'debug)を挿入することでこれを行う。

     Lispコードで定義した任意の関数は、解釈実行コードであろうとコンパイル済みのコードであろうと、関数に入るときにブレークするようにできる。関数がコマンドであると、Lispから呼ばれたときや対話的に呼ばれたときに（引数を読み取ってから）デバッガに入る。（Cで書いた）基本関数は、この方法ではデバッグできない。

     debug-on-entryを対話的に呼び出すと、ミニバッファでFUNCTION-NAMEを問い合わせる。その関数がすでに呼び出し時にデバッガを起動するようになっていると、 debug-on-entryはなにもしない。 debug-on-entryはつねにFUNCTION-NAMEを返す。

     注意： debug-on-entryを使ったあとに当該関数を再定義すると、デバッガに入るためのコードがなくなる。実質的には、関数を再定義すると呼び出し時にブレークする機能を取り消すことになる。

          (defun fact (n)
            (if (zerop n) 1
                (* n (fact (1- n)))))
               => fact

          (debug-on-entry 'fact)
               => fact

          (fact 3)

          ------ Buffer: *Backtrace* ------
          Entering:
          * fact(3)
            eval-region(4870 4878 t)
            byte-code("...")
            eval-last-sexp(nil)
            (let ...)
            eval-insert-last-sexp(nil)
          * call-interactively(eval-insert-last-sexp)
          ------ Buffer: *Backtrace* ------

          (symbol-function 'fact)
               => (lambda (n)
                    (debug (quote debug))
                    (if (zerop n) 1 (* n (fact (1- n)))))

 -- コマンド: cancel-debug-on-entry function-name
     この関数は、FUNCTION-NAMEに対するdebug-on-entryの効果（呼び出し時にブレークする）を取り消す。対話的に呼び出すと、ミニバッファでFUNCTION-NAMEを問い合わせる。 FUNCTION-NAMEがnilであったり空文字列であると、すべての関数について、呼び出し時にブレークすることを取り消す。

     呼び出し時にブレークする設定をしていない関数に対して cancel-debug-on-entryを呼び出してもなにもしない。つねにFUNCTION-NAMEを返す。

デバッガの明示的な起動
-----------

読者のプログラムに式(debug)を書くと、その箇所でデバッガを呼び出すことができます。つまり、ソースファイルを訪問して適当な箇所にテキスト(debug)を挿入し、 C-M-xと打ちます。警告：一時的なデバッグ目的でこれを行う場合には、ファイルを保存するまえにこの挿入箇所をもとに戻すこと！

(debug)を挿入する箇所は、余分なフォームを評価してもその値を無視できる場所でなければなりません。（(debug)の値が無視されないと、プログラムの実行を変えてしまう！）もっとも適した一般的な場所はprognや暗黙のprognの内側です（see Sequencing）。

デバッガの使い方
--------

デバッガに入ると、それまで選択していたバッファをあるウィンドウに、 *Backtrace*という名前のバッファを別のウィンドウに表示します。バックトレースバッファでは、各行は現在実行中のLisp関数の各レベルです。このバッファの先頭には、デバッガを起動するに至った理由（エラーで起動されたときにはエラーメッセージと関連データ）を表すメッセージがあります。

バックトレースバッファは読み出し専用であり、各文字をデバッガコマンドであると定義した特別なメジャーモード、debuggerモードを使います。 Emacsの通常の編集コマンドも使えます。したがって、エラー発生時に編集していたバッファを調べるためにウィンドウを切り替えたり、バッファを切り替えたり、ファイルを訪れたり、その他のどんな編集でもできます。しかし、デバッガは再帰編集レベル（see Recursive Editing）であるので、デバッグを終えるときには、バックトレースバッファに戻ってからデバッガを（コマンドqで）終了するのが賢い方法です。デバッガを終了すると、再帰編集から抜けバックトレースバッファを削除します。

バックトレースバッファでは、実行中の関数とその引数の値を表示します。また、スタックフレームを記述する行へポイントを移動することでスタックフレームを指定できます。（スタックフレームとは、Lispインタープリタが関数の起動に関する情報を記録しておく場所である。）ポイントがある行に対応するフレームをカレントフレーム（current frame）と呼びます。デバッガのある種のコマンドはカレントフレームに作用します。

デバッガ自身はバイトコンパイルしたものを実行する必要があります。というのは、デバッガ自身が使用するスタックフレームのサイズを仮定しているからです。解釈実行だとこの仮定が成り立ちません。

デバッガコマンド
--------

デバッガ内（debuggerモード）では、通常のカーソル移動コマンドに加えて以下の特別なコマンドを使えます。（ウィンドウやバッファの切り替えなどのEmacsの通常の機能も使えることに留意。）

デバッガコマンドのもっとも重要な使い方はステップ実行であり、これにより制御の流れを調べることです。デバッガは、解釈実行版の関数の制御構造をステップ実行できますが、バイトコンパイルした関数ではできません。バイトコンパイルした関数をステップ実行したい場合には、同じ関数を解釈実行版の定義に置き換える必要があります。（これには、関数のソースを訪れて、その定義内でC-M-xと打つ。）

debuggerモードのコマンド一覧を以下に示します。

c
     デバッガを終了し実行を継続する。継続可能であれば、（デバッガ内で行った変数値やデータ構造に対する変更などの副作用を除いて）デバッガを起動しなかったかのようにプログラムの実行を再開する。

     継続が可能なのは、関数呼び出し時や終了時、明示的な起動、中断によりデバッガに入った場合である。エラーが原因でデバッガが起動されたときには継続できない。

d
     実行を継続するが、任意のLisp関数を呼び出すとデバッガに入る。これにより、式の部分式をステップ実行して部分式が計算する値やその動作を調べることができる。

     このようにしてデバッガを起動した関数呼び出しのスタックフレームには自動的に印が付き、そのスタックから抜けるとデバッガがふたたび呼び出される。この印を消すにはコマンドuを使う。

b
     フレームから抜けるとデバッガに入るようにカレントフレームに印を付ける。このように印を付けたフレームには、バックトレースバッファでは星印が付く。

u
     カレントフレームから抜けるときにデバッガに入らない。これは、当該フレームに対するコマンドbを取り消す。視覚的にはバックトレースバッファの当該行から星印が取られる。

e
     ミニバッファでLisp式を読み取り、それを評価し、その値をエコー領域に表示する。この操作の一環として、デバッガは重要なある種の変数やカレントバッファを変更する。 eはそれらの値をデバッガの外側の値に一時的に復元するので、それらを調べたり変更したりできる。これによりデバッガは透過的になる。対照的に、M-:はデバッガ内で特別なことは行わない。デバッガ内での変数値を表示する。

R
     eと同様であるが、バッファ*Debugger-record*での評価結果も保存する。

q
     デバッグ中のプログラムを終了する。 Emacsのトップレベルのコマンド実行へ戻る。

     C-gでデバッガへ入ったが、実際には中断したいのであってデバッグはしたくない場合にはコマンドqを使う。

r
     デバッガから値を指定して戻る。その値は、ミニバッファで式を読み取り、それを評価して得る。

     （bで指定したりdでフレームに入ることで） Lispの呼び出しフレームから抜けでたためにデバッガが起動された場合に、コマンドrは有用である。コマンドrで指定した値は、当該フレームの値として使われる。このコマンドは、debugを呼び出してその戻り値を使う場合にも有用である。さもなければ、rはcと同じ効果であり、指定した戻り値は関係ない。

     エラーでデバッガに入った場合にはrは使えない。

デバッガの起動
-------

ここでは、デバッガを起動するために使われる関数debugの詳細を述べます。

 -- Function: debug &rest debugger-args
     この関数はデバッガに入る。 *Backtrace*（あるいはデバッガの第2レベルに再帰的に入ると *Backtrace*<2>など）という名前のバッファに切り替え、 Lisp関数の呼び出しスタックに関する情報でこのバッファを満たす。そして再帰編集に入りdebuggerモードのバックトレースバッファを表示する。

     debuggerモードのコマンドcやrで再帰編集から抜けだし、 debugはそれ以前のバッファに切り替え debugを呼び出したところへ戻る。これは、関数debugが呼び出し側へ戻る唯一の手段である。

     DEBUGGER-ARGSの使い途は、 debugが引数の残りをバッファ*Backtrace*の先頭に表示し、ユーザーが読めるようにすることである。以下に述べる場合を除いて、これがこれらの引数の唯一の用途である。

     debugの第1引数が特定の値を持つ場合、特別な意味がある。（通常、これらの値はEmacs内部で用いるだけであり、プログラマがdebugを呼ぶときには使わない。）以下にこれらの特別な値を示す。

     lambda
          第1引数がlambdaであると、 debug-on-next-callがnil以外であるために関数に入るときにdebugを呼び出したことを意味する。デバッガはバッファの先頭にテキスト行Entering:を表示する。

     debug
          第1引数がdebugであると、関数に入るときにデバッガを起動するようになっていたために debugを呼び出したことを示す。デバッガは、lambdaの場合と同様に、Entering:を表示する。さらに、当該関数のスタックフレームに関数から戻るときにデバッガを起動するように印を付ける。

     t
          第1引数がtであると、 debug-on-next-callがnil以外であるときにフォームの並びを評価したために debugを呼び出したことを示す。デバッガはバッファの先頭行につぎの行を表示する。

               Beginning evaluation of function call form:

     exit
          第1引数がexitであると、スタックフレームから抜けるときにデバッガを呼び出すように印を付けたスタックフレームから抜けたことを示す。この場合、debugの第2引数はフレームからの戻り値である。デバッガはバッファの先頭行にReturn value:に続けて戻り値を表示する。

     error
          第1引数がerrorであると、エラーやquitが通知されたが処理されないためにデバッガに入ったことを示し、 Signaling:に続けて通知されたエラーとsignalの引数を表示する。たとえばつぎのとおり。

               (let ((debug-on-error t))
                 (/ 1 0))

               ------ Buffer: *Backtrace* ------
               Signaling: (arith-error)
                 /(1 0)
               ...
               ------ Buffer: *Backtrace* ------

          エラーが通知されたときには、変数debug-on-errorはnil以外であるはずである。 quitが通知されたときには、変数debug-on-quitはnil以外であるはずである。

     nil
          明示的にデバッガに入るときには、 DEBUGGER-ARGSの先頭としてnilを使う。 DEBUGGER-ARGSの残りはバッファの先頭行に表示される。この機能を用いてメッセージを表示でき、たとえば、debugを呼び出した条件の覚え書きにする。

デバッガの内部
-------

本節では、デバッガが内部的に使用する関数や変数について述べます。

 -- Variable: debugger
     この変数の値は、デバッガを起動するために呼び出す関数である。その値は、可変個数の引数を取る関数（あるいは典型的には関数名）であること。その関数でなんらかのデバッガに入ると仮定する。この変数のデフォルト値はdebug。

     Lispが関数に渡す最初の引数で、呼び出した理由を表す。引数の規約はdebugに記述してある。

 -- コマンド: backtrace
     この関数は、現在活性なLisp関数呼び出しのトレースを表示する。これは、debugがバッファ*Backtrace*を満たすために用いる関数である。どの関数呼び出しが活性であるかを判断するためにスタックを参照する必要があるためCで書いてある。戻り値はつねにnil。

     以下の例では、Lisp式で明示的にbacktraceを呼び出す。これにより、バックトレースをストリームstandard-outputに出力する。ここではバッファbacktrace-outputに出力する。バックトレースの各行は、1つの関数呼び出しを表す。関数の引数値すべてが判ればそれらを行に表示する。それらが計算途中であれば、その旨を行に表示する。スペシャルフォームの引数は省略する。

          (with-output-to-temp-buffer "backtrace-output"
            (let ((var 1))
              (save-excursion
                (setq var (eval '(progn
                                   (1+ var)
                                   (list 'testing (backtrace))))))))

               => nil

          ----------- Buffer: backtrace-output ------------
            backtrace()
            (list ...computing arguments...)

            (progn ...)
            eval((progn (1+ var) (list (quote testing) (backtrace))))
            (setq ...)
            (save-excursion ...)
            (let ...)
            (with-output-to-temp-buffer ...)
            eval-region(1973 2142 #<buffer *scratch*>)
            byte-code("...  for eval-print-last-sexp ...")

            eval-print-last-sexp(nil)
          * call-interactively(eval-print-last-sexp)
          ----------- Buffer: backtrace-output ------------

     文字*は、抜け出るときにデバッガを起動する印が付いているフレームを表す。

 -- Variable: debug-on-next-call
     この変数がnil以外であると、つぎにeval、apply、funcallを呼び出すまえにデバッガを呼び出すことを指定する。デバッガに入るとdebug-on-next-callをnilに設定する。

     デバッガのコマンドdは、この変数を設定することで動作する。

 -- Function: backtrace-debug level flag
     この関数は、LEVELの深さのスタックフレームに値FLAGに応じてフレームから抜け出るときのデバッガ呼び出しの印を付ける。 FLAGがnil以外であると、のちに当該フレームから抜けるとデバッガに入る。非ローカルな脱出で当該フレームから抜けるときにもデバッガに入る。

     この関数はデバッガのみが使用する。

 -- Variable: command-debug-status
     この変数は、現在の対話的コマンドのデバッグ状況を記録する。コマンドが対話的に呼び出されるたびに、この変数はnilに束縛される。デバッガはこの変数に設定することで、同じコマンドの起動中にデバッガが将来起動された場合に備えて情報を残すことができる。

     デバッガにとっては、通常のグローバル変数ではなくこの変数を使う利点は、以降のコマンド起動にデータが繰り越さないことである。

 -- Function: backtrace-frame frame-number
     関数backtrace-frameは、Lispデバッガで使うことを意図している。深さFRAME-NUMBERのスタックフレームで進行中の計算に関する情報を返す。

     当該フレームで引数の評価を完了していなければ（あるいはスペシャルフォーム）、値は(nil FUNCTION ARG-FORMS...)。

     当該フレームで引数の評価を完了し関数を呼び出していれば、値は(t FUNCTION ARG-VALUES...)。

     戻り値において、FUNCTIONは評価したリストのCARであるか、マクロ呼び出しではlambda式である。関数に引数&restがあれば、リストARG-VALUESの残りで表現される。

     FRAME-NUMBERが範囲外であると、backtrace-frameはnilを返す。

     [file edebug.texi not included]

不正なLisp構文のデバッグ
==============

Lispリーダは不正な構文を報告しますが、どこに問題があるかは報告できません。たとえば、式を評価中のエラー『End of file during parsing』（構文解析中にファイルの終り）は、開き括弧（あるいは開き角括弧）が多すぎることを表します。 Lispリーダは括弧が対応していないことをファイルの末尾で検出しますが、どこに閉じ括弧があるべきかは判断できません。同様に、『Invalid read syntax: ")"』（不正な構文：")"）は閉じ括弧が多すぎるか開き括弧が足りないことを表しますが、どこに括弧が足りないかは判断できません。それでは、どこを変更すべきかどのように調べるのでしょう？

問題が単純な括弧の非対応でなければ、各関数定義の先頭でC-M-eを試し、関数定義の末尾に移動するかどうかをみるのは有用な技法です。正しく移動しなければ、その関数に問題があります。

Lispによくある構文エラーは括弧の非対応なので、これらの場面について詳しい助言を述べておきます。（さらに、対応括弧表示モードをオンにしてポイントを移動すると非対応を探しやすい。）

開き括弧の過剰
-------

最初の手順は、括弧が対応していない関数定義を探すことです。開き括弧が過剰であれば、ファイルの末尾に閉じ括弧を挿入し C-M-b（backward-sexp）を打ちます。こうすると、括弧が対応していない関数定義の先頭へ移動します。（そうしたら、C-SPC C-_ C-u C-SPCと打って、当該箇所にマークを設定してから閉じ括弧の挿入を取り消し、最終的にマークへ戻る。）

つぎの手順は、なにが悪いか正確に判断することです。プログラムを調べる以外にこれを確実に行う方法はありませんが、しばしば、既存の字下げが括弧のありかたを予想する鍵になります。これを利用するもっとも簡単な方法はC-M-qで字下げし直し、どのようになるか見ることです。まだやらないでください！まず読み進んてください。

これを行うまえに、関数定義に充分な数の閉じ括弧があることを確認してください。さもないと、C-M-qがエラーになったり、ファイルの末尾までを字下げし直してしまいます。ですから、関数定義の末尾へ移動して閉じ括弧を挿入しておきます。 C-M-eを使って移動しないでください。というのは、関数定義の括弧の対応が取れていないと失敗するからです。

関数定義の先頭へ移動してC-M-qを打ちます。通常、ある場所から関数の末尾までの行が右へずれます。その場所の近くで、閉じ括弧が足りなかったり開き括弧が多すぎるのです。（しかし、これが正しいと仮定してはならない。コードを調べて確認すること。）不具合箇所がみつかったならば、意図した括弧に対しては古い字下げが適しているでしょうから C-_でC-M-qをアンドゥします。

問題を解決できたと思ったら、再度C-M-qを使います。古い字下げが意図した括弧の入れ子に対応していて、必要な括弧を挿入できているならば、 C-M-qはなにも変えないはずです。

閉じ括弧の過剰
-------

過剰な閉じ括弧に対処するには、まず、ファイルの先頭に開き括弧を挿入し、その括弧のまえでC-M-fを打って、括弧が対応していない関数定義の末尾を探します。（そして、C-SPC C-_ C-u C-SPCと打って、当該箇所にマークを設定して開き括弧の挿入をアンドゥし、最終的にマークへ戻る。）

その関数定義の先頭でC-M-fと打って、実際に対応している閉じ括弧を探します。これにより、関数定義が終るべき場所より手前の箇所に移動するはずです。この付近に余分な閉じ括弧がみつかることもあるでしょう。

その場所に問題がなければ、つぎにすべきことは、関数定義の先頭でC-M-qと打つことです。ある範囲の行が左にずれるでしょう。もしそうならば、開き括弧が足りないか余分な閉じ括弧は、そのような行の先頭付近にあるでしょう。（しかし、これが正しいと仮定してはならない。コードを調べて確認すること。）不具合箇所がみつかったならば、意図した括弧に対しては古い字下げが適しているでしょうから C-_でC-M-qをアンドゥします。

問題を解決できたと思ったら、再度C-M-qを使います。古い字下げが意図した括弧の入れ子に対応していて、必要な括弧を挿入できているならば、 C-M-qはなにも変えないはずです。

コンパイル時の問題のデバッグ
==============

バイトコンパイル時にエラーが発生したときは、通常、読者がコンパイルしているプログラムの不正な構文に原因があります。コンパイラはバッファ*Compile-Log*に適切なエラーメッセージを表示してから停止します。メッセージにはエラーとなった関数の名前があったりなかったりします。いずれにしても、つぎのようにしてファイルのどこでエラーが生じたかを調べます。

まず、バッファ *Compiler Input*に切り替えます。（バッファ名が空白で始まり、そのため、 M-x list-buffersでは表示されないことに注意。）このバッファにはコンパイルしたプログラムが入っていて、ポイント位置はバイトコンパイラがどこまで読み取ったかを表します。

エラーの原因が不正なLisp構文であるならば、ポイント位置が不正構文を検出した箇所を正確に表します。エラー原因が近くにあるとは限りません！エラーを探すために前節の方法を使ってください。

正しく読み取ったフォームのコンパイル中にエラーを検出したときには、ポイントはそのフォームの末尾に位置しています。この場合、この方法ではエラー箇所を正確に判別できませんが、どの関数を確認すべきかを示しています。