
- •Теория вычислительных процессов и структур
- •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.3. Грамматика без циклов
Определение.
КС – грамматика G = (N, Р S) называется грамматикой без циклов, если в ней нет вывода А + А для АN. Грамматика называется приведённой, если она без циклов, без е – правил и без бесполезных символов.
Большинство (если не все) языки программирования обладают именно этими свойствами.
3.10.4. Нормальная форма Хомского
Определение. КС–грамматика G = (N, Р S) называется грамматикой в нормальной форме Хомского (или бинарной нормальной форме), если каждое правило из Р имеет один из следующих видов:
А ВС, где А, В, С принадлежит N;
А а, где а;
S е, если еL(G), причём S не встречается в правых частях правил.
На практике каждый КС – язык порождается грамматикой в нормальной форме Хомского. Это очень полезно, когда требуется простая форма представления КС – языка.
Алгоритм преобразования к нормальной форме Хомского.
Вход. КС–грамматика G = (N, Р S).
Выход. Эквивалентная КС-грамматика G' в нормальной форме Хомского, т.е. L(G')=L(G).
Метод. Грамматика G' строится следующим образом.
Включить в Р' каждое правило из Р вида А а.
Включить в Р' каждое правило из Р вида А ВС.
включить в Р' каждое правило Sе, если оно было в Р.
для каждого правила из Р вида
, где k >2, включить в Р' правила
…………………………………
,
где
,
если
;
– новый нетерминал, если
;
- новый терминал.
Для каждого правила из Р вида
, где хотя бы один из символов
и
принадлежит , включить в Р' правило
.
Для каждого нетерминала вида а', введённого на шагах 4) и 5), включить в Р' правило а'а. Наконец, пусть N' – это N вместе со всеми нетерминалами, введёнными при построении Р'. Тогда искомая грамматика G' = (N', ' Р' S).
Пример.
Пусть G – приведённая грамматика, определённая правилами
S аАВ | ВА
А ВВВ | а
В АS | b.
Строим Р' рассмотренным выше алгоритмом, сохраняя правила SВА, A а, В АS и В b. Заменяем правило S аАВ на S а'<AB> и <АВ> АВ, а А ВВВ – правилами A В<BB> и <BB>BB. Наконец, добавляем а'а. В результате получим грамматику G'= (N', {a, b}, Р', S) и Р' состоит из правил:
S а'<АВ> | BA
А В<BB> | a
B AS | b
<AB> AB
<BB> BB
a' а.
3.10.5. Нормальная формула Грейбах
Очень важно для языков программирования использовать грамматику, в которой все правые части правил начинаются с терминалов. Построение таких грамматик связано с устранением любой рекурсии.
Определение.
Нетерминал А в КС–грамматике G = (N, Р S) называется рекурсивным, если А+ A для некоторых и . Если = е, то А называется леворекурсивным. Аналогично, если = е, то А называется праворекурсивным. Грамматика, имеющая хотя бы один леворекурсивный терминал, называется леворекурсивной. Аналогично определяется и праворекурсивная грамматика. Грамматика, в которой все не терминалы, кроме может быть начального символа, рекурсивные называется рекурсивной грамматикой.
Практически все языки программирования определяются нелеворекурсивной грамматикой. Поэтому все элементы левой рекурсии должны быть устранены из грамматики.
Лемма.
Пусть G = (N, Р S) – КС–грамматика, в которой
-
все правила из Р и ни одна из цепочек
не начинается с А.
Пусть G'=(N{A'}, , P', S), где А' – новый терминал, а Р' получено из Р заменой А – правил правилами
.
Тогда L(G')=L(G).
Рассмотрим на графе, как это реализуется (рис. 3.10).
а)
б)
Рис 3.10. Праволинейная а) и леволинейная б) грамматики
Пример:
Пусть G0 наша обычная грамматика с правилами:
ЕE+T | T
TT*F | F
F(Е) a.
Применяя к ней вышерассмотренную лемму, получаем эквивалентную грамматику с правилами:
Е Т | TE'
E' +T | + TE'
Т F | FT'
Т'*F | * FT'
F (Е) | a.
На основании вышеописанного построим алгоритм устранения левой рекурсии. Он будет подобен алгоритму решения уравнения с размерными коэффициентами.
Алгоритм устранения левой рекурсии.
Вход. Приведённая КС–грамматика G = (N, Р S).
Выход. Эквивалентная КС-грамматика без левой рекурсии.
Метод.
Пусть
. Преобразуем G так, чтобы в правиле
цепочка начиналась либо с терминала, либо с такого
, что i>j. С этой целью положим i=1.
Пусть множество
, где ни одна из цепочек
не начинается с
, если ki заменим
– правила правилами:
,
где
– новый нетерминал. Правые части всех
– правил начинаются теперь с терминала
или с
,
для которого k>i.
Если i=n, то полученную грамматику считаем результатом и останавливаемся, в противном случае i=i+1 и j=1.
Заменим каждое правило
правилами
, где
для всех
- правил. Так как правая часть каждого
правила начинается уже с терминала или
для к>j, то правая часть каждого
- правила будет теперь обладать этими свойствами.
Если j=i-1, перейти к шагу 2), в противном случае положить i=i+1 и перейти к шагу 4).
На основании вышесказанного можно однозначно доказать теорему, что каждый КС-язык определяется нелеворекурсивной грамматикой.
Определение.
КС-грамматика G = (N, Р S) называется грамматикой в форме Грейбах, если в ней нет е- правил и каждое правило из Р, отличное от Se, имеет вид Аa, где а, N*.