На основі поточного стану

Скористаємося можливостями конструкції switch мови програмування С. Як елемент управління скінченого автомата візьмемо поточний стан скінченого автомата ( на початку програми q0=0).

int automat (FILE*fp)

{ int с, q=0; // початковий стан автомата

while((c=fgetch(fp))!=EOF)

{ if (index_litera(c) = = -1) break;

switch(q)

{case 0:

if (c>='1' && c<='9") {q=1; break;}

if (c= =' ' || c= ='\n' || c= ='\t' || c= ='\r') break;

if (c= ='0') { q=6; break;}

// помилка – недопустимий початок лексеми

my_error( ); return 0;

case 1:

if (c>='0' && c<='9') break;

// в заключному стані

return 1;

case 6:

if (c= ='Х' || c= ='x') {q=12; break;}

if (c>='0' && c<='7') {q=7; break;}

// в заключному стані

return 1;

case 12:

if ((c>='0' && c<='9') ||

(c>='A' && c<='F') ||

(c>='a' && c<='f')) {q=13; break;}

// помилка – невірне продовження шістнадцяткової константи

my_error ( ); return 0;

// --------------------------------------------------------------------

// в такому стилі програмуємо далі

// --------------------------------------------------------------------

}// кінець конструкції switch

// перевіримо на заключний стан

if (is_final ( row )) printf (" Лексема вірна - %s", text);

else printf (''Лексема помилкова-%s", text);

}// кінець циклу зчитування літер

}// кінець функції automat

Наведений вище приклад функції automat, в якій в основу управління покладено поточний стан скінченого автомата, спробуємо певною мірою оптимізувати. З тексту модуля видно, що основні операції – це операції порівняння та перевірка належності поточної вхідної літери діапазону літер. При цьому враховується конкретна властивість кодової таблиці ASCI: коди латинських літер та цифр займають певні діапазони. Щоб функція automat не залежала від властивостей кодової таблиці, запропонуємо новий варіант її реалізації.

Розділимо літери кодової таблиці на класи:

- проміжок, \n, \v, \r, \t, \b – літери, які розділяють лексеми;

- 1, 2, 3, ..7 – вісімкові цифри (крім 0);

- 0,...9,A,..F,a,..f — шістнадцяткові цифри;

- 0 – вісімковий або десятковий нуль

- клас, до якого входять літери ASCI: \, .

Як бачимо, в загальному випадку класи можуть перетинатися.

Розглянемо таблицю, об'ємом 256 елементів, в якій буде відмічатися належність літер до окремих класів.

# include <stdio.h>

#define DECIMAL 0x01

#define OCTAL 0x02

#define EMPTY 0x80

#define LITERA 0x04

char decimal[]=’0123456789’;

char hesh_digit[] = ‘0123456789ABCDEFabcdef’;

char octal[] = ‘01234567’;

char empty[] = ‘ \n\r\t\v\r\b’;

char litera[]=

‘ABCDEFGHIJKLMNOPQRSTUVUXYZ_abcdefghijklmnopqrstuvuxyz’

char vector_upr [256];

// початкова ініціалізація

void set_class (char * str, int code)

{ int i, len = strlen(str);

for (i=0; i<len; i + +) vector_upr [(int)*(str+i)] |= code;

}

int automat (FILE * fp)

{ int c, q =0; // початковий стан автомата

while ((c = fgetch(fp))! = EOF)

{ class_litera = vector_upr [(int) ( c )];

if (!class_litera) break; // літера не належить множині sigma

switch (q)

{ case 0: if (class_litera & DECIMAL) { q=1; break;}

if (c == ‘0’) {q=6; break; }

if (class_litera & EMPTY) break;

return ERROR;

// в такому стилі програмуємо далі

… …. … …..

}

} }

main ( ) {

int i;

FILE*fp; char file_name[80];

REPEAT:

printf("Вкажіть ім'я файла з лексеми:");

if(scant("%s", file_name) == 0) return 0; //відмовляється працювати

if( fp = fopen (file_name,"rt") == NULL)

{ printf ("файл %s не відкрито.\ n"); goto REPEAT;}

for (i = 0; i < 256; i++) *(vector_upr + i) = 0;

set_class(decimal, DECIMAL);

set_class(octal, OCTAL); set class(litera, LITERA);

set class(empty, EMPTY);

while (! eof (fp))

if ( automat(fp) == ERROR) printf (" Лексема вірна - %s", text);

else printf (''Лексема помилкова-%s", text);

}// кінець main