Опубликован: 06.08.2007 | Доступ: свободный | Студентов: 1164 / 402 | Оценка: 4.45 / 4.29 | Длительность: 18:50:00
Специальности: Программист
Лекция 5:

Синтаксический анализ

Разбор сверху-вниз (предсказывающий разбор)

Алгоритм разбора сверху-вниз

Пусть дана КС-грамматика G = (N; T; P; S). Рассмотрим разбор сверху-вниз (предсказывающий разбор) для грамматики G.

Главная задача предсказывающего разбора - определение правила вывода, которое нужно применить к нетерминалу. Процесс предсказывающего разбора с точки зрения построения дерева разбора проиллюстрирован на рис. 4.1

Фрагменты недостроенного дерева соответствуют сентенциальным формам. Вначале дерево состоит только из одной вершины, соответствующей аксиоме S. В этот момент по первому символу входной цепочки предсказывающий анализатор должен определить правило S -> X1X2 ... ; которое должно быть применено к S. Затем необходимо определить правило, которое должно быть применено к X1, и т.д., до тех пор, пока в процессе такого построения сентенциальной формы, соответствующей левому выводу, не будет применено правило Y -> a ...: Этот процесс затем применяется для следующего самого левого нетерминального символа сентенциальной формы.

На рис. 4.2 условно показана структура предсказывающего анализатора, который определяет


Рис. 4.1.

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


Рис. 4.2.

Таблица анализа - это двумерный массив M[A; a], где A - нетерминал, и a - терминал или символ $. Значением M[A; a] может быть некоторое правило грамматики или элемент "ошибка".

Магазин может содержать последовательность символов грамматики с $ на дне. В начальный момент магазин содержит только начальный символ грамматики на верхушке и $ на дне.

Анализатор работает следующим образом. Вначале анализатор находится в конфигурации, в которой магазин содержит S$, на входной ленте w$ ( w - анализируемая цепочка), выходная лента пуста. На каждом такте анализатор рассматривает X - символ на верхушке магазина и a - текущий входной символ. Эти два символа определяют действия анализатора. Имеются следующие возможности.

  1. Если X=a=$, анализатор останавливается, сообщает об успешном окончании разбора и выдает содержимое выходной ленты.
  2. Если X= a \ne  $, анализатор удаляет X из магазина и продвигает указатель входа на следующий входной символ.
  3. Если X - терминал, и X \ne  a, то анализатор останавливается и сообщает о том, что входная цепочка не принадлежит языку.
  4. Если X - нетерминал, анализатор заглядывает в таблицу M[X; a]. Возможны два случая:
    1. Значением M[X; a] является правило для X. В этом случае анализатор заменяет X на верхушке магазина на правую часть данного правила, а само правило помещает на выходную ленту. Указатель входа не передвигается.
    2. Значением M[X; a] является "ошибка". В этом случае анализатор останавливается и сообщает о том, что входная цепочка не принадлежит языку. Работа анализатора может быть задана следующей программой:
Поместить '$', затем S в магазин;
do
	{X=верхний символ магазина;
if (X - терминал)
	if (X==InSym)
		{удалить X из магазина;
		InSym=очередной символ;
		}
	else {error(); break;}
else if (X - нетерминал)
	if (M[X,InSym]=="X->Y1Y2...Yk")
	 {удалить X из магазина;
	  поместить Yk,Yk-1,...Y1 в магазин
		(Y1 на верхушку);
	  вывести правило X->Y1Y2...Yk;
	 }
	else {error(); break;} /*вход таблицы M пуст*/
 }
while (X!='$'); /*магазин пуст*/
if (InSym != '$') error(); /*Не вся строка прочитана*/

Пример 4.3. Рассмотрим грамматику арифметических выражений G=({E; E', T, T', F}, {id, +, *, (, )}, P, E) с правилами:

\begin{align*}
&E\rightarrow TE'      &T&' \rightarrow *FT' \\
&E'\rightarrow +TE'    &T&' \rightarrow e \\
&E'\rightarrow e       &F& \rightarrow (E) \\
&T\rightarrow FT'      &F& \rightarrow id. \\
\end{align*}

В таблица 4.3 приведена предсказывающего анализатора для этой грамматики. Пустые клетки таблицы соответствуют элементу "ошибка".

Таблица 4.3.
Нетерминал Входной символ
id + * ( ) $
E E->TE' E->TE'
E' E'->+TE' E'->e E'->e
T T->FT' T->FT'
T' T'->e T'->*FT' T'->e T'->e
F F->id F->(E)

При разборе входной цепочки id + id * id$ анализатор совершает последовательность шагов, изображенную в таблица 4.4. Заметим, что анализатор осуществляет в точности левый вывод. Если за уже просмотренными входными символами поместить символы грамматики в магазине, то можно получить в точности левые сентенциальные формы вывода. Дерево разбора для этой цепочки приведено на рис. рис. 4.3.

Таблица 4.4.
Магазин Вход Выход
E$ id + id * id$
TE'$ id + id * id$ E -> TE'
FT'E'$ id + id * id$ T -> FT'
id T'E'$ id + id * id$ F -> id
T'E'$ +id * id$
E'$ +id * id$ T' -> e
+TE'$ +id * id$ E' -> +TE
TE'$ id * id$
FT'E'$ id * id$ T -> FT'
id T'E'$ id * id$ F -> id
T'E'$ *id$
*F'T'E'$ *id$ T' -> *FT'
FT'E'$ id$
id T'E'$ id$ F -> id
T'E'$ $
E'$ $ T' -> e
$ $ E' -> e

Функции FIRST и FOLLOW

При построении таблицы предсказывающего анализатора нам потребуются две функции - FIRST и FOLLOW.

Пусть G = (N, T, P, S) - КС-грамматика. Для \alpha - произвольной цепочки, состоящей из символов грамматики, определим FIRST(\alpha ) как множество терминалов, с которых


Рис. 4.3.

начинаются строки, выводимые из \alpha. Если \alpha  \Rightarrow ^{*} e, то e также принадлежит FIRST(\alpha ).

Определим FOLLOW(A) для нетерминала A как множество терминалов a, которые могут появиться непосредственно справа от A в некоторой сентенциальной форме грамматики, то есть множество терминалов a таких, что существует вывод вида S \Rightarrow ^{*} \alpha Aa\beta для некоторых \alpha, \beta \in (N \cup T)^*. Заметим, что между A и a в процессе вывода могут находиться нетерминальные символы, из которых выводится e. Если A может быть самым правым символом некоторой сентенциальной формы, то $ также принадлежит FOLLOW(A).

Рассмотрим алгоритмы вычисления функции FIRST.

Алгоритм 4.3. Вычисление FIRST для символов КС- грамматики.

Вход. КС-грамматика G = (N, T, P, S).

Выход. Множество FIRST(X) для каждого символа X \in (N \cup T).

Метод. Выполнить шаги 1-3:

(1) Если X - терминал, то положить FIRST(X) = {X}; если X - нетерминал, положить FIRST(X) = \varnothing.

(2) Если в P имеется правило X -> e, то добавить e к FIRST(X).

(3) Пока ни к какому множеству FIRST(X) нельзя уже будет добавить новые элементы, выполнять:

do { continue = false;
  Для каждого нетерминала X
	Для каждого правила X -> Y1Y2...Yk
	{i=1; nonstop = true;
	while (i <= k && nonstop)
	 {добавить FIRST(Yi) n {e} к FIRST(X);
	 if (Были добавлены новые элементы)
		continue = true;
	 if (e != FIRST (Yi)) nonstop = false;
	 else i+ = 1;
	 }
    if (nonstop) {добавить e к FIRST(X);
		continue = true;
  } } }
while (continue);