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

97
3.10.2.3. Алгоритм устранения бесполезных символов
На базе двух рассмотренных алгоритмов построим обобщенный алго-
ритм устранения бесполезных символов.
Вход. КС-грамматика G = (N, Σ, P, S), у которой L(G).
Выход. КС-грамматика G' = (N', Σ', P', S), у которой L(G') = L(G) и в
N' Σ' нет бесполезных символов.
Метод:
1)Применив к G алгоритм «Не пуст ли язык?», получить Ne, положить
G1 = (N Ne, Σ, P1, S), где P1 состоит из множества правил P, содер-
жащих только символы из Ne Σ.
2)Применив к G1 алгоритм «Устранение недостижимых символов»,
получить G' = (N', Σ', P', S).
Таким образом, на шаге 1) нашего алгоритма из G устраняются все нетерминалы, которые не могут порождать терминальных цепочек. Затем на шаге 2) устраняются все недостижимые символы.
Каждый символ X результирующей грамматики должен появиться хотя бы в одном выводе вида S * wXy * wxy.
· · · · · · · · · · · · · · · · · · · · · · · |
|
Выводы · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Грамматика G', которую строит рассматриваемый алгоритм, не содер-
жит бесполезных символов.
·· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
3.10.2.4.Алгоритм преобразования в грамматику без e-правил
В практике построения трансляторов обычно правила A e бессмыс-
ленны. Очень полезно отработать метод устранения таких правил из грамма-
тики.

98
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Назовем КС-грамматику G = (N, Σ, P, S) грамматикой без e-правил (или неукорачивающей), если либо P не содержит e-
правил, либо есть точно одно правило S e и S не встречается в правых частях остальных правил из P.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
Алгоритм устранения e-правил:
Вход. КС-грамматика G = (N, Σ, P, S).
Выход. Эквивалентная КС-грамматика G' = (N', Σ', P', S') без e-правил.
Метод:
1)Построить Ne = {A | A N и A +G e}.
2)Построить P' следующим образом:
а) если A α0B1α1B2α2…Bkαk принадлежит P, k 0 и для 1 i k, но ни один символ в цепочках αj (0 j k) не принадлежит Ne, то включить в P' все правила вида
A α0X1α1X2…αk–1Xkαk,
где Xi – либо Bi, либо e, но не включает правило A e (хотя это могло бы произойти в случае, если все αi были равны e);
б) если S Ne, включить в P' правила S' e | S, где S' – новый сим-
вол, и положить N' = N{S'}, в противном случае положить N' = N и S' = S.
3)Положить G' = (N', Σ', P', S').
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Рассмотрим грамматику S aSbS | bSaS | e. Применяя к ней рассмот-
ренный алгоритм, получаем грамматику
S' S | e

99
S аSbS | bSaS | aSb | abS | ab | bSa | baS | ba.
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
3.10.2.5. Алгоритм устранения цепных правил
Другое полезное преобразование грамматик – устранение правил вида
A B, которые мы будем называть цепными.
Вход. КС-грамматика G = (N, Σ, P, S) без e-правил.
Выход. Эквивалентная КС-грамматика G' = (N', Σ', P', S) без e-правил и цепных правил.
Метод:
1)Для каждого A N построить NA = {B | A * B} следующим образом:
а) положить N0 = {A} и i = 1;
б) положить Ni = {C | B C принадлежит P и B Ni–1}Ni–1;
в) если Ni Ni–1, то положить i = i+1 и повторить шаг б), в против-
ном случае положить NA = Ni.
2)Построить P' следующим образом: если B α принадлежит P и не является цепным правилом, включать в P' правило A α для таких
A, что B NA.
3)Положить G' = (N', Σ', P', S).
· · · · · · · · · · · · · · · · · · · · · · · · |
|
Пример · · · · · · · · · · · · · · · · · · · · · · · |
|
|
|
Грамматика с правилами:
EE+T | T
TT*F | F
F(E) | a
Применим к данной грамматике рассмотренный выше алгоритм. На шаге 1) NE = {E, T, F}, NT = {T, F}, NF = {F}. После шага 2) множество P' ста-
нет таким: