Какие преимущества у парсеров LL перед парсерами LR?

Какие преимущества имеют парсеры LL перед парсерами LR, чтобы гарантировать их относительную популярность в современных инструментах генерации парсеров?

Согласно Wikipedia, синтаксический анализ LR имеет преимущества перед LL:

Синтаксический анализ LR может обрабатывать больший диапазон языков, чем анализ LL, а также лучше сообщает об ошибках, то есть обнаруживает синтаксические ошибки, когда входные данные не соответствуют грамматике, как можно скорее. Это отличается от LL (k) (или, что еще хуже, парсера LL (*)), который может отложить обнаружение ошибок на другую ветвь грамматики из-за обратного отслеживания, часто затрудняя локализацию ошибок среди дизъюнкций с длинными общими префиксами. .

Примечание: это не домашнее задание. Я был просто удивлен, когда узнал, что Antlr является генератором парсера LL (несмотря на то, что в его названии есть «LR»!).


person Adam Paynter    schedule 03.11.2010    source источник
comment
Говоря о синтаксических анализаторах (а не о грамматиках): LL (*) может быть написан простым рекурсивным подходом. Это +1 в моей книге.   -  person    schedule 04.11.2010
comment
@pst: Верно, я просто надеялся, что простота реализации не является основным преимуществом. :)   -  person Adam Paynter    schedule 04.11.2010
comment
Обратите внимание, что LR в ANTLR просто означает распознавание языка, а не что-либо о классе грамматики, который он принимает.   -  person Jerry Coffin    schedule 04.11.2010
comment
На самом деле, в понимании Терренса Парра, это означает Anti-LR. По крайней мере, я помню интервью с ним, где он признал, что этот оттенок не случаен. Он сказал, что создал ANTLR специально, потому что чувствовал, что почти полная сосредоточенность на синтаксическом анализе LR была большой ошибкой, и ему надоело говорить всем, что LR отстой и никто не слушает, поэтому он решил создать лучший в мире генератор парсеров, сокрушить всех остальные и оставить только LL ... или что-то в этом роде.   -  person Jörg W Mittag    schedule 04.11.2010
comment
@ Йорг: Правда? Вау, это определенно амбициозно! Похоже, Терренсу будет что добавить к этому вопросу! Возможно, мне стоит написать ему электронное письмо с просьбой внести свой вклад ...   -  person Adam Paynter    schedule 04.11.2010
comment
@ Jörg: Я только что написал ему по электронной почте, приглашая принять участие в этом обсуждении. Он, наверное, занят, но, может быть, он все равно присоединится!   -  person Adam Paynter    schedule 04.11.2010


Ответы (6)


GLR отлично подходит, если вы хотите дерево / лес синтаксического анализа и не возражаете против черных ящиков. Он позволяет вам вводить любой CFG, который вы хотите, на стоимость проверки на неоднозначность во время синтаксического анализа посредством исчерпывающего тестирования вместо статического разрешения конфликтов LR / LALR. Некоторые говорят, что это хороший компромисс. Инструмент Иры Бакстера DMS или Elkhound, который имеет бесплатную грамматику C ++, полезен для этого класса задач. ANTLR также полезен для большого класса языковых приложений, но использует нисходящий подход, генерируя синтаксические анализаторы с рекурсивным спуском. называется LL (*), что позволяет использовать семантические предикаты. Здесь я без доказательства заявлю, что предикаты позволяют анализировать контекстно-зависимые языки помимо CFG. Программистам нравится вставлять действия в грамматики, например, хорошо обрабатывать ошибки и выполнять пошаговую отладку. LL хорош по всем трем. LL - это то, что мы делаем вручную, поэтому его легче понять. Не верьте чепухе из Википедии о том, что LR лучше справляется с ошибками. Тем не менее, если вы много отказываетесь от ANTLR, ошибки действительно хуже с LL (*) (у PEG есть эта проблема).

Повторный возврат. GLR также спекулирует (т.е. возвращается), как и PEG, ANTLR и любые другие недетерминированные стратегии. В любом недетерминированном состоянии LR GLR «разветвляет» суб-парсеры, чтобы опробовать любой жизнеспособный путь. В любом случае, у LL есть хороший контекст для обработки ошибок. Если LR знает, что оно соответствует выражению, LL знает, что это выражение в присваивании или IF-условном; LR знает, что может быть в любом из них, но не уверен - и в этой неопределенности он черпает свою силу.

GLR - это O(n^3) худший случай. packrat / PEG - это O(n) худший случай. ANTLR O(n^2) из-за циклического упреждающего DFA, но O(n) на практике. На самом деле это не имеет значения. GLR достаточно быстр.

ANTLR - это AN другой инструмент для распознавания L и R, а не анти-LR. , но он мне тоже нравится;)

Честно говоря, как и многие молодые программисты 80-х, я не понимал LALR и не любил черные ящики (теперь я копаю красоту движка GLR, но все же предпочитаю LL). Я построил коммерческий компилятор на основе LL (k) и решил создать инструмент для генерации того, что я построил вручную. ANTLR не для всех, и такие крайние случаи, как C ++, могут быть лучше обработаны с помощью GLR, но многие люди считают, что ANTLR подходит для их зоны комфорта. С января 2008 года было 134 000 загрузок двоичного файла jar ANTLR в рамках ANTLRWorks, а общее количество исходных zip-архивов (по данным Google Analytics). См. нашу статью по LL (*) с большим количеством эмпирических данных.

person Terence Parr    schedule 04.11.2010
comment
Я определенно могу оценить возможность отладки построчно! Я также могу оценить идею контекста (то есть знать, что анализируемое выражение содержится внутри оператора if). Спасибо за ответ, он, безусловно, демонстрирует некоторые сильные стороны парсеров LL! - person Adam Paynter; 05.11.2010
comment
@ Теренс: что особенного в черном ящике? Все генераторы парсеров и механизмы поддержки в значительной степени являются загадкой для пользователей, и это правильно; большинство пользователей не хотят знать теорию или механизмы. Я покупаю ваше отсутствующее доказательство того, что ANTLR не ограничивается CFG; но это верно для любого движка, управляемого грамматикой, который также допускает семантические предикаты. С практической точки зрения, все они (по крайней мере, все те, которые я встречал или построил :), включая DMS. Одношаговое выполнение - это вопрос инструментария, а не технологии генератора синтаксического анализатора. Качество исправления ошибок имеет то же свойство. - person Ira Baxter; 06.11.2010
comment
Все: Я согласен с тем, что ANTLR и большинство генераторов парсеров на самом деле хороши для создания парсеров для скромных грамматик. Различие начинает проявляться, когда грамматика становится жесткой. Если вы контролируете грамматику и можете изменить ее, чтобы избавиться от сложных случаев, то подойдет любой генератор синтаксического анализатора. Если нет, то действительно имеет значение мощность генератора синтаксического анализатора. В любом случае техническая поддержка инструмента действительно помогает. Несмотря на мою предвзятость к GLR (на практике они тоже O (n)!), Я первым признаю, что Теренс проделал довольно приличную работу по обеспечению эффективности ANTLR. - person Ira Baxter; 06.11.2010
comment
@Ira: Я полностью согласен с вашим мнением. Я просто хочу сказать, что причина, по которой я принял ответ Теренса, заключалась в том, что я думал, что он лучше всего отвечает на исходный вопрос (какие преимущества у парсеров LL перед парсерами LR?). Я также согласен с вами (и Теренсом) в том, что GLR выглядит фантастически! Я также согласен с тем, что он отлично поработал с ANTLR. :) - person Adam Paynter; 06.11.2010
comment
@Ira: Я просто имел в виду, что GLR - это черный ящик, потому что он работает, но непрозрачен. Другая крайность - это рекурсивный анализатор спуска (генерируемый ANTLR), который не является черным ящиком, потому что это то, что программист построил бы вручную и может выполнять пошаговую отладку. На самом деле это не совсем так. LL (*) позволяет циклическому DFA сканировать вперед, и я генерирую конечные автоматы (черные ящики) для этих решений, но это только для альтернативного прогнозирования производства, а не для синтаксического анализа. - person Terence Parr; 10.11.2010
comment
re: обработка ошибок. представьте себе несогласованное состояние LR, в котором вы должны предположить несколько возможных путей, которые все приводят к недопустимому синтаксическому анализу. У вас есть ошибка, но вы не знаете, по какому пути получить сообщение об ошибке. У вас также неоднозначный контекст. Используете ли вы выражение для индекса массива, скажем, или выражение в операторе присваивания? Трудно понять, как вылечиться. Я не уверен, что понимаю, что обработка ошибок может зависеть только от инструмента. Инструменты на основе LR в этом отношении кажутся немного затруднительными по сравнению с инструментами на основе LL. - person Terence Parr; 10.11.2010
comment
Обычный трюк состоит в том, чтобы попытаться построить дерево из токенов, следующих за точкой ошибки, а затем найти одну вставку / удаление токена, которая позволит синтаксическому анализатору преодолеть разрыв. (Мы просто используем следующий токен, потому что мы не очень активно продвигали исправление ошибок). Это очень хорошо работает даже для несогласованного состояния. Большинство состояний не противоречат друг другу, поэтому есть только одно разумное продолжение. Почему у парсера LL такая же проблема, если есть несколько возможных следующих синтаксических анализов? Двусмысленность локального языка не исчезнет только потому, что вы поменяли технологию синтаксического анализа. - person Ira Baxter; 10.11.2010
comment
Что ж, LL довольно легко выполняет вставку и удаление отдельных токенов; Я уверен, что концепция аналогична LR, по крайней мере, в середине производства. Основная проблема заключается в том, что вам нужно выполнить восстановление в зависимости от того, какое правило активировало текущее правило (например, что находится в наборе FOLLOW?). В LL вы точно знаете, какой из них (конечно, за счет более слабой стратегии синтаксического анализа). LR может иметь несколько контекстов. Вы не знаете, выполнять ли повторную синхронизацию, используя до] или; например, при попытке очистить искаженное выражение. Если вас вызывают из индекса массива, который вы хотите использовать, до] и так далее. - person Terence Parr; 10.11.2010
comment
С GLR это относительно просто. Для всех оперативных синтаксических анализов в точке, где вы обнаруживаете синтаксическую ошибку, вы предлагаете вставку любого токена, сдвиг которого при любом синтаксическом анализе приводит к состоянию, в котором следующий токен является допустимым, и вы предлагаете удалить текущий токен. Он предлагает 10-20 лекарств, большинство из которых умирают обычным способом GLR. Наш парсер, кажется, отлично восстанавливает недостающие / лишние токены. Когда он утерян, он ужасно утерян, но обычно через некоторое время восстанавливается. Раньше я создавал метакомпиляторы (синтезировал парсеры рекурсивного спуска). В значительной степени, когда они заблудились, они никогда не выздоровели. - person Ira Baxter; 10.11.2010
comment
Обновление. Предстоящая статья OOPSLA '14 по Adaptive LL (), ALL (), которая принимает любую грамматику за одним исключением: отсутствие косвенной левой рекурсии. Обрабатывает e : e '*' e | INT ; файл правил antlr.org/papers/allstar-techreport.pdf ВСЕ (*) мое последнее слово по синтаксическому анализу. 25 лет, и я наконец его расколол. Вынул спецификацию C11 из коробки с левой рекурсией, хотя и медленным линейным темпом для синтаксического анализа без настройки грамматики. Анализаторы грамматики Java 12 920 файлов, 3,6 млн строк, размер библиотеки Java 123 МБ за ‹6 секунд. См. Разборку инструмента на бумаге. Требуется либо шкала журнала, либо отдельный график для инструментов GLR. - person Terence Parr; 08.10.2014

Если вам нужно передать код один, рекурсивный спуск (LL) - это то, что вы можете сделать реалистично; люди не могут вручную собрать L (AL) R парсеры.

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

Фактически, я предпочитаю синтаксические анализаторы GLR, которые в значительной степени анализируют что угодно с помощью контекстно-свободной грамматики. Никаких проблем с левой рекурсией. Не сдвигайте / не уменьшайте беспокойство о конфликте. Нет пределов просмотра вперед.

Если вы хотите увидеть диапазон языков, которые может обрабатывать один механизм синтаксического анализа GLR (включая известный язык C ++, с помощью которого трудно анализировать использование LL / LALR), вы можете посмотреть здесь.

person Ira Baxter    schedule 03.11.2010
comment
вам не нужно бороться с грамматиками только потому, что вы можете определять предшественники напрямую с помощью определенных команд внутри определения парсера, а не потому, что подход LR предъявляет меньше требований к самой грамматике. - person Jack; 04.11.2010
comment
@Ira: Очень интересный пост! Раньше я даже не слышал о парсерах GLR. - person Adam Paynter; 04.11.2010
comment
@Jack: Я согласен с вашей точкой зрения о том, что директивы приоритета не являются преимуществом, специфичным для LR. Однако согласны ли вы с точкой зрения Иры об исключении левой рекурсии? - person Adam Paynter; 04.11.2010
comment
Да, я согласен, поскольку парсер LL этого не допускает. Но левая рекурсия может быть решена очень просто, в то время как некоторые конфликты сокращения-уменьшения или сдвига-уменьшения требуют много размышлений и рефакторинга самой грамматики (что становится трудным, когда грамматика растет). - person Jack; 04.11.2010
comment
@ Джек: Достаточно честно. Поправьте меня, если я ошибаюсь, но разве конфликты сдвига / уменьшения и уменьшения / уменьшения эффективно не исчезают, если синтаксический анализатор LR допускает произвольное количество символов предварительного просмотра (то есть синтаксический анализатор LR (k))? Конечно, большинство генераторов парсеров LR ограничиваются одним опережающим символом, поэтому у меня нет большого опыта в этом направлении. - person Adam Paynter; 04.11.2010
comment
На самом деле LALR существует только потому, что упреждающий просмотр в LR-парсерах стоит очень дорого. Подумайте о том факте, что каждый прогноз увеличивает сложность IIRC на порядок. Поэтому на практике вы не будете использовать парсер LR (3). - person Jack; 04.11.2010
comment
LALR существует потому, что для многих практических грамматик вы получаете таблицы меньшего размера, чем LR. Вы, конечно, можете определить концепцию грамматик LALR (3), хотя на практике этого никто не делает. Причина GLR в том, что вы можете перестать думать о К. - person Ira Baxter; 04.11.2010
comment
@ Джек: В общем, это правда. Однако я удивлен, что больше генераторов парсеров LR не поддерживают LR (k), рассматривая решения к экспоненциальным требованиям к пространству, по-видимому, доступны с 1991 года. - person Adam Paynter; 04.11.2010
comment
@ Адам: Мы все кое-что узнали сегодня. Наш синтаксический анализатор GLR использует, по существу, генератор синтаксического анализатора LALR (1) в качестве основы, а наборы предпросмотра с 1 единицей фактически помогают избежать разбиения синтаксического анализа GLR на практике, снижая его накладные расходы. (Они немного медленнее, чем LALR, потому что есть дополнительное бухгалтерия [от которого вы можете избавиться, если очень постараетесь]. Документ LALR (k) может позволить нам иногда заглядывать вперед немного дальше и избегать разделений; в мои размышления - эта корзина. Спасибо за указатель. - person Ira Baxter; 04.11.2010
comment
@Ira: Очень хороший момент. Есть ли в свободном доступе документация по синтаксическим анализаторам GLR, которую я мог бы прочитать? - person Adam Paynter; 04.11.2010
comment
@Adam: Ссылки на сайтах Википедии обязательно к прочтению, но их трудно найти бесплатно; У меня есть бумажные копии, приобретенные много лет назад. Адриан Джонстон, похоже, много работает над расширенным синтаксическим анализом GLR, например: portal. acm.org/citation.cfm?id=1149674. Это бесплатно, если вы являетесь членом ACM. Его веб-сайт cs.rhul.ac.uk/research/languages/ публикации / скорее всего, имеет документы в свободном доступе. - person Ira Baxter; 04.11.2010
comment
@Ira: Спасибо за подсказку! Я также рад, что ссылка может быть вам полезна! Я бы предположил, что он был бы более известен в сообществе компиляторов почти через 20 лет (я заметил это только потому, что фонд Eclipse использует его в их парсер Java). - person Adam Paynter; 04.11.2010
comment
@Ira: Вы можете разместить свои источники в вопросе ресурсов алгоритма синтаксического анализа GLR. - person Adam Paynter; 04.11.2010
comment
Я действительно надеюсь, что это не покажется враждебным - это честный вопрос - когда левая рекурсия полезна / необходима на практике? Я не хочу сказать, что это бесполезно / необходимо, просто я никогда не видел использования левой рекурсии, которую нельзя было бы заменить квантификатором * или +. Я уверен, что есть допустимые варианты использования, но я не знаком ни с одним из них. - person Matt Fenwick; 12.11.2013
comment
* или + не являются стандартными правилами BNF. Они являются стандартными во многих расширенных правилах BNF. Если в вашем генераторе парсеров их нет, вам нужна левая или правая рекурсия. Если они у вас были, они соответствуют левой или правой рекурсии. Если вы генерируете синтаксический анализатор из грамматики, часто EBNF существенно сокращается до BNF (конечно, для синтаксических анализаторов LR-класса), и вам нужна левая рекурсия, потому что это делает синтаксический анализатор более эффективным; с правой рекурсией, для таких парсеров у вас должен быть стек, равный длине списка. ... - person Ira Baxter; 13.11.2013
comment
Синтаксические анализаторы, реализованные сверху вниз, могут преобразовывать операторы клини из логически правильной рекурсии в операции цикла. Но люди все еще могут писать правила, которые включают левую рекурсию сложным образом; У меня нет примера, но я намного счастливее, зная, что мне просто не нужно беспокоиться о том, как я пишу свои правила грамматики. Если вы посмотрите на жалобы людей на нисходящие синтаксические анализаторы, даже на те, которые имеют обозначение звездочки клини, вы почти всегда обнаружите, что они пытаются найти способ избавиться от неудобной левой рекурсии. Зачем вообще беспокоиться? - person Ira Baxter; 13.11.2013

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

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

person Jack    schedule 03.11.2010
comment
Я так понимаю ... Вы говорите, что наиболее практическая разница в том, что парсеры LL избегают конфликтов, которые обычно встречаются в парсерах LR. Будет ли это применяться только к синтаксическим анализаторам LR, которые ограничивают свой просмотр небольшим числом (например, LR (1) или LALR (1))? Я думал, что у парсеров LR (k) не так много конфликтов ... - person Adam Paynter; 04.11.2010

Единственное преимущество, с которым я когда-либо был знаком, - это то, что вы можете легко кодировать парсеры LL вручную. Парсеры LR НАМНОГО сложнее кодировать вручную (обычно вы используете генератор парсеров).

person Alex    schedule 04.11.2010
comment
А когда у вас есть такой генератор, создать его действительно легко. - person Ira Baxter; 13.11.2013

Сложность наихудшего случая анализа LL составляет O (n ^ 4), тогда как сложность наихудшего случая анализа LR лучше, O (n ^ 3).

(Но никто никогда не напишет грамматику O (n ^ 4).)

https://en.wikipedia.org/wiki/Top-down_parsing

person john ktejik    schedule 14.02.2018

Одна из причин, которые приходят на ум, заключается в том, что гораздо проще создать язык, для которого нужен произвольный возврат (cough C ++) в парадигме LL.

person zwol    schedule 03.11.2010
comment
Кашель C ++ НЕ требует произвольного возврата. Парсер GLR прекрасно справляется с этим. Смотрите мой ответ. - person Ira Baxter; 04.11.2010
comment
Я имею в виду, что C ++ не является LL (k) или LR (k) для любого конечного k из-за неоднозначности объявления / выражения. - person zwol; 04.11.2010
comment
Что ж, синтаксический анализ C ++ в чистом смысле (а не взлом GCC-resolves-types-during-parsing) требует, чтобы синтаксический анализатор также улавливал неоднозначные синтаксические анализы. Разборы LL / LR этого просто не делают. Парсеры GLR делают. Вы разрешите неоднозначность позже с помощью информации таблицы символов, что позволит вам отделить синтаксический анализ от разрешения имени и типа, что дает вам гораздо более чистые синтаксические анализаторы. - person Ira Baxter; 04.11.2010
comment
@Zack и @Ira: Какой интересный разговор! - person Adam Paynter; 04.11.2010
comment
Я не очень разбираюсь в теории, но я работал как над GCC, так и над интерфейсом EDG для C ++, и у меня сложилось впечатление, что было непрактично избегать того, что вы описываете как типы разрешений во время взлома синтаксического анализа, точка . Конечно, оба эти являются кодируемыми вручную парсерами рекурсивного спуска с возвратом, так что, возможно, это просто следствие техники реализации. Кто-нибудь написал полный парсер GLR для C ++? - person zwol; 04.11.2010
comment
@Zack: Прочтите мой ответ. Посмотрите ссылку. ДА. Мы полностью избегаем этого взлома. Мы используем его для модификации крупномасштабных систем C ++. - person Ira Baxter; 04.11.2010