コンフィクスパーサ

コンフィクスパーサ

コンフィクスパーサは三つの独立した要素からなる(おそらくネストした)シーケンスを認識する。(recognize a sequence out of three elements):、式、および。 このユーティリティパーサはある構造を構文解析するのに用いられるだろう、 ここでは恐らく(possibly)式に含まれ、 シーケンス全体は最初のサブシーケンスにマッチする部分を見た後でのみマッチする。 単純な例はネストした PASCAL のコメントである:

    { これは { ネストした } PASCAL のコメントである }

これは次のルール定義によって構文解析されることができる:

    rule<> pascal_comment_rule
        =   confix_nest_p('{', *anychar_p, '}')
        ;

もしネストしないコンフィクスパーサが必要ならば、 confix_pパーサジェネレータが使われるだろう、 必要なコンフィクスパーサを生成するために。 もし式部分が有効なコンフィクスシーケンスを含んでいる (コンフィクスシーケンスがネストを許す)なら、 confix_nest_p パーサジェネレータテンプレートはそのパーサの生成に用いられる。 confix_pconfix_nes_pへの三つのパラメータは単一の文字(上述)、文字列あるいは、 より複雑な構文解析ロジックが必要であれば、任意のパーサになりうる。これらのいずれも自動的に成功する構文解析に必要とされる対応するパーサ型へと変換される。

生成されたパーサは以下のルールと等価である:

    open >> (expr - close) >> close

もし expr パーサが action_parser_category 型パーサ(セマンティックアクションが接続されたパーサ)であれば、 特別なことをしなければならない。 これが起こると、もしユーザが何か次のように書くと:

    confix_p(open, expr[func], close)

ここで expr はパーサである、コンフィクスシーケンスの expr にマッチするパーサ、 そして funcexpr にマッチした後で呼び出されることになるファンクタである。 もし何もしなければ、その結果のコードは次のようなシーケンスを構文解析する:

    open >> (expr[func] - close) >> close

これは多くの場合、ユーザが期待するものではない(もしこれ期待するものであれば、 パーサのリファクタリングを禁止する confix_p または confix_nest_p ジェネレータ関数 direct() を使うこと)。 コンフィクスパーサが期待するように振る舞うようにするには:

    open >> (expr - close)[func] >> close

exprパーサに接続された actor は (expr - close) パーサ構築に再接続される。 これによって結果のコンフィクスパーサは '正しいことをする' 。 このリファクタリングはリファクタリングパーサの助けを受けて行われる。 もし expr パーサが次のような unary_parser_category 型パーサの場合であれば、

    confix_p(open, *anychar_p, close)

さらに特別な配慮が必要である。もし何のリファクタリングも施さなければ、その結果は

    open >> (*anychar_p - close) >> close

となって、期待した結果は得られない( *anychar_p は入力ストリームの終端に至るまですべての入力を食い尽くしてしまうだろう)。 そこでこれを次のようにリファクタリングする:

    open >> *(anychar_p - close) >> close

得られるのは正しい結果である。

expr パーサが二つの注意すべき(mentioned)問題の組み合わせである場合 (則ち、 expr パーサがアクションの接続された引数一つのパーサである)も同様に処理され、その為:

    confix_p(start, (*anychar_p)[func], close)

は期待されるように構文解析される:

    open >> (*(anychar_p - end))[func] >> close

必要とされるリファクタリングはここでもリファクタリングパーサの助けで実装されている。

コンフィクスパーサのリファクタリングのまとめ
記述したコード: リファクタリングされたコード:
confix_p(open, expr, close)

start >> (expr - close) >> close

confix_p(open, expr[func], close)

start >> (expr - close)[func] >> close

confix_p(open, *expr, close)

start >> *(expr - close) >> close

confix_p(open, (*expr)[func], close)

start >> (*(expr - close))[func] >> close

コメントパーサ

コメントパーサジェネレータテンプレート comment_pcomment_nest_p は、 任意の引数から コメントを構文解析できる 正しいコンフィクスパーサを生成するためのヘルパーである。 コメントは次の構造に従う:

    コメント開始トークン >> コメント本文 >> コメント終了トークン

パラメータとして以下の型がサポートされている: パーサ、単独の文字および文字列( as_parser を参照)。 二つの異なる定義済みコメントパーサジェネレータがある: comment_pcomment_nest_p 、 これらは特殊なコメントパーサを二つの異なる方法で作成するために使われる。 これらが一つのパラメータで用いられると、与えられた最初のパーサパラメータで始まるコメントは その行の終端までがマッチする。 その為、例えば以下のパーサは C++ 形式のコメントにマッチする:

    comment_p("//")

もし二つのパラメータで用いられた場合、最初のパーサパラメータで始まり二つ目のパーサパラメータまでのコメントがマッチする。例えば C 形式のコメントパーサは以下のように構築される:

    comment_p("/*", "*/")

comment_p パーサジェネレータは ネストしないコメント( C / C++ コメントのような)にマッチするパーサを生成することを許す。 時として、例えば Pascal のようにネストしたコメントを構文解析する必要があることがある。 そのようなネストしたコメントは comment_nest_p ジェネレータテンプレートファンクタによって生成されたパーサを通じて構文解析することが出来る。 次の例は、二つの異なる(ネストできる) Pascal のコメント形式を構文解析するために用いられるパーサを示している:

    rule<> pascal_comment
        =   comment_nest_p("(*", "*)")
        |   comment_nest_p('{', '}')
        ;

注意して欲しいことは、 コメントは暗黙のうちに、 あたかもcomment_p(...)ステートメント全体が lexeme_d[]ディレクティブの中に埋め込まれているかのように 構文解析される、ということである。 すなわち、 もし構文解析プロセス全体に対してスキップパーサを定義していたとしても、 コメントの構文解析の間、トークンのスキップは起こらない。



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