
- •Введение
- •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 Ошибки, связанные с нарушением ограничений
- •Заключение
- •Список литературы
- •Глоссарий
135
T a
Это не LL(1)-грамматика, т.к. для всех трех альтернатив порождающих правил с символом E в левой части получим T(E) = {(, a}.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Для нетерминала A в правой части правила B αAβ его направляющие символы определяются так:
|
|
|
|
|
|
|
|
|
|
S Aβ |
|
|
e F B |
|
e S Aβ , |
||
|
|
|
|
|||||
T A |
|
|
|
e S Aβ . |
|
|
|
|
S Aβ |
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
4.3 LL(1)-ТАБЛИЦА РАЗБОРА
Найдя LL(1)-грамматику для языка, можно перейти к следующему эта-
пу – применению найденной грамматики в фазе разбора. Обычно модуль компилятора, занимающийся семантическим разбором, называется драйве-
ром. Драйвер указывает на то место в синтаксисе, которое соответствует те-
кущему входному символу. Составной частью драйвера является стек, кото-
рый служит для запоминания адресов возврата всякий раз, когда он входит в новое порождающее правило, соответствующее какому-нибудь нетерминалу.
Опишем сначала возможный вид таблицы разбора, а затем рассмотрим возможные способы ее оптимизации относительно используемых вычисли-
тельных ресурсов.
Таблица разбора LL(1)-грамматики в общем виде представляет собой одномерный массив структур следующего вида [2]:
declare 1 TABLE,
2 terminals LIST,
2 jump int,
2 accept bool,
2 stack bool,
2 return bool,
136
2 error bool;
где
declare 1 LIST,
2 term string,
2 next pointer;
Кроме того, для работы драйвера нужен стек адресов возврата и указа-
тель стека.
Втаблице каждому шагу процесса разбора соответствует один элемент.
Впроцессе разбора осуществляются следующие шаги:
1)Проверка предварительно просматриваемого символа, для того что-
бы выяснить, не является ли он направляющим для какой-либо кон-
кретной правой части порождающего правила. Если этот символ – не направляющий и имеется альтернативная правая часть правила,
то она проверяется на следующем этапе. В особом случае, когда правая часть начинается с терминала, множество направляющих символов состоит только из одного терминала.
2)Проверка терминала, появляющегося в правой части порождающего правила.
3)Проверка нетерминала. Она заключается в проверке нахождения предварительно просматриваемого символа в одном из множеств направляющих символов для данного нетерминала, помещению в стек адреса возврата и переходу к первому правилу, относящемуся к этому нетерминалу. Если нетерминал появился в конце правой ча-
сти правила, то нет необходимости помещать в стек адрес его воз-
врата.
Таким образом, в таблицу разбора включается по одному элементу на каждое правило грамматики и на каждый экземпляр терминала или нетерминала правой части правил. Кроме того, в таблице будут находиться

137
элементы на реализацию пустой строки в правой части правил (по одному на каждую реализацию).
Драйвер содержит процедуру, которая обрабатывает элементы таблицы разбора и определяет следующий элемент для обработки. Поле перехода
обычно дает следующий элемент обработки, если значение поля возврата не окажется истиной. В последнем случае адрес следующего элемента берется из стека, что соответствует концу правила. Если же предварительно просмат-
риваемый символ отсутствует в списке терминалов и значение поля ошибки
окажется ложью, нужно обрабатывать следующий элемент таблицы с тем же предварительно просматриваемым символом (способ обращения с альтерна-
тивными правыми частями).
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Рассмотрим схему построения таблицы разбора и соответствующей программы для следующей грамматики:
(1)PROGRAM begin DECLIST semi STATLIST end
(2)DECLIST d X
(3)X comma DECLIST
(4)X e
(5)STATLIST s Y
(6)Y comma STATLIST
(7)Y e
Сначала представим грамматику в виде схемы (рис. 4.3). В скобках и справа на рисунке указаны номера элементов таблицы разбора.

138
(1) |
PROGRAM |
|
|
begin |
(2) |
|
|
|
|
|
|
|
(3) |
|
|
|
|
DECLIST |
|
|
|
|
|
|
|
|
(4) |
|
|
|
|
semi |
||
|
|
|
|
|
(5) |
|
|
|
|
|
STATLIST |
|
|
|
|
|
|
|
|
(6) |
|
|
|
|
end |
||
|
|
|
|
|
|
|
(7) |
DECLIST |
d |
(8) |
|
X |
|
(9) |
(10) |
|
|
|
|
|
|
(12) |
|
X1 |
|
|
comma |
|||
(11) |
|
|
|
|
|
|
(13) |
|
X2 |
|
|
DECLIST |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
e |
(14) |
|
(15) |
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
STATLIST |
|
|
s |
(16) |
||
|
|
|
|
|
|
(17) |
|
|
|
|
|
|
Y |
|
|
(18) |
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
Y1 |
|
|
comma |
(20) |
||
(19) |
|
|
|
|
|
(21) |
|
|
Y2 |
|
|
STATLIST |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
e |
(22) |
|
|
|
|
|
|
|
|
|
Рисунок 4.3 – Схема грамматики
Таблица разбора, соответствующая этой грамматике, может быть пред-
ставлена в виде табл. 4.10.
Таблица 4.10 – Таблица разбора
№ |
terminals |
jump |
accept |
stack |
return |
error |
|
|
|
|
|
|
|
1 |
{begin} |
2 |
false |
false |
false |
true |
|
|
|
|
|
|
|
2 |
{begin} |
3 |
true |
false |
false |
true |
|
|
|
|
|
|
|
3 |
{d} |
7 |
false |
true |
false |
true |
|
|
|
|
|
|
|
4 |
{semi} |
5 |
true |
false |
false |
true |
|
|
|
|
|
|
|
5 |
{s} |
15 |
false |
true |
false |
true |
|
|
|
|
|
|
|
6 |
{end} |
0 |
true |
false |
true |
true |
|
|
|
|
|
|
|
7 |
{d} |
8 |
false |
false |
false |
true |
|
|
|
|
|
|
|