Я создаю парсер для выполнения команд, которые пользователь может вводить в командной строке. Первая часть команды — это модуль, которому она принадлежит, вторая часть — функция вызываемого модуля.
К первому парсеру прикреплено семантическое действие (с 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
При создании этого минимального примера я заметил, что значение m_moduleName пустой во время выполнения функции разбора, хотя она была предварительно установлена на «initial_default».
Может кто-нибудь объяснить, что именно здесь происходит?
Почему значение пустое, а не mod01?
Вы не можете смешивать заполнители Boost Bind / Phoenix / Lambda / Qi / std.
На самом деле вы не можете использовать Boost Bind внутри семантического действия.
Вы хотите использовать использовать phoenix::bind
с qi::_1
, Ах, и добавь phoenix::cref()
вокруг m_moduleName
,
Кроме этого, вы вообще не хотите использовать некрасивые семантические действия:
Упрощенная:
#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";
}
Печать
Module name after parsing: mod01
Command after parsing: cmd02
Смотрите BOOST_FUSION_ADAPT_STRUCT и boost/fusion/adapted/std_pair.hpp
например способы масштабирования / автоматизации