最近の更新 (Recent Changes)

2014-01-01
2013-01-04
2012-12-22
2012-12-15
2012-12-09

Wikiガイド(Guide)

サイドバー (Side Bar)

← 前のページに戻る

デカルト言語のデバッグ・トレース

1. トレース機能

デカルト言語のデバッグには、トレース機能を使うのが有効です。 実行プログラム全体のトレースは勿論、ある一部に着目してトレース表示を行い、それ以外の部分ではトレース機能をオフにするような柔軟なデバッグも可能です。

トレース情報としては以下のようなものがあります。

- 呼び出し述語の履歴
- 呼び出し述語の結果と引数の表示
- EBNF機能の読み込んだトークンの表示

2. トレース機能のON/OFF

トレース機能を有効にするには、-tまたは--traceオプションを付けてデカルト言語を起動します。


  descartes -t プログラム
または
  descartes --trace プログラム

すべてのプログラムの実行がトレースされ、トレース情報が出力されます。


または、プログラムの中でtronとtroff述語を使うと、プログラムの一部だけのトレースを行うことができます。

<tron>述語を実行するとトレース機能がオンになり、実行時にトレース情報が出力されます。

トレース機能をオフにする場合は、<troff>述語を実行してください。

次の例では、ex1, ex2の両方の実行とも、トレースされます。


? <tron>;

? <ex1 a>;
? <ex2 b c>;

troff述語が実行されると、トレースは解除されます。

次の例では、troffの実行後の、ex2はトレースされません。


? <tron>;

? <ex1 a>;
? <troff>;
? <ex2 b c>;

実行中の述語の連なりの途中にtron, troffを入れて、部分的にトレースを行うことも可能です。

次の例では、tronとtroffに囲まれたex2だけがトレースされます。


? <ex1 a> <tron> <ex2 b c> <troff> <ex3 d e f>;

3. トレース情報の見方

3.1 組み込み述語情報

トレース機能がONである場合に、プログラムで組み込み述語が実行されると、 以下のようなトレース情報が出力されます。


builtin: <組み込み述語>...success

組み込みモジュールであるsysモジュールが実行された場合は、 以下のようなトレース情報が出力されます。


sys module: ::sys <SYSモジュール組み込み述語>...success

次に示すのは、組み込み述語のprint述語と、sysモジュールの組み込み述語であるwritenl述語を 実行されたときに出力されるトレース情報です。


builtin: <print 7>...success


sys module: ::sys <writenl 7>...success

述語が実行されるときの変数や引数についても表示されていることに着目してください。

3.2 ユニフィケーション情報

デカルト言語の実行で最も多く実行されるのが、ユニフィケーション(単一化)です。 これは、プログラムのヘッドと実行しているプログラムを比較し、パターンマッチが成功した場合にはお互いの引数の変数を解決し、値を決定して から、ヘッドの後のボディの処理を順に実行していく処理です。

プログラムは以下に示すような構造になっています。

<述語>       <述語> <述語> ... <述語> ;
---------  ------------------------------------ 節
ヘッド           ボディ


<ヘッド述語> 
        <ボディ述語>  
        <ボディ述語> 
        <ボディ述語>
;


トレースのユニフィケーション情報は、ユニフィケーション処理の実行履歴を次に示すように表示していきます。


Unification: プログラム上のマッチしたヘッド
           : 実行する述語
Result     > ユニフィケーション結果 ...success

例えば、<ABC #X 456>を実行中に、<abc 123 #y>というプログラムのヘッダとユニフィケーションを行い成功すると 以下のようなログを表示します。


Unification: <abc 123 Undef3>
           : <abc Undef4 456> 
Result     > <abc 123 456>...success

変数はUndefN(Nは数字)のように変更されて表示されます。これは、同じ変数名であっても、異なるヘッドに属するプログラムの変数は まったく別のものであるためです。プログラムのヘッダから、最後のセミコロン";"までに出現する変数は、そのプログラム内だけの ローカル変数です。異なるヘッドに属するプログラムの変数を区別するため、トレース情報ではこのような別名で表示します。

別名が同じ変数は、同じ値をもつ同じ変数です。 反対に、プログラム上は同じ変数名でも、トレース情報で別の名前で表示されるものは、全く別の変数であることを示しています。

トレースの表示で、最初の行がプログラムのヘッドであり、2行目が実行中のプログラムです。

3行目がプログラムのヘッドと実行中のプログラムがユニフィケーション処理を行った結果です。 引数の変数がお互いの値に設定されて解決されています。

3.3 トークン情報

トレース機能がONである場合に、プログラムでトークン(EBNF解析機能)の述語が実行されると、 以下のようなトレース情報が出力されます。


token: ファイル入力と一致したトークン...success

例えば、"abc"というトークンが実行され、ファイル入力も"abc"の場合には以下のようにログが表示されます。


token: abc...success

3.4 未定義述語のトレース情報

未定義述語を呼び出そうとすると、以下のようなトレース情報が出力されます。


Undeclared predicate : 未定義述語

例えば<abc #x>という未定義の述語が実行されると以下のようにログが表示されます。


Undeclared predicate : <abc Undef0>

4. トレース例

以下に示すプログラムのトレースをとります。このプログラムは、"abc.car"という名前で保存しておきます。


<ghi>
        "abc" "defghi"
        ;

<def #x>
        ::sys <writenl #x>
        ::sys <syntax "abcdefghi" <ghi>>
        ;

<abc #x>
        ::sys <writenl #x>
        <print #x>
        <def <let _ = #x+1>>
        ;

?<tron>;
?<abc 7>;

下から2行目にtron述語が挿入されています。 その下の<abc 7>の実行を、トレースすることになります。

実行結果を以下に示しましょう。


$ descartes abc.car
builtin: <tron>...success        (1)
result --
        <tron>
-- true
? (<abc 7>)
Unification: <abc 7>        (2)
           : <abc Undef3>
Result     > <abc 7>...success
7
sys module: ::sys <writenl 7>...success  (3)
7
builtin: <print 7>...success         (4)
Unification: <def <let Undef4 = 7 + 1>>   (5)
           : <def Undef5>
Result     > <def <let Undef4 = 7 + 1>>...success
func : <let Undef4 = 7 + 1>
builtin: <let 8 = 7 + 1>...success
8
sys module: ::sys <writenl <let 8 = 7 + 1>>...success
Unification: <ghi>               (6)
           : <ghi>
Result     > <ghi>...success
token: abc...success              (7)
token: defghi...success            (8)
sys module: ::sys <syntax abcdefghi <ghi>>...success  (9)
result --
        <abc 7>                 (10)
-- true

(1)は、tron述語が成功し、デバッグとレースが有効になったことを示しています。

(2)は、まず?<abc 7>の実行を行います。プログラムソースの、<abc #x>のヘッドとパターンマッチしています。 #xは、Undef3と表され、7とマッチングして、#x(Undef3)は、7に設定されます。

(3)では、次に、プログラムソースの、<abc #x>のボディであるsysモジュールの組み込み述語である::sys <writenl #x>が実行されます。 #xには、(2)で7が設定されているので、7が出力されます。

(4)では、同様に組み込み述語である<print #x>が実行されます。

(5)では、<def <let _ = #x+1>>が次項され、#x+1は7+1で8になるので、<def 8>が呼び出されます。

(6)では、syntax述語の中の<ghi>が呼び出されています。

(7)では、トークンabcの読み込みに成功しました。

(8)では、トークンdefghiの読み込みに成功しています。

(9)では、(6)から処理してきたsyntax述語の実行全体が成功しています。

(10)で、すべての述語の実行が成功したことを表しています。

このように、tron述語を使うことにより、述語の呼び出し関係のトレース情報をロギングすることができるのです。


次の例では、未定義述語の実行を示します。(注:未定義述語のログ表示は、次期リリース0.14.0からの新機能です。)


<aabc 1>;

?<tron>;
?<123><abc><def>;
?<aabc>;
?<aabc 2>;

このプログラムを実行すると次のようにログが表示されます。


builtin: <tron>...success
result --
        <tron>
-- true
? (<123> <abc> <def>)
Undeclared predicate : <123>     (1)
result --
        <123>
        <abc>
        <def>
-- unknown
? (<aabc>)                       (2)
Unification: <aabc> 
           : <aabc 1>
result --
        <aabc>
-- unknown
? (<aabc 2>)                     (3)
Unification: <aabc 2>
           : <aabc 1>
result --
        <aabc 2>
-- unknown

(1)では、<123>述語は定義されていないので、「Undeclared predicate : <123> 」と表示されます。

(2), (3)では、aabc述語は定義されているので、ユニフィケーション(単一化)には失敗しても、ログにUndeclared ~ とは、表示されません。

未定義述語は、述語名のうち間違えや、ライブラリの指定ミスで、よく発生します。そのような場合のデバッグにこの機能はとても有効です。