Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
3. Синтаксический и семантический анализ.pdf
Скачиваний:
31
Добавлен:
12.01.2020
Размер:
446.5 Кб
Скачать

Метод рекурсивного спуска

void B();

else ERROR();}

void ERROR();/ функция

void B()

обработки ошибок /

{if (c == 'b')

void S()

{c = fgetc(fp); A();}

{A(); B();

else ERROR();}

if (c != ' ') ERROR();}

void ERROR()

void A()

{printf ("ERROR!!!"); exit(1);}

{if (c=='a')

main()

c = fgetc(fp);

{fp = fopen("data","r");

else

c = fgetc(fp);

if (c == 'c')

S();

{c = fgetc(fp);

printf("SUCCESS!!!");

A();}

exit(0);}

О применимости метода рекурсивного спуска

Метод рекурсивного спуска применим в том случае, если каждое правило грамматики имеет вид:

a)либо A → α, где α (T N)*, и это единственное правило вывода для этого нетерминала;

b)либо A a1α1 | a2α2 | ... | anαn, где ai T для всех i = 1, 2, ..., n; ai aj для i j; αi (T N)*, т. е. если для нетерминала А правил вывода несколько, то они должны начинаться с терминалов, причем все эти терминалы должныбыть различными.

Ясно, что если правила вывода имеют такой вид, то рекурсивный спуск может быть реализован по вышеизложенной схеме.

Естественно, возникает вопрос: если грамматика не удовлетворяет этим условиям, то существует ли эквивалентная КС-грамматика, для которой метод рекурсивного спуска применим?

К сожалению, нет алгоритма, отвечающего на поставленный вопрос, то есть это

алгоритмическинеразрешимаяпроблема.

О применимости метода рекурсивного спуска

Изложенные выше ограничения являются достаточными, но не необходимыми. Попытаемся ослабить требования на вид правил грамматики.

1.При описании синтаксиса языков программирования часто встречаются правила,

описывающие последовательность однотипных конструкций, отделенных друг от друга каким-либо знаком-разделителем (например, список идентификаторов при описании переменных, список параметровпри вызове процедур и функций и т.п.).

Общий вид этих правил:

L a | a,L (в сокращеннойформе L a {,a}).

Формально здесь не выполняются условия применимости метода рекурсивного спуска, так как две альтернативы начинаются одинаковыми терминальными символами.

О применимости метода рекурсивного спуска

Действительно, в строке a,a,a,a,a из нетерминала L может выводиться и подстрока a , и подстрока a,a , и вся строка a,a,a,a,a.

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

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

Тогда для методарекурсивного спуска процедура L будет такой:

void L()

{ if (c != 'a') ERROR();

while ((c = fgetc(fp)) == ',') if ((c = fgetc(fp)) != 'a')

ERROR();}