リストパーサ

リストパーサは特殊な定義済みパーサ生成子オブジェクトである list_p によって生成される。 このオブジェクトは次のようなタイプのリスト構造を認識するパーサを生成する。

    item >> *(delimiter >> item) >> !end

ここで item は式、 delimiter は区切り子(delimiter)、そして end は省略可能な閉じる式である。 一見して明らかなように、 list_p によって生成されたパーサは空のリストを認識できない。 すなわち、パーサがマッチ成功を返すためには、入力ストリーム中に少なくとも一つの項目を見つけなければならない。 もし空のリストにもマッチさせたい場合は operator! を用いて list_p を省略可能にできる。 このユーティリティパーサがいかに便利であるかを示すため、カンマで区切られた C/C++ 文字列を構文解析する例を挙げる。これは以下のように容易に構成できる:

    rule<> list_of_c_strings_rule
        =   list_p(confix_p('\"', *c_escape_char_p, '\"'), ',')
        ;

confix_p および c_escape_char_p パーサジェネレータについては ここここ で述べている。

list_p パーサジェネレータオブジェクトは次の異なるタイプのリストパーサを生成するのに利用できる:

リストパーサ
list_p

list_pは特殊な項目の書式化なしにカンマ区切りリストを構文解析する。 すなわち、二つのカンマの間のあらゆるものが item にマッチ、リストトークンの終端 end にはマッチしない。

list_p(delimiter)

指定された delimiter で区切られたリストを認識するリストパーサを生成する。 それらの間にあるあらゆるものを item として返し、リストトークンの終端 end にはマッチしない。

list_p(item, delimiter)

指定された delimiter で区切られたリストを認識しするリストパーサを生成する。 与えられた item パーサに基づいて項目をマッチし、リストトークンの終端 end にはマッチしない。

list_p(item, delimiter, end)

指定された delimiter で区切られたリストを認識しするリストパーサを生成する。 与えられた item パーサに基づいて項目をマッチし、 さらに省略可能な end 式を認識する。

list_p への全てのパラメータは、単一の文字、文字列を用いることが出来る。もしより複雑な構文解析ロジックが必要ならば任意のパーサを用いることも出来る。これらは全て構文解析の成功に必要な対応するパーサ型に自動的に変換される。

item パラメータが action_parser_category 型(セマンティックアクションが接続されたパーサ)であれば、特別な処理を施さなければならない。 もしユーザが次のようなコードを書いたとする:

    list_p(item[func], delim)

ここで item はリストシーケンスのある一つの項目にマッチするパーサであり、 また func はある一つの項目にマッチした後に呼ばれるファンクタである。 もし特に何もしないのであれば、結果のコードはこのシーケンスを次のように構文解析する:

    (item[func] - delim) >> *(delim >> (item[func] - delim))

多くの場合起こることはユーザが期待していることではない (もしこれ期待していることなら、 list_p ジェネレータ関数の一つである direct() を利用してほしい。 これは item パーサのリファクタリングを禁止する)。 リストパーサを期待通りに振る舞わせるには次のようにする:

    (item - delim)[func] >> *(delim >> (item - delim)[func])

item パーサに接続されたオブジェクト(actor)は、結果のリストパーサが ’正しく動作する’ ように (item - delim) パーサの構築に際して再接続されなければならい。 このリファクタリングはリファクタリングパーサの助けによって為される。 もし item パーサが例えば次のような unary_parser_category 型のパーサであれば、さらに特殊な処置を施す必要がある:

    list_p(*anychar_p, ',')

何のリファクタリングも施さなければ、その結果は

        (*anychar_p - ch_p(','))
    >> *( ch_p(',') >> (*anychar_p - ch_p(',')) )

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

       *(anychar_p - ch_p(','))
    >> *( ch_p(',') >> *(anychar_p - ch_p(',')) )

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

item パーサが想定される二つの問題の組み合わせである(すなわち、 item パーサが一引数のパーサであり、かつアクションが接続されている)場合も同様に扱われ:

    list_p((*anychar_p)[func], ',')

期待されたとおりに構文解析される:

        (*(anychar_p - ch_p(',')))[func]
    >> *( ch_p(',') >> (*(anychar_p - ch_p(',')))[func] )

必要なリファクタリングはリファクタリングパーサの助けを受けて実装されている。

リストパーサのリファクタリングのまとめ
記述したコード: リファクタリングされたコード:
list_p(item, delimiter) (item - delimiter)
>> *(
delimiter >> (item - delimiter))
list_p(item[func], delimiter) (item - delimiter)[func]
>> *(
delimiter >> (item - delimiter)[func])
list_p(*item, delimiter) *(item - delimiter)
>> *(
delimiter >> *(item - delimiter))
list_p((*item)[func], delimiter) (*(item - delimiter))[func]
>> *(
delimiter >> (*(item - delimiter))[func])



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