saki7
saki7

Reputation: 692

Boost.Spirit.Qi: Defining a combination of too many parsers reaches template instantiation limit

This is a valid (and compilable) parser combination:

lit("foo") | lit("bar") | lit("baz")

But when it comes to around 200-400 binary concatenation, it fails.

This is the example error output:

fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)

Yes, of course. I love you, compiler.
And the actual error is this:

/usr/local/include/boost/proto/detail/preprocessed/matches_.hpp: In instantiation of ‘struct boost::proto::detail::matches_<boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::bitwise_or,

... bitwise_or continues forever.

I am quite sure that this is the nature of the expression template.
Quoting from Spirit's document:

Spirit pushes the C++ compiler hard.

lol.


So... Is there an efficient & simple-enough way to achieve the logically equivalent combined parser?
I've thought of the famous Nabialek trick, but it won't fit; it is for caching k-v pairs lazily and not for generating parser itself (if my understandings are correct).

Upvotes: 3

Views: 122

Answers (1)

sehe
sehe

Reputation: 393799

Just use a symbols<>. If you want to propagate the matched input, use raw[]

Here's a sample that parses and matches all keywords from rfc3092:

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <cassert>

namespace qi = boost::spirit::qi;
using     It = std::string::const_iterator;

int main() {

    qi::symbols<char> much;

    for (auto kw : {"bar", "baz", "qux", "quux", "corge", "grault", "garply", "waldo", "fred", "plugh", "xyzzy", "thud"})
        much.add(kw);

    qi::rule<It, std::string()> match_much = qi::raw [ much ];

    much.for_each([&](std::string const& kw, qi::unused_type) {
        std::string matched;
        assert(qi::parse(kw.begin(), kw.end(), match_much, matched));
        assert(kw == matched);
    });
}

Upvotes: 4

Related Questions