В чем разница между парсингом LL и LR?

Может ли кто-нибудь дать мне простой пример анализа LL по сравнению с анализом LR?


person Creativity2345    schedule 12.05.2011    source источник


Ответы (4)


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

Разбор LL - это вывод слева направо, крайний левый. То есть мы рассматриваем входные символы слева направо и пытаемся построить самое левое производное. Это делается, начиная с начального символа и многократно расширяя крайний левый нетерминал, пока мы не дойдем до целевой строки. LR-синтаксический анализ - это вывод слева направо, крайний правый вывод, что означает, что мы просматриваем слева направо и пытаемся построить крайнее правое происхождение. Синтаксический анализатор постоянно выбирает подстроку входных данных и пытается обратить ее обратно в нетерминал.

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

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

В качестве примера, учитывая эту грамматику:

  • S E
  • E T + E
  • E T
  • Т int

Затем, учитывая строку int + int + int, синтаксический анализатор LL (2) (который использует два токена просмотра вперед) проанализирует строку следующим образом:

Production       Input              Action
---------------------------------------------------------
S                int + int + int    Predict S -> E
E                int + int + int    Predict E -> T + E
T + E            int + int + int    Predict T -> int
int + E          int + int + int    Match int
+ E              + int + int        Match +
E                int + int          Predict E -> T + E
T + E            int + int          Predict T -> int
int + E          int + int          Match int
+ E              + int              Match +
E                int                Predict E -> T
T                int                Predict T -> int
int              int                Match int
                                    Accept

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

В парсере LR есть два действия:

  1. Shift: добавьте следующий токен ввода в буфер для рассмотрения.
  2. Уменьшить: уменьшите набор терминалов и нетерминалов в этом буфере до некоторого нетерминала, изменив производство.

Например, синтаксический анализатор LR (1) (с одним токеном просмотра вперед) может проанализировать ту же строку следующим образом:

Workspace        Input              Action
---------------------------------------------------------
                 int + int + int    Shift
int              + int + int        Reduce T -> int
T                + int + int        Shift
T +              int + int          Shift
T + int          + int              Reduce T -> int
T + T            + int              Shift
T + T +          int                Shift
T + T + int                         Reduce T -> int
T + T + T                           Reduce E -> T
T + T + E                           Reduce E -> T + E
T + E                               Reduce E -> T + E
E                                   Reduce S -> E
S                                   Accept

Известно, что два упомянутых вами алгоритма синтаксического анализа (LL и LR) имеют разные характеристики. Парсеры LL, как правило, легче писать вручную, но они менее мощны, чем парсеры LR, и принимают гораздо меньший набор грамматик, чем парсеры LR. Парсеры LR бывают разных видов (LR (0), SLR (1), LALR (1), LR (1), IELR (1), GLR (0) и т. Д.) И гораздо более мощные. Они также имеют тенденцию быть более сложными и почти всегда генерируются такими инструментами, как yacc или bison. Парсеры LL также бывают разных видов (включая LL (*), который используется инструментом ANTLR), хотя на практике LL (1 ) является наиболее широко используемым.

Если вы хотите узнать больше о парсинге LL и LR, я только что закончил преподавать курс компиляторов и получил раздаточные материалы и слайды лекций по синтаксическому анализу на веб-сайте курса. Я был бы рад подробнее остановиться на любом из них, если вы считаете, что это будет полезно.

person templatetypedef    schedule 26.07.2011
comment
Ваши слайды с лекциями феноменальны, это, пожалуй, самое забавное объяснение, которое я когда-либо видел :) Это то, что действительно вызывает интерес. - person kizzx2; 11.08.2011
comment
Я тоже должен прокомментировать слайды! Сейчас прохожу через все. Очень помогает! Спасибо! - person kornfridge; 30.05.2013
comment
Мне тоже очень нравится слайды. Я не думаю, что вы могли бы опубликовать версию файлов проекта, отличную от Windows (и файл scanner.l для pp2)? :) - person Erik P.; 23.08.2013
comment
Единственное, что я могу внести в отличный итоговый ответ Мэтта, - это то, что любая грамматика, которая может быть проанализирована парсером LL (k) (т.е. заглядывая вперед k терминалов для принятия решения о следующем действии синтаксического анализа), может быть проанализирована LR (1) парсер. Это дает намек на невероятную мощь синтаксического анализа LR над синтаксическим анализом LL. Источник: курс компиляции в UCSC, преподаваемый доктором Ф. Де Ремером, создателем парсеров LALR (). - person JoGusto; 02.02.2015
comment
@templatetypedef: Отличный ответ, спасибо за его вклад. Я смотрел слайды вашей лекции; в лекции 03 по синтаксическому анализу сверху вниз, часть I, на слайде, озаглавленном «Крайние левые производные», один маркер говорит: «Повышает вероятность того, что мы получим префикс нетерминалов». Вы уверены, что не имеете в виду Увеличивает вероятность того, что мы получим префикс терминалов? Терминалы мне кажутся правильными, и за два слайда до вас обсуждается попытка получить префикс терминалов. - person Mark; 13.02.2015
comment
Могу ли я так понять разницу между ними? Анализатор LL выдвигает гипотезу о структуре, которую он хочет, и проверяет структуру входной строки на соответствие гипотетической структуре, если она соответствует, сделайте левый вывод. Пока парсер LR будет пытаться найти подходящую структуру входной строки с помощью правил. - person code4j; 21.03.2016
comment
Это отличный ответ, я заинтригован прочитать ваши слайды в следующий раз! :) - person Agis; 18.05.2016
comment
@templatetypedef Небольшие технические исправления. LR - это самый правый вывод в обратном. Обратите внимание, что вывод S->E является первым в примере LL, но последним в примере LR. - person rocky; 12.10.2016
comment
Это изящно. Ваши ресурсы кажутся лучше, чем любые другие доступные тексты (не нужно покупать новый). Я обязательно посмотрю на твою в ближайшее время. Бесконечно благодарен. - person b1sub; 29.04.2017
comment
Отличный ресурс! Спасибо за предоставленные слайды, раздаточные материалы, проекты. - person P. Hinker; 21.09.2018
comment
Большое спасибо за пример! Я застрял в этом на пару дней, но после прочтения это стало намного понятнее !! Слайды лекций тоже отличные! Большое спасибо!! - person Jas; 19.05.2019

Джош Хаберман в своей статье LL и LR Parsing Demystified утверждает, что анализ LL напрямую соответствует польской нотации, тогда как LR соответствует Обратная польская нотация. Разница между PN и RPN заключается в порядке обхода двоичного дерева уравнения:

двоичное дерево уравнения

+ 1 * 2 3  // Polish (prefix) expression; pre-order traversal.
1 2 3 * +  // Reverse Polish (postfix) expression; post-order traversal.

По словам Хабермана, это иллюстрирует основное различие между парсерами LL и LR:

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

Подробное объяснение, примеры и выводы можно найти в Хабермана. статья.

person msiemens    schedule 14.08.2013

LL использует нисходящий подход, а LR - восходящий подход.

Если вы разбираете язык программирования:

  • LL видит исходный код, который содержит функции, которые содержат выражение.
  • LR видит выражение, которое принадлежит функциям, что приводит к полному исходному тексту.
person betontalpfa    schedule 28.05.2018

Разбор LL затруднен по сравнению с LR. Вот грамматика, которая является кошмаром для генератора парсеров LL:

Goal           -> (FunctionDef | FunctionDecl)* <eof>                  

FunctionDef    -> TypeSpec FuncName '(' [Arg/','+] ')' '{' '}'       

FunctionDecl   -> TypeSpec FuncName '(' [Arg/','+] ')' ';'            

TypeSpec       -> int        
               -> char '*' '*'                
               -> long                 
               -> short                   

FuncName       -> IDENTIFIER                

Arg            -> TypeSpec ArgName         

ArgName        -> IDENTIFIER 

FunctionDef выглядит точно так же, как FunctionDecl, до символа ';' или встречается '{'.

Анализатор LL не может обрабатывать два правила одновременно, поэтому он должен выбрать либо FunctionDef, либо FunctionDecl. Но чтобы узнать, какой из них правильный, нужно искать впереди ';' или '{'. Во время анализа грамматики прогноз (k) кажется бесконечным. Во время синтаксического анализа он конечен, но может быть большим.

Парсеру LR не нужно смотреть вперед, потому что он может обрабатывать два правила одновременно. Таким образом, генераторы синтаксического анализатора LALR (1) могут легко справиться с этой грамматикой.

Учитывая входной код:

int main (int na, char** arg); 

int main (int na, char** arg) 
{

}

Парсер LR может анализировать

int main (int na, char** arg)

не заботясь о том, какое правило распознается, пока не встретит ';' или '{'.

Парсер LL зависает на int, потому что ему нужно знать, какое правило распознается. Следовательно, он должен искать впереди ';' или '{'.

Другой кошмар для парсеров LL - это левосторонняя рекурсия в грамматике. Левая рекурсия - нормальное явление в грамматиках, не проблема для генератора парсеров LR, но LL не справляется с этим.

Таким образом, вы должны писать свои грамматики неестественным образом с LL.

person Community    schedule 08.06.2019