View on GitHub

boost_spirit_guide

パーサ・オペレータ

ルールを記述する上で一番重要なのがオペレータです。(namespace qi = boost::spirit::qi)
重要だと思う順に並べました。表中の A , B はパーサを示します。

オペレータ モデル 説明
*A UnaryParser 0回以上 A にマッチする
+A UnaryParser 1回以上 A にマッチする
A | B NaryParser A または B にマッチする
A » B NaryParser A にマッチした次に B にマッチする。B にマッチしなかった場合 A まで巻き戻る事ができる
A > B NaryParser A にマッチした次に B にマッチする。B にマッチしなかった場合、A には戻れない
A - B NaryParser A にマッチする中から B にマッチするケースを取り除く
A % B BinaryParser *(A % B) といった使い方をし、B は区切り記号のパーサである。配列要素 1,2,…,n を表現するためのパーサ
-A UnaryParser 0回または1回 A にマッチする
!A UnaryParser A にマッチしないパーサ。値は取り出せない
&A UnaryParser A にマッチするパーサ。値は取り出せない
A || B NaryParser A に0回または1回マッチし、B に0回または1回マッチする。ただし AB 共にマッチしない場合を除く
A ^ B NaryParser AB は、それぞれ0回または1回マッチし、かつ、AB のマッチする順序は問わない

ブランク(スペース・タブ)で区切られた数値を取り出す例

C++: *( A % B )
#include <boost/spirit/include/qi.hpp>
#include <vector>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::string input = "12345 223  54321";
  std::vector<int> v;
  qi::parse( input.begin(), input.end(), *( qi::int_ % +qi::standard::blank), v ); 
  for(int n: v) { std::cout << n << std::endl; }
  return 0;
}

ルールをつなげる

C++: A >> B
#include <boost/spirit/include/qi.hpp>
#include <vector>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::string input = "12345,abcd,54321";
  int n, m;
  std::string s;
  qi::parse( input.begin(), input.end(), 
    qi::int_ >> ',' >> +(qi::standard::char_ - ',') >> ',' >> qi::int_,
    n, s, m ); 
  std::cout << n << "," << s << "," << m << std::endl;
  return 0;
}

qi::lit(‘,’) は implicit conversion(暗黙の型変換)により ‘,’ と省略して記述する事ができます。
ただし、後述するセマンティック・アクションを適応する場合は、’A’[action] と省略形で記述するとコンパイルエラーになるので気をつけましょう。
+(qi::standard::char_ - ‘,’) は、’,’以外の文字から構成される文字列にマッチします。

ルールをつなげる(解析エラーをコントロールする)

C++: A > B
#include <boost/spirit/include/qi.hpp>
#include <vector>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::string input = "dog(2pochi),cat(tama)";
  std::vector<std::string> v;
  qi::parse( input.begin(), input.end(), 
    *( 
      (
       //("dog(" >> +qi::standard::char_("a-z")  >> ')')
       ("dog(" > +qi::standard::char_("a-z")  > ')')
       | (+qi::omit[qi::standard::alpha] > '(' > +qi::standard::alnum > ')')
      ) % ','
    )
    , v ); 
  for(std::string n: v) { std::cout << n << std::endl; }
  return 0;
}

ルール中に出てくる qi::omit は、後述するパーサ・ディレクティブで説明します。
cat を v へ入れたくないので qi::omit で指定しています。
dog( まで解析し、2pochi はアルファベットa-zの範囲外なのでマッチしません。
コメントアウトされている箇所のようにオペレータ » であれば巻き戻って、| 以降の次のルールで解析する事ができますが、
オペレータ > を使用しているため 2pochi に遭遇した段階で解析を終了します。
> の記述を » の記述にして実行すると、巻き戻る事ができ、
(+qi::omit[qi::standard::alpha] > ‘(‘ > +qi::standard::alnum > ‘)’) のルールで処理されるようになります。
構文解析において、if 文など出現すると後続する語句が決定される箇所に対しては > オペレータを使用します。