Компиляторы
Презентацию к данной лекции Вы можете скачать здесь.
Компиляция - первый шаг в создании процесса
От исходного текста программы к процессу (Linux)
Транслятор выполняет преобразование программы, написанной на одном языке программирования в программу на другом языке программирования.
Компилятор выполняет преобразование программы, написанной на языке программирования (как правило, высокого уровня) в программу на языке машинного уровня.
Результат трансляции и компиляции должны быть эквивалентны исходным программам – прежде всего, должна сохраняться корректность алгоритма.
Основные фазы компиляции
Лексический анализ - включает распознавание лексем языка программирования, замену их соответствующими кодами.
Лексемы - элементарные единицы, наделенные определенным "смыслом" и входящие в структуру предложения языка (ключевые или зарезервированные слова, константы, имена и т.д.).
Синтаксический анализ - проверка правильности использования предложений языка в соответствии с его грамматикой. Остальные фазы компиляции выполняются только при отсутствии синтаксических ошибок.
Трансляция кода в промежуточную форму - преобразование программы в матрицу промежуточного кода. Каждая строка матрицы содержит тройку: код операции и два операнда. Промежуточные коды не имеют прямых аналогов в системе машинных команд, поэтому данную форму представления программы называют машинно-независимой.
Оптимизация - уменьшение избыточности программы по затратам процессорного времени и памяти. Пользователь может управлять процессом оптимизации, используя подходящие сочетания ключей (опций) оптимизации.
Распределение памяти - определение объемов памяти каждого вида, используемого в программе. На этом этапе в матрицу промежуточного кода вносятся коды резервирования памяти . Каждая программа использует по крайней мере два вида памяти: статическую - для размещения данных и кодов программы, и стековую - для обращения к подпрограммам.
Генерация кода - подстановка кодовых образцов на выходном языке, соответствующих промежуточным кодам программы. Выполняется машинно-зависимая оптимизация программы – с учетом особенностей архитектуры целевой платформы.
Лексический анализ
Функции лексического анализатора:
- ввод строк исходной программы;
- распознавание лексем;
- заполнение таблиц идентификаторов и литералов;
- печать листинга исходной программы.
Лексический анализатор (сканер, лексер) учитывает особенности языка программирования. Это включает форматирование исходного текста, интерпретацию пробелов и т.д.
Лексический анализатор использует:
- исходный текст программы;
- таблицу терминальных символов;
- таблицу литералов;
- таблицу идентификаторов.
Таблица терминальных символов - таблица, содержащая терминальные символы языка, коды лексем и другую информацию.
Таблица символических имен - таблица, содержащая имена переменных, их тип, значение и другую информацию.
Таблица литералов - таблица, содержащая литералы (константы), их тип и другую информацию. Литералу выделяется ячейка памяти, в которую записывается константа. Далее все появления этого литерала заменяются обращениями по адресу этой ячейки.
Результат работы сканера - последовательность кодов лексем. Код лексемы представляется кодом таблицы и спецификатором. Спецификатор задает номер строки в таблице, куда занесена лексема.
Синтаксический анализ
Синтаксис и семантика.
Синтаксис - множество правил, описывающих структуру предложений языка (порядок следования лексем). Речь идет о формальной структуре предложений, а не о смысле.
Семантика - множество правил интерпретации смысла предложения.
Синтаксический анализ - построение дерева грамматического разбора обрабатываемого текста. Текст состоит из предложений.
Результат анализа исходного предложения в терминах грамматических конструкций представляется в виде дерева. Такие деревья обычно называются деревьями грамматического разбора или синтаксическими деревьями.
Таблица терминальных символов - таблица, содержащая терминальные символы языка, коды лексем и другую информацию.
Таблица символических имен - таблица, содержащая имена переменных, их тип, значение и другую информацию.
Таблица литералов - таблица, содержащая литералы (константы), их тип и другую информацию. Литералу выделяется ячейка памяти, в которую записывается константа. Далее все появления этого литерала заменяются обращениями по адресу этой ячейки.
Результат работы сканера - последовательность кодов лексем. Код лексемы представляется кодом таблицы и спецификатором. Спецификатор задает номер строки в таблице, куда занесена лексема.
Оптимизирующие преобразования
Использование возможностей автоматической оптимизации компилятора может дать значительный выигрыш в производительности
Удаление общих подвыражений
Если одно и то же подвыражение встречается несколько раз, компилятор может вычислить его один раз, а все последующие включения заменяются вычисленным значением:
a = (b+35) * (b+35); c = 12.0 * (b+35);
в результате удаления общего подвыражения превращается в следующий:
tmp = b + 35; a = tmp * tmp; c = 12.0 * tmp;
Развертка цикла
Развертка заключается в преобразовании цикла в линейную последовательность операций. Выигрыш в производительности достигается благодаря снижению накладных расходов на организацию цикла. Эффективным этот прием может быть в случае, когда тело цикла очень маленькое:
ifor (i = 0; i < 2; i++) a[i] = 2.0 * d[i];
После развертки:
a[0] = 2.0 * d[0]; a[1] = 2.0 * d[1]; a[2] = 2.0 * d[2];