【发布时间】:2015-10-03 03:44:52
【问题描述】:
我正在构建一个解析器来执行用户可以在命令行上输入的命令。命令的第一部分是它所属的模块,第二部分是要调用的模块的函数。
附加到第一个解析器的是一个语义操作(使用 boost::phoenix::ref()),它应该将模块的名称存储在变量 m_moduleName 中。附加到第二个解析器的是另一个语义动作,它调用函数 printParameters,前一个变量作为参数。
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/home/qi.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <string>
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
void printParameters(const std::string & module, const std::string & command)
{
std::cout << "Module name during parse: " << module << std::endl;
std::cout << "Command name during parse: " << command << std::endl;
}
template <typename Iterator>
struct myCommandParser : public qi::grammar<Iterator>
{
myCommandParser() : myCommandParser::base_type(start)
{
start = qi::as_string[+(~qi::char_(' '))][phoenix::ref(m_moduleName) = qi::_1]
>> qi::as_string[+(~qi::char_('\n'))][boost::bind(&printParameters, m_moduleName, ::_1)];
};
qi::rule<Iterator> start;
std::string m_moduleName;
};
int main()
{
myCommandParser<std::string::const_iterator> commandGrammar;
commandGrammar.m_moduleName = std::string("initial_default");
std::cout << "Module name before parsing: " << commandGrammar.m_moduleName << std::endl;
std::string str("mod01 cmd02\n");
std::string::const_iterator first = str.begin();
std::string::const_iterator last = str.end();
qi::parse(first, last, commandGrammar);
std::cout << "Module name after parsing: " << commandGrammar.m_moduleName << std::endl;
}
预期结果: 在第一个语义操作期间,m_moduleName 的值应设置为 mod01,该值应在 printParameters 函数期间打印。
实际结果(程序输出):
Module name before parsing: initial_default
Module name during parse:
Command name during parse: cmd02
Module name after parsing: mod01
在构建这个最小示例时,我注意到在执行 parse 函数期间 m_moduleName 的值是 empty,尽管它已预先设置为“initial_default”。
有人能解释一下这里到底发生了什么吗?
为什么值是空的而不是 mod01?
【问题讨论】:
-
尽管语法如此奇怪和神奇,但您需要记住
start规则的赋值发生在myCommandParser构造函数中。 Example。在语法构造函数boost::bind生成一个类似于[m_moduleName/*by current value*](const std::string& command){ printParameters(m_moduleName, command); }的对象。使用boost::bind(&printParameters, boost::cref(m_moduleName), ::_1)seems to work。 -
但是
phx::bind(&printParameters, phx::cref(m_moduleName), qi::_1)sehe 建议可能是更好的选择(例如,如果您需要传递两个参数而不是一个)。 Example.
标签: c++ boost-spirit-qi ref boost-phoenix