Устранение левой рекурсии — различия между версиями
| Shagal (обсуждение | вклад)  (→Устранение произвольной левой рекурсии) | Shagal (обсуждение | вклад)   (→Устранение произвольной левой рекурсии) | ||
| Строка 45: | Строка 45: | ||
| <div> | <div> | ||
|   for все нетерминалы <tex>A_i</tex>   |   for все нетерминалы <tex>A_i</tex>   | ||
| − |     for все нетерминалы <tex>A_j</tex>, такие, что <tex> 1 \leq j < i </tex>  | + |     for все нетерминалы <tex>A_j</tex>, такие, что <tex> 1 \leq j < i </tex>   | 
| − | + |       Если есть правило вида <tex>A_i \rightarrow A_j \alpha </tex> и правила вывода из <tex>A_j</tex>: <tex>A_j \rightarrow \delta_1 | \ldots | \delta_k</tex>. | |
| − | + |       Заменить каждое правило <tex>A_i \rightarrow A_j \alpha</tex> на <tex>A_i \rightarrow \delta_1\alpha| \ldots | \delta_k\alpha</tex>. | |
|     устранить непосредственную левую рекурсию для <tex>A_i</tex>. |     устранить непосредственную левую рекурсию для <tex>A_i</tex>. | ||
| </div> | </div> | ||
| − | + | Смысл вложенного цикла в том, чтобы избавиться от правил вида <tex>A_i \rightarrow A_j\alpha </tex> таких, что <tex> i < j </tex>. | |
| − | |||
| − | |||
| − | |||
| − | + | После вложенного цикла цепочка выводов вида <tex>A_i \rightarrow A_j \alpha \rightarrow A_k \ldots </tex> точно не придет в <tex>A_i</tex>, а значит для <tex>A_i</tex> может быть применен алгоритм удаление непосредственной левой рекурсии. | |
| − | |||
| − | |||
| ==Алгоритм  устранения левой рекурсии== | ==Алгоритм  устранения левой рекурсии== | ||
Версия 20:21, 16 декабря 2012
| Определение: | 
| Говорят, что контекстно-свободная(КС) грамматика содержит непосредственную левую рекурсию, если она содержит правило вида . | 
| Определение: | 
| Говорят, что КС-грамматика содержит левую рекурсию(left recursion), если в ней существует вывод вида . | 
Методы нисходящего разбора(top=down parsers) не в состоянии работать с леворекурсивными грамматиками. Проблема в том, что продукция вида  может применяться бесконечно долго, так и не выработав некий терминальный символ, который можно было бы сравнить со строкой. Поэтому требуется преобразование грамматики, которое бы устранило левую рекурсию.
Левая рекурсия может быть:
- непосредственной(immidiate)
- произвольной(indirect)
Содержание
Устранение непосредственной левой рекурсии
Опишем процедуру, устраняющую все правила вида , для фиксированного нетерминала .
- Запишем все правила вывода из  в виде: 
, где
- — непустая последовательность терминалов и нетерминалов ();
- — непустая последовательность терминалов и нетерминалов, не начинающаяся с .
 
- Заменим правила вывода из на .
- Создадим новый нетерминал .
Этот алгоритм не устраняет произвольную левую рекурсию,вызванную двумя или более шагами порождения.
Пример
S леворекурсивен, так как , но эта рекурсия не является непосредственной.
Устранение произвольной левой рекурсии
Пусть — упорядоченное множество всех нетерминалов.
for все нетерминалы for все нетерминалы , такие, что Если есть правило вида и правила вывода из : . Заменить каждое правило на . устранить непосредственную левую рекурсию для .
Смысл вложенного цикла в том, чтобы избавиться от правил вида таких, что .
После вложенного цикла цепочка выводов вида точно не придет в , а значит для может быть применен алгоритм удаление непосредственной левой рекурсии.
Алгоритм устранения левой рекурсии
Для произвольной грамматики левую рекурсию можно устранить следующим образом:
- Воспользуемся алгоритмом удаления -правил. Получим грамматику без -правил для языка .
- Воспользуемся алгоритмом устранения произвольной левой рекурсии.
- Если присутствовал в языке исходной грамматики, добавим новый начальный символ и правила .
Литература
- Хопкрофт Д., Мотвани Р., Ульман Д. — Введение в теорию автоматов, языков и вычислений, 2-е изд. : Пер. с англ. — Москва, Издательский дом «Вильямс», 2002. — 528 с. : ISBN 5-8459-0261-4 (рус.)
- Robert C. Moore — Removing Left Recursion from Context-Free Grammars
