Search code examples
boostboost-spiritboost-spirit-x3

How do you implement a custom parser object with boost spirit x3 such that it plays nice with a skipper?


I know I can implement a custom parser by making an object with the appropriate "parse" member function template, but I don't know what I need to do to make it use the skipper in the Context, which it seems to need to do. That is, below I expected both cases to succeed but the second fails:

namespace x3 = boost::spirit::x3;

namespace parser {

    struct foobar : x3::parser<foobar> {

        using attribute_type = std::string;

        template<typename Iterator, typename Context, typename RContext, typename Attribute>
        bool parse(Iterator& first, Iterator const& last, Context const& context,
            RContext const& rcontext, Attribute& attr) const
        {
            static const std::string foobar_str = "foobar";
            auto i = first;
            auto j = foobar_str.begin();
            while (i != last && j != foobar_str.end()) {
                if (*i++ != *j++)
                    return false;
            }
            first = i;
            attr = foobar_str;
            return true;
        };
    };

    const auto foo = foobar();
}

int main()
{
    std::string input = "foobarfoobarfoobar";
    std::vector<std::string> strings;

    auto foobars = parser::foo >> parser::foo >> parser::foo;

    bool success = x3::phrase_parse(input.begin(), input.end(), foobars, x3::space, strings);
    if (success)
        std::cout << "yes\n";  // yes for this one
    else
        std::cout << "no\n";

    input = "foobar    foobar    foobar";
    success = x3::phrase_parse(input.begin(), input.end(), foobars, x3::space, strings);
    if (success) 
        std::cout << "yes\n"; 
    else 
        std::cout << "no\n";  // no because of the spaces
}

Solution

  • You can simply apply the skipper by getting it from the context. It is up to you decide when to use it (e.g. whether post-skip is part of the behaviour), but I suppose pre-skip is implied when there is an active skipper anyways.

    If you inherit from x3::parser_base, you can simply invoke

     skip_over(f, l, ctx);
    

    to do the job.

    See for an example X3 parse rule doesn't compile