Обработка исключения в семантических действиях

Рассмотрим следующий парсер:

class test
{
public:
  static test from_string(const string &str); //throws!
};

template <typename Iterator = string::const_iterator>
struct test_parser : grammar<Iterator, test(), blank_type>
{
  test_parser() : test_parser::base_type(query)
  {
    query = id[_val = phx::bind(&test::from_string, qi::_1)];
    id = lexeme[*char_("a-zA-Z_0-9")];
  }
  rule<Iterator, test(), blank_type> query;
  rule<Iterator, string(), blank_type> id;
};

Я хотел бы перехватывать исключения, которые test::from_string может вызвать, и не выполнять совпадение при исключении. Мне не удалось найти прямой способ сделать это, поэтому я пытаюсь использовать функцию «адаптера», которая явно принимает контекст. Но как получить доступ к контексту и как привязать такое действие к грамматике? Пожалуйста, смотрите вопросы в коде:

template<class Context>
void match_test(const string &attr, Context &context, bool &mFlag)
{
  try
  {
    test t = test::from_string(attr);
    // how do I access the context to put t into _val?
  }
  catch(...)
  {
    mFlag = false;
  }
}

//...
test_parser() : test_parser::base_type(query)
{
  query = id[?match_test<?>? /*how to instantiate and use the above semantic action?*/];
  id = lexeme[*char_("a-zA-Z_0-9")];
}

person Igor R.    schedule 28.10.2013    source источник
comment
Как вы можете видеть в этом отличном ответе, вам нужно будет использовать boost::fusion::at_c<0>(context.attributes) = t;. Другой альтернативой, которая, я думаю, должна работать, но я никогда не тестировал, было бы использование query = id[phx::try_[_val = phx::bind(&test::from_string, qi::_1)].catch_all[_pass=false] ];.   -  person llonesmiz    schedule 28.10.2013
comment
Альтернатива phx::try_[].catch_all[], похоже, работает только с Phoenix v2.   -  person llonesmiz    schedule 28.10.2013
comment
@cv_and_he, может быть ... нам стоит подумать о регистрации ошибок здесь. Я не понимаю, почему это не работает, правда   -  person sehe    schedule 28.10.2013
comment
@sehe Если вы поместите try_catch в последовательность, например добавив std::cout << phx::val("testing...") или что-то глупое, например qi::_1=qi::_1, он компилируется. Я не знаю достаточно, чтобы быть уверенным, но я думаю, что код, который имеет дело с семантическими действиями, неявно ожидает некоторых требований от выражений феникса, а try_catch им не соответствует.   -  person llonesmiz    schedule 28.10.2013
comment
@cv_and_he хорошая работа, я добавил обходной путь к своему ответу. Не могли бы вы сообщить об этом в списке? Я полагаю, что это, вероятно, просто отсутствующая черта 'statement' для try_catch шаблонов выражений.   -  person sehe    schedule 28.10.2013
comment
@cv_and_he, @sehe - отлично, спасибо за помощь. try_catch именно то, что мне нужно.   -  person Igor R.    schedule 28.10.2013


Ответы (1)


Как сказал комментатор, используйте

    query = id[
            phx::try_ [
                qi::_val = phx::bind(&test::from_string, qi::_1)
            ].catch_all [ 
                qi::_pass = false 
            ]
        ];

См. в прямом эфире на Coliru

Версия, которая компилируется даже с BOOST_SPIRIT_USE_PHOENIX_V3: Live on Coliru

    query = id[
            phx::try_ [
                qi::_val = phx::bind(&test::from_string, qi::_1)
            ].catch_all [ 
                qi::_pass = false 
            ],
            qi::_pass = qi::_pass // to appease the spirit expression compilation gods
        ];
person sehe    schedule 28.10.2013
comment
Я перешел на V3, и оказалось, что описанный выше обходной путь не работает: семантическое действие просто не вызывается вообще. - person Igor R.; 03.12.2013
comment
@IgorR. Вы забыли включить соответствующий заголовок? Похоже на случай стандартного поведения оператора запятой (он же оператор запятой) - person sehe; 03.12.2013