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

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

Алгоритм 4.4. Вычисление FIRST для цепочки.

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

Выход. Множество FIRST(X_1 X_2  \ldots X_n), X_i \in (N \cup T).

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

(1) При помощи алгоритма 4.3. вычислить FIRST(X) для каждого X \in (N \cup T).

(2) Положить FIRST(X_{1}X_{2} \dots  X_{n}) = \varnothing.

(3)

{i = 1; nonstop = true;
   while (i <= && nonstop)
    {добавить FIRST(Xi) n {e} к FIRST(u);
      if (e not in FIRST(Xi) nonstop = false;
        else i+ = 1;
    }
if (nonstop) {добавить e к FIRST(u);
    } }

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

Алгоритм 4.5. Вычисление FOLLOW для нетерминалов грамматики.

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

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

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

(1) Положить FOLLOW(X) = \varnothing для каждого символа X \in N.

(2) Добавить $ к FOLLOW(S).

(3) Если в P eсть правило вывода A \to  \alpha B \beta, где \alpha, \beta \in (N \cup T)^*, то все элементы из FIRST(\beta ), за исключением e, добавить к FOLLOW(B).

(4) Пока ничего нельзя будет добавить ни к какому множеству FOLLOW(X), выполнять:

если в P есть правило A \to  \alpha B или A \to  \alpha B\beta, \alpha, \beta \in (N \cup T)^*, где FIRST(\beta ) содержит e (\beta \Rightarrow *e), то все элементы из FOLLOW(A) добавить к FOLLOW(B).

Пример 4.4. Рассмотрим грамматику из примера 4.3. Для нее

FIRST(E) = FIRST(T) = FIRST(F) = {(, id}
FIRST(E') = {+, e}
FIRST(T') = {*, e}
FOLLOW(E) = FOLLOW(E') = { ), $}
FOLLOW(T) = FOLLOW(T') = {+, ), $}
FOLLOW(F) = {+, *, ), $}

Например, id и левая скобка добавляются к FIRST(F) на шаге 3 при i = 1, поскольку FIRST(id) = {id} и FIRST("(") = {"("} в соответствии с шагом 1. На шаге 3 при i = 1, в соответствии с правилом вывода T -> FT', к FIRST(T) добавляются также id и левая скобка. На шаге 2 в FIRST(E') включается e.

Также при вычислении множеств FOLLOW на шаге 2 в FOLLOW(E) включается $. На шаге 3, на основании правила F -> (E), к FOLLOW(E) добавляется также правая скобка. На шаге 4, примененном к правилу E -> TE', в FOLLOW(E') включаются $ и правая скобка. Поскольку E' \Rightarrow^* e, они также попадают и во множество FOLLOW(T). В соответствии с правилом вывода E -> TE', на шаге 3 в FOLLOW(T) включаются и все элементы из FIRST(E'), отличные от e.

Определим теперь функцию FIRSTk(R), где k - натуральное число и \alpha \in (N \cup \Sigma)^*.

FIRST_k(\alpha) = \{w \in \Sigma^* \mid либо |w| < k и \alpha \Rightarrow_G w, либо \mid \! w \! \mid = k \; \text{и} \; R \Rightarrow_G wx для некоторого x \in \Sigma^*\}.

Если \alpha \in \Sigma^*, то FIRST_{k}(\alpha ) = \{ w\}, где w - это первые k символов цепочки \alpha при |\alpha | \ge  k и w = \alpha при |\alpha | < k.

Приведем алгоритм вычисления функции FIRST_{k}(\beta ), где \beta= X_1X_2 \ldots X_n \in (N \cup \Sigma)^*.

Определение. Пусть \Sigma - некоторый алфавит. Если L1 и L2 - подмножества \Sigma ^{*}, то положим

\begin{align*}
L_1 \oplus_k L_2 = \{&w \! \mid \; \text{для некоторых} \; x \in L_1 \; \text{и} \; y \in L2 \\
&\text{либо} \; w = xy, \; \text{если} \mid \! xy \! \mid \leq k,\\
&\text{либо }  w  \text{ состоит из первых } k \text{ символов}\\
&\text{цепочки } xy\}
\end{align*}

Лемма 4.1. Для любой КС-грамматики G = (N, \Sigma ,P, S) и любых \alpha, \beta \in (N \cup \Sigma)^*

FIRST_k(\alpha\beta) = FIRST_k(\alpha) \oplus_k FIRST_k(\beta)

Доказательство оставляем читателю в качестве упражнения.

Aлгоритм 4.6. Вычисление функции FIRST_{k}(\alpha ).

Вход. КС-грамматика G = (N, \Sigma , P, S) и цепочка \alpha =
X_1X_2 \ldots X_n \in (N \cup \Sigma)^*.

Выход. FIRST_{k}(\beta ).

Метод.Так как по последней лемме

\begin{align*}
FIRST_k(\beta) = &FIRST_k(X_1) \oplus_k FIRST_k(X_2) \oplus_k \ldots \\
&\ldots \oplus_k FIRST_k(X_n);
\end{align*}

то достаточно показать, как найти FIRSTk(X) для X \in N.

Если X \in \Sigma \cup \{e\}, то очевидно, что FIRSTk(X) = {X}.

Определим множества Fi(X) для каждого X \in N \cup \Sigma и возрастающих значений i >= 0:

(1) Fi(a) = {a} для всех a \in \Sigma и i >= 0:

(2) F_0(A) = \{x \mid x \in \Sigma^{*k} и существует правило A \to  x\alpha из P, для которого либо |x| = k, либо |x| < k и \alpha  = e\.

(3) Допустим, что F0, F1..., Fi-1 уже определены для всех A \in N. Тогда

F_{i}(A) = F_{i-1}(A) \cup  \{ x|A \to  Y_{1}\dots Y_{n} принадлежит P и x \in F_{i-1}(Y_1) \oplus_k F_{i-1}(Y_2) \oplus_k \ldots \oplus_k F_{i-1}(Y_n)\}

(4) Так как F_{i-1}(A) \subseteq F_i(A) \subseteq \Sigma^{*k} для всех A и i, то в конце концов мы дойдем до такого i, что Fi-1(A) = Fi(A) для всех A \in N. Тогда положим FIRSTk(A) = Fi(A) для этого значения i.

Конструирование таблицы предсказывающего анализатора

Для конструирования таблицы предсказывающего анализатора по грамматике G может быть использован алгоритм, основанный на следующей идее. Предположим, что A \to  \alpha - правило вывода грамматики и a \in FIRST(R). Тогда анализатор делает развертку A по \alpha, если входным символом является a. Трудность возникает, когда \alpha  = e или \alpha \Rightarrow^* e. В этом случае нужно развернуть A в \alpha, если текущий входной символ принадлежит FOLLOW(A) или если достигнут $ и \$ \in FOLLOW(A).

Алгоритм 4.7. Построение таблицы предсказывающего анализатора.

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

Выход. Таблица M[A; a] предсказывающего анализатора, A \in N, a \in T \cup \{ \$ \}.

Метод. Для каждого правила вывода A\to \alpha грамматики выполнить шаги 1 и 2. После этого выполнить шаг 3.

(1) Для каждого терминала a из FIRST(R) добавить A->R к M[A; a].

(2) Если e \in FIRST(R), добавить A -> R к M[A; b] для каждого терминала b из FOLLOW(A). Кроме того, если e \in FIRST(R) и \$ \in FOLLOW(A), добавить A \to  \alpha к M[A; $].

(3) Положить все неопределенные входы равными "ошибка".

Пример 4.5. Применим алгоритм 4.7 к грамматике из примера 4.3. Поскольку FIRST(TE') = FIRST(T) = {(, id }, в соответствии с правилом вывода E -> TE' входы M[E, ( ] и M[E, id ] становятся равными E -> TE'.

В соответствии с правилом вывода E' -> +TE' значение M[E', +] равно E' -> +TE'. В соответствии с правилом вывода E' -> e значения M[E', )] и M[E', $] равны E' -> e, поскольку FOLLOW(E') = { ), $}.

Таблица анализа, построенная по алгоритму 4.7. для этой грамматики, приведена в таблица 4.3.

LL(1)-грамматики

Алгоритм 4.7 построения таблицы предсказывающего анализатора может быть применен к любой КС-грамматике. Однако для некоторых грамматик построенная таблица может иметь неоднозначно определенные входы. Например, нетрудно доказать, что если грамматика леворекурсивна или неоднозначна, таблица будет иметь по крайней мере один неоднозначно определенный вход.

Грамматики, для которых таблица предсказывающего анализатора не имеет неоднозначно определенных входов, называются LL(1)-грамматиками. Предсказывающий анализатор, построенный для LL(1)-грамматики, называется LL(1)-анализатором. Первая буква L в названии связано с тем, что входная цепочка читается слева направо, вторая L означает, что строится левый вывод входной цепочки, 1 - что на каждом шаге для принятия решения используется один символ непрочитанной части входной цепочки.

Доказано, что алгоритм 4.7 для каждой из LL(1)-грам- матик G строит таблицу предсказывающего анализатора, распознающего все цепочки из L(G) и только эти цепочки. Нетрудно доказать также, что если G - LL(1)-грамматика, то L(G) - детерминированный КС-язык.

Справедлив также следующий критерий LL(1)-граммати- ки. Грамматика G = (N, T, P, S) является LL(1)-грамматикой тогда и только тогда, когда для каждой пары правил A \to  \alpha, A \to  \beta из P

(то есть правил с одинаковой левой частью) выполняются следующие 2 условия:

(1) FIRST(\alpha) \cap FIRST(\beta) = \oslash;

(2) Если e \in FIRST(\alpha), то FIRST(\beta ) \cap  FOLLOW(A)= \varnothing.

Язык, для которого существует порождающая LL(1)- грамматика, называют LL(1)-языком. Доказано, что проблема определения, порождает ли грамматика LL-язык, является алгоритмически неразрешимой.

Пример 4.6.Неоднозначная грамматика не является LL(1). Примером может служить следующая грамматика

G = ({S, E}, {if, then, else, a, b}, P, S) с правилами:
	S -> if E then S | if E then S else S | a
	E -> b

Эта грамматика является неоднозначной, что иллюстрируется на рис. 4.4.