Вопрос

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

Это было полезно?

Решение

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

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

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

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

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

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

Другие советы

В бусте 1.41 выпускается новая версия Spirit, которая выбивает штаны из духа :: classic:

  

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

     
    
      

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

    
  

Для меня самая большая проблема заключается в том, что выражения в Spirit, видимые компилятором или отладчиком, довольно длинные (я скопировал ниже часть одного выражения в духе Классики).Эти выражения пугают меня.Когда я работаю над программой, использующей 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 ()(символ 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<

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top