【发布时间】:2017-02-02 19:21:12
【问题描述】:
我刚刚开始使用 Boost::Spirit,但在理解以下代码中发生的事情时遇到了问题:
#include <cstdio>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
template <typename Iterator>
struct TestGrammar : qi::grammar<Iterator, std::string(), ascii::space_type>
{
qi::rule<Iterator, std::string(), ascii::space_type> expr;
qi::rule<Iterator, std::string(), ascii::space_type> tag;
std::string convertTag(std::string& tag)
{
printf("Tag: %s\n", tag.c_str());
tag = "_tag_" + tag;
return tag;
}
TestGrammar()
: TestGrammar::base_type(expr)
{
using qi::_1;
using qi::as_string;
using ascii::char_;
using namespace qi::labels;
// (1)
tag %= as_string[+char_] [ ph::bind(&TestGrammar::convertTag, this, _1) ];
// (2)
//tag = as_string[+char_] [ _val = ph::bind(&TestGrammar::convertTag, this, _1) ];
// (3)
//tag = as_string[+char_] [ _val += ph::bind(&TestGrammar::convertTag, this, _1) ];
expr = char_('!') >> tag;
}
};
int main(int argc, char** argv)
{
using ascii::space;
std::string str("!abc");
std::string::const_iterator beg = str.begin();
std::string::const_iterator end = str.end();
TestGrammar<std::string::const_iterator> expr;
std::string res;
bool r = phrase_parse(beg, end, expr, space, res);
if (r && beg == end) {
printf("Matched: %s\n", res.c_str());
} else {
printf("Didn't match!\n");
}
return 0;
}
这个例子应该解析带有前导'!'的标签(标识符),并以相同的格式将它们吐出,但在标签前加上“_tag_”(所以“!abc”变成“!_tag_abc”) .这只是显示我的问题的一个最小示例。
我不明白的是,当我使用 (1) 中的自动规则运行此代码时会发生什么。而不是预期的输出,我得到“_tag_!abc”,实际上convertTag()中的printf()实际上为标签打印了“!abc”。但这是为什么呢?我将_1 传递给convertTag(),我认为它应该是as_string[+char_] 解析的属性,所以它怎么会包含'!'用完全不同的规则解析?
当我改用规则 (2) 时(我认为它等同于 (1)),我得到的是“_tag_abc”,它似乎已经删除了最初的 '!',但为什么呢?
规则 (3) 做我想做的事,虽然我不知道为什么。
从 (2) 看来,在 tag 规则中覆盖 _val 实际上不仅覆盖了 tag 的整个合成属性,还覆盖了 expr 的整个合成属性。在tag中设置_val不只影响tag的综合属性吗?为什么会有一个“!”在我的_1 (1) 中?
// 编辑:
哎呀。我刚刚意识到 (2) 和 (3) 可能完全没有意义,因为它将 ph::bind() 的返回值(不是 convertTag() 本身)分配给_val,这可能不符合我的要求(或者是吗?)。尽管如此,问题仍然是为什么 (1) 没有按我想要的方式工作。
【问题讨论】:
-
如果你真的只是想添加一些东西,考虑
qi::attr("_tag_") >> tag
标签: c++ boost boost-spirit boost-spirit-qi