2014-10-03 3 views
2

Почему этот анализатор оставляет 'b' в атрибутах, даже если опция не была сопоставлена?Boost Spirit дополнительный синтаксический анализатор и обратный отсчет

using namespace boost::spirit::qi; 

std::string str = "abc"; 

auto a = char_("a"); 
auto b = char_("b"); 
qi::rule<std::string::iterator, std::string()> expr; 
expr = +a >> -(b >> +a); 

std::string res; 

bool r = qi::parse(
     str.begin(), 
     str.end(), 
     expr >> lit("bc"), 
     res 
); 

Он разбирает успешно, но res is "ab".

Если parse "abac" с одним экспиром, опция сопоставляется и атрибут "aba".

То же самое с "aac", опция не начинается, и атрибут "aa".

Но с "ab" атрибутом является "ab", хотя b получает обратный отсчет и, как в примере, соответствует следующему синтаксическому анализатору.

UPD

С expr.name("expr"); и debug(expr); я получил

<expr> 
    <try>abc</try> 
    <success>bc</success> 
    <attributes>[[a, b]]</attributes> 
</expr> 

ответ

3

Во-первых, это UB использовать auto переменные, чтобы сохранить шаблоны выражений, потому что они держат ссылки на временных "a" и "b"[1].

Вместо написать

expr = +qi::char_("a") >> -(qi::char_("b") >> +qi::char_("a")); 

или, если вы настаиваете:

auto a = boost::proto::deep_copy(qi::char_("a")); 
auto b = boost::proto::deep_copy(qi::char_("b")); 
expr = +a >> -(b >> +a); 

теперь заметив >> lit("bc") часть скрывается в parse вызова, предлагает Вам может ожидать отката к на успешно совпадающая жетоны когда сбой по сидению происходит по дороге.

Этого не происходит: Дух генерирует грамматики ПЭГ и всегда жадно совпадает слева направо.


На к образцу дал, ab результатов, даже если откат делает происходит, воздействие на атрибуте не откат без qi::hold: Live On Coliru

атрибутов контейнеров передаются вместе с реф и эффекты предыдущих (успешных) выражений - нет откат, если вы не говорите также о Духе. Таким образом, вы можете «заплатить за то, что используете» (так как копирование временного времени было бы дорогостоящим).

См., Например,

<a> 
    <try>abc</try> 
    <success>bc</success> 
    <attributes>[a]</attributes> 
</a> 
<a> 
    <try>bc</try> 
    <fail/> 
</a> 
<b> 
    <try>bc</try> 
    <success>c</success> 
    <attributes>[b]</attributes> 
</b> 
<a> 
    <try>c</try> 
    <fail/> 
</a> 
<bc> 
    <try>bc</try> 
    <success></success> 
    <attributes>[]</attributes> 
</bc> 
Success: 'ab' 

[1] см он Re:

+0

Ну, я уже заменил 'auto' на правила. –

+0

Но, я не понимаю, вы используете двоичный минус? Это другой язык, не так ли? –

+0

@MikhailCheshkov Я просто замечал эту опечатку. ** Обновлен ** ответ. Извините мою ошибку:/ – sehe

2

Цитирование @sehe из this SO вопрос

Атрибут строка является атрибутом контейнера и многие элементы могут быть назначены в него разным парсером subexpressi дополнения. Теперь за соображения эффективности, Spirit не откатывает значения испущенных атрибутов при возврате назад.

Итак, я поставил дополнительный парсер на удержание, и все сделано.

expr = +qi::char_("a") >> -(qi::hold[qi::char_("b") >> +qi::char_("a")]); 

Для получения дополнительной информации см упоминается вопрос и hold docs

+0

Эта информация верна в моем ответе. Мммм. Возможно, потому, что я не показывал использование 'hold'. Хорошо, +1 (спасибо за то, что я расстался с отсутствующей единомыслием) – sehe