
- •Теория вычислительных процессов и структур
- •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.2. Грамматики
Грамматики образуют наиболее важный класс генераторов языка. Грамматика – это математическая система, определяющая вид языка. Одновременно она является устройством, которое придаёт цепочкам (предложениям) языка полезную структуру. Мы будем пользоваться формализмом грамматик Хомского.
В грамматике, определяющей язык L, используются два конечных непересекающихся множества символов – множество нетерминальных символов, которое обычно обозначается буквой, и множество терминальных символов, обозначаемое. Из терминальных символов образуются слова (цепочки) определяемого языка. Нетерминальные символы служат для порождения слов языкаLопределённым способом.
Сердцевину грамматики составляет конечное множество Р правил образования, которое описывает процесс порождения цепочек языка. Правило – этопросто пара цепочек или элемент множества, иначе говоря, ()* ()* (). Первой компонентой правила является любая цепочка, содержащая хотя бы один нетерминал, а второй компонентой – любая цепочка.
Пример.
Например, правилом может быть пара (AB, CDE). Если уже установлено, что некоторая цепочкапорождается грамматикой исодержитAB, т.е. левую часть этого правила, в качестве своей подцепочки, то можно образовать новую цепочку, заменив одно вхождениеABвнаCDE.
Язык, определяемый грамматикой, - это множество цепочек, которые строятся только из терминальных символов и выводятся, начиная с одной особой цепочки, состоящей из одного выделенного символа, обычно обозначаемого S.
Соглашение.Правило (, ) будем записывать.
Определение.
Грамматикой называется четвёрка G=(N, Σ, P, S),
где
N – конечное множество нетерминальных символов или нетерминалов (иногда называемых вспомогательными символами, синтаксическими переменными или понятиями);
- непересекающееся с N конечное множество терминальных символов (терминалов);
P – конечное подмножество множества ()*()*() , элемент (,) множества P называется правилом (или продукцией) и записывается;
S – выделенный символ из N, называемый начальным (исходным) символом.
Примером грамматики служит четвёрка G1 = ({A, S}, {0, 1}, P, S), где P состоит из правил
S→0A1
0A→00A1
A→C.
Нетерминальными символами являются А и S, а терминальными - 1 и 0.
Грамматика определяет язык рекурсивным образом. Рекурсивность проявляется в задании особого рода цепочек, называемых вводимыми цепочками грамматики G=(N,Σ,P,S), где
S - вводимая цепочка;
если αβγ – выводимая цепочка и β→содержится в Р, то – тоже выводимая цепочка.
Выводимая цепочка грамматики G,не содержащая нетерминальных символов, называется терминальной цепочкой, порождаемой грамматикой G.
Терминология.
Пусть G=(N, Σ, P, S) – грамматика. ОтношениеG на множестве ()* (φGΨ означает Ψ, непосредственно выводимая из φ ) и практикуется: если αβγ – цепочка из ()* и β→δ – правило из Р, то αβγG αδγ.
Транзитивное замыкание отношения G обозначим через G+ и трактуется – Ψ, выводимая из φ нетривиальным образом.
Рефлексивное и транзитивное замыкание отношения G (G*) φG* Ψ, Ψ, выводимая из φ.
Далее, если ясно, о какой грамматике идёт речь, то индекс Gбудет опускаться.
Таким образом,
L(G) = {w |w,Sw}
через
будем обозначать k-ю
степень отношения . Иначе говоря
,
если существует
,
состоящая из k+1
цепочек, для которых
при 1 i
к
и
=.
Эта последовательность цепочек называется
выводом длины k
цепочки
из
цепочки в грамматике G.
Отметим,
что *
тогда и только тогда, когда
для некоторого i≥0,
и +
тогда и только тогда, когда
для некоторого i≥1.
Пример.
Рассмотрим грамматику G1 из ранее приведённого примера
S.
На первом шаге S заменяется на А01 в соответствии с правилом S→A01.
На втором шаге 0A заменяется на 00A1.
На третьем шаге A заменяется на e.
Можно сказать, что S3
S+
S*,
и что 0011 принадлежит языку L(G1).
Соглашение:1
2
…….
n
обозначим 1 2 ….n .
Кроме того, примем ещё следующие соглашения относительно символов и цепочек, связанных с грамматикой:
a, b ,c, d и цифры 0,1,2,..,9 обозначают терминальные символы;
A, B, C, D, S обозначают нетерминалы, S – начальный символ;
U, V,...,Z обозначают либо нетерминалы, либо терминалы;
обозначают цепочки, которые могут содержать как терминалы, так и нетерминалы;
u, v,...,z обозначают цепочки, состоящие только из терминалов.
Пример.
Пусть G0 = ({E, T, F},{a, +, * (, )}, P, E), где P состоит из правил:
E→E+T | T
T→T*F | F
F→(E) | a.
Пример вывода в этой грамматике:
EE+T
T+T
F+T
a+T
a+T*F
a+F*F
a+a*F
a+a*a,
т.е. язык G0 представляет собой множество арифметических выражений, построенных из символов a, +, *, (и).