Устранение левой рекурсии — различия между версиями
Shagal (обсуждение | вклад) |
Shagal (обсуждение | вклад) (→Устранение непосредственной левой рекурсии) |
||
Строка 10: | Строка 10: | ||
==Устранение непосредственной левой рекурсии== | ==Устранение непосредственной левой рекурсии== | ||
− | Опишем процедуру, устраняющую все правила вида <tex>A \ | + | Опишем процедуру, устраняющую все правила вида <tex>A \Rightarrow A\alpha</tex>, для фиксированного нетерминала <tex>A</tex>. |
<ol> | <ol> | ||
<li>Запишем все правила вывода из <tex>A</tex> в виде: | <li>Запишем все правила вывода из <tex>A</tex> в виде: | ||
− | <tex>A \ | + | <tex>A \Rightarrow A\alpha_1\,|\,\ldots\,|\,A\alpha_n\,|\,\beta_1\,|\,\ldots\,|\,\beta_m </tex>, где |
<ul> | <ul> | ||
<li> <tex>\alpha</tex> {{---}} непустая последовательность терминалов и нетерминалов (<tex>\alpha \nrightarrow \varepsilon </tex>);</li> | <li> <tex>\alpha</tex> {{---}} непустая последовательность терминалов и нетерминалов (<tex>\alpha \nrightarrow \varepsilon </tex>);</li> | ||
<li> <tex>\beta</tex> {{---}} непустая последовательность терминалов и нетерминалов, не начинающаяся с <tex>A</tex>.</li> | <li> <tex>\beta</tex> {{---}} непустая последовательность терминалов и нетерминалов, не начинающаяся с <tex>A</tex>.</li> | ||
</ul> | </ul> | ||
− | <li>Заменим правила вывода из <tex>A</tex> на <tex>A \ | + | <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 \ | + | <li>Создадим новый нетерминал <tex>A^\prime \Rightarrow \alpha_1A^\prime\, |\, \ldots\, |\, \alpha_nA^\prime | \alpha_1\, |\, \ldots\, |\, \alpha_n</tex>. </li> |
</li> | </li> | ||
</ol> | </ol> | ||
Нетерминал A порождает те же строки, что и ранее, но без левой рекурсии. Эта процедура устраняет все непосредственные рекурсии из продукций для A, при условии, что ни одна строка <tex>\alpha_i</tex> не является <tex>\epsilon</tex>. | Нетерминал A порождает те же строки, что и ранее, но без левой рекурсии. Эта процедура устраняет все непосредственные рекурсии из продукций для A, при условии, что ни одна строка <tex>\alpha_i</tex> не является <tex>\epsilon</tex>. | ||
− | |||
==Алгоритм устранения произвольной левой рекурсии== | ==Алгоритм устранения произвольной левой рекурсии== |
Версия 11:51, 7 января 2013
Определение: |
Говорят, что контекстно-свободная(КС) грамматика содержит непосредственную левую рекурсию, если она содержит правило вида . |
Определение: |
Говорят, что КС-грамматика | содержит левую рекурсию(left recursion), если в ней существует вывод вида .
Методы нисходящего разбора(top-down parsers) не в состоянии работать с леворекурсивными грамматиками. Проблема в том, что продукция вида может применяться бесконечно долго, так и не выработав некий терминальный символ, который можно было бы сравнить со строкой. Поэтому требуется преобразование грамматики, которое бы устранило левую рекурсию.
Устранение непосредственной левой рекурсии
Опишем процедуру, устраняющую все правила вида
, для фиксированного нетерминала .- Запишем все правила вывода из
- — непустая последовательность терминалов и нетерминалов ( );
- — непустая последовательность терминалов и нетерминалов, не начинающаяся с .
в виде:
, где
- Заменим правила вывода из на .
- Создадим новый нетерминал .
Нетерминал A порождает те же строки, что и ранее, но без левой рекурсии. Эта процедура устраняет все непосредственные рекурсии из продукций для A, при условии, что ни одна строка
не является .Алгоритм устранения произвольной левой рекурсии
Пусть
— множество всех нетерминалов.for все нетерминалыfor все нетерминалы , такие, что и рассмотреть все правила вывода из : . заменить каждое правило на . устранить непосредственную левую рекурсию для .
Таким образом, после применения алгоритма все правила вывода имеют вид:
- , где — терминал, — произвольный нетерминал;
- , где , — нетерминалы из исходной грамматики;
- , где — новый нетерминал, — нетерминал из исходной грамматики.
Если теперь перенумеровать нетерминалы, сохранив порядок для старых и присвоив всем новым меньшие номера, то все правила будут иметь вид:
- , где — терминал;
- , где .
После
итерации внешнего цикла в любой продукции вида i > k будет l > k</tex>. В результате после каждой итерации растет нижний предел m, таких, что существует продукция вида до тех пор, пока не будет достигнуто . Затем из устраняется непосредственная левая рекурсия и достигается m > i.
Для произвольной грамматики
левую рекурсию можно устранить следующим образом:- Воспользуемся алгоритмом удаления . Получим грамматику без -правил -правил для языка .
- Воспользуемся алгоритмом устранения произвольной левой рекурсии.
- Если присутствовал в языке исходной грамматики, добавим новый начальный символ и правила .
Литература
- Хопкрофт Д., Мотвани Р., Ульман Д. — Введение в теорию автоматов, языков и вычислений, 2-е изд. : Пер. с англ. — Москва, Издательский дом «Вильямс», 2002. — 528 с. : ISBN 5-8459-0261-4 (рус.)
- Robert C. Moore — Removing Left Recursion from Context-Free Grammars