Синтаксический анализ
Алгоритм 4.4. Вычисление FIRST для цепочки.
Вход. КС-грамматика G = (N, T, P, S).
Выход. Множество .
Метод. Выполнить шаги 1-3:
(1) При помощи алгоритма 4.3. вычислить FIRST(X) для каждого .
(2) Положить .
(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) для каждого символа .
Метод. Выполнить шаги 1-4:
(1) Положить для каждого символа .
(2) Добавить $ к FOLLOW(S).
(3) Если в P eсть правило вывода , где , то все элементы из , за исключением e, добавить к FOLLOW(B).
(4) Пока ничего нельзя будет добавить ни к какому множеству FOLLOW(X), выполнять:
если в P есть правило или , , где содержит , то все элементы из 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') включаются $ и правая скобка. Поскольку , они также попадают и во множество FOLLOW(T). В соответствии с правилом вывода E -> TE', на шаге 3 в FOLLOW(T) включаются и все элементы из FIRST(E'), отличные от e.
Определим теперь функцию FIRSTk(R), где k - натуральное число и .
либо |w| < k и , либо для некоторого .
Если , то , где w - это первые k символов цепочки при и при .
Приведем алгоритм вычисления функции , где .
Определение. Пусть - некоторый алфавит. Если L1 и L2 - подмножества , то положим
Лемма 4.1. Для любой КС-грамматики и любых
Доказательство оставляем читателю в качестве упражнения.
Aлгоритм 4.6. Вычисление функции .
Вход. КС-грамматика и цепочка .
Выход. .
Метод.Так как по последней лемме
то достаточно показать, как найти FIRSTk(X) для .
Если , то очевидно, что FIRSTk(X) = {X}.
Определим множества Fi(X) для каждого и возрастающих значений i >= 0:
(1) Fi(a) = {a} для всех и i >= 0:
(2) и существует правило из P, для которого либо |x| = k, либо |x| < k и .
(3) Допустим, что F0, F1..., Fi-1 уже определены для всех . Тогда
принадлежит P и
(4) Так как для всех A и i, то в конце концов мы дойдем до такого i, что Fi-1(A) = Fi(A) для всех . Тогда положим FIRSTk(A) = Fi(A) для этого значения i.
Конструирование таблицы предсказывающего анализатора
Для конструирования таблицы предсказывающего анализатора по грамматике G может быть использован алгоритм, основанный на следующей идее. Предположим, что - правило вывода грамматики и . Тогда анализатор делает развертку A по , если входным символом является a. Трудность возникает, когда или . В этом случае нужно развернуть A в если текущий входной символ принадлежит FOLLOW(A) или если достигнут $ и .
Алгоритм 4.7. Построение таблицы предсказывающего анализатора.
Вход. КС-грамматика G = (N, T, P, S).
Выход. Таблица M[A; a] предсказывающего анализатора, .
Метод. Для каждого правила вывода грамматики выполнить шаги 1 и 2. После этого выполнить шаг 3.
(1) Для каждого терминала a из FIRST(R) добавить A->R к M[A; a].
(2) Если , добавить A -> R к M[A; b] для каждого терминала b из FOLLOW(A). Кроме того, если и , добавить к 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)-грамматикой тогда и только тогда, когда для каждой пары правил , из P
(то есть правил с одинаковой левой частью) выполняются следующие 2 условия:
(1)
(2) Если , то .
Язык, для которого существует порождающая 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.