LL(k)-грамматики, множества FIRST и FOLLOW

Материал из Викиконспекты
Версия от 19:35, 4 сентября 2022; Maintenance script (обсуждение | вклад) (rollbackEdits.php mass rollback)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

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

LL(k)-грамматика

Дадим теперь формально определение LL(k)-грамматики.

Определение:
Пусть Γ=Σ,N,S,P — КС-грамматика. Рассмотрим два произвольных левосторонних вывода слова w в этой грамматике:
  • SpAβpαβpyη
  • SpAβpαβpyξ

где p и y — цепочки из терминалов, уже разобранная часть слова w, A — нетерминал грамматики, в которой есть правила Aα и Aα, причём α,α,β,η,ξ — последовательности из терминалов и нетерминалов.

Если из выполнения условий, что |y|=k или |y|<k,η=ξ=ε, следует равенство α=α, то Γ называется LL(k)-грамматикой.

LL(1)-грамматика является частным случаем. Её определение почти такое же, только вместо строки y один символ cΣ{ε}.

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

FIRST и FOLLOW

Ключевую роль в построении парсеров для LL(1)-грамматик играют множества FIRST и FOLLOW.

Пусть c — символ из алфавита Σ, α, β — строки из нетерминалов и терминалов (возможно пустые), S, A — нетерминалы грамматики (начальный и произвольный соответственно), $ — символ окончания слова. Тогда определим FIRST и FOLLOW следующим образом:

Определение:
FIRST(A)={cAcβ}{ε if Aε}


Определение:
FOLLOW(A)={cSαAcβ}{$ if SαA}

Другими словами, FIRST(A) — все символы (терминалы), с которых могут начинаться всевозможные выводы из α, а FOLLOW(A) — всевозможные символы, которые встречаются после нетерминала A во всех небесполезных правилах грамматики.

Замечание: более общим случаем множества FIRST является множество FIRSTk, однако в данном конспекте оно не используется.

Определение:
FIRSTk(A)={wAwβ, |w|k}{ε if Aε}

Примеры

Множества FIRST и FOLLOW могут отличаться даже для одной грамматики, если она задана разными правилами. Рассмотрим пример двух различных грамматик для языка правильных скобочных последовательностей.

  • A(A)Aε
  • BBB(B)ε
Правило FIRST FOLLOW
A { (, ε } { ), $ }
B { (, ε } { (, ), $ }

Теорема о связи LL(1)-грамматики с множествами FIRST и FOLLOW

Далее будет показано, как множества FIRST и FOLLOW связаны с понятием LL(1)-грамматики.

Теорема:
Γ=Σ,N,S,P — LL(1)-грамматика
  1. Aα, Aβ,AN  FIRST(α)FIRST(β)=
  2. Aα, Aβ,AN, εFIRST(α)  FOLLOW(A)FIRST(β)=
Доказательство:

Предположим, что данная грамматика не будет LL(1)-грамматикой. Значит, у какого-то слова w существует два различных левосторонних вывода.

  • SpAγpαγpcαγ
  • SpAγpβγpcβγ

Но это противоречит тому, что FIRST(α)FIRST(β)=.

Аналогично проверятся второе условие. Если, например, αε, то εFIRST(α), и FOLLOW(A)FIRST(β)

Предположим, что есть два различных правила Aα и Aβ таких, что cFIRST(A)FIRST(β). Тогда:

  • SpAγpαγpcαγ
  • SpAγpβγpcβγ

Последний переход можно совершить, так как c лежит в пересечении множеств FIRST двух правил вывода. Так как грамматика Γ является LL(1)-грамматикой, то из определения следует, что α=β. Это противоречит предположению, что α и β — различные правила.

Второе условие проверяется аналогичным образом.

Следствия

Сформулируем несколько важных cледствий из теоремы.

Левая рекурсия

Утверждение (1):
Грамматика Γ cодержит левую рекурсию  Γ не является LL(1)-грамматикой.

Если грамматика содержит левую рекурсию, значит, в ней существует какой-то нетерминал A с правилами AAαβ, где β — строка из терминалов и нетерминалов, не начинающаяся с A.

Тогда понятно, что FIRST(Aα)FIRST(β), и это противоречит первому условию теоремы.

Чтобы избавиться от левой рекурсии, можно воспользоваться алгоритмом устранения левой рекурсии.

Левая факторизация

Утверждение (2):
Грамматика Γ cодержит правое ветвление  Γ не является LL(1)-грамматикой.

Наличие в грамматике правого ветвления означает, что существует правило Aαβαγ,αε.

Очевидно, что FIRST(αβ)FIRST(αγ). Поэтому грамматика не будет LL(1)-грамматикой по первому условию теоремы.
Алгоритм устранения правого ветвленения

Чтобы избавиться от правого ветвления, нужно воспользоваться алгоритмом левой факторизации. Его суть заключается в следующем: для каждого нетерминала A ищем самый длинный префикс, общий для двух или более правил вывода из A. Важно, чтобы как можно больше строк имело общий префикс, и можно было вынести части правил после общего префикса в отдельный нетерминал. Более формально, рассмотрим правила

Aαβ1αβnγ1γm

Причём αε, а наибольший общий префикс α и γi (1im) равен ε. Тогда изменим грамматику следующим образом, введя новый нетерминал A:

AαAγ1γm

Aβ1βn

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

Замечание: отсутствие левой рекурсии и правого ветвления в грамматике не является достаточным условием того, что она будет LL(1)-грамматикой. После их устранения грамматика всё ещё может остаться не LL(1)-грамматикой.

См. также

Источники информации