LL(k)-грамматики, множества FIRST и FOLLOW — различия между версиями
Shersh (обсуждение | вклад) (→Левая факторизация) |
Shersh (обсуждение | вклад) (описан алгоритм левой факторизации) |
||
Строка 88: | Строка 88: | ||
}} | }} | ||
===== Алгоритм устранения правого ветвленения ===== | ===== Алгоритм устранения правого ветвленения ===== | ||
+ | Чтобы избавиться от правого ветвления, нужно воспользоваться алгоритмом левой факторизации. Его суть заключается в следующем: для каждого нетерминала <tex> A </tex> ищем самый длинный префикс, общий для двух или более правил вывода из <tex> A </tex>. Важно, чтобы как можно больше строк имело общий префикс, и можно было вынести части правил после общего префикса в отдельный нетерминал. Более формально, рассмотрим правила | ||
+ | |||
<tex> A \to \alpha \beta_1 \mid \ldots \mid \alpha \beta_n \mid \gamma_1 \mid \ldots \mid \gamma_m </tex> | <tex> A \to \alpha \beta_1 \mid \ldots \mid \alpha \beta_n \mid \gamma_1 \mid \ldots \mid \gamma_m </tex> | ||
− | + | Причём <tex> \alpha \ne \varepsilon </tex>, а наибольший общий префикс <tex> \alpha </tex> и <tex> \gamma_i,\ 1 \leqslant i \leqslant m</tex> равен <tex> \varepsilon </tex>. Тогда изменим грамматику следующим образом, введя новый нетерминал <tex> A' </tex>: | |
+ | |||
+ | <tex> A \to \alpha A' \mid \gamma_1 \mid \ldots \mid \gamma_m </tex> | ||
+ | |||
+ | <tex> A' \to \beta_1 \mid \ldots \mid \beta_n </tex> | ||
+ | |||
+ | Алгоритм завершится, когда в грамматике не будет правого ветвления. Он завершится за конечное число шагов, так как каждый раз длина правой части правил уменьшается ходя бы на единицу, а тривиальные префиксы мы не рассматриваем. К тому же, алгоритм не меняет язык грамматики, следовательно, является корректным. | ||
+ | |||
+ | '''Замечание:''' отсутствие левой рекурсии и правого ветвления в грамматике не является необходимым условием того, что она будет LL(1)-грамматикой. После их устранения грамматика всё ещё может остаться не LL(1)-грамматикой. | ||
== См. также == | == См. также == |
Версия 14:52, 28 июня 2014
Наибольший интерес в построении синтаксических анализаторов (парсеров) представляют LL(1)-грамматики, так как для них возможно построение нисходящих парсеров без возврата, то есть без корректировки выбранных правил в грамматике. LL(1)-грамматики являются подмножеством КС-грамматик. Однако для достаточно большого количества формальных языков можно построить LL(1)-грамматику, например, для языка арифметических выражений и даже для некоторых языков программирования, в частности можно и для языка Java.
Содержание
LL(k)-грамматика
Дадим теперь формально определение LL(k)-грамматики.
Определение: |
Пусть где | — КС-грамматика. Рассмотрим два произвольных левосторонних вывода слова в этой грамматике:
LL(1)-грамматика является частным случаем. Её определение почти такое же, только вместо строки
один символ .Неформально это означает, что, посмотрев на очередной символ после уже выведенной части слова, можно однозначно определить, какое правило из грамматики выбрать.
FIRST и FOLLOW
Ключевую роль в построении парсеров для LL(1)-грамматик играю множества
и .Пусть
— символ из алфавита , — строки из нетерминалов и терминалов (возможно пустые), — нетерминалы грамматики (начальный и произвольный соответственно), — символ окончания слова. Тогда определим и следующим образом:Определение: |
Определение: |
Другими словами, достижимых из начального.
— все символы (терминалы), с которых могут начинаться всевозможные выводы из , а — всевозможные символы, которые встречаются после нетерминала во всех правилах грамматики,Примеры
Множества
и могут отличаться даже для одной грамматики, если она задана разными правилами. Рассмотрим пример двух различных грамматик для языка правильных скобочных последовательностей.Правило | FIRST | FOLLOW |
---|---|---|
A | ||
B |
Теорема о связи LL(1)-грамматики с множествами FIRST и FOLLOW
Далее будет показано, как множества
и связаны с понятием LL(1)-грамматики.Теорема: |
Доказательство: |
очевидно |
Следствия
Сформулируем несколько важных cледствий из теоремы.
Левая рекурсия
Утверждение (1): |
Грамматика cодержит левую рекурсию не является LL(1)-грамматикой. |
Если грамматика содержит левую рекурсию, значит, в ней существует какой-то нетерминал Тогда понятно, что с правилами , где — строка из терминалов и нетерминалов, не начинающаяся с . , и это противоречит первому условию теоремы. |
Чтобы избавиться от левой рекурсии, можно воспользоваться алгоритмом устранения левой рекурсии.
Левая факторизация
Утверждение (2): |
Грамматика cодержит правое ветвление не является LL(1)-грамматикой. |
Наличие в грамматике правого ветвления означает, что существует правило Очевидно, что . . Поэтому грамматика не будет LL(1)-грамматикой по первому условию теоремы. |
Алгоритм устранения правого ветвленения
Чтобы избавиться от правого ветвления, нужно воспользоваться алгоритмом левой факторизации. Его суть заключается в следующем: для каждого нетерминала
ищем самый длинный префикс, общий для двух или более правил вывода из . Важно, чтобы как можно больше строк имело общий префикс, и можно было вынести части правил после общего префикса в отдельный нетерминал. Более формально, рассмотрим правила
Причём
, а наибольший общий префикс и равен . Тогда изменим грамматику следующим образом, введя новый нетерминал :
Алгоритм завершится, когда в грамматике не будет правого ветвления. Он завершится за конечное число шагов, так как каждый раз длина правой части правил уменьшается ходя бы на единицу, а тривиальные префиксы мы не рассматриваем. К тому же, алгоритм не меняет язык грамматики, следовательно, является корректным.
Замечание: отсутствие левой рекурсии и правого ветвления в грамматике не является необходимым условием того, что она будет LL(1)-грамматикой. После их устранения грамматика всё ещё может остаться не LL(1)-грамматикой.