
- •Глава 1. Введение 2
- •Глава 2. Лексический анализ 6
- •2.4. Построение детерминированного конечного
- •Глава 3. Синтаксический анализ 20
- •Глава 8. Генерация кода 76
- •Глава 9. Системы автоматизации построения трансляторов 120
- •Глава 1. Введение
- •1.1. Место компилятора в программном обеспечении
- •1.2. Структура компилятора
- •Глава 2. Лексический анализ
- •2.1. Регулярные множества и регулярные выражения
- •2.2. Конечные автоматы
- •2.5. Программирование лексических анализаторов
- •2.6. Конструктор лексических анализаторов lex
- •Глава 3. Синтаксический анализ
- •3.1. Основные понятия и определения
- •3.2. Таблично-управляемый предсказывающий разбор
- •3.2.1. Алгоритм разбора сверху-вниз
- •3.2.2. Множества first и follow.
- •3.2.4. Ll(1)-грамматики
- •3.2.5. Удаление левой рекурсии
- •3.2.6. Левая факторизация
- •3.2.7. Рекурсивный спуск
- •3.2.8. Диаграммы переходов для рекурсивного спуска
- •3.2.9. Восстановление после синтаксических ошибок
- •3.3. Разбор снизу-вверх типа сдвиг-свертка
- •3.3.1. Основа
- •3.3.2. Lr(k)-анализаторы
- •3.3.4. Конфликты разбора типа сдвиг-свертка
- •3.3.5. Восстановление после синтаксических ошибок
- •Глава 4. Промежуточные представления программы
- •4.1. Представление в виде ориентированного графа
- •4.2. Трехадресный код
- •4.3. Линеаризованные представления
- •4.4. Организация информации в генераторе кода
- •4.5. Уровень промежуточного представления
- •Глава 5. Элементы теории перевода
- •5.1. Преобразователи с магазинной памятью
- •5.2. Синтаксически управляемый перевод
- •5.3. Атрибутные грамматики
- •5.3.1. Определение атрибутных грамматик
- •5.3.2. Атрибутированное дерево разбора
- •5.3.3. Язык описания атрибутных грамматик
- •Глава 6. Контекстные условия языков программирования
- •6.1. Описание областей видимости и блочной структуры
- •6.2. Структура среды Модулы-2
- •6.3. Занесение в среду и поиск объектов
- •Глава 7. Организация таблиц символов компилятора
- •7.1. Таблицы идентификаторов и таблицы символов
- •7.2. Таблицы идентификаторов
- •7.3. Таблицы символов и таблицы расстановки
- •7.4. Функции расстановки.
- •7.5. Таблицы на деревьях
- •7.7. Сравнение различных методов реализации таблиц
- •Глава 8. Генерация кода
- •8.1. Модель машины
- •8.2. Динамическая организация памяти
- •8.3. Назначение адресов
- •8.4. Трансляция переменных.
3.3.4. Конфликты разбора типа сдвиг-свертка
Если грамматика не является LR(1), то анализатор типа
сдвигсвертка для нее может достигнуть конфигурации, в которой он, зная
содержимое магазина и следующий входной символ, не может решить,
делать ли сдвиг или свертку (конфликт сдвиг/свертка), или не может
решить, какую из нескольких сверток применить (конфликт
свертка/свертка). В частности, неоднозначная грамматика не может быть
LR.
Пример 3.9. Рассмотрим вновь следующую грамматику оператора
if-then-else:
St -> if Ex then St
| if Ex then St else St
| ...
Если анализатор типа сдвиг-свертка находится в конфигурации
Магазин Вход
... if Ex then St else ... $
то нельзя определить, является ли if Ex then St основой, вне
зависимости от того, что лежит в магазине ниже. Это конфликт
сдвиг/свертка. В зависимости от того, что следует на входе за else,
правильной может быть свертка по St -> if Ex then St или сдвиг else, а
затем разбор другого St и завершение альтернативы if Ex then St else
St. Таким образом нельзя сказать, нужно ли в этом случае делать сдвиг
или свертку, так что грамматика не LR(1).
Эта грамматика может быть преобразована к LR(1)-виду
следующим образом:
St -> CondSt | UnCondSt
CondSt -> IfThenSt | IfThenElseSt
FullSt -> IfThenElseSt | UnCondSt
IfThenElseSt -> if Ex then FullSt else St
IfThenSt ->if Ex then St
3.3.5. Восстановление после синтаксических ошибок
Одним из простейших методов является следующий. При
синтаксической ошибке просматриваем магазин от верхушки, пока не
найдем состояние s с переходом на выделенный нетерминал A. Затем
сканируются входные символы, пока не будет найден такой, который
допустим после A. В этом случае на верхушку магазина помещается
состояние goto[s,A] и разбор продолжается. Для нетерминала A может
иметься несколько таких вариантов. Обычно A - это нетерминал,
представляющий одну из основных конструкций языка, например оператор.
Тогда s - это, например, точка с запятой или end.
При более детальной проработке реакции на ошибки можно в каждой
пустой клетке анализатора поставить обращение к своей подпрограмме.
Такая подпрограмма может вставлять или удалять входные символы или
символы магазина, менять порядок входных символов.
Глава 4. Промежуточные представления программы
В процессе трансляции программы часто используют промежуточное
представление (ПП) программы, предназначенное прежде всего для
удобства генерации кода и/или проведения различных оптимизаций
программы. Сама форма ПП зависит от целей его использования. Наиболее
часто используемыми формами ПП является ориентированный граф (или, в
частности, абстрактное синтаксическое дерево), тройки, четверки,
префиксная или постфиксная запись, атрибутированное абстрактное
дерево.
4.1. Представление в виде ориентированного графа
Простейшей формой промежуточного представления является
синтаксическое дерево программы. Более полную информацию о входной
программе дает ориентированный ациклический граф (ОАГ), в котором в
одну вершину объединены вершины синтаксического дерева, представляющие
общие подвыражения. Синтаксическое дерево и ОАГ для оператора
присваивания a:=b*- c+b*-c приведены на рис. 4.1.
На рис. 4.2. приведены два представления в памяти синтаксического
дерева на рис. 4.1.а). Каждая вершина кодируется записью с полем для
операции и полями для указателей на потомков. На рис. 4.2.б) вершины
размещены в массиве записей и индексом (или входом) вершины служит
указатель на нее.