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

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

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

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

Рік:
2011
Тип роботи:
Інші
Предмет:
Системне програмування

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

МІНІСТЕРТСВО ОСВІТИ І НАУКИ УКРАЇНИ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ "ЛЬВІВСЬКА ПОЛІТЕХНІКА"  Пояснювальна записка до курсової роботи з курсу: "Системне програмування" на тему: "Розробка системних програмних модулів та компонент систем програмування" Анотація Метою виконання курсової роботи є закріплення теоретичних знань та практичних навичок системного програмування, набутих при вивченні дисципліни “Системне програмування”.. При виконанні над даної роботи студент повинен виконати індивідуальне завдання по розробці транслятора вхідної мови програмування. В даній курсовій роботі показано розробку і виконання наступних фаз компіляції: Лексичний аналіз; Синтаксичний аналіз; Генерація коду. Результатом виконання курсової роботи повинна бути повноцінна функціональна програма на мові Assembler, яка є інтрепретованою програмою реалізованої на заданій вхідній мові програмування. Зміст Завдання на курсову роботу 4 Вступ 5 1. Огляд методів та способів проектування трансляторів 6 2. Формальний опис вхідної мови програмування 8 2.1. Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура 8 2.2. Опис термінальних символів та ключових слів 9 3. Розробка транслятора вхідної мови програмування 10 3.1. Вибір технології програмування 10 3.2. Проектування таблиць транслятора та вибір структур даних 10 3.3. Розробка лексичного аналізатора 11 3.3.1. Опис програми реалізації лексичного аналізатора 11 3.4. Розробка синтаксичного та семантичного аналізатора 14 3.4.1. Розробка дерев граматичного розбору 15 3.4.2. Опис програми реалізації синтаксичного аналізатора 15 3.5. Розробка генератора коду 17 3.5.1. Опис програми реалізації генератора коду 18 3.6. Опис реалізації програми 19 4. Опис інтерфейсу та інструкції користувача 23 5. Відлагодження та тестування програми 25 5.1. Виявлення лексичних помилок 25 5.2. Виявлення синтаксичних помилок 25 5.3. Загальна перевірка коректності роботи транслятора 26 Висновки 27 Список літератури 28 Додаток А. Лістинг програми 29 Додаток Б. Результати відлагодження та тестування програми 52 Додаток В. Граф-схема алгоритму виконання програми через використання функцій 57 Додаток Г. Дерево граматичного розбору 58 Завдання на курсову роботу 1. Цільова мова транслятора асемблер (iх86). 2. Для отримання виконавчого файлу на виході розробленого транслятора скористатися програмами tasm.exe і tlink.exe або tasm32.exe і tlink32.exe. 3. Мова розробки транслятора: ANSI C або C++. 4. Реалізувати оболонку або інтерфейс з командного рядка. 5. На вхід розробленого транслятора має подаватися текстовий файл, написаний на заданій мові програмування. 6. На виході розробленого транслятора мають створюватись чотири файли: файл з повідомленнями про помилки (або про їх відсутність); файл на мові асемблера; об’єктний файл; виконавчий файл. 7. Назва вхідної мови програмування утворюється від першої букви у прізвищі студента та останніх двох цифр номера його варіанту. Саме таке розширення повинні мати текстові файли, написані на цій мові програмування. Для мого варіанту це будуть файли із розширенням (*.L69.). Деталізований опис вхідної мови Тип даних: знакове чотирьохбайтне ціле (Int32); Регістр ключових слів: Up-Low перший символ Up; Регістр ідентифікаторів: Up4; Арифметичні операції: +; -; Mul; Div, Mod; Операції порівняння: ==, !=, >, <; Логічні операції !!, &&, ||; Оператор присвоєння: <<; Блок тіла програми: Program <name>; Start Var …; Finish; Коментар {* *}; Оператор циклу (For – DownTo (Паскаль)); Оператори вводу, виводу: Get, Put. Вступ Транслятором називається програма перекладу (трансляції) початкової програми, записаною вхідною мовою, в еквівалентну їй об`єктну програму. Якщо мова високого рівня є вхідною, а мова асемблера чи машинна – вихідною, то такий транслятор називається компілятором.[5] Транслятори бувають двох типів: компілятори і інтерпретатори. Процес компіляції складається з двох частин: аналізу і синтезу. На етапі аналізу вхідну програму розбивають на окремі елементи (лексеми), перевіряють її на відповідність правилам граматики і створюють проміжне представлення вхідної програми. На етапі синтезу із проміжної форми створюють програму в машинних кодах. Така програма називається об’єктною програмою. В подальшому об’єктну програму можна виконати на комп’ютері без пере трансляції.[5] На відміну від компіляторів, інтерпретатор не створює нової програми, а просто виконує – інтерпретує кожен оператор вхідної мови програмування. Подібно компілятору, інтерпретатор аналізує вхідну програму, створює проміжне представлення, однак не створює об’єктної програми, а зразу виконує передбачені вхідною програмою. Компілятор переводить програму з однієї мови на іншу. На вхід компілятора поступає ланцюг символів, який є вхідною програмою на певній мові програмування. На виході компілятора (об’єктна програма) також представляє собою ланцюг символів, який вже належить іншій мові програмування, наприклад машинній мові деякого комп’ютера. При цьому сам компілятор може бути написаний третьою мовою. 1. Огляд методів та способів проектування трансляторів Транслятор - обслуговуюча програма, що перетворює вихідну програму, надану на вхідній мові програмування, у робочу програму, представлену на об'єктному мовою. Компілятор - це обслуговуюча програма, що виконує трансляцію на машинну мову програми, записаної мовою оригіналу програмування. Також як і асемблер, компілятор забезпечує перетворення програми з однієї мови на іншу (найчастіше, в мову конкретного комп'ютера). Інтерпретатор - програма або пристрій, що здійснює пооператорну трансляцію і виконання вихідної програми. На відміну від компілятора, інтерпретатор не породжує на виході програму на машинній мові. Розпізнавши команду вихідного мови, він тут же виконує її. Як у компіляторах, так і в інтерпретатора використовуються однакові методи аналізу вихідного тексту програми. Але інтерпретатор дозволяє почати обробку даних після написання навіть однієї команди. Це робить процес розробки і налагодження програм більш гнучким. Процес трансляції складається з наступних етапів: На фазі лексичного аналізу вхідна програма, що представляє собою потік літер, розбивається на лексеми - слова у відповідності з визначеннями мови. Основними формалізму, які лежать в основі реалізації лексичних аналізаторів, є кінцеві автомати та регулярні вирази. Лексичний аналізатор може працювати в двох основних режимах: або як підпрограма, що викликається синтаксичним аналізатором для отримання чергової лексеми, або як повний прохід, результатом якого є файл лексем. У процесі виділення лексем лексичний аналізатор може як самостійно будувати таблиці об'єктів (ідентифікаторів, рядків, чисел і т.д.), так і видавати значення для кожної лексеми при черговому до нього зверненні. У цьому випадку таблиці об'єктів будуються в наступних фазах (наприклад, в процесі синтаксичного аналізу). На етапі лексичного аналізу виявляються деякі (найпростіші) помилки (неприпустимі символи, неправильний запис чисел, ідентифікаторів та ін.) Основне завдання синтаксичного аналізу - розбір структури програми. Як правило, під структурою розуміється дерево, відповідне розбору в контекстно-вільної граматики мови. В даний час найчастіше використовується або LL (1)-аналіз (і його варіант - рекурсивний спуск), або LR (1) - аналіз та його варіанти (LR (0), SLR (1), LALR (1) та інші) . Рекурсивний спуск частіше використовується при ручному програмуванні синтаксичного аналізатора, LR (1) - при використанні систем автоматичного побудови синтаксичних аналізаторів. Результатом синтаксичного аналізу є синтаксичне дерево з посиланнями на таблиці об'єктів. У процесі синтаксичного аналізу також виявляються помилки, пов'язані зі структурою програми. На етапі контекстного аналізу виявляються залежності між частинами програми, які не можуть бути описані контекстно-вільною синтаксисом. Це в основному зв'язку «опис-використання», зокрема, аналіз типів об'єктів, аналіз областей видимості, відповідність параметрів, мітки та інші. У процесі контекстного аналізу таблиці об'єктів поповнюються інформацією про описах (властивостях) об'єктів. У процесі контекстного аналізу також можуть бути виявлені помилки, пов'язані з неправильним використанням об'єктів. Потім програма може бути переведена у внутрішнє представлення. Це робиться для цілей оптимізації та / або зручності генерації коду. Ще однією метою перетворення програми у внутрішнє представлення є бажання мати переносимий компілятор. Тоді тільки остання фаза (генерація коду) є машинно-залежною. В якості внутрішнього подання може використовуватися префіксная або постфіксній запис, орієнтований граф, трійки, четвірки та інші. Фаз оптимізації може бути декілька. Оптимізації зазвичай ділять на машинно-залежні та машинно-незалежні, локальні і глобальні. Частина машинно-залежною оптимізації виконується на фазі генерації коду. Глобальна оптимізація намагається взяти до уваги структуру всієї програми, локальна - тільки невеликих її фрагментів. Глобальна оптимізація грунтується на глобальному потоковий аналіз, який виконується на графі програми і представляє по суті перетворення цього графа. При цьому можуть враховуватися такі властивості програми, як межпроцедурний аналіз, міжмодульних аналіз, аналіз галузей життя змінних і т.д. Нарешті, генерація коду - остання фаза трансляції. Результатом її є або асемблерний модуль, або об'єктний (або завантажувальний) модуль. У процесі створення коду можуть виконуватися деякі локальні оптимізації, такі як розподіл регістрів, вибір довгих або коротких переходів, облік вартості команд при виборі конкретної послідовності команд. Для генерації коду розроблені різні методи, такі як таблиці рішень, зіставлення зразків, що включає динамічне програмування, різні синтаксичні методи. Звичайно, ті чи інші фази транслятора можуть або відсутні зовсім, або об'єднуватися. У найпростішому випадку однопрохідного транслятора немає явної фази генерації проміжного представлення та оптимізації, інші фази об'єднані в одну, причому немає і явно побудованого синтаксичного дерева. 2. Формальний опис вхідної мови програмування 2.1. Деталізований опис вхідної мови в термінах розширеної нотації Бекуса-Наура <program> ::=Program <name>; Start Var<declaration>; <blok> Finish < blok> ::= < operator > | [{< operator>}] <declaration> ::= <ident> <type>; <type> ::= Int32 <is> ::= << <ident> ::= <h_letter> [<l _letter>] <leter> ::=< h_letter >|<l_letter> <h_letter> ::= A|B|C|D|E|F|G|H|I|J|K|L|N|M|O|P|Q|R|S|T|U|V|W|X|Y|Z <l_letter> ::=a|b|c|d|e|f|g|h|i|j|k|l|n|m|o|p|q|r|s|t|u|v|w|x|y|z <number> ::= 0|1|2|3|4|5|6|7|8|9 <const> ::= [“-”]<number>[{number}] ; <name_const> ::={<letter >|<number> [{<letter>}]|[{<number>}]} <operator> ::= <equation >| <print> | <scan>| <circle>|<operator_block> <equation> ::= <ident><is><expression> <expression> ::= [(] <operand> [)] [{ [)]<operation>[(]<operand> [)] }] <operand> ::= <ident>|<const> |<ident> <operation> ::= <arifmetic>|<logic> <arifmetic> ::=<arifmetic>+<harifmetic>|<arifmetic>-<harifmetic>|harifmetic <harifmetic> ::=< harifmetic>Mul<farifmetic>|< harifmetic>Div <farifmetic>| < harifmetic>Mod<farifmetic>|<farifmetic> <farifmetic> ::=<operand>|(<arifmetic>) <logic> ::=<egual>[||<egual>]|<logic_b> logic_b> ::=<logic_b>&&<logic_h>|<logic_h> <logic_h> ::= !!<logic_h>| <logic_bh> <logic_bh> ::=(<logic>)|<egual> <egual> ::= (< operand ><eg_op><operand>) <eg_op> ::= ==| !=| >| <| <cyrcle> ::= For <equation> DownTo <ident> <operator_block> <get> ::= Get (<ident>); < put> ::= Put (<ident> | <name_const>); <operator_block> ::= Start < operator > | [{< operator>}] Finish 2.2. Опис термінальних символів та ключових слів Визначимо окремі термінальні символи та нерозривні набори термінальних символів (ключові слова): Program Start Var Finish For DownTo Get Put Int32 + - Mul Div Mod == != > < !! && || << ( ) {* *} , ; До термінальних символів віднесемо також усі цифри (0-9), латинські букви (a-z, A-Z), символи табуляції,символ переходу на нову стрічку, пробілу, знаку “-“. 3. Розробка транслятора вхідної мови програмування 3.1. Вибір технології програмування Перед тим як розпочинати створювати програму, для більш швидкого і ефективного її написання необхідно розробити алгоритм її функціонування, та вибрати технологію програмування, середовище програмування. Для виконання поставленного завдання найбільш доцільніше було використання мову програмування С++ та середовища програмування C++ Builder 2010 Для більш якісного і зручного використання розробленої програми користувачем, було прийнято рішення створення об’єктного інтерфейсу. Для цього на базі прийнятого середовища використовується метод розробки VCL Forms Application C++ Builder. Цей метод дозволяє легко і якісно створювати об’єктні форми , для цього потрібно лише вставити потрібний об’єкт, і після цього одразу створюється функція відповідного об’єкту, в яку заноситься модуль функціонування цього об’єкту. Також даний метод передбачає використання багатьох різних стандартних структур, які дозволяють спростити і полегшити написання, та спростити читабельність програми. 3.2. Проектування таблиць транслятора та вибір структур даних У програмі використовуються наступні структури даних: Переліr доступних лексем – дозволяє полегшити сприйняття коду: enum eTypesOfTokens { ltProgram, // program ltVar, // var ltType, // int32 ltBegin, // start ltEnd, // finish ltRead, // get ltWrite, // put ltFor, // For ltDownTo, // DownTo ltNewValue, // << ltAdd, // + ltSub, // - ltMul, // mul ltDiv, // div ltMod, // mod ltEqu, // == ltNotEqu, // != ltLess, // < ltGreate, // > ltNot, // !! ltAnd, // && ltOr, // || ltEOF, // EOF ltEndGroup, // ; ltComma, // , ltIdentifier, // Identificator ltNumber, // Number ltLBraket, // ( ltRBraket, // ) ltQuotes, // " ltLetters, // "text" ltUnknown //Unkown }; typedef struct tokens_ { char name[50]; int value; eTypesOfTokens type; int line; char text[255]; } tokens; Структура для опису ідентифікаторів: typedef struct identifier_ { char name[50]; int value; } identifier; Структура для опису рядкових даних: typedef struct letters_ { char name[50]; char text[255]; } letters; 3.3. Розробка лексичного аналізатора 3.3.1. Опис програми реалізації лексичного аналізатора Основна задача лексичного аналізу – розбити вихідний текст, що складається з послідовності одиночних символів, на послідовність слів, або лексем, тобто виділити ці слова з безперервної послідовності символів. Всі символи вхідної послідовності з цієї точки зору розділяються на символи, що належать яким-небудь лексемам, і символи, що розділяють лексеми. В цьому випадку використовуються звичайні засоби обробки рядків. Вхiдна програма проглядається послідовно з початку до кінця. Базовi елементи, або лексичнi одиницi, роздiляються пробілами, знаками операцiй i спецiальними символами (новий рядок, знак табуляції), i таким чином видiляються та розпізнаються iдентифiкатори, лiтерали i термiнальнi символи (операцiї, ключові слова). При виділенні лексеми вона розпізнається та записується у таблицю лексем за допомогою відповідного номера лексеми, що є унікальним для кожної лексеми із усього можливого їх набору. Це дає можливість наступним фазам компiляції звертатись лексеми не як до послідовності символів, а як до унікального номера лексеми, що значно спрощує роботу синтаксичного аналізатора: легко перевіряти належність лексеми до відповідної синтаксичної конструкції та є можливість легкого перегляду програми, як вгору, так і вниз, від текучої позиції аналізу. Також в таблиці лексем ведуться записи, щодо рядка відповідної лексеми – для місця помилки – та додаткова інформація. При лексичному аналiзі виявляються i вiдзначаються лексичнi помилки (наприклад, недопустимi символи i неправильнi iдентифiкатори). Лексична фаза вiдкидає також i коментарi, оскiльки вони не мають нiякого впливу на виконання програми, отже ж й на синтаксичний розбір та генерацію коду. Лексичний аналізатор (сканер) не обов’язково обробляє всю програму до початку всіх інших фаз. Якщо лексичний аналіз не виділяється як окрема фаза компіляції, а є частиною синтаксичного аналізу, то лексична обробка тексту програми виконується по мірі необхідності по запиту синтаксичного аналізатора. В даному курсовому проекті реалізовано прямий лексичний аналізатор, який виділяє з вхідного тексту програми окремі лексеми і на основі цього формує таблицю.  Рис. 3.1. Блок-схема роботи лексичного аналізатора 3.4. Розробка синтаксичного та семантичного аналізатора Основне завдання синтаксичного аналізу [1] - розбір структури програми. Як правило, під структурою розуміється дерево, відповідне розбору в контекстно-вільної граматики мови. В даний час найчастіше використовується або LL (1)-аналіз (і його варіант - рекурсивний спуск), або LR (1)-аналіз та його варіанти (LR (0), SLR (1), LALR (1) та інші) . Результатом синтаксичного аналізу є синтаксичне дерево з посиланнями на таблиці об'єктів. У процесі синтаксичного аналізу також виявляються помилки, пов'язані зі структурою програми. В основі синтаксичного аналізатора лежить Розпізнавач тексту вхідної програми на основі граматики вхідного мови. Як правило, синтаксичні конструкції мов програмування можуть бути описані за допомогою КС-граматик, рідше зустрічаються мови, які можуть бути описані за допомогою регулярних граматик. Найчастіше регулярні граматики застосовні до мов асемблера, а мови високого рівня побудовані на основі КС-мов. Розпізнавач дає відповідь на питання про те, належить або немає ланцюжок вхідних символів заданому мови. Однак, як у випадки лексичного аналізатора, завдання синтаксичного розбору не обмежується тільки перевіркою приналежності ланцюжка заданому мови. Синтаксичний аналізатор виконує ще ряд важливих функцій і вже не є різновидом МП-автомата - його функції можна трактувати ширше. Синтаксичний аналізатор повинен мати якусь вихідну у за допомогою якої він передає наступним фаз компіляції всю інформацію про знайдені і розібраних синтаксичних структурах. У такому випадки він вже є перетворювачем з магазинної пам'яттю - МП-перетворювачем. Синтаксичний розбір [1] - це основна частина компіляції на етапі аналізу. Без виконання синтаксичного розбору робота компілятора безглузда, у той час як лексичний аналізатор є зовсім необов'язковим. Усі завдання з перевірки лексики вхідного мови можуть бути вирішені на етапі синтаксичного розбору. Сканер тільки дозволяє позбавити складний за структурою лексичний аналізатор від рішення примітивних завдань з виявлення та запам'ятовування лексем вхідний програми. Виходом лексичного аналізатора є таблиця лексем. Ця таблиця утворює вхід семантичного аналізатора, який досліджує тільки один компонент кожної лексеми - її тип. Інша інформація про лексеми використовується на більш пізніх фазах компіляції при семантичному аналізі, підготовці до генерації та генерації коду результуючої програми. Синтаксичний аналіз - це процес, в якому досліджується таблиця лексем і встановлюється, чи задовольняє вона структурним умовам, явно сформованим у визначенні синтаксису мови. В даній курсовій роботі синтаксичний аналіз можна виконувати лише після виконання лексичного аналізу, він являється окремим етапом трансляції. На вхід даного синтаксичного аналізатора подається файл з лексемами, який був сформований на попередньому етапі трансляції. Крім цього, на базі цього файлу здійснюється формування таблиці ідентифікаторів. В кінці роботи аналізатора у файл виводиться список знайдених помилок, чи генерується повідомлення про їх відсутність. 3.4.1. Розробка дерев граматичного розбору Дерево граматичного розбору є дерево, де • Корінь початку позначається символом G; • Внутрішні вузли є нетерміналом G; • Листки є термінальними символами G; • Дітям вузла T (зліва направо) відповідає символ на правій стороні деякого представлення для T в G. [5] Кожен рядок терміналу, породжений граматикою має відповідне дерево розбору, кожне дерево розбору є рядком породженим граматикою (так званий вихід з дерева розбору). На основі дерева розбору аналізується черговий набір послідовних лексем та викликається відповідна генерація асемблерного коду. Дерево граматичного розбору на основі якого здійснюється перевірка в розробленому компіляторі приведене в додатку Г. 3.4.2. Опис програми реалізації синтаксичного аналізатора В даному курсовому проекті реалізовано синтаксичний аналізатор, який вирисовує метод операторного передування. Він заснований на аналізі пар послідовно розташованих операторів вихідної програми та вирішенні питання про те, який з них повинен виконуватися першим. Розглянемо, наприклад, арифметичне вираження А + В * З - D У відповідності зі звичайними правилами арифметики множення і ділення здійснюються до додавання і віднімання. Можна сказати, що множення і ділення мають більш високий рівень передування, ніж додавання і віднімання. При аналізі перших двох операторів (+ і *) з'ясується, що оператор + має більш низький рівень передування, ніж оператор *. Часто це записують наступним чином + <• * Аналогічно для наступної пари операторів (* і -) оператор * має більш високий рівень передування, ніж оператор -. Ми можемо записати це у вигляді * •> - Метод операторного передування використовує подібні відносини між операторами для управління процесом граматичного розбору. Зокрема, для розглянутого арифметичного виразу ми отримали наступні відносини передування: A + B * C-D <• •> Звідси випливає, що підвираз В * С повинно бути обчислене до обробки будь-яких інших операторів аналізованого виразу. У термінах дерева граматичного розбору це означає, що операція * розташована на більш низькому рівні вузлів дерева, чим операції + або -. Таким чином, розглянутий метод граматичного розбору повинен розпізнати конструкцію В * С, інтерпретуючи її в термінах заданої граматики, до аналізу сусідніх термів пропозиції. У рамках цього методу аналізоване пропозицію сканується зліва направо до тих пір, поки не буде знайдено підвираз, оператори якого мають більш високий рівень передування, ніж сусідні оператори. Далі це підвираз розпізнається в термінах правил виведення використовуваної граматики. Цей процес продовжується до тих пір, поки не буде досягнутий корінь дерева, що і буде означати закінчення процесу граматичного розбору.  Рис.3.2. блок-схема роботи синтаксичного аналізатора. 3.5. Розробка генератора коду Синтаксичне дерево в чистому вигляді несе тільки інформацію про структуру програми. Насправді в процесі генерації коду потрібно також інформація про змінні (наприклад, їх адреси), процедур (також адреси, рівні), мітки і т.д. Для представлення цієї інформації можливі різні рішення. Найбільш поширені два: інформація зберігається у таблицях генератора коду; інформація зберігається у відповідних вершинах дерева. Розглянемо, наприклад, структуру таблиць, які можуть бути використані в поєднанні з Лідер-виставою. Оскільки Лідер-подання не містить інформації про адреси змінних, значить, цю інформацію потрібно формувати в процесі обробки оголошень і зберігати в таблицях. Це стосується і описів масивів, записів і т.д. Крім того, в таблицях також повинна міститися інформація про процедури (адреси, рівні, модулі, в яких процедури описані, і т.д.). При вході в процедуру в таблиці рівнів процедур заводиться новий вхід - покажчик на таблицю описів. При виході покажчик поновлюється на старе значення. Якщо проміжне представлення - дерево, то інформація може зберігатися в вершинах самого дерева. Генерація коду – це машинно-залежний етап компіляції, під час якого відбувається побудова машинного еквівалента вхідної програми. Зазвичай входом для генератора коду служить проміжна форма представлення програми, а на виході може з’являтися об’єктний код або модуль завантаження.[5] Генератор асемблерного коду приймає масив лексем без помилок. Якщо на двох попередніх етапах виявлено помилки, то ця фаза не виконується. В даному курсовому проекті генерація коду реалізується як окремий етап. Можливість його виконання є лише за умови, що попередньо успішно виконався етап синтаксичного аналізу. І використовує результат виконання попереднього аналізу, тобто два файли: в перший в якому міститься з генерований асемблерний код відповідно операторам які були в програмі, другий файл містить таблицю змінних. Інформація з них зчитується в відповідному порядку, основні константні конструкції записуються в файл asm, для цього щоб це робити використовуються константи текстові. 3.5.1. Опис програми реалізації генератора коду У компілятора, реалізованого в даній курсовій роботі, вихідна мова - програма на мові Assembler. Ця програма записується у файл, що має таку ж саму назву, як і файл з вхідним текстом, але розширення “asm”. Генерація коду відбувається одразу ж після синтаксичного аналізу. В даному трансляторі генератор коду послідовно викликає окремі функції, які записують у вихідний файл частини коду. 3.6. Опис реалізації програми Дана програма написана мовою С++ з використанням визначень нових типів, перечислень та класів: #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> #include <ctype.h> #define MAX_TOKENS 1000 #define MAX_IDENT 100 #define MAX_BUF_SIZE 100 #define STACK_SIZE 200 #define MAX_LENGTH_TYPES 20 #define MAX_TEXT_LINE 100 bool isLight; bool ifSave; AnsiString way; AnsiString currFile; AnsiString currWay; AnsiString currName; enum eTypesOfTokens { ltProgram, ltVar, ltType, ltBegin, ltEnd, ltRead, ltWrite, ltFor, ltDownTo, ltNewValue, ltAdd, ltSub, ltMul, ltDiv, ltMod, ltEqu, ltNotEqu, ltLess, ltGreate, ltNot, ltAnd, ltOr, ltEOF, ltEndGroup, ltComma, ltIdentifier, ltNumber, ltLBraket, ltRBraket,ltQuotes, ltLetters, ltUnknown }; typedef struct tokens_ { char name[50]; int value; eTypesOfTokens type; int line; char text[255]; } tokens; typedef struct identifier_ { char name[50]; int value; } identifier; typedef struct letters_ { char name[50]; char text[255]; } letters; typedef struct STACK_ { int st[STACK_SIZE]; int top; } STACK; typedef class cStack { public: STACK S; void init(STACK* stackStack) { stackStack->top = -1; } void push(int i, STACK* stackStack) { if(IsFull(stackStack)) { puts("Error: ""Stack is full)"""); exit(0); } else { ++stackStack->top; stackStack->st[stackStack->top] = i; } } int pop(STACK* stackStack) { int i; if(IsEmpty(stackStack)) { puts("Error: ""Stack is empty)"""); exit(0); } else { i = stackStack->st[stackStack->top]; --stackStack->top; } return i; } bool IsEmpty(STACK* stackStack) { if(stackStack->top == -1) { return true; } else { return false; } } bool IsFull(STACK* stackStack) { if (stackStack->top == 199) { return true; } else { return false; } } void prints(STACK stackStack) { int i=0; for(; i < 10; ++i) { printf("%d_", stackStack.st[i]); } } } cStack; tokens TokensTable[MAX_TOKENS]; int numberTokens; identifier identTable[MAX_IDENT]; int numberOfIdent; letters lettersTable[MAX_TEXT_LINE]; int numberOfLetters,currLet = 0; int bufExprPostfixForm[MAX_BUF_SIZE]; int nNumberErrors; bool IsPresentInput, IsPresentOutput; bool Isletters, isquotes; AnsiString inFileName; AnsiString outFileName; FILE *fin, *fout; cStack stackStack; cStack startBlockStack; cStack cycleStack; В програмі також використовуються багато функцій тому вона є доволі структурованою (граф-схема алгоритму виконання програми розташована в додатку Б). Функції для реалізації лексичного аналізатора: void PrintTokensInFile() – виконує друк таблиці лексем у файл; tokens* GetNextTokens(FILE* f, int ii) – виконує визначення типу лексеми та встановлює її значення; int AnalisisTokens(FILE *fi) – формує таблицю лексем, результатом є кількість знайдених лексем. Функції для реалізації синтаксичного аналізатора: bool IsOperation(eTypesOfTokens t) – перевіряє чи поточна лексема є операцією; int IsExpression(int i, FILE* ef) – перевіряє чи лексема є частиною виразу; int Balans(int nom, eTypesOfTokens ends, eTypesOfTokens ltBegin, eTypesOfTokens ltEnd) – виконує перевірку чи вірна кількість відкриваючих і закриваючих дужок, або чи кожному оператору що відкриває блок є відповідний оператор що закриває цей блок; int ErrorChecking() – дана функція задіює попередні утворючи синтаксичний аналізатор, результатом є файл з помилками та кількість помилок. Функції для реалізації генератора коду: void BeginASMFile() - записує до вихідного файлу стандартну „шапку”; void BeginCodeSegm() - записує до вихідного файлу стандартний початок сегменту коду; void CheckPresentInputOutput() - перевіряє наявність в коді операторів вводу-виводу; void CodeGenerator(FILE*) - за таблицями ідентифікаторів та лексем генерує вихідний код на мові асемблера; int ConvertToPostfixForm(int) - перетворює вирази в постфіксну форму; int FindErrors() - функція пошуку помилок у вхідному файлі. Повертає їх кількість; void GenASMCode(const char *, FILE*) - генерує код для окремих операцій; bool IsElsePresent(int) - перевіряє наявність else у розгалуженні; int IsExpression(int, FILE*) - перевірка, чи є дана послідовність лексем виразом; bool IsOperation(LexemType) - перевірка, чи є дана лексема операцією; void MakeLexOutFile() - видруковує в файл масив лексем; void PrintData(FILE*) - видруковує в вихідний файл сегмент коду, який крім введених змінних за умови присутності операторів вводу/виводу (CheckPresentInputOutput()) і службову інформацію для них та додаткові буфери; void PrintCode(FILE*) - видруковує в вихідний файл основний код програми; void PrintAND(FILE*) - видруковує в вихідний файл процедуру ltAnd; void PrintOR(FILE*) - видруковує в вихідний файл процедуру ltOr; void PrintNOT(FILE*) - видруковує в вихідний файл процедуру ltNot; void PrintEQ(FILE*) - видруковує в вихідний файл процедуру ltEq; void PrintGE(FILE*) - видруковує в вихідний файл процедуру ltGreate; void PrintLE(FILE*) - видруковує в вихідний файл процедуру ltLess; void PrintMOD(FILE*) - видруковує в вихідний файл процедуру ltMod; void PrintEnding(FILE*) - видруковує в вихідний файл стандартне завершення *.asm-файлу; void PrintInput(FILE*) - видруковує в вихідний файл процедуру вводу; void PrintOutput(FILE*) - видруковує в вихідний файл процедуру виводу; bool Prioritet(LexemType,StackType) - перевіряє пріорітет операцій (використовується при перетворенні виразу у посифіксну форму). 4. Опис інтерфейсу та інструкції користувача Розробленний під час виконання даного курсового проекту компілятор є повноцінною Windows програмою яка запускається з будь-якого місця в операційній системі Windows, при наявності в каталозі з програмою деяких бібліотек. Для запуску програми потрібно запустити додаток Compiler.exe, після цього відкриється наступне вікно:  Рис.4.1. Інтерфейс програми- транслятора Робота з компілятором: 1. Щоб відкрити файл
Антиботан аватар за замовчуванням

01.06.2013 19:06-

Коментарі

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

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

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

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

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

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

Admin

26.02.2023 12:38

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