使用C++ Boost::Spirit PEG语法生成表达式

3
我对C++和boost::spirit非常陌生。尝试通过使用PEG构建仅包含||和&&的简单表达式树来学习两者。我已经从文档中的mini-xml教程构建了代码的许多部分。
这是代码,它适用于像"1 || 0"、"1 && 0"、"1 || 1 && 0"这样的简单字符串,但对于"(1 || 1)"则失败了。我不太明白为什么会打印失败,即使它说解析成功。
此外,请指导我如何使这段代码在长期运行中更加直观和可维护。
2个回答

4
启用Spirit调试支持可以帮助:
a) 添加一个定义
#define BOOST_SPIRIT_QI_DEBUG

并且b)在语法构造函数内添加一个

BOOST_SPIRIT_DEBUG_NODE(r);

对于所有规则(此处为r),解析器会在运行时打印一个执行树,显示执行了哪些规则以及使用了哪些输入和填充了哪些属性值(有关详细信息,请参见此处)。
作为一般说明(这可能不适用于您,因为您似乎尝试构建AST),Spirit的解析器是完全有属性的。这意味着通常您不需要任何语义操作来处理属性(有关简要介绍,请参见这里这里,以及这里)。

感谢@hkaiser!调试节点真的很有帮助,我能够解决我的错误(已更新要点)。问题出在我对指针的理解有限,语法运行得很好(调试模式证实了这一点)。 - na_ka_na
我该如何将我的语义动作分组到一个boost::phoenix函数中?目前我是这样做的:[at_c<1>(val) = new<E>()][*(at_c<1>(_val)) = _1] [at_c<2>(_val) = true]。这个方法可以工作,但如果我尝试[1,2,3],它只会考虑3(忽略1和2)。 - na_ka_na
如果只有逗号分隔表达式序列的最后一个元素被执行,那么您可能缺少正确的Phoenix头文件来定义逗号运算符重载。它是#include <boost/spirit/include/phoenix_statement.hpp>,如果我没记错的话。 - hkaiser

0

我不知道为什么你的特定Spirit代码不起作用,但考虑到你是“非常新的C++”并且要求如何使你的代码在长期内更易维护,我的答案是:

不要使用Boost Spirit。使用一个众所周知的解析器生成器,例如ANTLR(v2可以生成C++代码;v3不行,因此请使用v2),或者lex&yacc或类似工具。

Boost Spirit是一个展示C++某些特性能够达到何种程度的好工具。如果你的目标是直观和易于维护的代码,尤其是如果你还不是C++专家(这完全不是针对你的批评),它并没有特别帮助你。


我正在寻找深入学习C++的方法,因此我认为Boost库可能是一个不错的起点(错误地?)假设它很普遍。我也会尝试使用ANTLR。我的新工作场所要求我在某些任务中使用C++,因此需要可维护性。感谢您的建议! - na_ka_na
Spirit/Qi是Boost中最难理解的部分之一;Boost是最难理解的C++库之一;对于新手来说,C++是较为困难的语言之一。你选择了一条非常艰难的道路。 :) 我曾在两个完全不同的公司的两个完全不同的项目中尝试使用Boost Spirit来编写生产代码,但每次都在几天后放弃了。我不是最好的C++程序员,但我比你现阶段更擅长它,所以我建议你找一些其他与C++相关的东西来练习。 - John Zwinck
就普及程度而言,Boost 是广泛使用的;Spirit 则不然。在 Boost 中被大量使用的部分包括无序容器、智能指针、正则表达式、内嵌式容器、变体类型、函数对象绑定、文件系统、程序选项和线程模块等。 - John Zwinck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接