Reputation: 793
I'm building a parser to execute commands that a user may enter on the command line. The first part of the command is the module it belongs to, the second part is the module's function to call.
Attached to the first parser is a semantic action (with boost::phoenix::ref()) that is supposed to store the name of the module in a variable m_moduleName. Attached to the 2nd parser is another semantic action that calls the function printParameters with the former variable as a parameter.
#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;
}
Expected result: During the first semantic action the value of m_moduleName should be set to mod01 which should be printed during the printParameters function.
Actual result (program output):
Module name before parsing: initial_default
Module name during parse:
Command name during parse: cmd02
Module name after parsing: mod01
While constructing this minimal example I noticed that the value of m_moduleName is empty during the execution of the parse function, although it has been set to "initial_default" beforehand.
Can somebody please explain what exactly is going on here?
Why is the value empty instead of being mod01?
Upvotes: 1
Views: 278
Reputation: 394054
You cannot mix Boost Bind/Phoenix/Lambda/Qi/std placeholders.
In fact you cannot use Boost Bind inside a semantic action.
You want to use use phoenix::bind
with qi::_1
. Aoh, and add phoenix::cref()
around m_moduleName
.
Other than that, you don't want to use ugly semantic actions in this case at all:
Simplified:
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
int main()
{
std::string const str("mod01 cmd02\n");
std::string moduleName, command;
qi::parse(str.begin(), str.end(), +~qi::char_(' ') >> +~qi::char_('\n'), moduleName, command);
std::cout << "Module name after parsing: " << moduleName << "\n";
std::cout << "Command after parsing: " << command << "\n";
}
Prints
Module name after parsing: mod01
Command after parsing: cmd02
See BOOST_FUSION_ADAPT_STRUCT and boost/fusion/adapted/std_pair.hpp
e.g. for ways to scale/automate
Upvotes: 1