我一直在尝试为callgrind工具的输出(这是valgrind的一部分)创建Boost.Spirit解析器。 Callgrind输出一种特定于域的嵌入式编程语言(DSEL),该语言可让您执行各种很酷的工作,例如用于合成计数器的自定义表达式,但解析起来并不容易。我在https://gist.github.com/ned14/5452719#file-sample-callgrind-output放置了一些示例callgrind输出。我将当前的最佳尝试放在https://gist.github.com/ned14/5452719#file-callgrindparser-hpp和https://gist.github.com/ned14/5452719#file-callgrindparser-cxx上的Boost.Spirit词法分析器和解析器中。 Lexer部分很简单:它标记标记值,非空白文本,注释,行尾,整数,十六进制,浮点数和运算符(忽略示例代码中的标点符号,它们未使用)。空格被跳过。到现在为止还挺好。问题是解析标记化的输入流。我什至没有尝试过主要节,我仍在尝试解析文件值中上任何点可能出现的标记值。标签值如下所示:tagtext: unknown series of tokens<eol>它可以是自由格式的文本,例如desc: I1 cache: 32768 B, 64 B, 8-way associative, 157 picosec hit latency在这种情况下,您需要将 token 集转换为字符串,即转换为iterator_range并提取。但是,它可以是一个表达式,例如event: EPpsec = 316 Ir + 1120 I1mr + 1120 D1mr + 1120 D1mw + 1362 ILmr + 1362 DLmr + 1362 DLmw这表示从现在开始,将事件EPpsec合成为Ir乘以316加到I1mr乘以1120加上...等等。我想在这里指出的是,标记-值对需要作为任意的标记集进行累积,并进行后处理,以备以后将其转换为标记。为此,Boost.Spirit的utree()类正是我想要的,这就是示例代码所使用的。但是在VS2012上,使用带有可变参数模板的November CTP编译器,我目前看到此编译错误:1>C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(56): error C2440: 'static_cast' : cannot convert from 'boost::spirit::detail::list::node_iterator<const boost::spirit::utree>' to 'base_iterator_type'1> No constructor could take the source type, or constructor overload resolution was ambiguous1> C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(186) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_begin<const Range>(ForwardRange &)' being compiled1> with1> [1> IteratorT=base_iterator_type1> , Range=boost::spirit::utree1> , ForwardRange=boost::spirit::utree1> ]......这表明我的base_iterator_type是istreambuf_iterator的Boost.Spirit multi_pass 包装,具有正向迭代器性质,但Boost.Spirit的utree()实现无法理解它。问题是,我不确定这是我的错误代码还是Boost.Spirit代码错误,因为line_pos_iterator 无法正确指定其forward_iterator概念标签。感谢过去的Stackoverflow帮助,我可以编写一个纯的,没有标记的语法,但是它很脆弱。正确的解决方案是标记和使用具有相当任意输入能力的自由格式语法。可悲的是,让Boost.Spirit的Lex和Grammar一起在现实世界中的示例而不是玩具示例中运行的示例数量非常少。因此,任何帮助将不胜感激。尼尔 最佳答案 token属性提供了一个变体,除了base-iterator范围外,它还可以_假定在token_type typedef中声明的类型:typedef lex::lexertl::token<base_iterator_type, mpl::vector<std::string, int, double>> token_type;因此:string,int和double。但是请注意,当解析器实际使用该值时,强制转换为一种可能的类型只会延迟进行。utree是一个非常通用的容器 [1] 。因此,当您在规则上公开spirit::utree属性,并且 token 值变量包含iterator_range时,它将尝试将其分配给utree对象(此操作失败,因为迭代器是...'funky')。获得所需行为的最简单方法是强制 Qi将tag token 的属性解释为字符串,并将其分配给utree。因此,以下几行构成了一个使编译成功的修复程序: unknowntagvalue = qi::as_string[tok.tag] >> restofline;笔记说了这么多,我的确会提出以下建议考虑根据匹配的Nabialek Trick使用tag调度不同的惰性规则-这使得以后无需在上处理原始utree即可您可能已经成功地专门化了boost::spirit::traits::assign_to_XXXXXX特性(请参阅documentation)考虑使用纯Qi解析器。虽然我可以“感觉”到“它会变脆”的感觉,但它似乎已经证明它将复杂性提高到了某种程度,以至于没有实际值(value): [2] 属性实现的意外方式(此问题) line-pos迭代器的问题(这是常见问题,并且AFAIR大多具有困难或不完善的解决方案)关于例如临时调试(访问SA中的源数据),切换/禁用跳过程序等。我的个人经验是,查看词法分析器状态来驱动这些操作无济于事,因为切换词法分析器状态只能通过lexer token semantic actions可靠地工作,而通常,歧义会发生在Qi阶段 但我发散了:) [1] ,例如它们具有非常轻量级的“引用”迭代器范围的功能(例如,用于符号,或避免将字符从源缓冲区复制到属性中,除非需要) [2] 实际上,仅因为使用顺序词法分析器(扫描仪)大大减少了回溯机会的数量,所以它简化了解析器的思维模型。但是,您可以使用expectation points达到相同的效果。关于c++ - 使用Boost.Spirit解析标记化的自由格式语法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16196065/