Класс LR-грамматик является более широким, чем класс LL. Это объясняется тем, что на каждом шаге работы расширенного МПА обрабатывается больше информации, чем при работе обычного МПА. Существует и строгое доказательство этого факта. Вообще, для каждого языка, заданного LL-грамматикой, может быть построена LR-грамматика, задающая тот же язык (при этом значения k в них не обязаны совпадать).
Свойства LR(k)-грамматик.
§ Всякая LR(k)-грамматика для любого k³0 является однозначной.
§ Существует алгоритм проверки, является ли заданная КС-грамматика LR(k)-грамматикой для строго определённого числа k.
§ Класс LR-грамматик полностью совпадает с классом детерминированных КС-языков.
Проблемы LR(k)-грамматик:
§ Не существует алгоритма, позволяющего проверить, является ли заданная КС-грамматика LR(k)-грамматикой для любого числа k.
§ Не существует алгоритма преобразования произвольной КС-грамматики к виду LR(k)-грамматики для некоторого k (либо доказывающего, что такое преобразование невозможно).
Класс LR-грамматик удобен для построения распознавателей детерминированных КС-языков, следовательно, для распознавания языков программирования.
Для формального определения LR(k)-свойства для КС-грамматик, нужно ввести ещё одно определение.
Грамматика является пополненной, если её целевой символ не встречается нигде в правых частях правил. Для приведения произвольной КС-грамматики к такому виду необходимо к множеству правил добавить S¢®S, а S¢ сделать целевым символом.
Формальное определение LR(k)-свойства.
Если для произвольной КС-грамматики G в её пополненной грамматике G¢ для двух произвольных цепочек вывода из условий:
1. S¢ Þ* aAwÞ abw
2. S¢ Þ* gBxÞ aby
3. FIRST(k,w)= FIRST(k,y)
следует, что aAy = gBx, т.е. a = g, A = B, x = y, то доказано, что грамматика G обладает LR(k)-свойством (так же, как и её пополненная грамматика G¢).
Понятие пополненной грамматики введено для того, чтобы появление символа S¢ на вершине стека означало окончание работы алгоритма.
Распознаватель для LR(k)-грамматик основан на специальной управляющей таблице T. Эта таблица состоит из двух частей, называемых «действия» и «переходы».
По строкам таблицы распределены все цепочки символов на верхушке стека, которые могут приниматься во внимание в процессе работы распознавателя; по столбцам в части «действия»– все возможные части входной цепочки длины не более k символов, которые могут следовать за считывающей головкой в процессе выполнения разбора; в части «переходы» – все терминальные и нетерминальные символы, которые могут появляться на верхушке стека в процессе выполнения действий.
Клетки управляющей таблицы в части «действия» содержат информацию о необходимых в каждой ситуации действиях, в частности:
§ «сдвиг», если требуется выполнение сдвига (переноса текущего символа из входной цепочки в стек);
§ «успех», если возможна свёртка к целевому символу грамматики S и разбор завершен;
§ целое число («свёртка»), если возможно выполнение свёртки (число обозначает номер правила грамматики, по которому должна выполняться свёртка);
§ «ошибка» – во всех других ситуациях.
Клетки управляющей таблицы T в части «переходы» служат для определения номера строки таблицы, которая будет использоваться для выполнения действия на очередном шаге. Эти клетки содержат данные:
§ целое число – номер строки таблицы T;
§ «ошибка» – во всех других ситуациях.
Для удобства работы используются два дополнительных символа начала и конца цепочки: ^н и ^к. Тогда в начальном состоянии работы распознавателя символ ^н находится на верхушке стека, а считывающая головка обозревает первый символ входной цепочки. В конечном состоянии в стеке должны находиться целевой символ и ^к, а считывающая головка должна обозревать символ ^к.
Алгоритм работы распознавателя:
Шаг 1 Занести в стек символ начала цепочки ^н и начальную (нулевую) строку управляющей таблицы T (её номер), в конец цепочки поместить символ ^к.
Шаг 2 Прочитать с вершины стека строку управляющей таблицы T (её номер). Выбрать из неё часть «действие» в соответствии с аванцепочкой.
Шаг 3 В соответствии с типом действия:
– «сдвиг»: если это не ^к, то прочитать и запомнить как «новый символ» очередной символ входной цепочки, сдвинув считывающую головку вправо на 1 символ; иначе остановка с ошибкой;
– «целое число, свёртка»: выбрать соответствующее числу правило (пусть это A ® b), убрать из стека 2×½b½ символов, запомнить A как «новый символ»;
– «ошибка»: остановка с ошибкой;
– «успех»: свернуть к S, если текущий символ ^к, то завершить с успехом, иначе завершить с ошибкой.
Шаг 4 Прочитать с вершины стека строку таблицы T (её номер). Выбрать часть «переход» в соответствии с «новым символом».
Шаг 5 Если «переход» содержит «ошибка», то остановка алгоритма с ошибкой. Иначе (если «переход» содержит номер) – в стек занести «новый символ» и строку таблицы (выбранный номер). Вернуться на шаг 2.
Рассмотрим пример для LR(0)-грамматики.
Пример.
Рассмотрим грамматику G({a,b}, {S}, {S®aSS|b}, S).
Данная грамматика определяет язык, в цепочках которого количество символов ‘a’ на один меньше, чем ‘b’, первый символ всегда ‘a’, в конце всегда пара ‘bb’. Исключение – минимальная цепочка ‘b’.
Поскольку символ S входит в правую часть правил, необходимо преобразовать грамматику G в пополненную G¢. Правила P¢ перенумеруем.
G¢({a,b},{S,S¢},P¢,S¢); P¢: (1) S¢®S; (2) S®aSS, (3) S®b.
№ строки |
Стек |
Действие |
Переход |
||
S |
a |
b |
|||
0 |
^н |
сдвиг |
1 |
2 |
3 |
1 |
S |
успех, 1 |
|||
2 |
a |
сдвиг |
4 |
2 |
3 |
3 |
b |
свёртка, 3 |
|||
4 |
aS |
сдвиг |
5 |
2 |
3 |
5 |
aSS |
свёртка, 2 |
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.