Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
1_Компіляція-основні поняття.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
311.3 Кб
Скачать

1 Компіляція: основні поняття

У 50-х роках минулого століття про компілятори ходила слава як про програми, вкрай складних у написанні (наприклад, на розробку першого компілятора мови програмування Fortran знадобилося 18 людино-років роботи). Знання про організацію і написанні компіляторів істотно зросли з часів перших компіляторів, що з'явилися на початку 1950-х р.р. З тих пір розроблені різноманітні системні технології вирішення багатьох завдань, виникаючих при компіляції. Принципи і технології написання компіляторів зараз настільки поширені, що їх ідеї використовуються в самих різних галузях інформаційних технологій. Написання компіляторів охоплює мови програмування, архітектуру обчислювальних систем, теорію мов, алгоритми й технологію створення програмного забезпечення. На щастя, при створенні трансляторів для широкого кола мов і машин достатньо лише кількох основних технологій написання компіляторів.

1.1 Транслятори і компілятори

Транслятор – це програма, яка зчитує текст програми, що написана однією мовою – початковою або вхідною, і транслює (перекладає) його в еквівалентний текст іншою мовою – цільовою (рис. 1.1).

Canvas 56

Компілятор ­– це транслятор, який крім «прямого» перекладу, додає (компілює) в цільову програму ще й програмні модулі із бібліотек програм як «стандартні», так й спеціально розроблені (рис. 1.2).

Canvas 46

Рис. 1.2. Узагальнена схема компілятора

Компіляція складається з двох частин: аналізу і синтезу. Аналіз – це розгалуження початкової програми на складові частини та створення її проміжного представлення. Синтез – це конструювання потрібної цільової програми з проміжного представлення. Так, при компиляції арифметичних операторів, що є майже в усіх мовах програмування, у процесі аналізу визначаються та записуються в ієрархічну деревоподібну структуру операції, що задані початковою програмою (дерево синтаксичного розбору). Так, для оператора присвоєння значення арифметичного виразу мовою Pascal position:=initial+rate*60 кожен вузол представляє операцію, а дочірні вузли – аргументи (операнди) операції (рис. 1.3).

Canvas 36

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

Canvas 21

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

1.2. Аналіз початкової програми

При компіляції аналіз складається з трьох фаз:

  1. Лексичний (лінійний) аналіз, при якому потік символів початкової програми зчитується, як правило, зліва направо і групується в токени (token), що представляють собою послідовність символів з певним сукупним значенням.

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

  3. Семантичний аналіз, що дозволяє перевірити, наскільки коректним є сумісне розміщення компонентів програми.

1.2.1 Лексичний аналіз

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

position:=initial+rate*60

будуть згруповані в наступні токени:

1. Ідентифікатор position.

2. Символ присвоєння :=.

3. Ідентифікатор initial.

4. Знак додавання +.

5. Ідентифікатор rate.

6. Знак множення *.

7. Число 60.

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

1.2.2 Синтаксичний аналіз

Ієрархічний аналіз називають розбором (parsing) або синтаксичним (граматичним) аналізом, який включає групування токенів початкової програми в граматичні фрази, використовувані компілятором для синтезу виводу. Зазвичай, граматичні фрази представляють у вигляді дерева, приклад якого для того ж рядка position:=initial+rate*60 наведено на рис. 1.5.

Canvas 91

Іерархічна структура програми зазвичай виражається рекурсивними правилами. Наприклад, при визначенні виразів можна дотримуватися наступних правил:

1. Кожен ідентифікатор (identifier) є вираз (expression).

2. Кожнe число (number) є вираз (expression).

3. Якщо expression1 і expression2 є виразами, то виразами є:

3.1. expression1 + expression2

3.2. expression1 * expression2

3.3. (expression1), (expression2)

Правила (1) і (2) є базовими (нерекурсивними), а правила (3) визначають вирази за допогою операторів, що застосовуються до інших виразів, і вони є рекурсивними. Точно также багато мов програмування рекурсивно визначають інструкції (оператори) мови.

Розгалуження аналіза на лексичний і синтаксичний досить умовно. Зазвичай, воно застосовується для спрощення аналізу у цілому. Одним із визначаючих факторів розгалуження є використання рекурсії в правилах аналізу. Лексичні конструкції не потребують рекурсії (точніше, для іх розпізнавання можна обійтися без рекурсії), в той час як синтаксичні конструкції рідко обходяться без неї. Наприклад, рекурсія може бути не потрібна при розпізнаванні ідентифікаторів, які зазвичай є рядки літер і цифр, що починаються з літери. Розпізнати ідентифікатор можна за допомогою простого послідовного сканування вхідного потоку до тих пір, поки в ньому не зустрінеться символ, який не є символом ідентифікатора. Після цього скановані символи групуються в токен, що представляє ідентифікатор. Згруповані символи записуються в так звану таблицю символів, видаляються з вхідного потоку, і починається сканування наступного токена. Однак таке лінійне сканування недостатньо для аналізу виразів чи інших конструкцій. Наприклад, ми не можемо перевірити відповідність дужок у виразах або ключових слів begin і end в інструкціях без накладення деякої ієрархічної або вкладеної структури на дані, що уводяться.

Дерево розбору, що показане на рис. 1.5, описує синтаксичну структуру інформації, що надходить. Більш загальне внутрішнє подання цієї синтаксичної структури – синтаксичне дерево – було представлено на рис. 1.3.

Синтаксичне дерево - це "стиснуте" дерево розбору, в якому оператори розміщені у внутрішніх вузлах, а операнди оператора представлені дочірніми гілками вузла, що представляє цей оператор. Такі ієрархічні дерева використовуються, зокрема, в так званих синтаксично керованих трансляторах, які будуть розглянуті в п.6.