- •2 Лексичний аналіз
- •2.1. Роль лексичних аналізаторів
- •2.1.1 Завдання лексичного аналізу
- •2.1.2 Токени, шаблони, лексеми
- •2.1.3 Атрибути токенів
- •2.2. Алфавит, рядки і мови
- •2.2.1 Алфавит та рядки над алфавитом
- •2.2.2 Рядки й мови
- •2.2.3 Операції над мовами
- •2.3 Регулярні вирази
- •2.2.4 Регулярні визначення
- •2.2.5 Скорочення
- •2.2.6 Нерегулярні множини
- •2.4. Розпізнавання токенів
- •Id → letter (letter | digit)*
- •2.3.1 Діаграми переходів
- •2.3.2 Реалізація діаграми переходів
2 Лексичний аналіз
2.1. Роль лексичних аналізаторів
Лексичний аналізатор являє собою першу фазу компілятора. Його основне завдання полягає в читанні нових символів і видачі послідовності токенів, використовуваних синтаксичним аналізатором у своїй роботі. На рис. 2.1 схематично показана взаємодія лексичного й синтаксичного аналізаторів, що звичайно реалізується шляхом створення лексичного аналізатора як підпрограма синтаксичного аналізатора (або підпрограми, викликуваної ним). При одержанні запиту на наступний токен лексичний аналізатор зчитує вхідний потік символів до точної ідентифікації наступного токена.
Оскільки лексичний аналізатор є частиною компілятора, що зчитує вхідний текст, він може також виконувати деякі вторинні завдання інтерфейсу. До них, наприклад, відносяться видалення з тексту вхідної програми коментарів і не несучих значеннєвого навантаження проміжків (а також символів табуляції й нового рядка). Ще одна завдання полягає в узгодженні повідомлень про помилки компіляції й тексту вхідної програми. Наприклад, лексичний аналізатор може підрахувати кількість лічених рядків і вказати рядок, що викликав помилку. На жаль, особливо в складних програмах і складних мовах програмування така вказівка помилки не завжди є вірною — іноді помилка може бути розпізнана тільки після зчитування декількох рядків. Такі ситуації можуть зустрічатися й у комерційних компіляторах, хоча в цьому випадку вони досить рідкі.
У деяких компіляторах лексичний аналізатор створює копію тексту вхідної програми із вказівкою помилок. Якщо вхідна мова підтримує макроси й директиви препроцесора, то вони також можуть бути реалізовані лексичним аналізатором.
Найчастіше робота лексичного аналізатора складається із двох фаз - сканування й лексичного аналізу. Фаза сканування відповідає за виконання найпростіших завдань, у той час як на фазу лексичного аналізу покладають більш складні завдання. Так, наприклад, компілятор може використати сканер для видалення із вхідного тексту зайвих проміжків.
2.1.1 Завдання лексичного аналізу
Є ряд причин, по яких фаза аналізу компіляції розділяється на лексичний і синтаксичний аналізи.
Мабуть, найбільш важливою причиною є спрощення розробки. Відділення лексичного аналізатора від синтаксичного часто дозволяє спростити одну з фаз аналізу. Наприклад, включення в синтаксичний аналізатор коментарів і проміжків істотно складніше, ніж видалення їх лексичним аналізатором, При створенні нової мови поділ лексичних і синтаксичних правил може привести до більше чіткої і ясної побудови мови.
Збільшується ефективність компілятора. Окремий лексичний аналізатор дозволяє створити спеціалізований і потенційно більш ефективний процесор для рішення поставленого завдання. Оскільки на читання вихідної програми й розбір її на токени витрачається багато часу, спеціалізовані технології буферизації йобробки токенів можуть істотно підвищити продуктивність компілятора.
Збільшується переносність (мобільність) компілятора. Особливості вхідного алфавиту та інші специфічні характеристики використовуваних пристроїв можуть обмежувати можливості лексичного аналізатора. Наприклад, у такий спосіб може бути вирішена проблема спеціальних нестандартних символів, таких як ↑ в Pascal.
Існує ряд спеціалізованих інструментів, призначених для автоматизації побудови лексичних та синтаксичних аналізаторів, навіть і у тому випадку, коли вони розділені.
