
- •Теория вычислительных процессов и структур
- •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. Ошибки, связанные с нарушением ограничений
9.5. Время компиляции и время прогона
Как отмечалось ранее, генератор кода во время компиляции обращается к нижнему стеку и генерирует код операций, которые будут выполняться во время прогона. Что именно должно быть сделано во время компиляции, а что во время прогона существенно зависит от языка программирования. Тем не менее, разработчик компилятора имеет возможность разделять функции компиляции и прогона. Например, не вполне ясно, повлечет ли разыменование за собой какие-либо действия при прогоне или нет. На первый взгляд может показаться, что нет, так как это просто замена в памяти одного значения другим и изменение адреса времени прогона. Новым адресом будет тот, на который указывает первоначальный адрес. Однако, значение указателя может быть неизвестным при компиляции, новый адрес можно обозначить, изменив первоначальный адрес так, чтобы в нем указывался дополнительный косвенный уровень. Т.е. в некоторых случаях требуется выполнить действие (переслать значение по новому адресу).
Для повышения эффективности выдаваемого кода при компиляции можно проделать дополнительную работу, которую показывают компиляцией. В оптимизацию входит удаление кодов из циклов там, где это не влияет на значение программы, исключение возможности вычисления идентичных выражений более одного раза и т.д. Особое внимание уделяется возможности избежать перезаписи сложных структур данных во время прогона.
Контрольные вопросы
Технология создания промежуточного кода. Виды промежуточного кода.
Алгоритм преобразования арифметического выражения в префиксную и постфиксную форму.
Формализация записи промежуточного кода.
Структуры данных для генерации промежуточного кода.
Алгоритм генерации промежуточного кода для арифметических выражений.
Таблица блоков, ее назначение.
Генерация кода для присвоения.
Генерация кода для условных зависимостей.
Генерация кода для описания идентификаторов.
Генерация кода для циклов.
Генерация кода для входа и выхода из блока.
Генерация кода для прикладной реализации.
Проблемы генерации кода, связанные с типами.
Работа генератора кода во время компиляции и во время прогона.
10. Исправление и диагностика ошибок
10.1. Типы ошибок
Если программа, представленная компилятору, написана с ошибками, не на «исходном» языке, «недружелюбный» компилятор может просто проинформировать пользователя об этом, не указав, где произошла ошибка. Большинство пользователей не удовлетворит такой подход, поскольку они ожидают от компилятора:
точного указания, где находится (первая) ошибка программирования;
продолжения компиляции (или, по крайней мере, анализа) программы после обнаружения первой ошибки с целью обнаружения остальных.
Основные причины возникновения ошибок программирования можно классифицировать следующим образом.
Программист не совсем понимает язык, на котором он пишет, и использует неправильную конструкцию программы.
Программист недостаточно осторожен в применении конструкции языка и забывает описать идентификатор или согласовать открывающую скобку с закрывающей и т.д.
Программист неправильно пишет слово языка или какого-либо другой символ в программе.
Ошибки, обусловленные этими тремя факторами, по-разному обнаруживаются компилятором. Ошибки первого типа вылавливаются синтаксическим анализатором, и генерируется сообщение с указанием того символа, на котором поток программы стал недействительным. Ошибки второго типа распадаются на две категории. Те, которые относятся к контекстным свойствам языка (отсутствие идентификатора и д.р.), обнаруживаются процедурой выборки из таблицы символов во время синтаксического анализа. Такие ошибки, как недостающие скобки, обнаруживаются самим анализатором во время выполнения фазы одного из проходов. Ошибки третьего типа обычно выявляются во время лексического анализа.
Существуют ошибки еще одного типа, когда программа пытается выполнить деление на ноль или считывание за пределами файла. Они называются ошибками времени прогона, и обычно их нельзя обнаружить в процессе компиляции. Наша задача проанализировать методы диагностики всех видов ошибок фазы компиляции и рассмотреть методы их коррекции.