Разве синтаксический анализатор LR(0) также не использует просмотр вперед?

LL(1)-парсеру нужен предпросмотр-символ, чтобы иметь возможность решить, какую продукцию использовать. Это причина, по которой я всегда думал, что термин «упреждающий просмотр» используется, когда синтаксический анализатор просматривает следующий входной токен, не «потребляя» его (т.е. он все еще может быть прочитан из ввода следующим действием). Однако синтаксические анализаторы LR(0) заставили меня усомниться в правильности этого:

Каждый пример LR(0)-парсеров, которые я видел, также использует следующий входной токен для принятия решения о сдвиге или уменьшении. В случае сокращения входной токен не расходуется.

Я использовал бесплатный инструмент «ParsingEmu» для создания таблицы LR и выполнения приведенной ниже оценки LR для слова «aab». Как видите, заголовок столбца содержит токены. Из оценки вы можете видеть, что синтаксический анализатор решает, какой столбец использовать, просматривая следующий входной токен. Но когда синтаксический анализатор сокращает на шагах 4–6, входные данные не меняются (хотя синтаксическому анализатору необходимо знать следующий входной токен «$» при выполнении перехода в следующее состояние).

Грамматика:

S -> A
A -> aA
A -> b

Таблица: LR table

Оценка: Оценка LR

Теперь я сделал следующие предположения по причине моего замешательства:

  1. Мое предположение об определении «предварительного просмотра» (предварительный просмотр = входной токен не используется) неверно. Lookahead просто означает две разные вещи для LL-парсеров или LR-парсеров. Если да, то как тогда можно определить «упреждающий просмотр»?

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

  3. Показанная выше оценка — это LR(1). Если да, то как будет выглядеть оценка LR(0)?

Теперь, что правильно, 1, 2 или 3 или что-то совсем другое?


person fishbone    schedule 14.03.2015    source источник
comment
возможный дубликат Как синтаксический анализатор LR(0) может покинуть состояние 0? (мой собственный вопрос)   -  person user541686    schedule 19.08.2015


Ответы (1)


Важно быть точным:

Синтаксический анализатор LR(k) использует текущее состояние анализатора и k символов просмотра вперед, чтобы решить, нужно ли уменьшать, и если да, то каким производством.

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

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

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

Если, с другой стороны, переход со сдвигом приводит к назначенному состоянию Accept, то синтаксический анализ завершается успешно, и алгоритм завершается.

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


Парсеры LL(k) должны предсказать, какая продукция заменит нетерминал, как только они увидят нетерминал. Базовый алгоритм LL начинается со стека, содержащего [S, $] (сверху вниз), и выполняет одно из следующих действий, пока не будет выполнено:

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

  • Если вершина стека является терминалом, прочитайте следующий входной токен. Если это тот же терминал, извлеките стек и продолжите. В противном случае синтаксический анализ завершился неудачно и алгоритм завершает работу.

  • Если стек пуст, синтаксический анализ завершился успешно, и алгоритм завершает работу. (Мы предполагаем, что в конце входных данных есть уникальный EOF-маркер $.)


В обоих случаях упреждающий просмотр имеет одинаковое значение: он состоит в просмотре входных токенов без перемещения курсора ввода.

Если k равно 0, то:

  • Синтаксический анализатор LR(k) должен решить, выполнять ли сокращение, не проверяя входные данные, что означает, что ни одно состояние не может иметь два разных действия сокращения или действие сокращения и сдвиг. .

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

person rici    schedule 14.03.2015
comment
Является ли синтаксический анализ, показанный на изображениях моего вопроса, синтаксическим анализатором LR (1)? - person fishbone; 16.03.2015
comment
Но будет ли грамматика LR(0)-анализируемой, поскольку в одном состоянии она должна либо сдвигаться (состояния 0 и 1), либо уменьшаться (состояния 3 и 4)? Это не было бы LR (0)-анализируемым, если бы одна строка состояния содержала действия как сдвига, так и сокращения в зависимости от столбца (= токена)? - person fishbone; 16.03.2015
comment
@fishbone: Верно. Это LR(0). Нет состояния JJ, так как и сдвиг, и сокращение действий, или два действия сокращения для разных производств. - person rici; 16.03.2015
comment
решение о смещении (или ошибке) должно быть принято до чтения следующей входной лексемы. Почему? Я все еще в замешательстве... Если мы не прочитали следующий токен, как убедиться, что сдвиг прошел успешно? Например: в данном состоянии синтаксического анализатора и невозможности сокращения, если следующий входной токен равен «t», то его можно сдвинуть, в противном случае он не может и сообщает об ошибке. Таким образом, все еще нужно прочитать следующий токен, чтобы решить, будет ли сдвиг или нет. - person chansey; 19.03.2018
comment
@chansey: синтаксический анализатор решает сдвинуться или ошибиться, прежде чем увидит следующий токен. Если сдвиг впоследствии завершится ошибкой, будет выдана ошибка. Возможно, я мог бы сформулировать это лучше. Дело в том, что грамматика LR(0) должна принимать решение о сокращении или сдвиге, используя 0 символов просмотра вперед. Но это не мешает ему ошибиться, как только он прочитает следующий символ. (Или даже до того, как он прочитает следующий символ; действие редукции может перевести синтаксический анализатор в состояние без каких-либо применимых действий, хотя алгоритм создания машин LR(0) никогда не создаст такой случай.) - person rici; 19.03.2018
comment
Я понимаю, что грамматика LR(0) должна принять решение уменьшить, используя 0 символов просмотра вперед. Например: мы не можем использовать Follow Set для разрешения конфликта уменьшения/уменьшения в LR(0). Но меня больше всего смущает shift. Например: в каком-то конкретном состоянии жизнеспособного префикса DFA у нас есть только один элемент: T -> .int, но следующий токен ')' вместо 'int', это вызывает ошибку синтаксического анализа. Итак, мы читаем следующий токен ')', чтобы убедиться, что ошибка синтаксического анализа. (Но LR(0) не должен читать следующий токен, потому что это 0 вперед) - person chansey; 19.03.2018
comment
@chansey: shift использует токен, поэтому он должен его прочитать :) Парсеру LR(0) не нужно знать, в какое состояние он перейдет, прежде чем он прочитает токен; ему нужно только знать, что он сдвинется. Как только он примет это решение, оно станет необратимым; он не может решить, что сокращение имело больше смысла. Я предполагаю, что это кажется несимметричным, и это так: процесс синтаксического анализа полностью основан на действиях редукции, поскольку цель состоит в том, чтобы обнаружить вывод. Сдвиг — это просто способ сказать, здесь нет сокращения, попробуйте следующую точку ввода. Это также верно и для состояния парсера, которое... - person rici; 19.03.2018
comment
...деталь реализации, если хотите. Наблюдаемые действия синтаксического анализатора выдают шаг деривации и потребляют входной токен, а синтаксический анализатор LR (0) должен определить первое перед вторым. В более общем случае синтаксический анализатор LR(k) может выполнить не более k потребления, прежде чем он выдаст вывод, заканчивающийся потребляемой лексемой. - person rici; 19.03.2018
comment
Этот ответ - лучший, он помог мне избавиться от путаницы в отношении просмотра вперед. У меня есть только одно сомнение в парсере LL(0), когда потребляется входной символ? - person kapil; 09.04.2020
comment
@kapil: синтаксический анализатор LL имеет стек предсказаний, который представляет собой то, что он ожидает увидеть дальше. Если вершина стека предсказаний является нетерминалом, синтаксический анализатор должен решить, какие из продуктов нетерминала предсказывать. Затем он выталкивает нетерминал и толкает правую сторону производства. Если вершина стека предсказания является терминалом, синтаксический анализатор использует токен, который должен быть таким же, как предсказанный токен наверху стека. Если это правильный токен, он извлекает стек предсказаний; в противном случае объявляется ошибка. - person rici; 09.04.2020