Інформація про навчальний заклад

ВУЗ:
Інші
Інститут:
Не вказано
Факультет:
Не вказано
Кафедра:
Не вказано

Інформація про роботу

Рік:
2024
Тип роботи:
Курсова робота
Предмет:
Інші

Частина тексту файла (без зображень, графіків і формул):

Міністерство освіти і науки України. Національний університет “Львівська політехніка” ІКТАМ Кафедра ЕОМ КУРСОВА РОБОТА з предмету: “Системне програмування” на тему: “Розробка системних програмних модулів та компонент систем програмування” Львів-2007 АНОТАЦІЯ Транслятором називається програма перекладу (трансляції) початкової програми, записаною вхідною мовою, в еквівалентну їй об`єктну програму. Якщо мова високого рівня є вхідною, а мова асемблера чи машинна – вихідною, то такий транслятор називається компілятором. Транслятори дозволяють пререкладати програми із вхідної мови програмування в деяку вихідну, які пізніше, після етапів компіляції та зв`язування, перетворюються у виконавчі файли. Потреба різноманіття трансляторів дуже важлива, це прямо залежить від вхідної мови, яку він перекладає. Кожна з них реалізує клас задач, необхідних для користувача. Кажучи простіше, існує виконавець – автомат або персональна ЕОМ, що вміє реалізувати скінчений набір дій. Наказ на виконання дії з вказаного набору, що виражається певним, раніше обумовленим способом, називається розпорядженням, а вся сукупність допустимих наказів – системою розпорядження виконавця. Даючи завдання виконавцю на деяку роботу, ми звичайно даємо йому не одне розпорядження, а деяку скінчену послідовність розпоряджень, задаючи також порядок, у якому вони виконуються. Така послідовність розпоряджень з вказанням порядку їх виконання називається програмою. Саме програма на певній мові програмування є вхідним даним для транслятора, що перекладає послідовність команд вхідної мови програмування в деяку вихідну. ЗАВДАННЯ Варіант 52; Розробити транслятор вхідної мови програмування , короткий опис якої подано нижче: - типи даних: int_4; - оператор вводу: get (); - оператор виводу: put (); - блок тіла програми: - оператор: do-while (сі); - регістр ключових слів: Lov; - регістр ідентифікаторів: Up-Low4 перший символ_; - операції арифметичні: add, sub, *, /, %; - операції порівняння: ==, !=, !>, !< - операції логічні: not, and, or; - коментар: {* *} - ідентифікатори змінних, числові константи; - оператор присвоєння: := ; Для отримання виконавчого файлу на виході розробленого транслятора скористатися програмами tasm.exe і tlink.exe. ЗМІСТ АНОТАЦІЯ 2 ЗАВДАННЯ 3 ВСТУП 6 1. ОГЛЯД МЕТОДІВ ТА СПОСОБІВ ПРОЕКТУВАННЯ ТРАНСЛЯТОРІВ 7 1.1. Введення в трансляцію 7 1.2. Структура транслятора 7 1.3. Проходи транслятора 8 1.4. Засоби побудови трансляторів 9 2. ФОРМАЛЬНИЙ ОПИС ВХІДНОЇ МОВИ ПРОГРАМУВАННЯ 10 2.1. Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура. 10 2.2. Термінальні символи та ключові слова 11 3. РОЗРОБКА ТРАНСЛЯТОРА ВХІДНОЇ МОВИ ПРОГРАМУВАННЯ 12 3.1. Вибір технології програмування 12 3.2. Проектування таблиць транслятора 13 3.3. Розробка лексичного аналізатора 15 3.4. Розробка синтаксичного та семантичного аналізатора 20 3.5. Розробка генератора коду 24 4. ОПИС ПРОГРАМИ (В ТОМУ ЧИСЛІ ГРАФ-СХЕМ) 25 5. ОПИС ІНТЕРФЕЙСУ ТА ІНСТРУКЦІЯ КОРИСТУВАЧЕВІ 31 6. ВІД ЛАГОДЖЕННЯ ТА ТЕСТУВАННЯ ПРОГРАМИ 32 6.1. Виявлення лексичних помилок 32 6.2. Виявлення синтаксичних помилок 32 6.3. Виявлення семантичних помилок 32 6.4. Загальна перевірка коректності роботи транслятора 33 7. ВИСНОВКИ 34 СПИСОК ЛІТЕРАТУРИ 35 ДОДАТКИ 36 Додаток 1. Текст програми-транслятора на мові С++. 36 Додаток 2. Текст програми з лексичними помилками. 78 Додаток 3. Текст файлу з повідомленнями про лексичні помилки. 78 Додаток 4. Текст програми з синтаксичними помилками. 78 Додаток 5. Текст файлу з повідомленнями про синтаксичні помилки. 78 Додаток 6. Текст програми з семантичними помилками. 79 Додаток 7. Текст файлу з повідомленнями про семантичні помилки. 79 Додаток 8. Текст коректної програми. 79 Додаток 9. Результати виконання програми. 80 ВСТУП Компілятори становлять істотну частину програмного забезпечення ЕОМ. Це пов’язано з тим, що мови високого рівня стали основним засобом розробки програм. Тільки дуже незначна частина програмного забезпечення, що вимагає особливої ефективності, програмується за допомогою асемблерів. На сьогодні існує досить багато мов програмування. Нарівні з традиційними мовами, такими, як Fortran, широке поширення отримали так звані «універсальні мови» (Паскаль, Сі, Модула-2, Ада та інші), а також деякі спеціалізовані (наприклад, мова обробки облікових структур Лісп). Крім того, велике поширення отримали мови, пов’язані з вузькими предметними областями, такі, як вхідні мови пакетів прикладних програм. Для деяких мов є досить багато реалізацій. Наприклад, реалізацій Паскаля, Модули-2 або Сі для ЕОМ типу IBM/PC на ринку десятки. З іншого боку, постійно зростаюча потреба в нових компіляторах пов’язана з бурхливим розвитком архітектури ЕОМ. Цей розвиток йде у різних напрямах. Удосконалюється стара архітектура, як в концептуальному відношенні, так і по окремих, конкретних лініях. Це можна проілюструвати на прикладі мікропроцесора Intel 80х86. Послідовні версії цього мікропроцесора 8086, 80186, 80286, 80386, 80486, 80586 відрізняються не тільки технічними характеристиками, але і, що більш важливо, новими можливостями і, значить, зміною (розширенням) системи команд. Отже, це вимагає нових компіляторів (або модифікації старих). Також бурхливо розвивається різна паралельна архітектура – векторні системи, багатопроцесорні системи, а також системи з широким командним словом (VLIW), варіантом яких є суперскалярні ЕОМ. На ринку вже є десятки типів ЕОМ з паралельною архітектурою, починаючи від супер-ЕОМ (Cray, CDC та інші), через робочі станції (наприклад, IBM/RS-6000) і закінчуючи персональними (наприклад, на основі мікропроцесора і860). Отже, для кожної з машин створюються нові компілятори для багатьох мов програмування. Тут необхідно також відмітити, що нова архітектура вимагає розробки абсолютно нових підходів до створення компіляторів, так що поряд з розробкою компіляторів ведеться і велика наукова робота по створенню нових методів трансляції. 1. ОГЛЯД МЕТОДІВ ТА СПОСОБІВ ПРОЕКТУВАННЯ ТРАНСЛЯТОРІВ 1.1. Введення в трансляцію. Транслятором називається програма перекладу (трансляції) початкової програми, записаної вхідною мовою, в еквівалентну їй об`єктну програму. Якщо мова високого рівня є вхідною, а мова асемблера чи машинна – вихідною, то такий транслятор називається компілятором. Програма, записана мовою високого рівня, найчастіше має два етапи – компіляції та виконання. На першому початкова програма перекладається машиною А в об`єктну програму мовою машини, на другому вона заноситься в пам`ять машини В. При її виконанні, за необхідності вводяться початкові дані та виводяться результати. Якщо А і В –різні машини, то говорять, що на ЕОМ А виконується крос-компіляція, і такий транслятор називається крос-компілятором. Інтерпретатором є різновид транслятора для перекладу початкової програми в програму, записану простою проміжною алгоритмічною мовою, та для її виконання. Деякі програми в проміжну форму не перекладається, а відразу виконуються. Інтерпретатор простіший від компілятора, але працює повільніше. Транслятор з різними вхідною та об`єктною мовами високого рівня називається препроцесором. Як частина компілятора, він при бажанні може використовуватися самостійно для розширення можливостей конкретної мови програмування (наприклад мови Сі). 1.2. Структура транслятора. Компілятор – це велика за розмірами програма. Складання компілятора ділять на фази, на яких перетворюють одне зображення програми в інше. Фази лексичного (ЛА) та синтаксичного (СА) аналізів розкладають початкову програму на частини. Генерація коду проміжною мовою (ГПК), оптимізація (ОК) та генерація коду (ГК) асемблера синтезують програму на вихідній мові. Керування таблицями (КТ) та обробка помилками (ОП) використовуються на всіх фазах трансляції. Лексичний аналіз об`єднує літери в лексеми – службові слова, ідентифікатори, знаки операцій та пунктуації. Лексеми можна кодувати цілими числами, наприклад, do-одиницею, “+” – двійкою, ідентифікатор – трійкою, константу – четвіркою тощо. До коду лексем ідентифікаторів і констант додається ще одна величина – вид чи значення лексеми. Синтаксичний аналіз групує лексеми в синтаксичні структури, які можуть бути складовими інших синтаксичних структур; наприклад, А+В може входити в оператор чи вираз. Як рекурсивні структури даних, вони зображуються (явно чи неявно) у формі дерева з лексемами в вузлах і з позначенням синтаксичних конструкцій у внутрішніх вузлах. Крони піддерев відтворюють частини програми відповідної синтаксичної конструкції. Необов`язкова оптимізація коду має призначенням створення проміжного коду, за якого асемблерна програма буде ефективніша. Керування таблицями розв`язує задачу зберігання імен, використаних у програмі, інформації про них (наприклад, типу даних) та доступу до цієї інформації. Переважно використовується таблиця символів як структура даних. Обробка помилок відбувається кожного разу, коли помічені дефекти у програмі. Вона полягає у формуванні повідомлення про помилку та її нейтралізації, тобто виправленні інформації для передачі наступній фазі, щоб остання могла виконуватися. Основна мета – за одну обробку програми транслятором виявити максимум помилок. 1.3. Проходи транслятора. При реалізації транслятора одна чи декілька фаз (можлива частина фази) об’єднуються в програмні модулі, названі проходами. За кожного проходу прочитується з файлу початкова програма чи результат попереднього проходу; здійснюється перетворення, задане його фазами; записується результат у проміжний або в результатний файл. Число проходів та методика об`єднання фаз у прохід визначаються особливостями вхідної та вихідної мов. Так, у мові ПЛ-1 описи даних можуть з`явитися після їхнього використання, як наприклад у групі операторів goto M; . . . ; M: a:=b+c;, де до ідентифікатора М звертаються раніше, ніж до опису. За такої ситуації скласти повністю код для оператора goto M; не можна до обробки опису М (оператора М: а:=b+c). Реалізація таких мов потребує щонайменше двох проходів. Кілька проходів можна скомбінувати в один, виконуючи їх паралельно із взаємною синхронізацією – таким чином створюється однопрохідний транслятор. Результат одного проходу, потрібний іншому, завдяки синхронізації та буферам дозволяє побудувати необхідний інтерфейс між фазами. Як правило, в однопрохідному трансляторі ведучою є фаза синтаксичного аналізу, яка кожного разу, коли потрібна їй лексема, запрошує фазу лексичного аналізу, керує генерацією проміжного коду, передає команди цього коду генератору коду для створення програми вихідною мовою. Проблеми, що виникають при використанні елемента даних раніше його означення за єдиного проходу, можна розв`язати методом оберненого заповнення: при генерації коду для команди goto M; за невизначеного М формується неповна команда і запам`ятовується її місце, а в момент визначення мітки М заповнюються всі порожні місця. Проте цей метод працює тоді, коли віддаль між точками використання та означення імені невелика. 1.4. Засоби побудови трансляторів. Існують спеціальні засоби (компілятори компіляторів, генератори компіляторів тощо) для полегшення конструювання компіляторів чи трансляторів. Ідеальною вважається ситуація, коли є програма (або система програм), яка автоматично будує компілятор, маючи на вході описи лексики, синтаксису вхідної мови, результатів перетворень синтаксичних конструкцій та опис цільової машини. Для полегшення побудови трансляторів розроблені такі основні інструментальні засоби: генератор лексичних аналізаторів, в якому інформація про лексеми задається регулярними виразами, а можливі дії обробки – операторами мови Сі; генератор, який за граматикою початкової мови створює СА з діями обробки; засоби генерації коду – спеціальні мови, зручні для опису процесу генерації вихідного коду. 2. ФОРМАЛЬНИЙ ОПИС ВХІДНОЇ МОВИ ПРОГРАМУВАННЯ 2.1. Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура. Однією з перших задач, що виникають при побудові компілятора, є визначення вхідної мови програмування. Для цього використовують різні способи формального опису, серед яких я застосував розширену нотацію Бекуса-Наура (Backus/Naur Form - BNF). <program> ::= mainprogram data <data_blok> start <code_blok> end . <data_blok> ::= <type> [<declaration> [{, <declaration>} ] ] ; . <type> ::= int_4 . <declaration> ::= <ident> [ <is> <const> ] . <is> ::= := . <ident> ::= _<h_letter>[<l _or_n>][<l _or_n>][<l _or_n>][<l _or_n>] . <l_or_n> ::= <l_letter>|<number> . <h_letter> ::= A|B|C|D|E|F|G|H|I|J|K|L|N|M|O|P|Q|R|S|T|U|V|W|X|Y|Z . <l_letter> ::= a|b|c|d|e|f|g|h|i|j|k|l|n|m|o|p|q|r|s|t|u|v|w|x|y|z . <number> ::= 0|1|2|3|4|5|6|7|8|9 . <const> ::= [-]<number>[{number}] . <code_blok> ::= <statement> [{<statement>}] . <statement> ::= <equation>|<cycle>|<get>|<put> . <equation> ::= <ident><is><expression> . <expression> ::= [(] <operand> [)] [{ [)]<operation>[(]<operand> [)] }] ; . <operand> ::= <ident>|<const> . <operation> ::= add|sub|/|*|%|not|or|and|!>|!<|!=|== . <cycle> ::= <do><code_blok> <while> . <do> ::= do <open_blok> . <open_blok> ::= { . <while> ::= <close_blok> while <expression> . <close_blok> ::= } . <get> ::= get(<ident>); . <put> ::= put <expression> . 2.2. Термінальні символи та ключові слова. Визначимо окремі термінальні символи та нерозривні набори термінальних символів (ключові слова): ; , := add sub * / % and not or !> !< == != ( ) { } int_4 mainprogram data start end put get do while До термінальних символів віднесемо також усі цифри (0-9), латинські букви (a-z, A-Z), символи табуляції,символ переходу на нову стрічку, пробілу, знаку “-“ та підчерку. 3. РОЗРОБКА ТРАНСЛЯТОРА ВХІДНОЇ МОВИ ПРОГРАМУВАННЯ 3.1. Вибір технології програмування. Для ефективної роботи створюваної програми важливу роль відіграє попереднє складення алгоритму роботи програми, алгоритму написання програми і вибір технології програмування, а саме використання яких структур, типів даних чи алгоритмів дасть нам виграш у кількості коду, його якості і ефективності чи в розумінні. Тому робимо аналіз нашої програми. Для роботи з балансом дужок чи операторів, таких операторів як do{}while(); нам знадобиться структура стек. Тому на основі знань, здобутих в курсі основ програмування реалізовуємо стек, а також необхідні функції для роботи з ним: Push (закинути значення до стеку), Pop (витягнути значення зі стеку), IsEmpty (перевірка на порожній стек), IsFull (перевірка на повний стек), Init (ініціалізація стеку). Для полегшення роботи з типами використовуємо тип enum для перерахування всіх можливих типів і полегшення наступного опрацювання лексем. Для полегшення обробки лексем також використовуємо структуру Lexem для зберігання імені лексеми, значення (якщо це число), її типу та рядка вхідного файлу (для полегшення обробки помилок). Також використовуємо структуру Reg для зберігання робочих даних програми – таблиці лексем, таблиці ідентифікаторів, деяких допоміжних змінних, необхідних для використання у різних функціях програми, і буфер для виразу в постфіксній формі. Крім того, доцільним є розбиття коду на підпрограми (функції), оскільки великі частини коду часто повторюються. Для цього, наприклад, створені функції PrintAND, PrintOR, PrintNOT, PrintEQ, PrintNG, PrintNL тощо. Використання даних структур повинно спростити написання коду програми і полегшити її розуміння і читабельність, тому, на мою думку, технологія програмування вибрана вірно. 3.2. Проектування таблиць транслятора. Використання таблиць значно полегшує створення трансляторів, тому у даному випадку використовуються кілька таблиць: 1) Таблиця лексем з елементами, які мають таку структуру: Lexema LexAr[1000]; //таблиця лексем з елементами типу Lexema typedef struct Lexem { char name[50]; //ім’я int value; //значення TypeOfLex type; //тип }Lexema; enum TypeOfLex { mainprogram, data, int4, start, end, do_, while_, put, get, var, number, separator, //; koma, //, open, //( close, //) openblok, //{ closeblok, //} add_, sub_, not_, and_, or_, mul_, // * div_, // / mod_, // % is, //:= eq, //== neq, //!= ng, //!> nl, //!< eof, us //неопізнаний символ }; 2) Таблиця ідентифікаторів з елементами типу Identificator та додатковою цілочисельною змінною цілочисельного типу в якій зберігається кількість визначених змінних. Структура елементів така: typedef struct ID { char name[50]; //ім’я int val; //значення }Identificator; 3.3. Розробка лексичного аналізатора. Основна задача лексичного аналізу – розбити вихідний текст, що складається з послідовності одиночних символів, на послідовність слів, або лексем, тобто виділити ці слова з безперервної послідовності символів. Всі символи вхідної послідовності з цієї точки зору розділяються на символи, що належать яким-небудь лексемам, і символи, що розділяють лексеми. В цьому випадку використовуються звичайні засоби обробки рядків. Вхiдна програма проглядається послідовно з початку до кінця. Базовi елементи, або лексичнi одиницi, роздiляються пробілами, знаками операцiй i спецiальними символами (новий рядок, знак табуляції), i таким чином видiляються та розпізнаються iдентифiкатори, лiтерали i термiнальнi символи (операцiї, ключові слова). При виділенні лексеми вона розпізнається та записується у таблицю лексем за допомогою відповідного номера лексеми, що є унікальним для кожної лексеми із усього можливого їх набору. Це дає можливість наступним фазам компiляції звертатись лексеми не як до послідовності символів, а як до унікального номера лексеми, що значно спрощує роботу синтаксичного аналізатора: легко перевіряти належність лексеми до відповідної синтаксичної конструкції та є можливість легкого перегляду програми, як вгору, так і вниз, від текучої позиції аналізу. Також в таблиці лексем ведуться записи, щодо рядка відповідної лексеми – для місця помилки – та додаткова інформація. При лексичному аналiзі виявляються i вiдзначаються лексичнi помилки (наприклад, недопустимi символи i неправильнi iдентифiкатори). Лексична фаза вiдкидає також i коментарi, оскiльки вони не мають нiякого впливу на виконання програми, отже ж й на синтаксичний розбір та генерацію коду. Лексичний аналізатор (сканер) не обов’язково обробляє всю програму до початку всіх інших фаз. Якщо лексичний аналіз не виділяється як окрема фаза компіляції, а є частиною синтаксичного аналізу, то лексична обробка тексту програми виконується по мірі необхідності по запиту синтаксичного аналізатора. В даному курсовому проекті реалізовано прямий лексичний аналізатор, який виділяє з вхідного тексту програми окремі лексеми і на основі цього формує таблицю. На рисунках 1 і 2-4 показано блок-схеми лексичного аналізу.  Рис1. Блок-схема лексичного аналізатора.  Рис2. Блок-схема функції одержання лексем (частина 1).  Рис3. Блок-схема функції одержання лексем (частина 2).  Рис4. Блок-схема функції одержання лексем (частина 3). 3.4.Розробка синтаксичного аналізатора Синтаксичний аналіз – це процес, в якому досліджується послідовність лексем, яку повернув лексичний аналізатор, і визначається, чи відповідає вона структурним умовам, що сформульовані у визначені синтаксису мови. Синтаксичний аналізатор – це частина компілятора, яка відповідає за виявлення основних синтаксичних конструкцій вхідної мови. В задачу синтаксичного аналізатора входить: знайти та виділити основні синтаксичні конструкції мови в послідовності лексем програми, встановити тип та правильність побудови кожної синтаксичної конструкції і представити синтаксичні конструкції у вигляді, зручному для подальшої генерації тексту результуючої програми. Як правило, синтаксичні конструкції мови програмування можуть бути описані за допомогою контекстно-вільних граматик. Розпізнавач дає відповідь на питання, належить чи ні, ланцюжок вхідних лексем заданій мові. В даному трансляторі синтаксичний аналізатор працює паралельно почергово з генератором коду, частиною якого він і є. Принцип роботи такий: на основі нижче наведеного дерева граматичного розбору (рис.5) аналізується черговий набір послідовних лексем та викликається відповідна генерація асемблерного коду. Потім знову вище описані дії повторюються поки не обробляться всі лексеми. На рисунках 6 та 7 показано блок-схему роботи синтаксичного аналізатора.  Рис.5 Дерево граматичного розбору.  Рис.6 Блок-схема синтаксичного аналізатора(частина 1).  Рис.7 Блок-схема синтаксичного аналізатора(частина 2). 3.5.Розробка генератора коду Генерація коду – це машинно-залежний етап компіляції, під час якого відбувається побудова машинного еквівалента вхідної програми. Зазвичай входом для генератора коду служить проміжна форма представлення програми, а на виході може з’являтися об’єктний код або модуль завантаження. У компілятора, реалізованого в даній курсовій роботі, вихідна мова - програма на мові Assembler. Ця програма записується у файл, що має таку ж саму назву, як і файл з вхідним текстом, але розширення “asm”. Генерація коду відбувається одразу ж після синтаксичного аналізу. В даному трансляторі генератор коду послідовно викликає окремі функції, які записують у вихідний файл частини коду. PrintTitle(f,in); Записує код заголовку програми. CheckPresentGetPut(); Визначає присутність операторів вводу/виводу для наступної функції. PrintData(f); Записує сегмент даних (визначені змінні та службові буфери та змінні) PrintInit(f); Записує код ініціалізації сопроцесора. PrintCode(f); Записує сегмент коду. PrintEnding(f); Записує завершення програми та необхідні процедури. 4. ОПИС ПРОГРАМИ (В ТОМУ ЧИСЛІ ГРАФ-СХЕМ) Дана програма написана мовою С++ з використанням визначень нових типів, перечислень та класів: enum TypeOfLex //перечислення можливих типів лексем { mainprogram, data, int4, start, end, do_, while_, put, get, var, number, separator, //; koma, //, open, //( close, //) openblok, //{ closeblok, //} add_, sub_, not_, and_, or_, mul_, // * div_, // / mod_, // % is, //:= eq, //== neq, //!= ng, //!> nl, //!< eof, us //неопізнаний символ }; //DATA typedef struct Lexem { char name[50]; int value; TypeOfLex type; }Lexema; typedef struct ID { char name[50]; int val; }Identificator; typedef struct L { Lexema LexAr[1000]; //масив лексем int Len; // Identificator IdTable[50]; //масив ідентифікаторів int idnum; // int LTable[50]; //стек міток do{}while() int TopL; // bool IsPresentPut; //визначає присутність put(); bool IsPresentGet; //визначає присутність get(); int Errors; char InputFileName[50]; char OutputFileName[50]; int PFExpr[200]; //масив в якому вираз у постфіксній формі }Data; typedef struct Stacks //стеків тип { int st[200]; int top; }StackType; typedef class stack //клас який реалізує стек { public: StackType S; void Init(StackType* s) { s->top = -1; } void Push(int i, StackType* s) { … } int Pop(StackType* s) { … } bool IsEmpty(StackType* s) { … } bool IsFull(StackType* s) { … } void prints(StackType s) { … } }Stack; Stack s; Data Reg; //змінна-реєстр, в якій зберігаються основні дані програми В програмі також використовуються багато функцій тому і являється доволі структурованою. Головною функцією є int main(int argc, char* argv[]) з якої і починає своє виконання програма. В ній послідовно викликаються наступні функції: int LexicalAnalis(FILE*); -- виконує лексичний аналіз і створює масив лексем. void PrintLexArray(); -- видруковує в файл масив лексем. int CheckProgram(FILE*); -- перевіряє вхідну програму на коректність (згідно створеної таблиці лексем), якщо виявлені помилки, то програма видає повідомлення про помилки та завершує роботу. int CreateIdTab(FILE*); -- створює таблицю ідентифікаторів. void CodeGenerator(FILE*, char*); -- за таблицями ідентифікаторів та лексем генерує вихідний код на мові асемблера. Вище описані функції використовують в свою чергу наступні: Lexema* GetLex(FILE*); -- повертає в LexicalAnalis чергову лексему. void CheckPresentGetPut(); -- перевіряє присутність відповідних операторів в програмі. void PrintTitle(FILE*, char*); -- видруковує в вихідний файл заголовок програми. void PrintData(FILE*); -- видруковує в вихідний файл сегмент коду, який крім введених змінних за умови присутності операторів вводу/виводу (CheckPresentGetPut();) і службову інформацію для них та додаткові буфери. void PrintInit(FILE*); -- видруковує в вихідний файл код ініціалізації сопроцесора. void PrintEnding(FILE*); -- видруковує заключну частину коду та викликає наступні функції для запису: void PrintGet(FILE*); -- видруковує в вихідний файл процедуру вводу. void PrintPut(FILE*); -- видруковує в вихідний файл процедуру виводу. void PrintMOD(FILE*); -- видруковує в вихідний файл процедуру mod_. void PrintAND(FILE*); -- видруковує в вихідний файл процедуру and_. void PrintOR(FILE*); -- видруковує в вихідний файл процедуру or_. void PrintNOT(FILE*); -- видруковує в вихідний файл процедуру not_. void PrintEQ(FILE*); -- видруковує в вихідний файл процедуру eq. void PrintNL(FILE*); -- видруковує в вихідний файл процедуру nl. void PrintNG(FILE*); -- видруковує в вихідний файл процедуру ng. void PrintCode(FILE*); -- видруковує в вихідний файл основний код програми. Дана функція напряму чи опосередковано викликає наступні функції: void GenASMCode(const char *, FILE*); -- генерує код для окремих операцій. Використовує наступну функцію: int ConvertToPostfixForm(int); -- перетворює вирази в постфіксну форму. Використовує : bool IsOperation(TypeOfLex); -- перевіряє чи лексема є операція. bool Prioritet(TypeOfLex,StackType); void PushL(int); int PopL(); bool IsemptyL(); bool IsFullL(); void InitL(); -- функції роботи із стеком міток. 5. ОПИС ІНТЕРФЕЙСУ ТА ІНСТРУКЦІЯ КОРИСТУВАЧЕВІ Створений компілятор являється DOS програмою що запускається з командної стрічки з параметром, а саме іменем вхідного файлу в якому записана програма на вхідній мові. Файл повинен мати розширення .d52. Отже формат введення повинен бути таким: D52c <ім’я програми>.d52 У випадку некоректного введення програма видасть повідомлення про помилку і завершить своє виконання. Якщо коректно введене ім’я вхідного файлу та вдалось його відкрити, то компілятор почне його опрацювання. Початковою фазою обробки є лексичний аналіз (розбиття на окремі лексеми), наступною -- перевірка на правильність написання програми (вхідної). У випадку, коли виявлені помилки, компілятор видасть повідомлення про їхню присутність, вкаже в якому файлі можна ці помилки переглянути та завершить своє виконання. Якщо ж програма написана вірно, то компілятор перейде на наступну фазу семантичного розбору та генерації асемблерного коду та вкаже ім’я результуючого файлу з розширенням .asm та завершить своє виконання. Для одержання виконавчого файлу необхідно скористатись програмами tasm.exe filename.asm для компіляції та tlink filename.obj для лінкування. 6. ВІД ЛАГОДЖЕННЯ ТА ТЕСТУВАННЯ ПРОГРАМИ Відлагодження та тестування компілятора проводиться з використанням кількох вхідних програм з навмисне введеними помилками та з коректною програмою для загальної перевірки роботи транслятора. 6.1. Виявлення лексичних помилок. Виявлення лексичних помилок відбувається на стадії лексичного аналізу. При розборі вхідної програми на окремі лексеми лексичний аналізатор перевіряє чи відповідає отримана лексема лексиці заданої мови програмування. У випадку неспівпадіння лексемі присвоюється тип “невпізнаної лексеми”. Повідомлення про такі помилки можна побачити лише після виконання процедури перевірки таблиці лексем. Приклад виявлення: Текст програми з лексичними помилками (Додаток 2). Текст файлу з повідомленнями про лексичні помилки (Додаток 3). 6.2. Виявлення синтаксичних помилок. Виявлення синтаксичних помилок відбувається на стадії перевірки програми на коректність окремо від синтаксичного аналізу. При цьому перевіряється окремо кожне твердження яке може бути або виразом, або оператором (циклу, вводу/виводу), або оголошенням, та перевіряється структура програми в цілому. Приклад виявлення: Текст програми з синтаксичними помилками (Додаток 4). Текст файлу з повідомленнями про синтаксичні помилки (Додаток 5). 6.3. Виявлення семантичних помилок. Суттю виявлення семантичних помилок є перевірка числових констант на відповідність типу int_4 тобто знаковому цілому числу з відповідним діапазоном значень. Приклад виявлення: Текст програми з семантичними помилками (Додаток 6). Текст файлу з повідомленнями про семантичні помилки (Додаток 7). 6.4. Загальна перевірка коректності роботи транслятора. Загальна перевірка полягає в транслюванні завідомо коректної вхідної програми з використанням всіх можливостей мови в асемблерний код та перевірці на правильність виконання програми попередньо скомпільованої та злінкованої за допомогою tasm та tlink. Приклад виявлення: Текст коректної програми (Додаток 8). Результати виконання програми (Додаток 9). 7. ВИСНОВКИ В процесі виконання курсової роботи було виконано наступне: Складено формальний опис мови програмування D52c, в термінах розширеної нотації Бекуса-Наура, виділено усі термінальні символи та ключові слова. Створено компілятор мови програмування D52c, а саме: Розроблено прямий лексичний аналізатор, орієнтований на розпізнавання лексем, що є заявлені в формальному описі мови програмування. Розроблено синтаксичний аналізатор на основі автомата з магазинною пам’яттю. Складено таблицю переходів для даного автомата згідно правил записаних в термінах Бекуса-Наура. Розроблено генератор коду, відповідні процедури якого викликаються після перевірки синтаксичним аналізатором коректності запису чергового оператора, мови програмування D52c. Вихідним кодом генератора є програма
Антиботан аватар за замовчуванням

19.11.2013 19:11-

Коментарі

Ви не можете залишити коментар. Для цього, будь ласка, увійдіть або зареєструйтесь.

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!