DevioLabавтоматичне керування капіталом
ПРАЦЮЄ 24/7
КРИПТОВАЛЮТИ · АКЦІЇ · 10 БІРЖ

Портфель, який керується автоматично

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

10підключених біржCrypto + Stocksв одному портфелі24/7автоматичний контроль

Розробка системних програмних модулів та компонент систем програмування

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

ВУЗ:
Національний університет Львівська політехніка
Інститут:
ІКТА
Факультет:
Комп’ютерні науки
Кафедра:
Кафедра ЕОМ

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

Рік:
2026
Тип роботи:
Курсова робота
Предмет:
Системне програмування
Група:
КН-31
Коротко про документ

Про що ця робота

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

У роботі розглядаються

  • Системне програмування
  • Транслятори
  • Лексичний аналіз
  • Синтаксичний аналіз
  • Генерація коду
  • Мова асемблера
  • Об'єктно-орієнтоване програмування

Зміст і розділи

  1. Завдання на курсову роботу
  2. Вступ
  3. Огляд методів та способів проектування трансляторів
  4. Формальний опис вхідної мови програмування
  5. Розробка транслятора вхідної мови програмування
  6. Опис інтерфейсу та інструкції користувачеві
  7. Відлагодження та тестування програми
  8. Висновки
  9. Список літератури
  10. Додатки
Для кого:Студенти технічних спеціальностей, викладачі та розробники системного програмного забезпечення
Викладачі:Не вказано

Ключові поняття

нотація Бекуса-Наурастекієрархія успадкуваннялексема

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

Міністерство освіти і науки України. Національний університет “Львівська політехніка” ІКТА Кафедра ЕОМ Пояснювальна записка до курсової роботи з предмету:“Системне програмування” на тему: “Розробка системних програмних модулів та компонент систем програмування” Індивідуальне завдання “Розробка транслятора з вхідної мови програмування” Варіант №23 Анотація В курсовій роботі розроблено транслятор з вхідної мови програмування,відповідно до варіанту,в асемблерний файл,після чого реалізована його компіляція і створення виконавчого файлу. Дана програма здійснює перевірку вхідного файлу на помилки (синтаксичні, семантичні, лексичні). Було реалізовано висхідний тип, методом зсув - згортка. А також транслятор був протестований на виявлення помилок і коректність роботи. Зміст Завдання на курсову роботу………………………………………………………….4 Вступ……………………………………………………………………………………5 Огляд методів та способів проектування трансляторів…………………………….6 Формальний опис вхідної мови програмування…………………………………….8 Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура……………………………………………………………………………….8 Опис термінальних символів та ключових слів……………………………………..9 Розробка транслятора вхідної мови програмування………………………………..11 Вибір технології програмування………………………………………………………11 Проектування таблиць транслятора та вибір структур даних……………..12 Розробка лексичного аналізатора…………………………………………………...16 Розробка граф-схеми алгоритму…………………………………………………..16 Опис програми реалізації лексичного аналізатора…………………………….18 Розробка синтаксичного та семантичного аналізатора………………………19 Розробка граф-схеми алгоритму…………………………………………………..21 Опис програми реалізації синтаксичного та семантичного аналізатора.22 Розробка генератора коду……………………………………………………………...23 Розробка граф-схеми алгоритму……………………………………………………23 Опис програми реалізації генератора коду……………………………………..25 Опис інтерфейсу та інструкції користувача………………………………………….27 Відлагодження та тестування програми……………………………………………..29 Виявлення лексичних помилок……………………………………………………………29 Виявлення синтаксичних помилок………………………………………………………29 Виявлення семантичних помилок………………………………………………………..29 Загальна перевірка коректності роботи транслятора…………………………..29 Висновки……………………………………………………………………………31 Список літератури………………………………………………………………..32 Додатки …………………………………………………………………………….33 А. Лістинг програм………………………………………………………………………33 Завдання на курсову роботу Темою даного курсового проекту є розробка системних програмних модулів та компонент систем програмування. Варіант №22 Потрібно розробити транслятор вхідної мови програмування. Опис вхідної мови: Блок тіла програми : MAINPROGRAM DATA…; START – END Оператор вводу : GET Оператор виводу : PUT Оператор присвоєння : := Оператор: FOR – DOWNTO - DO (Паскаль) Регістр ключових слів : Up Регістр ідентифікаторів : Up _ Арифметичні операції : +; -; *; DIV; MOD Операції порівняння : ==; !=; LT; GT Логічні операції : !!; AND; OR Типи даних : INTEGER, BOOLEAN, рядкова константа Коментар : %% ... %% ВСТУП Системне програмування - це вид програмування, який полягає в роботі з системним програмним забезпеченням. Знати мову програмування і мати комп'ютер — не достатньо, щоб реалізувати програму. Потрібно мати транслятор мови і, бажано, бібліотеки стандартних програм та засоби отримання підказок від комп'ютера, що робити у випадку допущення помилок. Сукупність таких засобів утворює систему програмування деякою мовою. Найважливішим елементом у такій системі є транслятор. Транслятор — це спеціальна програма, яку використовують для перекладу програм користувача, написаних мовою програмування високого рівня, у так звані машинні коди, зрозумілі процесору. Транслятори створюють для кожної мови програмування. Отже, транслятори перекладають команди користувача в набір команд процесора. Це дає змогу використовувати програми, створені мовою низького рівня, на різних типах машин. Іншими словами, транслятор — це перекладач. Розрізняють два типи трансляторів:компілятори, інтерпретатори. Компілятор - це програма, призначена для перекладу в машинні коди програми, що написана мовою високого рівня. Процес такого перекладання називається компіляцією. Кінцевим результатом роботи компілятора є програма в машинних кодах, яка потім виконується ЕОМ. Існує інший спосіб поєднання процесів трансляції та виконання програм. Він називається інтерпретацією. Інтерпретатор - це програма, що призначена для трансляції та виконання вихідної програми по командах. Такий процес називається інтерпретацією. У процесі трансляції відбувається перевірка програми на відповідність до правил її написання. Якщо в програмі знайдені помилки, транслятор виводить повідомлення про них на екран монітора. Судячи з цього зручніше було б подавати текст вхідної мови у вигляді послідовності лексем. У випадку відсутності помилок повинен генеруватися код. 1. ОГЛЯД МЕТОДІВ ТА СПОСОБІВ ПРОЕКТУВАННЯ ТРАНСЛЯТОРІВ Створення компіляторів відбувається в певних конкретних умовах: для різних мов, для різних цільових платформ, з різними вимогами для створення компіляторів. Є такі методи створення компіляторів: 1. Прямий метод - цільовою мовою і мовою реалізації є асемблер. 2. Метод розкрути - саме цей метод і використовується у даній курсовій роботі, тобто вибирається інструмент (в даній курсовій це мова асемблер), для якого вже існує компілятор. 3.Використання крос-трансляторів. 4.З використанням віртуальних машин – дає спосіб отримати переносимо програму. 5. Компіляція на ходу. В даній курсовій роботі згідно із завданням для непарних варіантів необхідно реалізувати висхідний метод граматичного розбору. Детермiнованi висхiднi розпiзнавачi, так само як i спаднi, можуть бути побудованi не для всякої КВ-граматики, а тiльки для визначених пiдкласiв таких граматик. Найбiльш широким пiдкласом КВ-граматик є LR(k)–граматики. Цi граматики забезпечують розпiзнавання ланцюжка при переглядi злiва направо, про що свiдчить буква L (/I>Left) у назвi граматики, i дозволяють виконати правобiчне згортання, про що свiдчить буква R (Right) у назвi. Параметр k свiдчить про те, що для визначення правила граматики, яке потрiбно застосувати для згортання ланцюжка, треба переглянути не бiльше нiж k ще не прочитаних символiв вхiдного ланцюжка. У загальному випадку алгоритми побудови розпiзнавачiв для LR(k)–граматик виявляються досить складними i трудомiсткими, тому на практицi найчастiше використовують пiдкласи LR(k)–граматик: LR(0) або SLR(1) – простi (Simple), LR(1)–граматики, що дозволяють вiдносно просто виконувати побудову висхiдних розпiзнавачiв. При цьому для кожного пiдкласу LR(k)–граматик використовується свiй алгоритм побудови. У загальному випадку процедуру побудови висх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дно до множини граматичних входжень, що позначають рядки. Транслятор — це програма, що призначена для перекладу тексту програми з однієї мови програмування на іншу. Процес перекладання називається трансляцією. У процесі трансляції програми інтерпретатором відбувається перевірка програми на відповідність правилам її написання. Якщо в програмі знайдені помилки, транслятор виводить повідомлення про них на екран монітора. 2. ФОРМАЛЬНИЙ ОПИС ВХІДНОЇ МОВИ ПРОГРАМУВАННЯ 2.1. Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура. <program> ::= MAINPROGRAM DATA <VAR_blok>START <code_blok> END . <VAR_blok> ::= <declarations> [{;<declarations>} ] . <declarations>::= INTEGER <declaration_i> [{,<declaration_i>} ] | BOOLEAN <declaration_b> [{,<declaration_b>} ]. <declaration_i> ::= <ident> [:= <const_i> ] . <declaration_b> ::= <ident> [:= <const_b> ] . <ident> ::= _<h_letter>[<h_letter>|<number>]. <l_or_n> ::= <letter>|<number> . <letter> ::= <l_leter>|<h_leter> <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_leter>::= 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>|<Input>|<Output> . <equation> ::= <ident>:=<expression_i>|<expression_b>. <expression_i>::=<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> | LT <term_b> | GT <term_b>}]. <term_b>::=<ident>|<const_b>|<factor_b>. <factor_b>::=<term_b>[{OR<term_b>|<and>|<not>|<brackets_b>}]. <and>::=[{AND<term_b>}]. <not>::=!!<factor_b>. <brackets_b>::=(<expression_b>). <cycle> ::= FOR <equation> DOWNTO <const_i> DO [START] <code_blok> [END]. <Input> ::= GET(<ident>). <Output> ::= PUT (<expression_i>|<string>) . <string> ::= “<l_or_n>[{<l_or_n>}]”. 2.2. Термінальні символи та ключові слова. MAINPROGRAM – Початок програми DATA – блок опису змінних START – початок тіла програми ENT – кінець тіла програми GET – оператор вводу PUT – оператор виводу FOR – DOWNTO – DO – оператор циклу * – операція множення DIV – операція ділення MOD – остача від ділення == – рівно != – не рівно INTEGER – цілий тип даних BOOLEAN – дійсний тип := - присвоєння LT - менше GT - більше + - операція додавання - - операція віднімання !! - інверсія AND - кон`юнкція OR - диз`юнкція %%…%% – блочний коментар “ – початок рядкової константи при операції виводу; ” – кінець рядкової константи при операції виводу; – розділювач між аргументами; ; – ознака кінця оператора; (– відкриваюча дужка; ) – закриваюча дужка; Як термінальні символи використовуються також усі індійські цифри (0–9), латинські букви (a-z, A-Z), символи табуляції, символ переходу на нову стрічку та пробіл. 3. РОЗРОБКА ТРАНСЛЯТОРА ВХІДНОЇ МОВИ ПРОГРАМУВАННЯ 3.1. Вибір технології програмування Було обрано технологію об'єктно-орієнтованого програмування. Об'єктно-орієнтоване програмування (ООП) — одна з парадигм програмування, яка розглядає програму як множину «об'єктів», що взаємодіють між собою. В ній використано декілька технологій від попередніх парадигм, зокрема успадкування, модульність, поліморфізм та інкапсуляцію. На відміну від традиційних поглядів, коли програму розглядали як набір підпрограм, або як перелік інструкцій комп'ютеру, ООП програми можна вважати сукупністю об'єктів. Відповідно до парадигми об'єктно-орієнтованого програмування, кожний об'єкт здатний отримувати повідомлення, обробляти дані, та надсилати повідомлення іншим об'єктам. Кожен об'єкт — своєрідний незалежний автомат з окремим призначенням та відповідальністю. Об'єктно-орієнтований підхід полягає в наступному наборі основних принципів: Все є об'єктами. Кожен об'єкт має незалежну пам'ять, яка складається з інших об'єктів. Кожен об'єкт є представником (екземпляром, примірником) класу, який виражає загальні властивості об'єктів. У класі задається поведінка (функціональність) об'єкта. Таким чином усі об'єкти, які є екземплярами одного класу, можуть виконувати одні й ті ж самі дії. Класи організовані у єдину деревовидну структуру з загальним корінням, яка називається ієрархією успадкування. Пам'ять та поведінка, зв'язані з екземплярами деякого класу, автоматично доступні будь-якому класу, розташованому нижче в ієрархічному дереві. . NET Framework - програмна платформа компанії Microsoft , призначена для створення звичайних програм та веб-додатків. Головною ідеєю розробки. NET Framework було прагнення зробити платформонезалежну віртуальну машину для виконання одного і того ж коду в різних ОС без внесення змін на момент компіляції. Але з часом Microsoft обмежилася підтримкою тільки своїх операційних систем Windows. Підтримкою деяких інших платформ займаються незалежні розробники (проекти Mono , Portable.NET ). Однією з основних ідей 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: 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) - MAINPROGRAM 1) - DATA 2) – INTEGER 3) - BOOLEAN 4) - <ident> 5) - <num> 6) - := 7) - TRUE 8) - FALSE 9) - , 10) - ; 11) - START 12) - INPUT 13) - OUTPUT 14) - ( 15) - ) 16) - + 17) - - 18) - MUL 19) - DIV 20) - MOD 21) – == 22) - != 23) - LT 24) - GT 25) - !! 26) - AND 27) - OR 28) - <string> 29) – FOR 30) – END 31) – DO 32) – DOWNTO Атрибути використовуються генератором коду для формування відповідних процедур мовою асемблер. Для зберігання таблиці ідентифікаторів використовується Hashtable ID = new Hashtable() Полем таблиці є клас ID_info ,до якого входять такі поля: 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 – Початок роботи лексичного аналізатора Блок 2 – Відкриття і порядкове читання вхідного файлу Блок 3 – Перевірка чи кінець файлу Блок 4 – Виділення першого символу нової лексеми Блок 5 – Перевіряє чи перший символ A-Z Блок 6 – Розпізнання ключових слів Блок 7 – Перевіряє чи перший символ _ Блок 8 – Розпізнання ідентифікаторів Блок 9 – Перевіряє чи перший символ 0-9 Блок 10 – Розпізнання числових констант Блок 11 – Перевіряє чи перший символ “ Блок 12 – Розпізнання рядкових констант Блок 13 – Перевіряє чи символ є оператор Блок 14 – Зберігання до таблиці лексем Блок 15 – Перевіряє чи перший символ є % Блок 16 – Розпізнання коментарів Блок 17 – Перевіряє чи символ є розділювач Блок 18 – Зберігання до таблиці лексем Блок 19 – Перевірка чи лексема Блок 20 – Зберігання нерозпізнаної лексеми Блок 21 – Завершення роботи 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.Граф-схема роботи синтаксичного аналізатора Блок 1 – Початок синтаксичного аналізатора Блок 2 – Перевірка чи не кінець Блок 3 – Виділення пешого символа лексеми Блок 4 – Перевірка чи наступний символ GET Блок 5 – Зсув до кінця конструкції Блок 6 – Перевірка чи конструкція розпізнана Блок 7 – Згортка конструкції GET Блок 8 - Перевіряє чи наступний символ PUT Блок 9 – Зсув до кінця конструкції Блок 10 – Перевірка чи конструкція розпізнана Блок 11 – Згортка конструкції PUT Блок 12 - Перевіряє чи наступний символ FOR Блок 13 – Зсув до кінця конструкції Блок 14 - Перевірка чи конструкція розпізнана Блок 15 - Згортка конструкції FOR Блок 16 - Перевіряє чи наступний символ вираз Блок 17 - Зсув до кінця конструкції Блок 18 - Перевірка чи конструкція розпізнана Блок 19 – Згортка виразу Блок 20 – Конструкція нерозпізнана Блок 21 - Перевіряє чи наступний символ START Блок 22 – Зсув до кінця конструкції Блок 23 - Перевірка чи конструкція розпізнана Блок 24 – Згортка блоку коду Блок 25 – Перевіряє чи наступний символ тип даних Блок 26 – Зсув до кінця конструкції Блок 27 - Перевірка чи конструкція розпізнана Блок 28 – Згортка оголошення змінних Блок 29 – Перевіряє чи наступний символ DATA Блок 30 – Зсув до кінця конструкції Блок 31 - Перевірка чи конструкція розпізнана Блок 32 – Згортка блоку даних Блок 33 – Згортка всієї програми Блок 34 – Кінець Блок 35 – Нерозпізнана конструкція Блок 36 – Кінець 3.4.2 Опис програми реалізації синтаксичного та семантичного аналізатора На вхід синтаксичному аналізатору подається таблиця лексем. Програма почерзі заштовхує всі лексеми в магазин (стек) поки не дійде до «листків дерева». Зустрівши конструкції які є листками синтаксичний аналізатор починай перевірку відповідності конструкцій з правилами вхідної граматики. Конструкція згортається і стає «листком дерева». Аналіз триває доти поки програма не згорне всі конструкції і не дійде до «кореня дерева», яким є термінал Program. В програмі використовуються 2 функції: Фуккція зсуву – шукає кінець конструкції і перевіряє чи наступний символ відповідає допустимий в даному контексті програми Функція згортки – витягує з стеку розпізнану конструкцію, згортає її і заштовхує в стек у згорнутому вигляді. В аналізаторі присутні функції перетворення виразів з інфіксної в постфіксну форми і перевірки на коректність використання у виразах відповідних змінних. Всі помилки виявлені на етапі синтаксичного аналізу заносяться в таблицю помилок. Конструкції, які не згортаються не зберігаються в магазині, це забезпечує продовження роботи транслятора при виявленні помилки. 3.5.Розробка генератора коду 3.5.1 Розробка граф-схеми алгоритму Генерація коду є тісно пов*язаним з синтаксичним аналізом,зразу після розпізнавання генерується код. Блок 1 – Початок генератора коду Блок 2 – Перевірка чи не кінець Блок 3 – Виділення пешого символа лексеми Блок 4 – Перевірка чи наступний символ GET Блок 5 – Зсув до кінця конструкції Блок 6 – Перевірка чи конструкція розпізнана Блок 7 - Виконання функції GenInput() Блок 8 - Перевіряє чи наступний символ PUT Блок 9 – Зсув до кінця конструкції Блок 10 – Перевірка чи конструкція розпізнана Блок 11 – Виконання функції GenOutput() Блок 12 - Перевіряє чи наступний символ FOR Блок 13 – Зсув до кінця конструкції Блок 14 - Перевірка чи конструкція розпізнана Блок 15 - Виконання функції GenFor() Блок 16 - Перевіряє чи наступний символ вираз Блок 17 - Зсув до кінця конструкції Блок 18 - Перевірка чи конструкція розпізнана Блок 19 - Генерація виразів Блок 20 – Конструкція нерозпізнана Блок 21 - Перевіряє чи наступний символ START Блок 22 – Зсув до кінця конструкції Блок 23 - Перевірка чи конструкція розпізнана Блок 24 – Виконання функції GenStart() Блок 25 – Перевіряє чи наступний символ тип даних Блок 26 – Зсув до кінця конструкції Блок 27 - Перевірка чи конструкція розпізнана Блок 28 – Виконання функції GenType() Блок 29 – Перевіряє чи наступний символ DATA Блок 30 – Зсув до кінця конструкції Блок 31 - Перевірка чи конструкція розпізнана Блок 32 – Виконання функції GenData() Блок 33 – Виконання функції GenMainProg() Блок 34 – Кінець Блок 35 – Нерозпізнана конструкція Блок 36 – Кінець 3.5.2 Опис програми реалізації генератора коду Програма перебирає по черзі лексеми із таблиці лексем. В залежності від коду знайденої лексеми в проміжному представленні програми буде вставлено відповідний еквівалентний асемблерний код. Для прикладу, коли зустрінеться ключове слово Data, вставиться опис сегменту даних,а при зустрічі ключового слова Input, то згенерується виклик функції Input. Програма розроблена таким чином, що в асемблер пустий код генеруватися не буде. Для виключення можливості помилок імена ідентифікаторів будуть генеруватися в асемблерний код зі змінами. В розробленому трансляторі генератор коду послідовно викликає функції,які записують у вихідний файл частини коду. Створюється відповідний вихідний код взалежності від лексем. 4. Опис інтерфейсу та інструкції користувачеві Програму Notepad можна запустити з виконавчого файлу G23.exe. G23 є програмою, яка працює на платформі .NET і є візуальною програмою(повинна бути встановлена платформа net framework 2.0). Notepad містить редактор тексту і транслятор. Редактор тексту дозволяє відкривати файли з розширенням *.v23. Рис 4.Вікно редактора тексту В розробленому редакторі реалізовані такі можливості, як:введення і редагування тексту,відкриття нового файл,збереження файлу,закриття файлу,копіювання тексту. Тепер потрібно ввести код програми або відкрити готовий для того щоб його транслювати. Для того щоб транслювати програму потрібно в меню вибрати пункт Build або натиснути клавішу F5.Після чого ми отримаємо вікно транслятора,яке складається з 5 вкладок: Таблиця лексем Таблиця ідентифікаторів Таблиця рядкових констант Таблиця помилок Файл асемблерного коду Рис5.Вікно транслятора 5. ВІДЛАГОДЖЕННЯ ТА ТЕСТУВАННЯ ПРОГРАМИ Відлагодження програми відбувається та тестування програми відбувається в покроковому режимі в середовищі Visual Studio 2010.З використанням точок зупинки, що дає можливість знайти місце логічної помилки. В покроковому режимі у нас є можливість прослідкувати за значеннями змінних. 5.1. Виявлення лексичних помилок. Нерозпізнана лексема – це єдина помилка яка може виникнути на етапі лексичного аналізу. Коли ця помилка все таки виникла,то на етапі синтаксичного аналізу буде згенерована помилка. 5.2. Виявлення синтаксичних помилок. На етапі синтаксичного аналізу виявляється основна кількість помилок. Ці помилки пов’язані з невірними записами конструкцій вхідної мови. Всі помилки виявленні на етапі синтаксичного аналізу заносяться в таблицю помилок. 5.3. Виявлення семантичних помилок. Виявлення семантичних помилок – це перевірка числових констант на відповідність типу, перевірка на коректність використання змінних різних типів у цілочисельних і логічних виразах. 5.4. Загальна перевірка коректності роботи транслятора. Загальна перевірка коректності роботи транслятора полягає в транслюванні коректної вхідної програми з використанням всіх можливостей мови,в асемблерний код та перевірці на правильність виконання програми, яку потрібно попередньо скомпілювати і странслювати за допомогою ml.exe Текст програми: MAINPROGRAM DATA INTEGER _A:=1,_B,_D:=3,_C:=1000,_G:=(-3); BOOLEAN _F; START GET(_A); GET(_B); FOR _D:=1 DOWNTO 2 DO START _A:=_A *_B; PUT("A = "); PUT(_A); END; END Результат роботи програми: Висновки Підчас виконання курсової роботи: 1. Складено формальний опис мови програмування v23 у формі розширеної нотації Бекуса-Наура, дано опис усіх символів та ключових слів. 2. Створено транслятор мови програмування v23, а саме: 2.1.1. Розроблено лексичний аналізатор, здатний розпізнавати лексеми, що є описані в формальному описі мови програмування. 2.1.2. Розроблено синтаксичний аналізатор на основі методу зсув-згортка. 2.1.3. Розроблено генератор коду, який починає свою роботу під час коректного виявлення кожної конструкції і генерує код який відповідає кожній конструкції вхідної мови. 3. Проведене тестування транслятора за допомогою тестових програм за наступними пунктами: Виявлення лексичних помилок. Виявлення синтаксичних помилок. Виявлення семантичних помилок. Загальна перевірка роботи компілятора. СПИСОК ЛІТЕРАТУРИ Шильдт Г. С#. – Санкт-Петербург: BXV, 2007. – 688 с. Ахо А., Ульман Дж. Теория синтаксического анализа, перевода и компиляции. – М.: Мир, 1978. – т.1, 612 с. А.Ю. Молчанов «Системное програмное обеспечение» Лабораторный практикум 2005р. Компаниец Р.И., Маньков Е.В., Филатов Н.Е. Системное программирование. Основы построения трансляторов. – СПб.: КОРОНА принт, 2004. – 256 с. Ваймгартен Ф. Трансляция языков программирования. – М.: Мир, 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 isStart = 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 = new ArrayList(); public static ArrayList lines = new ArrayList(); static Iden_info id_info; 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 (line.Length == 1) continue; if (Form1.isCom) i = ParseComments(line, i) - 1; if (line[i] >= 'A' && line[i] <= 'Z') { i = ParseKeyWords(line, i) - 1; continue; } if (line[i] == '_') { i = ParseIdent(line, i) - 1; continue; } if ((line[i] >= '0' && line[i] <= '9')) { i = ParseNum(line, i)-1; continue; } switch (line[i]) { case '+': lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "+"; lexem.Type = 16; lexem.Comments = "Арифметичний оператор"; lexems.Add(lexem); break; case '-': lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "-"; lexem.Type = 17; lexem.Comments = "Арифметичний оператор"; lexems.Add(lexem); break; case '*': lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "*"; lexem.Type = 18; lexem.Comments = "Арифметичний оператор"; lexems.Add(lexem); break; case '!': if (line[i + 1] == '!') { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "!!"; lexem.Type = 25; lexem.Comments = "Оператор NOT"; lexems.Add(lexem); i++; } else { if (line[i + 1] == '=') { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "!="; lexem.Type = 22; lexem.Comments = "Оператор не рівно"; lexems.Add(lexem); i++; } else { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "!"; lexem.Type = -1; lexem.Comments = "Нерозпізнана лексема"; lexems.Add(lexem); } } break; case '=': if (line[i + 1] == '=') { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "=="; lexem.Type = 23; lexem.Comments = "Оператор рівно"; lexems.Add(lexem); i++; } else { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "="; lexem.Type = -1; lexem.Comments = "Нерозпізнана лексема"; lexems.Add(lexem); } break; case ':': if (line[i + 1] == '=') { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = ":="; lexem.Type = 6; lexem.Comments = "Оператор присвоєння"; lexems.Add(lexem); i++; } else { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = ":"; lexem.Type = -1; lexem.Comments = "Нерозпізнана лексема"; lexems.Add(lexem); } break; case '\"': i = ParseString(line, i)-1; break; case '%': i = ParseComments(line, i) - 1; break; case ';': lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = ";"; lexem.Type = 10; lexem.Comments = "Розділювач"; lexems.Add(lexem); break; case ',': lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = ","; lexem.Type = 9; lexem.Comments = "Розділювач"; lexems.Add(lexem); break; case ')': lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = ")"; lexem.Type = 15; lexem.Comments = "Розділювач"; lexems.Add(lexem); break; case '(': lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "("; lexem.Type = 14; lexem.Comments = "Розділювач"; lexems.Add(lexem); break; case' ': break; case '\t': break; case '\n': lines.Add(num); break; default: i = ParseNoLex(line, i) - 1; break; } } } private static int ParseIdent(string line, int position) { int i = position + 1; string id; while (line[i] >= 'A' && line[i] <= 'Z' || line[i] >= '0' && line[i] <= '9') { i++; } id = line.Remove(0, position); id = id.Remove(i - position); lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = id; lexem.Type = 4; lexem.Comments = "Ідентифікатор"; lexems.Add(lexem); return i; } private static int ParseKeyWords(string line,int position) { string Key_Word; int i = position+1; while (line[i] >= 'A' && line[i] <= 'Z') { i++; } Key_Word = line.Remove(0, position); Key_Word = Key_Word.Remove(i-position); string[] KeyWords = { "MAINPROGRAM", "DATA", "START", "END", "GET", "PUT", "FOR", "DO", "AND", "DIV", "MOD", "LT", "GT", "INTEGER", "BOOLEAN", "TRUE", "FALSE", "OR", "DOWNTO" }; foreach (string st in KeyWords) { if (st.Equals(Key_Word)) { lexem = new Lexem(); lexem.Id = num; num++; switch (Key_Word) { case "MAINPROGRAM": lexem.Type = 0; break; case "DATA": lexem.Type = 1; break; case "START": isStart = true; lexem.Type = 11; break; case "END": lexem.Type = 30; break; case "GET": lexem.Type = 12; break; case "PUT": lexem.Type = 13; break; case "FOR": lexem.Type = 31; break; case "AND": lexem.Type = 26; break; case "DIV": lexem.Type = 19; break; case "BOOLEAN": lexem.Type = 3; break; case "INTEGER": lexem.Type = 2; break; case "TRUE": lexem.Type = 7; break; case "FALSE": lexem.Type = 8; break; case "MOD": lexem.Type = 20; break; case "LT": lexem.Type = 23; break; case "GT": lexem.Type = 24; break; case "DO": lexem.Type = 32; break; case "DOWNTO": lexem.Type = 29; break; case "OR": lexem.Type = 27; break; } lexem.Lex = Key_Word; lexem.Comments = "Ключове слово"; lexems.Add(lexem); return i; } } lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = Key_Word; lexem.Type = -1; lexem.Comments = "Нерозпізна лексема"; lexems.Add(lexem); return i; } private static int ParseNum (string line,int position) { int i = position; string Num; i++; while (line[i] >= '0' && line[i] <= '9') { i++; } Num = line.Remove(0, position); Num = Num.Remove(i - position); lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = Num; try { if (isStart) const_int.Add(Num, Num); } catch { } lexem.Type = 5; lexem.Comments = "Числова константа"; lexems.Add(lexem); return i; } private static int ParseString(string line,int position) { int i=position+1; string st; while (i < line.Length) { if (line[i] == '\"') { i++; break; } i++; } if (i == line.Length) { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "\""; lexem.Type = -1; lexem.Comments = "Нерозпізна лексема"; lexems.Add(lexem); return position + 1; } else { st = line.Remove(0, position); st = st.Remove(i - position); lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = st; strs = new Const_Strings(); strs.Value = st; strs.Number = num; try { const_str.Add(st, strs); } catch { }; lexem.Type = 28; lexem.Comments = "Рядкова константа"; lexems.Add(lexem); return i; } } private static int ParseComments(string line, int position) { int i = position + 1; string com; if (line[i] != '%' && !Form1.isCom) { lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = "%"; lexem.Comments = "Нерозпізна лексема"; lexems.Add(lexem); return position + 1; } else { if (line.LastIndexOf("%%") != -1) { com = line.Remove(0, position); com = com.Remove(line.LastIndexOf("%%") + 2 - position); Comments = Comments + com; lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = Comments; Comments = ""; lexem.Comments = "Коментар"; //lexems.Add(lexem); Form1.isCom = false; return line.LastIndexOf("%%") + 3; } { com = line.Remove(0, position); Comments = Comments + com; Form1.isCom = true; return line.Length; } } } private static int ParseNoLex(string line, int position) { int i = position; string NoLex; while (line[i] != ' ' && line[i] != '\t' && line[i] != '\n' && line[i] != ')' && line[i] != '(' && line[i] != ',' && line[i] != ';') { i++; } NoLex = line.Remove(0, position); NoLex = NoLex.Remove(i - position); lexem = new Lexem(); lexem.Id = num; num++; lexem.Lex = NoLex; lexem.Type = -1; lexem.Comments = "Нерозпізна лексема"; lexems.Add(lexem); return i; } } } using System; using System.Collections.Generic; using System.Text; using System.Collections; using System.Windows.Forms; namespace Notepad { public class Error { int NumLex; string TextErr; public int Num_Lex { get { return NumLex; } set { NumLex = value; } } public string Error_Text { get { return TextErr; } set { TextErr = value; } } } class Syntax { static Error err; static PreTabel pt = new PreTabel(); static ArrayList Row; public static ArrayList errors = new ArrayList(); static Stack magazin = new Stack(); static Stack construct = new Stack(); static Lexem Pred, Next, Temp; public static int i = 0; static string state = ""; static bool isEqu=false; static int Exit = 0,Start,Finish; static int j = 0; static Iden_info id_info; static string Type_var = ""; static string ident = ""; static string Value = ""; static bool isMinus = false; static bool isGet = false,isPut = false,isWhile=false; static int Put_Start=0, Put_Finish=0; static bool isString = false; public static void Analiz(ArrayList lexems) { Pred = (Lexem)lexems[i++]; if (Pred.Type == 0) { construct.Push(Pred); magazin.Push(Pred); Generation.GenerateBegin(); } else { err = new Error(); err.Error_Text = "Програма повинна розпочинатись з ключового слова Program"; err.Num_Lex = i - 1; errors.Add(err); return; } Next = (Lexem)lexems[i++]; while (i < lexems.Count) { try { Temp = (Lexem)construct.Peek(); if (Next.Type == 11 && Temp.Type == 1 || Temp.Type == 0 && Next.Type == 11) { Pred = Temp; } else if (Next.Type == 1 || Next.Type == 2 || Next.Type == 3 || Next.Type == 11 || Next.Type == 14 || (Next.Type == 4 && Pred.Type == 9) || (Next.Type == 4 && Pred.Type == 2) || (Next.Type == 4 && Pred.Type == 3)) construct.Push(Next); } catch { } if (Next.Type == 2) Type_var = "INTEGER"; if (Next.Type == 3) Type_var = "BOOLEAN"; if (Next.Type == 4) ident = Next.Lex; if (Next.Type == 17) isMinus = true; if (Next.Type == 5) if (!isMinus) Value = Next.Lex; else { Value = "-" + Next.Lex; isMinus = false; } if (Next.Type == 7) Value = "1"; if (Next.Type == 8) Value = "0"; if (Next.Type == 9 || Next.Type == 10) { id_info = new Iden_info(); id_info.Id = ident; id_info.Type = Type_var; id_info.Value = Value; try { if (ident != "") Parser.identy.Add(ident, id_info); } catch { err = new Error(); err.Error_Text = "Змінна вже оголошена"; err.Num_Lex = i - 1; errors.Add(err); return; } ident = ""; Value = ""; } try { Row = (ArrayList)PreTabel.preTable[Pred.Type]; state = (string)Row[Next.Type]; } catch { err = new Error(); err.Error_Text = "Нерозпізнана лексема"; err.Num_Lex = i - 1; errors.Add(err); return; } switch (state) { case "<": magazin.Push(Next); Pred = Next; Next = (Lexem)lexems[i++]; break; case ">": //try //{ Temp = (Lexem)construct.Pop(); while (Temp != (Lexem)magazin.Pop()) { } if (Pred.Type == 1 && Next.Type == 11 || Pred.Type == 0 && Next.Type == 11) { construct.Push(Next); magazin.Push(Next); Generation.GenereteVar(); Generation.GenereteDerlaration(); AnalizBegin(lexems, i - 1); return; } if (!(Temp.Type == 4 && Next.Type == 10)) { Pred = Next; Next = (Lexem)lexems[i++]; } //} //catch { // Pred = Next; // Next = (Lexem)lexems[i++]; //} break; case "=": Pred = Next; Next = (Lexem)lexems[i++]; break; case "-": err = new Error(); err.Error_Text = "Помилка в оголошенні змінних"; err.Num_Lex = i - 1; errors.Add(err); return; } } } private static void AnalizBegin(ArrayList lexems, int i) { bool Type = true ; Iden_info id; Pred = (Lexem)lexems[i++]; Next = (Lexem)lexems[i++]; while (i <= lexems.Count) { if (Next.Type == 12) isGet = true; if (Next.Type == 13) isPut = true; if (Next.Type == 12 || Next.Type == 13 || Next.Type == 31) { Type = true; } if (Next.Type == 31) { isWhile = true; } if (Next.Type == 4 && Pred.Type == 11 || Next.Type == 4 && Pred.Type == 10 || Next.Type == 4 && Pred.Type == 31 || Next.Type == 4 && Pred.Type == 32) { isEqu = true; Exit = i - 1; j = 0; if (Next.Type == 4) { if (Parser.identy.ContainsKey(Next.Lex)) { id = (Iden_info)Parser.identy[Next.Lex]; Type = (id.Type == "INTEGER") ? true : false; } } } if (!isWhile && Next.Type == 4) isDeclaredVariable(Next, Type, i - 1); if (Next.Type == 32) Generation.RepeatStart(); if (Next.Type == 10 && Pred.Type == 30) Generation.GenerateUntil(); if (Next.Type == 5 && Pred.Type == 29) Generation.GenereteInicialCycle(Next); if (isGet && Pred.Type == 4 && Next.Type != 15) { err = new Error(); err.Error_Text = "Невірний запис конструкції Get"; err.Num_Lex = i; errors.Add(err); return; } if (isGet && Pred.Type == 4 && Next.Type == 15) { Lexem lx = (Lexem)lexems[i-2]; Generation.GenerateReadVar(lx.Lex); Infix_to_Postfix(lexems, i - 2, i - 1, false); } if (isPut && Pred.Type == 14 && Next.Type == 4) Put_Start = i - 1; if (isPut && Pred.Type == 14 && Next.Type == 28) isString = true; if (isPut && Pred.Type == 15 && Next.Type == 10) { if (!isString) { Put_Finish = i - 3; if (Put_Start != 0 && Put_Finish != 0 && Put_Start != lexems.Count) { Infix_to_Postfix(lexems, Put_Start, Put_Finish, false); Generation.GenerateWrite(true); Put_Start = 0; Put_Finish = 0; } } } if (isPut && isString) { Lexem lx = (Lexem)lexems[i - 1]; Generation.GenerateStr(lx.Lex); Generation.GenerateWrite(false); isString = false; } if (Next.Type == 11 || Next.Type == 12 || Next.Type == 13 || Next.Type == 14 || Next.Type == 31 || (Next.Type == 4 && Pred.Type == 10) || (Next.Type == 4 && Pred.Type == 11) || (Next.Type == 4 && Pred.Type == 31) || (Next.Type == 4 && Pred.Type == 32)) { construct.Push(Next); } if (Next.Type == 14) j++; try { Row = (ArrayList)PreTabel.preTable[Pred.Type]; state = (string)Row[Next.Type]; } catch { err = new Error(); err.Error_Text = "Нерозпізнана лексема"; err.Num_Lex = i - 1; errors.Add(err); return; } switch (state) { case "<": magazin.Push(Next); Pred = Next; Next = (Lexem)lexems[i++]; break; case ">": if (Next.Type == 10 && isGet) isGet = false; if (Next.Type == 10 && isPut) isPut = false; if (Next.Type == 10 || Next.Type == 29) Finish = i - 1; if (Next.Type == 30 && i == lexems.Count) { Temp = (Lexem)construct.Pop(); if (Temp.Type != 11) { err = new Error(); err.Error_Text = "Неправельне завершення програми, конструкції не завершені."; err.Num_Lex = lexems.Count - 1; errors.Add(err); return; } else Generation.GenerateEndProgram(); return; } Temp = (Lexem)construct.Peek(); if (Next.Type == 30 && Temp.Type != 11) { Pred = Next; Next = (Lexem)lexems[i++]; continue; } if (isEqu) Start--; Temp = (Lexem)construct.Pop(); if (Temp.Type == 4) { if (Type && Exit != 0) { if (Next.Type == 29) Infix_to_Postfix(lexems, Exit, Finish, true); else Infix_to_Postfix(lexems, Exit, Finish, false); } else { Infix_to_Postfix_b(lexems, Exit, Finish); } } if (!isEqu) while (Temp != (Lexem)magazin.Pop()) { } else { construct.Push(Temp); Temp = (Lexem)construct.Peek(); if (Temp.Type == 4) { Start = Start + i - j; while (Exit < Start) { magazin.Pop(); Start--; } Temp = (Lexem)construct.Peek(); if (Temp.Type == 4) { construct.Pop(); } Temp = (Lexem)magazin.Peek(); if (Temp.Type == 4) { magazin.Pop(); } Start = 0; Finish = 0; Exit = 0; isEqu = false; } else { while (Temp != (Lexem)magazin.Pop()) { Start--; } construct.Pop(); //j--; } } if (i == lexems.Count) { i++; break; } else { Pred = Next; Next = (Lexem)lexems[i++]; } break; case "=": Pred = Next; Next = (Lexem)lexems[i++]; break; case "-": err = new Error(); err.Error_Text = "Задана лексема не може використовуватись в цій конструкції"; err.Num_Lex = i - 1; errors.Add(err); return; } } } private static void isDeclaredVariable(Lexem lex, bool Type, int num) { if (!Parser.identy.ContainsKey(lex.Lex)) { err = new Error(); err.Num_Lex = num; err.Error_Text = "Змінна не оголошена"; errors.Add(err); } else { Iden_info id = (Iden_info)Parser.identy[lex.Lex]; if (Type) { if (id.Type != "INTEGER") { err = new Error(); err.Num_Lex = num; err.Error_Text = "Змінна повинна бути типу INTEGER"; errors.Add(err); } } else { if (id.Type != "BOOLEAN") { err = new Error(); err.Num_Lex = num; err.Error_Text = "Змінна повинна бути типу BOOLEAN"; errors.Add(err); } } } } static Stack stack; static ArrayList postfix; public static void Infix_to_Postfix(ArrayList lexems, int start, int finish, bool b) { stack = new System.Collections.Stack(); postfix = new ArrayList(); Lexem lexem, lex, Zero = new Lexem(); Lexem lexReturn = new Lexem(); lexReturn.Id = -1; Zero.Id = 0; Zero.Lex = "0"; Zero.Type = 35; Lexem type; lex = (Lexem)lexems[start + 1]; if (lex.Type == 6) { lexReturn = (Lexem)lexems[start]; start = start + 2; } for (int j = start; j <= finish; j++) { lexem = (Lexem)lexems[j]; lex = (Lexem)lexems[j + 1]; if (lexem.Type == 14 && lex.Type == 17) postfix.Add(Zero); switch (lexem.Type) { case 4: postfix.Add(lexem); break; case 5: postfix.Add(lexem); break; case 14: stack.Push(lexem); break; case 15: if (stack.Count != 0) { type = (Lexem)stack.Pop(); while (type.Type != 14) { postfix.Add(type); if (stack.Count != 0) type = (Lexem)stack.Pop(); else { err = new Error(); err.Num_Lex = j; err.Error_Text = "Дизбаланс дужок"; errors.Add(err); break; } } } break; case 16: if (stack.Count != 0) { type = (Lexem)stack.Pop(); while (stack.Count != 0 && type.Type != 14) { postfix.Add(type); type = (Lexem)stack.Pop(); if (stack.Count == 0) postfix.Add(type); } if (type.Type == 14) stack.Push(type); stack.Push(lexem); } else stack.Push(lexem); break; case 17: if (stack.Count != 0) { type = (Lexem)stack.Pop(); while (stack.Count != 0 && type.Type != 14) { postfix.Add(type); type = (Lexem)stack.Pop(); if (stack.Count == 0) postfix.Add(type); } if (type.Type == 14) stack.Push(type); stack.Push(lexem); } else stack.Push(lexem); break; case 18: if (stack.Count != 0) { type = (Lexem)stack.Pop(); switch (type.Type) { case 16: stack.Push(type); stack.Push(lexem); break; case 17: stack.Push(type); stack.Push(lexem); break; case 18: postfix.Add(type); stack.Push(lexem); break; case 19: postfix.Add(type); stack.Push(lexem); break; case 20: postfix.Add(type); stack.Push(lexem); break; default: if (type.Type == 14) { stack.Push(type); stack.Push(lexem); } break; } } else { stack.Push(lexem); } break; case 19: if (stack.Count != 0) { type = (Lexem)stack.Pop(); switch (type.Type) { case 16: stack.Push(type); stack.Push(lexem); break; case 17: stack.Push(type); stack.Push(lexem); break; case 18: postfix.Add(type); stack.Push(lexem); break; case 19: postfix.Add(type); stack.Push(lexem); break; case 20: postfix.Add(type); stack.Push(lexem); break; default: if (type.Type == 14) { stack.Push(type); stack.Push(lexem); } break; } } else { stack.Push(lexem); } break; case 20: if (stack.Count != 0) { type = (Lexem)stack.Pop(); switch (type.Type) { case 16: stack.Push(type); stack.Push(lexem); break; case 17: stack.Push(type); stack.Push(lexem); break; case 18: postfix.Add(type); stack.Push(lexem); break; case 19: postfix.Add(type); stack.Push(lexem); break; case 20: postfix.Add(type); stack.Push(lexem); break; default: if (type.Type == 14) { stack.Push(type); stack.Push(lexem); } break; } } else { stack.Push(lexem); } break; } } while (stack.Count != 0) { type = (Lexem)stack.Pop(); if (type.Type != 14) postfix.Add(type); else { err = new Error(); err.Num_Lex = finish; err.Error_Text = "Дизбаланс дужок"; errors.Add(err); break; } } //string Mess=""; //foreach (Lexem lx in postfix) //{ // Mess = Mess + lx.Lex; //} //MessageBox.Show(Mess); Generation.GenereteExp_i(postfix, lexReturn, isPut, b); lexReturn.Id = -1; } public static void Infix_to_Postfix_b(ArrayList lexems, int start, int finish) { stack = new System.Collections.Stack(); postfix = new ArrayList(); Lexem lexem,lex; Lexem type, lexReturn_b = new Lexem(); lexReturn_b.Id = - 1; lex = (Lexem)lexems[start + 1]; if (lex.Type == 6) { lexReturn_b = (Lexem)lexems[start]; start = start + 2; } for (int j = start; j <= finish; j++) { lexem = (Lexem)lexems[j]; switch (lexem.Type) { case 4: postfix.Add(lexem); break; case 5: postfix.Add(lexem); break; case 14: stack.Push(lexem); break; case 15: if (stack.Count != 0) { type = (Lexem)stack.Pop(); while (type.Type != 14) { postfix.Add(type); if (stack.Count != 0) type = (Lexem)stack.Pop(); else { err = new Error(); err.Num_Lex = j; err.Error_Text = "Дизбаланс дужок"; errors.Add(err); break; } } } break; case 25: if (stack.Count != 0) { type = (Lexem)stack.Pop(); if (type.Type == 25) { postfix.Add(type); } else { stack.Push(type); } stack.Push(lexem); } else { stack.Push(lexem); } break; case 26: if (stack.Count != 0) { type = (Lexem)stack.Pop(); switch (type.Type) { case 21: stack.Push(type); stack.Push(lexem); break; case 14: stack.Push(type); stack.Push(lexem); break; case 25: postfix.Add(type); if (stack.Count != 0) { type = (Lexem)stack.Pop(); if (type.Type == 26) postfix.Add(type); else stack.Push(type); stack.Push(lexem); } else { stack.Push(lexem); } break; case 26: postfix.Add(type); stack.Push(lexem); break; case 27: stack.Push(type); stack.Push(lexem); break; case 22: stack.Push(type); stack.Push(lexem); break; } } else { stack.Push(lexem); } break; case 27: if (stack.Count != 0) { type = (Lexem)stack.Pop(); switch (type.Type) { case 21: stack.Push(type); stack.Push(lexem); break; case 14: ...
Допоможи студентському архіву

Ми допомогли тобі — допоможи наступному студенту

Файл ще не обрано

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

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

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

Admin

26.02.2023 12:38

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