Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
kursova_metodychka(2).doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
1.39 Mб
Скачать

1.3. Інші способи Побудови лексичного аналізатора

1.3.1. Побудова лексичного аналізатора засобами регулярних виразів

Побудова лексичного аналізатора (сканера) засобами регулярних виразів можлива при використанні мов програмування з вбудованою підтримкою регулярних виразів, наприклад, C#, PHP, Python, Java, Perl, тощо. При цьому за допомогою регулярних виразів задають правила виділення лексем і ідентифікаторів з подальшим утворенням таблиці лексем і ідентифікаторів. Наприклад ідентифікатор, який починається з знаку «_» після якого іде буква після якої може зустрічатися або буква або цифра нуль або більше разів можна виділити задавши регулярний вираз: '_[a-zA-Z][a-zA-Z0-9]*'.

1.3.2. Побудова лексичного аналізатора засобами спеціалізованого програмного забезпечення

Побудова лексичного аналізатора (сканера) засобами генераторів лексичних аналізаторів, наприклад, інструменту і мови Lex або Flex відбувається в 3 етапи (рис.1.7).

Рис.1.7. Створення лексичного аналізатора засобами Lex або Flex.

Flex на вході отримує текст у вільному форматі й правила виділення лексем. На виході дає код аналізатора, в вигляді функції на мові C.

Правила задаються в вигляді регулярних виразів ліворуч і, здебільшого, коду на мові C праворуч. Правила містять три секції, відокремлені рядком «%%»:

визначення

%%

правила

%%

код користувача

Визначення містять стартові значення й визначення, правила, безпосередньо самі вирази й дії, що відповідають їм, користувацький код просто включається в вивід flex. Деякі секції можуть бути відсутніми.

Функція аналізатора отримує текст на вході й виконує заданий код для кожної знайденої лексеми. Наприклад, код:

%%

username

printf( "%s", getlogin() );

для кожного входження username в тексті, виконає код printf("%s",getlogin()).

Дана функція виведе в потік рядок, що повертається функцією getlogin(). Тобто, кожне входження username у вхідному потоці буде замінено значенням, поверненим getlogin(). Наприклад, іменем поточного користувача.

Нижче наведено правила, відповідно до яких остаточна функція має друкувати на виході тип лексеми (if, змінна, число, унарна чи бінарна операція) та значення для деяких лексем:

%%

if printf ("IF statement\n");

[a-z]+ printf ("tag, value %s\n", yytext);

{D}+ printf ("decimal number %s\n", yytext);

"++" printf ("unary op\n");

"+" printf ("binary op\n");

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

%{

int num_lines = 0, num_chars = 0;

%}

%%

\n

++num_lines; ++num_chars;

.

++num_chars;

%%

main()

{

yylex();

printf( "# of lines = %d, # of chars = %d\n", num_lines, num_chars );

}

Далі, функцію, створену генератором можна використати з генераторами синтаксичних аналізаторів. Зазвичай flex використовують з yacc чи bison. Синтаксичний аналізатор використовує виклик функції yylex(), створеної генератором flex для пошуку наступної лексеми.

1.3.3. Приклад файлу з правилами виділення лексем для Flex

В даному прикладі розглядається побудова файлу з правилами виділення лексем для flex для імперативної мови програмування PL/0.

Розпізнаються наступні лексеми: '+', '-', '*', '/', '=', '(', ')', ',', ';', '.', ':=', '<', '<=', '<>', '>', '>='; числа: 0-9 {0-9}; ідентифікатори: a-zA-Z {a-zA-Z0-9} та ключові слова: begin, call, const, do, end, if, odd, procedure, then, var, while.

Файл lex.l матиме наступний вигляд:

%{

#include "y.tab.h"

%}

digit [0-9]

letter [a-zA-Z]

%%

"+" { return PLUS; }

"-" { return MINUS; }

"*" { return TIMES; }

"/" { return SLASH; }

"(" { return LPAREN; }

")" { return RPAREN; }

";" { return SEMICOLON; }

"," { return COMMA; }

"." { return PERIOD; }

":=" { return BECOMES; }

"=" { return EQL; }

"<>" { return NEQ; }

"<" { return LSS; }

">" { return GTR; }

"<=" { return LEQ; }

">=" { return GEQ; }

"begin" { return BEGINSYM; }

"call" { return CALLSYM; }

"const" { return CONSTSYM; }

"do" { return DOSYM; }

"end" { return ENDSYM; }

"if" { return IFSYM; }

"odd" { return ODDSYM; }

"procedure" { return PROCSYM; }

"then" { return THENSYM; }

"var" { return VARSYM; }

"while" { return WHILESYM; }

{letter}({letter}|{digit})* {

yylval.id = (char *)strdup(yytext);

return IDENT; }

{digit}+ { yylval.num = atoi(yytext);

return NUMBER; }

[ \t\n\r] /* skip whitespace */

. { printf("Unknown character [%c]\n",yytext[0]);

return UNKNOWN; }

%%

int yywrap(void){return 1;}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]