Устранение левой рекурсии — различия между версиями
MikhailOK (обсуждение | вклад) м |
MikhailOK (обсуждение | вклад) |
||
Строка 17: | Строка 17: | ||
Запишем все правила вывода из <tex>A</tex> в виде | Запишем все правила вывода из <tex>A</tex> в виде | ||
− | < | + | <tex>A \rightarrow A\alpha_1\,|\,\ldots\,|\,A\alpha_n\,|\,\beta_1\,|\,\ldots\,|\,\beta_m </tex> |
где | где | ||
Строка 25: | Строка 25: | ||
Заменим правила вывода из <tex>A</tex> на: | Заменим правила вывода из <tex>A</tex> на: | ||
− | < | + | <tex>A \rightarrow \beta_1A^\prime\, |\, \ldots\, |\, \beta_mA^\prime \,|\, \beta_1 \,|\, \ldots \,|\, \beta_m</tex> |
И создадим новый нетерминал | И создадим новый нетерминал | ||
− | < | + | <tex>A^\prime \rightarrow \alpha_1A^\prime\, |\, \ldots\, |\, \alpha_nA^\prime</tex> |
===Устранение произвольной левой рекурсии=== | ===Устранение произвольной левой рекурсии=== | ||
Строка 35: | Строка 35: | ||
: for i = 1 to n { | : for i = 1 to n { | ||
::for j = 1 to i – 1 { | ::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> |
:} | :} | ||
Инвариант: после <tex>j</tex> итераций внутреннего цикла для <tex>i</tex> | Инвариант: после <tex>j</tex> итераций внутреннего цикла для <tex>i</tex> |
Версия 23:26, 28 октября 2010
Определение: |
Говорят, что к.с. грамматика | содержит непосредственную левую рекурсию, если она содержит правило вида .
Определение: |
Говорят, что к.с. грамматика | содержит левую рекурсию, если в ней существует вывод вида .
Алгоритм устранения левой рекурсии
Приведем алгоритм, позволяющий для к.с. грамматики без ε-правил построить эквивалентную ей к.с. грамматику (без ε-правил), не содержащую левой рекурсии.
Для произвольной грамматики
левую рекурсию можно устранить следующим образом:- Воспользоваться алгоритмом удаления ε-правил. Получим грамматику без ε-правил для языка
- Воспользоваться алгоритмом для новой грамматики
- Если присутствовал в языке исходной грамматики, добавить новый начальный символ и правила
Устранение непосредственной левой рекурсии
Опишем процедуру, устраняющую все правила вида
для фиксированного нетерминала .Запишем все правила вывода из
в виде
где
- - непустая последовательность терминалов и нетерминалов ( )
- - непустая последовательность терминалов и нетерминалов, не начинающаяся с .
Заменим правила вывода из
на:
И создадим новый нетерминал
Устранение произвольной левой рекурсии
Пусть множество всех нетерминалов
- for i = 1 to n {
- for j = 1 to i – 1 {
- рассмотреть все правила вывода из
- заменить каждое правило на
- }
- устранить непосредственную левую рекурсию для
- for j = 1 to i – 1 {
- }
Инвариант: после
итераций внутреннего цикла для- для правые части правил вывода из не начинаются с
- правые части правил вывода из не начинаются с
- правые части правил вывода не начинаются с добавленных алгоритмом нетерминалов
- грамматика не содержит ε-правил
(проверяется индукцией по парам
)Таким образом, после применения алгоритма все правила вывода имеют вид
- , где - терминал, - произвольный нетерминал
- , где , - нетерминалы из исходной грамматики
- , где - новый нетерминал, - нетерминал из исходной грамматики
Если теперь перенумеровать нетерминалы, сохранив порядок для старых и присвоив всем новым меньшие номера, то все правила будут иметь вид
- , где - терминал
- , где