Boost :: spirit нелегальное_отслеживание исключения

Я использую Boost.Spirit.Lex и .Qi для проекта простого калькулятора, и (как обычно) это доставляет мне некоторую боль при отладке и использовании. Отладка печатает:

<expression>
<try>boost::spirit::multi_pass::illegal_backtracking

Это исключение выброшено, и я не могу понять, почему. Я использую макросы в своем коде, и было бы больно приводить минимальный пример, поэтому я даю весь проект. Просто сделайте «make» в корне, а затем запустите ./sash, появится приглашение, если вы хотите протестировать, просто выполните «-echo $ 5-8».

Похоже, что Google не нашел подобных проблем с этим исключением …

Синтаксический анализатор находится в арифметическом /, и вызов синтаксического анализатора находится в конце arithmetic /valuator.cpp

Любой помогает очень ценить.

1

Решение

Ваш код не работает, потому что BOOST_SPIRIT_QI_DEBUG, а также on_error<> кажется, что обработчик использует итераторы после того, как они могли быть признаны недействительными.

Если честно, я не совсем уверен, как это могло произойти.

Фон

AFAICT lexertl использует spirit::multipass<> с split_functor политика ввода и split_std_deque политика хранения [1].

Теперь (к счастью?) Политика проверки buf_id_check Это означает, что итератор будет проверять наличие недействительности во время разыменования.

Ожидается, что итераторы будут признаны недействительными, если

  1. итератор разыменовывается, увеличивая буфер до> 16 токенов а также итератор является единственным, ссылающимся на общее состояние.
  2. или где-то вдоль линии clear_queue вызывается точно (например, из flush_multi_path примитив в духовном хранилище)

Честно говоря, я не вижу ни одного из этих двух условий. Быстрый и грязный

token_iterator_type clone = iter; // just to make it non-unique...

в evaluator.cpp не имеет значения (исключая причину № 1)

Временное отключение docheck реализация в buf_id_check_policy заставил Вальгринда указать, что on_error<> и BOOST_SPIRIT_DEBUG * вызывают недействительные ссылки на память. Комментирование и то и другое действительно устраняет все проблемы (и eval_expression в настоящее время работает).

Однако это, вероятно, не ваше предпочтительное решение.

поскольку

  • вы работаете с фиксированным контейнером в памяти, представляющим ввод, который вам на самом деле не нужен multi_pass эмуляция поведения
  • вы используете тривиальную грамматику, вы не получаете от lexertl — в то время как вы получаете много дополнительной сложности (как вы можете видеть)

Я быстро изменил код: https://github.com/sehe/sash-refactor/commits/master

  • совершить dec31496 sanity - lets do without macros
    4 файла изменены, 59 вставок (+), 146 удалений (-)

  • совершить 6056574c dead code, excess scope, excess instantiation
    5 файлов изменено, 38 вставок (+), 62 удалений (-)

  • совершить 99d441db remove lexer
    9 файлов изменены, 25 вставок (+), 177 удалений (-)

Теперь вы обнаружите, что ваш код, как правило, намного проще, к тому же намного короче, не выходит за пределы multi_pass, и вы все равно можете иметь SPIRIT_DEBUG, а также on_error управляемость 🙂 В итоге

  • двоичный размер в -g3 равен уменьшено с 16 МБ до 6,5 МБ
  • чистые 263 строки кода был удален
  • важнее, оно работает

Вот несколько примеров (без отладочной информации):

$ ./sash <<< '-echo $8-9'
-1
Warning: Empty environment variable "8-9".
$ ./sash <<< '-echo $8\*9'
72
Warning: Empty environment variable "8*9".
$ ./sash <<< '-echo $8\*(9-1)'
64
Warning: Empty environment variable "8*(9-1)".
$ ./sash <<< '-echo $--+-+8\*(9-1)'
-64
Warning: Empty environment variable "--+-+8*(9-1)".

[1] Которые, несмотря на свое название, буферы ранее видели токены в std::vector<>

3

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

Других решений пока нет …