Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
tyap(l).doc
Скачиваний:
22
Добавлен:
30.07.2019
Размер:
806.91 Кб
Скачать
  1. Понятие компилятора. Синтаксический анализ.

Каждый язык программирования имеет правила, которые предписывают синтаксическую структуру корректных программ.

В нашей модели компилятора синтаксический анализатор получает строку токенов от лексического анализатора и проверяет, может ли эта строка порождаться грамматикой исходного языка. Он также сообщает о всех выявленных ошибках, причем достаточно внятно и полно. Кроме того, он должен уметь обрабатывать обычные, часто встречающиеся ошибки и продолжать работу с оставшейся частью программы.

Выход синтаксического анализатора является некоторым деревом разбора входного потока токенов.

  1. Понятие компилятора. Семантический анализ.

Компилятор должен убедиться, что исходная программа следует как синтаксическим, так и семантическим соглашениям исходного языка. Такая проверка, именуемая статической (static checking), — в отличие от динамической, выполняемой в процессе работы целевой программы, — гарантирует, что будут выявлены определенные типы программных ошибок. Ниже представлены примеры статических проверок.

  • Проверки типов. Компилятор должен сообщать об ошибке, если оператор применяется к несовместимому с ним операнду, например при сложении переменных, представляющих собой массив и функцию.

  • Проверки управления. Передача управления за пределы языковых конструкций должна производиться в определенное место. Например, в языке программирования С оператор break передает управление за пределы наиболее вложенной инструкции

  • while, for или switch; если же таковые отсутствуют, то выводится сообщение об ошибке.

  • Проверки единственности. Существуют ситуации, когда объект может быть опреде­лен только один раз. Например, в языке программирования Pascal идентификатор должен объявляться только один раз, все метки в конструкции case должны быть различны, а элементы в скалярном типе не должны повторяться.

  • Проверки, связанные с именами. Иногда одно и то же имя должно использоваться дважды (или большее число раз). Например, в языке программирования Ada цикл или блок может иметь имя, которое должно находиться как в начале, так и в конце конструкции. Компилятор должен проверить, что в обоих местах используется одно и то же имя.

  1. Понятие компилятора. Основные фазы компиляции.

Концептуально компилятор работает пофазно, причем в процессе каждой фазы происходит преобразование исходной программы из одного представления в другое. Типичное разбиение компилятора на фазы показано на рис. 1. На практике некоторые фазы могут быть сгруппированы вместе, и промежуточные представления программы внутри таких групп могут явно не строиться.

Первые три фазы, формирующие анализирующую часть компилятора, были рассмотрены в предыдущем разделе. Управление таблицей символов и обработка ошибок показаны во взаимодействии с шестью фазами: лексическим анализом, синтаксическим анализом, семантическим анализом, генерацией промежуточного кода, оптимизацией кода и генерацией кода. Неформально диспетчер таблицы символов и обработчик ошибок также могут считаться "фазами" компилятора.

Таблицы символов

Одной из важных функций компилятора является запись используемых в исходной программе идентификаторов и сбор информации о различных атрибутах каждого идентификатора. Эти атрибуты предоставляют сведения об отведенной идентификатору памяти, его типе, области видимости. При использовании имен процедур атрибуты говорят о количестве и типе их аргументов, методе передачи каждого аргумента и типе возвращаемого значения, если таковое имеется.

Таблица символов представляет собой структуру данных, содержащую записи о каждом идентификаторе с полями для его атрибутов. Данная структура позволяет быстро найти информацию о любом идентификаторе и внести необходимые изменения.

Обнаружение ошибок

В каждой фазе компиляции могут встретиться ошибки. Однако после их обнаружения необходимы определенные действия, чтобы продолжить компиляцию и выявить другие ошибки в исходной программе. Компилятор, который останавливается при обнаружении первой же ошибки, не настолько полезен в работе, каким мог бы быть.

В процессе синтаксического и семантического анализа обычно обрабатывается большая часть ошибок, обнаруживаемых компилятором. При лексическом анализе выявляются ошибки, при которых символы из входного потока не формируют ни один из токенов языка. Ошибки, при которых поток токенов нарушает структурные правила (синтаксис) языка, определяются в фазе синтаксического анализа. В процессе семантического анализа компилятор пытается обнаружить конструкции, корректные с точки зрения синтаксиса, но не имеющие смысла с точки зрения выполняемых операций.

Генерация промежуточного кода

После синтаксического и семантического анализа некоторые компиляторы генерируют явное промежуточное представление исходной программы, которое можно рассматривать как программу для абстрактной машины. Это представление должно легко создаваться и транслироваться в целевую программу.

Оптимизация кода

При оптимизации кода производятся попытки улучшить промежуточный код, чтобы получить более эффективный машинный код. Некоторые оптимизации тривиальны. Например, естественный алгоритм генерирует промежуточный код, используя инструкцию для каждого оператора в дереве, созданном в результате семантического анализа.

Степень оптимизации кода у различных компиляторов значительно отличается. В некоторых компиляторах, называемых "оптимизирующими", большая часть времени работы уходит именно на оптимизацию. Однако существуют простые приемы оптимизации, которые существенно уменьшают время работы целевой программы, не сильно замедляя работу компилятора.

Генерация кода

Последняя фаза компиляции состоит в генерации целевого кода, обычно перемещаемого машинного кода или ассемблерного кода. Для каждой переменной программы определяется ее положение в памяти. После этого каждая промежуточная инструкция транслируется в последовательность машинных инструкций, выполняющих ту же самую работу. Ключевой аспект этой фазы заключается в назначении переменных регистрам.