このページではJavaScriptを使用しています。

6.デバッガ

6-1.概要

この章では、AZ-Prologインタプリタに組み込まれているデバッガの使い方について説明します。このデバッガは虫取りだけでなく、インタプリタの動作そのものの理解の助けにもなると思います。
まず、次項の「6-2.デバッガの基本的な使い方(トレースとスパイ)」においてデバッガの基本的な使い方を解説します。

6-2.デバッガの基本的な使い方(トレースとスパイ)

AZ-Prologのトレースは、インタプリタが今現在何をしているのかの情報をすべてターミナルに出力します。表示される情報量は多く、どのような局面で情報を表示するかは設定で変えられるようになっています。情報量を選択することも可能です。
なにはともあれ、早速使ってみましょう。
その前に、

| 理解する(松尾さん,ワビ).↓             /*松尾さんは“ワビ”がわかる。*/
| 理解する(松尾さん,サビ).↓             /*松尾さんは“サビ”がわかる。*/
| 理解する(ブリキ屋さん,サビ).↓         /*ブリキ屋さんは“サビ”がわかる。*/
| 理解する(X,風流):- 理解する(X,ワビ).↓ /*“ワビ”がわかる人は風流を理解する。*/
| 理解する(X,風流):- 理解する(X,サビ).   /*“サビ”がわかる人は風流を理解する。*/

というプログラムを何等かの方法で入力してください。このサンプルは他の章でも説明に多用しているプログラムです。
邪魔なコードが混じっていない5-4-1.の例の部分を利用する方法もあります。正しく入力出来たか確かめてみます。

| ?-listing.↓
理解する(松尾さん,ワビ).
理解する(松尾さん,サビ).
理解する(ブリキ屋さん,サビ).
理解する(X,風流) :-
    理解する(X,ワビ).
理解する(X,風流) :-
    理解する(X,サビ).
yes
| ?-

まず、トレースを使ってみます。

| ?-trace.↓
yes
debug mode on
||?-

これで、次の質問からトレースがかかります。 厳密には「trace/0」が成功した時点からトレースがかかっています。プロンプトが「| ?-」から「||?-」に変わったのは、インタプリタがデバッグモード( 「6-3.デバッグモード」参照)で動いているということを知らせるためです。(トレースまたはスパイをかけると自動的にデバッグモードになります。 ) また、「LOOP=」に続く整数値はインタプリタがゴールを実行する際に述語を呼出した回数(下のトレースの実行例で、Tryした回数と言えば分かり易いですね。)です( 「6-4-3.ループカウンタ」参照)。

||?-理解する(ブリキ屋さん,風流).↓
 [1] 0 Try   : 理解する(ブリキ屋さん,風流) ?↓        (1)
  Match   : 理解する(ブリキ屋さん,風流) :-
                理解する(ブリキ屋さん,ワビ).          (2)
 [2] 1 Try   : 理解する(ブリキ屋さん,ワビ) ?↓        (3)
 [2] 1 Fail  : 理解する(ブリキ屋さん,ワビ)            (4)
 [1] 0 Pop   : 理解する(ブリキ屋さん,風流)            (5)
 [1] 0 Retry : 理解する(ブリキ屋さん,風流) ?↓        (6)
  Match   : 理解する(ブリキ屋さん,風流) :-
                理解する(ブリキ屋さん,サビ).          (7)
 << LAST CALL >>                                      (8)
 [1] 0 Try   : 理解する(ブリキ屋さん,サビ) ?↓        (9)
  Match   : 理解する(ブリキ屋さん,サビ).              (10)
 [1] 0 Succ  : 理解する(ブリキ屋さん,サビ)            (11)
yes
LOOP = 3
||?-

これらは以下のようなことを意味します。

(1)これから「理解する(ブリキ屋さん,風流)」を実行します(Try)。
(2)「理解する(ブリキ屋さん,風流)」と単一化可能な頭部を持つ節がみつかりました。それはこの節です(Match)。
     (質問: 「理解する(ブリキ屋さん,風流)」を「理解する(ブリキ屋さん,ワビ)」に置き換えます。)
(3)これから「理解する(ブリキ屋さん,ワビ)」を実行します(Try)。
(4)「理解する(ブリキ屋さん,ワビ)」と単一化可能な頭部を持つ節はありません(Fail)。
(5)「理解する(ブリキ屋さん,風流)」を実行しようとして、途中までうまくいきましたがだめでした。内部状態を元に戻します(Pop)。
(6)「理解する(ブリキ屋さん,風流)」 の別解を探します(Retry)。
(7)「理解する(ブリキ屋さん,風流)」に別の選択肢がありました。(Match)。
     (質問: 「理解する(ブリキ屋さん,風流)」を「理解する(ブリキ屋さん,サビ)」に置き換えます。)
(8)この節は定義の最終節です( << LAST CALL >>)。
(9)「理解する(ブリキ屋さん,サビ)」を実行します(Try)。
(10)「理解する(ブリキ屋さん,サビ)」と単一化可能な頭部を持つ節がみつかりました。それはこの節です(Match)。
(11)「理解する(ブリキ屋さん,サビ)」の実行に成功しました(Succ)

実行例の様に、デバッガの出力するメッセージには「Try」「Match」「Succ」「Fail」「Pop」「Retry」という、実行動作の局面を表す文字列が含まれています。
それぞれがどのような場合に出力されるのか、以上の説明によっておおよそ理解してもらえたと思います。
(詳しくは「6-4.デバッガから出力される情報」を参照してください。)

トレースを終えるには次のようにします。

||?-notrace.↓
 [1] 0 Try   : notrace ?↓
 << BUILTIN CALL >>
yes
LOOP = 1
||?-

「《BUILTIN CALL》」というのは「Try」した「notrace」が組込述語であった事を表しています。
トレース終了後のプロンプトを見て気付かれたと思いますが、デバッグモードは解除されていません。これを解除するには次のようにします。

||?-nodebug.↓
yes
debug mode off
| ?-

トレースは上の例でも分るように、ゴール(質問)の実行の最初から最後までに呼び出された全述語の実行の過程・結果を表示します。
従って、上の例ように簡単なプログラムの場合はともかく、ちょっと大きなプログラムになると出力される情報は膨大な量になってしまいます。
その例として次のサンプルプログラムを試してみましょう。このファイルはAZ-Prologのインストールディレクトリ下の「sample\other」に入っています(Linux版ではshare/azprolog/sample/other)。

| ?-[-'queen.pl'].↓

これはよく知られた8クイーンを解くプログラムです。
ただし、このプログラムは8クイーンだけではなくnクイーン(即ち、互いに取り合えないようなn×nの盤上のn個のクイーンの配置を求める問題です。)を解くことができます。

| ?-queen(4,X).↓
X       = [2,4,1,3]↓
yes
| ?-

試しに、これにトレースをかけてみてください。

| ?-trace.↓
yes
debug mode on
||?-queen(4,X).↓
 [1] 0 Try   : queen(4,X_5) ? ↓
  Match   : queen(4,X_5) :-
                generate(4,L1_11),
                put(L1_11,[],X_5).
 [2] 1 Try   : generate(4,L1_11) ? ↓
  Match   : generate(4,[4|L_15]) :-
                N1_17 is 4-1,
                generate(N1_17,L_15).
 [3] 2 Try   : N1_17 is 4-1 ? ↓
 << BUILTIN CALL >>
 [3] 2 Succ  : 3 is 4-1
 << LAST CALL >>
 [2] 1 Try   : generate(3,L_15) ? ↓
  Match   : generate(3,[3|L_26]) :-
                N1_28 is 3-1,
                generate(N1_28,L_26).
 [3] 2 Try   : N1_28 is 3-1 ? ↓
 << BUILTIN CALL >>
 [3] 2 Succ  : 2 is 3-1
 << LAST CALL >>
 [2] 1 Try   : generate(2,L_26) ? a↓    <- "a"を入力し"↓"(Enterキー)を押す
 LOOP = 6
||?-

おそらく、うんざりしてきたと思います。
(デバッガが「……?」ときいてきたときに「a ↓」を入力すればインタプリタのトップレベルに戻ります。)
こんなときのためにスパイがあります。 (下図の実行例で、?の後に縦棒のように見えているのは小文字のL(エル)です。Lコマンドについては「6-5」を参照してください。)

||?-notrace.
 [1] 0 Try   : notrace ? 
 << BUILTIN CALL >>
yes
LOOP = 1
||?-spy put/3.
yes
LOOP = 1
||?-queen(4,X).      
 [1] 0 Try   : put([4,3,2,1],[],X_5) ? l  <- Lコマンドを入力して改行
 [3] 1 Try   : put([3,2,1],[4],X_5) ? l
 [5] 2 Try   : put([3,1],[2,4],X_5) ? l
 [5] 2 Pop   : put([3,1],[2,4],X_5)
 [5] 2 Retry : put([3,1],[2,4],X_5) ? l
 [5] 2 Fail  : put([3,1],[2,4],X_5)
 [5] 2 Try   : put([3,2],[1,4],X_5) ? l
 [7] 3 Try   : put([2],[3,1,4],X_5) ? l
 [7] 3 Pop   : put([2],[3,1,4],X_5)
 [7] 3 Retry : put([2],[3,1,4],X_5) ? l
 [7] 3 Fail  : put([2],[3,1,4],X_5)
 [5] 2 Pop   : put([3,2],[1,4],X_5)
 [5] 2 Retry : put([3,2],[1,4],X_5) ? l
 [5] 2 Fail  : put([3,2],[1,4],X_5)
 [3] 1 Pop   : put([3,2,1],[4],X_5)
 [3] 1 Retry : put([3,2,1],[4],X_5) ? l
 [3] 1 Fail  : put([3,2,1],[4],X_5)
 [3] 1 Try   : put([4,2,1],[3],X_5) ? l
 [5] 2 Try   : put([4,2],[1,3],X_5) ? l
 [7] 3 Try   : put([2],[4,1,3],X_5) ? l
 [9] 4 Try   : put([],[2,4,1,3],X_5) ? l
 [9] 4 Pop   : put([],[2,4,1,3],X_5)
 [9] 4 Retry : put([],[2,4,1,3],X_5) ? l
 [9] 4 Succ  : put([],[2,4,1,3],[2,4,1,3])
 [7] 3 Succ  : put([2],[4,1,3],[2,4,1,3])
 [5] 2 Succ  : put([4,2],[1,3],[2,4,1,3])
 [3] 1 Succ  : put([4,2,1],[3],[2,4,1,3])
 [1] 0 Succ  : put([4,3,2,1],[],[2,4,1,3])
X       = [2,4,1,3]
yes
LOOP = 124
||?-

スパイはトレースすると、大量に出力される情報を人間が指定したものだけに制限します。上の例は、述語queen/2の中で呼ばれるput/3だけに限定して、その実行の流れを辿ったものです。(スパイは、機械語プログラムのデバッグ時によく使用されるブレークポイントに相当します。)
また当然ですが、複数個の述語にスパイを同時にかけることもできます。
スパイがどの述語にかかっているかは次のようにして知ることができます。

||?-debugging.↓

 << DEBUGGING >>

 Debug Mode     = debug                            (1)
 Unknown           = fail                          (2)
 Spy Points     = put/3                            (3)
 Command Point = Try Retry                         (4)
 Display Point = Try Match Succ Fail Pop Retry     (5)
 Verbos Mode   = middle                            (6)
yes
LOOP = 1
|| ?-

このように「debugging/0」によって

(1)現在デバッグモードか否か、もしくはトレースがかかっているかどうか。
(2)定義されていない述語を実行しようとしたとき、失敗するかトレースを始めるか。
(3)スパイがかかっている述語。
(4)トレース時にどの局面でコマンド入力を受け付けるか。(leash/1で設定。設定方法は「6-5-1.」を参照してください。)
(5)トレース時及びスパイにおいてどの局面を表示するか。(leash1/1で設定。設定方法は「6-4-3.(1)」を参照してください。)
(6)トレースの際に出力する情報量。(leash2/1で設定。設定方法は「6-4-3.(2)」を参照してください。


という6つの情報を得ることができます。

スパイの外しかたには2通りあります。ひとつは以下のような方法です。

||?-nospy put/3.↓
yes
LOOP = 1
||?-

もうひとつは「nodebug/0」によってデバッグモードを解除する方法です。
この述語は、デバッグモードを解除すると同時にすべてのスパイを外します。

||?-nodebug.↓
yes
debug mode off
| ?-

6-3.デバッグモード

このインタプリタにはデバッグモードがあります。(デバッグモードに対して普通の状態のことをノーマルモードと呼びます。)
前項のようにトレースかスパイをかけると自動的にデバッグモードに入りますが、「notrace/0」や「nospy/0」を実行してトレースまたはスパイを終了してもデバッグモードから抜けません。
つまり、トレースもスパイもかかっていないデバッグモードの状態がある訳です。
この状態では、ループカウンタを表示する以外、内部的な動作はほとんどノーマルモードと変りません。スタックなどのメモリを余計に消費するということもありません。
ただし、スパイポイントを調べる動作をするため、実行速度は若干(約10%程度)落ちます。従って、デバッグが終わって実際にプログラムを走らせる時には、必ずノーマルモードで動かすようにしてください。

デバッグモードか否かを知るには2つの方法があります。

(1)インタプリタのコマンドレベルのプロンプトを見る。

・ノーマルモードの場合
「| ?-」(ユーザモード)あるいは「! ?-」(システムモード)


・デバッグモードの場合
「||?-」(ユーザモード)あるいは「!!?-」(システムモード)


(2)debugging/0を実行してデバッグモードか否かをコンソールに表示する。
ノーマルモードからデバッグモードにするには「debug/0、spy/1、trace/0」のうちどれかを実行します。
逆に、デバッグモードからノーマルモードに戻すには「nodebug/0」を実行します。
プログラムの実行中においては、モードの移行はおこなわれませんので、通常はトップレベルにおいて質問、コマンドで与えます。ゴールの中に書かれたこれらのコマンドのうちモードの移行に関するものは、プログラムが終了しトップレベルに戻ってから移行がおこなわれます。ゴールとして「trace/0」を含むプログラムは初めからデバッグモードで実行させてください。
また、デバッグモードのまま「halt/0」「halt/1」でインタプリタを終了しても特に問題ありません。

6-4.デバッガから出力される情報

このデバッガでは、インタプリ夕の基本的な動作の局面を「Try、 Match、Succ、Fail、Pop、Retry」の6つに分けています。ですので、まず「6-4-1.インタプリタの基本的な動作局面」で各局面について説明します。その上で、「6-4-2.局面ごとの出力情報」では、どの局面で何が出力され、それはどのような意味を表しているのかを説明します。「6-4-3.出力情報の制御」では、デバッガが情報を出力する局面を変更したり、情報量を変える方法を説明します。デバッガの出力中に含まれる「LOOP =」について理解して頂くため、ループカウンタについて「6-4-4.ループカウンタ」で解説しています。また、「6-4-5.述語コールカウンタ」では、プログラム実行中にどの述語が何回呼ばれたかの集計情報を表示し、バグの検出や実行効率の向上に役立てる機能について説明しています。

6-4-1.インタプリタの基本的な動作局面
前述した6つの局面のそれぞれがどういう局面なのか、その局面では何が表示され(ここでは簡単に)、この局面が終わってからどのような局面に制御が移っていくのかということについて説明します。

(1)Try
【局面】 インタプリ夕が次に実行すべきゴールに移る時。
【表示】 これから実行するゴールを表示します。
【遷移】 そのゴールが組込述語なら、対応する機械語コードを呼び出し、成功すれば「Succ」に、失敗すれば「Fail」に制御が移ります。定義述語なら、そのゴールと単一化可能な頭部を持つ節を探し、あれば「Match」に、なければ「Fail」に制御が移ります。
(2)Match
【局面】 「Try」で表示されたゴールと単一化可能であるような頭部を持つ節をみつけた時。
【表示】 単一化された節を表示します。
【遷移】 その節が単位節(ゴール列を持たない節)なら「Succ」へ。それ以外は、その節の本体の最初のゴールを「Try」しに行きます。
(3)Succ
【局面】 実行したゴールが成功した時。
【表示】 成功したゴールを表示します。
【遷移】 そのゴールが節の本体の最後のゴールなら、節の頭部が成功し「Succ」へ、続くゴールがあれば、そのゴールを「Try」しに行きます。
(4)Fail
【局面】 組込述語の実行に失敗した時。あるいは「Try」または「Retry」するゴールと単一化可能な頭部を持つ節がなかった時。
【表示】 失敗したゴールを表示します。
【遷移】 「Pop」へと移ります。
(5)Pop
【局面】 バックトラック(後戻り)している時。
【表示】 バック卜ラックして不用になったゴールを表示します。
【遷移】 別の選択肢(その頭部が「Pop」したゴールと単一化可能かどうかまだ調べていない節)が見つかるまで「Pop」が続き、見つかった時点で制御は「Retry」へ移ります。
(6)Retry
【局面】 別の選択肢(代替節)が見つかった時。
【表示】 代替節を実行するゴールを表示します(「Try」の表示と同じ)。
【遷移】 未だ調べていない節から探し始める以外は「Try」同じです。


6-4-2.局面による出力情報

トレースをかけると、インタプリタが6つの局面の内のどれかに達した時、その局面名と現在インタプリタが注目しているゴールまたは節を表示します。これによって、今現在インタプリタが何をしているかがわかります。
ただし、このとき表示されるゴールまたは節は、それらの定義イメージそのままではありません。各局面に共通することなので、局面ごとの出力の説明に移る前に、このことについて若干説明します。


デバッガがゴールや節の情報を表示する場合、その中に現れる変数に値が代入(ユニファイ)されていたら、変数の部分は変数名ではなくその値が表示されます。

例:

||?-listing.↓
a(X) :-
    write(X).                   /*節の定義イメージ*/
yes
LOOP = 1
||?-trace,a(b(c)).↓            /*a(b(c))をトレース実行*/
 [1] 0 Succ  : trace
 [1] 0 Try   : a(b(c)) ?↓
  Match   : a(b(c)) :-
                write(b(c)).    /*節中の変数Xはb(c)に置換されている*/
 << LAST CALL >>
 [1] 0 Try   : write(b(c)) ?↓  
 << BUILTIN CALL >>
b(c) [1] 0 Succ  : write(b(c))
 [1] 0 Succ  : trace,a(b(c))
yes
LOOP = 4
||?-

このように、述語a/1の定義中の変数Xは、トレース実行時には項b(c)にユニファイされるので、各局面で表示される節やゴールでは項b(c)に置き換えられた形で表示されています。
一方、上の例には含まれませんが、未代入の変数の場合は、元々の変数名の後に「_NN」(アンダスコア+領域の取られたセル番号)が付加された形で表示されます。同じ節中でこの形の表示が同じものは同じ変数を表すと考えてください。他の節に同名の変数があっても、セル番号が違ってきますから、別物であることが容易に分かります。

デバッガーから出力される情報は、Matchとそれ以外の局面で内容が異なります。以下にそれぞれの場合を説明しますが、ここに書かれているのは「標準的なdebug情報」についての内容です。それ以外の場合については、「6-4-3.(2)出力される情報量の選択」を参照してください。

(1)Match以外の局面の場合

即ち、Try、Succ、Fail、Pop、Retryの場合の出力情報は以下の通りです。


[シリアルナンバー] スタックの深さ 局面名 : ゴール


ここで、シリアルナンバーは「インタプリテーションが始まってから何番目にこのゴールを実行しようとしたかの数値」、スタックの深さは「このゴールの実行までに使われているスタックの深さ」を表しています。

[15] 1 Try:queen1(4,[4,3,2,1],[],Ⅹ,[],[])?

局面名は「Try」です。
シリアルナンバーが「15」で、スタックの深さは「1」です。
「?」を出力してコマンド(「6-5.デバッガのコマンド」参照)を要求しています。


(2)Matchの場合

Matchの場合の出力情報は以下の通りです。
Match:頭部がゴールと単一化された節
例:

Match   : put([4,3,2,1],[],L_14) :-
select([4,3,2,1],S_22,D_24),
safe([],S_22,S_22),
put(D_24,[S_22],L_14).
6-4-3.出力情報の制御

ここではデバッガが情報を出力する局面を変更したり、情報量を変える方法を説明します。


(1)情報を出力する局面の選択

通常はすべての局面で情報が出力されますが、 「Try、 Match、Succ、Fail、Pop、Retry」のうち特定の局面に達したときのみ出力するように「leash1/1」によって設定することもできます。
「leash1(整数)」を実行すると、整数を2進数で表したときのビット0~5 (ビット0が最下位ビット:least significant bit)の6ビットの対応するビットが1である局面についてのみ出力されるようになります。ビットと局面の対応は以下の通りです。

ビット 5 4 3 2 1 0
局面 Retry Pop Fail Succ Match Try


例えば、「leash1(4)」を実行すると「Succ」のときにしか出力しません。
また、「leash1(63)」を実行するとすべての局面について出力されます。

【注意】
組込述語については、その種類(「5-10-1.組込述語」参照)にかかわらずヒープ領域に節の実体が無い為、その実行過程は表示されません。この場合「《BUILTIN CALL》」と表示されます。
また、 ヒープ領域に定義された述語(定義述語)であっても、決定性述語(代替節のない述語)の場合は、6つの局面のうち「Retry」と「Pop」の情報は出力されません。


(2)出力される情報量の選択 

トレースの際に出力する情報量は組込述語leash2/1で選択することができます。引数には0~2の整数値を与えます。数値の意味は以下の通りです。何もしなければ、デフォルトは1(標準的な情報出力)に設定されています。「6-4-2.局面ごとの出力情報」で解説した内容がこれに当たります。


0:最小のdebug情報
  Match以外の局面でのゴール表示は「述語名/アリティ」のみ。
Matchの局面での節は何も出力されません。
1:標準的なdebug情報
  「6-4-2.局面ごとの出力情報」を参照してください。
2:最大のdebug情報
 

標準的なdebug情報に加え、以下のような情報が出力されます。
< Clause No.1 :queen(N,L) >
これは、ゴールを単一化しようとした同一述語名/アリティの節の情報です。標準的な情報では、Try/RetryはMatchした節がある場合にしか表示されませんが、この節の情報にはMatchしなかったものも含まれます。


いずれかを選択するには以下のようにします。
例.最小のdebug情報の場合

?- leash2(0).

6-4-4.ループカウンタ

デバッグモードでは、ゴールから述語を呼出した回数をカウントする「ループカウンタ」が動作します。Prologのコマンドレベルから発せられる質問の実行が終了すると、そのカウントの結果が次の様に表示されます。

例: queen.plが読み込まれているとします。

||?-q(8).

:
:
No.92
 . . . Q . . . .
 . Q . . . . . .
 . . . . . . Q .
 . . Q . . . . .
 . . . . . Q . .
 . . . . . . . Q
 . . . . Q . . .
 Q . . . . . . .

Total = 92
yes
LOOP = 116718

この機能を使って例えば、「同じ動作をする二つのプログラムのどちらが動作効率がいいか(どちらのプログラムがコールの回数が少なくてすむか)」というようなプログラム効率の検証ができます。

細かい話ですが、もう一つループカウンタを使っていて少し「あれ?」と思われる事があるかも知れません。
それでは、次の質問を実行してみましょう。

||?-true.↓
yes
LOOP = 1
||?-

これはtrue/0という節(組込述語)を1回コールしたのですから納得できます。
問題は次の場合です。

||?-true,true.
yes
LOOP = 3
||?-

「true/0」を2回コールしたのですから「LOOP=2」となりそうですね。にも関わらず「LOOP=3」と表示されています。
これは、ゴールの区切りの「,」が文法上引数2個のオペレータとして扱われているため、インタプリタはこれを「','(true, true)」と解釈して、先ずこの「','/2」をコール(実行)してからその引数のコール(実行)にかかる為です。

しかし、実際には上で紹介した様な「どちらが動作効率がいいか」というような相対的に比べる使い方をする場合は関係ない事ではあります。

6-4-5.述語コールカウンタ

述語コールカウンタを利用すると、プログラムを実行した際にどの述語(組込、ユーザ定義とも)が何回呼ばれているかをチェックすることができます。


<用途>

  • 呼ばれるはずなのに表示されない、呼ばれるはずのない述語が表示される、などバグの検出
  • どの述語の負荷が高いか(すなわちCall回数が多いか)など、アルゴリズムの検討
  • 論理的に等価なプログラムでもゴールの並び順によって大きく効率が違うことがあるので呼び出し述語量の検討

など


<使い方>

デバッグモードにおいて、次のような形で質問をします。実行するプログラムをゴールで与えます。通常モードではゴールは実行されますが、述語呼び出し回数の集計情報は表示されません。

||  ?- call_count_check(ゴール).

プログラム(ゴール)が終了してトップレベルに戻った時に、使われた各述語がそれぞれ何回呼び出されたかを表示します。ユーザ述語/システム述語/組込述語(これらについては「5-1.述語の種類」を参照)の順に集計・表示されます。

<使用例>

$ prolog_c -c queen.pl
AZ-Prolog Version 7.54 (Linux/x64) 
Copyright (C) SOFNEC CO., LTD. 1987-2014/05/13
| ?-debug.
yes
debug mode on
||?-call_count_check(q(4)).
No.1
 . Q . .
 . . . Q
 Q . . .
 . . Q .
 
No.2
 . . Q .
 Q . . .
 . . . Q
 . Q . .
 
Total = 2
===CALL COUNT===
exec_status=succ
==== user ====
safe/3  =>  52
select/3  =>  49
disp2/1  =>  20
disp1/2  =>  20
put/3  =>  17
disp/2  =>  10
generate/2  =>  5
queen/2   =>  1
=== system ===
=== builtin ===
is/2  =>  106
\== /2  =>  64
write/1  =>  38
e_register/3  =>  4
nl/0  =>  2
yes
LOOP = 404
|| ?-


6-5.デバッガのコマンド

デバッガがある局面に達してその局面に関する情報をコンソールに出力した後に「?」を表示した場合には、デバッガに対してコマンドを入力することができます。(逆に、このような場合にしかコマンドを入力することはできません。)

どの局面でコマンド入力を受け付けるかは、設定によって変更することができます。まず、「6-5-1.コマンド入力局面の選択」でこの設定方法を説明し、次に「6-5-2.コマンド解説」で、使用できるデバッガのコマンドについて解説していきます。


6-5-1.コマンド入力局面の選択

デフォルトでは、「Try」「Retry」の2つの局面にインタプリタが達したときのみコマンド入力を受け付けるようになっています。
どの局面に達したときにトレース情報を表示するかを「leash1/1」によって変えられるのと同じように(前項参照)、どの局面のときコマンド入力を受け付けるかも「leash/1」によって変更する事が出来ます。
局面とビットとの対応は、前項の「leash1/1」と同じです。


ビット 5 4 3 2 1 0
局面 Retry Pop Fail Succ Match Try

また、やはり対応するビットが「1」である局面のときのみコマンド入力を受け付けます。

6-5-2.コマンド解説 

デバッガのコマンドには以下のようなものがあります。
(インタプリタがどの局面にさしかかっているかによって使えるコマンドも変わってきます。すべての局面では使えないコマンドについては、コマンド解説の最初に「使用可能局面:」でこれを示します。)

<carriage return> インタプリタが次の局面に達し次第、その局面に関する情報をコンソールに出力します。連続してこのコマンドを使うと、インタプリタの動作に関するすべての情報がコンソールに出力されます。
;(セミコロン) 【使用可能局面】「Match」「Succ」
「Match」において使われた場合には、単一化可能な頭部を持つ別の節を探しにいきます。
「Succ」使われた場合には、表示されたゴールの別の可能性を試します。
どちらの場合にも、その直後の実行に失敗してバックトラックした場合とまったく同じように動きます。そのような状態を強制的に作りだしているわけです。
A アボー卜します。
プログラムの実行を強制的に打ち切り、インタプリタのトップレベルに戻ります。
ただし、「errorset/2」または「consult/1」「reconsult/1」の中でこのコマンドが使われた場合には、そこでトラップされます。
「abort/0」を実行した場合とまったく同じです。
B 【使用可能局面】「Try」「Succ」「Fail」「Pop」「Retry」
プログラムの実行を中断し、新しいブレークレベルに入ります。 Aコマンドとは異なり、「unbreak/0」によって実行を再開することができます。デバッグの途中で、「leash/1」「leash1/1」などを使ってデバッガの出力情報の量をコントロールしたり、プログラムをエディットしたりする時に使います。
「break/0」を実行した時とまったく同じように動作します。
F 【使用可能局面】「Try」「Match」「Retry」
「Try」「Retry」において使われた場合には、表示されたゴールと単一化可能な頭部を持つ節の有無に関わらず直ちに失敗させます。
「Match」の場合には、表示された節も含めて、ゴールと単一化可能な頭部を持つ節は1つもなかったかのように動作します。
H それぞれの局面で使用可能なコマンドの表をコンソールに出力します。
L スパイまたはマーク(Sコマンド参照)がかかっているゴールに関する処理をインタプリタが行うまでデバッガの表示を打ち切ります。スパイまたはマークをかけた述語に関する情報のみを表示させたいときには連続してこのコマンドを使います。
N トレースまたはスパイポイントを解除します。ただしデバッグモードは解除されません。
P 先祖である節をすべて表示します。
(節1の本体にあるゴールと、単一化可能な頭部を持つ節2をインタプリタが見つけ、その実行に取り掛かったとします。そのようなとき、節1は節2の親であると呼びます。親および親の親、そのまた親の親・・・・を先祖と呼びます。)
J 【使用可能局面】「Try」「Match」
「Try」のとき、この述語を実行せずに決定性成功をします。
「Match」のとき、この節のボディーゴールを実行せずに成功します。
S 【使用可能局面】「Try」「Retry」
スタックにマークを付けます。
Q 【使用可能局面】「Try」「Retry」
スタックにマークを付け「Lコマンド」の処理を実行します。