Каковы недостатки фреймворка парсера-генератора Spirit от boost.org?

В нескольких вопросах я видел рекомендации для Spirit фреймворк генератора парсеров с сайта boost.org, но потом в комментариях ворчат люди, использующие Spirit, которые не счастливы. Не могли бы эти люди встать и объяснить остальным из нас, в чем недостатки или недостатки использования Духа?


person Norman Ramsey    schedule 11.01.2009    source источник
comment
хорошая обработка текста в ускоренном видео Эрика Ниблера: video.google.de/videoplay?docid=3723782552647089226< /а> . Слайды здесь: nwcpp.org/Downloads/2007/Text_Processing_With_Boost.ppt . Радоваться, веселиться!   -  person Johannes Schaub - litb    schedule 11.01.2009
comment
Думаю, рабочее видео находится здесь youtube.com/watch?v=6eVtvQ3IEfc /cc @JohannesSchaub-litb   -  person sehe    schedule 30.06.2016


Ответы (5)


Это довольно крутая идея, и мне она понравилась; было особенно полезно действительно научиться использовать шаблоны C++.

Но их документация рекомендует использовать Spirit для парсеров малого и среднего размера. Синтаксический анализатор для полного языка потребует целую вечность для компиляции. Я назову три причины.

  • Бессканерный разбор. Хотя это довольно просто, когда требуется возврат, это может замедлить анализатор. Однако это необязательно - лексер может быть интегрирован, см. Препроцессор C, созданный с помощью Spirit. Грамматика из ~300 строк (включая файлы .h и .cpp) компилируется (неоптимизированно) в файл размером 6M с помощью GCC. Встраивание и максимальная оптимизация позволяют сократить это число до ~1,7M.

  • Медленный синтаксический анализ - нет статической проверки грамматики, ни для намека на необходимость чрезмерного просмотра вперед, ни для проверки основных ошибок, таких как, например, использование левой рекурсии (что приводит к бесконечной рекурсии в LL-грамматиках парсеров с рекурсивным спуском). Однако левая рекурсия не является действительно сложной ошибкой для отслеживания, но чрезмерный просмотр вперед может привести к экспоненциальному увеличению времени синтаксического анализа.

  • Интенсивное использование шаблонов — хотя это имеет определенные преимущества, это влияет на время компиляции и размер кода. Кроме того, определение грамматики обычно должно быть видно всем другим пользователям, что еще больше влияет на время компиляции. Я смог переместить грамматики в файлы .cpp, добавив явные экземпляры шаблонов с правильными параметрами, но это было непросто.

ОБНОВЛЕНИЕ: мой ответ ограничен моим опытом работы с классическим Spirit, а не с Spirit V2. Я бы по-прежнему ожидал, что Spirit будет в значительной степени основан на шаблонах, но сейчас я просто предполагаю.

person Blaisorblade    schedule 13.01.2009
comment
+1 за время компиляции и раздувание кода ... Однажды я использовал дух для небольшого проекта (анализ конфигурационных файлов), а позже решил удалить его именно по этим причинам. - person Nils Pipenbrinck; 20.10.2009
comment
Время компиляции для реального полезного грамматика, скажем, более дюжины правил, катастрофически медленное. - person ravenspoint; 13.09.2011
comment
@Blaisorblade - этот ответ относится к Spirit classic или к Spirit V2 ?? (см. другой ответ: stackoverflow.com/questions/432173/) - person Martin Ba; 07.11.2011

В boost 1.41 выходит новая версия Spirit, и она лучше, чем у Spirit::classic:

После долгого пребывания в бета-версии (более 2 лет с Spirit 2.0) Spirit 2.1, наконец, будет выпущен вместе с предстоящим выпуском Boost 1.41. Теперь код очень стабилен и готов к работе. Мы усердно работаем над завершением документации к Boost 1.41. Вы можете просмотреть текущее состояние документации здесь. В настоящее время вы можете найти код и документацию в транке Boost SVN. Если у вас есть новый проект с участием Spirit, мы настоятельно рекомендуем начать с Spirit 2.1 прямо сейчас. Позвольте мне процитировать сообщение OvermindDL из списка рассылки Spirit:

Я могу начать походить на бота из-за того, как часто я говорю это, но Spirit.Classic древний, вам следует переключиться на Spirit2.1, он может делать все, что вы делали выше, ГОРАЗДО проще, намного меньше кода, и он выполняет Быстрее. Например, Spirit2.1 может построить весь ваш AST в режиме реального времени, без каких-либо странных переопределений, без необходимости создавать что-то потом и т. д., и все это как один приятный и быстрый шаг. Вам действительно нужно обновиться. См. другие сообщения за прошлый день для ссылок на документы и тому подобное для Spirit2.1. Spirit2.1 в настоящее время находится в Boost Trunk, но официально будет выпущен вместе с Boost 1.41, но в остальном он завершен.

person mmocny    schedule 20.10.2009
comment
Spirit X3 повторил упражнение. Он компилируется на порядок быстрее и поддерживает современный C++ (например, семантику перемещения), что также делает среду выполнения более производительной. Однако он отказался от некоторых хороших поддержек, что сделало его еще более ориентированным на небольшие парсеры, IMO. - person sehe; 30.06.2016

Для меня самой большой проблемой является то, что выражения в Spirit, как их видит компилятор или отладчик, довольно длинные (ниже я скопировал часть одного выражения в Spirit Classic). Меня пугают эти выражения. Когда я работаю над программой, которая использует Spirit, я боюсь использовать valgrind или печатать обратную трассировку в gdb.

boost::spirit::classic::parser_result<boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<optional_suffix_parser<char const*>, boost::spirit::classic::ref_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::ref_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::clear_action> >, boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > >, boost::spirit::classic::kleene_star<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::action<boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::alternative<boost::spirit::classic::chlit<char>, boost::spirit::classic::chlit<char> >, boost::spirit::classic::positive<boost::spirit::classic::alternative<boost::spirit::classic::alternative<boost::spirit::classic::alnum_parser, boost::spirit::classic::chlit<char> >, boost::spirit::classic::chlit<char> > > > >, boost::spirit::classic::ref_value_actor<std::vector<std::string, std::allocator<std::string> >, boost::spirit::classic::push_back_action> >, boost::spirit::classic::action<boost::spirit::classic::rule<boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> >, boost::spirit::classic::nil_t, boost::spirit::classic::nil_t>, boost::spirit::classic::ref_const_ref_actor<std::vector<std::string, std::allocator<std::string> >, std::string, boost::spirit::classic::push_back_action> > >, boost::spirit::classic::contiguous<boost::spirit::classic::sequence<boost::spirit::classic::chlit<char>, boost::spirit::classic::action<boost::spirit::classic::uint_parser<unsigned int, 10, 1u, -1>, boost::spirit::classic::ref_value_actor<std::vector<int, std::allocator<int> >, boost::spirit::classic::push_back_action> > > > > > > > >, void ()(char const, char const*)>, boost::spirit::classic::scanner<char const*, boost::spirit::classic::scanner_policies<boost::spirit::classic::skipper_iteration_policy<boost::spirit::classic::iteration_policy>, boost::spirit::classic::match_policy, boost::spirit::classic::action_policy> > >::type boost::spirit::classic::action<boost::spirit::classic::sequence<boost::spirit::classic::action<boost::spirit::classic::action<

person marcin    schedule 04.06.2010

Вот что мне в нем не нравится:

  • документация ограничена. Существует одна большая веб-страница, где объясняется «все», но в текущих объяснениях не хватает деталей.

  • плохая генерация АСТ. AST плохо объяснены, и даже после того, как вы ударились головой о стену, чтобы понять, как работают модификаторы AST, трудно получить простой для манипулирования AST (то есть такой, который хорошо соответствует проблемной области)

  • Это значительно увеличивает время компиляции даже для грамматик "среднего" размера.

  • Синтаксис слишком тяжеловесен. Это факт жизни, что в C/C++ вы должны дублировать код (т.е. между объявлением и определением). Однако кажется, что в boost::spirit, когда вы объявляете грамматику‹>, вы должны повторять некоторые вещи 3 раза :D (когда вам нужны AST, а это то, что я хочу :D)

Кроме этого, я думаю, что они неплохо поработали с парсером, учитывая ограничения C++. Но я думаю, что они должны улучшить его больше. На странице истории описывается, что до нынешнего «статического» духа существовал «динамический» дух; Мне интересно, насколько быстрее и насколько лучше у него был синтаксис.

person user51568    schedule 29.01.2009
comment
Не уверен, но не думаю, что динамичный дух может быть намного лучше нынешнего. Это могло бы быть намного медленнее из-за дополнительных виртуальных вызовов; IIRC, в настоящее время есть виртуальные вызовы только при входе в парсер правил ‹...›, в динамическом духе каждый вызов между составным парсером и одним из его компонентов был бы виртуальным. - person Blaisorblade; 20.12.2009
comment
Я забыл согласиться с вашими замечаниями по документации и генерации AST. Когда я использовал Spirit, некоторые детали не были определены документами, и код, казалось, давал бессвязные и ошибочные результаты по ним, возможно, потому, что разработчики их не указали. - person Blaisorblade; 20.12.2009

Я бы сказал, что самой большой проблемой является отсутствие какой-либо диагностики или другой помощи при проблемах с грамматикой. Если ваша грамматика неоднозначна, синтаксический анализатор может не разобрать то, что вы от него ожидаете, и нет никакого хорошего способа заметить это.

person Chris Dodd    schedule 29.01.2009
comment
Кроме того, у вас может быть экспоненциальный возврат из-за чрезмерного просмотра вперед, и у вас могут возникнуть проблемы с его отладкой. Однажды я быстро собрал грамматику, которая не заканчивала синтаксический анализ (за несколько минут) 1 выражение из ~100 токенов. Однако (я полагаю) это не специфично для Spirit, но применимо ко всем текущим библиотекам комбинаторов синтаксических анализаторов (доступным в большинстве функциональных языков, таких как Haskell или Scala), которые позволяют определять грамматику на вашем языке программирования, а не использовать отдельный инструмент. - person Blaisorblade; 24.03.2011