2012年4月28日土曜日

boost::spirit::qi ドキュメント探訪

boost::spirit は、構文解析を行うためのテンプレート・プログラミングです。一見、難しそうに見えますが、ドキュメントの歩き方を知っていれば、そんなに難しくありません。 boost 1_49_0 時点では、ドキュメントは、以下になります。 http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/

Quick Reference - Qi Parsers

まずは、Quick Reference の Qi Parsers を見ましょう。 http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers.html

Character Parsers

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/char.html 文字パーサでは、どの文字コードが、どんな表現に該当するか?が記述されています。 表のうちExpression が、プログラムコード中で書く表現です。ここに alnum と書いてあれば、namespace が boost::spirit::qi なので
  boost::spirit::qi::alnum
という表現をコード中に書く事になります。Expression 中の Ch とは、文字列で、
  boost::spirit::qi::lit("command")
というように文字列リテラルを指定します。Ch 等の説明は  Quick Reference の Common Notation に解説されています。  http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/common_notation.html 表のうちAttribute は属性で 、Unused は「マッチしても値として取り出す事はしませんよ」という意味で、Ch は「マッチした文字をそのまま値として採用しますよ」という意味になります。 表の Description は、説明です。 参考までに、任意回数のマッチを表す * を利用すると
  *boost::spirit::qi::digit
は、138793285 などの連続した一連の数字にマッチし、マッチした文字列を抽出できます。

Numeric Parsers

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/numeric.html 数値パーサでは、std::atoi std::atof といったような数値の文字列を解釈して数値に変換するための表現が記述されています。 Expression がコードに書く部分で、Attribute は変換される型になります。
  boost::spirit::qi::long_
とすると、12345 という表現にマッチした場合は、long 型に変換されます。

String Parsers

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/string.html 少し、Character Parser と被ります。ここでの注目は、symbols でしょう。 symbols は、テンプレートになっており、任意の文字列を任意の型のある値へと変換するパーサのクラスを作成する事ができます。 たいていは、wchar_t ではなく char 型を構文解析にかけるので、symbols の最初に指定する型は char 型です。論理値 bool 型に変換したい場合は、以下のように書きます。
  boost::spirit::qi::symbols<char,bool>  bool_symbol;
とします。ただ、これではパースすべき文字列がひっかからないので add 関数で、以下のようにマッチすべき文字列と値の組み合わせを、事前に追加しておきます。
  bool_symbol.add("true",true)("false",false);
変な構文に見えますが、operator() ( const char*, bool ) を使ったトリックで構成されていたように思います(未確認なんで嘘かもしれません)。

Auxiliary Parsers

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/auxiliary.html ここは、若干高度で説明も難しいです。Description を見てお茶を濁しておきましょうwww eol は改行なんで、わかると思いますが、パーサでスペースは対象外にするとか、skipするパターンの指定の仕方によっては、改行もスキップされるので、使い所が無いかもしれません。 eps だけ、ちょっと解説を・・・。
  boost::spirit::qi::int_ >> boost::spirit::qi::eps >> boost::spirit::qi::lit(",")
こうした場合に、123435という数値パターンにマッチした場合、空気のように eps は無条件にマッチします。実は、パーサ要素の後ろに [] をつけると、[]の中にアクション関数を設置すれば、[]の中のアクションをマッチ後に実行するという動作を記述できます。こうする事によって、地雷(踏んだら爆発する)を設置する事ができます。 特定の文字(例えば"hello")にマッチしたかどうかを調べて、何事も無かったかのように振る舞う事もできます。
  boost::spirit::qi::eps("hello") >> boost::spirit::qi::lit("hello")
上記の例では、epsで "hello" にマッチしなかった場合は次に通しませんが、"hello"にマッチした場合は、eps に入る前の状態に巻き戻して、次のパーサへ引き継ぎを行います。まるで忍者の偵察部隊のように何事も無かったかのように次の状態をアクション無し副作用無しで調査してくれるので、先読み条件分岐として利用する事ができます。
2013/2/16:訂正 旧spritのeps_pと異なり、現在は 式のみ受け付けるようです。従って、この構文はコンパイルを通りません(残念)。通過後に構文違反になったらエラーを確定させたい場合には、>> 演算子の代わりに > 演算子を利用します。先読みは、通常の構文解析 >> を利用して | 接続させてください。

Binary Parsers

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/binary.html Numeric Parsers と似てるので飛ばします。

Auto Parser

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/auto.html 何かにマッチする・・・便利すぎて効能をちょっと思いつきません

Parser Directives

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/directive.html lexeme[] の[]中でのパースはスキップする文字列を無効にします。no_case[]の[]中でパースは大文字小文字の区別をしないようにします。raw[]の[]中をひとつの塊として見なします。repeat[]の[]中のパターンを指定回繰り返します。サンプルもあるので研究してみてください。

Parser Operators

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/operator.html 何回マッチするか? - + *  
Aというパターンの次にはBというパターンにマッチします >>
AというパターンかBというパターンにマッチします |
といったパーサに対する関係演算子について書かれています。

Parser Semantic Actions

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/action.html パーサを()で括って塊にし、 [] をつける事で、[]中にアクションを指定できます。アクションは、関数だったり、phoenix という奇天烈な template だったりします。

Quick Reference - Phoenix

http://www.boost.org/doc/libs/1_49_0/libs/spirit/doc/html/spirit/qi/quick_reference/phoenix.html …すみません、嘘をついてました。魔術でした。ごめんなさい…。

0 件のコメント: