Що таке транслятор. Мови програмування. Компілятори та інтерпретатори. Алгоритм роботи простого інтерпретатора

Конкретними виконавцями мов програмування є транслятори та інтерпретатори.

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

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

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

Мова, на якій представлена ​​вхідна програма, називається вихідниммовою, а сама програма – вихідним кодом. Вихідна мова називається цільовою мовою або об'єктнимкодом. Мета трансляції - перетворити текст з однієї мови на іншу, яка зрозуміла адресату тексту. У разі програм-трансляторів адресатом є технічний пристрій(процесор) чи програма-інтерпретатор.

Транслятори реалізуються як компіляторів чи інтерпретаторів. З погляду виконання роботи компілятор та інтерпретатор суттєво різняться.

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

Компілятор(англ. compiler- упорядник, збирач) читає всю програму повністю, робить її переклад і створює закінчений варіант програми машинною мовою, який потім і виконується. Результат роботи компілятора - бінарний файл, що виконується.

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

Якщо вихідна мова є мовою асемблера (низькорівневою мовою, близькою до машинної мови), то компілятор такої мови називається асемблером.

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

Інтерпретатор(англ. interpreter- тлумач, усний перекладач) перекладає та виконує програму рядок за рядком.

Інтерпретатор програмно моделює машину, цикл вибірки виконання якої працює з командами мовами високого рівня, а не з машинними командами. Таке програмне моделювання створює віртуальну машину, що реалізує мову. Цей підхід називається чистою інтерпретацією. Чиста інтерпретація застосовується зазвичай для мов із простою структурою (наприклад, АПЛ чи Лисп). Інтерпретатори командного рядкаобробляють команди в скриптах UNIX або пакетних файлах (.bat) в MS-DOS також зазвичай у режимі чистої інтерпретації.

Гідність інтерпретатора: відсутність проміжних дій для трансляції спрощує реалізацію інтерпретатора і робить його зручнішим у використанні, у тому числі в діалоговому режимі. Недолік - інтерпретатор має бути в наявності на цільовій машині, де має виконуватися програма. Також, як правило, є більш менш значний програш у швидкості. А властивість чистого інтерпретатора, що помилки в програмі, що інтерпретується, виявляються тільки при спробі виконання команди (або рядка) з помилкою, можна визнати як недоліком, так і гідністю.

Існують компромісні між компіляцією та чистою інтерпретацією варіанти реалізації мов програмування, коли інтерпретатор перед виконанням програми транслює її на проміжну мову (наприклад, у байт-код або p-код), більш зручний для інтерпретації (тобто йдеться про інтерпретатора з вбудованим транслятором) . Такий метод називається змішаною реалізацією. Прикладом змішаної реалізації мови може бути Perl. Цей підхід поєднує як переваги компілятора та інтерпретатора (більша швидкість виконання та зручність використання), так і недоліки (для трансляції та зберігання програми проміжною мовою потрібні додаткові ресурси; для виконання програми на цільовій машині має бути представлений інтерпретатор). Також, як і у випадку компілятора, змішана реалізація вимагає перед виконанням вихідний кодне містив помилок (лексичних, синтаксичних та семантичних).

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

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

Цей метод добре підходить для веб-застосунків. Відповідно, динамічна компіляція виникла і підтримується у тому мірою у реалізаціях Java, . NET Framework, Perl, Python.

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

Відкомпіловані програми працюють швидше, але простіше виправляти і змінювати інтерпретовані.

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

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

Алгоритм роботи простого інтерпретатора:

2. проаналізувати інструкцію та визначити відповідні дії;

3. виконати відповідні дії;

4. якщо не досягнуто умови завершення програми, прочитати наступну інструкцію та перейти до пункту 2

Мови програмування можуть бути поділені на компілювані та інтерпретовані.

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

Якщо програма написана мовою, що інтерпретується, то інтерпретатор безпосередньо виконує (інтерпретує) вихідний текст без попереднього перекладу. При цьому програма залишається вихідною мовою і не може бути запущена без інтерпретатора. Можна сміливо сказати, що процесор комп'ютера - це інтерпретатор машинного коду.

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

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

Для будь-якої інтерпретованої мови можна створити компілятор - наприклад, мова Лісп, що спочатку інтерпретується, може компілюватися без будь-яких обмежень. Код, що створюється під час виконання програми, може також динамічно компілюватися під час виконання.

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

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

Однак програми, що інтерпретуються, виконуються помітно повільніше, ніж компілювані, крім того, вони не можуть виконуватися без додаткової програми-інтерпретатора.

Деякі мови, наприклад, Java і C#, знаходяться між компілюваними та інтерпретованими. Зокрема, програма компілюється над машинний мову, а машинно-незалежний код низького рівня, байт-код. Далі байт-код виконується віртуальною машиною. Для виконання байт-коду зазвичай використовується інтерпретація, хоча окремі частини для прискорення роботи програми можуть бути трансльовані в машинний код безпосередньо під час виконання програми за технологією компіляції "на льоту" (Just-in-time compilation, JIT). Для Java байт-код виконується віртуальною машиною Java(Java Virtual Machine, JVM), для C# - Common Language Runtime.

Подібний підхід у певному сенсі дозволяє використовувати плюси як інтерпретаторів, і компіляторів. Слід згадати також оригінальну мову Форт (Forth), що має інтерпретатор і компілятор.

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

Транслятор - обслуговуюча програма, що перетворює вихідну програму, надану вхідною мовою програмування, робочу програму, представлену об'єктною мовою.

В даний час транслятори поділяються на три основні групи: асемблери, компілятори та інтерпретатори.

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

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

Компілятор - це обслуговуюча програма, що виконує трансляцію машинною мовою програми, записаної вихідною мовою програмування. Так само як і асемблер, компілятор забезпечує перетворення програми з однієї мови на іншу (найчастіше в мову конкретного комп'ютера). Разом з тим, команди вихідної мови значно відрізняються за організацією та потужністю від команд машинної мови. Існують мови, у яких одна команда вихідної мови транслюється у 7-10 машинних команд. Проте є й такі мови, у яких кожній команді може відповідати 100 і більше машинних команд (наприклад, Пролог). Крім того, у вихідних мовах досить часто використовується сувора типізація даних, що здійснюється через їх попередній опис. Програмування може спиратися не так на кодування алгоритму, але в ретельне обдумування структур даних чи класів. Процес трансляції з таких мов зазвичай називається компіляцією, а вихідні мови зазвичай належать до мов програмування високого рівня (чи високорівневих мов). Абстрагування мови програмування від системи команд комп'ютера призвело до незалежного створення найрізноманітніших мов, орієнтованих вирішення конкретних завдань. З'явилися мови для наукових розрахунків, економічних розрахунків, доступу до баз даних та інші.

Інтерпретатор - програма або пристрій, що здійснює пооператорну трансляцію та виконання вихідної програми. На відміну від компілятора, інтерпретатор не породжує на виході програму машинною мовою. Розпізнавши команду вихідної мови, він одразу виконує її. Як у компіляторах, і у інтерпретаторах використовуються однакові методи аналізу вихідного тексту програми. Але інтерпретатор дозволяє розпочати обробку даних після написання навіть однієї команди. Це робить процес розробки та налагодження програм більш гнучким. Крім того, відсутність вихідного машинного коду дозволяє не "захаращувати" зовнішні пристрої додатковими файлами, а сам інтерпретатор можна досить легко адаптувати до будь-яких машинних архітектур, розробивши його лише один раз широко поширеною мовою програмування. Тому, що інтерпретуються мови, типу Java Script, VB Script, набули широкого поширення. Недоліком інтерпретаторів є низька швидкість виконання програм. Зазвичай інтерпретовані програми виконуються в 50-100 разів повільніше за програми, написані в машинних кодах.

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

Емулятори використовуються досить часто в різних цілях. Наприклад, при розробці нових обчислювальних систем спочатку створюється емулятор, що виконує програми, що розробляються для ще неіснуючих комп'ютерів. Це дозволяє оцінити систему команд та напрацювати базове програмне забезпеченняще до того, як буде створено відповідне обладнання.

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

Перекодувальник - програма або програмний пристрій, що перекладають програми, написані машинною мовою однієї ЕОМ в програми машинною мовою іншої ЕОМ. Якщо емулятор є менш інтелектуальним аналогом інтерпретатора, то перекодувальник виступає в тій же якості по відношенню до компілятора. Точно також вихідний (і зазвичай двійковий) машинний код або проміжне уявлення перетворюються на інший аналогічний код по одній команді і без будь-якого загального аналізу структури вихідної програми. Перекодувальники бувають корисні при перенесенні програм з одних комп'ютерних архітектур на інші. Вони можуть також використовуватися для відновлення тексту програми мовою високого рівня за наявним двійковим кодом.

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

Макропроцесори використовують і з мовами високого рівня. Вони збільшують функціональні можливості мов PL/1, C, C++. Особливо широко макропроцесори застосовуються C і C++, дозволяючи спростити написання програм. Макропроцесори підвищують ефективність програмування без зміни синтаксису та семантики мови.

Синтаксис - сукупність правил деякої мови, що визначають формування її елементів. Інакше висловлюючись, це сукупність правил освіти семантично значимих послідовностей символів у цій мові. Синтаксис задається за допомогою правил, що описують поняття деякої мови. Прикладами понять є: змінна, вираз, оператор, процедура. Послідовність понять та їх допустиме використання у правилах визначає синтаксично правильні структури, що утворюють програми. Саме ієрархія об'єктів, а чи не те, як вони взаємодіють між собою, визначаються через синтаксис. Наприклад, оператор може зустрічатися тільки у процедурі, а вираз в операторі, змінна може складатися з імені та необов'язкових індексів тощо. Синтаксис не пов'язаний з такими явищами у програмі як "перехід на неіснуючу мітку" або "змінна з цим ім'ям не визначена". Цим займається семантика.

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

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

Будь-який транслятор виконує такі основні завдання:

  • - аналізує програму, що транслюється, зокрема визначає, чи містить вона синтаксичні помилки;
  • - генерує вихідну програму (її часто називають об'єктною) мовою машинних команд;
  • - розподіляє пам'ять для об'єктної програми.1.1 Інтерпретатори

Одна, найчастіше згадувана перевага інтерпретаторної реалізації полягає в тому, що вона допускає "безпосередній режим". Безпосередній режим дозволяє вам задавати комп'ютеру завдання типу PRINT 3.14159*3/2.1 і повертає вам відповідь, як тільки ви натиснете клавішу ENTER (це дозволяє використовувати комп'ютер вартістю 3000 доларів як калькулятор вартістю 10 доларів). Крім того, інтерпретатори мають спеціальні атрибути, які полегшують налагодження. Можна, наприклад, перервати обробку інтерпретаторної програми, відобразити вміст певних змінних, швидко переглянути програму, а потім продовжити виконання.

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

Проте, інтерпретаторні мови мають недоліки. Необхідно, наприклад, мати копію інтерпретатора в пам'яті весь час, тоді як багато можливостей інтерпретатора, а отже, і його можливості можуть бути необхідними для виконання конкретної програми.

Слабко помітним недоліком інтерпретаторів є те, що вони мають тенденцію відбивати полювання до хорошого стилю програмування. Оскільки коментарі та інші деталі, що формалізуються, займають значне місце програмної пам'яті, люди прагнуть ними не користуватися. Він менш лютий, ніж програміст, що працює на інтерпретаторному Бейсіку, намагається отримати програму в 120К у пам'яті ємністю 60К. Але найгірше те, що інтерпретатори тихохідні.

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

Розглянемо програму: на інтерпретаторному Бейсіку 10 FOR N=1 TO 1000 20 PRINT N,SQR(N) 30 NEXT N при першому переході за цією програмою Бейсік-Інтерпретатор повинен розгадати що означає рядок 20:

  • 1. перетворити числову змінну N на рядок
  • 2. надіслати рядок на екран
  • 3. перемістити до наступної зони друку
  • 4. обчислити квадратний корінь з N
  • 5. перетворити результат на рядок
  • 6. надіслати рядок на екран

При другому проході циклу все це розгадування повторюється знову, тому що абсолютно забуто всі результати вивчення цього рядка якусь мілісекунду тому. І так у всіх наступних 998 проходах. Цілком очевидно, що якщо вам вдалося якимось чином відокремити фазу сканування/розуміння від фази виконання, ви мали б більше швидку програму. І це саме те, навіщо існують компілятори.


4. Основні засади побудови трансляторів. Транслятори, компілятори та інтерпретатори – загальна схема роботи. Сучасні компілятори та інтерпретатори.

Основні засади побудови трансляторів.

Транслятори, компілятори, інтерпретатори – це загальна схема роботи.

Визначення транслятора, компілятора, інтерпретатора

Для початку дамо кілька визначень - що ж таке є транслятори і компілятори, що вже багаторазово згадувалися.

Формальне визначення транслятора

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

По-перше, сам транслятор є програмою 1 – зазвичай він входить до складу системного програмного забезпечення обчислювальної системи. Тобто транслятор - це частина програмного забезпечення (ПЗ), він є набором машинних команд і даних і виконується комп'ютером, як і всі інші програми в рамках операційної системи (ОС). Всі складові транслятора являють собою фрагменти або модулі програми зі своїми вхідними та вихідними даними.

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

По-третє, вихідними даними транслятора є текст результуючої програми. Результуюча програма будується за синтаксичними правилами, заданими у вихідній мові транслятора, а її значення визначається семантикою вихідної мови. Важливою вимогою визначення транслятора є еквівалентність вхідний і вихідний програм. Еквівалентність двох програм означає збіг їхнього сенсу з погляду семантики вхідної мови (для вихідної програми) та семантики вихідної мови (для результуючої програми). Без виконання цієї вимоги сам транслятор втрачає будь-який практичний зміст.

Отже, щоб створити транслятор, необхідно перш за все вибрати вхідну та вихідну мови. З точки зору перетворення пропозицій вхідної мови в еквівалентні їм пропозиції вихідної мови транслятор виступає як перекладач. Наприклад, трансляція програми з мови С в мову асемблера по суті нічим не відрізняється від перекладу, скажімо, з російської мови на англійську, з тією різницею, що складність мов дещо інша (чому не існує трансляторів з природних мов - див. розділ «Класифікація мов та граматик», глава 9). Тому саме слово «транслятор» (англійська: translator) означає «перекладач».

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

Теоретично можлива реалізація транслятора за допомогою апаратних засобів. Автору зустрічалися такого роду розробки, проте широкого практичного застосування їх невідомо. У такому разі і всі складові транслятора можуть бути реалізовані у вигляді апаратних засобів та їх фрагментів - ось тоді схема розпізнавача може отримати цілком практичне втілення!

Визначення компілятора.

Відмінність компілятора від транслятора

Крім поняття «транслятор» широко використовується також близьке йому за змістом поняття «компілятор».

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

Таким чином, компілятор відрізняється від транслятора лише тим, що його результуюча програма завжди повинна бути написана мовою машинних кодів або мовою асемблера. Результуюча програма транслятора, в загальному випадку, може бути написана будь-якою мовою – можливий, наприклад, транслятор програм з мови Pascal на мову С. Відповідно, будь-який компілятор є транслятором, але не навпаки – не всякий транслятор буде компілятором. Наприклад, згаданий вище транслятор з мови Pascal на З компілятором не буде 1 .

Саме слово «компілятор» походить від англійського терміна"compiler" ("упорядник", "компонувальник"). Очевидно, термін зобов'язаний своєму походженню здатності компіляторів складати об'єктні програми з урахуванням вихідних програм.

Результуюча програма компілятора називається об'єктною програмою або об'єктним кодом. Файл, в який вона записана, зазвичай називається "об'єктним файлом". Навіть у тому випадку, коли результуюча програма породжується мовою машинних команд, між об'єктною програмою (об'єктним файлом) і програмою (виконуваним файлом), що виконується, є істотна різниця. Породжена компілятором програма не може безпосередньо виконуватися на комп'ютері, оскільки вона не прив'язана до конкретної області пам'яті, де повинні розташовуватися її код і дані (див. розділ «Принципи функціонування систем програмування», розділ 15) 2 .

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

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

Визначення інтерпретатора. Різниця між інтерпретаторами та трансляторами

Крім схожих між собою понять "транслятор" і "компілятор" існує принципово відмінне від них поняття інтерпретатора.

Інтерпретатор -це програма, яка сприймає вхідну програму вихідною мовою та виконує її.

На відміну від трансляторів інтерпретатори не породжують результуючу програму (і взагалі будь-якого результуючого коду) - і в цьому принципова різниця між ними. Інтерпретатор, як і і транслятор, аналізує текст вихідної програми. Однак він не породжує результуючої програми, а відразу виконує вихідну відповідно до її змісту, заданого семантикою вхідної мови. Таким чином, результатом роботи інтерпретатора буде результат, заданий змістом вихідної програми, якщо ця програма правильна, або повідомлення про помилку, якщо вихідна програма неправильна.

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

1 Слід особливо згадати, що зараз у сучасних системах програмування стали з'являтися компілятори, в яких результуюча програма створюється не мовою машинних команд і не мовою асемблера, а деякою проміжною мовою. Сама по собі ця проміжна мова не може безпосередньо виконуватися на комп'ютері, а вимагає спеціального проміжного інтерпретатора для виконання написаних на ньому програм. Хоча в даному випадку термін «транслятор» був би, напевно, правильнішим, у літературі вживається поняття «компілятор», оскільки проміжна мова є мовою дуже низького рівня, будучи родинним машинним командам та мовам асемблера.

Тут виникає одвічне питання «про курку та яйця». Звичайно, у першому поколінні перші компілятори писалися безпосередньо на машинних командах, але потім, з появою компіляторів, від цієї практики відійшли. Навіть найвідповідальніші частини компіляторів створюються, як мінімум, із застосуванням мови асемблера – а він також обробляється компілятором. точаться при необхідності - оскільки цього вимагає конкретна реаліза) інтерпретатора. Користувач же бачить результат виконання цих кодів -є результат виконання вихідної програми (вимога про еквівалентність вихідної програми і породжених машинних кодів і в цьому випадку, (умовно, має виконуватися).

Більш детально питання, пов'язані з реалізацією інтерпретаторів та їх від чиєм від компіляторів, розглянуті далі у відповідному розділі.

Призначення трансляторів, компіляторів та інтерпретаторів. Приклади реалізації

Перші програми, які створювалися ще для ЕОМ першого покоління, сідали безпосередньо мовою машинних кодів. Це була справді пекло робота. Відразу стало ясно, що людина не повинна і не може говорити мовою машинних команд, навіть якщо вона фахівець з обчислювальної техніки. Про; ко і всі спроби навчити комп'ютер говорити мовами людей успіхів увінчалися і навряд чи колись увінчаються (на що є певні o6i тивні причини, розглянуті в першому розділі цього посібника).

З того часу весь розвиток програмного забезпечення комп'ютерів нерозривно i зано з виникненням та розвитком компіляторів.

Першими компіляторами були компілятори з мов асемблера або, як називалися, мнемокоди. Мнемокоды перетворили «филькину грамоту» яз машинних команд на більш-менш доступний розумінню фахівця мову ^ монічних (переважно англомовних) позначень цих команд. (Дати програми вже стало значно простіше, але виконувати сам мнемс (мова асемблера) жоден комп'ютер нездатний, відповідно, виникла обхідність у створенні компіляторів. Ці компілятори елементарно про але вони продовжують відігравати істотну роль в системах програмування сьогодні. Більш детально про мову асемблера і компіляторах з нього розповідь: далі у відповідному розділі.

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

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

Щойно виникла масова потреба у створенні компіляторів, почала розвиватися і спеціалізована теорія. Згодом вона знайшла практичний додаток у безлічі створених компіляторів. Компілятори створювалися і продовжують створюватися як для нових, але й давно відомих мов. Багато виробників від відомих, солідних фірм (таких, як Microsoft або Inprise) до мало кому знайомих колективів авторів випускають ринку все нові й нові зразки компіляторів. Це зумовлено низкою причин, які будуть розглянуті далі.

Нарешті, відколи більшість теоретичних аспектів у галузі компіляторів отримали свою практичну реалізацію (а це, треба сказати, сталося досить швидко, наприкінці 60-х років), розвиток компіляторів пішов шляхом їхньої дружності людині - користувачеві, розробнику програм мовами найвищого рівня. Логічним завершенням цього процесу стало створення систем програмування. програмних комплексів, що поєднують у собі крім безпосередньо компіляторів безліч пов'язаних з ними компонентів програмного забезпечення. З'явившись, системи програмування швидко завоювали ринок і нині у своїй переважають на ньому (фактично, відокремлені компілятори - це рідкість серед сучасних програмних засобів). Про те, що є і як організовані сучасні системи програмування, див. розділ «Сучасні системи програмування». Нині компілятори є невід'ємною частиною будь-якої системи. Без їх існування програмування будь-якого прикладного завдання було б утруднене, а то й просто неможливе. Та й програмування спеціалізованих системних завдань, як правило, ведеться якщо не мовою високого рівня (у цій ролі нині найчастіше застосовується мова С), то мовою асемблера, отже, застосовується відповідний компілятор. Програмування безпосередньо мовами машинних кодів відбувається винятково рідко і лише вирішення дуже вузьких питань. Декілька слів про приклади реалізації компіляторів та інтерпретаторів, а також про те, як вони співвідносяться з іншими існуючими програмними засобами. Компілятори, як буде показано далі, зазвичай дещо простіше у реалізації, ніж інтерпретатори. За ефективністю вони також перевершують їх - очевидно, що відкомпільований код буде виконуватися завжди швидше, ніж інтерпретація аналогічної вихідної програми. Крім того, не кожна мова програмування припускає побудову простого інтерпретатора. Однак інтерпретатори мають одну істотну перевагу – відкомпільований код завжди прив'язаний до архітектури обчислювальної системи, на яку він орієнтований, а вихідна програма – лише до семантики мови програмування, яка набагато легше піддається стандартизації. Цей аспект спочатку не брали до уваги. Першими компіляторами були компілятори з мнемокод. Їхні нащадки - сучасні компілятори з мов асемблера - існують практично для всіх відомих обчислювальних систем. Вони дуже жорстко орієнтовані на архітектуру. Потім з'явилися компілятори таких мов, як FORTRAN, ALGOL-68, PL/1. Вони були орієнтовані великі ЕОМ з пакетної обробкою завдань. З перелічених вище тільки FORTRAN, мабуть, продовжує використовуватися до цього дня, оскільки має величезну кількість бібліотек різного призначення. Багато мов, народившись, так і не набули широкого поширення - ADA, Modula, Simula відомі лише вузькому колу фахівців. Водночас на ринку програмних системдомінують компілятори мов, яким не пророкували світлого майбутнього. Насамперед, зараз це С і C++. Перший з них народився разом із операційними системамитипу UNIX, разом із нею завоював своє «місце під сонцем», та був перейшов під ОС інших типів. Другий успішно втілив у собі приклад реалізації ідей об'єктно-орієнтованого програмування на добре зарекомендувала себе практичної основі 1 . Ще можна згадати досить поширений Pascal, який несподівано для багатьох вийшов за межі суто навчальної мови для університетського середовища.

Історія інтерпретаторів менш багата (поки!). Як вже було сказано, спочатку їм не надавали істотного значення, оскільки майже за всіма параметрами вони поступаються компіляторам. З відомих мов, що передбачали інтерпретацію, можна згадати хіба що Basic, хоча більшості зараз відома його компілювана реалізація Visual Basic, зроблена фірмою Microsoft. Проте зараз ситуація дещо змінилася, оскільки питання про переносимість програм та їх апаратно-платформну незалежність набуває все більшої актуальності з розвитком мережі Інтернет. Найвідоміший зараз приклад - це мова Java (сам по собі вона поєднує компіляцію та інтерпретацію), а також пов'язаний з нею JavaScript. Зрештою, мова HTML, якою ґрунтується протокол HTTP, що дав поштовх настільки бурхливому розвитку Всесвітньої мережі, - це теж мова, що інтерпретується. На думку автора, в області появи нових інтерпретаторів на всіх ще чекають сюрпризи, і з'явилися вже перші з них - наприклад, мова С# («сі-дієз», але назва скрізь йде як «Сі шарп»), що анонсується фірмою Microsoft.

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

Етапи трансляції. Загальна схема роботи транслятора

На рис. 13.1 представлено загальну схему роботи компілятора. З неї видно, що ъЗагалом процес компіляції складається з двох основних етапів - синтезу та аналізу.

На етапі аналізу виконується розпізнавання тексту вихідної програми, створення та заповнення таблиць ідентифікаторів. Результатом його роботи є якесь внутрішнє уявлення програми, зрозуміле компілятору.

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

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

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

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

По-друге, компілятор є генератором для мови результуючої програми. Він повинен побудувати на виході ланцюжок вихідної мови за операцією; ним правилам, передбачуваним мовою машинних команд чи мовою iсемблера. Розпізнавальником цього ланцюжка буде виступати вже обчислювальна система, під яку створюється результуюча програма.

Лексичний аналіз(сканер) - це частина компілятора, яка читає літе] програми вихідною мовою і будує з них слова (лексеми) вихідної мови. На вхід лексичного аналізатора надходить текст вихідної програм, а вихідна інформація передається для подальшої обробки компілятор на етапі синтаксичного аналізу. З теоретичної точки зору лексичний аналізатор не є обов'язковою, необхідною частиною компілятора. Однак існує чинники, які визначають його присутність на практично всіх компіляторах. Докладніше див. «Лексичні аналізатори (а нери). Принципи побудови сканерів».

Синтаксичний розбір- Це основна частина компілятора на етапі аналізу. Про виконує виділення синтаксичних конструкцій у тексті вихідної програми, обробленому лексичним аналізатором. На цій же фазі компіляції перевіряється синтаксична правильність програми. Синтаксичний розіграє головну роль - роль розпізнавача тексту вхідної мови програмування (див. розділ «Синтаксичні аналізатори. Синтаксично керований; переклад» цього розділу).

Семантичний аналіз- це частина компілятора, що перевіряє правильно * тексту вихідної програми з погляду семантики вхідної мови. КРС безпосередньо перевірки, семантичний аналіз повинен виконувати преоб; зування тексту, потрібні семантикою вхідної мови (такі, як додано функцій неявного перетворення типів). У різних реалізаціях компі. торов семантичний аналіз може частково входити у фазу синтаксичного розбору, частково - у фазу підготовки до генерації коду.

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

Генерація коду- це фаза, безпосередньо пов'язана з породженням кома складових пропозиції вихідної мови і в цілому текст результатів.

Можуть, звісно, ​​різнитися залежно від версії компілятора. Однак у тому чи іншому вигляді всі представлені фази практично завжди присутні у кожному конкретному компіляторі.

Компілятор загалом з погляду теорії формальних мов виступає у «двох іпостасях», виконує дві основні функції. програми. Це основна фаза на етапі синтезу результуючої програми. Крім безпосереднього породження тексту результуючої програми, генерація зазвичай включає також оптимізацію - процес, пов'язаний з обробкою вже породженого тексту. Іноді оптимізацію виділяють в окрему фазу компіляції, оскільки вона істотно впливає на якість та ефективність результуючої програми (див. розділи «Генерація коду. Методи генерації коду» та «Оптимізація коду. Основні методи оптимізації», розділ 14).

Таблиці ідентифікаторів(іноді – «таблиці символів») – це спеціальним чином організовані набори даних, що служать для зберігання інформації про елементи вихідної програми, які потім використовуються для породження тексту результуючої програми. Таблиця ідентифікаторів у конкретній реалізації компілятора може бути одна, або таких таблиць може бути кілька. Елементами вихідної програми, інформацію про які потрібно зберігати в процесі компіляції, є змінні, константи, функції тощо - конкретний склад набору елементів залежить від вхідної мови програмування, що використовується. Поняття «таблиці» зовсім не передбачає, що це сховище даних має бути організоване саме у вигляді таблиць або інших масивів інформації - можливі методи їхньої організації докладно розглянуті далі, у розділі «Таблиці ідентифікаторів». Організація таблиць ідентифікаторів».

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

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

Концепція проходу. Багатопрохідні та однопрохідні компілятори

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

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

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

В якості зовнішньої пам'ятіможуть виступати будь-які носії інформації - оперативна пам'ять комп'ютера, накопичувачі на магнітних дисках, магнітних стрічках і т.п. диски. Інші носії інформації в сучасних компіляторах не використовуються через невисоку швидкість обміну даними.

При виконанні кожного проходу компілятор доступна інформація, отримана в результаті всіх попередніх проходів. Як правило, він прагне використовувати в першу чергу лише інформацію, отриману на проході, що безпосередньо передував поточному, але в принципі може звертатися і до даних від ранніх проходів аж до вихідного тексту програми. Інформація, одержувана компілятором під час виконання проходів, недоступна користувачеві. Вона або зберігається в оперативної пам'яті, яка звільняється компілятором після завершення процесу трансляції, або оформляється як тимчасових файлів на диску, які також знищуються після завершення роботи компілятора. Тому людина, яка працює з компілятором, може навіть не знати, скільки проходів виконує компілятор - вона завжди бачить лише текст вихідної програми та результуючу об'єктну програму. Але кількість виконуваних проходів – це важлива технічна характеристикакомпілятора, солідні фірми - розробники компіляторів зазвичай вказують їх у описі свого продукту.

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

Однак скоротити кількість проходів не завжди вдається. Кількість необхідних проходів визначається насамперед граматикою та семантичними правилами вихідної мови. Чим складніша граматика мови і чим більше варіантів припускають семантичні правила - тим більше проходів виконуватиме компілятор (звичайно, грає свою роль та кваліфікація розробників компілятора). Наприклад, саме тому зазвичай компілятори з мови Pascal працюють швидше, ніж компілятори з мови С - граматика мови Pascal простіша, а семантичні правила жорсткіші. Однопрохідні компілятори – рідкість, вони можливі лише для дуже простих мов. Реальні компілятори виконують зазвичай від двох до п'яти проходів. Таким чином, реальні компілятори багатопрохідні. Найбільш поширені дво- та трипрохідні компілятори, наприклад: перший прохід - лексичний аналіз, другий - синтаксичний розбір та семантичний аналіз, третій - генерація та оптимізація коду (варіанти виконання, звичайно, залежать від розробника). У сучасних системах програмування нерідко перший прохід компілятора (лексичний аналіз коду) виконується паралельно з редагуванням коду вихідної програми (такий варіант побудови компіляторів розглянуто далі у розділі).

Інтерпретатори. Особливості побудови інтерпретаторів

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

Термін "інтерпретатор" (interpreter), як і "транслятор", означає "перекладач". З погляду термінології ці поняття схожі, але з погляду теорії формальних мов і компіляції з-поміж них велика принципова різниця. Якщо поняття «транслятор» та «компілятор» майже невиразні, то з поняттям «інтерпретатор» їх плутати неможливо.

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

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

Відсутність кроку оптимізації визначає ще одну особливість, характерну для багатьох інтерпретаторів: як внутрішнє представлення програми в них дуже часто використовується зворотний польський запис (див. розділ «Генерація коду. Методи генерації коду», розділ 14). Ця зручна форма подання операцій має лише один істотний недолік - вона погано піддається оптимізації. Але в інтерпретаторах саме це таки не потрібно.

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

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

Перевагою інтерпретатора є незалежність виконання програм від архітектури цільової обчислювальної системи. В результаті компіляції: виходить об'єктний код, який завжди орієнтований на певну архітектуру. Для переходу на іншу архітектуру цільової обчислювальної системи] програму потрібно відкомпілювати заново. А для інтерпретації програм] необхідно мати тільки її вихідний текст та інтерпретатор з відповідної мови.

Інтерпретатори довгий час значно поступалися поширеністю коьпіляторам. Як правило, інтерпретатори існували для обмеженого крізь га щодо простих мов програмування (таких, наприклад, як Basic Високопродуктивні професійні засоби розробки програмного забезпечення будувалися на основі компіляторів.

Новий імпульс розвитку інтерпретаторів додало поширення глобальних обчислювальних мереж. Такі мережі можуть включати до свого складу ЕОМ ра: особистої архітектури, і тоді вимога одноманітного виконання кожний їх тексту вихідної програми стає визначальним. Тому з розвитком глобальних мереж та поширенням всесвітньої мережі Інтернет з'явилося
У сучасних системах програмування існують реалізації програмного забезпечення, що поєднують у собі функції компілятора, і функції інтерпретатора - залежно від вимог користувача вихідна програма або компілюється, або виконується (інтерпретується). Крім того, деякі сучасні мови програмування передбачають дві стадії розробки: спочатку вихідна програма компілюється в проміжний код (деяка мова низького рівня), а потім цей результат компіляції виконується за допомогою інтерпретатора цієї проміжної мови. Більш докладно варіанти таких систем розглянуті у розділі «Сучасні системи програмування».

Широко поширеним прикладом інтерпретованої мови може бути HTML (Hypertext Markup Language) - мова опису гіпертексту. На його основі зараз функціонує практично вся структура мережі Інтернет. Інший приклад - мови Javaта JavaScript – поєднують у собі функції компіляції та інтерпретації. Текст вихідної програми компілюється в деякий проміжний двійковий код, що не залежить від архітектури цільової обчислювальної системи, цей код поширюється по мережі і виконується на стороні, що приймає - інтерпретується.

Транслятори з мови асемблера («ассемблери»)

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

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

Реалізація компіляторів з мови асемблера

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

Поле мітки містить ідентифікатор, що є міткою, або є порожнім. Кожен ідентифікатор мітки може зустрічатися у програмі мові асемблера лише один раз. Мітка вважається описаною там, де вона упосередньо зустрілася у програмі (попередній опис міток потрібно). Мітка може бути використана для передачі управління на пов'язану нею команду. Нерідко мітка відокремлюється від решти команди соціальним роздільником (найчастіше - двокрапкою «:»).

Код операції завжди являє собою строго певну мнемоніку однією з можливих команд процесора або також строго певну команду (мого компілятора. Код операції записується алфавітними символами вхс ного мови. Найчастіше його довжина становить 3-4, рідше - 5 або 6 символів.

Поле операндів або є порожнім, або являє собою список з одного, двох, рідше - трьох операндів. Кількість операндів суворо визначено і: висить від коду операції - кожна операція мови асемблера передбачає жорстко задане число своїх операндів. Відповідно, кожному з цих варіантів відповідають безадресні, одноадресні, двоадресні або триадресні команди (більше число операндів практично не використовується, в сучасних ЕОМ навіть триадресні команди зустрічаються рідко). Як опер; дов можуть виступати ідентифікатори чи константи.

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

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

Наприклад, наступна послідовність команд

Є прикладом послідовності команд мови асемблера п; цесорів сімейства Intel 80x86. Тут присутні команда опису наб (даних (db), мітка (loops), коди операцій (mov, dec і jnz). Операндами є ідентифікатор набору даних (datas), позначення регістрів процесу

(Ьх і сх), мітка (loops) та константа (4). Складовий операнд datas відображає непряму адресацію набору даних datas за базовим регістром Ьх зі зміщенням 4.

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

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

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

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

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

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

Макровизначення та макрокоманди

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

Для полегшення праці розробника було створено звані макрокоманди.

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

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

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

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

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

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

Синтаксис макрокоманд і макровизначень перестав бути суворо заданим. Він може відрізнятися залежно від реалізації компілятора з мови асемблера. Але сам принцип виконання макропідстановок у тексті програми незмінний і не залежить від їхнього синтаксису.

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

Наприклад, наступний текст визначає макрокоманду push_0 у мові асемблера процесора типу Intel 8086:

Хог ах,ах ■ push ax endm

Семантика цієї макрокоманди полягає у записі числа «0» у стек через регістр процесора ах. Тоді скрізь у тексті програми, де зустрінеться макрокоманда

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

Хог ах,ах ■ push ax

Це найпростіший варіант макровизначення. Існує можливість створювати складніші макровизначення з параметрами. Одне з таких макровизначень описано нижче:

Глибина такої рекурсії, як правило, дуже обмежена. На послідовність рекурсивних викликів макрокоманд накладаються зазвичай більш жорсткі обмеження, ніж на послідовність рекурсивних викликів процедур і функцій, яка при стіковій організації дисплея пам'яті обмежена тільки розміром стека передачі параметрів. add_abx macro xl,x2

Push ax
endm

Тоді в тексті програми макрокоманда також має бути зазначена з відповідним числом параметрів. У цьому прикладі макрокоманда

Add_abx4,8 буде в результаті макропідстановки замінено на послідовність команд:

Add ах,4 add bx.4 add ex,8 push ax

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

Loop_ax macro xl, x2, yl

Хог bx.bx loopax: add bx.yl

Тут мітка 1 oopax є локальною, визначеною лише всередині цього макровизначення. У цьому випадку вже не може бути виконана проста текстова підстановка макрокоманди в текст програми, оскільки якщо цю макрокоманду виконати двічі, це призведе до появи в тексті програми двох однакових міток 1 оорах. У такому варіанті макрогенератор повинен використовувати складніші методи текстових підстановок, аналогічні тим, що використовуються в компіляторах при ідентифікації лексичних елементів вхідної програми, щоб дати всім можливим локальним змінним та міткам макрокоманд унікальні імена в межах усієї програми. Макровизначення і макрокоманди знайшли застосування у мовах асемблера, а й у багатьох мовами високого рівня. Там їх обробляє спеціальний модуль, який називається препроцесором мови (наприклад, широко відомий препроцесор мови С). Принцип обробки залишається тим самим, що й програм мовою асемблера - препроцессор виконує текстові підстановки безпосередньо над рядками самої вихідної програми. У мовах високого рівня макровизначення повинні бути відокремлені від тексту самої вихідної програми, щоб препроцесор не міг сплутати їх із синтаксичними конструкціями вхідної мови. Для цього використовуються або спеціальні символи та команди (команди препроцесора), які ніколи не можуть зустрічатися в тексті вихідної програми, або макровизначення зустрічаються

Усередині незначної частини вихідної програми - входять до складу коментарів (така реалізація існує, наприклад, компіляторі з мови Pascal, створеному фірмою Borland). Макрокоманди, навпаки, можуть зустрічатися у довільному місці вихідного тексту програми, і синтаксично їх виклик може відрізнятися від виклику функцій у вхідному мові.

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

Розглянемо приклад мовою С. Якщо описано функцію

Int fKint a) ( return a + а: ) та аналогічна їй макрокоманда

#define f2(a) ((a) + (а)) результат їх виклику не завжди буде однаковий.

Дійсно, виклики j=fl(i) і j=f2(i) (де i та j - деякі цілочисленні змінні) призведуть до одного й того самого результату. Але виклики j=fl(++i) та j=f2(++i) дадуть різні значеннязмінної j. Справа в тому, що оскільки f2 - це макровизначення, то в другому випадку буде виконано текстову підстановку, яка призведе до послідовності операторів j=((++i) + (++i)). Видно, що в цій послідовності операція ++i буде виконана двічі, на відміну від функції fl(++i), де вона виконується тільки один раз.

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

Існують два види трансляторів: інтерпретатори, компілятори.

Інтерпретаторомназивається транслятор, що проводить пооператорну (покомандну) трансляцію та подальше виконання відтрансльованого оператора вихідної програми. Два недоліки методу інтерпретації:

1. інтерпретуюча програма повинна бути у пам'яті ЕОМ протягом усього процесу виконання вихідної програми, тобто займати певний обсяг пам'яті;

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

Компілятор– це програма, яка перетворює (транслює) вихідну програму на програму (модуль) машинною мовою. Після цього програма записується на згадку про комп'ютера і потім виконується.

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

Будь-який транслятор вирішує такі основні завдання:

1. Аналізує програму, що транслюється, і визначає, чи містить вона синтаксичні помилки;

2. Генерує вихідну програму мовою команд ЕОМ;

3. Розподіляє пам'ять вихідної програми, тобто. кожній змінній, константі, масивам та іншим об'єктам відводиться свою ділянку пам'яті.

Таким чином, Компілятор(англ. compiler- упорядник, збирач) читає всю програму повністю, робить її переклад і створює закінчений варіант програми машинною мовою, який потім і виконується.

Інтерпретатор(англ. interpreter- тлумач, усний перекладач) перекладає та виконує програму рядок за рядком.

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

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

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

Транслятор - обслуговуюча програма, що перетворює вихідну програму, надану вхідною мовою програмування, в робочу програму, представлену об'єктною мовою.

В даний час транслятори поділяються на три основні групи: асемблери, компілятори та інтерпретатори.

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

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

Компілятор - це обслуговуюча програма, що виконує трансляцію машинною мовою програми, записаної вихідною мовою програмування. Так само як і асемблер, компілятор забезпечує перетворення програми з однієї мови на іншу (найчастіше в мову конкретного комп'ютера). Разом з тим, команди вихідної мови значно відрізняються за організацією та потужністю від команд машинної мови. Існують мови, у яких одна команда вихідної мови транслюється у 7-10 машинних команд. Проте є й такі мови, у яких кожній команді може відповідати 100 і більше машинних команд (наприклад, Пролог). Крім того, у вихідних мовах досить часто використовується сувора типізація даних, що здійснюється через їх попередній опис. Програмування може спиратися не так на кодування алгоритму, але в ретельне обдумування структур даних чи класів. Процес трансляції з таких мов зазвичай називається компіляцією, а вихідні мови зазвичай належать до мов програмування високого рівня (чи високорівневих мов). Абстрагування мови програмування від системи команд комп'ютера призвело до незалежного створення найрізноманітніших мов, орієнтованих вирішення конкретних завдань. З'явилися мови для наукових розрахунків, економічних розрахунків, доступу до баз даних та інші.

Інтерпретатор - програма або пристрій, що здійснює пооператорну трансляцію та виконання вихідної програми. На відміну від компілятора, інтерпретатор не породжує на виході програму машинною мовою. Розпізнавши команду вихідної мови, він одразу виконує її. Як у компіляторах, і у інтерпретаторах використовуються однакові методи аналізу вихідного тексту програми. Але інтерпретатор дозволяє розпочати обробку даних після написання навіть однієї команди. Це робить процес розробки та налагодження програм більш гнучким. Крім того, відсутність вихідного машинного коду дозволяє не "захаращувати" зовнішні пристрої додатковими файлами, а сам інтерпретатор можна досить легко адаптувати до будь-яких машинних архітектур, розробивши його лише один раз широко поширеною мовою програмування. Тому, що інтерпретуються мови, типу Java Script, VB Script, набули широкого поширення. Недоліком інтерпретаторів є низька швидкість виконання програм. Зазвичай інтерпретовані програми виконуються в 50-100 разів повільніше за програми, написані в машинних кодах.

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

Емулятори використовуються досить часто в різних цілях. Наприклад, при розробці нових обчислювальних систем спочатку створюється емулятор, що виконує програми, що розробляються для ще неіснуючих комп'ютерів. Це дозволяє оцінити систему команд та напрацювати базове програмне забезпечення ще до того, як буде створено відповідне обладнання.

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

Перекодувальник - програма або програмний пристрій, що перекладають програми, написані машинною мовою однієї ЕОМ в програми машинною мовою іншої ЕОМ. Якщо емулятор є менш інтелектуальним аналогом інтерпретатора, то перекодувальник виступає в тій же якості по відношенню до компілятора. Точно також вихідний (і зазвичай двійковий) машинний код або проміжне уявлення перетворюються на інший аналогічний код по одній команді і без будь-якого загального аналізу структури вихідної програми. Перекодувальники бувають корисні при перенесенні програм з одних комп'ютерних архітектур на інші. Вони можуть також використовуватися для відновлення тексту програми мовою високого рівня за наявним двійковим кодом.

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

Макропроцесори використовують і з мовами високого рівня. Вони збільшують функціональні можливості мов PL/1, C, C++. Особливо широко макропроцесори застосовуються C і C++, дозволяючи спростити написання програм. Макропроцесори підвищують ефективність програмування без зміни синтаксису та семантики мови.

Синтаксис - сукупність правил деякої мови, що визначають формування її елементів. Інакше висловлюючись, це сукупність правил освіти семантично значимих послідовностей символів у цій мові. Синтаксис задається за допомогою правил, що описують поняття деякої мови. Прикладами понять є: змінна, вираз, оператор, процедура. Послідовність понять та його допустиме використання у правилах визначає синтаксично правильні структури, що утворюють програми. Саме ієрархія об'єктів, а чи не те, як вони взаємодіють між собою, визначаються через синтаксис. Наприклад, оператор може зустрічатися тільки у процедурі, а вираз в операторі, змінна може складатися з імені та необов'язкових індексів тощо. Синтаксис не пов'язаний з такими явищами у програмі як "перехід на неіснуючу мітку" або "змінна з цим ім'ям не визначена". Цим займається семантика.

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

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

Будь-який транслятор виконує такі основні завдання:

Аналізує програму, що транслюється, зокрема визначає, чи містить вона синтаксичні помилки;

Генерує вихідну програму (її часто називають об'єктною) мовою машинних команд;

Розподіляє пам'ять об'єктної програми.