デバッグ

Spirit のトップダウンという性質は、生成されたパーサが 使用する C++ コンパイラに同梱されている標準的なデバッガを用いて 容易に micro- debug できるようにする。 再帰降下によって、 構文解析走査(parse traversal)は C++ の関数呼び出し機構を通じてハードウェアスタックを利用する。 テーブルをデバッグし難くするものや、構文解析の論理フローを分かりにくくする状態機械などはない。 デバッガで見られるスタックフローは階層的な文法構造に忠実に従う。

どの生成規則も構文解析走査を開始できるため、 一つか少しのルールに焦点を合わせてバグを特定することはずっと容易である。 相対的に複雑な構文解析タスクに対しては、 頑健な C++ プログラムを書くのと同じように、 モジュール単位を基本に反復的に文法を開発するのが賢明である。 各モジュールは完全な文法の小さなサブセットである。 この方法で、最上位のモジュールに辿り着くまで個別のモジュールを少しずつ耐久テストできる。 例えばスクリプト言語を開発する場合、まず式から始めてステートメントに移り、それから関数へ…と、完全な文法を得るまで上へ向かっていくことができる。

文法が非常に複雑になった時点で、構文解析走査を視覚化して、何が起こっているのか見てみるのが望ましい。 このフレームワークにはデバッグの目的で構文解析走査の視覚化を助ける機能がいくつか用意されている。次のマクロはそれらの機能を有効にする。

デバッグマクロ

BOOST_SPIRIT_ASSERT_EXCEPTION

Spirit は不正に使われた場合に作動するアサーションを持っている。 デフォルトではこれらのアサーションは標準ライブラリの assert マクロを使用する。 代わりに例外を投げて欲しいのであれば、 BOOST_SPIRIT_ASSERT_EXCEPTION を投げて欲しいクラスの名前に定義する。 このクラスのコンストラクタは、投げられる際に、ファイルのバージョン、行、アサーション条件を文字列にした const char* を渡される。 アサーションを全面的に向こうにしたいのであれば、 #define NDEBUG すること。

BOOST_SPIRIT_DEBUG

デバッグを有効にするにはこれを定義する。

デフォルトでは、 BOOST_SPIRIT_DEBUG マクロが定義されると、全ての可能なデバッグ出力が生成される。 生成されるテキストの量を微調整するために、 BOOST_SPIRIT_DEBUG_FLAGS 定数を以下のフラグの組み合わせに等しくなるように定義することができる:

デバッグ出力の微調整に利用可能なフラグ
BOOST_SPIRIT_DEBUG_FLAGS_NODES

ノードに関する情報を出力する(パーサ汎用)

BOOST_SPIRIT_DEBUG_FLAGS_TREES

構文解析木と AST に関する情報を出力する(ツリーパーサ汎用)

BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES クロージャに関する情報を出力する(クロージャを持ったパーサ汎用)
BOOST_SPIRIT_DEBUG_FLAGS_ESCAPE_CHAR

esc_char_parserからの情報を出力する

BOOST_SPIRIT_DEBUG_FLAGS_SLEX SLEX パーサからの情報を出力する

BOOST_SPIRIT_DEBUG_OUT

デバッグ診断出力をどこか別のところ(例.ファイルやストリーム)にリダイレクトするには、これを定義する。デフォルトは std::cout である。

BOOST_SPIRIT_DEBUG_TOKEN_PRINTER

BOOST_SPIRIT_DEBUG_TOKEN_PRINTER マクロはストリームに文字を出力する方法を再定義できるようにする。

BOOST_SPIRIT_DEBUG_OUT の型が StreamT であれば、 文字型は CharT であり BOOST_SPIRIT_DEBUG_TOKEN_PRINTERfoo と定義される。これは以下の使い方と互換性がなければならない:

    foo(StreamT, CharT)

デフォルトの出力子(printer)を定義するには operator<<(StreamT, CharT) が要求される。 さらに、もし CharT が通常の文字型(charwchar_t または int)に変換可能であるなら、それは制御文字の出力を良きに計らってくれる(例えば、 '\n' を受け取った場合、改行の代わりに実際には \n の二文字を出力する)。

BOOST_SPIRIT_DEBUG_PRINT_SOME

BOOST_SPIRIT_DEBUG_PRINT_SOME 定数は診断のためにストリームから出力される文字数を定義する。このデフォルトは最初の20文字である。

BOOST_SPIRIT_DEBUG_TRACENODE

デフォルトではすべてのパーサノードがトレースされる。 この定数はこのデフォルトを再定義するために用いられる。 もしこれが 1true)ならばトレースはデフォルトで有効になる。 もしこの定数が 0false) ならば、トレースはデフォルトで無効になる。このプリプロセッサ定数はデフォルトでは 1 true)である。

以下の BOOST_SPIRIT_DEBUG_...() マクロは関数スコープでのみ利用できる点に注意して欲しい。

BOOST_SPIRIT_DEBUG_NODE(p)

パーサ p のデバッグ診断を出力するにはこれを定義する。 このマクロは

構文解析前:ルールに入る前に、現在のイテレータポジションのデータを伴ってそのルール名が出力される。

構文解析後:ルールを構文解析した後で、現在のイテレータポジションのデータを伴ってそのルール名が出力される。 ここで、ルール名の前の '/' は成功したマッチを示し、 '#' は成功しなかったマッチを示す。

以下は BOOST_SPIRIT_DEBUG_NODE の別名である

  1. BOOST_SPIRIT_DEBUG_RULE
  2. BOOST_SPIRIT_DEBUG_GRAMMAR

BOOST_SPIRIT_DEBUG_TRACE_NODE(p, flag)

BOOST_SPIRIT_DEBUG_NODE と同様である。 さらに、選択的デバッグを可能にする。 これは厳選したノードの集合をデバッグしたいような状況で有用である。

以下は BOOST_SPIRIT_DEBUG_TRACE_NODE の別名である

  1. BOOST_SPIRIT_DEBUG_TRACE_RULE
  2. BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR

BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME(p, name, flag)

BOOST_SPIRIT_DEBUG_NODE と同様である。 さらに、選択的デバッグを可能とし、デバッグ出力の間に用いられる名前を指定することができる。 これは厳選したノードの集合をデバッグしたいような状況で有用である。 name は状況に応じて再定義することができ、パーサのパラメータはデバッグするパーサの名前を反映しないようになる。

以下は BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME の別名である

  1. BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME
  2. BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME

以下はデバッグ機能を有効にした電卓である:

    #define BOOST_SPIRIT_DEBUG  ///$$$ 他のどれよりも先にこれを定義すること $$$///
    #include "boost/spirit.hpp"

    /***/

    /*** 電卓の文法定義はここ ***/

    BOOST_SPIRIT_DEBUG_RULE(integer);
    BOOST_SPIRIT_DEBUG_RULE(group);
    BOOST_SPIRIT_DEBUG_RULE(factor);
    BOOST_SPIRIT_DEBUG_RULE(term);
    BOOST_SPIRIT_DEBUG_RULE(expr);

さて、以下がその電卓の使用例である。


    Type an expression...or [q or Q] to quit

    1 + 2
    expr:   "1 + 2 "
        term:   "1 + 2 "
            factor: "1 + 2 "
                integer: "1 + 2 "
    push    1
                /integer:   "+ 2 "
            /factor:    "+ 2 "
        /term:  "+ 2 "
        term:   "2 "
            factor: "2 "
                integer:    "2 "
    push    2
                /integer:   " "
            /factor:   " "
        /term:  " "
    popped 1 and 2 from the stack. pushing 3 onto the stack.
    /expr:  " "
    parsing succeeded
    result = 3

"1 + 2" と入力した。最上位のルール expr からは二つの成功した分岐がある点に注目して欲しい。 赤いテキストはパーサのセマンティックアクションによって生成されたもので、それ以外はルールのデバッグ診断によって生成されたものである。 一つ目の integer ルールが "1" を取り、一つ目の term ルールが "+" を取り、そして最後に二つ目の integer ルールが "2" を取っていることに注目して欲しい。



このドキュメントの対象: Boost Version 1.30.0
最新版ドキュメント(英語)