В нескольких вопросах я видел рекомендации для Spirit рамки анализатора-генератора из boost.org, но затем в комментариях ворчит от людей, использующих Духа, которые недовольны. Будут ли эти люди проситься вперед и объяснить остальным из нас, каковы недостатки или недостатки использования Духа?
Каковы недостатки структуры синтаксического анализатора Spirit от boost.org?
Ответ 1
Это довольно крутая идея, и мне это понравилось; особенно полезно было научиться использовать шаблоны С++.
Но в их документации рекомендуется использовать дух для парсеров малого и среднего размера. Парсер для полного языка потребует времени для компиляции. Я приведу три причины.
-
Анализ без сканера. Хотя это довольно просто, когда требуется обратное отслеживание, это может замедлить парсер. Это необязательно - лексер может быть интегрирован, см. Препроцессор C, построенный с помощью Spirit. Грамматика ~ 300 строк (включая файлы .h и .cpp) компилирует (неоптимизируется) в файл 6M с GCC. Инлайн и максимальная оптимизация достигают до 1,7М.
-
Медленный синтаксический анализ - нет никакой статической проверки грамматики, ни намека на чрезмерный просмотр, ни на проверку основных ошибок, таких как, например, использование левой рекурсии (что приводит к бесконечной рекурсии в рекурсивном спускании парсеры LL грамматики). Левая рекурсия не очень сложная ошибка для отслеживания, однако, но чрезмерный просмотр может привести к экспоненциальному времени разбора.
-
Использование тяжелых шаблонов - хотя это имеет определенные преимущества, это влияет на время компиляции и размер кода. Кроме того, определение грамматики обычно должно быть видимым для всех других пользователей, что влияет на еще большее время компиляции. Я смог переместить грамматики в файлы .cpp, добавив явные шаблонные экземпляры с правильными параметрами, но это было непросто.
UPDATE: мой ответ ограничен моим опытом с Spirit classic, а не с Spirit V2. Я бы все же ожидал, что Spirit будет сильно основан на шаблонах, но теперь я просто догадываюсь.
Ответ 2
В boost 1.41 выпущена новая версия Spirit, и это удары брюк от духа:: classic:
После долгого времени в бета-версии (более 2 лет с Spirit 2.0), Spirit 2.1 наконец, будет выпущена с предстоящий выпуск Boost 1.41. Код сейчас очень стабильна и готова к производственный код. Мы много работаем своевременно завершить документацию для Boost 1.41. Вы можете заглянуть в текущее состояние документации Вот. В настоящее время вы можете найти код и документация в Boost SVN хобот. Если у вас есть новый проект с участием Духа, мы настоятельно рекомендуем начиная с Spirit 2.1. Позволь мне процитировать сообщение OvermindDL из Список рассылки Spirit:
Я могу начать звучать как бот с как часто я это говорю, но Spirit.Classic древний, вы должны переключитесь на Spirit2.1, он может сделать все, что вы сделали над БОЛЬШОЙ сделкой проще, намного меньше кода, и это выполняется быстрее. Например, Spirit2.1 может построить ваш весь АСТ встроенный, без каких-либо странных переопределений, нет необходимости строить вещи потом и т.д., все как один хороший и быстрый шаг. Вы действительно нужно обновить. См. Другой сообщения за последний день для ссылок на документы и т.д. для Spirit2.1. Spirit2.1 в настоящее время находится в Boost Trunk, но будет быть официально выпущен с Boost 1.41, но в остальном завершен.
Ответ 3
Для меня самая большая проблема заключается в том, что выражения в Spirit, как видно из компилятора или отладчика, довольно длинны (я копировал под частью одного выражения в Spirit Classic). Эти выражения меня пугают. Когда я работаю над программой, использующей Spirit, я боюсь использовать valgrind или печатать backtrace в 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<
Ответ 4
Вот что мне не нравится в этом:
-
документация ограничена. Существует одна большая веб-страница, где объясняется "все", но текущие объяснения отсутствуют в деталях.
-
бедная генерация АСТ. АСТ плохо объяснены и даже после удара головой о стену, чтобы понять, как работают модификаторы АСТ, трудно получить легкое управление АСТ (т.е. Хорошо отображаемое в проблемной области)
-
Это увеличивает время компиляции чрезвычайно, даже для "средних" -размерных грамматик
-
Синтаксис слишком тяжелый. Это факт жизни, что в C/С++ вы должны дублировать код (т.е. Между объявлением и определением). Однако, кажется, что в boost:: spirit, когда вы объявляете грамматику < > , вы должны повторять некоторые вещи 3 раза: D (когда вы хотите получить АСТ, чего я хочу: D)
Кроме этого, я думаю, что они отлично справились с парсером, учитывая ограничения С++. Но я думаю, что они должны улучшить его больше. Страница истории описывает, что перед текущим "статическим" духом существовал "динамический" дух; Мне интересно, насколько быстрее и насколько лучше синтаксис у него был.
Ответ 5
Я бы сказал, что самая большая проблема заключается в отсутствии какого-либо диагноза или другой помощи для проблем грамматики. Если ваша грамматика неоднозначна, синтаксический анализатор может не анализировать то, что вы ожидаете, и нет хорошего способа заметить это.