Boost.Spirit.Qi qi::eps

qi::epsは、ゼロ幅にマッチするパーサーです。


たとえば、以下のようにパーサー式の間にepsを単に挟んだ場合には、epsは常にマッチし、結果を取得することもないので、とくに影響がありません。

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix.hpp>
#include <boost/range/algorithm/for_each.hpp>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

template <class Rule, class Result>
bool parse(const std::string& input, const Rule& r, Result& result)
{
    std::string::const_iterator it = input.begin();
    return qi::phrase_parse(it, input.end(), r, qi::space, result);
}

int main()
{
    const std::string input = "1 2 3 4 5";
    std::vector<int> result;

    int last_value = 0;
    if (!parse(input, *(qi::eps >> qi::int_[phx::ref(last_value) = qi::_1]), result)) {
        std::cout << "parse error" << std::endl;
        return 1;
    }

    boost::for_each(result, [](int x) { std::cout << x << std::endl; });
}
1
2
3
4
5

それと、qi::epsは述語を引数にとることもできるので、セマンティックアクションなどで変動した状態によってマッチさせないために使用することができます。

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <iostream>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix.hpp>
#include <boost/range/algorithm/for_each.hpp>

namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

template <class Rule, class Result>
bool parse(const std::string& input, const Rule& r, Result& result)
{
    std::string::const_iterator it = input.begin();
    return qi::phrase_parse(it, input.end(), r, qi::space, result);
}

int main()
{
    const std::string input = "1 2 3 4 5";
    std::vector<int> result;

    int last_value = 0;
    if (!parse(input, *(qi::eps(phx::ref(last_value) < 4) >> // 5はマッチさせない
                        qi::int_[phx::ref(last_value) = qi::_1]), result)) {
        std::cout << "parse error" << std::endl;
        return 1;
    }

    boost::for_each(result, [](int x) { std::cout << x << std::endl; });
}
1
2
3
4

参照:
Epsilon Parser (eps) - Boost.Spirit.Qi