Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы, часть 2.doc
Скачиваний:
0
Добавлен:
12.01.2020
Размер:
80.41 Mб
Скачать

Условия использования метода рекурсивного спуска

Метод рекурсивного спуска без возвратов можно использовать только для грамматик, правила которых удовлетворяют следующему условию: первого символа каждого правила должно быть достаточно для того, чтобы определить, какое правило применимо в данном случае. Более точно это условие можно формализовать путем определения множества FIRST.

Определение.Для КС-грамматики G и цепочки w, состоящей из терминальных и нетерминальных символов, определим множество FIRST k (w) следующим образом:

FIRST k (w) = {x | w =>* xv, |x| = k или w =>* x, |x| < k}, где k - натуральное число.

Иными словами, множество FIRST k (w) состоит из всех терминальных префиксов длины k терминальных цепочек, выводимых из w.

Пример.Рассмотрим грамматику, порождающую подмножество типов языка Pascal.

Для этой грамматики мы имеем:

FIRST1 (simple) = {integer, char, num}

FIRST1 (^id) = {^}

FIRST1 (array [simple] of type) = { array }

Понятно, что если цепочка w состоит только из терминалов, то FIRST k (w) - это первые k символов цепочки w , если |w| >=, или это сама цепочкаw, если |w| < k <

Устранение левой рекурсии

Определение:

Говорят, что контекстно-свободная (КС) грамматика   содержит непосредственную левую рекурсию (direct left recursion), если она содержит правило вида  .

Определение:

Говорят, что КС-грамматика   содержит левую рекурсию (left recursion), если в ней существует вывод вида  .

Методы нисходящего разбора (top-down parsers) не в состоянии работать с леворекурсивными грамматиками. Проблема в том, что продукция вида   может применяться бесконечно долго, так и не выработав некий терминальный символ, который можно было бы сравнить со строкой. Поэтому требуется преобразование грамматики, которое бы устранило левую рекурсию.

[Править]Устранение непосредственной левой рекурсии

Опишем процедуру, устраняющую все правила вида  , для фиксированного нетерминала  .

  1. Запишем все правила вывода из   в виде:  , где

    •  — непустая последовательность терминалов и нетерминалов ( );

    •  — непустая последовательность терминалов и нетерминалов, не начинающаяся с  .

  2. Заменим правила вывода из   на  .

  3. Создадим новый нетерминал  .

Изначально нетерминал   порождает сроки вида  . В новой грамматике нетерминал   порождает  , а   порождает строки вида  . Из этого очевидно, что изначальная грамматика эквивалентна новой.

[Править]Пример

Есть непосредственная левая рекурсия  . Добавим нетерминал   и добавим правила  .

Новая грамматика:

В новой грамматике нет непосредственной левой рекурсии, но нетерминал   леворекурсивен, так как есть 

[Править]Алгоритм устранения произвольной левой рекурсии

Воспользуемся алгоритмом удаления  -правил. Получим грамматику без  -правил для языка  .

Упорядочим нетерминалы и будим добиваться того, чтобы не было правил вида  , где  . Если данное условие выполняется для всех , то в грамматике нет  , а значит не будет левой рекурсии.

Пусть   — упорядоченное множество всех нетерминалов.

for все нетерминалы

for все нетерминалы , такие, что и

рассмотреть все правила вывода из : .

заменить каждое правило на .

устранить непосредственную левую рекурсию для .

Если   присутствовал в языке исходной грамматики, добавим новый начальный символ   и правила  .

После   итерации внешнего цикла в любой продукции внешнего цикла в любой продукции вида  , должно быть  . В результате при следующей итерации внутреннего цикла растет нижний предел   всех продукций вида   до тех пор, пока не будет достигнуто  .

После   итерации внешнего цикла в грамматике будут только правила вида  , где  . Можно заметить, что неравенство становится строгим только после применения алгоритма устранения непосредственной левой рекурсии. При этом добавляются новые нетерминалы. Пусть   новый нетерминал. Можно заметить, что нет правила вида  , где   самый левый нетерминал, а значит новые нетерминалы можно не рассматривать во внешнем цикле.

На   итерации внешнего цикла все правила вида   где   заменяются на   где  . Очевидно, что одна итерация алгоритма не меняет язык, а значит язык получившийся в итоге грамматики совпадает с исходным.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]