Що таке дизайн компілятора? Типи, будівельні інструменти, приклад

⚡ Розумний підсумок

Фази компілятора описують шість етапів, які перетворюють вихідний код на машинний код: лексичний аналіз, синтаксичний аналіз, семантичний аналіз, генерація проміжного коду, оптимізація коду та генерація коду, що підтримується керуванням таблицею символів та обробкою помилок.

  • 🔤 Лексичний аналіз: Сканер групує символи в токени та записує їх у таблицю символів.
  • ???? Синтаксичний аналіз: Парсер перевіряє граматику та будує ієрархічне дерево розбору з токенів.
  • ✔️ Семантичний аналіз: Цей етап перевіряє сумісність типів та їх значення за допомогою синтаксичного дерева.
  • Code Покоління: Проміжний код генерується, оптимізується та, нарешті, перетворюється на цільовий машинний код.
  • 📋 Процедури підтримки: Таблиця символів та процедура обробки помилок взаємодіють з кожним етапом компіляції.

Фази компілятора з прикладом: процес та кроки компіляції

Які фази проектування компілятора?

A компілятор працює в різні фази, і кожна фаза перетворює вихідну програму з одного представлення в інше. Кожна фаза отримує вхідні дані з попередньої фази та передає свій вихідний код до наступної фази компілятора. У компіляторі є 6 фаз. Кожна з цих фаз допомагає у перетворенні мови високого рівня на машинний код. Фази компілятора:

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

Фази компілятора

Фази компілятора

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

Етап 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: Проміжна Code Покоління

Після завершення фази семантичного аналізу компілятор генерує проміжний код для цільової машини. Він являє собою програму для деяких ABS.tracт машина.

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

Функції проміжного зв'язку Code покоління:

  • Його слід генерувати із семантичного представлення вихідної програми.
  • Зберігає значення, обчислені під час процесу перетворення.
  • Допомагає вам перекласти проміжний код на цільову мову.
  • Дозволяє підтримувати порядок пріоритету вихідної мови.
  • Він містить правильну кількість операндів інструкції.

Приклад

Наприклад:

total = count + rate * 5

Проміжний код за допомогою методу адресного коду такий:

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

Фаза 5: Code Оптимізація

Наступний етап – оптимізація проміжного коду. Цей етап видаляє зайві рядки коду та впорядковує послідовність операторів, щоб пришвидшити виконання програми без марнування ресурсів. Головна мета цього етапу – покращити проміжний код для створення коду, який працює швидше та займає менше місця.

Основними функціями цієї фази є:

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

приклад: Розглянемо такий код:

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

Може стати:

b = c * 10.0
f = e + b

Фаза 6: Code Покоління

Code Генерація коду – це остання та завершальна фаза компілятора. Вона отримує вхідні дані з фази оптимізації коду та в результаті створює код сторінки або об'єктний код. Метою цієї фази є виділення пам'яті та генерація переміщуваного машинного коду.

Він також виділяє місця в пам'яті для змінних. Інструкції в проміжному коді перетворюються на машинні інструкції. Цей етап перетворює оптимізований або проміжний код на цільову мову.

Цільовою мовою є машинний код. Тому всі комірки пам'яті та регістри також вибираються та розподіляються на цьому етапі. Код, згенерований на цьому етапі, виконується для отримання вхідних даних та генерації очікуваних виходів.

Приклад

a = b + 60.0, можливо, буде переведено в регістри як:

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

Управління таблицею символів

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

Процедура обробки помилок

У процесі проектування компілятора помилки можуть виникати на всіх наведених нижче етапах:

  • Лексичний аналізатор: Неправильно написані лексеми.
  • Синтаксичний аналізатор: Відсутня дужка.
  • Генератор проміжного коду: Невідповідні операнди для оператора.
  • Code оптимізатор: Коли твердження недоступне.
  • Code Generator: Коли пам'ять переповнена або не виділено відповідні регістри.
  • Таблиці символів: Помилка кількох оголошених ідентифікаторів.

Найпоширенішими помилками є недійсні послідовності символів під час сканування, недійсні послідовності токенів у типі, помилка області видимості та синтаксичний аналіз у семантичному аналізі.

Помилка може виникнути на будь-якій із вищезазначених фаз. Після виявлення помилок, фаза повинна їх обробити, щоб продовжити процес компіляції. Про ці помилки необхідно повідомити обробнику помилок, який обробляє їх для виконання процесу компіляції. Зазвичай, про помилки повідомляють у вигляді повідомлення.

Поширені запитання

Так. Помічники зі штучним інтелектом можуть пояснити кожен етап, tracяк зразки коду перетворюються на токени та дерева розбору, а також вказують на місця виникнення синтаксичних або семантичних помилок. Вони є корисними допоміжними засобами для навчання, але перевіряють пояснення на основі матеріалів курсу.

Машинне навчання може передбачити, які проходи оптимізації створюють найшвидший код для заданої програми та машини, налаштовуючи вибір, який колись був ручною евристикою. Компілятор все ще повинен гарантувати, що оптимізована програма поводиться точно так само, як оригінал.

Фронтенд обробляє лексичний, синтаксичний та семантичний аналіз, а також проміжний код, і залежить від мови програмування. Бекенд займається оптимізацією та генерацією коду і залежить від цільової машини. Такий поділ спрощує ретаргетинг.

Ні. Лексичний аналіз (сканування) групує символи в токени, тоді як парсинг (синтаксичний аналіз) упорядковує ці токени в дерево розбору відповідно до граматичних правил. Спочатку виконується лексичний аналіз, який передає свої токени синтаксичному аналізатору.

Підсумуйте цей пост за допомогою: