// ANALIZATOR LEKSYKALNY
//
// Wczytuje ze standardowego wejscia ciag znakow.
// Drukuje na standardowe wyjscie podzial tego ciagu na leksemy.
#include<stdio.h>
#include<stdlib.h>
#define max_dl_leksemu 100
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
typedef enum { STAN_POCZ = 0,
STAN_A = 1,
STAN_K = 2,
STAN_AD = 3,
STAN_AS = 4,
STAN_KA = 5,
STAN_ADA = 6,
STAN_ASI = 7,
STAN_KAM = 8,
STAN_KAMI = 9,
STAN_KAMIL = 10,
STAN_KAMILA = 11,
STAN_ADAM = 12,
STAN_ASIA = 13,
STAN_NIEOKR = 14 } Stany;
typedef enum { ZNAK_A = 0,
ZNAK_D = 1,
ZNAK_M = 2,
ZNAK_S = 3,
ZNAK_I = 4,
ZNAK_K = 5,
ZNAK_L = 6,
ZNAK_NIEOKR = 10 } Znaki;
// MEZCZYZNA i KOBIETA
typedef enum { MEZCZYZNA = 0,
KOBIETA = 1 } Jednostki;
struct leksem
{
Jednostki jed; // rodzaj leksemu
int dlug; // dlugosc leksemu ( 1 <= dlug <= max_dl_leksemu )
char zaw[max_dl_leksemu]; // chary skladajace sie na leksem
};
void blad (char s[], char ch)
// sygnalizacja bledu; drukuje napis s i char ch
// a nastepnie sie zatrzymuje
{
printf ("!!! %s '%c' !!!\n\n", s, ch);
exit(1);
}
Znaki kategoria (char ch)
// ta funkcja grupuje chary z wejscia w elementy typu Znaki ;
// to znaczy zapomina o roznicy miedzy literami malymi i duzymi,
// wszystkim cyfrom przypisuje ZNAK_CYF ,
// nielegalnym znakom przypisuje ZNAK_NIEOKR
{
if (ch == 'a' || ch == 'A') return ZNAK_A; else
if (ch == 'd' || ch == 'D') return ZNAK_D; else
if (ch == 'm' || ch == 'M') return ZNAK_M; else
if (ch == 's' || ch == 'S') return ZNAK_S; else
if (ch == 'i' || ch == 'I') return ZNAK_I; else
if (ch == 'k' || ch == 'K') return ZNAK_K; else
if (ch == 'l' || ch == 'L') return ZNAK_L;
else return ZNAK_NIEOKR;
}
// poprawic na ilosci tabelki
Stany tab_symb[12][8];
// -- tabela symboli czyli zakodowany automat; indeksowana stanami
// od STAN_POCZ do STAN_SEPAR oraz znakami od ZNAK_B do ZNAK_NIEOKR
char wejscie;
// char przeczytany na zapas z wejscia
void leks (struct leksem* lk)
// zasadnicza funkcja programu;
// jej wywolanie powoduje wczytanie odpowiedniej liczby charow z
// wejscia i zlozenie z nich leksemu (lub sygnalizacja bledu);
// zakladamy, ze w momencie wywolania w zmiennej globalnej wejscie
// jest juz wczytany jeden char z wejscia;
// po zakonczeniu dzialania tej funkcji w tej zmiennej jest juz
// wczytany jeden char na zapas
{
Stany q, q1;
Znaki z;
Boolean koniec;
q1 = STAN_POCZ; lk->dlug = 0; koniec = FALSE;
do
{ z = kategoria(wejscie);
q = q1; q1 = tab_symb[q][z];
if (q1 == STAN_NIEOKR) { /* blad */ q1 = q; koniec = TRUE; } else
// zmienic na ostatni z ktorego nie wychodza strzalki
if (q1 > STAN_NIEOKR)
{ /* koniec leksemu */
lk->zaw[lk->dlug] = wejscie; lk->dlug++; scanf("%c", &wejscie);
/* Uwaga: brak sygnalizacji przepelnienia tablicy lk->zaw */
koniec = TRUE;
}
else
{ lk->zaw[lk->dlug] = wejscie; lk->dlug++; scanf("%c", &wejscie);
/* Uwaga: brak sygnalizacji przepe�nienia tablicy lk->zaw */
}
}
while (! koniec);
// po zakonczeniu powyzszej petli w q1 jest stan, na ktorym
// automat zakonczyc dzialanie; pozostaje sprawdzic, czy to jest
// stan akceptujacy i co akceptujacy
// USTAWIC TRESCI
switch (q1)
{ case STAN_POCZ : blad("Nieoczekiwany znak", wejscie); break;
case STAN_A : blad("Mialo byc 'asia','ada' lub 'adam' a jest", wejscie); break;
case STAN_K : blad("Mialo byc 'kasia','kamil' lub 'kamila' a jest", wejscie); break;
case STAN_AD : blad("Mialo byc 'ada' lub 'adam'", wejscie); break;
case STAN_AS : blad("Mialo byc 'asia' lub 'kasia'", wejscie); break;
case STAN_KA : blad("Mialo byc 'kasia','kamil' lub 'kamila' a jest", wejscie); break;
case STAN_ASI : blad("Mialo byc 'asia' lub 'kasia' a jest", wejscie); break;
case STAN_KAM : blad("Mialo byc 'kamil' lub 'kamila' a jest", wejscie); break;
case STAN_KAMI : blad("Mialo byc 'kamil' lub 'kamila' a jest", wejscie); break;
// 5 stanow konczacych : KOBIETA lub MEZCZYZNA
case STAN_ADA : lk->jed = KOBIETA; break;
case STAN_ADAM : lk->jed = MEZCZYZNA; break;
case STAN_KAMIL : lk->jed = MEZCZYZNA; break;
case STAN_KAMILA : lk->jed = KOBIETA; break;
case STAN_ASIA : lk->jed = KOBIETA; break;
case STAN_NIEOKR : blad("Nieoczekiwany znak", wejscie); break;
}
}
void wydruk (struct leksem lk)
// wydruk pojedynczego leksemu
{
int i;
printf("LEKSEM: ");
switch (lk.jed)
// MEZCZYZNA ALBO KOBIETA
{ case MEZCZYZNA : printf("mezczyzna '"); break;
case KOBIETA : printf("kobieta '"); break;
}
for (i=0; i<lk.dlug; i++) printf("%c", lk.zaw[i]);
printf("'\n");
}
int main ()
{
//------------------------------------------------------
// Inicjalizacja tabeli symboli:
Stany q; Znaki z; struct leksem lk;
// uzupelnienia
for (q = STAN_POCZ; q <= STAN_NIEOKR; q++)
for (z = ZNAK_A; z <= ZNAK_NIEOKR; z++)
tab_symb[q][z] = STAN_NIEOKR;
/*for (q = STAN_CGW; q <= STAN_CGWGW; q++)
for (z = ZNAK_B; z <= ZNAK_NIEOKR; z++)
tab_symb[q][z] = STAN_CGW;
*/
tab_symb[STAN_POCZ][ZNAK_A] = STAN_A;
tab_symb[STAN_POCZ][ZNAK_K] = STAN_K;
tab_symb[STAN_A][ZNAK_D] = STAN_AD;
tab_symb[STAN_A][ZNAK_S] = STAN_AS;
tab_symb[STAN_K][ZNAK_A] = STAN_KA;
tab_symb[STAN_AD][ZNAK_A] = STAN_ADA;
tab_symb[STAN_AS][ZNAK_I] = STAN_ASI;
tab_symb[STAN_KA][ZNAK_M] = STAN_KAM;
tab_symb[STAN_KA][ZNAK_S] = STAN_AS;
tab_symb[STAN_ADA][ZNAK_M] = STAN_ADAM;
tab_symb[STAN_ASI][ZNAK_A] = STAN_ASIA;
tab_symb[STAN_KAM][ZNAK_I] = STAN_KAMI;
tab_symb[STAN_KAMI][ZNAK_L] = STAN_KAMIL;
tab_symb[STAN_KAMIL][ZNAK_A] = STAN_KAMILA;
//------------------------------------------------------
// Inne inicjalizacje:
printf("\n"); scanf("%c", &wejscie); printf("\n");
//------------------------------------------------------
// Analiza leksykalna:
while (wejscie != '\n') { leks(&lk); wydruk(lk); }
printf("\n");
//------------------------------------------------------
return 0;
}