詳細:パーサコンテキスト

パーサのコンテキストは別のもう一つの概念である。 context クラスのインスタンス(オブジェクト)は非終端記号が構文解析を開始する前に作成され、 構文解析が終了した直後に破壊される。 非終端記号は rulesubrule 、または grammar である。 非終端記号はテンプレートパラメータ ContextT を持つ。 次の擬似コードは非終端記号が呼び出された時に何が起こるのかを示したものである:

    return_type
    a_non_terminal::parse(ScannerT const& scan)
    {
        context_t ctx(/**/);
        ctx.pre_parse(/**/);

        //  非終端記号の構文解析コードの本体はここに…

        return ctx.post_parse(/**/);
    }

コンテキストは拡張性のために提供される。 その主な目的は、非終端記号の parse メンバ関数の開始と終了を外部からフックできるように 公開することである。 非終端記号を拡張することが出来る、多くの方法で、特殊化されたコンテキストクラスを書くことで、 クラスそのものに手を加えることなく。 例えば、 非終端記号が呼び出された構文解析走査の中の各々のポイントで、スキャナの現在の状態を出力するようなコンテキストクラスを書くことで、 その非終端記号がデバッグ用診断情報を発するようにできる。

デバッグ情報を出力するパーサコンテキストの例:

    pre_parse      非終端記号 XXX に入りました。現在の入力の状態は
                    "hello world, this is a test" です。

    post_parse     非終端記号 XXX は終了し、 "hello world" に一致しました。
                    現在の入力の状態は ", this is a test"です。

ほとんどの場合、このコンテキストはユーザの視界からは見えないだろう。 一般に、フレームワークの利用者はコンテキストを扱う必要がないばかりか、知る必要すらない。 パワーユーザはコンテキストの使い道を見つけるだろうから、そんなわけで、これは公開APIの一部となっている。 コアより上の別レイヤに属すフレームワークの他の部分は非終端記号を拡張するというコンテキストの利点を享受している。

parser_context クラスは非終端記号が用いるデフォルトのコンテキストクラスである。

    struct parser_context
    {
        typedef implementation_defined attr_t;
        typedef implementation_defined base_t;
        typedef parser_context_linker<parser_context> context_linker_t;

        template <typename ParserT>
        parser_context(ParserT const& p) {}

        template <typename ParserT, typename ScannerT>
        void
        pre_parse(ParserT const& p, ScannerT const& scan) {}

        template <typename ResultT, typename ParserT, typename ScannerT>
        ResultT&
        post_parse(ResultT& hit, ParserT const& p, ScannerT const& scan)
        { return hit; }
    };

非終端記号の ContextT テンプレートパラメータはコンセプトの一種である。 上記の parser_context クラスはこのコンセプトのもっとも簡単なモデルである。 デフォルトの parser_contextpre_parsepost_parse メンバ関数は単になにもしない。 非終端記号の ContextT テンプレートパラメータのことを 非終端記号が構文解析の前後にどのように振る舞うかを司るポリシーだと考えてよい。 利用者は、ユーザ定義のコンテキストパラメータを望みの非終端記号に渡すことで、独自のコンテキストポリシーを供給できる。

パーサコンテキストポリシー
attr_t typedef:非終端記号の属性の型。一致判定を参照。
base_t typedef:非終端記号の基底クラス。非終端記号はこのクラスから派生する。
context_linker_t typedef: このクラス型は可能性を開く(open up)、Spiritにさらなる機能性を加えるという、 非終端記号の parse 関数へ、あるいは与えられたコンテキストをバイパスすることで、 (this class type opens up the possibility for Spirit to plug in additional functionality into the non-terminal parse function or even bypass the given context) これは単純にparser_context_linker<T>にtypedefされる。ここで T はユーザ定義のコンテキストクラスの型である。
constructor コンテキストを構築する。非終端記号はそのコンストラクタへの引数として渡される。
pre_parse 構文解析に先立って何らかの処理を行う。 引数として非終端記号と現在のスキャナが渡される。
post_parse 構文解析の後に何らかの処理を行う。 これは構文解析の結果に寄らず呼び出される。 パーサの結果への参照が渡される。 コンテキストはこれを修正する能力がある。 非終端記号および現在のスキャナも引数として渡される。

base_tはさらに説明するだけの価値がある。 早速始めよう…。 コンテキストは、厳密にはスタックを基本としたクラスである。 それは構文解析の前に作成され、非終端記号の parse メンバ関数が終了した後に破壊される。 時折、非終端記号ホストの生存期間を通して存在するような補助データが必要になる。 非終端記号はコンテキストのbase_tから派生しているので、 コンテキストそれ自身は、作成された際に、この上位の構築作業へのアクセスを得る、 非終端記号がそのコンストラクタへの引数として渡された時に。 pre_parsepost_parseも同様。

コンテキストは base_t typedefを継承する。 ただ一つの必須事項は、デフォルトコンストラクタが用意されているクラスであることである。 コピーコンストラクタと代入の要求はホストに依存する。 もしホストがそれを必要とするなら、コンテキストの base_t はそのようにする。 一般に、これらの基本的な要求に応えても問題になることはないだろう。



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