Celem niniejszego wykładu jest:
- poznanie podstawowych środków opisu składni
(wyrażenia regularne, gramatyki bezkontekstowe),
- poznanie narzędzi wspomagających przetwarzanie danych o
określonej składni (Lex, Yacc).
- zrozumienie podstawowych pojęć
dotyczących obliczalności i odpowiedzenie sobie na kilka
podstawowych pytań jej dotyczących:
- Co to znaczy, że dany problem może zostać rozwiązany za
pomocą programu komputerowego?
- Czy istnieją problemy obliczeniowe, których nie można
rozwiązać za pomocą programu komputerowego?
- W jakim stopniu to co możemy obliczyć zależy od
modelu obliczeń czy dostępnych konstrukcji
programistycznych?
Nie są to proste pytania.
W trakcie kolejnych wykładów będziemy poznawać kolejne klasy
języków tworzące tzw. hierarchię Chomsky'ego.
Hierarchia ta jest owocem prac
Noama Chomsky'ego,
lingwisty, który próbował sformalizować
pojęcia gramatyki i języka.
Hierarchia ta składa się z czterech rodzajów gramatyk:
- 0.
- gramatyki ogólne,
- 1.
- gramatyki kontekstowe,
- 2.
- gramatyki bezkontekstowe,
- 3.
- gramatyki liniowe.
W trakcie badań nad pojęciem obliczalności pojawiło się
wiele modeli, o różnej sile wyrazu:
- automaty skończone, wyrażenia regularne
(stała skończona pamięć),
- automaty stosowe (stała skończona pamięć + nieograniczony
stos),
- bez ograniczeń:
- maszyny Turinga,
- systemy Posta,
- rachunek
, i inne.
Niektóre z nich powstały na długo przed tym zanim powstały
komputery i informatyka.
Okazało się, że modele te w zadziwiający sposób odpowiadają
kolejnym klasom w hierarchii Chomsky'ego:
- gramatyki liniowe = automaty skończone =
wyrażenia regularne,
- gramatyki bezkontekstowe = automaty stosowe,
- gramatyki kontekstowe = liniowo ograniczone maszyny Turinga,
- gramatyki ogólne = maszyny Turinga.
Nie są to czysto teoretyczne formalizmy.
Niektóre z nich mają wiele praktycznych zastosowań.
Szczególny nacisk położymy na dwa najważniejsze z tych formalizmów:
wyrażenia regularne i gramatyki bezkontekstowe.
W szczególności służą do specyfikowania analizatorów leksykalnych
i składniowych -- typowych modułów pojawiających się wszędzie
tam, gdzie program wczytuje dane o określonej składni.
Poznamy też narzędzia wspomagające tworzenie takich analizatorów
-- generatory, które same tworzą kod źródłowy analizatorów na
podstawie ich specyfikacji.
We wprowadzeniu wspomnieliśmy o obliczeniach i
językach.
Gdy mówimy o obliczaniu, to zwykle mamy na myśli obliczenie
wartości takiej czy innej funkcji.
Gdy zaś mówimy o języku, to mamy na myśli (potencjalnie
nieskończony) zbiór napisów złożonych ze znaków ustalonego
(skończonego) alfabetu.
(Napisy takie będziemy nazywać słowami.)
Jak połączyć te dwa pojęcia?
Definicja
Problem decyzyjny to funkcja, która możliwym danym
wejściowym przyporządkowuje wartości logiczne tak/nie.
Inaczej mówiąc problem decyzyjny, to taki problem, w którym
szukany wynik to wartość logiczna.
Na problem decyzyjny możemy też patrzeć jak na zbiór danych --
zbiór tych danych, dla których odpowiedź brzmi ,,tak''.
I odwrotnie, na dowolny zbiór danych możemy patrzeć jak na
problem decyzyjny -- czy dane należą do określonego zbioru?
Jak to jednak ma się do języków?
Jeśli interesuje nas tylko składnia języka (a nie jego
semantyka, czyli znaczenie), to każdy język możemy przedstawić
sobie jako zbiór (być może nieskończony) słów.
Tak więc każdy język nie jest niczym więcej niż problemem
decyzyjnym określonym dla słów.
Powyższe intuicje są przedstawione bardziej formalnie poniżej.
W trakcie tego kursu będziemy zajmować się m.inn. tym, dla jakich
języków (gdy spojrzymy na nie jak na problemy decyzyjne) można
skonstruować automatyczne mechanizmy
odpowiadające na pytanie, czy dane słowo należy do języka.
Definicja
Alfabet to dowolny niepusty, skończony zbiór.
Elementy alfabetu nazywamy
znakami.
Alfabetem może to być np. zbiór cyfr dziesiętnych, zbiór znaków
ASCII, czy zbiór bitów {0, 1}.
Alfabet będziemy zwykle oznaczać przez
, a elementy
alfabetu przez
.
Definicja
Słowo (lub
napis) nad alfabetem

,
to dowolny skończony ciąg znaków z

.
W szczególności, pusty ciąg jest też słowem
(i to nad dowolnym alfabetem).
Oznaczamy go przez

.
Słowa będziemy zwykle reprezentować przez zmienne
.
W przypadku języków programowania mówimy zwykle o
napisach.
Natomiast w teorii języków używa się raczej terminu
słowo.
Dodatkowo, w odniesieniu do języków naturalnych bardziej
właściwe niż ,,słowo'' wydaje się ,,zdanie''.
Tak naprawdę jednak chodzi o to samo pojęcie.
Definicja
Długość słowa oznaczamy przez

.
Na przykład |ala|=3,
.
Definicja
Sklejenie (konkatenacja) słów to słowo powstałe
z połączenia słów, tak jakby zostały one zapisane kolejno
po sobie.
Sklejanie zapisujemy pisząc po sobie sklejane słowa.
Na przykład, jeżeli
x=ala, y=ma, z=kota, to
xyz = alamakota.
Sklejanie słów jest łączne, tzn. x(yz)=(xy)z,
a
jest elementem neutralnym sklejania, tzn.
.
Sposób zapisu sklejania słów przypomina zwyczajowy zapis
iloczynów (bez znaku mnożenia).
Przez analogię, możemy wprowadzić operacje ,,potęgowania'' słów:
Definicja
Przez an oznaczamy n-krotne powtórzenie znaku a.
Podobnie, przez xn oznaczamy n-krotne powtórzenie
słowa x.
Na przykład, a5=aaaaa,
, an+1=ana, oraz
, xn+1=xnx.
Jeżeli x=ala, to
x3 = alaalaala.
Definicja
Przez #a(x) oznaczamy liczbę wystąpień znaku a w
słowie x.
Na przykład, #a(ala) = 2.
Definicja
Prefiksem słowa nazywamy dowolny jego początkowy
fragment, tzn.
x jest prefiksem
y wtw., gdy istnieje
takie
z, że
xz = y.
Jeżeli ponadto

i

, to mówimy,
że
x jest
właściwym prefiksem
y.
Analogicznie sufiksem słowa nazywamy dowolny jego
końcowy fragment, tzn. x jest sufiksem y wtw., gdy istnieje
takie z, że zx = y.
Jeżeli ponadto
i
, to mówimy,
że x jest właściwym sufiksem y.
Podsłowem danego słowa nazywamy dowolny jego spójny fragment,
tzn. powiemy, że x jest podsłowem y wtw., gdy istnieją
takie v i w, że vxw = y.
Na przykład, kaj i kaja są prefiksami (właściwymi) słowa
kajak, natomiast jak jest jego sufiksem (właściwym).
Definicja
Przez

oznaczamy słowo
x czytane wspak.
Na przykład

.
Jeżeli słowo x czytane wprost i wspak jest takie samo
(tzn.
), to mówimy, że x jest palindromem.
Przejdziemy teraz o jeden poziom wyżej i zajmijmy się zbiorami
słów czyli językami.
Definicja
Język (nad alfabetem

), to dowolny zbiór słów
(nad alfabetem

).
Jeżeli alfabet
jest znany z kontekstu, to będziemy go
czasami pomijać.
Języki będziemy zwykle oznaczać przez
.
Język złożony ze wszystkich możliwych słów nad alfabetem
będziemy oznaczać przez
.
Język, to podzbiór zbioru
.
Będziemy więc (w kolejnych wykładach) utożsamiać język
z problemem decyzyjnym, dla zbioru danych
.
Skoro języki to zbiory słów (napisów), a więc określone są na
nich wszystkie podstawowe operacje na zbiorach:
to pusty język, który nie zawiera żadnego
słowa,
to suma języków A i B,
to część wspólna (przecięcie) języków A i B,
to różnica języków A i B.
Na przykład,
.
Przyda nam się też kilka operacji charakterystycznych dla języków:
Definicja

to dopełnienie języka
A, czyli

.
Na przykład
.
Definicja
AB oznacza sklejenie (konkatenację) języków
A i
B,
czyli język zawierający wszystkie możliwe sklejenia
słów z
A ze słowami z
B,

.
Na przykład
{a, ab} {b, bb} = {ab, abb, abbb}.
Zauważmy, że sklejanie języków jeszcze bardziej przypomina
mnożenie, niż to miało miejsce w przypadku sklejania słów.
Elementem neutralnym (czyli ,,jedynką'') sklejania języków jest
język zawierający tylko słowo puste
,
.
Natomiast ,,zerem'' sklejania języków jest język pusty,
.
W odróżnieniu od operacji mnożenia, sklejanie języków nie jest
przemienne.
Sklejanie języków jest rozdzielne względem sumowania języków:
Jest tak dlatego, że każde sklejenie słowa należącego do
A ze słowem należącym do
jest sklejeniem
słowa należącego do A ze słowem należącym do B, lub
sklejeniem słowa należącego do A ze słowem należącym do C,
i vice versa.
Analogicznie:
Mając zdefiniowane sklejanie języków, możemy analogicznie do
potęgowania słów zdefiniować potęgowanie języków:
Definicja
Język
An definiujemy rekurencyjnie:
-
,
-
An+1 = AnA.
Czyli

.
Inaczej mówiąc, An to język zawierający wszystkie możliwe
sklejenia n (niekoniecznie różnych) słów wziętych z A.
Języki, jako zbiory, mogą być nieskończone.
Możemy więc rozważać sklejenie dowolnej liczby słów pochodzących
z A.
Prowadzi to do tzw. domknięcia Kleene'ego:
Definicja
Domknięcie Kleene'ego języka
A, oznaczane jako
A*, to

.
Inaczej mówiąc,
A* to język zawierający wszystkie możliwe
sklejenia dowolnej liczby (łącznie z 0) słów należących do
A.
Dla każdego języka A mamy
, gdyż
.
Jeżeli tylko A zawiera jakieś niepuste słowo, to A* jest
zbiorem nieskończonym.
Na przykład,
.
Jeżeli spojrzymy na
nie jak na alfabet, ale jak na
zbiór słów długości 1, to wyjaśni się dlaczego
jest zbiorem wszystkich słów nad alfabetem
-- po prostu każde słowo jest sklejeniem pewnej liczby
znaków.
Czasami będzie nas interesowało sklejenie dowolnej, ale
dodatniej, liczby słów z A:
Definicja
Przez A+ oznaczamy język zawierający wszystkie możliwe
sklejenia dowolnej dodatniej liczby słów należących do
A, A+ = AA*.
Przypomnijmy sobie kilka pojęć dotyczących relacji.
Definicja
Niech
X będzie dowolnym zbiorem, a

relacją (binarną) określoną na tym zbiorze.
Powiemy, że relacja

jest:
- zwrotna, jeżeli dla każdego
zachodzi
,
- symetryczna, gdy dla dowolnych
jeżeli mamy
, to mamy również
,
- przechodnia, gdy dla dowolnych
jeżeli mamy
i
, to mamy również
,
- antysymetryczna, gdy dla dowolnych
jeśli
i
, to x = y,
- relacją równoważności, jeśli jest zwrotna, symetryczna i
przechodnia,
- częściowym porządkiem, jeśli jest zwrotna, przechodnia i
antysymetryczna.
Relacja równoważności dodatkowo dzieli zbiór X na rozłączne klasy
abstrakcji.
Definicja
Jeśli

jest relacją równoważności,

, to
przez
![$[x]_\rho$](jfa-main-img86.png)
oznaczamy klasę abstrakcji
x:
Przez

oznaczamy zbiór klas abstrakcji elementów
zbioru
X:
Pojęcia te są bardziej intuicyjne, gdy przedstawimy sobie
relację jako graf skierowany (z pętelkami).
Wyobraźmy sobie, że elementy zbioru X, to wierzchołki grafu.
Z wierzchołka x prowadzi krawędź do wierzchołka y wtedy i
tylko wtedy, gdy
.
(W szczególności, gdy
, to mamy ,,pętelkę'' prowadzącą
z x do x.)
Relacja jest zwrotna, gdy w każdym wierzchołku jest ,,pętelka''.
Relacja jest symetryczna, gdy krawędzie między (różnymi)
wierzchołkami są dwukierunkowe
(tzn. jeżeli jest krawędź w jednym kierunku, to jest i w drugim).
Relacja jest antysymetryczna, gdy krawędzie między (różnymi)
wierzchołkami mogą być tylko jednokierunkowe.
Relacja jest przechodnia, jeżeli dla każdej ścieżki w grafie
(długości przynajmniej 1)
istnieje w nim krawędź łącząca początek ścieżki z jej końcem.
Inaczej mówiąc, graf musi zawierać wszystkie możliwe krawędzie
idące ,,na skróty''.
Relacja jest relacją równoważności, jeżeli graf jest podzielony
na ileś spójnych składowych, każda składowa to klika (tzn. między
każdymi dwoma wierzchołkami tej samej składowej mamy krawędź),
natomiast między wierzchołkami należącymi do różnych składowych
nie mamy krawędzi.
Spójne składowe takiego grafu są nazywane klasami abstrakcji.
Relacja jest częściowym porządkiem, jeżeli nie zawiera cykli
(z wyjątkiem pętelek, które są we wszystkich wierzchołkach).
Pojęcia zwrotności, przechodniości i symetryczności wszystkie
polegają na tym, że pewne pary/krawędzie muszą być obecne.
Będziemy mówić o odpowiednim domknięciu relacji, jako o
relacji powstałej przez dodanie odpowiednich par/krawędzi,
niezbędnych do spełnienia określonej własności.
Szczególnie przydatne będzie nam domknięcie zwrotnio-przechodnie.
Definicja
Niech

będzie dowolną relacją
binarną.
Domknięciem zwrotnio-przechodnim relacji

nazywamy najmniejszą taką relację

,
która:
- zawiera relację
,
,
- jest zwrotna i przechodnia.
Podobnie definiujemy domknięcie przechodnie, czy symetryczne.
Intuicyjnie, domknięcie zwrotnio-przechodnie polega na
dodaniu wszystkich takich krawędzi, które w oryginalnym grafie
mogły być realizowane przez ścieżki -- łącznie z pętelkami,
które odpowiadają ścieżkom długości 0.
Przykład
Relacja i jej domknięcie zwrotnio-przechodnie:
W tym wykładzie poznaliśmy podstawowe pojęcia dotyczące słów i
języków.
Przypomnieliśmy też podstawowe informacje na temat relacji,
które będą nam potrzebne w dalszych wykładach.
- Alfabet
to dowolny niepusty, skończony zbiór.
Elementy alfabetu nazywamy znakami.
- Domknięcie Kleene'ego
języka A, oznaczane jako A*, to
.
Inaczej mówiąc, A* to język zawierający wszystkie możliwe
sklejenia dowolnej liczby (łącznie z 0) słów należących do
A.
- Domknięcie zwrotnio-przechodnie
relacji
to najmniejsza taka relacja
,
która: zawiera relację
,
,
oraz jest zwrotna i przechodnia.
- Dopełnienie języka
A, oznaczane jako
, to
.
- Język
(nad alfabetem
), to dowolny zbiór słów
(nad alfabetem
).
- Palindrom
to takie słowo x, które czytane wprost i wspak jest takie
samo,
.
- Podsłowo
danego słowa to dowolny jego spójny fragment,
tzn. powiemy, że x jest podsłowem y wtw., gdy istnieją
takie v i w, że vxw = y.
- Prefiks
słowa to dowolny jego początkowy
fragment, tzn. x jest prefiksem y wtw., gdy istnieje
takie z, że xz = y.
Jeżeli ponadto
i
, to mówimy,
że x jest właściwym prefiksem y.
- Problem decyzyjny
to funkcja, która możliwym danym
wejściowym przyporządkowuje wartości logiczne tak/nie.
- Sklejenie (konkatenację) języków
to język zawierający wszystkie możliwe sklejenia
słów z A ze słowami z B,
.
- Sklejenie (konkatenacja) słów
to słowo powstałe z połączenia słów, tak jakby zostały one
zapisane kolejno po sobie.
- Słowo
(lub napis) nad alfabetem
,
to dowolny skończony ciąg znaków z
.
- Sufiks
słowa to dowolny jego
końcowy fragment, tzn. x jest sufiksem y wtw., gdy istnieje
takie z, że zx = y.
Jeżeli ponadto
i
, to mówimy,
że x jest właściwym sufiksem y.
- Jaka jest różnica między
i
?
Ile słów zawierają te języki?
- Podaj które prefiksy słowa ababbbabab są równocześnie jego
sufiksami.
- Podaj wszystkie słowa należące do języka
{aba, ba, a}{ba, baba}.
- Podaj wszystkie słowa należące do języka
.
- Podaj wszystkie słowa należące do języka
.
- Operacje na zbiorach.
Niech
.
Narysować diagram przedstawiający te zbiory.
Które są sobie równe?
Które z nich można uszeregować zgodnie z zawieraniem.
,
,
- X,
- A,
- B,
,
,
-
,
-
,
-
,
-
,
-
,
-
,
-
,
-
,
-
.
- Wybieramy dowolny numer telefonu i traktujemy go jak
słowo złożone z cyfr.
Podaj:
- wszystkie prefiksy tego ciągu,
- wszystkie sufiksy tego ciągu,
- kilka podciągów (niekoniecznie spójnych);
ile jest wszystkich?
- kilka spójnych podciągów (podsłów);
ile jest wszystkich?
- Wybieramy zbiór 2-3 elementowy.
Jakie są jego podzbiory?
Ile podzbiorów ma zbiór n-elementowy?
- Które z poniższych tożsamości są prawdziwe?
W przypadku prawdziwych uzasadnij, a w przypadku fałszywych
podaj przykład słowa, które przeczy tożsamości.
-
,
-
,
-
,
-
,
-
,
-
,
-
(AB)* = A*B*,
-
,
-
A*+ = A+*,
-
.
- Co to za języki:
-
,
Rozwiązanie
-
,
Rozwiązanie
Jeśli

, to

.
W przeciwnym przypadku jest to

.
zamknij
-
,
Rozwiązanie
Słowa powstałe ze sklejenia słów z
A i
B, przy czym konieczne jest wzięcie słów z obu tych języków.
zamknij
-
{aa, ba, bb, ab}*,
Rozwiązanie
-
,
Rozwiązanie
-
,
Rozwiązanie
Słowa nieparzystej długości.
zamknij
-
Rozwiązanie
Również słowa nieparzystej długości.
zamknij
I
A
Rozwiązanie
A to jest po grecku pizza. :-)
zamknij
- Używając symboli i operacji wprowadzonych na pierwszym wykładzie
(czyli operacji na słowach, zbiorach, językach i definicji
zbiorów) zdefiniować języki:
- słowa zawierające tyle samo liter a i b,
- słowa nad alfabetem {a, b} (nie)parzystej długości,
- inne ...
- Podać domknięcie zwrotnio-przechodnie i domknięcie symetryczne
relacji
{(1,2), (2,3), (3,1), (2,4), (5,3) }
określonej na zbiorze
.
- Pokazać, że następujące relacje są relacjami równoważności:
- słowa x i y są w relacji wtw., gdy |x| = |y|,
- słowa x i y są anagramami,
- języki A i B są w relacji wtw., gdy A* = B*.
- Pokazać, że następujące relacje są częściowymi porządkami:
- relacja zawierania
na językach nad ustalonym
alfabetem,
- relacja porządku leksykograficznego (alfabetycznego) na słowach,
- relacja bycia prefiksem.
- Relacja
jest określona na językach nad ustalonym
alfabetem w następujący sposób:
wtw., gdy istnieje taki język C, że AC = B.
Udowodnij, że relacja
jest częściowym porządkiem.