Устранение левой рекурсии — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Отмена правки 28697 участника Shagal (обсуждение))
Строка 1: Строка 1:
 
{{Определение
 
{{Определение
|definition=Говорят, что [[Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора|контекстно-свободная(КС) грамматика]] <tex>\Gamma</tex> содержит '''непосредственную левую рекурсию''', если она содержит правило вида <tex>A \rightarrow A\alpha</tex>.
+
|definition=Говорят, что [[Контекстно-свободные грамматики, вывод, лево- и правосторонний вывод, дерево разбора|контекстно-свободная(КС) грамматика]] <tex>\Gamma</tex> содержит '''непосредственную левую рекурсию''', если она содержит правило вида <tex>A \Rightarrow A\alpha</tex>.
 
}}
 
}}
 
{{Определение
 
{{Определение
Строка 6: Строка 6:
 
}}
 
}}
  
Методы нисходящего разбора(top=down parsers) не в состоянии работать с леворекурсивными грамматиками. Проблема в том, что продукция вида <tex>A \Rightarrow^* A\alpha</tex> может применяться бесконечно долго, так и не выработав некий терминальный символ, который можно было бы сравнить со строкой. Поэтому требуется преобразование грамматики, которое бы устранило левую рекурсию.
+
Методы нисходящего разбора(top-down parsers) не в состоянии работать с леворекурсивными грамматиками. Проблема в том, что продукция вида <tex>A \Rightarrow^* A\alpha</tex> может применяться бесконечно долго, так и не выработав некий терминальный символ, который можно было бы сравнить со строкой. Поэтому требуется преобразование грамматики, которое бы устранило левую рекурсию.
  
Левая рекурсия может быть:
 
* непосредственной(immidiate)
 
<tex>A \Rightarrow A\alpha</tex>
 
* произвольной(indirect)
 
<tex>A_0 \rightarrow A_1\alpha</tex>
 
 
<tex>A_1 \rightarrow A_0\alpha</tex>
 
  
 
==Устранение непосредственной левой рекурсии==
 
==Устранение непосредственной левой рекурсии==
Строка 32: Строка 25:
 
</ol>
 
</ol>
  
Этот алгоритм не устраняет произвольную левую рекурсию,вызванную двумя или более шагами порождения.
+
Нетерминал A порождает те же строки, что и ранее, но без левой рекурсии. Эта процедура устраняет все непосредственные рекурсии из продукций для A, при условии, что ни одна строка <tex>\alpha_i</tex> не является <tex>\epsilon</tex>.
  
===Пример===
 
<tex>S \rightarrow Aa|b</tex>
 
  
<tex>A \rightarrow Ac|Sd|\epsilon</tex>
+
==Алгоритм  устранения произвольной левой рекурсии==
 
+
Пусть <tex>N = \lbrace A_1, A_2, \ldots , A_n \rbrace</tex> {{---}} множество всех нетерминалов.
S леворекурсивен, так как <tex>S \Rightarrow Aa \Rightarrow Sda</tex>, но эта рекурсия не является непосредственной.
 
 
 
==Устранение произвольной левой рекурсии==
 
Пусть <tex>N = \lbrace A_1, A_2, \ldots , A_n \rbrace</tex> {{---}} упорядоченное множество всех нетерминалов.
 
 
<div>
 
<div>
 
  for все нетерминалы <tex>A_i</tex>  
 
  for все нетерминалы <tex>A_i</tex>  
Строка 60: Строка 47:
 
*<tex>B_i \rightarrow B_j \alpha </tex>, где <tex>i < j</tex>.
 
*<tex>B_i \rightarrow B_j \alpha </tex>, где <tex>i < j</tex>.
  
==Алгоритм устранения левой рекурсии==
+
После <tex>i^ой</tex> итерации внешнего цикла в любой продукции вида <tex>A_k \rightarrow A_l\alpha<tex> где </tex> i > k будет l > k</tex>.
 +
В результате после каждой итерации растет нижний предел m, таких, что существует продукция вида <tex>A_i \rightarrow A_m\alpha</tex> до тех пор, пока не будет достигнуто <tex>m \geq i</tex>. Затем из <tex>A_i</tex> устраняется непосредственная левая рекурсия и достигается m > i.  
 +
 
 +
 
  
 
Для произвольной грамматики <tex>\Gamma</tex> левую рекурсию можно устранить следующим образом:
 
Для произвольной грамматики <tex>\Gamma</tex> левую рекурсию можно устранить следующим образом:

Версия 11:50, 7 января 2013

Определение:
Говорят, что контекстно-свободная(КС) грамматика [math]\Gamma[/math] содержит непосредственную левую рекурсию, если она содержит правило вида [math]A \Rightarrow A\alpha[/math].


Определение:
Говорят, что КС-грамматика [math]\Gamma[/math] содержит левую рекурсию(left recursion), если в ней существует вывод вида [math]A \Rightarrow^* A\alpha[/math].


Методы нисходящего разбора(top-down parsers) не в состоянии работать с леворекурсивными грамматиками. Проблема в том, что продукция вида [math]A \Rightarrow^* A\alpha[/math] может применяться бесконечно долго, так и не выработав некий терминальный символ, который можно было бы сравнить со строкой. Поэтому требуется преобразование грамматики, которое бы устранило левую рекурсию.


Устранение непосредственной левой рекурсии

Опишем процедуру, устраняющую все правила вида [math]A \rightarrow A\alpha[/math], для фиксированного нетерминала [math]A[/math].

  1. Запишем все правила вывода из [math]A[/math] в виде: [math]A \rightarrow A\alpha_1\,|\,\ldots\,|\,A\alpha_n\,|\,\beta_1\,|\,\ldots\,|\,\beta_m [/math], где
    • [math]\alpha[/math] — непустая последовательность терминалов и нетерминалов ([math]\alpha \nrightarrow \varepsilon [/math]);
    • [math]\beta[/math] — непустая последовательность терминалов и нетерминалов, не начинающаяся с [math]A[/math].
  2. Заменим правила вывода из [math]A[/math] на [math]A \rightarrow \beta_1A^\prime\, |\, \ldots\, |\, \beta_mA^\prime \,|\, \beta_1 \,|\, \ldots \,|\, \beta_m[/math].
  3. Создадим новый нетерминал [math]A^\prime \rightarrow \alpha_1A^\prime\, |\, \ldots\, |\, \alpha_nA^\prime | \alpha_1\, |\, \ldots\, |\, \alpha_n[/math].

Нетерминал A порождает те же строки, что и ранее, но без левой рекурсии. Эта процедура устраняет все непосредственные рекурсии из продукций для A, при условии, что ни одна строка [math]\alpha_i[/math] не является [math]\epsilon[/math].


Алгоритм устранения произвольной левой рекурсии

Пусть [math]N = \lbrace A_1, A_2, \ldots , A_n \rbrace[/math] — множество всех нетерминалов.

for все нетерминалы [math]A_i[/math] 
  for все нетерминалы [math]A_j[/math], такие, что [math] 1 \leq j \lt  i [/math] и 
    рассмотреть все правила вывода из [math]A_j[/math]: [math]A_j \rightarrow \delta_1 | \ldots | \delta_k[/math].
    заменить каждое правило [math]A_i \rightarrow A_j \gamma[/math] на [math]A_i \rightarrow \delta_1\gamma | \ldots | \delta_k\gamma[/math].
  устранить непосредственную левую рекурсию для [math]A_i[/math].

Таким образом, после применения алгоритма все правила вывода имеют вид:

  • [math]A \rightarrow c \alpha [/math], где [math]c[/math] — терминал, [math]A[/math] — произвольный нетерминал;
  • [math]A_i \rightarrow A_j \alpha [/math], где [math]i \lt j[/math], [math]A_i , A_j[/math] — нетерминалы из исходной грамматики;
  • [math]A_i^{\prime} \rightarrow A_j \alpha [/math], где [math]A_i^{\prime}[/math] — новый нетерминал, [math]A_j[/math] — нетерминал из исходной грамматики.

Если теперь перенумеровать нетерминалы, сохранив порядок для старых и присвоив всем новым меньшие номера, то все правила будут иметь вид:

  • [math]B_i \rightarrow c \alpha [/math], где [math]c[/math] — терминал;
  • [math]B_i \rightarrow B_j \alpha [/math], где [math]i \lt j[/math].

После [math]i^ой[/math] итерации внешнего цикла в любой продукции вида [math]A_k \rightarrow A_l\alpha\lt tex\gt где [/math] i > k будет l > k</tex>. В результате после каждой итерации растет нижний предел m, таких, что существует продукция вида [math]A_i \rightarrow A_m\alpha[/math] до тех пор, пока не будет достигнуто [math]m \geq i[/math]. Затем из [math]A_i[/math] устраняется непосредственная левая рекурсия и достигается m > i.


Для произвольной грамматики [math]\Gamma[/math] левую рекурсию можно устранить следующим образом:

  1. Воспользуемся алгоритмом удаления [math] \varepsilon [/math]-правил. Получим грамматику без [math] \varepsilon [/math]-правил для языка [math]L(\Gamma) \setminus \lbrace \varepsilon \rbrace[/math].
  2. Воспользуемся алгоритмом устранения произвольной левой рекурсии.
  3. Если [math]\varepsilon[/math] присутствовал в языке исходной грамматики, добавим новый начальный символ [math]S'[/math] и правила [math]S' \rightarrow S \, | \, \varepsilon [/math].


Литература

  • Хопкрофт Д., Мотвани Р., Ульман Д.Введение в теорию автоматов, языков и вычислений, 2-е изд. : Пер. с англ. — Москва, Издательский дом «Вильямс», 2002. — 528 с. : ISBN 5-8459-0261-4 (рус.)
  • Robert C. MooreRemoving Left Recursion from Context-Free Grammars