МІНІСТЕРСТВО ОСВІТИ І НАУКИ, МОЛОДІ ТА СПОРТУ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
ІКТА
Пояснювальна записка
до курсової роботи
з дисципліни:
"Системне програмування" (III курс, 5-й семестр)
На тему : «Розробка системних програмних модулів та компонент систем програмування.»
Анотація
Курсова робота з дисципліни "Системне програмування" являється підсумком вивчення даного курсу, її мета закріпити теоретичні знання та практичні навички системного програмування.
В даній курсовій роботі здійснюється розробка транслятора з вхідної мови програмування, заданої завданням, на мову асемблер, з подальшою компіляцією отриманого коду і створення виконавчого файлу. Даний транслятор виконує лексичний аналіз, синтаксичний і семантичний і при наявності помилок створює список помилок і попереджень. У курсовій роботі створений лексичний аналізатор на базі скінченного автомата, а також синтаксичний аналізатор на основі рекурсивного спуску.
Зміст
Анотація……………………………………………………………………………………………………………………………………………………..2
Зміст…………………….……………………………………………………………………………………………………………………………………..3
Завдання на курсову роботу……………………..……………………………………………………………………………………………….4
Вступ……………………..………………………………………………………………………………........................................................5
Огляд методів та способів проектування трансляторів…………………….……………………………………………………..7
Формальний опис вхідної мови програмування…………………….………………………………………………………………..8
Деталізований опис вхідної мови в термінах розширеної нотації
Бекуса-Наура…………………….………………………………………………………………………………………………………………………..8
Опис термінальних символів та ключових слів………………………………………………………………………………………9
Розробка транслятора вхідної мови програмування….……………………………………………..……………………………11
Вибір технології програмування…………………………………………………….………………………………………………………11
Проектування таблиць транслятора та вибір структур даних………………………………………………………12
Розробка лексичного аналізатора…………………………………………………….……………………………………………………14
Розробка граф-схеми алгоритму……………………………………………………………………………………………………………15
Опис програми реалізації лексичного аналізатора…………………………………………………………..…………………..16
Розробка синтаксичного та семантичного аналізатора…………………………………………..……………………….16
Розробка дерева граматичного розбору…………..……………………………………………….…………………………………17
Розробка граф-схеми алгоритму……………………………………………………………………………………………………………19
Опис програми реалізації синтаксичного та
семантичного аналізатора……………………………………………….…………………………………………………………………..20
Розробка генератора коду……………………………………………………………..……………………………………………………….21
Розробка граф-схеми алгоритму……………………………………………………………………………………………………………21
Опис програми реалізації генератора коду………………………………………………………………..………………………….22
Опис інтерфейсу та інструкції користувача……………………………………………………………………………………………..23
Відлагодження та тестування програми…………………………………………………………………………………………………25
Виявлення лексичних помилок…………………………………………………………….………………………………………………….25
Виявлення синтаксичних помилок………………………………………………………………………………………………………….26
Загальна перевірка коректності роботи транслятора………………………………………………..……………………27
Висновки…………………………………………………………………..………………………………………………………………………………29
Список літератури…………………………………………………………….……………………………………………………………………..30
Додатки……………………………………………………………………………….…………………………………………………………………….31
А. Лістинг програм………………………………………………………..…………………………………………………………………………32
Завдання на курсову роботу
Тема: Розробка транслятора з вхідної мови програмування.
- типи даних: LONGINT, const string;
- оператор вводу: GET;
- оператор виводу: PUT;
- блок тіла програми: BEGIN, END
- оператор: FOR (C);
- регістр ключових слів:UP ;
- регістр ідентифікаторів: Up-Low4 перший символ Up ;
- операції арифметичні: +, -, *, DIV, MOD;
- операції порівняння: ==, !=, LT, GT
- операції логічні: NOT, AND, OR;
- коментар: /*
- ідентифікатори змінних, числові константи, рядкові константи;
- оператор присвоєння:<<;
Для отримання виконавчого файлу з вихідного асемблерного коду потрібно використовувати ml.ex (MASM32) вбудований в MSVisualStudio 2010.
Вступ
Транслятор – програма або технічний засіб, що виконує трансляцію програми. Транслятор зазвичай виконує також діагностику помилок, формує словники ідентифікаторів, видає для друку тексти програми і т. д.
Трансляція програми – перетворення програми, представленої на одній з мов програмування, в програму на іншій мові, в певному сенсі, рівносильну зпершою. Мова, на якій представлена вхідна програма, називається вихідним мовою, а сама програма – вихідним кодом. Вихідна мова називається цільовою мовою або об'єктним кодом.
Поняття трансляції відноситься не тільки до мов програмування, але і до інших комп'ютерних мов, на зразок мов розмітки, аналогічних HTML, і до природних мов, на зразок англійської або російської
Транслятори поділяються на:
Адресний.
Діалоговий.
Багатопрохідної.
Зворотний.(детранслятор).
Однопрохідної.
Оптимізуючий.
Синтаксично-орієнтований (синтаксично-керований).
Тестовий.
Мова процесорів (машинний код) зазвичай є низькорівневою. Існують платформи, які використовують в якості машинної мову високого рівня (наприклад, iAPX-432), але вони є винятком із правила через складність і високу вартість. Транслятор, який перетворює програми в машинну мову, який приймає і виконуваний безпосередньо процесором, називається компілятором.
Процес компіляції як правило складається з декількох етапів: лексичного, синтаксичного та семантичного аналізів (англ. Semanticanalysis), генерації проміжного коду, оптимізації та генерації результуючого машинного коду. Крім цього, програма як правило залежить від сервісів, наданих операційною системою і сторонніми бібліотеками (наприклад, файловий ввід-висновок або графічний інтерфейс), і машинний код програми необхідно пов'язати з цими сервісами. Для зв'язування зі статичними бібліотеками виконується редактор зв'язків або компонувальник (який може представляти із себе окрему програму або бути частиною компілятора), а з операційною системою і динамічними бібліотеками зв'язування виконується на початку виконання програми завантажувача.
1. Огляд методів та способів проектування трансляторів
Є такі методи створення компіляторів:
1. Прямий метод- цільовою мовою і мовою реалізації є асемблер.
2. Метод розкрути- саме цей метод і використовується у даній курсовій роботі, тобто вибирається інструмент (в даній курсовій це мова асемблер), для якого вже існує компілятор.
3.Використання крос-трансляторів.
4.З використанням віртуальних машин–дає спосіб отримати переносимо програму.
5. Компіляція на ходу.
В даній курсовій роботі згідно із завданням для парних варіантів необхідно реалізувати нисхідний метод граматичного розбору. Низхідний розбір — один з методів визначення приналежності вхідного рядка деякій формальній мові, описаній LL(k)-граматикою.
Для кожного нетермінального символу K будується функція, яка для будь-якого вхідного слова x робить дві речі:
Знаходить найбільший початок z слова x, здатний бути початком виводжуваного з K слова
Визначає, чи є початок z виводжуваним з K
Така функція має задовольняти наступні критерії:
зчитувати із ще необробленого вхідного потоку максимальний початок A, який є початком деякого слова, виводжуваного з K
визначати чи є A вивідним з K або просто невивідним початком виводжуваного з K слова
У випадку, якщо такий початок зчитати не вдається (і коректність функції для нетермінала K доведена), тоді вхідні дані не відповідають мові, і потрібно зупинити розбір.Розбір містить у собі виклики описаних вище функцій. Якщо для зчитаного нетермінала є складене правило, тоді при його розборі будуть викликані інші функції для розбору терміналів, що входять в нього. Дерево викликів, починаючи із самої«верхньої» функції еквівалентно дереву розбору.
2. Формальний опис вхідної мови програмування
2.1. Деталізованийописвхідноїмови в термінахрозширеноїнотації Бекуса-Наура.
<program>::=PROGRAM<name>VAR<var_blok>BEGIN<code_blok>END.
<var_blok> ::=<declarations> {;<declarations> ;} .
<declarations>::=LONGINT<declaration_i> {,<declaration_i>}
.<declaration_i> ::= <ident> | {<ident> << <const_i>} .
<ident> ::= <letter>{ <l _or_n>} .
<l_or_n> ::= <letter>|<number> .
<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|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_i> ::= {[-]<number>} .
<code_blok> ::= {<statement>} .
<statement> ::= <equation>|<cycle>|<input>|<output> .
<equation> ::= <ident> {ident <<<expression_i>|ident-> <expression_b>}; .
<expression_i>::=<term> {<term> + <term> | <term> - <term>}.
<term>::=<ident>|<const_i>|<factor>.
<factor>::={* <term> | DIV <term>| MOD <term> | <brackets>}.
<brackets>::=(<expression_i>).
<expression_b>::=<term_b> {<term_b>==<term_b> | term_b != <term_b> | <term_b> LT<term_b>|<term_b> GT <term_b>}.
<term_b>::=<ident>|<const_b>|<factor_b>.
<factor_b>::=<term_b> { |<term_b> | <and> |<not>|<brackets_b>}.
<and>::= &<term_b>
<not>::=!<factor_b>
<brackets_b>::=(<expression_b>).
<cycle> ::= FOR(<expression_i>;<expression_b>;|< expression_i>) BEGIN
<code_blok> END.
<input> ::= GET(<ident>); .
<output> ::= PUT(<expression_i>|<string>|<expression_b>); .
<string> ::= “{<l_or_n>}” .
2.2. Термінальні символи та ключові слова.
PROGRAM – початок тексту програми, наступним описується ім’я програми;
VAR - блок описузмінних;
BEGIN – початок тілапрограми (циклу);
END – кінецьтілапрограми (циклу);
PUT– оператор виводу (змінних і рядкових констант)
GET– оператор вводу змінних;
<< оператор присвоєння;
FOR– початок уиклу
BEGIN – початок тіла умовного циклу
+ – операція додавання
- – операція віднімання
* – операція множення
DIV – операція ділення
MOD – операція знаходження залишку від ділення;
== – операціяперевірки на рівність;
!= – перевірка на нерівність;
LT – перевірка чи менше;
GT – перевірка чи більше/рівно;
NOT – операція логічного заперечення;
AND – кон’юнкція;
OR – диз’юнкція;
LONGINT – 32ох розрядні знакові цілі;
/* – рядковий коментар
“ – початок/завершення рядкової константи при операції виводу;
,– розділювач між деклараціями змінних;
; – ознака кінця оператора;
(– відкриваюча дужка;
) – закриваюча дужка;
Як термінальні символи використовуються також усі арабські цифри (0–9), латинські букви (a-z, A-Z), символи табуляції, символ переходу на нову стрічку, пробіл.
3. Розробка транслятора вхідної мови програмування
3.1. Вибір технології програмування.
Необхідно вибрати ефективні методи розв’язку загальних задач, таких як розпізнавання лексем, синтаксичний розбір, семантичний аналіз та організація вводу / виводу, обчислення арифметичних виразів та організація вкладених операторів. Для реалізації лексичного аналізу в курсовій роботі використано метод перебору, тобто до чергової лексеми додається наступна буква, а тоді здійснюється пошук лексеми в таблицях ключових слів, та ідентифікаторів, якщо лексема не знайдена, тоді видається повідомлення про помилку. Під час аналізу поточних лексем здійснюється перевірка на наявність коментарів та рядкових констант при виводі. Першим проходом формується таблиця лексем, в яку коментарі не вносяться. Таблиця лексем містить лексема, саму лексему, клас лексеми та її код. Синтаксичний аналіз базується на перевірці послідовності класів лексем, наприклад, якщо після оператора присвоєння слідує синтаксична лексема, чи після математичного оператора слідує лексема з класу порівнянь, то буде сформовано повідомлення по помилку. Для розробки синтаксичного аналізатора використано метод рекурсивного спуску. На фазі семантичного аналізу здійснюється перевірка на відповідність типів. На цьому етапі перевіряється, чи не використовуються в одному виразі змінні одного типу, та чи не застосовано до них недопустимих операцій. Генератор коду починає свою роботу паралельно з синтаксичним аналізом, після розпізнання кожної конструкції генерується код. В залежності від коду лексеми в асемблерний файл вставляється конкретний набір команд. Для реалізації обчислень арифметичних виразів використовується переведення їх у постфіксну форму, після чого такий вираз обчислюється з використанням математичного співпроцесора. Для переведення виразу у постфіксну форму використовується структура даних стек. Стек реалізований на базі класу Stack платформи .NET. Push (заштовхування елементу у вершину стеку), Pop (вилучення елементу із вершини стеку). Ввід та вивід реалізовано за допомогою Win32API функцій WriteConsoleі readConsole. Цикл реалізовано за допомогою команд умовних і безумовного переходів.
3.2. Проектування таблиць транслятора.
Для реалізації лексичного аналізу створюємо таблицю, в яку поміщаємо всі лексеми (ArrayListlexems = newArrayList()), і таблицю (Hashtableidenty = newHashtable()) для ідентифікаторів, які будуть введені користувачем. Ім’япрограми в цютаблицю не заноситься. Дляреалізаціїтаблиці лексем описаний тнаступний класLexem:
Поле id призначене для зберігання номера лексеми;
Поле lexпризначене для зберігання самої лексеми;
Поле comment призначене для зберігання класу до якого належить лексема;
Поле typeKeywordпризначене для зберігання класу Ключових слів до якого належить лексема;
Поле type призначене для зберігання коду лексеми.
Сама таблиця лексем є масивом таких структур.
Лексеми мають такі класи:
Клас лексем блоку
клас операторів вводу виводу
клас операторів присвоєння
клас математичних операторів
клас операторів порівняння
клас логічних операторів
клас ідентифікаторів
клас операторів циклу
клас лексем оголошення
клас лексем опису і аргументів виводу
клас констант
Відомості про класи з таблиці лексем використовуються при синтаксичному аналізі. Інформація з поля atributeвикористовується при семантичномуаналізі.
Лексеми мають наступні коди:
Нерозпізнана лексема - -1
Ідентифікатори - 1
Числові константи - 2
Рядкові константи - 3
Коментарі - 4
== - 5
* - 6
- - 7
+ - 8
!= - 9
<< - 10
; - 11
, - 12
) - 13
( - 14
PROGRAM - 15
VAR - 16
BEGIN - 17
END - 18
LONGINT - 19
GET - 20
PUT - 21
NOT - 22
AND - 23
OR - 24
FOR -25
BEGIN - 26
DIV -27
MOD - 28
LT - 29
GT -30
Коди використовуються генератором коду для формування відповідних процедур мовою асемблер.
Для зберігання таблиці ідентифікаторів використовується Hashtableidenty = newHashtable()
Полем таблиці є клас Iden_info він містить наступні поля:
Поле idпризначене для зберігання ідентифікаторів;
Поле type призначене для зберігання типу змінної.
Поле Id_value призначене для зберігання значення змінної.
Для запам’ятовування виразу в постфікс ній формі використовуєтьсяArrayList.
3.3. Розробка лексичного аналізатора.
Лексичний аналіз – перша фаза трансляції, призначена для групування символів вхідного ланцюга в більш крупні конструкції, що називаються лексемами. З кожною лексемою зв’язано два поняття:
Класлексеми, щовизначаєзагальнуназву для категоріїелементів, щомаютьспільнівластивості (наприклад, ідентифікатор, ціле число, рядок символів і т. д.).
Значеннялексеми, щовизначаєпідрядоксимволіввхідноголанцюга, щовідповідаютьрозпізнаномукласулексеми. В залежностівідкласу, значеннялексемиможе бути перетворено у внутрішнєпредставленнявже на етапілексичногоаналізу. Так, наприклад, роблять з числами, перетворюючиїх в машиннедвійковепредставлення, щозабезпечуєбільшкомпактнезберігання і перевіркуправильностідіапазону на раннійстадіїаналізу.
3.3.1. Розробка граф-схеми алгоритму
Рис 1.Граф-схема роботилексичногоаналізатора
3.3.2Опис програми реалізації лексичного аналізатора
Програмапо рядках читає вхідний файл. Прочитаний рядок передає як параметр функції Parse класу Parser. В лексичному аналізаторі для розпізнання використовуються наступні функції:
Функція Parse() аналізує перший символ нової лексеми:
якщо перший символ A-Z, то запускається функція ParseKeyWords()
якщо перший символ 0-9 або -, то запускається функція ParseNum()
якщо перший символ =,!,&,|,;, , ,(,) відбувається збереження лексеми
якщо перший символ /, то запускається функція ParseComments()
якщо перший символ “,то запускається функція ParseString()
якщо перший символ не є жодним з вищезгаданих то запускається процедура ParseNoLex()
Функція ParseKeyWords() виділяє послідовність символі, які можуть містити ключові слова і перевіряє чи ця послідовність символів є ключовим словом і якщо це ключове слово зберігає його, як лексему
Функція ParseIdent()виділяє послідовність символі, які можуть містити ідентифікатори і зберігає ідентифікатор
Функція ParseNum()виділяє послідовність символі, які можуть містити числові константи і зберігає лексему
Функція ParseComments() перевіряє чи 2 символ *, то всі символи які знаходяться перед символами *} вважає коментарем
Функція ParseString() шукає символ завершення рядка і всі символи між початком і кінцем рядка вважає рядковою константою
Функція ParseNoLex() шукає розділювач і вважає що всі символи, які вона виділила є нерозпізнаною лексемою
3.4.Розробка синтаксичного аналізатора
Синтаксичний розбір (розпізнавання) є першим етапом синтаксичного аналізу. Саме при його виконанні здійснюється підтвердження того, що вхідний ланцюжок символів є програмою, а окремі підланцюжки складають синтаксично правильні програмні об'єкти. Вслід за розпізнаванням окремих підланцюжків здійснюється аналіз їх семантичної коректності на основі накопиченої інформації. Потім проводиться додавання нових об'єктів в об'єктну модель програми або в проміжне представлення.
Розбір призначений для доказу того, що аналізований вхідний ланцюжок, записаний на вхідній стрічці, належить або не належить безлічі ланцюжків породжуваних граматикою даної мови. Виконання синтаксичного розбору здійснюється розпізнавачами, тому даний процес також називається розпізнаванням вхідного ланцюжка. Мета доказу в тому, щоб відповісти на питання: чи належить аналізований ланцюжок безлічі правильних ланцюжків заданої мови. Відповідь «так» дається, якщо така приналежність встановлена. Інакше дається відповідь «ні». Отримання відповіді «ні» пов'язано з поняттям відмови. Єдина відмова на будь-якому рівні веде до загальної відмови.
Щоб одержати відповідь «так» щодо всього ланцюжка, треба його одержати для кожного правила, що забезпечує розбір окремого підланцюжка. Аналізатор вибирає перший символ з сукупності лексем аналізуючи його визначає, яку функцію треба запустити щоб виконати перевірку заданого підланцюжка. Цей метод називається методом рекурсивного спуску, аналіз проводиться від кореня до листків.
Основним завданням семантичного аналізатора є перевірка типів. Також семантичний аналізатор повинен знаходити вирази, що використовуються без присвоєння та видавати попередження.
Сама програма перевірки типів базується на інформації про синтаксичні конструкції мови, представлення типів і правилах присвоєння типів конструкціям мови.
3.4.1. Розробка дерева граматичного розбору
Коренем дерева є не термінальний символ <Program>. Безпосередньо його листками є термінали PROGRAM, VAR, BEGIN, END та нетермінали <Var_Blok>, <Code_block>. Листками не терміналу <Var_Blok> є не термінал <declarations>. Листками не терміналу <declarations> є не термінал <declaration_i>і термінал LONGINT. Листками не терміналу <declaration_i> є не термінали <ident> і <const_i> і термінал <<. Листками не терміналу <ident> є не термінали <letter> і <l _or_n>. Листками не терміналу <l_or_n> є не термінали <letter> і <number>.Листками не терміналу <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,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_i> є не термінал <number> і термінал -. Листком не терміналу <code_blok> є не термінал <statement>. Листками <statement> є нетермінали<equation>, <cycle>, <input>, <output>. Листками <equation> є не термінали <ident>, <expression_i> і <expression_b> і термінал ->.Листками не терміналу <expression_i> є не термінал <term> і термінали + і -. Листками не теміналу <term> є не термінали <ident>, <const_i>, <factor>. Лисками <factor> є не термінали <term> і <brackets> і термінали *, DIV, MOD. Листками <brackets> є не термінал <expression_i>і термінали (, ). Листками <expression_b> є не термінал<term_b> і термінали ==, !=, LT, GT. Листками <term_b> є не термінали <ident>, <const_b> і <factor_b>. Листками <factor_b> є не термінали <term_b>, <brackets_b>, <and>, <not>. Листками <and> є не термінал<term_b> і термінал &. Листками <not> є не термінал <factor_b> і термінал !. Листками <brackets_b> є не термінали <expression_b> і термінали ( і ). Листками не терміналу <cycle> є не термінали <expression_b>, <ident>, <code_blok> і не термінали (, ), FOR, BEGIN, END. Листками <input> є не термінал <ident> і термінал GET, ( і ). Листками <output> є не термінали <expression_i>, <string>, <expression_b>, PUT, (, ). Листками <string> є не термінал <l_or_n> і термінал “.
Дерево граматичного розбору розроблено згідно правил, даних у формі розширеної нотації Бекуса-Наура, та оформлено згідно правил ЄСКД.
3.4.2 Розробка граф-схеми алгоритму
Рис 2.Граф-схема роботи синтаксичного аналізатора
3.4.3 Опис програми реалізації синтаксичного аналізатора
На вхід синтаксичного аналізатора подається таблиця лексем, створена на етапі лексичного аналізу. Потім по черзі перебираємо лексеми та аналізуємо класи лексем, що слідують за ними. Якщо після чергової лексеми слідує лексема, що має некоректний клас (наприклад після лексеми класу вводу/ виводу слідує лексема класу математичних операторів), то формується повідомлення про помилку. Також здійснюється перевірка чи не йдуть підряд дві лексеми однакового класу (за винятком синтаксичних та операції множення на від’ємне число), якщо це справджується то виводиться повідомлення про помилку. При знаходженні оператора присвоєння, математичних та логічних операторів чи операторів порівняння здійснюється перевірка атрибутів усіх ідентифікаторів, що входять у даний вираз. Якщо у виразі використовуються дані різних типів, то формується повідомлення про помилку.
При кожному знаходженні помилки в таблицю помилок додається одне поле.
В синтаксичному аналізі використовуються функції для розбору всіх конструкції вхідної мови, вони рекурсивно викликають одна одну відповідно до заданих правил. Також додатково описані функції Infix_to_Postfix() і Infix_to_Postfix_b() і функція isDeclaredVariable() яка виконує перевіряє чи змінна оголошена, чи вона відповідно до контексту має правельний тип і чи має значення.
3.5.Розробка генератора коду
3.5.1 Розробка граф-схеми алгоритму
Так як генерація коду тісно пов’язана з синтаксичним аналізом, тобто код конструкції генерується відразу після розпізнавання.
Рис 3.Граф-схема роботи генератора коду
3.5.2 Опис програми реалізації генератора коду
Програма починає по черзі перебирати лексеми із таблиці лексем. У відповідності до коду знайденої лексеми у проміжне представлення програми буде вставлено відповідний еквівалентний асемблерний текст. Наприклад, при зустрічі ключового слова Program, в асемблерний файл вставляється текст з описом моделі та сегментів, а при зустрічі ключового слова Var, вставляється опис сегменту даних.
Реакція на лексеми розроблена так, що пустий код не буде включений в асемблерний файл. Для того щоб уникнути помилок, імена ідентифікаторів, дані у вхідній програмі користувачем, вносяться у асемблерний файл із змінами. Наприклад, невідомо, як буде працювати згенерований код, якщо у ньому будуть зустрічатись створені користувачем змінні end, loop.
В даному трансляторі генератор коду послідовно викликає окремі функції, які записують у вихідний файл частини коду. Для кожного ланцюжка вхідної мови існує окрема функція, яка враховуючи послідовність лексем створює відповідний вихідний код.
4. Опис інтерфейсу та інструкції користувачеві
Програма NotepadProgможна запустити з виконавчого файлу NotepadProg.exe, або вибрати пункт меню Пуск/Виконати і ввести шлях до файлу і назву програми. NotepadProg є програмою, яка працює на платформі .NETі є візуальною програмою, тому для її запуску повинна бути встановлена платформа netframeworkне нижче 2 версії.NotepadProg містить редактор тексту і транслятор. Редактор тексту дозволяє відкривати файли з розширенням *.prog.
/
Рис 4.Вікно редактора тексту
В редакторі присутні наступні функції:
Ведення і редагування тексту
Відкриття нового файл
Збереження файлу
Закриття файлу
Копіюваннятексту
Зміна шрифту програми
Зміна режимів розташування вікон редактора (каскадний, горизонтальний, вертикальний)
Після введення тексту програми код потрібно з транслювати. Під час першого запуску програми потрібно задати шлях до папки masm32 щоб в згенерований код транслятор коректо додав адресу бібліотек Win32. Щоб задати шлях потрібно виконати команду tools/Folders
Рис 5.Вікно введення шляху до папки masm32
Після цього можна запустити транслятор вхідної мови це можна зробити за допомогою пункту меню Build/Run (F5). Вікно транслятора складається з 5 вкладок:
Таблиця лексем
Таблиця Ідентифікаторів
Таблиця рядкових констант
Таблиця помилок
Файл Асемблерного коду
/
Рис 6.Вікно транслятора
5. Відлагодження та тестування програми
Відлагодження програми відбувається на основі спеціально створених тестів за допомогою автоматизованого відлагоджувача який присутній в середовищі MsVisualStudio 2010, в покроковому режимі перевіряється значення потрібних змінних і вмістиме потрібних структур даних. За допомогою breakpointsвідбувається запинка виконання програми в тих місцях де відбулася логічна помилка або в місцях визначених студентом.
5.1. Виявлення лексичних помилок.
До помилок виявлених на етапі лексичного аналізу відносить тільки одна помилка – виявлення нерозпізнаної лексеми. Якщо було виявлено нерозпізнану лексему – в таблицю лексем заноситься поле з коментарем «нерозпізнана лексема», і їй присвоюється код -1, і на етапі синтаксичного аналізу буде згенерована помилка пов’язана з цією лексемою.Приклад виявлення нерозпізнаної наведений на рис. 7:
/
Рис 7.Виявлення помилок на етапі лексичного аналізу
5.2. Виявлення синтаксичних помилок.
На етапі синтаксичного аналізу виявляється основна кількість помилок. Ці помилки пов’язані з невірними записами конструкцій вхідної мови. Всі помилки виявленні на етапі синтаксичного аналізу заносяться в таблицю помилок, Таблиця помилок містить лексему яка спричинила помилку, коментар і рядок в якому виникла помилка. Приклад таблиці помилок наведений на рис.8:
/Рис 8.Виявлення помилок на етапі синтаксичного аналізу
5.4. Загальна перевірка коректності роботи транслятора.
Загальна перевірка полягає в транслюванні завідомо коректної вхідної програми з використанням всіх можливостей мови в асемблерний код та перевірці на правильність виконання програми попередньо скомпільованої та злінкованої за допомогоюml.exe
Текст програми:
PROGRAM N1
VAR LONGINT A << 345, B<<5, I<<0, C<<0;
BOOLEAN F<<TRUE;
BEGIN
PUT("A = ");
GET(A);
PUT("B = ");
GET(B);
A << A * (B + A)DIV B;
PUT("A = ");
PUT(A);
PUT("C = ");
GET(C);
FOR (I<<0;I LT C;I<<I + 1) BEGIN
A << A + B;
PUT("A = ");
PUT(A);
END;
END
Результати роботи програми:
/
Висновки
Підчас виконання курсової роботи:
1. Складено формальний опис мови програмування Prog у формі розширеної нотації Бекуса-Наура, дано опис усіх символів та ключових слів.
2. Створено транслятор мови програмування Prog, а саме:
2.1.1. Розроблено лексичний аналізатор, здатний розпізнавати лексеми, що є описані в формальному описі мови програмування, та додані під час безпосереднього використання транслятора.
2.1.2. Розроблено синтаксичний аналізатор на основі рекурсивного спуску. Дерево виклику функцій згідно правил записаних в нотації у формі Бекуса-Наура.
2.1.3. Розроблено генератор коду, який починає свою роботу під час коректного виявлення кожної конструкції і генерує код який відповідає кожній конструкції вхідної мови. Проміжним кодом генератора є програма на мові Assembler(i586). Вихідним кодом є машинний код, що міститься у виконуваному файлі
3. Проведене тестування транслятора за допомогою тестових програм за наступними пунктами: Виявлення лексичних помилок. Виявлення синтаксичних помилок. Загальна перевірка роботи компілятора. Тестування не виявило помилок в роботі компілятора, а всі помилки в тестових програмах мовою prog були виявлені і дано попередження про їх наявність. В результаті виконання даної курсової роботи було успішно засвоєно методи розробки та реалізації компонент системного програмного забезпечення.
Список використаної літератури
Ахо и др. Компиляторы: принципы, технологии и инструменты.: Пер с англ. – М.: Издательський дом «Вильямс». 2003. – 768 с.: ил. Парал. тит. англ.
Шильдт Г. С#. – Санкт-Петербург: BXV, 2002. – 688 с.
Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы построения трансляторов. – СПб.: КОРОНА принт, 2004. – 256 с.
Б. Керниган, Д. Ритчи «Язык программирования Си». – Москва «Финансы и статистика», 1992. – 271 с.
Л. Дао. Программирование микропроцессора 8088. Пер.с англ.М. «Мир», 1988.
Ваймгартен Ф. Трансляция языков программирования. – М.: Мир, 1977.
Додатки:
Додаток А
Лістинг програми:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;
namespace Notepad
{
public class Const_Strings
{
private string str_value = "";
private int num_lex;
public string Value
{
get { return str_value; }
set { str_value = value; }
}
public int Number
{
get { return num_lex; }
set { num_lex = value; }
}
}
public class Iden_info
{
private string id="";
private string type = "";
private string Id_value = "";
public string Id
{
get { return id; }
set { id = value; }
}
public string Type
{
get { return type; }
set { type = value; }
}
public string Value
{
get { return Id_value; }
set { Id_value = value; }
}
}
public class Lexem
{
private int id=0;
private string lex = "";
private string comments = "";
private int type = 0;
private int typeKeyword = -1;
public int Id
{
get { return id; }
set { id = value; }
}
public int Type
{
get { return type; }
set { type = value; }
}
public int TypeKeyword
{
get { return typeKeyword; }
set { typeKeyword = value; }
}
public string Lex
{
get { return lex; }
set { lex = value; }
}
public string Comments
{
get { return comments; }
set { comments = value; }
}
}
static class Parser
{
public static bool isStart = false;
public static int num = 0;
public static Hashtable identy = new Hashtable();
public static ArrayList lexems = new ArrayList();
public static Hashtable const_str = new Hashtable();
public static Hashtable const_int = new Hashtable();
public static ArrayList lines = new ArrayList();
public static Iden_info id_info;
public static string Comments;
static Const_Strings strs;
static Lexem lexem;
public static void Parse(string line)
{
line = line + '\n';
for (int i = 0; i < line.Length;i++)
{
if (Form1.isCom)
i = ParseComments(line, i) - 1;
if (line.Length == 1)
continue;
if (line[i] >= 'A' && line[i] <= 'Z')
{
i = ParseKeyWords(line, i) -