
- •Теория вычислительных процессов и структур
- •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. Ошибки, связанные с нарушением ограничений
2.2. Синтаксис и семантика
Перевод обычно рассматривают как композицию двух более простых отображений. Первое из них, называемое синтаксическим отображением, связывает с каждым выходом (программа на исходном языке) некоторую структуру, которая служит аргументом второго отображения, называемого семантическим.
Почти всегда структурой любой программы является помеченное дерево. Поэтому сущность алгоритмов перевода обычно сводится к построению подходящих деревьев для входных программ
Рис. 2.1. Древовидная структура английского предложения
В качестве примера, как для цепочек строятся эти деревья, рассмотрим разбиение английского предложения на синтаксические категории (рис. 2.1).
The pig is in the pen.
Неконцевые вершины этого дерева помечены синтаксическими категориями, а концевые (листья), помечены концевыми, или терминальными, символами, в данном случае – английскими словами.
Аналогично можно программу, написанную на языке программирования, расчленить на синтаксические компоненты в соответствии с синтаксическими правилами, управляющими этим языком (рис. 2.2).
Пример.
Цепочка a+b*c.
Рис. 2.2. Дерево арифметического выражения
Процесс нахождения синтаксической структуры данного предложения называется синтаксическим анализом, или синтаксическим разбором.
Синтаксический разбор позволяет понять взаимоотношения между различными частями предложения. Термином «синтаксис» языка будем называть отношения, связывающие с каждым предложением языка некоторую синтаксическую структуру, тогда правильное предложение языка можно определить как цепочку символов, синтаксическая структура которой соответствует категории «предложение».
Естественно, нам нужно более строгое определение синтаксиса. Что и будет сделано позднее.
Вторая часть перевода – семантическое отображение, оно отображает структурированный вход в выход, который обычно является программой на машинном языке.
Термином «семантика языка» будем называть отображение, связывающее с синтаксической структурой каждой входной цепочки цепочку в некотором языке, рассматриваемую как «смысл» первоначальной цепочки.
Строгой теории синтаксиса и семантики пока еще нет, однако для простых случаев – языков программирования - есть два понятия, которые можно используются для разборки части необходимого описания.
Первое из них – понятие контекстно – свободной(КС) грамматики. В виде контекстно – свободной грамматики можно формализовать большую часть правил, предназначенных для описания синтаксической структуры.
Второе понятие – схема синтаксически управляемого перевода, с помощью которого можно задавать отображение одного языка в другой.
Оба этих понятия – цель дальнейшего изучения.
2.3. Процесс компиляции
Практически для всех компиляторов есть некоторые общие процессы, попробуем их выделить.
Исходная программа, написанная на некотором языке, есть цепочка знаков. Компилятор превращает эту цепочку знаков в цепочку битов – объектный код. В этом процессе превращения можно выделить следующие подпроцессы:
лексический анализ;
работа с таблицами;
синтаксический анализ или разбор;
генерация кода или трансляция в промежуточный код (например, Ассемблер);
оптимизация кода;
генерация объектного кода.
В конкретных трансляторах состав и порядок этих процессов может отличаться.
Кроме того, транслятор должен быть построен так, что никакая цепочка не может нарушить его работоспособности, т.е. он должен реагировать на любые из них («защита от дурака»).
Кратко рассмотрим каждый из этих процессов.