МІНІСТЕРСТВО ОСВІТИ І НАУКИ, МОЛОДІ ТА СПОРТУ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
Кафедра ЕОМ
/
КУРСОВА РОБОТА
з предмету “Системне програмування”
на тему “Розробка системних програмних модулів та компонент систем програмування.”
Варіант 123
\
Анотація
Курсова робота з дисципліни "Системне програмування" вміщає в собі весь матеріал, який ми вивчали протягом даного курсу. Вона узагальнює матеріал і закріпляє навички які ми набули при вивченні матеріалу.
В ній ми маємо продемонструвати розробку транслятора з вхідної мови програмування, яка нам була задана, на мову асемблер, компілювати код і створити виконавчий файл. Транслятор повинен виконувати: лексичний аналіз, синтаксичний аналіз, семантичний аналіз, виводити список помилок при наявності та попереджень.
В цій курсовій роботі буде використовуватися лексичний аналізатор на базі скінченного автомата та на основі магазинного автомата.
Зміст
Анотація 2
Завдання на курсову роботу 4
1. Огляд методів та способів проектування трансляторів 6
2. Формальний опис вхідної мови програмування 8
2.1. Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура 8
2.2. Термінальні символи та ключові слова. 9
3. Розробка транслятора вхідної мови програмування 11
3.1. Вибір технології програмування 11
3.2. Проектування таблиць транслятора. 12
3.3. Розробка лексичного аналізатора. 15
3.3.1. Розробка граф-схеми алгоритму 15
3.3.2 Опис програми реалізації лексичного аналізатора 17
3.4.Розробка синтаксичного аналізатора 18
3.5.Розробка генератора коду 20
3.5.1 Розробка граф-схеми алгоритму 20
3.5.2 Опис програми реалізації генератора коду 23
4. Опис інтерфейсу та інструкції користувачеві 24
5. Відлагодження та тестування програми 26
5.1. Виявлення лексичних помилок 26
5.2. Виявлення синтаксичних помилок 27
5.3. Виявлення семантичних помилок 27
5.4. Загальна перевірка коректності роботи транслятора. 27
Висновки 29
Додатки: 31
Додаток А 31
Завдання на курсову роботу
Тема: Розробка транслятора з вхідної мови програмування.
- початок програми Program
- початок блоку даних Var
- типи даних: Integer32, Boolean, String;
- оператор вводу: Read;
- оператор виводу: Write;
- блок тіла програми: Begin, End
- оператор: For-To-Do (Паскаль);
- регістр ключових слів: Up-Low перший символ Up;
- регістр ідентифікаторів: Up-Low8 перший символ _;
- операції арифметичні: +, -, Mul, Div,Mod;
- операції порівняння: ==; !=; Le; Ge
- операції логічні: !; And; Or
- коментар: !!...
- ідентифікатори змінних, числові константи, рядкові константи;
- оператор присвоєння: <-
Для отримання виконавчого файлу з вихідного асемблерного коду потрібно використовувати masm32.exe.
Вступ
Компілятор (англ. Compiler від англ. to compile збирати в ціле) - комп'ютерна програма, що перетворює (компілює) програмний код, написаний певною мовою програмування, на семантично еквівалентний код в іншій мові програмування, який, як правило, необхідний для виконання програми машиною.
Транслятор – це той самий компілятор, з тею різницею, що генерує він не об’єктний код, а код на іншій мові програмування.
Процес компіляції як правило складається з декількох етапів: лексичного, синтаксичного та семантичного (типозалежного) аналізів, генерації проміжного коду, оптимізації та генерації результуючого машинного коду. Крім цього, програма як правило залежить від сервісів, наданих операційною системою і сторонніми бібліотеками (наприклад, файловий ввід-вивід або графічний інтерфейс), і машинний код програми необхідно пов'язати з цими сервісами. Для зв'язування зі статичними бібліотеками виконується редактор зв'язків або компонувальник, а з операційною системою і динамічними бібліотеками зв'язування виконується на початку виконання програми завантажувача.
Основні задачі, які виконуються різними компіляторами та трансляторами, по суті, одні і ті ж. Розуміючи ці задачі, існує можливість створювати транслятори для різних початкових мов і цільових машин з використанням одних і тих же базових технологій.
В даній курсовій роботі створюватимется транслятор мови програмування заданої варіантом, який включає:
- лексичний аналізатор, здатний розпізнавати лексеми, що є описані в формальному описі мови програмування.
- синтаксичний аналізатор на основі методу зсув-згортка.
- генератор коду, що генерує код який відповідає кожній конструкції вхідної мови.
Також повинне бути забеспечене виявлення лексичних та синтаксичних помилок, виконана загальна перевірка роботи компілятора.
1. Огляд методів та способів проектування трансляторів
Створення компіляторів відбувається в певних конкретних умовах: для різних мов, для різних цільових платформ, з різними вимогами для створення компіляторів. Є такі методи створення компіляторів:
1. Прямий метод - цільовою мовою і мовою реалізації є асемблер.
2. Метод розкрути - саме цей метод і використовується у даній курсовій роботі, тобто вибирається інструмент (в даній курсовій це мова асемблер), для якого вже існує компілятор.
3.Використання крос-трансляторів.
4.З використанням віртуальних машин – дає спосіб отримати переносимо програму.
5. Компіляція на ходу.
В даній курсовій роботі згідно із завданням для непарних варіантів необхідно реалізувати висхідний метод граматичного розбору.
При такій стратегії дерево синтаксичного аналізу будується, рухаючись від листя (вхідної програми, яка розглядається як рядок символів) до кореня дерева (аксіоми граматики). Аналізатор (розпізнавач) шукає частину рядка, яку можна звести до нетермінального символу. Таку частину рядка називають фразою. У більшості висхідних розпізнавачів відшукується найлівіша фраза, що безпосередньо зводиться до нетермінального символу (така фраза називається основою). Основа заміняється нетермінальним символом. У отриманому рядку знову відшукується основа, заміняється нетермінальним символом і т.д.
У загальному випадку процедуру побудови висхiдного розпiзнавача за заданою граматикою можна описати в такий спосiб:
Визначити для даної граматики функцiї ВПЕРВ i ВПIСЛЯ.
Побудувати детермiновану таблицю переходiв, що має по одному стовпцю для кожного граматичного символу i по одному рядку для кожного граматичного входження i маркера дна.
Якщо таблиця, побудована на кроцi 2, виходить недетермiнованою (має бiльше одного стану), то потрiбно перетворити цю таблицю в детермiновану, розглядаючи її як недетермiновану таблицю переходiв кiнцевого автомата з початковим станом h0.
Стани, отриманi на кроцi 3 (крiм стану, що вiдповiдає порожнiй множинi), варто використовувати як магазиннi символи. Отримана таблиця переходiв може мiстити переходи в порожню множину. Такi елементи варто розумiти як забороненi i розглядати переходи в них як помилки.
Керуючу таблицю заповнюють рядок за рядком вiдповiдно до множини граматичних входжень, що позначають рядки.
Фази лексичного (ЛА) та синтаксичного (СА) аналізів розкладають початкову програму на частини. Генерація коду проміжною мовою (ГПК), оптимізація (ОК) та генерація коду (ГК) асемблера синтезують програму на вихідній мові. Керування таблицями (КТ) та обробка помилками (ОП) використовуються на всіх фазах трансляції.
Лексичний аналіз об`єднує літери в лексеми - службові слова, ідентифікатори, знаки операцій та пунктуації. Лексеми можна кодувати цілими числами, наприклад, do-одиницею, "+" - двійкою, ідентифікатор - трійкою, константу - четвіркою тощо. До коду лексем ідентифікаторів і констант додається ще одна величина - вид чи значення лексеми.
Синтаксичний аналіз групує лексеми в синтаксичні структури, які можуть бути складовими інших синтаксичних структур; наприклад, А+В може входити в оператор чи вираз. Як рекурсивні структури даних, вони зображуються (явно чи неявно) у формі дерева з лексемами в вузлах і з позначенням синтаксичних конструкцій у внутрішніх вузлах. Крони піддерев відтворюють частини програми відповідної синтаксичної конструкції.
2. Формальний опис вхідної мови програмування
2.1. Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура
Розширена форма Бекуса-Наура (скор. РБНФ) - формальна система визначення синтаксису, в якій одні синтаксичні категорії послідовно визначаються через інші. Використовується для опису контекстно-вільних формальних граматик. Запропоновано Никлаусом Віртом. Є розширеною переробкою форм Бекуса-Наура, відрізняється від БНФ більш «вмістимими» конструкціями, що дозволяють при тій же виразності дозволяє спростити і скоротити в обсязі опис.
<program> ::= Program <nane> Begin Var <VAR_blok> <code_blok> End.
<VAR_blok> ::=<declarations> {;<declarations>};.
<declarations>::=<type_i><declaration_i> {,<declaration_i>} | <type_b> <declaration_b> {,<declaration_b>}.
<type_i> ::=Integer32.
<type_b> ::=Boolean.
<declaration_i> ::= <ident> [ -> <const_i>] .
<declaration_b> ::= <ident> [ -> <const_b>] .
<ident> ::= <letter>[<l _or_n>] .
<name>::= <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>{number} .
<const_b> ::=True|False
<code_blok> ::= <statement> {<statement>}.
<statement> ::= <equation>|<cycle>|<read>|<write> .
<equation> ::= <ident> -> <expression_i>|<expression_b>; .
<expression_i>::= <term> {add <term> | sub <term>}.
<term>::=<ident>|<const_i>|<factor>.
<factor>::= {Mul <term> | Div <term>| Mod <term> | <brackets>}.
<brackets>::=(<expression_i>).
<expression_b>::= <term_b> {== <term_b> | <> <term_b> | !< <term_b>| !> <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 <equation> To <const_i> Do [START] <code_blok> [END].
<read> ::= Read(<ident>); .
<write> ::= Write(<expression_і>|<string>); .
<string> ::= “{<l_or_n>}” .
2.2. Термінальні символи та ключові слова.
Якщо ми маємо якусь мову задану граматикою, то термінальними символами є всі символи, які з'являються в конструкціях мови. Термінальний означає кінцевий.
Program – початок програми, визначає назву програми
Var – блок даних
Begin – Початок блоку коду;
End – кінець тіла програми (циклу);
Write– оператор виводу (змінних і рядкових констант)
Read – оператор вводу змінних;
<- - оператор присвоєння;
For – To – Do – оператор циклу
+ – операція додавання
- – операція віднімання
Mul – операція множення
Div – операція ділення
Mod – операція знаходження залишку від ділення;
== – операція перевірки на рівність;
!= – перевірка на нерівність;
Le – операція порівняння «менше або рівно»;
Ge – операція порівняння «більше або рівно»;
! – операція логічного заперечення;
And – кон’юнкція;
Or – диз’юнкція;
Integer32 – 32ох розрядні знакові цілі;
Boolean – однобайтні логічні змінні;
!!... – коментар
“ – початок/завершення рядкової константи при операції виводу;
, – розділювач між деклараціями змінних;
; – ознака кінця оператора;
(– відкриваюча дужка;
) – закриваюча дужка;
Як термінальні символи використовуються також усі арабські цифри (0–9), латинські букви (a-z, A-Z), символи табуляції, символ переходу на нову стрічку, пробіл.
3. Розробка транслятора вхідної мови програмування
3.1. Вибір технології програмування
Було обрано технологію об'єктно-орієнтованого програмування. Об'єктно-орієнтоване програмування (ООП) — одна з парадигм програмування, яка розглядає програму як множину «об'єктів», що взаємодіють між собою. В ній використано декілька технологій від попередніх парадигм, зокрема успадкування, модульність, поліморфізм та інкапсуляцію.
На відміну від традиційних поглядів, коли програму розглядали як набір підпрограм, або як перелік інструкцій комп'ютеру, ООП програми можна вважати сукупністю об'єктів. Відповідно до парадигми об'єктно-орієнтованого програмування, кожний об'єкт здатний отримувати повідомлення, обробляти дані, та надсилати повідомлення іншим об'єктам. Кожен об'єкт — своєрідний незалежний автомат з окремим призначенням та відповідальністю.
Клас – це тип, що описує будову об'єктів. Поняття "клас" має на увазі деяка поведінка і спосіб представлення. Поняття "об'єкт" має на увазі щось, що має певну поведінку і спосіб представлення. Говорять, що об'єкт – це екземпляр класу. Клас можна порівняти з кресленням, згідн о з яким створюються об'єкти. Зазвичай класи розробляють так, щоб їх об'єкти відповідали об'єктам предметної області.
Структура даних "клас" є об'єктним типом даних. При цьому елементи такої структури (члени класу) можуть самі бути не лише даними, але і методами (тобто процедурами або функціями). Таке об'єднання називається інкапсуляцією.
Об'єктно-орієнтований підхід полягає в наступному наборі основних принципів:
Все є об'єктами.
Всі дії та розрахунки виконуються шляхом взаємодії (обміну даними) між об'єктами, при якій один об'єкт потребує, щоб інший об'єкт виконав деяку дію. Об'єкти взаємодіють, надсилаючи і отримуючи повідомлення. Повідомлення — це запит на виконання дії, доповнений набором аргументів, які можуть знадобитися при виконанні дії.
Кожен об'єкт є представником (екземпляром, примірником) класу, який виражає загальні властивості об'єктів.
У класі задається поведінка (функціональність) об'єкта. Таким чином усі об'єкти, які є екземплярами одного класу, можуть виконувати одні й ті ж самі дії.
. NET Framework - програмна платформа компанії Microsoft , призначена для створення звичайних програм та веб-додатків.
Однією з основних ідей Microsoft .NET є сумісність програмних частин, написаних на різних мовах. Наприклад, служба, написана на C + + для Microsoft. NET, може звернутися до методу класу з бібліотеки, написаної на Delphi ; на C # можна написати клас, успадкованих від класу, написаного на Visual Basic. NET , а виключення , створене методом, написаним на C# , може бути перехоплено і оброблено в Delphi. Кожна бібліотека (збірка) в. NET має свідчення про свою версію, що дозволяє усунути можливі конфлікти між різними версіями збірок.
. NET є патентованою технологією корпорації Microsoft.
3.2. Проектування таблиць транслятора.
Для того,щоб реалізувати лексичний аналіз створюємо таблицю, в якій розмістимо всі лексеми (ArrayList lexems = new ArrayList()), і таблицю (Hashtable ID = new Hashtable()) для ідентифікаторів, які будуть введені користувачем. Для реалізації таблиці лексем описаний наступний клас Token:
id
Lex
comment
type
зберігання номера лексеми
зберігання лексеми
зберігання класу лексеми
зберігання коду лексеми
public class Token
{
private int id=0;
private int type;
private string lex = "";
private string comment = "";
public int ID
{
get { return id; }
set { id = value; }
}
public int Type
{
get { return type; }
set { type = value; }
}
public string Lex
{
get { return lex; }
set { lex = value; }
}
public string Comment
{
get { return comment; }
set { comment = value; }
}
}
Атрибути лексем з використовуються при синтаксичному аналізі. Лексеми мають наступні коди:
-1) - Нерозпізнана лексема
0) - Program
1) - Var
2) – Integer32
3) - Boolean
4) - <ident>
5) - <num>
6) - <-
7) - True
8) - False
9) - ,
10) - ;
11) - Begin
12) - Read
13) - Write
14) - (
15) - )
16) - +
17) - -
18) - Mul
19) - Div
20) - Mod
21) – ==
22) - !=
23) - Le
24) - Ge
25) - !
26) - And
27) - Or
28) - <string>
29) – For
30) – End
31) – To
32) – Do
Атрибути використовуються генератором коду для формування відповідних процедур мовою асемблер.
Для зберігання таблиці ідентифікаторів використовується Hashtable ID = new Hashtable()
Полем таблиці є клас ID_info, до якого входять такі поля:
Id
Var_value
type
зберігання ідентифікаторів
зберігання типу змінної
зберігання значення змінної
public class ID_info
{
private string id="";
private string type = "";
private string Var_value = "";
public string ID
{
get { return id; }
set { id = value; }
}
public string Type
{
get { return type; }
set { type = value; }
}
public string Var_Value
{
get { return Var_value; }
set { Var_value = value; }
}
}
3.3. Розробка лексичного аналізатора.
Лексичний аналіз – це перша фаза трансляції, яка застосовується для групування символів вхідного ланцюга в більші конструкції, що називаються лексемами. З кожною лексемою зв’язано два поняття:
- Клас лексеми, що визначає загальну назву для категорії елементів, що мають спільні властивості (наприклад, ідентифікатор, ціле число, рядок символів і т. д.).
- Значення лексеми, що визначає підрядок символів вхідного ланцюга, що відповідають розпізнаному класу лексеми. В залежності від класу, значення лексеми може бути перетворено у внутрішнє представлення вже на етапі лексичного аналізу. Так, наприклад, роблять з числами, перетворюючи їх в машинне двійкове представлення, що забезпечує більш компактне зберігання і перевірку правильності діапазону на ранній стадії аналізу.
3.3.1. Розробка граф-схеми алгоритму
Лексичний аналізатор був розроблений на основі скінченного автомата.
Скінченний автомат, є особливим видом автомату — абстракції, що використовується для описання шляху зміни стану об'єкта в залежності від досягнутого стану та інформації отриманої ззовні. Його особливістю є скінченність множини станів автомату. Розбір виконується взалежності від кількості символів з яких складається лексема. Згідно даного алгоритму лексеми можуть бути одно символьні, двосимвольні та багатосимвольні. Для багатосимвольних лексем розроблено функцію, яка виділяє лексеми.
Рис 1. Схема алгоритму
Лексичний аналізатор починає свою роботу з блоку 1 (Рис 1). Далі відривається вхідний файл у блоці 2 (Рис 1). Наступні блоки оформлені в виді циклу. Виконується перевірка на кінець файлу у блоці 3 (Рис 1). Якщо файл закінчився або виникла помилка, то лексичний аналізатор закінчує свою роботу у блоці 21 (Рис 1).
Блок 4 (Рис 1) виділяє перший символ нової лексеми. У блоках 5,7,9,11 (Рис 1) перевіряється відповідність лексеми до типу.
У блоках 6,8,10 та 12 (Рис 1) відбувається обробка лексеми та перехід до перевірки наявності наступної.
У блоці 19 (Рис 1) виявляються нероспізнані лексеми які зберігаються у таблицю лексем у блоці 20 (Рис 1) для формування повідомлення про помилку.
3.3.2 Опис програми реалізації лексичного аналізатора
Програма по одному символу читає із вхідного тексту , котрий дописується до поточної лексеми, якщо зустрічається пробіл чи символ переходу на новий рядок, то вони пропускаються. Після цього відбувається перевірка на наявність лексеми в таблиці ключових слів та таблиці ідентифікаторів. Якщо лексема не виявлена, то формується повідомлення про помилку. Під час цього встановлюються прапорці при знаходженні коментарів чи рядкових констант для виводу, тоді перевірка не відбувається, оскільки в такому випадку лексеми можуть бути якими-завгодно.
Прочитаний рядок передає як параметр функції Lexical_Analyzer. В лексичному аналізаторі для розпізнання використовуються наступні функції:
Lexical_Analyzer() тут відбувається аналіз першого символу нової лексеми:
A-Z => запуск ParseKeys()
_ => запуск ParseID()
0-9 або - => запуск ParseConst()
==,!=,!,;, , ,(,) => збереження лексеми
!! => запуск ParseCom ()
“ => запускається функція ParseStr()
не є жодним з вищезгаданих => запуск RozbirNoTok()
ParseID()-розбираються символи, які можуть містити ідентифікатори і потім відбуваються його збереження.
ParseKeys()- розбираються символи, які можуть міститись в ключових словах і здійснюється перевірка чи ці символи є ключовим словом і якщо це так то зберігає його, як лексему
ParseCom() -перевіряє чи 2 символ !, якщо це так то цей рядок є коментарем.
ParseConst()- розбираються символи, які можуть містити числові константи і зберігає лексему
ParseNoLex()- пошук розділювача, рахується що всі символи, які були виділені є нерозпізнаною лексемою
ParseStr() - відбувається пошук символа завершення рядка, всі символи,що містяться між початком і кінцем вважається рядковою константою.
3.4.Розробка синтаксичного аналізатора
Першим етапом синтаксичного аналізу є синтаксичний розбір. На етапі його виконання підтверджується то, що вхідний ланцюжок символів є програмою, а окремі підланцюжки складають синтаксично правильні програмні об'єкти. Після чого здійснюється аналіз їх семантичної коректності.
Розбір призначений для перевірки того, чи ланцюжок відповідаю якомусь правилу з сукупності правил визначеної граматикою. Синтаксичний розбір виконується розпізнавачами. Якщо на будь – якому рівні ланцюжок не відповідає ніякому правилу,то ми дістанемо загальну відмову.
Аналізатор вибирає лексему з сукупності лексем аналізуючи її визначає чи вона може стояти в цьому місці, якщо так, то заштовхує її в стек. Після чого знов вибирає лексему і перевіряє чи вона може стояти в цьому місці, якщо так то її також заштовхує в стек. Ця процедура виконується доти, доки ми не дійдемо до лексеми , яка завершує певну конструкцію. Тоді ця конструкція виштовхується зі стеку, згортається і в згорненому вигляді назад заштовхується в стек. Цей метод називається методом синтаксичного аналізу на базі магазинного автомата, аналіз проводиться від листків до кореня.
Основним завданням семантичного аналізатора є перевірка типів. Сама програма перевірки типів базується на інформації про синтаксичні конструкції мови, представлення типів і правилах присвоєння типів конструкціям мови.
3.4.1 Розробка дерева граматичного розбору
Порядок застосування правил граматики для розбору вхідних рядки буде називати деревом розбору. На рис. 2 представлено дерево граматичного розбору для вхідної мови.
Дерево граматичного розбору розроблено згідно правил, даних у формі розширеної нотації Бекуса-Наура, та оформлено згідно правил ЄСКД.
Рис 2. Дерево граматичного розбору
3.5.Розробка генератора коду
3.5.1 Розробка граф-схеми алгоритму
Рис 3. Граф-схема роботи синтаксичного аналізатора
Генерація коду є тісно пов’язаним з синтаксичним аналізом, одразу після розпізнавання генерується код. Синтаксичний аналізатор починає роботу з блоку 1 (Рис 3). Далі йде перевірка чи є наступний символ. Якщо немає, або виникає помилка, то синтаксичний аналізатор завершує свою роботу у блоці 36 (Рис 3) або якщо ще залишились символи лексема позначається як нерозпізнана у блоці 20 (Рис 3). Якщо наступна лексема наявна, то вона вибирається у блоках 31, 29, 27, 25, 23, 21, 18, 16, 14, 12, 10, 8, 6, 4 (Рис 3) а у наступному з цих блоків відбувається згортка (Рис 3). Якщо програма правильно визначає і згортає всі лексеми, то робота завешується у блоці 34 (Рис 3).
3.5.2 Опис програми реалізації генератора коду
Програма перебирає по черзі лексеми із таблиці лексем. В залежності від коду знайденої лексеми в проміжному представленні програми буде вставлено відповідний еквівалентний асемблерний код. Для прикладу, коли зустрінеться ключове слово Var, вставиться опис сегменту даних,а при зустрічі ключового слова Read, то згенерується виклик функції Read.
Програма розроблена таким чином, що в асемблер пустий код генеруватися не буде. Для виключення можливості помилок імена ідентифікаторів будуть генеруватися в асемблерний код зі змінами.
В розробленому трансляторі генератор коду послідовно викликає функції,які записують у вихідний файл частини коду. Створюється відповідний вихідний код взалежності від лексем.
4. Опис інтерфейсу та інструкції користувачеві
Програма З123 можна запустити з виконавчого файлу З123.exe. З123 є програмою, яка працює на платформі .NET і є візуальною програмою, тому для її запуску повинна бути встановлена платформа net framework не нижче 2 версії. З123 містить редактор тексту і транслятор. Редактор тексту дозволяє відкривати файли з розширенням *.v123.
/
Рис 4.Вікно редактора тексту
В редакторі (рис. 4) присутні наступні функції:
Ведення і редагування тексту
Відкриття нового файл
Збереження файлу
Закриття файлу
Копіювання тексту
/
Рис 5.Вікно транслятора
Запустити транслятор вхідної мови можна за допомогою пункту меню Build/Run (F5). Вікно транслятора складається з 5 вкладок:
Таблиця лексем
Таблиця Ідентифікаторів
Таблиця рядкових констант
Таблиця помилок
Файл Асемблерного коду
/
Рис 6.Інтерфейс програми masm32
Щоб отримати виконавчий файл потрібно згенерований код скомпілювати за допомогою masm32.exe. Виконати згенерований код можна за допомогою опції Run Program(рис. 6).
5. Відлагодження та тестування програми
5.1. Виявлення лексичних помилок
До помилок виявлених на етапі лексичного аналізу відносить тільки одна помилка – виявлення нерозпізнаної лексеми. Якщо було виявлено нерозпізнану лексему – в таблицю лексем заноситься поле з коментарем «нерозпізнана лексема», і їй присвоюється код -1, і на етапі синтаксичного аналізу буде згенерована помилка:
/
Рис 7.Приклад лексичної помилки
5.2. Виявлення синтаксичних помилок
На етапі синтаксичного аналізу виявляється основна кількість помилок. Ці помилки пов’язані з невірними записами конструкцій вхідної мови. Всі помилки виявленні на етапі синтаксичного аналізу заносяться в таблицю помилок, Таблиця помилок містить лексему яка спричинила помилку, коментар і рядок в якому виникла помилка.
/
Рис 8.Приклад синтаксичної помилки
5.3. Виявлення семантичних помилок
Суттю виявлення семантичних помилок є перевірка числових констант на відповідність типу Integer32, тобто знаковому цілому числу з відповідним діапазоном значень і перевірку на коректність використання змінних Integer32 і Boolean у цілочисельних і логічних виразах.
/
Рис 9.Приклад семантичної помилки
5.4. Загальна перевірка коректності роботи транслятора.
Загальна перевірка полягає в транслюванні завідомо коректної вхідної програми з використанням всіх можливостей мови в асемблерний код та перевірці на правильність виконання програми попередньо скомпільованої та злінкованої за допомогою masm32.exe
Текст програми:
Program
Var
Integer32 _A,_B,_D<-0,_C<-1000,_G<-(-3);
Boolean _F;
Begin
Read(_B);
Read(_A);
For Write(_B); _B<-1 To 4 Do Begin
Write(_A);
Write(_B);
_D<-_A + _B; !!Додавання чисел в циклі
_A<-_D;
Write(_D);
End;
Write("hello");
Read(_D);
End
Результати роботи програми:
/
Рис 10.Приклад виконання програми
Висновки
Під час виконання курсової роботи:
Складено формальний опис мови програмування у формі розширеної нотації Бекуса-Наура, дано опис усіх символів та ключових слів.
Створено транслятор мови програмування з використанням методу розкрутки, розробка включає такі пункти:
Розроблено лексичний аналізатор, здатний розпізнавати лексеми, що є описані в формальному описі мови програмування, та додані під час безпосереднього використання транслятора. Лексичний аналізатор побудований на базі скінченного автомата та на основі магазинного автомата.
Розроблено синтаксичний аналізатор на основі методу зсув-згортка.
Розроблено генератор коду, який починає свою роботу під час коректного виявлення кожної конструкції і генерує код який відповідає кожній конструкції вхідної мови. Проміжним кодом генератора є програма на мові Assembler(i586). Вихідним кодом є машинний код, що міститься у виконуваному файлі.
Проведене тестування транслятора за допомогою тестових програм за наступними пунктами: Виявлення лексичних помилок. Виявлення синтаксичних помилок. Загальна перевірка роботи компілятора. Тестування не виявило помилок в роботі компілятора, а всі помилки в тестових програмах мовою З123 були виявлені і дано попередження про їх наявність. В результаті виконання даної курсової роботи було успішно засвоєно методи розробки та реалізації компонент системного програмного забезпечення. Список використаної літератури
Ахо и др. Компиляторы: принципы, технологии и инструменты.: Пер с англ. – М.: Издательський дом «Вильямс». 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 int type = -1;
private string lex = "";
private string comments = "";
public int Id
{
get { return id; }
set { id = value; }
}
public int Type
{
get { return type; }
set { type = value; }
}
public string Lex
{
get { return lex; }
set { lex = value; }
}
public string Comments
{
get { return comments; }
set { comments = value; }
}
}
static class Parser
{
public static int num = 0;
public static bool isBegin = false;
public static string Comments;
public static Hashtable identy = new Hashtable();
public static Hashtable labels = new Hashtable();
public static Hashtable const_str = new Hashtable();
public static Hashtable const_int = new Hashtable();
public static ArrayList lexems