
- •Введение
- •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 Ошибки, связанные с нарушением ограничений
- •Заключение
- •Список литературы
- •Глоссарий

87
Отношения ≡ для k ≥ 0 имеют следующие классы эквивалентности:
–класс отношения ≡0 – {A, F}, {B, C, D, E};
–класс отношения ≡1 – {A, F}, {B, E}, {C, D};
–класс отношения ≡2 – {A, F}, {B, E}, {C, D}.
Так как ≡2 = ≡1, то ≡ = ≡1. Приведенный автомат M' будет ({[A], [B], [C], {a, b}, δ', A, {[A]}}), где δ' определяется следующей табл. 3.4.
Таблица 3.4 – Приведенный конечный автомат
Состояние |
a |
b |
|
|
|
[A] |
[A] |
[B] |
|
|
|
[B] |
[B] |
[C] |
|
|
|
[C] |
[C] |
[A] |
|
|
|
Здесь:
–[A] – выбрано для представления класса {A, F};
–[B] – выбрано для представления класса {B, E};
–[C] – выбрано для представления класса {C, D}.
·· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
3.10 КОНТЕКСТНО-СВОБОДНЫЕ ЯЗЫКИ
Из четырех классов грамматики иерархии Хомского класс контекстно-
свободных языков наиболее важен с точки зрения приложения к языкам про-
граммирования и компиляции. С их помощью можно определить большую часть синтаксических структур языков программирования. Кроме того, они служат основой различных схем перевода, т.к. в ходе процесса компиляции синтаксическую структуру, передаваемую входной программе КС-
грамматикой, можно использовать при построении перевода этой программы
[1].
Синтаксическую структуру входной цепочки можно определить по по-
следовательности правил, применяемых при выводе этой цепочки. Таким об-
88
разом, на часть компилятора, называемую синтаксическим анализатором,
можно смотреть как на устройство, которое пытается выяснить, существует ли в некоторой фиксированной КС-грамматике вывод входной цепочки.
Естественно, что эта задача нетривиальная – по данной КС-грамматике
G и входной цепочке w выяснить, принадлежит ли w языку L(G), и если «да»,
то найти вывод цепочки w в грамматике G.
3.10.1ДЕРЕВЬЯ ВЫВОДОВ
Вграмматике может быть несколько выводов, эквивалентных в том смысле, что во всех них применяются одни и те же правила в одних и тех же местах, но в различном порядке. КС-грамматика позволяет ввести удобное графическое представление класса эквивалентных выводов, называемое де-
ревом выводов [5].
Дерево вывода в КС-грамматике G = (N, Σ, P, S) – это помеченное упо-
рядоченное дерево, каждая вершина которого помечена символом из множества N Σ{e}, где:
–N – конечное множество нетерминальных символов;
–Σ – непересекающееся с N множество терминальных символов;
–P – конечное подмножество множества N(N Σ)* (элемент (A, α)
множества P называется правилом или продукцией A α);
–S – выделенный символ из N, называемый начальным или исходным символом.
Если внутренняя вершина помечена символом A, а ее прямые потомки
– символами X1, X2, …, Xn, то A X1 | X2 | … | Xn – правило грамматики.
Помеченное упорядоченное дерево D называется деревом вывода (или деревом разбора) в КС-грамматике G(A) = (N, Σ, P, A), если выполняются следующие условия:
1) корень дерева помечен A;

89
2)если D1, D2, …, Dk – поддеревья, над которыми доминируют прямые потомки корня дерева, и корень Di помечен Xi, то A X1 | X2 | … | Xn
– правило из множества P. Di должно быть деревом вывода в грам-
матике G(Xi) = (N, Σ, P, Xi), если Xi – нетерминал, и Di состоит из единственной вершины, помеченной Xi, если Xi – терминал.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Имеем грамматику G = G(S) с правилами S aSbS | bSaS | e (рис. 3.7).
Возможные варианты деревьев вывода:
S 1 aSbS 2 abSaSb 3 abab S 1 bSaS 2 babSaS 3 baba S 1 e
S S S
S |
|
S |
S |
|
S |
a |
b |
b |
a |
|
e |
S |
S |
|
|
S |
S |
b |
a |
e |
e b |
|
a |
e |
e |
e |
e |
Рисунок 3.7 – Деревья выводов
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Заметим, что существует единственное упорядочение вершин упорядо-
ченного дерева, у которого прямые потомки вершины упорядочиваются
«слева направо».

90
Допустим, что n – вершина и n1, n2, …, nk – ее прямые потомки. Тогда,
если i < j, то вершина ni и все ее потомки считаются расположенными левее вершины ni и всех ее потомков.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Кроной дерева вывода назовем цепочку, которая получит-
ся, если выписать слева направо метки листьев.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Например, кроны деревьев на рис. 3.7 – abab, baba, e.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Сечением дерева D назовем такое множество C вершин дерева D, что
1)никакие две вершины из C не лежат на одном пути в D;
2)ни одну вершину дерева D нельзя добавить к C, не нарушив свой-
ства 1).
Частные случаи:
–множество вершин дерева, состоящего из одного корня, является сечением;
–листья также образуют сечение.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Кроной сечения дерева D является цепочка, получаемая конкатенацией (в порядке слева направо) меток вершин, образу-
ющих некоторое сечение.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Крона сечения дерева, приведенного на рис. 3.8 – abaSbS.

91
S
S |
|
S |
a |
|
b |
S |
|
S |
|
|
|
b |
a |
e |
e e
Рисунок 3.8 – Пример сечения дерева
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Пусть S = α1, α2, …, αn – вывод цепочки αn из S в КС-
грамматике G = (N, Σ, P, S). Тогда в G можно построить дерево вывода D, для которого αn – крона, а α1, α2, …, αn–1 – некоторые из крон сечения.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Пусть D – дерево вывода в КС-грамматике G = (N, Σ, P, S) с
кроной α. Тогда S * α (транзитивное и рефлексивное замыкание
*, т.е. α выводима из S).
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Доказательство. Пусть C0, C1, …, Cn – такая последовательность сече-
ний дерева D, что
1) C0 – содержит только один корень дерева D;

92
2)Ci+1 для 0 ≤ i < n получается из Ci заменой одной нетерминальной вершины ее прямыми потомками;
3)Cn – крона дерева D.
Ясно, что хотя бы одна такая последовательность существует.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Если αi – крона сечения Ci, то существующий вывод α1, α2,
…, αn называется левым выводом цепочки αn из α0 в грамматике
G. Правый вывод определяется аналогично.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Если S = α1, α2, …, αn–1 = w – левый вывод терминальной цепочки w, то каждая цепочка αi (0 ≤ i < n) имеет вид xiAiβi, где xi Σ*, Ai N и βi(N Σ)*.
Каждая следующая цепочка αi+1 левого вывода получается из преды-
дущей цепочки αi заменой самого левого нетерминала Ai правой частью неко-
торого правила.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Рассмотрим КС-грамматику G0 с правилами:
EE+T | T
TT*F | F
F(E) | a.
Нарисуем дерево вывода (рис. 3.9).