В чем разница между парсерами LR, SLR и LALR? - PullRequest
99 голосов
/ 20 апреля 2010

Какая разница между парсерами LR, SLR и LALR? Я знаю, что SLR и LALR являются типами парсеров LR, но какова реальная разница с точки зрения их таблиц синтаксического анализа?

А как показать, является ли грамматика LR, SLR или LALR? Для грамматики LL мы просто должны показать, что ни одна ячейка таблицы синтаксического анализа не должна содержать несколько правил производства. Есть ли похожие правила для LALR, SLR и LR?

Например, как мы можем показать, что грамматика

S --> Aa | bAc | dc | bda
A --> d

это LALR (1), но не SLR (1)?


РЕДАКТИРОВАТЬ (ибунгалобилл) : Я не получил удовлетворительного ответа на вопрос, в чем разница между LALR и LR. Таким образом, таблицы LALR меньше по размеру, но могут распознавать только подмножество грамматик LR. Может кто-нибудь подробнее рассказать о разнице между LALR и LR, пожалуйста? LALR (1) и LR (1) будет достаточно для ответа. Оба они используют 1 токен, и оба управляются за столом! Чем они отличаются?

Ответы [ 8 ]

57 голосов
/ 22 октября 2010
Парсеры

SLR, LALR и LR могут быть реализованы с использованием одного и того же механизма, управляемого таблицами.

По сути, алгоритм синтаксического анализа собирает следующий входной токен T и обращается к текущему состоянию S (и соответствующим таблицам предпросмотра, GOTO и сокращения), чтобы решить, что делать:

  • SHIFT: если текущая таблица говорит SHIFT на токене T, пара (S, T) помещается в стек разбора, состояние изменяется в соответствии с тем, что таблица GOTO говорит для текущего токена (например, GOTO (T)), другой входной токен T 'выбирается, и процесс повторяется
  • УМЕНЬШЕНИЕ: В каждом штате есть 0, 1 или много возможных сокращений, которые могут произойти в этом состоянии. Если синтаксическим анализатором является LR или LALR, токен проверяется на основе наборов предварительного просмотра для всех допустимых сокращений для состояния. Если токен совпадает с набором преднамеренного сокращения для правила грамматики G = R1 R2 .. Rn, происходит уменьшение стека и сдвиг: вызывается семантическое действие для G, стек выталкивается n (из Rn) раз, пара ( S, G) помещается в стек, новое состояние S 'устанавливается в GOTO (G), и цикл повторяется с тем же маркером T. Если синтаксический анализатор является синтаксическим анализатором SLR, существует не более одного правила сокращения для состояние и поэтому действие сокращения может быть выполнено вслепую без поиска, чтобы увидеть, какое сокращение применяется. Для парсера SLR полезно знать, есть ли сокращение или нет; легко сказать, записывает ли каждое состояние количество сокращений, связанных с ним, и этот счет необходим для практических версий L (AL) R в любом случае.
  • ОШИБКА: если ни SHIFT, ни REDUCE невозможны, объявляется синтаксическая ошибка.

Итак, если они все используют один и тот же механизм, какой смысл?

Предполагаемое значение в SLR - это его простота в реализации; вам не нужно сканировать возможные сокращения, проверяя наборы предварительного просмотра, потому что их самое большее, и это единственное жизнеспособное действие, если нет состояний SHIFT, выходящих из состояния. То, какое сокращение применяется, может быть привязано конкретно к государству, так что механизм синтаксического анализа SLR не должен охотиться за ним. На практике парсеры L (AL) R обрабатывают полезно больший набор языков, и для их реализации так мало дополнительной работы, что никто не реализует SLR, кроме как для академического упражнения.

Разница между LALR и LR связана с таблицей генератора . Генераторы синтаксического анализатора LR отслеживают все возможные сокращения от определенных состояний и их точный предварительный набор; в итоге вы получите состояния, в которых каждое сокращение связано с его точным прогнозным набором из левого контекста. Это имеет тенденцию создавать довольно большие наборы состояний. Генераторы синтаксических анализаторов LALR готовы объединять состояния, если таблицы GOTO и наборы элементов поиска для сокращений совместимы и не конфликтуют; это приводит к значительно меньшему количеству состояний за счет невозможности различить определенные последовательности символов, которые может различать LR. Таким образом, парсеры LR могут анализировать больший набор языков, чем парсеры LALR, но имеют намного большие таблицы парсеров. На практике можно найти грамматики LALR, которые достаточно близки к целевым языкам, так что размер конечного автомата стоит оптимизировать; места, где парсер LR был бы лучше, обрабатываются специальной проверкой вне парсера.

Итак: все трое используют один и тот же механизм. SLR «легок» в том смысле, что вы можете проигнорировать чуть-чуть машины, но это не стоит хлопот. LR анализирует более широкий набор языков, но таблицы состояний имеют тенденцию быть довольно большими. Это оставляет LALR в качестве практического выбора.

Сказав все это, стоит знать, что GLR-парсеры могут анализировать любой контекстно-свободный язык, используя более сложную технику , но точно такие же таблицы (включая уменьшенную версию, используемую LALR). Это означает, что GLR строго более мощный, чем LR, LALR и SLR; в значительной степени, если вы можете написать стандартную грамматику BNF, GLR будет анализировать в соответствии с ней. Разница в механизме заключается в том, что GLR желает попробовать несколько разборов, когда есть конфликты между таблицей GOTO и / или наборами предвкушения. (То, как GLR делает это эффективно, является чистым гением [не моим], но не вписывается в этот пост SO).

Это для меня чрезвычайно полезный факт. Я строю анализаторы программ, и преобразователи кода и анализаторы необходимы, но "неинтересны"; интересная работа - это то, что вы делаете с проанализированным результатом, поэтому основное внимание уделяется выполнению работы после разбора. Использование GLR означает, что я могу относительно легко создавать рабочие грамматики по сравнению со взломом грамматики, чтобы получить LALR-форму. Это очень важно, когда вы пытаетесь работать с неакадемическими языками, такими как C ++ или Fortran, где вам буквально нужны тысячи правил для правильной работы со всем языком, и вы не хотите тратить свою жизнь на попытки взломать грамматические правила, чтобы соответствовать ограничениям LALR (или даже LR).

В качестве своего рода известного примера, C ++ считается чрезвычайно сложным для анализа ... парнями, занимающимися анализом LALR. C ++ легко анализировать, используя механизм GLR, используя в значительной степени правила, приведенные в конце справочного руководства по C ++. (У меня есть именно такой синтаксический анализатор, и он обрабатывает не только ванильный C ++, но и различные диалекты вендоров. Это возможно только на практике, потому что мы используем анализатор GLR, ИМХО).

[РЕДАКТИРОВАТЬ Ноябрь 2011: Мы расширили наш синтаксический анализатор для обработки всего C ++ 11. GLR сделал это намного проще. РЕДАКТИРОВАТЬ Авг 2014: Теперь обрабатывает все C ++ 17. Ничего не сломалось и не стало хуже, GLR по-прежнему кошачий мяукан.]

18 голосов
/ 23 октября 2010

Синтаксические анализаторы LALR объединяют похожие состояния в грамматике LR для создания таблиц состояний синтаксического анализатора, которые точно такого же размера, что и эквивалентная грамматика SLR, которые обычно на порядок меньше, чем таблицы анализа чистого LR. Однако для грамматик LR, которые слишком сложны, чтобы быть LALR, эти объединенные состояния приводят к конфликтам синтаксического анализатора или создают синтаксический анализатор, который не полностью распознает исходную грамматику LR.

Кстати, я упоминаю несколько вещей об этом в моем алгоритме таблицы разбора MLR (k) здесь .

Добавление

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

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

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

Основное отличие состоит в том, что алгоритм для создания таблиц LR содержит больше информации между переходами из состояния в состояние, а алгоритм LALR - нет. Таким образом, алгоритм LALR не может определить, действительно ли данное объединенное состояние следует оставить как два или более отдельных состояния.

12 голосов
/ 16 мая 2013

Еще один ответ (ЯА).

Алгоритмы разбора для SLR (1), LALR (1) и LR (1) идентичны, как сказала Ира Бакстер,
однако таблицы синтаксического анализатора могут отличаться из-за алгоритма генерации синтаксического анализатора.

Генератор синтаксического анализатора SLR создает конечный автомат LR (0) и вычисляет прогнозные значения из грамматики (наборы FIRST и FOLLOW). Это упрощенный подход и может сообщать о конфликтах, которые на самом деле не существуют в конечном автомате LR (0).

Генератор синтаксического анализатора LALR создает конечный автомат LR (0) и вычисляет прогнозные значения из конечного автомата LR (0) (через терминальные переходы). Это правильный подход, но иногда он сообщает о конфликтах, которых не было бы в конечном автомате LR (1).

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

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

LRSTAR 10.0 может генерировать синтаксические анализаторы LALR (1), LR (1), CLR (1) или LR (*) в C ++ - все, что необходимо для вашей грамматики. См. эту диаграмму , которая показывает разницу между анализаторами LR.

[Полное раскрытие: LRSTAR - мой продукт]

5 голосов
/ 16 сентября 2015

Предположим, что анализатор без предвкушения успешно разбирает строки для вашей грамматики.

Используя ваш пример, он наталкивается на строку dc, что он делает? Уменьшает ли это значение до S, потому что dc является допустимой строкой, созданной этой грамматикой? ИЛИ, может быть, мы пытались разобрать bdc, потому что даже это приемлемая строка?

Поскольку люди, которых мы знаем, ответ прост, мы просто должны помнить, только что мы только что проанализировали b или нет. Но компьютеры тупые:)

Так как синтаксический анализатор SLR (1) имел дополнительную мощность над LR (0) для выполнения предварительного просмотра, мы знаем, что любое количество предварительных просмотров не может сказать нам, что делать в этом случае; вместо этого нам нужно оглянуться назад в наше прошлое. Таким образом, на помощь приходит канонический парсер LR. Он помнит прошлый контекст.

Способ, которым он запоминает этот контекст, заключается в том, что он дисциплинирует себя, что всякий раз, когда он встречает b, он начинает идти по пути к чтению bdc, как одна из возможностей. Поэтому, когда он видит d, он знает, идет ли он уже по пути. Таким образом, парсер CLR (1) может делать то, чего не может парсер SLR (1)!

Но теперь, поскольку нам пришлось определить так много путей, состояния машины становятся очень большими!

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

Это ваш анализатор LALR (1).


Теперь, как это сделать алгоритмически.

Когда вы рисуете наборы настроек для вышеуказанного языка, вы увидите конфликт сдвига-уменьшения в двух состояниях. Чтобы удалить их, вы можете рассмотреть SLR (1), который принимает решения с учетом последующего, но вы заметите, что он все равно не сможет. Таким образом, вы должны нарисовать наборы конфигурации снова, но на этот раз с ограничением, что всякий раз, когда вы вычисляете замыкание, добавляемые дополнительные производства должны иметь строгие правила. См. Любой учебник о том, что они должны быть.

4 голосов
/ 05 июня 2014

Парсер SLR распознает правильное подмножество грамматик, распознаваемых парсерами LALR (1), которые, в свою очередь, распознают правильное подмножество грамматик, распознаваемых парсерами LR (1).

Каждый из них построен как конечный автомат, причем каждое состояние представляет некоторый набор правил производства грамматики (и позиции в каждом) при синтаксическом анализе ввода.

Книга Дракона Пример грамматики LALR (1), которая не является SLR, таков:

S → L = R | R
L → * R | id
R → L

Вот одно из состояний этой грамматики:

S → L•= R
R → L•

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

Здесь анализатор может либо сдвинуть =, либо уменьшить R → L.

Синтаксический анализатор SLR (он же LR (0)) определит, может ли он уменьшиться, проверив, находится ли следующий входной символ в наборе следующего набора из R (т. Е. В наборе всех терминалов в грамматика, которая может следовать R). Поскольку = также находится в этом наборе, синтаксический анализатор SLR сталкивается с конфликтом уменьшения смещения.

Однако парсер LALR (1) будет использовать набор всех терминалов, которые могут следовать за этим конкретным производством от R, что составляет только $ (т. Е. Конец ввода). Таким образом, нет конфликта.

Как отмечали предыдущие комментаторы, парсеры LALR (1) имеют то же количество состояний, что и парсеры SLR. Алгоритм распространения в обратном направлении используется для привязки данных к производствам состояний SLR из соответствующих состояний LR (1). Результирующий анализатор LALR (1) может вводить конфликты уменьшения-уменьшения, отсутствующие в синтаксическом анализаторе LR (1), но он не может вводить конфликты уменьшения-уменьшения.

В вашем примере следующее состояние LALR (1) вызывает конфликт уменьшения сдвига в реализации SLR:

S → b d•a / $
A → d• / c

Символ после / является следующим набором для каждого производства в анализаторе LALR (1). В SLR следуют (A) , включая a, которые также могут быть смещены.

4 голосов
/ 30 августа 2011

Основное различие между таблицами синтаксического анализатора, созданными с помощью SLR и LR, состоит в том, что действия сокращения основаны на наборе Follows для таблиц SLR. Это может быть чрезмерно ограничительным, что в конечном итоге приведет к конфликту «сдвиг-сокращение».

С другой стороны, синтаксический анализатор LR уменьшает количество решений только по набору терминалов, которые могут фактически следовать за нетерминальным сокращением. Этот набор терминалов часто является правильным подмножеством набора Follows такого нетерминала и поэтому имеет меньше шансов конфликтовать с действиями смены.

По этой причине парсеры LR более мощные. Однако таблицы разбора LR могут быть очень большими.

Анализатор LALR начинается с идеи построения таблицы синтаксического анализа LR, но объединяет сгенерированные состояния таким образом, что приводит к значительно меньшему размеру таблицы. Недостатком является то, что для некоторых грамматик может возникнуть небольшая вероятность конфликтов, которых в противном случае избегала бы таблица LR.

LALR-парсеры немного менее мощные, чем LR-парсеры, но все же более мощные, чем SLR-парсеры. По этой причине YACC и другие подобные генераторы синтаксических анализаторов обычно используют LALR.

P.S. Для краткости, SLR, LALR и LR выше действительно означают SLR (1), LALR (1) и LR (1), так что подразумевается один взгляд на токен.

0 голосов
/ 19 июня 2019

В дополнение к ответам выше, эта диаграмма демонстрирует, как соотносятся разные парсеры:

enter image description here

0 голосов
/ 10 августа 2015

Один простой ответ заключается в том, что все грамматики LR (1) являются грамматиками LALR (1).По сравнению с LALR (1), LR (1) имеет больше состояний в связанном автомате конечных состояний (более чем в два раза больше состояний).И это главная причина, по которой грамматикам LALR (1) требуется больше кода для обнаружения синтаксических ошибок, чем грамматикам LR (1).И еще одна важная вещь, которую необходимо знать в отношении этих двух грамматик, заключается в том, что в грамматиках LR (1) у нас может быть меньше конфликтов уменьшения / уменьшения.Но в LALR (1) есть больше возможностей уменьшить / уменьшить конфликты.

...