Фазы компилятора с примером: процесс и шаги компиляции

Каковы этапы разработки компилятора?

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

  1. Лексический анализ
  2. Синтаксический анализ
  3. Семантический анализ
  4. Генератор промежуточного кода
  5. Оптимизатор кода
  6. Генератор кода
Фазы компилятора
Фазы компилятора

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

Этап 1: Лексический анализ

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

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

Пример:
х = у + 10

Лексемы

X идентификатор
= Оператор присваивания
Y идентификатор
+ Оператор сложения
10 Номер регистрации

Этап 2: Синтаксический анализ

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

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

Пример

Любой идентификатор/число является выражением
Если x — идентификатор, а y+10 — выражение, то x= y+10 — оператор.
Рассмотрим дерево разбора для следующего примера

(a+b)*c

Пример синтаксического анализа

В дереве разбора

  • Внутренний узел: запись с полем оператора и двумя дочерними файлами.
  • Лист: записи с 2/более полями; один для токена и другой информации о токене
  • Убедитесь, что компоненты программы содержательно сочетаются друг с другом.
  • Собирает информацию о типах и проверяет совместимость типов.
  • Проверяет, что операнды разрешены исходным языком

Этап 3: Семантический анализ

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

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

Пример

float x = 20.2;
float y = x*30;

В приведенном выше коде семантический анализатор преобразует целое число 30 в число с плавающей запятой 30.0 перед умножением.

Этап 4: Промежуточная генерация кода

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

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

Пример

Например,

total = count + rate * 5

Промежуточный код с помощью метода адресного кода:

 
t1 := int_to_float(5) 
t2 := rate * t1 
t3 := count + t2
total := t3

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

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

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

Пример:
Рассмотрим следующий код

a = intofloat(10)
b = c * a
d = e + b
f = d

Может стать

b =c * 10.0
f = e+b

Этап 6: Генерация кода

Генерация кода — это последний и заключительный этап работы компилятора. Он получает входные данные от этапов оптимизации кода и в результате создает код страницы или объектный код. Целью этого этапа является выделение памяти и создание перемещаемого машинного кода.
Он также выделяет ячейки памяти для переменной. Инструкции промежуточного кода преобразуются в машинные инструкции. На этом этапе оптимизируемый или промежуточный код преобразуется в целевой язык.
Целевой язык — машинный код. Таким образом, на этом этапе также выбираются и распределяются все ячейки памяти и регистры. Код, сгенерированный на этом этапе, выполняется для приема входных данных и генерации ожидаемых выходных данных.

Пример

а = б + 60.0
Возможно было бы переведено в регистры.

MOVF a, R1
MULF #60.0, R2
ADDF R1, R2

Управление таблицей символов

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

Процедура обработки ошибок

В процессе разработки компилятора ошибка может возникнуть на всех следующих этапах:

  • Лексический анализатор: Неправильно написанные токены
  • Анализатор синтаксиса: отсутствует скобка
  • Генератор промежуточного кода: несовпадающие операнды для оператора
  • Оптимизатор кода: когда оператор недоступен
  • Code Generator: Когда память заполнена или не выделены нужные регистры.
  • Таблицы символов: ошибка нескольких объявленных идентификаторов

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

Резюме

  • Компилятор работает на различных этапах, каждый этап преобразует исходную программу из одного представления в другое.
  • Шесть этапов дизайн компилятора 1) Лексический анализ 2) Синтаксический анализ 3) Семантический анализ 4) Генератор промежуточного кода 5) Оптимизатор кода 6) Код Generator
  • Лексический анализ — это первый этап, когда компилятор сканирует исходный код.
  • Синтаксический анализ – это обнаружение структуры в тексте.
  • Семантический анализ проверяет семантическую согласованность кода.
  • После завершения фазы семантического анализа компилятор сгенерирует промежуточный код для целевой машины.
  • Фаза оптимизации кода удаляет ненужную строку кода и упорядочивает последовательность операторов.
  • Фаза генерации кода получает входные данные от фазы оптимизации кода и в результате создает код страницы или объектный код.
  • Таблица символов содержит запись для каждого идентификатора с полями для атрибутов идентификатора.
  • Процедура обработки ошибок обрабатывает ошибки и сообщает о них на многих этапах.