Search code examples
c++boost-spirit-x3

Boost.Spirit.X3 how to prevent token from being parsed by previous rule?


given this grammar :

const auto grammar_def = x3::lit("start")
                        > x3::lit("{")
                        > (*(char_("a-zA-Z0-9\".{}=_~")))
                        > x3::lit("}") > x3::lit(";");

the last x3::lit("}") is being consumed by (*(char_("a-zA-Z0-9\".{}=_~"))) since it contains "}"
is there way to prevent that ? something like giving x3::lit("}") higher priority during parse?


Solution

  • You can always write a custom parser that works like kleene star but can backtrack and also takes a second parser that must match as well. Something like this should work.

            template <class Left, class Right>
            struct backtracking : binary_parser<Left, Right, backtracking<Left, Right>>
            {
                using base = binary_parser<Left, Right, backtracking<Left, Right>>;
                backtracking(Left const& left, Right const& right)
                    :  base(left, right)
                {
                }
    
                template<typename It, typename Ctx, typename Other>
                bool parse(It& f, It l, Ctx const& ctx, Other const& other, unused_type) const
                {
                    auto end_it = l;
                    while (end_it != f) {
                        auto save = f;
                        if (this->left.parse(f, end_it, ctx, other, unused)) {
                            if (this->right.parse(f, l, ctx, other, unused))
                                return true;
                        }
                        f = save;
                        --end_it;
                    }
                    return false;
                }
            };
    
    const auto grammar_def = x3::lit("start")
                            > x3::lit("{")
                            > backtracking(
                                 *(char_("a-zA-Z0-9\".{}=_~")), lit("}") >> lit(";"));