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

133
При третьем проходе новые элементы во множествах F(B) не появятся,
поэтому он будет последним.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
4.2.2.3 Множество направляющих символов
Если A – нетерминал в левой части правила, то его направляющими символами T(A) будут символы-предшественники A и все символы, следую-
щие за A, если A может генерировать пустую строку:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
A |
|
e S A , |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
T |
|
A |
|
|
|
S |
|
A |
e |
|
F |
|
|||||
|
|
|
|
||||||||||||||
|
|
|
|
|
|
|
|
|
|
e S A . |
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
· · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
|
|
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
||||||||||
|
|
|
|
|
|
||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Для рассмотренной выше грамматики получим результат, приведенный в табл. 4.9.
Таблица 4.9 – Множества направляющих символов
P |
|
S(A) |
F(A) |
T(A) |
|
|
|
|
|
E T E′ |
(, a |
|
, ) |
(, a |
|
|
|
|
|
E′ + T E′ |
+ |
|
, ) |
+ |
|
|
|
|
|
E′ e |
e |
|
|
, ) |
|
|
|
|
|
T F T′ |
(, a |
|
, +, ) |
(, a |
|
|
|
|
|
T′ * F T′ |
* |
|
, +, ) |
* |
|
|
|
|
|
T′ e |
e |
|
|
, +, ) |
|
|
|
|
|
F ( E ) |
( |
|
, +, *, ) |
( |
|
|
|
|
|
F a |
a |
|
|
a |
|
|
|
|
|
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Обратите внимание, что множество символов-предшественников ищет-
ся для цепочки, а множество предшествующих символов – для нетерминала.

134
Поэтому для альтернатив порождающего правила с одним и тем же нетерминалом A в левой части множества S(A) будут разными, а множества
F(A) будут совпадать.
Как следует из данного ранее определения, для грамматики типа LL(1)
множества направляющих символов для порождающих правил с одинаковым символом в левой части не должны пересекаться. То есть, если имеются аль-
тернативы порождающего правила:
A1 α1
A2 α2
………
An αn
и A1 = A2 = … = An соответственно, то
T(Ai) T(Aj) = при i ≠ j.
В рассмотренной выше грамматике это условие выполняется. Из этого условия следуют и другие требования к LL(1)-грамматикам. В частности, за-
прет левой рекурсии. Действительно, если в грамматике есть правила вида:
A Aα
A β
то элементы множества S(β) войдут во множества T(A) для обеих альтерна-
тив.
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Рассмотрим грамматику:
E T + T
E T * T E T
T ( E )