読者です 読者をやめる 読者になる 読者になる

Boost.Spirit.Qi utree使い始め

C++

Boost 1.47.0からBoost.Spiritに、構文木を扱うためのutreeクラスが入りました。
調べながら使ってみたらこんな感じでした。

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <boost/foreach.hpp>

namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
typedef std::string::const_iterator Iterator;

int main()
{
    const std::string input = "1,Akira,26";

    spirit::utree ut;

    qi::rule<Iterator, spirit::utree()> r =
        qi::int_ >> ',' >> qi::as_string[*(qi::char_ - ',')] >> ',' >> qi::int_;

    Iterator it = input.begin();
    if (!qi::parse(it, input.end(), r, ut)) {
        std::cout << "parse error" << std::endl;
        return 1;
    }

    BOOST_FOREACH (const spirit::utree& data, ut) {
        switch (data.which()) {
            case spirit::utree_type::int_type:
                std::cout << data.get<int>() << std::endl;
                break;

            case spirit::utree_type::string_type: {
                const spirit::utf8_string_range_type r = data.get<spirit::utf8_string_range_type>();
                const std::string s(r.begin(), r.end());
                std::cout << s << std::endl;
                break;
            }

            default:
                std::cout << "default" << std::endl;
                assert(false);
        }
    }
}
1
Akira
26

utreeはイテレータインタフェースを持っているので、BOOST_FOREACHなどで走査することができます。
utreeに入ったデータはType Erasureによって型情報が消されているので、適切な型に変換して取り出す必要があります。


文字列はboost::spirit::utf8_string_range_typeになるらしいです。
std::stringには直接取り出せないので注意。
それと、as_stringしないと文字ごとにutreeになるので注意。


ちなみに、utreeは入出力ストリームの演算子を持ってるのでそのまま出力できます。

#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_utree.hpp>
#include <boost/foreach.hpp>

namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
typedef std::string::const_iterator Iterator;

int main()
{
    const std::string input = "1,Akira,26";

    spirit::utree ut;

    qi::rule<Iterator, spirit::utree()> r =
        qi::int_ >> ',' >> qi::as_string[*(qi::char_ - ',')] >> ',' >> qi::int_;

    Iterator it = input.begin();
    if (!qi::parse(it, input.end(), r, ut)) {
        std::cout << "parse error" << std::endl;
        return 1;
    }

    BOOST_FOREACH (const spirit::utree& data, ut) {
        std::cout << "|" << data << "|" << std::endl;
    }
}
|1 |
|"Akira" |
|26 |

なぜかダブルクォーテーションと後ろにスペースが付く。