Створюємо додаток перегляду класів у CBuilder

Призначення додатка перегляду класів полягає в синтаксичному аналізі та відображенні на екрані інформації про класи компонентів C + +, що зберігається в заголовних файлах цих компонентів Ця програма не є ні повноцінним броузером класів (хоча, гарненько вклавшись, можна його довести до подібного рівня), ні ідеальним аналізатором (задавшись метою, його можна наповнити абсолютної нісенітницею), але в більшості випадків воно цілком виконує свою місію Я абсолютно впевнений, що якщо у вас є час і сили, ви зможете перетворити це додаток в повноцінний броузер класів і аналізатор, у мене просто не вистачило сил на це

Рис 171 Форма додатка перегляду класів

На рис 171 показана головна форма програми Вона містить списки, в яких будуть перераховані доступні класи, а також методи і властивості для цих класів Варто відразу ж зазначити, що сам по собі аналізатор не розрізняє подія і властивість, оскільки насправді для системи CBuilder вони одне і те ж Якщо ви хочете знати, що з них є що, то, як правило, можете орієнтувати ся по приставці «On» (при), відсутньої у властивостей і наявної у більшості подій

Для створення цього додатка нам потрібно деяку кількість допоміжного коду – для синтаксичного аналізу та створення списків Якщо це ваш перший досвід роботи з великоваговим кодом на C + + в CBuilder (але, швидше за все, не останній), ви отримаєте гарне уявлення про написання справжнього коду C + + (замість роботи тільки з візуальними (GUI) елементами системи) Памятайте, що CBuilder містить потужний компілятор C + + Використовуйте цей компілятор і всі його можливості

Допоміжний модуль буде першою частиною системи, яку ми втілимо Цей модуль буде надавати допоміжні можливості, які знадобляться нам в системі Як правило, краще розділяти в ваших проектах код GUI (код, що втілює і підтримує візуальні аспекти додатки) і допоміжний код (багаторазово використовувані класи та функції) Ми це зробимо в нашому теперішньому прикладі, виявивши весь код, що не належить до візуальних аспектів роботи, і перенісши його в допоміжний файл

Вибравши File | New Unit, створіть в CBuilder новий модуль Цей модуль містить допоміжні елементи, так що ми назвемо його Utility У створений файл додайте (або скопіюйте з компакт-диска) наступний код Лістинг досить великий, так що краще, можливо, все ж скопіювати його з диска

Ми будемо періодично вставляти в код деякі коментарі, в основному з приводу роботи і використання окремих закінчених функцій

#include &quotUtilityh&quot

//——————————————————————-

#include &ltstdioh&gt

#include &ltstringh&gt

#include &ltstdlibh&gt

#include &ltctypeh&gt

int GetWordQuoted ( char *string, char *word, char *brkChar )

{

/ / Шукаємо початок рядка

int nEndPos = 0

for ( int i=0 i&lt(int)strlen(string) ++i )

if ( isspace(string[i])&amp&amp(string[i] = , &amp&amp string[i] = |) )

{

nEndPos = i break

Створюємо додаток перегляду класів

}

/ / Шукаємо кінець слова

char term_char = 0

if ( string[nEndPos] == &quot’ &amp&amp string[nEndPos-1] = \\ )

{

term_char = &quot’; nEndPos++

}

int nWordPos = 0

for ( int j=nEndPos j&lt(int)strlen(string) ++j )

{

if ( term_char )

{

if ( string[j] == term_char )

{

word[j-nEndPos] = 0 j++

nWordPos = j

break

}

}

else

if (isspace(string[j]) || string[j]==, || string[j] == | )

{

nWordPos = j break

}

word[j-nEndPos] = string[j] nWordPos = j

}

word[nWordPos-nEndPos] = 0 if ( brkChar )

*brkChar = string[nWordPos]

if ( string[nWordPos] == , || string[nWordPos] == | ) nWordPos++

return nWordPos

}

Функція GetWordQuoted повертає окреме «слово» у рядку, де під «словом» розуміється будь-який набір символів (можливо, укладених в лапки), що починається і закінчується допустимим символом-роздільником Ця функ

ція відмінно підходить для виділення і виведення на екран окремих слів з блоку, так що ми будемо її використовувати для перегляду назв класів, властивостей і методів у наших заголовних

файлах

Int IsEndOfLine( char ch )

{

if ( ch == ;’ ) return 1

if ( ch == { ) return 1

if ( ch == } ) return 1

return 0

}

Метод IsEndOfLine призначений для синтаксичного аналізу виразів C + +, він перевіряє, є переданий йому символ кінцем рядка у вираженні C + + чи ні Вирази в C + + можуть закінчуватися крапкою з комою, а також що відкривається або закривається фігурними дужками Тобто, простіше кажучи, цей метод перевіряє свій символ-параметр на збіг з цими трьома символами і дає нам знати про результат порівняння

BOOL CheckClass( char *strLine, char *strClassName )

{

char szWord[ 256 ]

int nPos = GetWordQuoted ( strLine, szWord, NULL ) if ( strcmp(szWord, &quottypedef&quot) ||

!strcmp(szWord, &quotextern&quot) ) return false

if ( strcmp(szWord, &quotclass&quot) &amp&amp strLine[strlen(strLine)-1] = ;’)

{

nPos += GetWordQuoted ( strLine+nPos, szWord, NULL ) if ( strncmp(szWord, &quot__declspec&quot, 10) )

GetWordQuoted ( strLine+nPos, szWord, NULL )

strcpy( strClassName, szWord ) return true

}

return false

}

Функція CheckClass перевіряє, чи є передане їй вираз описом класу Для цього вона витягує перше слово з цього виразу за допомогою функції GetWordQuoted, А потім перевіряє це слово на збіг з описом класу («class») Функція ігнорує форвардні описи класів, приймаючи значення true, тільки у випадку нормальних описів класів

int SkipToEndOfComment(FILE *fp)

{

int c = 0

int last_c = 0 do {

c = fgetc(fp)

if ( c == / &amp&amp last_c == * ) break

if ( c == EOF ) break

last_c = c

} while ( feof(fp) )

/ / Запамятовуємо, що слід за коментарем

if ( feof(fp) )

c = fgetc(fp) return c

}

Метод ScipToEndOfComment переглядає вміст файлу в пошуках кінця коментаря (вкладені коментарі не підтримує) Цей метод повертає символ, наступний безпосередньо за блоком коментаря

BOOL PreScanClasses(char *strFileName, TListBox *pListBox)

{

FILE *fp = fopen(strFileName, &quotr&quot) if ( fp == NULL )

{

return false

}

char szBuffer[ 1024 ] char szClassName[ 256 ] int brace_cnt = 0

while ( feof(fp) )

{

int c = 0 int pos = 0

/ / Очищаємо буфер символів

memset ( szBuffer, 0, 1024 ) int last_c = 0

do {

c = fgetc(fp) if ( c == { ) brace_cnt ++ if ( c == } ) brace_cnt ++

if ( c == # &amp&amp pos == 0 )

break

if ( c == / &amp&amp last_c == / ) break

if ( c == EOF ) break

if ( c == * &amp&amp last_c == / )

{

last_c = 0

pos – / / Відступаємо назад до початку коментаря

c = SkipToEndOfComment(fp)

}

/ / Перевіряємо, чи треба додавати цей символ

if ( c = \n )

if ( pos || isspace(c) ) szBuffer[pos++] = c last_c = c

} while ( IsEndOfLine(c) )

if ( (c == # &amp&amp pos == 0) || (c == / &amp&amp last_c == /) )

{

while ( c = \n &amp&amp feof(fp) ) c = fgetc(fp)

}

else

if ( brace_cnt )

{

if ( CheckClass(szBuffer, szClassName ) ) pListBox-&gtItems-&gtAdd( szClassName )

}

}

fclose(fp)

}

Функція PreScanClasses використовується для вилучення з заголовного файлу імен класів для відображення в початковому списку класів у вікні нашого застосування Вона переглядає заголовки та виділяє вираження C + +, які передає функції CheckClass для перевірки, чи підходять вони до синтаксису опису класів

BOOL ProcessLine( BOOL bDisplay, char *strLine, char *szClassName, TListBox *pPropList,  TListBox *pMethodList )

{

char szWord[ 256 ]

int nPos = GetWordQuoted ( strLine, szWord, NULL ) if ( strcmp(szWord, &quottypedef&quot) ||

!strcmp(szWord, &quotextern&quot) )

return bDisplay

if ( strcmp(szWord, &quotclass&quot) &amp&amp strLine[strlen(strLine)-1] = ;’)

{

nPos += GetWordQuoted ( strLine+nPos, szWord, NULL )

/ / Пропускаємо слово __ declspec

if ( strncmp(szWord, &quot__declspec&quot, 10) )

nPos += GetWordQuoted ( strLine+nPos, szWord, NULL ) if ( strcmp(szWord, szClassName) )

return true else

return false

}

/ / Якщо ми до цих пір не знайшли класу,

/ / Далі можна не ходити if (bDisplay == false) return false

/ / Шукаємо властивості

if ( strcmp(szWord, &quot__property&quot) )

{

char szType[ 256 ]

char szPropName[ 256 ]

nPos += GetWordQuoted ( strLine+nPos, szType, NULL ) nPos += GetWordQuoted ( strLine+nPos, szPropName, NULL )

if ( strcmp(szPropName, &quot*&quot) ||

!strcmp(szPropName, &quot&amp&quot) )

{

strcat( szType, szPropName )

nPos += GetWordQuoted ( strLine+nPos, szPropName, NULL )

}

/ / Успадковані властивості вже мають імя

if ( strlen(szPropName) &amp&amp strcmp(szPropName, "&quot) &amp&amp strcmp(szPropName, &quot=&quot) )

pPropList-&gtItems-&gtAdd(szPropName)

else

pPropList-&gtItems-&gtAdd(szType)

}

else

if ( strstr(strLine, &quot__fastcall&quot) )

{

pMethodList-&gtItems-&gtAdd(strLine)

}

return true

}

Метод ProcessLine – Це допоміжна функція, яка використовується наступною функцією (GetMethodsAndProperties) Для вилучення методів або властивостей, виявлених в заданому виразі C + +

void GetMethodsAndProperties(char *fileName, char *className, TListBox *pPropList, TListBox *pMethodList )

{

FILE *fp = fopen(fileName, &quotr&quot) if ( fp == NULL )

{

return

}

char szBuffer[ 1024 ] int brace_cnt = 0

BOOL bFoundIt = FALSE

while ( feof(fp) )

{

char c = 0 int pos = 0

/ / Очищаємо символьний буфер memset (szBuffer, 0, 1024) char last_c = 0

do {

c = fgetc(fp) if ( c == { ) brace_cnt ++ if ( c == } ) brace_cnt ++

if ( c == # &amp&amp pos == 0 )

break

if ( c == / &amp&amp last_c == / ) break

if ( c == EOF )

break

if ( c == * &amp&amp last_c == / )

{

last_c = 0

pos – / / Відступаємо назад на початок коментаря

c = SkipToEndOfComment(fp)

}

if ( c = \n )

if ( pos || isspace(c) ) szBuffer[pos++] = c

if ( strcmp(szBuffer, &quotpublic:&quot) ||

!strcmp(szBuffer, &quotprivate:&quot) ||

!strcmp(szBuffer, &quotprotected:&quot) )

{

pos = 0

szBuffer[pos] = 0

}

last_c = c

} while ( IsEndOfLine(c) )

if ( (c == # &amp&amp pos == 0) || (c == / &amp&amp last_c == /) )

{

while ( c = \n &amp&amp feof(fp) ) c = fgetc(fp)

}

else

bFoundIt = ProcessLine( bFoundIt, szBuffer, className, pPropList, pMethodList )

}

fclose(fp)

}

Остання в нашому коді функціяGetMethodsAndProperties   використовується для заповнення другого (властивостей) і третього (методів) списку в нашому додатку

Наведені вище методи відповідають за синтаксичнийаналіз рядків і розміщення даних таким

чином, щоб інші допоміжні функції могли з ними працювати

Тепер, коли ми розібралися з допоміжними функціями, прийшов час написати код для самої форми, використовуючи ці чудові функції Перше, що треба зробити, – це додати обробник для команди меню Файл д Відкрити Отже, додайте обробник для цього пункту меню, а в нього впишіть наступні рядки:

void __fastcall TForm1::Open1Click(TObject *Sender)

{

ListBox1-&gtClear()

if ( OpenDialog1-&gtExecute() )

{

FstrFileName = OpenDialog1-&gtFileName PreScanClasses(FstrFileNamec_str(),  ListBox1)

}

}

Цей метод відкриває діалог відкриття файлу, для того щоб користувач міг вибрати заголовний файл для розгляду вмісту Після того як файл вибраний, завантажується перший список (з іменами класів) за допомогою виклику функції PreScanClasses, Яку ми втілили у допоміжному модулі нашого проекту

Вибір наступного пункту меню – Файл д Вихід припиняє роботу нашого застосування Додайте обробник для пункту меню Файл д Вихід і внесіть до нього наступні рядки:

void __fastcall TForm1::Exit1Click(TObject *Sender)

{

Application-&gtTerminate()

}

Останнім кроком процесу розробки форми стане обробка вибору класу в першому списку Коли користувач вибирає небудь клас у списку наявних класів, ми оновлюємо обидва інших списку з тим, щоб в них були відображені властивості і методи обраного класу Додайте обробник для клацання миші в полі першого списку і в нього додайте рядки:

void __fastcall TForm1::ListBox1Click(TObject *Sender)

{

AnsiString s

/ / Отримуємо обраний елемент

for ( int i=0 i&ltListBox1-&gtItems-&gtCount ++i ) if ( ListBox1-&gtSelected[i] )

{

s = ListBox1-&gtItems-&gtStrings[i]

}

/ / Завантажуємо інші списки

ListBox2-&gtClear() ListBox3-&gtClear()

GetMethodsAndProperties(FstrFileNamec_str(),

sc_str(), ListBox3, ListBox2 )

}

Як можна бачити з наведеного коду, більшу частину роботи виконують наші допоміжні функції, які можуть призвести синтаксичний розбір заголовного файлу, завантажити списки і перевірити коректність відображення інформації для користувача Отже, тепер у вас є повністю завершене додаток перегляду класів, яке може використовуватися для відображення всіх класів, а також їх властивостей і методів, що містяться в обраному заголовному файлі На рис 172 показано вікно працюючого програми, в якому відображені класи, знайдені в директорії, в якій знаходиться VCL системи

Джерело: Теллес М – Borland C + + Builder Бібліотека програміста – 1998

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*