Laboratorium 10: „Maszyna stanów”

Wprowadzenie

Laboratorium poświęcone jest operacjom na napisach (ciągach znaków).

Przypominam, że:

  • 'a' to stała typu char o „wartości" znaku (litery) a małe;

  • "Ala ma kota" to stała typu char * (czyli tablica znakowa) zawierająca napis „Ala ma kota";

  • char z = 'A'; to deklaracja zmiennej o nazwie zet zainicjowanej wartością literą „A wielkie";

  • char napis[]="Ala ma kota"; to deklaracja tablicy znakowej o długości 12 elementów (jedenaście liter i specjalny znak, o kodzie ASCII 0) informujący o końcu napisu; zawartość tablicy może być dowolnie modyfikowana, ale nie możemy przekroczyć sumarycznej długości 11 liter (plus znak końca).

  • char * tekst = "Ala ma kota"; to deklaracja wskaźnika typu char * i zainicjowanie go wartością adresu miejsca pamięci, w którym przechowywana jest stała znakowa o wartości „Ala ma kota"; W efekcie jest to też „tablica" o długości 11 znaków (plus znak końca), ale jej zawartość nie może być modyfikowana!

  • na zmiennych znakowych można wykonywać normalne operacje porównywania: 'a' < 'b', tekst[0]=='A', itd.

Funkcja sprawdzająca czy zmienna ma wartość „odstępu"1, moze wyglądac tak:

int czy_odstęp( char x)
{
    return x == ' ' || x == '\n' || x == '\t';
}

Funkcja jako odstępy traktuje spacje, znak nowej linii i znak tabulacji czyli znaki „niewidoczne".

Zadanie do wykonania

Mamy dwa zadania do wyboru:

  1. Funkcja sprawdzająca czy zadany ciąg liczb jest liczbą całkowitą.

  2. Funkcja sprawdzająca czy zadany ciąg liczb jest liczbą rzeczywistą.

(A dokładniej mówiąc, czy liczba zostanie potraktowana właściwie jako dana wejściowa dla programu napisanego w C, albo czy będzie właściwą stałą odpowiedniego typu2.)

Maszyna stanów

Żeby zadanie zrealizować trzeba najpierw zastanowić się jak wygląda (poprawna) liczba całkowita. Nie jest to skomplikowane:

  • Na jej początku jest (być może) pewna liczba odstępów3 (które nie mają wpływu na poprawność liczby); można je zignorować.

  • Później jest (nieobowiązkowy) znak (+-). Po znaku musi wystąpić co najmniej jedna cyfra.

  • Po pierwszej cyfrze może wystąpić zero lub więcej cyfr.

Zakładamy, że pierwszy odstęp (po cyfrach) kończy liczbę. Kończy ją również znak o kodzie ASCII 0 (zero).

Można sobie życie ułatwić (albo utrudnić) budując maszynę Turinga, która mając na taśmie napis przejrzy go i zdecyduje czy napis jest liczbą czy też nie.

Program nawiązuje do maszyny Turinga. Szerzej opisywana ona była na zajęciach z Technologii Informacyjnych.

Możemy skonstruować maszynę Turinga realizującą algorytm sprawdzania czy napis jest liczbą, zgodnie z powyższymi zasadami. Poniżej przedstawiam proponowany diagram stanów.

stateDiagram-v2 [*] --> Start Start --> Start: pusty Start --> Widziałem_znak: +,- Start --> Widziałem_cyfrę: cyfra Widziałem_cyfrę --> Widziałem_cyfrę: cyfra Start --> Błąd: EOT, inny Widziałem_znak --> Widziałem_cyfrę: cyfra Widziałem_znak --> Błąd: +, -, EOT, pusty, inny Widziałem_cyfrę --> Błąd: +, -, inny Widziałem_cyfrę --> OK: EOT, pusty

Zakładamy, że liczba zapisana jest na taśmie, a głowica znajduje się przed pierwszym znakiem napisu.

Na diagramie tym, podwójne okręgi oznaczają stan początkowy i stany końcowe. Opisy nad krawędziami (lab na prawo od nich) oznaczją ,,kategorie" znaków, które mogę się pojawić:

  • +, - to (ewentualny) znak liczby;

  • pusty oznacza tak zwany ,,biały znak" (czyli w najprostszym przypadku jest to odstęp, w sytuacjach bardziej skomplikowanych może to być nowa linia, znak poziomej lub pionowej tabulacji, wysów strony). Wszystkie takie znaki przed rozpoczęciem cyfry mogą być po cichu zignorowane;

  • cyfra to dowolna cyfra z zakresu od 0 do 9;

  • EOT to umowny (symboliczny) zapis znaku o kodzie ASCII zero, oznaczający w języku C koniec napisu;

  • inny to (ponownie umowny) zapis oanaczajacy znaki poza wymienionymi dotychczas.

Nie gwarantuję, oczywiście, że przedstawione schematy są poprawne.

Każda ścieżka od start od OK powinna opisywać poprawną postać liczby.

Można opisać podobne zasady opisujące wygląd liczby rzeczywistej:

  • ignorujemy znaki puste na początku;

  • później może być +/–/cyfra,

  • pomiędzy cyframi może pojawić się kropka (lub przecinek) dziesiętna,

  • po cyfrach może pojawić się litera e (lub E albo d lub D) a po niej plus albo minus albo odstęp, a później cyfra/cyfry wykładnika.

Uproszczony (choć niewolny zapewne od błędów) diagram maszyny Turinga sprawdzającej czy napis jest liczbą rzeczywistą zamieściłem poniżej.

stateDiagram-v2 [*] --> Start Start --> Start:pusty Start --> Znak:+,– Start --> Cyfry:cyfra Start --> Ułamek0:kropka Start --> Błąd:E, D, EOT, inny Znak --> Cyfry:cyfra Znak --> Ułamek0:kropka Znak --> Błąd:pusty, EOT, E, D, inny Ułamek0 --> Ułamek:cyfra Ułamek0 --> Błąd:inny Cyfry --> Cyfry:cyfra Cyfry --> Ułamek:kropka Cyfry --> OK:EOT Cyfry --> Wykładnik:E, D Ułamek --> Ułamek:cyfra Ułamek --> Wykładnik:E, D Ułamek --> OK:koniec Ułamek --> Błąd:inny Wykładnik --> Błąd:koniec, inny Wykładnik --> ZnakW:+,– Wykładnik --> CyfraW:cyfra ZnakW --> Błąd:inny,koniec ZnakW -->CyfraW:cyfra CyfraW --> CyfraW:cyfra CyfraW --> Błąd:inny CyfraW --> OK:koniec

Wybieramy jedno z tych zadań i programujemy. Wszystkie czynności sprawdzające powinna wykonywać funkcja (na potrzeby instrukcji nazwę ją czy, wywoływana w sposób następujący:

int czy(char napis[ ]);

na przykład:

if(czy("+123") printf("Liczba!\n");

Funkcja zwraca wartość jeden gdy napis jest liczbą, zero w przeciwnym razie.

Można próbować utrudnić/ułatwić sobie życie programując szereg funkcji pomocniczych sprawdzających czy:

  • znak jest cyfrą (int czy_cyfra( char );)

  • jest znakiem (+ -) int czy_znak( char );

  • odstępem,

Uwagi

Uwaga 1: Można zaprogramować funkcję bardziej rozbudowaną, która będzie poprawnie rozpoznawała jako liczby stałe dwójkowe, ósemkowe czy szesnastkowe…

Uwaga 2: Na koniec zajęc należy umieścić na e-portalu.

Uwaga 3: Można zaprogramować oba!

Uwaga 4: Można pokusić się o rozpoznawanie liczb całkowitych zapisanych ósemkowo (zaczynają się od cyfry 0), później mogą być tylko cyfry z zakresu 0–7 i/lub szesnastkowo (zaczynają się od znaków 0x lub 0X)..


  1. Jako odstępy traktuję również znaki nowej linii \n i tabulacji \t↩︎

  2. Ale rozważamy wyłącznie typy podstawowe! ↩︎

  3. Jako odstępy uważać będziemy dowolne „znaki białe" (to znaczy takie, które nie zostawiają na papierze żadnego czarnego śladu). Będą to odstęp, znak tabulacji (\t), znak nowej linii (\n) i być może jeszcze jakieś… ↩︎

Poprzedni
Następny