it-roy-ru.com

В чем разница между парсерами LR, SLR и LALR?

Какова реальная разница между парсерами 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 прогнозный токен, а both управляются таблицами! Чем они отличаются?

96
Prasoon Saurav

Синтаксические анализаторы 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 связана с таблицей generator. Генераторы синтаксического анализатора 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++. (У меня есть именно такой синтаксический анализатор, и он обрабатывает не только Vanilla C++, но также и различные диалекты вендоров. Это возможно только на практике, потому что мы используем синтаксический анализатор GLR, IMHO).

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

[EDIT November 2011: We've extended our parser to handle all of C++11. GLR made that a lot easier to do. EDIT Aug 2014: Now handling all of C++17. Nothing broke or got worse, GLR is still the cat's meow.]

51
Ira Baxter

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

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

Приложение

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

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

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

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

18
David R Tribble

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

Алгоритмы разбора для 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 9.1 может генерировать минимальные парсеры LR (1) и LR (*) в C++. Смотрите эта диаграмма, которая показывает разницу между LR-парсерами. 

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

12
Paul B Mann

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

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

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

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

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

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

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

Это ваш LALR (1) парсер.


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

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

5
Kang

Парсеры 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)) определит, может ли он уменьшиться, проверив, находится ли следующий входной символ в follow set of 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 follow (A) включает a, которая также может быть смещена.

4
Klaus

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

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

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

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

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

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

4
tgoneil

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

0
Anil Kumar