Почему анализ снизу вверх более распространен, чем анализ сверху вниз?

похоже, что Парсеры рекурсивного спуска не только просты в объяснении, но и просты в проектировании и обслуживании. Они не ограничены грамматиками LALR(1), и сам код может быть понят простыми смертными. Напротив, синтаксические анализаторы снизу вверх имеют ограничения на грамматики, которые они могут распознавать, и должны быть сгенерированы специальными инструментами (потому что таблицы, которые их управляют, практически невозможно сгенерировать вручную).

Почему тогда снизу вверх (т. е. shift-reduce) разбор более распространенный, чем сверху вниз (т. е. рекурсивный спуск) разбор?

6 ответов


Если вы выберете мощный генератор синтаксического анализатора, вы можете закодировать свою грамматику, не беспокоясь о специфических свойствах. (LA)LR означает, что вам не нужно беспокоиться о левой рекурсии, одной головной боли меньше. GLR означает, что вам не нужно беспокоиться о локальной двусмысленности или lookahead.

и Парсеры снизу вверх, как правило, довольно эффективны. Итак, как только вы заплатили цену за немного сложной машины, легче писать грамматики, и Парсеры работают хорошо.

вы следует ожидать увидеть такой выбор, где бы ни была какая-то программная конструкция, которая обычно происходит: если ее легче указать, и она работает довольно хорошо, даже если оборудование сложное, сложное оборудование победит. В качестве другого примера, мир базы данных перешел к реляционным инструментам, несмотря на то, что вы можете вручную создать индексированный файл самостоятельно. Его легче писать схемы данных, его легче указать индексы и с достаточно сложным оборудованием позади (вы не надо смотреть на шестерни, вы просто используете их), они могут быть довольно быстро почти без усилий. Же причинам.


Это связано с несколькими разными вещами.

BNF (и теория грамматик и тому подобное) исходит из вычислительной лингвистики: люди, исследующие разбор естественного языка. BNF-очень привлекательный способ описания грамматики, и поэтому естественно хотеть использовать эти обозначения для создания парсера.

к сожалению, методы разбора сверху вниз, как правило, падают при применении к таким обозначениям, потому что они не могут обрабатывать многие распространенные случаи (например, слева рекурсия.) Это оставляет вас с семейством LR, которое хорошо работает и может обрабатывать грамматики, и поскольку они производятся машиной, кого волнует, как выглядит код?

вы правы, хотя: синтаксические анализаторы сверху вниз работают более "интуитивно", поэтому их легче отлаживать и поддерживать, и как только у вас есть небольшая практика, их так же легко писать, как и те, которые генерируются инструментами. (Особенно, когда вы попадаете в shift/reduce conflict hell.) Многие ответы говорят о разборе производительность, но на практике нисходящие Парсеры часто могут быть оптимизированы так же быстро, как машинные Парсеры.

вот почему многие компиляторы используют рукописные лексеры и Парсеры.


Парсеры рекурсивного спуска пытаются гипотезировать общую структуру входной строки, Что означает, что до конца строки происходит много проб и ошибок. Это делает их менее эффективными, чем Парсеры снизу вверх, которым не нужны такие двигатели вывода.

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


У меня есть две догадки, хотя я сомневаюсь, что они полностью объясняют это:

  1. анализ сверху вниз может быть медленным. Парсеры рекурсивного спуска могут потребовать экспоненциального времени для выполнения своей работы. Это поставило бы серьезные ограничения на масштабируемость компилятора, который использует синтаксический анализатор сверху вниз.

  2. лучшие инструменты. Если вы можете выразить язык в каком-то варианте EBNF, то, скорее всего, вы можете Lex/Yacc свой путь мимо большого количества утомительного кода. Кажется, не так много инструментов, которые помогут автоматизировать задачу создания парсера сверху вниз. И давайте посмотрим правде в глаза, шлифовка кода парсера-это не самая забавная часть игры с языками.


чтобы добавить к другим ответам, важно понимать, что помимо эффективности, Парсеры снизу вверх могут принимать значительно больше грамматик чем Парсеры рекурсивного спуска. Нисходящие синтаксические анализаторы-предсказательные или нет-могут иметь только 1 токен lookahead и терпеть неудачу, если текущий токен и все, что непосредственно следует за токеном, могут быть получены с использованием двух разных правил. Конечно, вы можете реализовать парсер, чтобы иметь больше lookaheads(например, LL (3)), но как далеко вы готовы нажать это до того, как он станет таким же сложным, как парсер снизу вверх? Парсеры снизу вверх (в частности, LALR), с другой стороны, поддерживают список firsts и follows и может обрабатывать случаи, когда Парсеры сверху вниз не могут.

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


Я никогда не видел реального сравнения между парсером сверху вниз и shift-reduce:

только 2 небольшие программы работали в то же время бок о бок, один с использованием подхода сверху вниз и более одного с использованием подхода снизу вверх, каждая из ~200 строк кода,

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

Итак, как честно говорить о том, чего мы никогда не делали : строго сравнивая два подхода ?