Избегайте выбрасывания Expectation_failure при сбое анализатора ожидания

Как избежать создания исключения, когда анализатор ожидания не работает?

У меня есть правило "function" > (!x3::lexeme[keyword >> !(x3::alnum | '_')] >> symbol) > ('(' > -lvalue_list > ')') > statements > "end" проанализировать код как:

function a() return one end

keywords есть (zero, one, function, return, end так далее).

Если я буду кормить парсер function one() return zero end код, затем в функции expect_directive::parse Исключение выдается отсюда:

if (!r)
{
boost::throw_exception(
expectation_failure<Iterator>(
first, what(this->subject)));
}

Когда это произойдет, я получил Программа неожиданно завершилась. или же Прервано (ядро сброшено) (в зависимости от используемого терминала).

При отладке кода GDB автоматически разрывается при закрывающей скобке ‘}’ в boost::throw_exception функция с сообщением:

The inferior stopped because it received a signal from the Operating System.

Signal name :
SIGABRT
Signal meaning :
Aborted

При пошаговом выполнении упомянутой функции видно, что throw enable_current_exception(enable_error_info(e)); строка — последняя строка, выполненная перед выдачей сигнала. Почему для поиска в обработчике исключений нет разматывания стека? Почему прервать мгновенно подняли (выглядит как boost::throw_exception иметь noexcept Спецификатор)?

Я обнял в try { ... } catch (x3::expectation_failure< input_iterator_type > const & ef) { ... } x3::phrase_parse вызов функции. x3::expectation_failure< input_iterator_type > именно ожидание, выброшенное из boost::throw_exception, Все это не имеет значения.

Есть ли способ полностью избежать x3::expectation_failure исключение в Boost.Spirit X3, но все же прервать парсинг кода в целом и сделать x3::phrase_parse возвращать false на провал ожидания?

Мои подозрения следующие:

Из-за обычного возвращаемого значения parse() функция-член всех парсеров (как концепция в X3) является boolЯ подозреваю, что есть только два способа сообщить о сбое: исключение xor код возврата (который может быть только true или же false, а также true уже занят для Разбор успешен отчет о результатах). Это присуще реализации рекурсивных нисходящих парсеров в C ++. Но если мы изменим тип результата parse от bool что-то более широкое, мы можем более гибко различать сообщения о сложных или мягких ошибках (или что-то еще) во время синтаксического анализа — с помощью различных значений кода возврата.

3

Решение

Вы не можете избежать сбоя ожидания при использовании синтаксического анализатора ожидания. Это цель этого оператора.

использование operator>> для «отслеживаемых ожиданий» (то есть альтернатив).

Когда вы используете точки ожидания (operator>) просто обработай исключение тоже.

Заметка Это выглядит как опечатка

('(' > -lvalue_list > '>')

должно быть

('(' > -lvalue_list > ')')

Также return one end не совпадает "begin" >> statements >> "end" независимо от того, что statements определяется как…

Исправление вещей:

Жить с отладкой правил (только c ++ 14)

#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>

namespace SO {
namespace x3 = boost::spirit::x3;

x3::symbols<char> const keyword = []{
x3::symbols<char> kw;
kw += "for","begin","end","function","while","break","switch";
return kw;
}();

x3::rule<struct symbol_tag>      const symbol     ("symbol");
x3::rule<struct identifier_tag>  const identifier ("identifier");
x3::rule<struct lvalue_list_tag> const lvalue_list("lvalue_list");
x3::rule<struct statements_tag>  const statements ("statements");
x3::rule<struct rule_tag>        const rule       ("rule");

auto symbol_def      = x3::lexeme[x3::alnum >> *(x3::alnum | '_')];
auto identifier_def  = (!(x3::lexeme[keyword >> !(x3::alnum | '_')]) >> symbol);
auto lvalue_list_def = identifier % ',';
auto statements_def  = *identifier;
auto rule_def        = "function">> identifier
>> ('(' > -lvalue_list > ')')
>> ("begin" > statements > "end")
;

BOOST_SPIRIT_DEFINE(symbol, identifier, lvalue_list, statements, rule)
}

int main() {
std::string const sample = "function a() begin return one end";
auto f = sample.begin(), l = sample.end();

bool ok = phrase_parse(f, l, SO::rule, SO::x3::space);
if (ok)
std::cout << "Parse success\n";
else
std::cout << "Parse failed\n";

if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

Печать:

<rule>
<try>function a() begin r</try>
<identifier>
<try> a() begin return on</try>
<symbol>
<try> a() begin return on</try>
<success>() begin return one </success>
</symbol>
<success>() begin return one </success>
</identifier>
<lvalue_list>
<try>) begin return one e</try>
<identifier>
<try>) begin return one e</try>
<symbol>
<try>) begin return one e</try>
<fail/>
</symbol>
<fail/>
</identifier>
<fail/>
</lvalue_list>
<statements>
<try> return one end</try>
<identifier>
<try> return one end</try>
<symbol>
<try> return one end</try>
<success> one end</success>
</symbol>
<success> one end</success>
</identifier>
<identifier>
<try> one end</try>
<symbol>
<try> one end</try>
<success> end</success>
</symbol>
<success> end</success>
</identifier>
<identifier>
<try> end</try>
<fail/>
</identifier>
<success> end</success>
</statements>
<success></success>
</rule>
Parse success

Без отладки

Это становится намного проще:

Жить на Колиру (Г ++ / лязг ++)

#include <boost/spirit/home/x3.hpp>
#include <iostream>

int main() {
namespace x3 = boost::spirit::x3;

x3::symbols<char> keyword;
keyword += "for","begin","end","function","while","break","switch";

static auto symbol      = x3::lexeme[x3::alnum >> *(x3::alnum | '_')];
static auto identifier  = (!(x3::lexeme[keyword >> !(x3::alnum | '_')]) >> symbol);
static auto lvalue_list = identifier % ',';
static auto statements  = *identifier;
static auto rule        = "function">> identifier
>> ('(' > -lvalue_list > ')')
>> ("begin" > statements > "end")
;

std::string const sample = "function a() begin return one end";
auto f = sample.begin(), l = sample.end();

bool ok = phrase_parse(f, l, rule, x3::space);
if (ok)
std::cout << "Parse success\n";
else
std::cout << "Parse failed\n";

if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

Просто печатает

Parse success

Just И просто чтобы показать вам, Можно справиться с ошибкой ожидания просто отлично: Ожидание обработки ошибок

4

Другие решения