
- •Анотація
- •1. Огляд методів та способів проектування трансляторів
- •1.1. Введення в трансляцію
- •1.2. Структура транслятора
- •1.3. Проходи транслятора
- •1.4. Засоби побудови трансляторів
- •2. Формальний опис вхідної мови програмування
- •2.1 Деталізований опис вхідної мови в термінах ebnf
- •2.2 Опис термінальних символів та ключових слів
- •3. Розробка транслятора вхідної мови
- •3.1 Вибір технології програмування
- •3.2 Проектування таблиць транслятора та вибір структур даних
- •3.3 Розробка лексичного аналізатора
- •Розробка граф-схеми алгоритму
- •Опис програми реалізації лексичного аналізатора
- •3.4 Розробка синтаксичного та семантичного аналізатора
- •Розробка граф-схеми алгоритму
- •Опис програми реалізації синтаксичного та семантичного аналізатора
- •3.5 Розробка генератора коду
- •Розробка граф-схеми алгоритму
- •Опис програми реалізації генератора коду
- •Повне дерево граматичного розбору
- •Результат роботи генератора коду:
- •4. Опис інтерфейсу та інструкції користувача
- •5. Відлагодження та тестування програми
- •5. 1. Виявлення лексичних помилок
- •Виявлення синтаксичних помилок
- •Для початку протестуємо наступний код в якому навмисно допущено різноманітні помилки. Як видно з (рис. 5.2) транслятор коректно виявляє різноманітні синтаксичні помилки.
- •Виявлення семантичних помилок
- •5.2. Загальна перевірка коректності роботи транслятора
- •Висновки
- •Список літератури
- •Додаток а: Завдання на курсову роботу
- •Додаток б: Загальний алгоритм роботи транслятора
- •Додаток в. Текст коректної програми на мові z30
1.3. Проходи транслятора
При реалізації транслятора одна чи декілька фаз (можлива частина фази) об’єднуються в програмні модулі, названі проходами. За кожного проходу прочитується з файлу початкова програма чи результат попереднього проходу; здійснюється перетворення, задане його фазами; записується результат у проміжний або в результатний файл. Число проходів та методика об`єднання фаз у прохід визначаються особливостями вхідної та вихідної мов. Так, у мові ПЛ-1 описи даних можуть з`явитися після їхнього використання, як наприклад у групі операторів goto M; . . . ; M: a:=b+c;, де до ідентифікатора М звертаються раніше, ніж до опису. За такої ситуації скласти повністю код для оператора goto M; не можна до обробки опису М (оператора М: а:=b+c). Реалізація таких мов потребує щонайменше двох проходів.[2]
Кілька проходів можна скомбінувати в один, виконуючи їх паралельно із взаємною синхронізацією – таким чином створюється однопрохідний транслятор. Результат одного проходу, потрібний іншому, завдяки синхронізації та буферам дозволяє побудувати необхідний інтерфейс між фазами. Як правило, в однопрохідному трансляторі ведучою є фаза синтаксичного аналізу, яка кожного разу, коли потрібна їй лексема, запрошує фазу лексичного аналізу, керує генерацією проміжного коду, передає команди цього коду генератору коду для створення програми вихідною мовою. Проблеми, що виникають при використанні елемента даних раніше його означення за єдиного проходу, можна розв`язати методом оберненого заповнення: при генерації коду для команди goto M; за невизначеного М формується неповна команда і запам`ятовується її місце, а в момент визначення мітки М заповнюються всі порожні місця. Проте цей метод працює тоді, коли віддаль між точками використання та означення імені невелика.[3]
1.4. Засоби побудови трансляторів
Існують спеціальні засоби (компілятори компіляторів, генератори компіляторів тощо) для полегшення конструювання компіляторів чи трансляторів. Ідеальною вважається ситуація, коли є програма (або система програм), яка автоматично будує компілятор, маючи на вході описи лексики, синтаксису вхідної мови, результатів перетворень синтаксичних конструкцій та опис цільової машини.
Для полегшення побудови трансляторів розроблені такі основні інструментальні засоби: генератор лексичних аналізаторів, в якому інформація про лексеми задається регулярними виразами, а можливі дії обробки – операторами мови Сі; генератор, який за граматикою початкової мови створює СА з діями обробки; засоби генерації коду – спеціальні мови, зручні для опису процесу генерації вихідного коду.
2. Формальний опис вхідної мови програмування
Одною з перших задач, що виникають при побудові компілятора, є визначення вхідної мови програмування. Для цього використовують різні способи формального опису, серед яких я використаю розширену нотацію Бекуса-Наура (Backus/Naur Form - BNF).
2.1 Деталізований опис вхідної мови в термінах ebnf
Правила написання правил у розширеній нотації Бекуса-Наура:
нетермінальні вирази записуються у кутових дужках: “<”, “>” ;
термінальні вирази записуються жирним шрифтом або у подвійних лапках;
усі нетермінальні вирази мають бути “розкриті” за допомогою термінальних;
символ “::=” відділяє праву частину правила від лівої;
символ “|” розділяє альтернативи;
символи “[”, “]” означають необов’язковість (вираз в дужках може бути відсутнім);
символи “{”, “}” означають повторення.
Таблиця 2.1 Деталізований опис вхідної мови
<program> |
::= startprogram startblock <declaration> {<statement>} endblock |
<statement> |
::= <condition> | <input> | <output>| <assign> |
<declaration> |
::= variable <var> [>> <number>] {,<var> [>> <number>] } integer_4; |
<assign> |
::= <var> >> <expression>; |
<var> |
::= <letter>{<letter> | <digit>} |
<letter> |
::= a..z |
<digit> |
::= 0..9 |
< condition > |
::= if <expression> startblock {<statement>} endblock else startblock {<statement>} endblock |
<number> |
::= <digit> {<digit>} |
<input> |
::= read <var>; |
<output> |
::= write <var> | <string> | <num> {,<var> | <string> | <num>}; |
<equality> |
::= =| <> |
<comparison> |
::= !> | !< |
<addition> |
::= add | sub |
<multiplication> |
::= * | / | % |
<expression> |
::= <atom> [{ || <atom> }] |
<atom> |
::= <eq> [{ && <eq> }] |
<eq> |
::= <comp> [{ <equality> <comp> }] |
<comp> |
::= <term> [{ <comparison> <term> }] |
<term> |
::= <mult> [{ <addition> <mult> }] |
<mult> |
::= <operand> [{ <multiplication> <operand> }] |
<operand> |
::= <var> | <number> | (<expression>) | !!<var> | !!<number> | !!(<expression>) |