Я пытаюсь понять крайний левый вывод в контексте алгоритма синтаксического анализа LL. Эта ссылка объясняет это с генеративной точки зрения . то есть показывает, как следовать самому левому выводу, чтобы сгенерировать конкретную последовательность токенов из набора правил.

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

Давайте продолжим использовать следующую грамматику из вышеупомянутой ссылки:

enter image description here

И данная последовательность токенов: 1 2 3

Один из способов это:

1 2 3
-> D D D 
-> N D D (rewrite the *left-most* D to N according to the rule N->D.)
-> N D (rewrite the *left-most* N D to N according to the rule N->N D.)
-> N  (same as above.)

Но есть и другие способы применения правил грамматики:

1 2 3 -> D D D -> N D D -> N N D -> N N N

ИЛИ

1 2 3 -> D D D -> N D D -> N N D -> N N

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

По мере увеличения длины последовательности токенов может быть гораздо больше способов. Я думаю, чтобы сделать правильный вывод , необходимы 2 предварительных условия:

  • стартовое / корневое правило
  • последовательность токенов

После того, как вы зададите эти 2, каков алгоритм, чтобы найти производные шаги? Должны ли мы сделать конечный результат одиночным нетерминальным?

0
smwikipedia 8 Янв 2017 в 13:22
Возможно, моя правка проясняет мой ответ. Если нет, спрашивайте :)
 – 
rici
9 Янв 2017 в 03:02

1 ответ

Лучший ответ

Общий процесс разбора LL состоит из повторения:

  • Спрогнозируйте результативность верхнего грамматического символа в стеке, если этот символ нетерминальный, и замените этот символ правой частью продуктивного символа.

  • Сопоставьте верхний символ грамматики в стеке со следующим входным символом, отбросив их оба.

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

На любом этапе этого алгоритма частично производная строка является потребляемым вводом, добавленным к стеку. Изначально нет потребляемого ввода, и стек состоит только из начального символа, так что частично производная строка (к которой применено 0 производных). Поскольку потребляемый ввод состоит исключительно из терминалов, а алгоритм всегда изменяет только верхний (первый) элемент стека, ясно, что последовательность частично производных строк составляет крайнее левое производное.

Если синтаксический анализ успешен, весь ввод будет использован, а стек будет пуст, поэтому синтаксический анализ приведет к самому левому производному ввода от начального символа.

Вот полный анализ вашего примера:

Consumed           Unconsumed   Partial      Production
Input      Stack   input        derivation   or other action
--------   -----   ----------   ----------   --------------- 
           N       1 2 3        N            N → N D
           N D     1 2 3        N D          N → N D
           N D D   1 2 3        N D D        N → D
           D D D   1 2 3        D D D        D → 1
           1 D D   1 2 3        1 D D        -- match --
1          D D       2 3        1 D D        D → 2
1          2 D       2 3        1 2 D        -- match --
1 2        D           3        1 2 D        D → 3
1 2        3           3        1 2 3        -- match --
1 2 3      --         --        1 2 3        -- success --

Если вы прочитаете последние два столбца, вы увидите, как процесс вывода начинается с N и заканчивается 1 2 3. В этом примере прогноз можно сделать только с помощью магии, потому что правило N → N D не является LL ( k ) для любого k ; использование вместо этого правила правой рекурсии N → D N разрешило бы процедуру принятия решения LL (2) (например, "использовать N → D N, если есть по крайней мере два неиспользованных входных токена; в противном случае N → D". )

Диаграмма, которую вы пытаетесь создать, которая начинается с 1 2 3 и заканчивается N, является синтаксическим анализом снизу вверх . Анализ снизу вверх с использованием алгоритма LR соответствует крайним правым производным, но производные нужно читать в обратном направлении, поскольку они заканчиваются начальным символом.

1
rici 9 Янв 2017 в 02:59
Спасибо. Таким образом, с помощью вспомогательного стека и правильного способа принятия решения о прогнозировании можно продолжить синтаксический анализ. Но я не совсем понимаю это предложение , потому что правило N → N D не равно LL(k) ни для какого k; использование вместо этого правила правой рекурсии N → D N разрешило бы процедуру принятия решения LL(2). . На мой взгляд, с правилом N → N D, если есть хотя бы два неиспользованных входных токена, мне все равно нужно применить N → N D. Я не вижу здесь другого выбора.
 – 
smwikipedia
9 Янв 2017 в 05:24
1
@smwikipedia: замена N на N D никогда не потребляет входной токен. Вы должны сделать это ровно столько раз, сколько у вас есть входных данных, но поскольку он не потребляет входные данные, вы не можете знать, сколько раз, без проверки всего входного потока, неограниченного просмотра вперед. Напротив, после замены N на D N следующие два шага должны использовать входной токен, соответствующий D, что позволит продолжить синтаксический анализ. Таким образом, стек всегда состоит только из D N, и только тогда, когда следующий токен является последним оставшимся, вам нужно сделать что-то другое.
 – 
rici
9 Янв 2017 в 05:37
1
@smwikipedia: Я определенно считаю, что LR - лучший алгоритм. В самом деле, я не думаю, что в этом есть какие-либо сомнения, потому что каждый язык LL (k) может быть описан грамматикой LR (1), но есть много языков LR (1), которые не имеют LL (k) грамматика. Поскольку оба алгоритма являются линейными по времени и постоянным пространством (а константы сопоставимы), аргумента об эффективности также нет. Но это не совсем то, о чем вы спрашиваете ...
 – 
rici
9 Янв 2017 в 05:51
1
... ключ, как я уже упоминал, заключается в том, как принимаются решения. Базовые алгоритмы синтаксического анализа слева направо, сверху вниз и снизу вверх, представляют собой фреймворки, которые могут работать с любым алгоритмом точного принятия решений. LL и LR являются конкретными экземплярами тех соответствующих структур, в которых решение принимается путем обращения к таблице поиска с использованием следующих неиспользованных элементов ввода k для некоторого фиксированного k. Как это бывает, алгоритм LR будет работать как с леворекурсивными, так и с праворекурсивными правилами, но алгоритм LL не будет работать с леворекурсивными правилами, как показано на этом тривиальном примере. Но обычно можно конвертировать ...
 – 
rici
9 Янв 2017 в 05:55
1
... левую рекурсию в правую, хотя и за счет изменения структуры результирующего дерева синтаксического анализа. Разбор LR (k) не универсален; есть много грамматик (а также много языков), которые нельзя анализировать таким образом, и есть разные алгоритмы, которые могут справиться с этими грамматиками. Однако различные алгоритмы больше не являются линейными по времени. Одна из возможностей - это, действительно, возврат при возникновении проблемы, но в целом возврат происходит экспоненциально во времени. Другой подход - это «общий» анализ LR, который может выполняться в кубическом времени. В википедии много ссылок.
 – 
rici
9 Янв 2017 в 05:59