Boost.Spirit.Qi:定义太多解析器的组合达到模板实例化限制

时间:2017-02-16 10:29:57

标签: c++ boost boost-spirit-qi

这是一个有效的(可编译的)解析器组合:

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

但是当涉及 200-400 二进制连接时,它会失败。

这是示例错误输出:

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

是的,当然。我爱你,编译器。
实际错误是这样的:

/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永远持续下去。

我很确定这是表达模板的本质 引自Spirit的文件:

Spirit pushes the C++ compiler hard.

洛尔。

所以......有效率吗?简单的方法来实现逻辑等效的组合解析器?
我已经想到了着名的Nabialek技巧,但它不合适;它是懒惰地缓存k-v对而不是为了生成解析器本身(如果我的理解是正确的)。

1 个答案:

答案 0 :(得分:4)

只需使用symbols<>即可。如果要传播匹配的输入,请使用raw[]

这是一个解析并匹配来自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);
    });
}