
- •Теория вычислительных процессов и структур
- •1. Предварительные математические сведения
- •1.2. Операции над множествами Объединение множеств
- •Пересечение множеств
- •Разность множеств
- •1.3. Множества цепочек
- •1.4. Языки
- •1.5. Алгоритмы
- •1.6. Некоторые понятия теории графов
- •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. Регулярные множества, их распознавание
- •3.6. Регулярные множества и конечные автоматы
- •3.7. Графическое представление конечных автоматов
- •3.8. Конечные автоматы и регулярные множества
- •3.9. Минимизация конечных автоматов
- •3.10. Контекстно-свободные языки
- •3.10.1. Деревья выводов
- •3.10.2. Преобразование кс–грамматик
- •3.10.3. Грамматика без циклов
- •3.10.4. Нормальная форма Хомского
- •3.10.5. Нормальная формула Грейбах
- •3.11. Автоматы с магазинной памятью
- •3.11.1. Основные определения
- •3.11.2. Эквивалентность мп-автоматов и кс-грамматик
- •4.1. Эквивалентность мп-автоматов и кс-грамматик
- •4.2. Ll(1)-грамматики
- •4.3. Ll(1)-таблица разбора
- •5. Синтаксический анализ снизу вверх
- •5.1. Разбор снизу вверх
- •5.2. Lr(1) - таблица разбора
- •5.3. Построение lr – таблицы разбора
- •5.4. Сравнение ll – и lr – методов разбора
- •6. Включение действий в синтаксис
- •6.1. Получение четверок
- •6.2. Работа с таблицей символов
- •7. Проектирование компиляторов
- •7.1. Число проходов
- •7.2. Таблицы символов
- •Identifier, type.
- •Int procedure rehash(int n)
- •Int procedure rehash(int n)
- •7.3. Таблица видов
- •8. Распределение памяти
- •8.1. Стек времени прогона
- •Integer a, b, X, y
- •Int table[1:10, -5:5].
- •8.2. Методы вызова параметров
- •8.3. Обстановка выполнения процедур
- •8.4. «Куча»
- •8.5. Счетчик ссылок
- •8.6. Сборка мусора
- •9. Генерация кода
- •(Тип – адреса, номер - блока, смещение).
- •9.2. Структура данных для генерации кода
- •9.3. Генерация кода для типичных конструкций
- •9.3.1. Присвоение
- •9.3.2. Условные зависимости
- •If b then c else d
- •9.3.3. Описание идентификаторов
- •9.3.4. Циклы
- •9.3.5. Вход и выход из блока
- •9.3.6. Прикладные реализации
- •9.4. Проблемы, связанные с типами
- •9.5. Время компиляции и время прогона
- •10. Исправление и диагностика ошибок
- •10.1. Типы ошибок
- •10.2. Лексические ошибки
- •10.3. Ошибки в употреблении скобок
- •Begin end
- •Case esac
- •10.4. Синтаксические ошибки
- •10.5. Методы исправления синтаксических ошибок
- •End begin
- •10.6. Предупреждения
- •10.7. Сообщения о синтаксических ошибках
- •10.8. Контекстно-зависимые ошибки
- •Identifier xyz not declared
- •Identifier blank alredy declared in block
- •10.9. Ошибки, связанные с употреблением типов
- •Int I; char c;
- •10.10. Ошибки, допускаемые во время прогона
- •10.11. Ошибки, связанные с нарушением ограничений
3.10.2. Преобразование кс–грамматик
КС-грамматику часто требуется модифицировать так, чтобы порождаемые ею языки приобрели нужную структуру. Рассмотрим, например, язык L(G0). Этот язык порождается грамматикой G с правилами
ЕЕ+Е | Е*Е | (Е) | a.
Но эта грамматика имеет два недостатка. Прежде всего, она неоднозначна из-за наличия правила ЕЕ+Е | Е*Е. Эту неоднозначность можно устранить, взяв вместо G грамматику G1 с правилами
ЕЕ+Т | Е*Т | Т
Т(Е) | а.
Другой недостаток грамматики G, которым обладает и грамматика G1, заключается в том, что операции + и * имеют один и тот же приоритет, т.е. структура выражения а+а*а и а*а+а, которую мы придаём грамматике G1, подразумевает тот же порядок выполнения операций, что и в выражениях (а+а)*а и (а*а)+а соответственно.
Чтобы получить обычный приоритет операций + и *, при которых * предшествует + и выражение а+(а*а) понимается как а+(а*а), надо перейти к грамматике G0.
Общего алгоритмического метода, который придавал бы данному языку произвольную структуру, не существует. Но с помощью ряда преобразований можно видоизменить грамматику, не испортив порождаемый ею язык.
Начнём с очевидных, но важных преобразований. Например, в грамматике G=({S,A}, {a, b}, P, S), где Р={Sa, Ab}, нетерминал А и терминал b не могут появляться ни в какой выводимой цепочке. Таким образом, эти символы не имеют отношения к языку L(G) и их можно устранить из определения грамматики G, не затронув языка L(G).
Определение.
Назовём символ ХN бесполезным в КС – грамматике G = (N, Р S), если в ней нет вывода вида S wXy wxy, где w, x, y принадлежат .
Чтобы установить, бесполезен ли нетерминал А, построим сначала алгоритм, выясняющий, может ли этот нетерминал порождать какие - либо нетерминальные цепочки, т.е. алгоритм, решающий проблему пустоты множества {w | A w, w }.
Алгоритм. Непуст ли язык L(G)?
Вход. КС-грамматика G = (N, Р S).
Выход. «ДА» если L(G), «НЕТ» в противном случае.
Метод.
Строим множества
рекурсивно.
Положить
= , i=1.
Положить
.
Если
, то положить i=i+1 и перейти к шагу 2), в противном случае -
=
.
если S
, то выдать вывод «ДА», в противном случае – «НЕТ».
Так
как символ
N,
то алгоритм должен остановиться максимум
после n+1
повторения шага 2).
Теорема.
Алгоритм, приведённый выше, говорит «ДА» тогда и только тогда, когда Sw для некоторой цепочки w .
Определение.
Символ XN назовём недостижимым в КС – грамматике G = (N, Р S), если х не появляется ни в одной выводимой цепочке.
Недостижимые символы можно устранить из КС – грамматики с помощью следующего алгоритма.
Алгоритм устранения недостижимых символов.
Вход. КС – грамматика G = (N, Р S).
Выход. КС - грамматика G' = (N', ' Р' S), у которой
i) L(G')=L(G),
ii)
для
всех
существуют такие цепочки и из (N'
')*,
что SG'
X.
Метод.
Положить
= {S} и i=1.
Положить
.
Если
, положить i=i+1 и перейти к шагу (2), в противном случае, пусть
,
,
Р' – состоит из правил множества Р, содержащих только символы из
,
G' = (N', ' Р' S).
Заметим,
что шаг 2) алгоритма можно повторить
только конечное число раз, т.к.
.
На базе двух рассмотренных алгоритмов построим обобщенный алгоритм устранения бесполезных символов.
Алгоритм устранения бесполезных символов.
Вход. КС – грамматика G = (N, Р S), у которой L(G).
Выход. КС - грамматика G' = (N', ' Р' S), у которой L(G')=L(G) и в N' ' нет бесполезных символов.
Метод.
Применив к G алгоритм «не пуст ли язык?», получить
, положить G1 = (N
, ,
, S), где
состоит из множества правил Р, содержащих только символы из
.
Применив к G1 алгоритм «устранение недостижимых символов», получить G' = (N', ' Р' S).
Таким образом, на шаге 1) нашего алгоритма из G устраняются все нетерминалы, которые не могут порождать терминальных цепочек. Затем на шаге 2) устраняются все недостижимые символы.
Каждый символ Х результирующей грамматики должен появиться хотя бы в одном выводе вида S wXy wxy.
Резюме. Грамматика G', которую строит рассматриваемый алгоритм, не содержит бесполезных символов.
В практике построения трансляторов обычно правила Ае бессмысленны. Очень полезно отработать метод устранения таких правил из грамматики.
Определение.
Назовём КС – грамматику G = (N, Р S) грамматикой без е - правил (или неукорачивающей), если либо Р не содержит е – правил, либо есть точно одно правило Sе и S не встречается в правых частях остальных правил из Р.
Алгоритм преобразования в грамматику без е – правил.
Вход. КС – грамматика G = (N, Р S).
Выход. Эквивалентная КС - грамматика G' = (N', ' Р' S) без е – правил.
Метод.
Построить
.
Построить Р' следующим образом:
a)
если
принадлежит Р, k
и
для 1iк,
но ни один символ в цепочках
(0jk)
не принадлежит
,
то включить в Р'
все правила вида:
,
где
-
либо
,
либо е,
но не включает правило Ае
(это могло бы произойти в случае, если
все
равны е);
б)
если S
,
включить в Р'
правила S'e
|
S, где S'
– новый символ, и положить N'=N{S'},
в противном случае положить N'=N
и S'=S.
Положить G' = (N', ' Р' S').
Пример.
Рассмотрим грамматику SаSbS | bSaS | e. Применяя к ней рассмотренный алгоритм, получаем грамматику
S'S | e
S аSbS | bSaS | aSb | abS | ab | bSa | baS | ba.
Другое полезное преобразование грамматик – устранение правил вида А В, которые мы будем называть цепными.
Алгоритм устранения цепных правил.
Вход. КС – грамматика G = (N, Р S ) без е – правил.
Выход. Эквивалентная КС - грамматика G' = (N', ' Р' S) без е – правил и цепных правил.
Метод.
Для каждого АN построить NА = {B | A * В} следующим образом.
а)
положить
=
{A}
и i=1;
б)
положить
;
в)
если
,
то положить i=i+1
и повторить шаг б),
в противном случае положить
.
Построить Р' следующим образом: если В принадлежит Р и не является цепным правилом, включать в Р' правило А для таких А, что
.
Положить G' = (N', ' Р' S).
Пример.
Грамматика с правилами
Е Е+Т | Т
Т Т * F | F
F (Е) | a.
Применим к данной грамматике рассмотренный выше алгоритм. На шаге 1) NЕ = {E, T, F}, NТ = {T, F}, NF = {F}. После шага 2) множество Р' станет такими:
E Е+Т | T*F | (E)| a
Т Т*F | (E) | a
F (Е) | а.