Устранение левой рекурсии — различия между версиями
| Строка 35: | Строка 35: | ||
===Устранение произвольной левой рекурсии=== | ===Устранение произвольной левой рекурсии=== | ||
Пусть множество всех нетерминалов <tex>N = \lbrace A_1, A_2, \ldots , A_n \rbrace</tex> | Пусть множество всех нетерминалов <tex>N = \lbrace A_1, A_2, \ldots , A_n \rbrace</tex> | ||
| − | + | <div> | |
| − | + | for i = 1 to n { | |
| − | + | for j = 1 to i – 1 { | |
| − | + | рассмотреть все правила вывода из <tex>A_j</tex> | |
| − | + | <tex>A_j \rightarrow \delta_1 | \ldots | \delta_k</tex> | |
| − | + | заменить каждое правило <tex>A_i \rightarrow A_j \gamma</tex> на | |
| − | + | <tex>A_i \rightarrow \delta_1\gamma | \ldots | \delta_k\gamma</tex> | |
| − | + | } | |
| − | + | устранить непосредственную левую рекурсию для <tex>A_i</tex> | |
| + | } | ||
| + | </div> | ||
Инвариант: после <tex>j</tex> итераций внутреннего цикла для <tex>i</tex> | Инвариант: после <tex>j</tex> итераций внутреннего цикла для <tex>i</tex> | ||
*для <tex>k < i</tex> правые части правил вывода из <tex>A_k</tex> не начинаются с <tex>A_1, A_2, \ldots , A_k</tex> | *для <tex>k < i</tex> правые части правил вывода из <tex>A_k</tex> не начинаются с <tex>A_1, A_2, \ldots , A_k</tex> | ||
Версия 02:35, 27 ноября 2011
| Определение: |
| Говорят, что к.с. грамматика содержит непосредственную левую рекурсию, если она содержит правило вида . |
| Определение: |
| Говорят, что к.с. грамматика содержит левую рекурсию, если в ней существует вывод вида . |
Содержание
Алгоритм устранения левой рекурсии
Приведем алгоритм, позволяющий для к.с. грамматики без ε-правил построить эквивалентную ей к.с. грамматику (без ε-правил), не содержащую левой рекурсии.
Для произвольной грамматики левую рекурсию можно устранить следующим образом:
- Воспользоваться алгоритмом удаления ε-правил. Получим грамматику без ε-правил для языка
- Воспользоваться алгоритмом для новой грамматики
- Если присутствовал в языке исходной грамматики, добавить новый начальный символ и правила
Устранение непосредственной левой рекурсии
Опишем процедуру, устраняющую все правила вида для фиксированного нетерминала .
Запишем все правила вывода из в виде
где
- - непустая последовательность терминалов и нетерминалов ()
- - непустая последовательность терминалов и нетерминалов, не начинающаяся с .
Заменим правила вывода из на:
И создадим новый нетерминал
Устранение произвольной левой рекурсии
Пусть множество всех нетерминалов
for i = 1 to n {
for j = 1 to i – 1 {
рассмотреть все правила вывода из
заменить каждое правило на
}
устранить непосредственную левую рекурсию для
}
Инвариант: после итераций внутреннего цикла для
- для правые части правил вывода из не начинаются с
- правые части правил вывода из не начинаются с
- правые части правил вывода не начинаются с добавленных алгоритмом нетерминалов
- грамматика не содержит ε-правил
(проверяется индукцией по парам )
Таким образом, после применения алгоритма все правила вывода имеют вид
- , где - терминал, - произвольный нетерминал
- , где , - нетерминалы из исходной грамматики
- , где - новый нетерминал, - нетерминал из исходной грамматики
Если теперь перенумеровать нетерминалы, сохранив порядок для старых и присвоив всем новым меньшие номера, то все правила будут иметь вид
- , где - терминал
- , где
Литература
- Хопкрофт Д., Мотвани Р., Ульман Д. — Введение в теорию автоматов, языков и вычислений, 2-е изд. : Пер. с англ. — Москва, Издательский дом «Вильямс», 2002. — 528 с. : ISBN 5-8459-0261-4 (рус.)