Устранение левой рекурсии — различия между версиями
Строка 7: | Строка 7: | ||
==Алгоритм устранения левой рекурсии== | ==Алгоритм устранения левой рекурсии== | ||
− | Приведем алгоритм, позволяющий для к.с. грамматики | + | Приведем алгоритм, позволяющий для к.с. грамматики ''без <tex> \varepsilon </tex>-правил'' построить эквивалентную ей к.с. грамматику (без <tex> \varepsilon </tex>-правил), не содержащую левой рекурсии. |
Для произвольной грамматики <tex>\Gamma</tex> левую рекурсию можно устранить следующим образом: | Для произвольной грамматики <tex>\Gamma</tex> левую рекурсию можно устранить следующим образом: | ||
− | #Воспользоваться [[Удаление_eps-правил_из_грамматики | алгоритмом удаления | + | #Воспользоваться [[Удаление_eps-правил_из_грамматики | алгоритмом удаления <tex> \varepsilon </tex>-правил]]. Получим грамматику без <tex> \varepsilon </tex>-правил для языка <tex>L(\Gamma) \setminus \lbrace \epsilon \rbrace</tex> |
#Воспользоваться алгоритмом для новой грамматики | #Воспользоваться алгоритмом для новой грамматики | ||
#Если <tex>\epsilon</tex> присутствовал в языке исходной грамматики, добавить новый начальный символ <tex>S'</tex> и правила <tex>S' \rightarrow S \, | \, \epsilon </tex> | #Если <tex>\epsilon</tex> присутствовал в языке исходной грамматики, добавить новый начальный символ <tex>S'</tex> и правила <tex>S' \rightarrow S \, | \, \epsilon </tex> | ||
Строка 17: | Строка 17: | ||
Опишем процедуру, устраняющую все правила вида <tex>A \rightarrow A\alpha</tex> для фиксированного нетерминала <tex>A</tex>. | Опишем процедуру, устраняющую все правила вида <tex>A \rightarrow A\alpha</tex> для фиксированного нетерминала <tex>A</tex>. | ||
− | Запишем все правила вывода из <tex>A</tex> в виде | + | <ol> |
+ | <li>Запишем все правила вывода из <tex>A</tex> в виде | ||
+ | <tex>A \rightarrow A\alpha_1\,|\,\ldots\,|\,A\alpha_n\,|\,\beta_1\,|\,\ldots\,|\,\beta_m </tex>, где | ||
+ | <ul> | ||
+ | <li> <tex>\alpha</tex> - непустая последовательность терминалов и нетерминалов (<tex>\alpha \ne \epsilon </tex>)</li> | ||
+ | <li> <tex>\beta</tex> - непустая последовательность терминалов и нетерминалов, не начинающаяся с <tex>A</tex>.</li> | ||
+ | </ul> | ||
+ | <li>Заменим правила вывода из <tex>A</tex> на: <tex>A \rightarrow \beta_1A^\prime\, |\, \ldots\, |\, \beta_mA^\prime \,|\, \beta_1 \,|\, \ldots \,|\, \beta_m</tex> </li> | ||
− | < | + | <li>И создадим новый нетерминал <tex>A^\prime \rightarrow \alpha_1A^\prime\, |\, \ldots\, |\, \alpha_nA^\prime | \alpha_1\, |\, \ldots\, |\, \alpha_n</tex> </li> |
− | + | </li> | |
− | + | </ol> | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | И создадим новый нетерминал | ||
− | |||
− | <tex>A^\prime \rightarrow \alpha_1A^\prime\, |\, \ldots\, |\, \alpha_nA^\prime | \alpha_1\, |\, \ldots\, |\, \alpha_n</tex> | ||
===Устранение произвольной левой рекурсии=== | ===Устранение произвольной левой рекурсии=== |
Версия 03:21, 27 ноября 2011
Определение: |
Говорят, что контекстно-свободная(к.с.) грамматика содержит непосредственную левую рекурсию, если она содержит правило вида . |
Определение: |
Говорят, что к.с. грамматика | содержит левую рекурсию, если в ней существует вывод вида .
Содержание
Алгоритм устранения левой рекурсии
Приведем алгоритм, позволяющий для к.с. грамматики без
-правил построить эквивалентную ей к.с. грамматику (без -правил), не содержащую левой рекурсии.Для произвольной грамматики
левую рекурсию можно устранить следующим образом:- Воспользоваться алгоритмом удаления . Получим грамматику без -правил -правил для языка
- Воспользоваться алгоритмом для новой грамматики
- Если присутствовал в языке исходной грамматики, добавить новый начальный символ и правила
Устранение непосредственной левой рекурсии
Опишем процедуру, устраняющую все правила вида
для фиксированного нетерминала .- Запишем все правила вывода из
- - непустая последовательность терминалов и нетерминалов ( )
- - непустая последовательность терминалов и нетерминалов, не начинающаяся с .
в виде
, где
- Заменим правила вывода из на:
- И создадим новый нетерминал
Устранение произвольной левой рекурсии
Пусть множество всех нетерминалов
for i = 1 to n { for j = 1 to i – 1 { рассмотреть все правила вывода иззаменить каждое правило на } устранить непосредственную левую рекурсию для }
Инвариант: после
итераций внутреннего цикла для- для правые части правил вывода из не начинаются с
- правые части правил вывода из не начинаются с
- правые части правил вывода не начинаются с добавленных алгоритмом нетерминалов
- грамматика не содержит ε-правил
(проверяется индукцией по парам
)Таким образом, после применения алгоритма все правила вывода имеют вид
- , где - терминал, - произвольный нетерминал
- , где , - нетерминалы из исходной грамматики
- , где - новый нетерминал, - нетерминал из исходной грамматики
Если теперь перенумеровать нетерминалы, сохранив порядок для старых и присвоив всем новым меньшие номера, то все правила будут иметь вид
- , где - терминал
- , где
Литература
- Хопкрофт Д., Мотвани Р., Ульман Д. — Введение в теорию автоматов, языков и вычислений, 2-е изд. : Пер. с англ. — Москва, Издательский дом «Вильямс», 2002. — 528 с. : ISBN 5-8459-0261-4 (рус.)