Я строю парсер для выполнения команд, которые пользователь может ввести в командной строке. Первая часть команды - это модуль, к которой он принадлежит, вторая часть - это функция модуля для вызова.Порядок семантических действий с использованием Spirit (с ссылкой Phoenix)
К первому парсеру относится семантическое действие (с 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?
Несмотря на то, что синтаксис настолько странный и волшебный, вам нужно иметь в виду, что назначение правила 'start' происходит внутри конструктора' myCommandParser'. [Пример] (http://coliru.stacked-crooked.com/a/d2de0d37cbc0b1d6). В конструкторе грамматики 'boost :: bind' генерирует объект, похожий на' [m_moduleName/* по текущему значению *] (const std :: string & command) {printParameters (m_moduleName, command); } '. Использование 'boost :: bind (& printParameters, boost :: cref (m_moduleName), :: _ 1)' [кажется, работает] (http: //coliru.stacked-crooked.ком/а/d81a32c98f40dd7c). – llonesmiz
Но 'phx :: bind (& printParameters, phx :: cref (m_moduleName), qi :: _ 1)', как рекомендует sehe, вероятно, является лучшей альтернативой (например, если вам нужно передать два параметра вместо одного). [Пример] (http://coliru.stacked-crooked.com/a/48509abadc1255d9). – llonesmiz