使用长语法序列时Boost Spirit Qi解析出现编译错误
问题分析与解决方案
问题背景
需要解析以下格式的字符串:
CONNECT clk sda 1.020::1.030 0.200::0.00 CONNECT da doai 0.100::0.050 0.040::0.300
解析后通过回调函数传递令牌,但使用完整语法序列时触发编译错误,缩短语法序列(仅解析单个PIN和单个值)时编译正常。
无编译错误的短语法示例
解析目标字符串:
CONNECT clk 0.200::0.00 CONNECT da 0.040::0.300
对应语法代码:
auto connect_parser = qi::copy(qi::lit("CONNECT") >> qi::space >> pin_parser[boost::phoenix::bind(callback, "PIN1", qi::_1)] >> qi::space >> val_parser >> qi::space );
触发编译错误的长语法代码
void Parse(string const& input) { string::const_iterator begin = input.begin(), end = input.end(); auto pin_parser = qi::copy(+(qi::char_("a-z"))); auto val_parser = qi::copy(qi::float_ >> ':' >> *(qi::float_) >> ':' >> qi::float_); auto connect_parser = qi::copy( qi::lit("CONNECT") >> qi::space >> pin_parser[boost::phoenix::bind(callback, "PIN1", qi::_1)] >> qi::space >> pin_parser[boost::phoenix::bind(callback, "PIN2", qi::_1)] >> qi::space >> val_parser >> qi::space >> val_parser >> qi::space ); bool is_succ = qi::parse(begin, end, +connect_parser); std::cout << "Succ " << is_succ << std::endl; }
编译错误信息
spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l> >, 2l>&>, 1l>]' PASDFParser.cpp:81:62: required from here /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/convert.hpp:27:13: error: invalid use of incomplete type 'struct boost::fusion::detail::barrier::as_vector<13>' type; ^ In file included from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/detail/as_vector.hpp:15:0, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/convert.hpp:11, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector.hpp:30, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/view/zip_view/detail/at_impl.hpp:12, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/view/zip_view/zip_view.hpp:19, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/view/zip_view.hpp:12, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/sequence/intrinsic/swap.hpp:15, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/sequence/intrinsic.hpp:23, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/include/intrinsic.hpp:11, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/proto/fusion.hpp:22, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/proto/core.hpp:21, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/proto/proto.hpp:12, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/support/meta_compiler.hpp:19, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi/meta_compiler.hpp:14, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi/action/action.hpp:14, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi/action.hpp:14, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/home/qi.hpp:14, from /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/spirit/include/qi.hpp:16, from PASDFParser.h:17, from PASDFParser.cpp:10: /calypto/tools/install/boost/boost_1_59_0/rhel7/m64/include/boost/fusion/container/vector/detail/cpp03/as_vector.hpp:28:12: note: declaration of 'struct boost::fusion::detail::barrier::as_vector<13>' struct as_vector;
错误原因
你使用的Boost 1.59版本中,Boost Fusion的默认元编程序列长度上限为10(部分场景下为12)。当语法序列展开后的内部元素(包括解析器、动作、分隔符等)数量超过这个上限时,就会触发as_vector<N>的不完整类型错误——因为Boost预定义的Fusion Vector特化只覆盖到固定长度,超出后没有生成对应的模板实例。你的长语法序列展开后,内部组合的序列长度达到了13,超过了默认上限。
解决方案
方案1:提升Fusion序列长度上限
在包含任何Boost头文件之前,定义BOOST_FUSION_MAX_VECTOR_SIZE宏,设置一个足够大的值(比如20),强制Fusion生成对应长度的Vector特化:
#define BOOST_FUSION_MAX_VECTOR_SIZE 20 #include <boost/spirit/include/qi.hpp> #include <boost/phoenix.hpp> // 其他项目头文件
方案2:拆分语法,降低单序列元素数量
将复杂的语法拆分为更小的子规则,避免单个>>连接的序列过长,同时修正val_parser的错误写法(原写法会匹配任意数量的float,不符合目标格式的x::y结构):
namespace qi = boost::spirit::qi; namespace phoenix = boost::phoenix; void Parse(string const& input) { string::const_iterator begin = input.begin(), end = input.end(); auto pin_parser = qi::copy(+(qi::char_("a-z"))); auto val_parser = qi::copy(qi::float_ >> "::" >> qi::float_); // 修正为匹配固定双冒号分隔符 // 拆分出PIN解析子规则 auto pins_parser = qi::copy( pin_parser[phoenix::bind(callback, "PIN1", qi::_1)] >> qi::space >> pin_parser[phoenix::bind(callback, "PIN2", qi::_1)] >> qi::space ); // 拆分出值解析子规则 auto vals_parser = qi::copy( val_parser >> qi::space >> val_parser >> qi::space ); auto connect_parser = qi::copy( qi::lit("CONNECT") >> qi::space >> pins_parser >> vals_parser ); bool is_succ = qi::parse(begin, end, +connect_parser); std::cout << "Succ " << is_succ << std::endl; }
方案3:升级Boost版本
较新的Boost版本(如1.65及以上)中,Fusion的序列长度上限已大幅提升,且实现更灵活,不会轻易触发这类长度限制问题。如果项目允许,升级到新版本Boost可以一劳永逸解决该问题。
内容的提问来源于stack exchange,提问作者Amit Dey
相关产品推荐
相关产品推荐

