
- •Введение
- •1 Предварительные математические сведения
- •1.1 Множества
- •1.2 Операции и отношения
- •1.2.1 Операции над множествами
- •1.2.2 Отношения на множествах
- •1.3.1 Цепочки
- •1.3.2 Операции над цепочками
- •1.4.2 Операции над языком
- •1.5 Алгоритмы
- •1.5.1 Частичные алгоритмы
- •1.5.2 Всюду определенные алгоритмы
- •1.5.3 Рекурсивные алгоритмы
- •1.5.4 Задание алгоритмов
- •1.5.5 Проблемы
- •1.6 Некоторые понятия теории графов
- •1.6.1 Ориентированные графы
- •1.6.2 Ориентированные ациклические графы
- •1.6.3 Деревья
- •1.6.4 Упорядоченные графы
- •2 Введение в компиляцию
- •2.1 Задание языков программирования
- •2.2 Синтаксис и семантика
- •2.3 Процесс компиляции
- •2.4 Лексический анализ
- •2.5 Работа с таблицами
- •2.6 Синтаксический анализ
- •2.7 Генератор кода
- •2.8 Оптимизация кода
- •2.9 Исправление ошибок
- •2.10 Резюме
- •3 Теория языков
- •3.1 Способы определения языков
- •3.2 Грамматики
- •3.3 Грамматики с ограничениями на правила
- •3.4 Распознаватели
- •3.5.1 Определения
- •3.8 Конечные автоматы и регулярные множества
- •3.9.1 Постановка задачи
- •3.10 Контекстно-свободные языки
- •3.10.2 Преобразование КС-грамматик
- •3.10.2.1. Алгоритм проверки пустоты языка
- •3.10.2.2. Алгоритм устранения недостижимых символов
- •3.10.2.3. Алгоритм устранения бесполезных символов
- •3.10.2.5. Алгоритм устранения цепных правил
- •3.10.3 Грамматика без циклов
- •3.10.4 Нормальная форма Хомского
- •3.10.5 Нормальная форма Грейбах
- •3.11 Автоматы с магазинной памятью
- •3.11.1 Основные определения
- •4.1 LL(k)-грамматики
- •4.2.2 Алгоритм поиска направляющих символов
- •4.2.2.1 Множество предшествующих символов
- •4.2.2.2 Множество последующих символов
- •4.2.2.3 Множество направляющих символов
- •4.3 LL(1)-таблица разбора
- •4.3.1 Построение таблицы
- •5 Синтаксический анализ снизу вверх
- •5.1 LR(k)-грамматики
- •5.2 LR(1)-грамматики
- •5.3 LR(1)-таблица разбора
- •5.3.1 Состояния анализатора
- •5.3.2 Построение таблицы
- •5.3.3 LR-конфликты
- •5.3.4 Разбор цепочки по таблице
- •5.4 Сравнение LL- и LR-методов разбора
- •6 Включение действий в синтаксис
- •6.2 Работа с таблицей символов
- •7 Проектирование компиляторов
- •7.1 Число проходов
- •7.2 Таблицы символов
- •7.2.2 Бинарное дерево
- •7.4.1 Стек времени прогона
- •7.4.2 Методы вызова параметров
- •7.4.3 Обстановка выполнения процедур
- •8 Генерация кода
- •8.1 Генерация промежуточного кода
- •8.2 Структура данных для генерации кода
- •8.3.1 Присвоение
- •8.3.2 Условные зависимости
- •8.3.3 Описание идентификаторов
- •8.3.4 Циклы
- •8.3.5 Вход и выход из блока
- •8.3.6 Прикладные реализации
- •8.4 Проблемы, связанные с типами
- •8.5 Время компиляции и время прогона
- •9 Исправление и диагностика ошибок
- •9.1 Типы ошибок
- •9.2 Лексические ошибки
- •9.3 Ошибки в употреблении скобок
- •9.4 Синтаксические ошибки
- •9.4.1 Методы исправления синтаксических ошибок
- •9.4.2 Предупреждения
- •9.4.3 Сообщения о синтаксических ошибках
- •9.5 Контекстно-зависимые ошибки
- •9.6 Ошибки, связанные с употреблением типов
- •9.7 Ошибки, допускаемые во время прогона
- •9.8 Ошибки, связанные с нарушением ограничений
- •Заключение
- •Список литературы
- •Глоссарий
139
8 |
{d} |
9 |
true |
false |
false |
true |
|
|
|
|
|
|
|
9 |
{comma, semi} |
10 |
false |
false |
false |
true |
|
|
|
|
|
|
|
10 |
{comma} |
12 |
false |
false |
false |
false |
|
|
|
|
|
|
|
11 |
{semi} |
14 |
false |
false |
false |
true |
|
|
|
|
|
|
|
12 |
{comma} |
13 |
true |
false |
false |
true |
|
|
|
|
|
|
|
13 |
{d} |
7 |
false |
false |
false |
true |
|
|
|
|
|
|
|
14 |
{semi} |
0 |
false |
false |
true |
true |
|
|
|
|
|
|
|
15 |
{s} |
16 |
false |
false |
false |
true |
|
|
|
|
|
|
|
16 |
{s} |
17 |
true |
true |
false |
true |
|
|
|
|
|
|
|
17 |
{comma, end} |
18 |
false |
false |
false |
true |
|
|
|
|
|
|
|
18 |
{comma} |
20 |
false |
false |
false |
false |
|
|
|
|
|
|
|
19 |
{end} |
22 |
false |
false |
false |
true |
|
|
|
|
|
|
|
20 |
{comma} |
21 |
true |
false |
false |
true |
|
|
|
|
|
|
|
21 |
{s} |
15 |
false |
false |
false |
true |
|
|
|
|
|
|
|
22 |
{end} |
0 |
false |
false |
true |
true |
|
|
|
|
|
|
|
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
4.3.1 ПОСТРОЕНИЕ ТАБЛИЦЫ
Алгоритм построения таблицы разбора следующий:
1. Разметить грамматику. При этом порядковые номера i M присваи-
ваются всем элементам грамматики, от первого правила к последнему, от ле-
вого символа к правому. Как видно из рис. 4.3, при наличии у порождающего правила альтернатив сначала нумеруются левые части всех альтернативных правил, а уже затем их правые части. Еще одним важным требованием явля-
ется то, что все альтернативные правила должны следовать друг за другом в списке правил.
2. Построить два вспомогательных множества ML M и MR M. В пер-
вое включить порядковые номера i M элементов грамматики, расположен-
140
ных в левой части порождающего правила, во второе – порядковые номера элементов, которыми заканчиваются правые части порождающих правил:
ML = {i | (Xi α) P}, MR = {j | (A αXj) P}.
3. Построить таблицу, состоящую из столбцов terminals, jump, accept, stack, return, error. Количество строк таблицы определяется количеством элементов во множестве M – по одной строке на каждый элемент граммати-
ки.
4. Заполнить ячейки таблицы.
4.1. Для нетерминала множество terminals совпадает с множеством направляющих символов. Для терминала множество terminals включает лишь сам терминал. Для пустой цепочки множество terminals совпадает с множеством направляющих символов соответствующего правила, у которого данная пустая цепочка стоит в правой части:
|
T X |
|
|
|
|
X |
|
N , |
|
|
|
|
|
||||
|
|
i |
|
|
|
|
i |
|
|
|
|
|
|
|
|||
terminalsi |
|
|
Xi , |
|||||
|
||||||||
Xi |
|
|||||||
|
|
|
|
|
|
Xi e X j Xi P. |
||
|
|
|
|
|
||||
|
T X j |
|
|
|||||
|
|
|
|
|
|
|
|
|
4.2. Переход jump от нетерминала в левой части правила осуществля-
ется к первому символу правой части этого правила. Переход от нетерминала в правой части правила осуществляется на такой же нетерминал в левой ча-
сти. Причем если имеется несколько альтернатив соответствующего порож-
дающего правила, переход осуществляется к первой из альтернатив. От тер-
минала, не последнего в цепочке правой части правила, переход осуществля-
ется к следующему символу цепочки. Если терминал завершает цепочку либо это символ e (он в правой части может быть только один, поэтому будет од-
новременно начинать и завершать ее), то значение jump равно нулю:

|
|
|
|
|
|
|
141 |
||
|
k |
|
|
i M L Xi X k α P , |
|||||
|
|
|
|||||||
|
|
|
|
Xi N i M L |
X k Xi j M L j 1 M L , |
||||
|
k |
|
|
||||||
jumpi |
|
|
|
|
i i M R |
|
|
|
|
|
|
|
|
|
|
||||
|
i 1 |
, |
|
|
|||||
|
0 |
|
i e i M |
|
. |
||||
|
|
|
|||||||
|
|
|
|
|
R |
|
4.3. Символ принимается (accept), если это терминал:
|
true |
|
X |
i |
, |
|
|
||||
|
|
|
|
|
|
accepti |
|
|
Xi . |
||
|
|||||
|
false |
|
|||
|
|
|
|
|
|
4.4. Номер строки таблицы разбора помещается в стек (stack), если со-
ответствующий символ грамматики – нетерминал в правой части порождаю-
щего правила, но не в конце цепочки правой части:
|
true |
|
X |
N i M |
L |
i M |
R |
, |
|
|
|||||||
|
|
|
i |
|
|
|
||
stacki |
|
|
Xi N i M L i M R . |
|||||
|
||||||||
|
false |
|
||||||
|
|
|
|
|
|
|
|
|
4.5. Возврат (return) по стеку при разборе осуществляется, если символ грамматики является терминалом, расположенным в конце цепочки правой части порождающего правила, или символом e (т.е. когда jumpi = 0):
|
|
|
i e i M R , |
|
|
||
|
true |
|
|
returni |
|
|
i e i M R . |
|
|||
|
false |
|
|
|
|
|
|
4.6. Ошибка (error) при разборе не генерируется, если следующий символ грамматики находится в левой части альтернативного порождающего правила:
|
false |
|
i M |
L |
i 1 M |
L |
, |
||
|
|
||||||||
|
|
|
|
|
|
||||
errori |
|
|
|
|
i M L i 1 M L . |
|
|||
|
|
|
|||||||
|
true |
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
142
Маркировка грамматики для языка математических выражений будет иметь следующий вид:
E1 T2 E′3
E′4 +6 T7 E′8
E′5 e9
T10 F11 T′12
T′13 *15 F16 T′17
T′14 e18
F19 (21 E22 )23
F20 a24
Здесь уже не допускается использование символа «|» для записи аль-
тернативных порождающих правил, т.к. их левые части будут маркироваться разными метками. В грамматике 24 элемента Xi, i M, M = {1, 2, …, 24}, сле-
довательно, в таблице разбора будет 24 строки. При этом:
ML = {1, 4, 5, 10, 13, 14, 19, 20},
MR = {3, 8, 9, 12, 17, 18, 23, 24}.
Строим таблицу разбора (табл. 4.11).
Таблица 4.11 – Таблица разбора
i |
X |
terminals |
jump |
accept |
stack |
return |
error |
|
|
|
|
|
|
|
|
1 |
E |
(, a |
2 |
|
|
|
|
|
|
|
|
|
|
|
|
2 |
T |
(, a |
10 |
|
true |
|
|
|
|
|
|
|
|
|
|
3 |
E′ |
+, ), |
4 |
|
|
|
|
|
|
|
|
|
|
|
|
4 |
E′ |
+ |
6 |
|
|
|
false |
|
|
|
|
|
|
|
|
5 |
E′ |
), |
9 |
|
|
|
|
|
|
|
|
|
|
|
|
6 |
+ |
+ |
7 |
true |
|
|
|
|
|
|
|
|
|
|
|
7 |
T |
(, a |
10 |
|
true |
|
|
|
|
|
|
|
|
|
|
8 |
E′ |
+, ), |
4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
9 |
|
e |
), |
0 |
|
|
|
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
T |
(, a |
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
F |
(, a |
19 |
|
|
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
T′ |
+, *, ), |
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
T′ |
* |
15 |
|
|
|
|
|
false |
|
|
|
|
|
|
|
|
|
|
|
14 |
|
T′ |
+, ), |
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
* |
* |
16 |
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
F |
(, a |
19 |
|
|
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
T′ |
+, *, ), |
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
e |
+, ), |
0 |
|
|
|
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
F |
( |
21 |
|
|
|
|
|
false |
|
|
|
|
|
|
|
|
|
|
|
20 |
|
F |
a |
24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
( |
( |
22 |
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
E |
(, a |
1 |
|
|
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
) |
) |
0 |
|
true |
|
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
24 |
|
a |
a |
0 |
|
true |
|
|
true |
|
|
|
|
|
|
|
|
|
|
|
|
Все |
остальные ячейки |
accept, |
stack и |
return содержат false, а все |
остальные ячейки error – true.
·· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
4.3.2РАЗБОР ЦЕПОЧКИ ПО ТАБЛИЦЕ
Для разбора цепочки α = a1a2…an нам потребуется магазин (стек) M.
Операцию помещения элемента в стек будем обозначать как M ← x, опера-
цию извлечения элемента из стека – как M → x. Номер текущей строки таб-
лицы разбора обозначим как i, номер текущего символа во входной строке – k.
Алгоритм разбора цепочки по таблице:
1. Положить i := 1 (разбор начинается с первой строки таблицы).

144
2.Положить k := 1 (разбор идет слева направо, начиная с первого сим-
вола цепочки).
3.M ← 0 (поместить в стек значение 0).
4.Если ak terminalsi, то:
4.1.Если accepti = true, то k := k + 1 (перейти к следующему симво-
лу входной цепочки).
4.2.Если stacki = true, то M ← i (поместить в стек номер текущей строки таблицы разбора).
4.3.Если returni = true, то:
4.3.1.M → i;
4.3.2.Если i = 0, то перейти на шаг 6;
4.3.3.i := i + 1;
4.3.4.Вернуться на шаг 4.
4.4.Если jumpi ≠ 0, то:
4.4.1.i := jumpi;
4.4.2.Вернуться на шаг 4.
5.Иначе если errori = false, то у правила есть еще одна альтернатива и нужно просто перейти к следующей строке таблицы разбора:
5.1.i := i + 1;
5.2.Вернуться на шаг 4.
6.В противном случае разбор окончен. Если при этом стек M пуст, а ak
= , то разбор завершен успешно. Иначе цепочка содержит синтак-
сическую ошибку и k – позиция этой ошибки.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Рассмотрим разбор предложения
begin d comma d semi s semi end
по табл. 4.10. Действия приведены в табл. 4.12.
145
Таблица 4.12 – Разбор предложения
№ |
Действия |
Стек |
|
|
разбора |
|
|
|
1 |
begin считывается и проверяется; перейти к 2 |
0 |
|
|
|
2 |
begin считывается и принимается; перейти к 3 |
0 |
|
|
|
3 |
d считывается и проверяется; 3 помещается в стек; пе- |
3 |
|
рейти к 7 |
0 |
|
|
|
7 |
d принимается; перейти к 8 |
3 |
|
|
0 |
|
|
|
8 |
d проверяется и принимается; перейти к 9 |
3 |
|
|
0 |
|
|
|
9 |
comma считывается и проверяется; перейти к 10 |
3 |
|
|
0 |
|
|
|
10 |
comma проверяется; перейти к 12 |
3 |
|
|
0 |
|
|
|
12 |
comma проверяется и принимается; перейти к 13 |
3 |
|
|
0 |
|
|
|
13 |
d считывается и проверяется; перейти к 7 |
3 |
|
|
0 |
|
|
|
7 |
d проверяется; перейти к 8 |
3 |
|
|
0 |
|
|
|
8 |
d проверяется и принимается; перейти к 9 |
3 |
|
|
0 |
|
|
|
9 |
comma считывается и проверяется; перейти к 10 |
3 |
|
|
0 |
|
|
|
10 |
semi не совпадает с comma; ошибка – «ложь», перейти к |
3 |
|
11 |
0 |
|
|
|
11 |
comma проверяется; перейти к 14 |
3 |
|
|
|
146
|
|
0 |
|
|
|
14 |
semi проверяется; возврат – «истина», удаляется 3; пе- |
0 |
|
рейти к 4 |
|
|
|
|
4 |
semi проверяется и принимается; перейти к 5 |
0 |
|
|
|
5 |
s считывается и проверяется; 5 помещается в стек; пе- |
5 |
|
рейти к 15 |
0 |
|
|
|
15 |
s проверяется; перейти к 16 |
5 |
|
|
0 |
|
|
|
16 |
s проверяется и принимается; перейти к 17 |
5 |
|
|
0 |
|
|
|
17 |
comma считывается и проверяется; перейти к 18 |
5 |
|
|
0 |
|
|
|
18 |
comma проверяется; перейти к 20 |
5 |
|
|
0 |
|
|
|
20 |
comma проверяется и принимается; перейти к 21 |
5 |
|
|
0 |
|
|
|
21 |
s считывается и проверяется; перейти к 15 |
5 |
|
|
0 |
|
|
|
15 |
s проверяется; перейти к 16 |
5 |
|
|
0 |
|
|
|
16 |
s проверяется и принимается; перейти к 17 |
5 |
|
|
0 |
|
|
|
17 |
end считывается и проверяется; перейти к 18 |
5 |
|
|
0 |
|
|
|
18 |
end не совпадает с comma; ошибка – «ложь», перейти к |
5 |
|
19 |
0 |
|
|
|
19 |
end проверяется; перейти к 22 |
5 |
|
|
|

147
|
|
0 |
|
|
|
22 |
end проверяется; возврат – «истина», удалить 5; перей- |
0 |
|
ти к 6 |
|
|
|
|
6 |
end проверяется и принимается; возврат – «истина», |
|
|
удалить 0; разбор заканчивается |
|
|
|
|
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Метод разбора LL(1) имеет ряд преимуществ:
1)Никогда не требует возврата, поскольку этот метод детерминирован.
2)Время разбора пропорционально длине программы.
3)Имеются хорошие диагностические характеристики, существует возможность исправления ошибок, т.к. синтаксические ошибки рас-
познаются по первому неприемлемому символу, а в таблице разбора есть список возможных символов предложения.
4)Таблица разбора меньше, чем соответствующие таблицы в других методах разбора.
5)LL(1)-разбор применим к широкому классу современных языков.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Контрольные вопросы по главе 4
·· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
1.Эквивалентность МП-автоматов и КС-грамматик.
2.LL(k)-грамматики.
3.s-грамматика.
4.LL(1)-грамматика.
5.Алгоритм определения принадлежности данной грамматики к
LL(1)-грамматике.
6.LL(1)-таблица разбора.
7.Разбор по таблице.