Процес створення компілятора вхідної мови
З розмежуванням задач, які повинна виконувати обчислювальна машина, почалось і розмежування програмного забезпечення, не тільки в плані функціоналу виконуваної роботи, а й в плані взаємодії з операційною системою, апаратним забезпеченням, користувачем. А з поділом програм виникла потреба в поділі мов програмування, на яких ці програми можна інтерпретувати — одні середовища розробки зробили ставку… Читати ще >
Процес створення компілятора вхідної мови (реферат, курсова, диплом, контрольна)
Зміст Вступ
1. Завдання на курсову роботу
2. Аналіз вихідного коду та його компіляція
2.1 Синтаксис вхідної програми
2.2 Початок роботи програми. Опрацювання вихідного тексту програми лексичним аналізатором
2.3 Синтаксичний аналіз
2.4 Генерація та оптимізація об'єктного коду
3. Графічний інтерфейс програми Висновки Список використаної літератури Додатки
Вступ
компілятор код файл аналізатор Розвиток комп’ютерних систем в наш час вимагає постійного впровадження технологій, як в апаратному забезпеченні, так і в програмному. Не дивно, що з часів першої написаної програми для машини Бебіджа кількість мов програмування зростає постійно, аджне яка б мова не була універсальна, все одно знайдуться операції, що будуть вимагати розширення її функціоналу, або, в більш радикальних випадках — заміни іншою мовою програмування.
З розмежуванням задач, які повинна виконувати обчислювальна машина, почалось і розмежування програмного забезпечення, не тільки в плані функціоналу виконуваної роботи, а й в плані взаємодії з операційною системою, апаратним забезпеченням, користувачем. А з поділом програм виникла потреба в поділі мов програмування, на яких ці програми можна інтерпретувати — одні середовища розробки зробили ставку на пряму взаємодію з системою, інші - на простоту роботи для звичайного користувача. Зв'язок між мовою, на якій ми думаємо/програмуємо і завданнями та рішеннями, які ми можемо представляти в своїй уяві, дуже близька. З цієї причини обмежувати властивості мови тільки цілями виключення помилок програміста в кращому випадку небезпечно. Як і у випадку з природними мовами, є величезна користь бути, принаймі, двомовним. Мова надає програмісту набір концептуальних інструментів, якщо вони не відповідають завданню, то їх просто ігнорують. Гарне проектування і відсутність помилок може гарантуватися чисто за рахунок мовних засобів.
Компілятор (англ. to compile — збирати в ціле), комп’ютерна програма (або набір програм) що перетворює програмний код, написаний певною мовою програмування, на семантично еквівалентний код в іншій мові програмування, який, як правило, необхідний для виконання програми машиною, наприклад, комп’ютером. Завданням компілятора є повний переклад програми, написаний на одній з мов програмування (вихідній мові) в програму іншої мови програмування, до початку її виконання. Він оцінює її відповідно до синтаксичної конструкції мови та перекладає на машинну мову. Іншими словами, компілятор не виконує програми, він їх будує.
У курсовій роботі використані принципи і технології, що лежать в основі всіх сучасних мов програмування, оскільки всі ці мови побудовані на одному фундаментальному базисі, який складає теорія формальних мов і граматик. На цих принципах і технологіях побудовані всі засоби розробки, які в даний час є не просто трансляторами і компіляторами, а комплексами, що є системами програмування.
Метою даної курсової роботи є вивчення теоретичних основ, на яких базується робота компілятора, а також програмна реалізація алгоритмів кожної стадії компіляції вихідного коду.
Курсова робота полягає в створенні окремих частин компілятора заданої мови, а саме: лексичного аналізатора, синтаксичного аналізатора, оптимізатора та генератора результуючого коду.
Для програмної реалізації завдання курсової роботи використовувалось середовище розробки Borland CodeGear RAD Studio Delphi 2009.
1. Завдання на курсову роботу Побудувати компілятор із заданої підмножини мови Паскаль з незначними модифікаціями і спрощеннями (повний опис вхідної і вихідної мов даний далі в завданні для кожного варіанту).
Компілятор повинен запускатися командним рядком з декількома вхідними параметрами. Першим і головним вхідним параметром має бути ім'я вхідного файлу, другим параметром має бути ім'я результуючого файлу. Вимоги до решти параметрів командного рядка і управляючих ключів (якщо вони необхідні), встановлюються виконавцем самостійно.
Компілятор рекомендується побудувати з наступних складових частин:
лексичний аналізатор;
синтаксичний аналізатор;
оптимізатор;
генератор результуючого коду.
Для побудови компілятора рекомендується використовувати методи, освоєні в ході виконання лабораторних робіт по курсу «Системне програмне забезпечення». Вхідна мова компілятора повинна задовольняти наступним вимогам:
вхідна програма зачинається ключовим словом prog і закінчується ключовим словом end.
вхідна програма може бути розбита на рядки довільним чином, всі пропуски і переходи рядка повинні ігноруватися компілятором;
текст вхідної програми може містити коментарі будь-якої довжини, які повинні ігноруватися компілятором (вид коментаря заданий у варіанті завдання);
вхідна програма має бути єдиним модулем, що містить лінійну послідовність операторів, виклики процедур і функцій не передбачаються;
мають бути передбачені наступні варіанти операторів вхідної програми:
оператор привласнення виду <�змінна>:=^<�вираз>;
умовний оператор вигляду if <�умова> then <�оператор>, або
і/<�умова> then <�оператор> else <�оператор>
складений оператор виду begin. end;
оператор циклу, передбачений варіантом завдання;
вирази в операторах можуть містити наступні операції (мінімум):
арифметичні операції складання (+) і віднімання (-);
операції порівняння менше (<), більше (>), рівно (=);
логічні операції «і» (and), «або» (or), «ні» (not);
додаткові арифметичні операції, передбачені варіантом завдання;
операндами у виразах можуть виступати ідентифікатори (змінні) і константи (тип допустимих констант вказаний у варіанті завдання);
всі ідентифікатори, що зустрічаються в вихіднійпрограмі, повинні сприйматися як змінні, що мають тип, заданого у варіанті завдання (попередній опис ідентифікаторів в вихідній програмі не потрібний);
повинні враховуватися два зумовлені ідентифікатори InpVar і CompileTest. сенс яких буде ясний з опису вихідної мови, що приводиться нижче.
Пріоритет операцій виконавець роботи повинен вибрати самостійно (пріоритет операцій враховується в граматиці вхідної мови). Для зміни пріоритету операцій повинні використовуватися круглі дужки.
Повний опис вхідної мови має бути заданий в граматиці вхідної мови, яка будується виконавцем на першому етапі роботи. Граматика вхідної мови повинна передбачати будь-які вхідні ланцюжки, що задовольняють викладеним вище вимогам. Допускаються будь-які модифікації вхідної мови по вибору виконавця, якщо вони не виходять за рамки вказаних вище вимог. Допускається розширювати набір дозволених операцій і операторів вхідної мови за умови задоволення заданим мінімальним вимогам, але при цьому не дозволяється використовувати операції і операторів з інших варіантів завдання — всі такі оператори обов’язково повинні трактуватися як помилкові.
Компілятор повинен перевіряти наступні семантичні обмеження вхідної мови:
— не допускається присвоєння значень константам;
— не допускається привласнення значення ідентифікатору InpVar;
— не допускається використовувати ідентифікатор CompileTest інакше, як для привласнення йому значень.
Як вихідна (результуюча) мова повинна використовуватися мова асемблера, процесорів типу Intel 80×86 в модифікації вбудованої мови асемблера компілятора Pascal виробництва фірми Borland.
Повинна використовуватись додаткова арифметична операція декрементування, тип циклу: цикл з передумовою, шістнадпяткові константи типу Word, та коментарі типу { .}
2. Аналіз вихідного коду та його компіляція
2.1 Синтаксис вхідної програми Синтаксис — сторона мови програмування, яка описує структуру програм як наборів символів (зазвичай кажуть — безвідносно до змісту). Синтаксису мови протиставляється його семантика. Синтаксис мови описує «чисту» мову, в той же час семантика приписує значення (дії) різним синтаксичним конструкціям.
Кожна мова програмування має синтаксичний опис. Зазвичай синтаксис мови визначають за допомогою правил Бекуса-Наура.
Найчастіше синтаксис перевіряється до компілювання, тобто компілятор не запускається, якщо у вихідному коді, програми були знайдені помилки. У інтерпретуючих мовах програмування перевірка синтаксису проводиться перед кожною інтерпретацією.
Синтаксис вхідної програми дуже схожий на синтаксис мови Pascal, хоча і має деякі відмінності, а саме: для присвоєння значення змінній використовується знак рівності, для логічних операцій AND, OR, XOR і NOT використовуються спеціальні символи — «&», «|», «-» і «!» відповідно, для операції декрементування вирішено використати символ «-» .
Константи оголошуються, як звичайні десяткові числа в діапазоні від 0 до 65 535, а в таблиці ідентифікаторів представляються у вигляді числа, що складається з чотирьох шістнадцяткових цифр.
Кількість змінних і констант може бути обмежена тільки об'ємом оперативної пам’яті комп’ютера.
Окремих блоків для оголошення констант та змінних не передбачено, таблиця ідентифікаторів формується по ходу лексичного аналізу програми.
Кількість вкладених блоків є теоретично необмеженою, на практиці вона обмежується розміром стеку.
В середині блоку можуть знаходитись вирази які містять арифметичні оператори: +, -, оператор декрементування; логічні оператори &, j, !, які означають операції and, or, хог і not відповідно; і на кінець оператори відношення >, <, =.
Умовою курсової роботи передбачена підтримка управляючих структур then або if-then і оператор циклу, з перерахуванням по заданій змінній.
Синтаксис оператора умови наступний:
if () then ;
де — булевий вираз, який в разі істинності призводить до виконання блоку <�Ь1оск>.Конструкція if-then повинна закінчуватись крапкою з комою.
Цикл з передумовою описується наступним чином: while (< condition> ісс begin end;
де — булевий вираз який є умовою виконання циклу, блок операторів або один вираз, який є тілом циклу. Наприклад:
while і<5 do begin а=а" і; і=і+1; end;
Оскільки в програмі умовою не передбачено розпізнавання операцій множення та ділення, то коментарі для оптимізації робот та виключення зайвих переходів при лексичному аналізі будемо вміщувати в структуру { .}
2.2 Початок роботи програми. Опрацювання вихідного тексту програми лексичним аналізатором При запуску програми на компіляцію основний модуль програми вивантажує вихідний код програми в об'єкт ТМето, після чого викликає модуль лексичного аналізатора (LexAuto).
Принцип роботи лексичного аналізатора базується на графі кінцевих станів автомата при по символьному аналізу тексту програми. Лексичний аналізатор передбачає наступні проміжні стани аналізу лексеми:
AP_START — стан початку виразу;
АР _IF1,AP_IF2 — стани посимвольного аналізу ключового слова if;
AP_NOT 1, AP_NOT2, AP_NOT3 — стани посимвольного аналізу ключового слова not;
AP_ELSE1,AP_ELSE2,AP_ELSE3,AP_ELSE4 — стани посимвольного аналізу ключового слова else;
AP_END2,AP_END3 — стани посимвольного аналізу ключового слова end; AP_PROGl, AP_PROG2,AP_PROG3,AP_PROG4 — стани посимвольного аналізу ключового слова prog;
AP_ORl, AP_OR2 — стани посимвольного аналізу ключового слова or; AP_BEGIN1,AP_BEGIN2,AP_BEGIN3,AP_BEGIN4,AP_BEGIN5 — стани посимвольного аналізу ключового слова begin;
AP_XORl, AP_XOR2,AP_XOR3 — стани посимвольного аналізу ключового слова хог;
AP_AND1,AP_AND2,AP_AND3 — стани посимвольного аналізу ключового слова and;
AP_WHILE1, AP_WHILE2, AP_WHILE3, AP_WHILE4, AP_WHILE5 — стани посимвольного аналізу ключового слова while;
AP_COMM, AP_COMMSG — стани розпізнавання початку і кінця коментарів; AP_ASSIGNстан розпізнавання оператора присвоєння;
АР_VAR — стан розпізнавання змінної;
AP_CONST — стан розпізнавання константи;
AP_D01,AP_D02 — стани посимвольного аналізу ключового слова do;
AP_SIGN — стан, що передбачає можливість вживання оператора інкрементування;
AP_LT — стан, що передбачає можливість вживання оператора «не дорівнює» ;
AP_FIN — стан кінця виразу;
AP_ERR — стан помилки.
У разі задоволення умов певного порядку слідування символів, автомат переходить в чітко визначені стани, що дозволяють нам розпізнати лексему (оголошені в модулі LexType).
Приведемо список даних станів:
LEX_PROG — ключове слово prog;
LEX_FIN — ключове слово end.;
LEX_SEMI — символ «;» ;
LEX_IF — ключове слово if;
LEX_OPEN — відкрита дужка;
LEX_CLOSE — закрита дужка;
LEX_ELSE — ключове слово else;
LEX_BEGIN — ключове слово begin;
LEX_END — ключове слово end;
LEX_WHILE — ключове слово while;
LEX_DO — ключове слово do;
LEX_VAR — змінна;
LEX_CONST — константа;
LEX_ASSIGN — присвоєння;
LEX_OR ключове слово or;
LEX_XOR — ключове слово хог;
LEX_AND — ключове слово and;
LEX_LT — «менше» ;
LEX_GT — «більше» ;
LEX_EQ — «рівне» ;
LEX_NEQ — «нерівне» ;
LEX_NOT — ключове слово not;
LEX_SUB — віднімання;
LEX_ADD — додавання;
LEX_UMIN — інкрементування;
LEX_START — початок виразу.
На основі даних станів головна програма починає побудову таблиці ідентифікаторів. Модуль LexElem визначає тип елементів таблиці та робить вивід, що відображається у вигляді простого списку в другій закладці форми основної програми (перед цим попередньо в основному модулі програми всі константи переводяться в формат, визначений варіантом завдання). Після цього на основ хеш-функції, яка визначається результатом додавання ASCII-коду першого середнього символів лексеми, поміщається в таблицю ідентифікаторів те виконує підключений модуль FncTree).
2.3 Синтаксичний аналіз Синтаксичний аналіз здійснюється модулем SyntSymb на основі результатів роботи модуля LexElem, а також виходячи з даних, поданих в модулі SyntRule. До цих даних відносяться правила вихідної граматики та матриця операторного передування, побудована на основі цих правил.
Приведемо дані правила нижче:
S> prog L end.
L>О|L;О|L;
О>if (B)О else О| if (B) О| begin L end| while (B)do О| a:=E
B>B or C|B xor C| C
C>C and D|D
D>EE|E=E|EoE|(B)|not (B)
E>E-T|E+T|T
T> inc T|F
F>(E)|a|c
Після визначення правої та лівої граматик для кожного символу, ми можемо побудувати матрицю операторного передування, яка буде визначати порядок синтаксичних структур.
По заданій матриці модуль SyntSymb проводить синтаксичний розбір з допомогою алгоритму «зсув-згортка». Результат цього розбору формується в бінарне дерево модулем TblElem, що ми можемо бачити на закладці «Синтаксис» основної програми.
2.4 Генерація та оптимізанія об'єктного коду Після виконання синтаксичного розбору програма приступає до генерації коду. Для цього на проміжній стадії краще за все використати внутрішнє представлення команд у вигляді тріад. Структуру побудови тріад описує модуль Triads, а побудову списку проводить модуль TrcMake. Даний модуль на основі результатів роботи модуля TblElem формує самі тріади. Після формування списку тріад модуль TrdType формує їхнє представлення у вікні програми.
Після цього потрібно оптимізувати тріади методом згортки об'єктного коду або видаленням лишніх операцій. Дана робота проводиться в модулі TrdOpt, разом з тим модуль TrdCalc виконує обчислення результату виконання вихідного коду.
Останнім етапом є представлення асемблерного коду програми. Виходячи з результатів виконання побудови списку тріад та оптимізації коду, модуль TrdAsm формує код програми, який представляється в закладці основної форми програми «Команди» .
Під час усіх етапів основною програмою ведеться контроль за наявністю синтаксичних, лексичних, семантичних помилок у вихідному коді. Після завершення роботи всіх модулів, основний модуль перевіряє, чи не повідомив якийсь із них про виникнення помилок в процесі аналізу, генерації та оптимізації коду, і, при коректному виконанні завдання всіма модулями програми, виводить повідомлення «Компіляція виконана успішно» .
3. Графічний інтерфейс програми Рис. 3.1. Графічний інтерфейс програми
Висновки В результаті виконання даної курсової роботи мною було створено компілятор для заданої вхідної мови. Введення коду програми здійснюється завантаженням текстового файлу, при виконанні компілятор будує таблицю ідентифікаторів, робить синтаксичний розбір коду, виконує побудову списку тріад, опгимізує його, та генерує вихідний асемблерний код.
Виконання даної курсової роботи дозволяє студенту набути необхідних знань в теоретичних основах роботи компіляторів, а також удосконалити навики в об'єктно-орієнтованого програмування та роботи в комплексних середовищах розробки прикладних програм на мовах високого рівня.
Список використаної літератури
1. Молчанов А. Ю. Системное программное обеспечение: Учебник для вузов [Текст] /А.Ю. Молчанов. — СПб.: Питер, 2003
2. Компилятор — Википедия [електронний pecypc]/http://ru.wikipedia.org/wiki/ %D0%9A%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D 1%8F%D 1%82%D 0%BE%D 1%80.
3. Конспект лекцій з дисципліни «Системне програмне забезпечення» .
4. Гордеев А. В. Системное программное обеспечение [Текст] /А.В. Гордеев, А. Ю. Молчанов. — СПб.: Питер, 2002
5. Зубков С. В. Ассемблер для DOS, Windows и Unix. — М.: ДМК Пресс, 2000. ;
Додатки Додаток, А Лістинг головної форми програми
using System;
using System.Collections.Generic;
using System. ComponentModel;
using System. Data;
using System. Drawing;
using System. Linq;
using System. Text;
using System.Windows.Forms;
using System. Diagnostics;
using System. Globalization;
using SysBio. dataStructures;
using System. IO;
namespace lab3_Sintax
{
public partial class Form1: Form
{
public Form1()
{
InitializeComponent ();
}
public struct AllWords
{
public string lName;
public int charNumber;
public int rowNumber;
public int charInRowNumber;
}
public AllWords[] Lexems;
//Ключові слова
public string[] KeyWords = {" ціле" ,/*" дробове" ," символ" ," рядок" ,*/
" якщо" ," то" ,/*" інакше" ," для" ,*/" доки" ,
" ПРОГРАМА" ," КІНЕЦЬ" ," закрити" ,
" правдиве" ," хибне" ,
" друк" };
//Оператори та синтаксичні символи
public struct Oper
{
public string name;
public string type;
}
public Oper[] Operators = new Oper[] { new Oper {name = «+», type = «Знак суми» },
new Oper {name = «-», type = «Знак різниці» },
new Oper {name = «*», type = «Знак множення» },
new Oper {name = «/», type = «Знак ділення» },
new Oper {name = «=», type = «Знак присвоєння» },
new Oper {name = «==», type = «Перевірка на рівність» },
new Oper {name = «++», type = «Інкремент» },
new Oper {name = «—», type = «Декремент» },
new Oper {name = «&», type = «Логічне І» },
new Oper ,
new Oper {name = «!», type = «Логічне НЕ» },
new Oper {name = «>», type = «Знак порівняння» },
new Oper {name = «<», type = «Знак порівняння» },
new Oper {name = «(«, type = «Відкриваюча дужка» },
new Oper {name = «)», type = «Закриваюча дужка» },
new Oper {name = «{», type = «Знак відкриття блоку» },
new Oper {name = «}», type = «Знак закриття блоку» },
new Oper {name = «,», type = «Кома (синтаксис)» },
new Oper {name = «;», type = «Знак закінчення рядка» },
//new Oper {name = «[», type = «Відкриваюча кв. дужка» },
//new Oper {name = «]», type = «Закриваюча кв. дужка» },
new Oper {name = «» «, type = «лапка. познач тексту» }
};
//Бінарні дерева:
public TBinarySTree BTKeyWords = new TBinarySTree ();
public TBinarySTree BTOperators = new TBinarySTree ();
public int errorCount = 0; //лічильник помилок
public bool LexAnalizPerformed = false; //Чи був зроблений лексичний аналіз
public bool AnalizPerformed = false; //Чув був проведений повний аналіз
//Формуємо бінарні дерева ідентифікаторів при завантаженні форми:
public void Form1_Load (object sender, EventArgs e)
{
this.KeyPreview = true;
int i;
for (i = 0; i < (KeyWords.Length); i++)
{
BTKeyWords.insert (KeyWords[i], i);
}
for (i = 0; i < (Operators.Length); i++)
{
BTOperators.insert (Operators[i]. name, i);
}
/* Приклад пошуку в дереві:
TTreeNode fs = BTOperators. findSymbol («(»);
MessageBox.Show (fs.name+Operators[(int)fs.value]. type);
*/
/*Викликаємо функцію заповнення матриці передування*/
PriorityMatrixContainer ();
//Заборона редагування вихідног коду:
richTextBox2.ReadOnly = true;
//Додамо вспливаючі підказки:
ToolTip tip1 = new ToolTip ();
tip1.SetToolTip (LoadButton, «Оберіть текстовий файл програмиnАбо надрукуйте його в текстовому полі нижче»);
}
//шлях останнього фалйу
public string lastFilePath="" ;
private void LoadButton_Click (object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog () == DialogResult. OK)
{
lastFilePath = openFileDialog1. FileName;
StreamReader sr = new
StreamReader (lastFilePath, Encoding. GetEncoding (1251));
richTextBox1.Text = sr. ReadToEnd ();
}
}
private void SaveButton_Click (object sender, EventArgs e)
{
if (lastFilePath ≠ «»)
{
File.WriteAllText (lastFilePath, richTextBox1. Text, Encoding. GetEncoding (1251));
}
else
{
MessageBox.Show («Невідомий шлях до файлу. Відкрийте його або скористайтесь кнопкою Зберегти як»);
}
}
private void SaveHowButton_Click (object sender, EventArgs e)
{
if (saveFileDialog1.ShowDialog () == DialogResult. OK)
{
lastFilePath = saveFileDialog1. FileName;
File.WriteAllText (lastFilePath, richTextBox1. Text, Encoding. GetEncoding (1251));
}
}
private void AnalizButton_Click (object sender, EventArgs e)
{
//ЛЕКСИЧНИЙ АНАЛІЗАТОР
string lexa_prog = «» ;
int i = 0, j = 0;
Stopwatch time = new Stopwatch ();
time.Start ();//запуск таймера
//Стираємо попередні записи таблиці, якщо такі були
LexGridView.Rows.Clear ();
dataGridView1.Rows.Clear ();
IdentTable.Rows.Clear ();
errorCount = 0;
//Видаляємо лишні рядки, додаємо текст програми в змінну lexa_prog
foreach (string temp in richTextBox1. Lines)
{
if (temp ≠ «»)
{
lexa_prog += temp + «rn» ;
}
}
//займемся коментарями:
lexa_prog = CommentRemover («/*», «*/», lexa_prog);
//Розділяємо строки, записуємо їх в масив lexa_lines
string[] lexa_lines = lexa_prog.Split (new Char[] { 'r' });
lexa_prog = «» ;
for (i = 0; i < lexa_lines.Length — 1; i++) //отут про цей -1 тре буде ше задуматись. походу останній рядок містить просто r
{
lexa_prog += SpaceCorrector (lexa_lines[i]);
}
//Текст вже відформатований до зручного вигляду і знаходиться в lexa_prog.
int wcount = 0; //рахунок слів
int nlexcount = 0; //рахунок невідомих лексем
int stind = 0, sts=0; //зміщення в тексті при пошуку лексем
int r = 0, s = 0; //Рядок/символ
string tempStringConstant=""; //для збірки докупи строкових констант
/*пояснення до реалізації пошуку строкових змінних:
якщо функція пословного перебору натрапляє на знак лапки, то тимчасова змінна tempStringConstant буде збирати всі лексеми, що знаходяться між ними, аж доки не натрапить на ще одну лапку.
Також вводиться булева величина tsc, яка дорівнює true,
якщо проводиться збір докупи строкової константи. Необхідна для заборони виконання інших перевірок*/
bool tsc = false;
int quotesCount = 0;
//проведемо пословну перевірку
string[] lexa_words = lexa_prog.Split (new Char[] { ' ' });
foreach (string temp in lexa_words)
{
if (temp == «» «) quotesCount++;
if (temp == «» «&& tsc == false && quotesCount%2==1)
{
tsc = true;
}
if (temp ≠ «» && tsc == false)
{
wcount++;
//Записуємо координати лексеми:
r = richTextBox1. GetLineFromCharIndex (richTextBox1.Text.IndexOf (temp, stind));
s = richTextBox1. Lines[r]. IndexOf (temp, sts);
if (richTextBox1.Lines[r]. LastIndexOf (temp) ≠ richTextBox1. Lines[r]. IndexOf (temp)/* && sts ≠ richTextBox1. Lines[r]. LastIndexOf (temp) — просто я не знаю, нашо я це зробив. хай буде*/)
{
sts = richTextBox1. Lines[r]. IndexOf (temp, sts);
}
else
{
sts = 0;
}
r++; //щоб не починався рахунок з нуля
s++; //щоб не починався рахунок з нуля
stind = richTextBox1.Text.IndexOf (temp, stind);
//Перевіряємо належність лексем
//Ключове слово?
TTreeNode word = BTKeyWords. findSymbol (temp);
if (word ≠ null)
{
LexGridView.Rows.Add (wcount.ToString (), temp, «Ключове слово», r. ToString (), s. ToString ());
}
else
{
//Оператор? Я тоже оператор
word = BTOperators. findSymbol (temp);
if (word ≠ null)
{
LexGridView.Rows.Add (wcount.ToString (), temp, Operators[(int)word.value]. type, r. ToString (), s. ToString ());
}
else
{
char[] templet = temp. ToCharArray ();
int numberOfDigits = 0, numberOfLawSymbols = 0;
for (i = 0; i < templet. Length; i++)
templet[i] == '_') numberOfLawSymbols++;
//Константа?
if (temp.Length == numberOfDigits && !temp.Contains ('9') && !temp.Contains ('8'))
{
LexGridView.Rows.Add (wcount.ToString (), temp, «Константа (8-ва)», r. ToString (), s. ToString ());
} //Змінна?
else if ((char.IsLetter (templet[0])) && temp. Length == numberOfLawSymbols)
{
LexGridView.Rows.Add (wcount.ToString (), temp, «Змінна», r. ToString (), s. ToString ());
}//Нічого не підійшло? помилка!
else
{
LexGridView.Rows.Add (wcount.ToString (), temp, «Невідома лексема», r. ToString (), s. ToString ());
nlexcount++; errorCount++;
ErrAdd (errorCount, r, s, temp," «);
}
}
}
stind = richTextBox1.Text.IndexOf (temp, stind);
}
else if (tsc==true) {
tempStringConstant += temp + ««;
if (temp == «» «&& tempStringConstant. Length > 2 && quotesCount % 2 == 0)
{
wcount++;
LexGridView.Rows.Add (wcount.ToString (), tempStringConstant, «Константа (строкова)», r. ToString (), s. ToString ());
tsc = false;
tempStringConstant = «» ;
}
}
}
time.Stop ();
MessageBox.Show («Таблиця лексем побудована за: nr» + time.Elapsed.ToString () + «сnrЗнайдено невідомих лексем: «+ nlexcount. ToString ());
LexAnalizPerformed = true; //Відмітимо, що лекс. аналіз завершено
//СИНТАКСИЧНИЙ АНАЛІЗАТОР
time.Start ();//запуск таймера
int SyntErrCount = 0;
if (LexAnalizPerformed == true)
{
//Формуємо вихідний текст для синтаксичного аналізу:
string SyntText = «S «;
for (i = 0; i < LexGridView. RowCount; i++)
{
switch (LexGridView[" mean", i]. Value. ToString ())
{
default:
case «Ключове слово» :
SyntText += LexGridView[" lex", i]. Value. ToString () + ««;
break;
case «Невідома лексема» :
case «Змінна» :
case «Константа (строкова)» :
case «Константа (8-ва)» :
SyntText += «E «;
break;
case «Знак закінчення рядка» :
try
{
if (LexGridView[" lex", i + 1]. Value. ToString () == «}» || i == LexGridView. RowCount — 2)
{
SyntText += «F «;
}
else
{
SyntText += «F S «; //Розбиваємо на символ початку і кінця рядка
}
}
catch
{
SyntText += «F «;
}
break;
case «Знак відкриття блоку» :
SyntText += «{ S «;
break;
case «Знак закриття блоку» :
if (LexGridView[" lex", i + 1]. Value. ToString () == «}»)
{
SyntText += «} F «;
}
else
{
SyntText += «} F S «;
}
break;
}
}
SyntText = SyntText. Replace («ПРОГРАМА «, «»);
SyntText = SyntText. Replace («КІНЕЦЬ «, «»);
//Згортаємо те, що в лапках (бо це строкова константа)
//Якщо кількість лапок непарна — згортається все після лапки
int firstIndex, secondIndex;
while (SyntText.Contains (««»))
{
firstIndex = SyntText. IndexOf ('" ');
secondIndex = SyntText. IndexOf ('" ', firstIndex + 1);
if (secondIndex < 0)
{
SyntText = SyntText. Remove (firstIndex, SyntText. Length — firstIndex);
break;
}
SyntText = SyntText. Remove (firstIndex, secondIndex — firstIndex + 1);
SyntText = SyntText. Insert (firstIndex, «E»);
}
SyntText.TrimEnd (new Char[] { ' ' });
//згортка умов (Т)
while (SyntText.Contains («E > E») || SyntText. Contains («E < E») || SyntText. Contains («E == E») || SyntText. Contains («(T)»))
{
SyntText = SyntText. Replace («E > E», «T»);
SyntText = SyntText. Replace («E < E», «T»);
SyntText = SyntText. Replace («E == E», «T»);
SyntText = SyntText. Replace («(T)», «T»);
}
//згортка дій № 1 (E математ. опеації)
while (SyntText.Contains («E + E») || SyntText. Contains («E — E») || SyntText. Contains («E * E») || SyntText. Contains («E = E») || SyntText. Contains («E / E») || SyntText. Contains («(E)»))
{
SyntText = SyntText. Replace («E + E», «E»);
SyntText = SyntText. Replace («E — E», «E»);
SyntText = SyntText. Replace («E * E», «E»);
SyntText = SyntText. Replace («E / E», «E»);
SyntText = SyntText. Replace («E = E», «E»);
SyntText = SyntText. Replace («(E)», «E»);
}
//згортка дій № 2 (E)
while (SyntText.Contains («друк E») || SyntText. Contains («ціле E») || SyntText. Contains («S E F») || SyntText. Contains («B B»))
{
SyntText = SyntText. Replace («друк E», «E»);
SyntText = SyntText. Replace («ціле E», «E»);
SyntText = SyntText. Replace («S E F», «B»);
SyntText = SyntText. Replace («B B», «B»);
}
//згортка дій № 3 (B блоки)
while (SyntText.Contains («доки T { B }») || SyntText. Contains («якщо T { B }») || SyntText. Contains («S E F») || SyntText. Contains («B B»))
{
SyntText = SyntText. Replace («доки T { B }», «E»);
SyntText = SyntText. Replace («якщо T { B }», «E»);
SyntText = SyntText. Replace («S E F», «B»);
SyntText = SyntText. Replace («B B», «B»);
}
//ПЕРЕЛІК МОЖЛИВИХ СИНТАКСИЧНИХ ПОМИЛОК:
//" має починатись словом ПРОГРАМА і закінчуватись словом КІНЕЦЬ"
if (richTextBox1.Text.IndexOf («ПРОГРАМА») ≠ 0)
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «1», «»);
}
if (richTextBox1.Text.IndexOf («КІНЕЦЬ») ≠ richTextBox1.Text.Length — 6)
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, richTextBox1.Lines.Length + 1, 0, «1», «»);
}
//Перевіримо на к-ть відкриваючих/закриваючих дужок, лапки перевырялись раніше:
char[] controlCharText = richTextBox1.Text.ToCharArray ();
int openBracketCount = 0, closeBracketCount = 0, openZBracketCount = 0, closeZBracketCount = 0;
for (i = 0; i < controlCharText. Length; i++)
{
switch (controlCharText[i])
{
case '{':
openZBracketCount++;
break;
case '}':
closeZBracketCount++;
break;
case '(':
openBracketCount++;
break;
case ')':
closeBracketCount++;
break;
}
}
if (openBracketCount ≠ closeBracketCount)
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «2», «»);
}
if (openZBracketCount ≠ closeZBracketCount)
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «3», «»);
}
if (quotesCount % 2 == 1)
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «9», «»);
}
//ПОМИЛКИ, пов’язані з результатом згортання:
if (SyntText ≠ «B» && SyntText ≠ «B «&& quotesCount%2==0)
{
if (SyntText == «S» || SyntText == «S «) //синтаксичний аналізатор не сприймає пустого тексту
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «4», «»);
}
else if (SyntText.Contains («E E»))
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «6», «»);
}
else if (SyntText.Contains («+») || SyntText. Contains («= «) || SyntText. Contains («-») || SyntText. Contains («/») || SyntText. Contains («*») || SyntText. Contains («>») || SyntText. Contains («<») || SyntText. Contains («==»))
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «7», «»);
}
else
{
//виключимо згадані вище помилки з неправильною кількістю дужок
if (openZBracketCount == closeZBracketCount || openBracketCount == closeBracketCount)
{
errorCount++;
SyntErrCount++;
ErrAdd (errorCount, 0, 0, «5», «»);
}
}
}
time.Stop ();
if (SyntErrCount ≠ 0)
{
MessageBox.Show («Синтаксичний аналіз проведено за час: «+ time.Elapsed.ToString () + «cnЗнайдено синтаксичних помилок: «+ SyntErrCount. ToString () + «nРезультат згортання синтаксичного аналізатора:n» + SyntText);
}
else
{
MessageBox.Show («Синтаксичних помилок не знайдено! nЧас роботи аналізатора: «+ time.Elapsed.ToString () + «сnРезультат згортки: n» + SyntText);
}
}
else
{
MessageBox.Show («Для роботи Синтаксичного аналізатора необхідно спочатку провести лексичний аналіз»);
}
//СЕМАНТИЧНИЙ АНАЛІЗАТОР:
/*Формуємо список оголошених ідентифікаторів:*/
int DeclaredIdentCount = 0;
for (i = 0; i < LexGridView. RowCount; i++)
{
if (LexGridView[" mean", i]. Value. ToString () == «Змінна»)
{
try //якщо змінна буде першим словом, то попереднє не існуватиме
{
if (LexGridView[" lex", i — 1]. Value. ToString () == «ціле») //сюди піде доповнення, якщо я створю інші типи змінних
{
DeclaredIdentCount++;
IdentTable.Rows.Add (DeclaredIdentCount.ToString (), LexGridView[" lex", i]. Value. ToString (), «ціле», LexGridView[" row", i]. Value. ToString () + «;» + LexGridView[" sym", i]. Value. ToString ());
}
}
catch { }
}
}
//тепер знаходимо змінні, що не були оголошені. якщо такі є, то це семантична помилка
bool IdFinded = false;
for (i = 0; i < LexGridView. RowCount; i++)
{
if (LexGridView[" mean", i]. Value. ToString ()=="Змінна") {
for (j = 0; j < DeclaredIdentCount; j++)
{
if (LexGridView[" lex", i]. Value. ToString ()==IdentTable[1,j].Value.ToString ())
{
IdFinded = true; //такий ідентифікатор був оголошений
}
}
//якщо ж ідентифікатор є, але його забули оголосити, видаєм помилку:
if (IdFinded == false)
{
errorCount++;
ErrAdd (errorCount, Convert. ToInt32(LexGridView[" row", i]. Value. ToString ()), Convert. ToInt32(LexGridView[" sym", i]. Value. ToString ()), «8″, LexGridView[» lex", i]. Value. ToString ());
}
IdFinded = false; //повертаємо у вихідне значення для нової ітерації
}
}
AnalizPerformed = true;
}
//Додавання помилок:
public void ErrAdd (int erident, int RowNumber, int SymbolInRowNumber, string erDescr, string ErrorLex)
{
switch (erDescr) {
case «1» :
dataGridView1.Rows.Add (erident.ToString (), «Відсутні границі програми (ПОЧАТОК або КІНЕЦЬ)», RowNumber. ToString (), SymbolInRowNumber. ToString ());
break;
case «2» :
dataGridView1.Rows.Add (erident.ToString (), «Неоднакова кількість відкриваючих і закриваючих дужок», «-», «-»);
break;
case «3» :
dataGridView1.Rows.Add (erident.ToString (), «Неоднакова кількість відкриваючих і закриваючих фігурних дужок», «-», «-»);
break;
case «4» :
dataGridView1.Rows.Add (erident.ToString (), «Відсутнє тіло програми», «-», «-»);
break;
case «5» :
dataGridView1.Rows.Add (erident.ToString (), «Невизначена синтаксична помилка», «-», «-»);
break;
case «6» :
dataGridView1.Rows.Add (erident.ToString (), «Випущений символ закінчення рядка», «-», «-»);
break;
case «7» :
dataGridView1.Rows.Add (erident.ToString (), «Відсутній якийсь з операндів», «-», «-»);
break;
case «8» :
dataGridView1.Rows.Add (erident.ToString (), «Неоголошена змінна «+ErrorLex, RowNumber. ToString (), SymbolInRowNumber. ToString ());
break;
case «9» :
dataGridView1.Rows.Add (erident.ToString (), «Непарна кількість лапок. Помилка критична «+ ErrorLex, RowNumber. ToString (), SymbolInRowNumber. ToString ());
break;
default:
dataGridView1.Rows.Add (erident.ToString (), «Невідома лексема «+ erDescr, RowNumber. ToString (), SymbolInRowNumber. ToString ());
break;
}
}
//Функція видалення лишніх пробілів та розмежування операторів
public string SpaceCorrector (string textline)
{
int i;
//розділення деяких операторів (для зручнішого зчитування)
//Індуський код, але простіший для розуміння. Якщо додавати пробіли тільки для операторів, які його
//не мають, то прийдеться розбивати кожного разу string на масив char. Складніше і довше для
//виконання процесором, але зручніше для використання в C#
for (i = 0; i < Operators. Length; i++)
{
if (textline.Contains (Operators[i]. name+Operators[i].name)){
if (Operators[i]. name=="+" ||Operators[i].name=="-" ||Operators[i].name=="="||Operators[i].name=="|"){
textline = textline. Replace (Operators[i]. name + Operators[i]. name, («» + Operators[i]. name + Operators[i]. name + ««));
} else {
textline = textline. Replace (Operators[i]. name, («» + Operators[i]. name + ««));
}
}
else {
textline = textline. Replace (Operators[i]. name, («» + Operators[i]. name + ««));
}
}
//Видалення повторень пробілів на початку та в кінці рядка
textline = textline. Trim (new Char[] { ' ', 't', 'r', 'n' });
//видалення табуляції (якщо випадково попала в середину рядка)
while (textline.Contains («t»))
{
textline = textline. Replace («t», ««);
}
//видалення повторення пробілів в середині рядка
while (textline.Contains (««))
{
textline = textline. Replace (««, ««);
}
textline = textline + ««;
return textline;
}
//видалення коментарів:
public string CommentRemover (string CommentOpen, string CommentClose, string textmas){
int op=0, cl=0;
while (textmas.Contains (CommentOpen))
{
op = textmas. IndexOf (CommentOpen, op);
cl = textmas. IndexOf (CommentClose, op);
textmas = textmas. Remove (op, cl — op + 2);
}
return textmas;
}
//Деякі функції для полегшення роботи з текстовим редактором:
private void ClearButton_Click (object sender, EventArgs e)
{
errorCount = 0;
richTextBox1.Text = «» ;
richTextBox2.Text = «» ;
lastFilePath = «» ;
dataGridView1.Rows.Clear ();
LexGridView.Rows.Clear ();
LexAnalizPerformed = false;
AnalizPerformed = false;
IdentTable.Rows.Clear ();
}
private void Form1_KeyDown1(object sender, KeyEventArgs e)
{
char[] tmp;
int i, pos;
if (e.Control)
{
switch (e.KeyCode)
{
//Виділяти все при натисненні CNTRL+A
case Keys. A:
richTextBox1.SelectAll ();
break;
//Зберегти текст по CNTRL+S
case Keys. S:
SaveButton.PerformClick ();
break;
//Відкрити файл по CNTRL+O
case Keys. O:
LoadButton.PerformClick (); ;
break;
//Вставляти символи > < за кнтрл+ю і кнтрл+Б
case Keys. OemPeriod:
tmp = richTextBox1.Text.ToCharArray ();
Array.Resize (ref tmp, tmp. Length + 1);
pos = richTextBox1. SelectionStart;
for (i = richTextBox1.Text.Length; i > pos; i—) tmp[i] = tmp[i — 1];
tmp[pos] = '>';
richTextBox1.Text = new string (tmp);
richTextBox1.SelectionStart = pos + 1;
break;
case Keys. Oemcomma:
tmp = richTextBox1.Text.ToCharArray ();
Array.Resize (ref tmp, tmp. Length + 1);
pos = richTextBox1. SelectionStart;
for (i = richTextBox1.Text.Length; i > pos; i—) tmp[i] = tmp[i — 1];
tmp[pos] = '<';
richTextBox1.Text = new string (tmp);
richTextBox1.SelectionStart = pos + 1;
break;
//Символи [ i ] будуть вставлятись за комбінацією кнтрл+х і кнтрл+ї
//Якщо буде зажатий шифт, то дужки будуть фігурні
case Keys. OemOpenBrackets:
tmp = richTextBox1.Text.ToCharArray ();
Array.Resize (ref tmp, tmp. Length + 1);
pos = richTextBox1. SelectionStart;
for (i = richTextBox1.Text.Length; i > pos; i—) tmp[i] = tmp[i — 1];
if (e.Shift) tmp[pos] = '{'; else tmp[pos] = '[';
richTextBox1.Text = new string (tmp);
richTextBox1.SelectionStart = pos + 1;
break;
case Keys. OemCloseBrackets:
tmp = richTextBox1.Text.ToCharArray ();
Array.Resize (ref tmp, tmp. Length + 1);
pos = richTextBox1. SelectionStart;
for (i = richTextBox1.Text.Length; i > pos; i—) tmp[i] = tmp[i — 1];
if (e.Shift) tmp[pos] = '}'; else tmp[pos] = ']';
richTextBox1.Text = new string (tmp);
richTextBox1.SelectionStart = pos + 1;
break;
//символ |
case Keys. OemPipe:
tmp = richTextBox1.Text.ToCharArray ();
Array.Resize (ref tmp, tmp. Length + 1);
pos = richTextBox1. SelectionStart;
for (i = richTextBox1.Text.Length; i > pos; i—) tmp[i] = tmp[i — 1];
tmp[pos] = '|';
richTextBox1.Text = new string (tmp);
richTextBox1.SelectionStart = pos + 1;
break;
}
}
}
//Інформація про компілятор
private void HelpinfButton_Click (object sender, EventArgs e)
{
MessageBox.Show («Швидкі клавіші:ncntrl+a — виділити всеncntrl+s — зберегти в поточному файлі;ncntrl+o — відкрити файл;ncntrl+[(shift)+(х,ї, б, ю)] - вставляє необхідний символ без переключення розкладки. nnОпис мови: сі-подібна з використанням кирилиці. Підтримує ключові слова: друк, ціле, програма, кінець. Оператор умови — якщо. Оператор циклу — доки. Арифметичні операції - +,-,*,/,інкремент, декремент. Логічні функції - І, НЕ, АБО, перевірку на рівність;nnКоментарі до роботи лексичного аналізатора:nnКоментарі до роботи синтаксичного аналізатора:nПри виникненні помилок на попередньому кроці - вони обробляються як змінні/константи/n/nДля генерування коду необхідно провести спочатку аналіз коду на наявність помилок»);
}
//заповнення матриці передування:
public void PriorityMatrixContainer ()
{
PriorityMatrixGrid.Columns.Add («cS» ," S (с.початку)");
PriorityMatrixGrid.Columns.Add («cF», «F (с.кінця)»);
PriorityMatrixGrid.Columns.Add («cE», «E (змін/конст/дія)»);
PriorityMatrixGrid.Columns.Add («cT», «T (умова)»);
PriorityMatrixGrid.Columns.Add («cB», «B (блок)»);
PriorityMatrixGrid.Columns.Add («cIF», «якщо»);
PriorityMatrixGrid.Columns.Add («cWHILE», «доки»);
PriorityMatrixGrid.Columns.Add («cO», «O (±*/)»);
PriorityMatrixGrid.Columns.Add («cOp», «Op (><==)»);
PriorityMatrixGrid.Columns.Add («c (», «(«);
PriorityMatrixGrid.Columns.Add («c)», «)»);
int i=0;
for (i = 0; i < 5; i++) PriorityMatrixGrid. Columns[i]. Width = 60;
for (i = 5; i < 9; i++) PriorityMatrixGrid. Columns[i]. Width = 40;
for (i = 9; i < 11; i++) PriorityMatrixGrid. Columns[i]. Width = 20;
PriorityMatrixGrid.Rows.Add (11);
PriorityMatrixGrid.Rows[0]. HeaderCell. Value = «S» ;
PriorityMatrixGrid.Rows[1]. HeaderCell. Value = «F» ;
PriorityMatrixGrid.Rows[2]. HeaderCell. Value = «E» ;
PriorityMatrixGrid.Rows[3]. HeaderCell. Value = «T» ;
PriorityMatrixGrid.Rows[4]. HeaderCell. Value = «B» ;
PriorityMatrixGrid.Rows[5]. HeaderCell. Value = «якщо» ;
PriorityMatrixGrid.Rows[6]. HeaderCell. Value = «доки» ;
PriorityMatrixGrid.Rows[7]. HeaderCell. Value = «O» ;
PriorityMatrixGrid.Rows[8]. HeaderCell. Value = «Op» ;
PriorityMatrixGrid.Rows[9]. HeaderCell. Value = «(«;
PriorityMatrixGrid.Rows[10]. HeaderCell. Value = «)» ;
}
//Вивід положення курсору в тексті
private void richTextBox1_SelectionChanged (object sender, EventArgs e)
{
int l, s;
l = richTextBox1. GetLineFromCharIndex (richTextBox1.SelectionStart);
Point pt = richTextBox1. GetPositionFromCharIndex (richTextBox1.SelectionStart);
pt.X = 0;
s = richTextBox1. SelectionStart — richTextBox1. GetCharIndexFromPosition (pt);
textCursorLine.Text = (l+1).ToString ();
textCursorSymbol.Text = (s+1).ToString ();
}
//Заборона або дозвіл редагування асемблерного коду
private void checkBox2_CheckedChanged (object sender, EventArgs e)
{
if (checkBox2.Checked)
{
richTextBox2.ReadOnly = false;
}
else
{
richTextBox2.ReadOnly = true;
}
}
//==ГЕНЕРАЦІЯ КОДУ:==
private void GenButton_Click (object sender, EventArgs e)
{
string TempGen; //різноробоча тимчасова строкова змінна
int i, j;
int StrConstCount = 0, VarCount = 0; //Лічильники змінних та строкових констант
if (errorCount == 0 && AnalizPerformed == true)
{
//Додаємо обрамлення асемблерного коду:
richTextBox2.Text = «;==ПАРАМЕТРИ COM-ФАЙЛУ==n.model tinyn. codenorg 100hn.386n;==КОД ОСНОВНОЇ ЧАСТИНИ ПРОГРАМИ==nmain:» ;
richTextBox2.Text += «t;—Ініціалізація ES та DS, обнулення edx—ntmov ax, csntmov ds, axntmov es, axntxor edx, edxn» ;
richTextBox2.Text += «t;—Встановлення відеорежиму:ntmov ah, 00hntmov al, 02h ;80×25 чорнобілий текстовий режимntint 10hn» ;
richTextBox2.Text += «t;—Ставимо курсор в початок координат:—ntmov ah, 02ntmov bh, 00 ;сторінка відеопам'ятіntmov dh, 0 ;строкаntmov dl, 0 ;стовпчикntint 10hn» ;
//=Розклад коду за результатом аналізу=
//Додамо закінчення для головної програми та
//блок процедур
richTextBox2.Text += «nret n;==КІНЕЦЬ ГОЛОВНОЇ ПРОГРАМИ== n n;==ПОЧАТОК БЛОКУ ПРОЦЕДУР== n;—Функція виведення на екран строки (Використовувати LEA EDX,ім'яізмінної перед викликом): — nPSB proc ;Print String in Bios int ntxor ecx, ecx nt;—Підрахунок кількості символів:—t npks: t ntmov al,[EDX+ECX] ntcmp al,» $" ntje pksg ntinc cx ntmov i, cx ntjmp pks npksg: ntxor esi, esi npsbd1: nt;—Друк символу: — ntmov ah, 0Eh ntmov al,[EDX+ESI] ;ASCII-код символу ntmov bh, 00t;сторінка відеопам'яті ntmov cx, 01h ntint 10h nt;—команди циклу: — ntinc si ntcmp si, i ntje psbd2 ntjmp psbd1 npsbd2: ntret nPSB endp n" ;
richTextBox2.Text += «n;—Процедура переведення курсору на новий рядок: — nENT proc ntmov ah, 03h ntmov bh, 00h ntint 10h ntmov ah, 02h ntmov bh, 00h ntinc dh ntmov dl, 00h ntint 10h ntret nENT endp n n;—Ф-я виведення слова в шістнадцятковій системі (необх. слово заносимо в wpt перед використанням): — nWORDPRINT proc ntpusha ntmov cx, 16d ntl1: nttsub cx, 4h nttmov ax, wpt nttshr ax, cl nttand ax, 0fh ;маскою виділяємо молодший розряд nttcmp al, 9h nttjbe pc ;cifra nttcmp al, 0Fh nttjbe pb ;bukva ntpc: nttadd al, 30h nttjmp prnt ntpb: nttadd al, 37h nttjmp prnt ntprnt: nttmov asciitemp, al nttcall PSymB ntjcxz l2 ntjmp l1 ntl2: nttpopa nttret nWORDPRINT endp n» ;
richTextBox2.Text += «n;—Функція виведення на екран символу (символ в asciitemp): — nPSymB proc ntpusha nt;—Друк Символа власною персоною: — ntmov ah, 0Eh ntmov al, asciitemp ntmov bh, 00h ntmov cx, 01h ntint 10h ntpopa ntret nPSymB endp n n;—Виведення одного біту слова: (вик-є wpt — слово та n — номер біту) — nPBB proc ntmov ax, wpt ntmov bx, 01h ntmov cl, n ntshl bx, cl ;Підготовка маски ntand ax, bxt;Накладання маски ntmov al, 30h ;Код нуля ntjz endpbb ntmov al, 31h ;Код одиниці nendpbb: nt;—Друк: — ntmov ah, 0Eh ntmov bh, 00h ntmov cx, 01h ntint 10h ntret nPBB endp n;==КIНЕЦЬ БЛОКУ ПРОЦЕДУР==n» ;
//БЛОК ОГОЛОШЕННЯ ЗМІННИХ
richTextBox2.Text += «nn;==ПОЧАТОК БЛОКУ ОГОЛОШЕННЯ ЗМІННИХ== n;змінні процедур: ni dw? nn db? nwpt dw? ;wordprint temp nasciitemp db? n;змінні тіла програми:» ;
//додаємо строкові константи та змінні, знайдені в коді:
for (i = 0; i < LexGridView. RowCount; i++)
{
if (LexGridView[" mean", i]. Value. ToString () == «Константа (строкова)»)
{
TempGen = LexGridView[" lex", i]. Value. ToString ().Trim (new Char[] { ' ','" ' });
richTextBox2.Text += «nStrConst» +StrConstCount+" db «» + TempGen + «», «$» «;
StrConstCount++;
}
}
for (i=0;i
richTextBox2.Text += «nVariable» + VarCount. ToString () + «dw?; «+ IdentTable[1, i]. Value. ToString ();
VarCount++;
}
//Закінчуємо блок змінних та програму:
richTextBox2.Text += «n;==КIНЕЦЬ БЛОКУ ОГОЛОШЕННЯ ЗМIННИХ== nend main» ;
MessageBox.Show («Код згенерований успішно! Перейдіть на іншу вкладку для його перегляду чи збереження»);
GenSyn ();
}
else if (AnalizPerformed == false)
{
MessageBox.Show («Генерація коду не можлива без проведення аналізу»);
} else {
MessageBox.Show («Виправте виявлені помилки»);
}
}
//Кнопка збереження згенерованого коду
private void SaveAsButton1_Click1(object sender, EventArgs e)
{
if (saveFileDialog1.ShowDialog () == DialogResult. OK)
{
File.WriteAllText (saveFileDialog1.FileName, richTextBox2. Text, Encoding. GetEncoding (1251));
}
}
//Формуємо текст для обробки генератором:
public string generatext="" ;
public void GenSyn ()
{
int i;
for (i = 0; i < LexGridView. RowCount; i++)
{
switch (LexGridView[" mean", i]. Value. ToString ()) {
default:
case «Ключове слово» :
if (LexGridView[" lex", i]. Value. ToString () ≠ «ПРОГРАМА» && LexGridView[" lex", i]. Value. ToString () ≠ «КІНЕЦЬ») generatext += LexGridView[" lex", i]. Value. ToString () + ««;
break;
case «Змінна» :
generatext += «V «;
break;
case «Константа (строкова)» :
generatext += «S «;
break;
case «Константа (8-ва)» :
generatext += «C «;
break;
case «Знак відкриття блоку» :
generatext += «{ «;
break;
case «Знак закриття блоку» :
generatext += «} «;
break;
}
}
generatext = generatext. Trim ();
string[] gtlines = generatext. Split (new Char[] { ';' });
generatext = «» ;
for (i = 0; i < gtlines. Length; i++)
{
gtlines[i]. Trim ();
if (!gtlines[i]. Contains («ціле»)) generatext += gtlines[i];
}
MessageBox.Show (generatext);
}
}
}
Додаток Б Лістинг класу BinaryTree. cs, що реалізує побудову та пошук в таблицях ідентифікаторів за методом бінарного дерева
using System;
using System. Collections;
namespace SysBio. dataStructures
{
// Оголошення гілок дерева
public class TTreeNode
{
public string name;
public double value;
public TTreeNode left, right;
// Конструктор створення одинарної гілки
public TTreeNode (string name, double d)
{
this.name = name;
value = d;
left = null;
right = null;
}
}
// Бінарне дерево власною персоною
public class TBinarySTree
{
// Доступні методи:
// count ()
// clear ()
// insert ()
// delete ()
// findSymbol ()
private TTreeNode root; // Вказує на корінь дерева
private int _count = 0;
public TBinarySTree ()
{
root = null;
_count = 0;
}
// Знищення бінарного дерева або під-дерева
private void killTree (ref TTreeNode p)
{
if (p ≠ null)
{
killTree (ref p. left);
killTree (ref p. right);
p = null;
}
}
/// Очищення елементів дерева.
public void clear ()
{
killTree (ref root);
_count = 0;
}
/// Повертає кількість гілок в дереві
/// Кількість гілок бінарного дерева
public int count ()
{
return _count;
}
/// Знаходить ім'я в дереві. Повертає звернення
/// якщо символ знайдений або null при виникненні помилки.
/// Ім'я гілки, яку потрібно знайти
/// Повертає null якщо не було знайдено такої гілки, в іншому випадку повертає посилання на гілку
public TTreeNode findSymbol (string name)
{
TTreeNode np = root;
int cmp;
while (np ≠ null)
{
cmp = String. Compare (name, np.name);
if (cmp == 0) // знайшовся !
return np;
if (cmp < 0)
np = np. left;
else
np = np. right;
}
return null; // Повертаю null щоб ідентифікувати помилку
}
// Знаходить пустий слот в дереві і додає в потрібне місце нову гілку
private void add (TTreeNode node, ref TTreeNode tree)
{
if (tree == null)
tree = node;
else
{
// Якщо знайдено гілку з таким ж ім'ям
// тоді це копія і ми не можемо продовжувати
int comparison = String. Compare (node.name, tree.name);
if (comparison == 0)
throw new Exception ();
if (comparison < 0)
{
add (node, ref tree. left);
}
else
{
add (node, ref tree. right);
}
}
}
/// Додає елемент до дерева якщо він новий та повертає звернення до нього
/// В іншому випадку повертає нуль, що означає присутність такого ж елементу в дереві
/// Ім'я вузла
/// Значення вузла
/// Повертає посилання на вузол, якщо він був вдало доданий.
/// Якщо такий вже був у наявності, то повертає null
public TTreeNode insert (string name, double d)
{
TTreeNode node = new TTreeNode (name, d);
try
{
if (root == null)
root = node;
else
add (node, ref root);
_count++;
return node;
}
catch (Exception)
{
return null;
}
}
// Пошук вузла за ім'ям. Якщо вузол знайдено — повертає посилання на останній вузол
// та його попередників. В іншому випадку повертає null.
private TTreeNode findParent (string name, ref TTreeNode parent)
{
TTreeNode np = root;
parent = null;
int cmp;
while (np ≠ null)
{
cmp = String. Compare (name, np.name);
if (cmp == 0) // знайшов !
return np;
if (cmp < 0)
{
parent = np;
np = np. left;
}
else
{
parent = np;
np = np. right;
}
}
return null; // Повертає null щоб виявити помилку
}
/// Знаходження наступників вузла
/// Ключ-ім'я для пошуку
/// Повертає ім'я попередника якщо пошук вдалий
/// Повертає посилання на вузол, якщо такий знайдено
public TTreeNode findSuccessor (TTreeNode startNode, ref TTreeNode parent)
{
parent = startNode;
startNode = startNode. right;
while (startNode.left ≠ null)
{
parent = startNode;
startNode = startNode. left;
}
return startNode;
}
/// Видалення вузла.
/// Ім'я вузла, що видаляється
public void delete (string key)
{
TTreeNode parent = null;
// Спочатку знайдемо сам вузол, аби виділити його попередників
TTreeNode nodeToDelete = findParent (key, ref parent);
if (nodeToDelete == null)
throw new Exception («Unable to delete node: «+ key. ToString ()); // неможливо знайти вузол
// Якщо це кінцева гілка, то просто анулюємо посилання попередника
if ((nodeToDelete.left == null) && (nodeToDelete.right == null))
{
if (parent == null)
{
root = null;
return;
}
// шукаємо, якщо ліва чи права гілка пов’язані з іншими
// попередниками і належним вситавляємо null
if (parent.left == nodeToDelete)
parent.left = null;
else
parent.right = null;
_count—;
return;
}
// Одне із посилань вузла null, тоді
// видаляємо вузол і виставляємо ненульове посилання на його місце
if (nodeToDelete.left == null)