Jak porządnie opisać język nieskończony? Generatory: gramatyki

Transkrypt

Jak porządnie opisać język nieskończony? Generatory: gramatyki
Wykład 17: powtórka, str. 1
Jak porządnie opisać język nieskończony?
• {λ,
ab, aabb, oaaabbb, . . .} — co oznaczają kropeczki?
n
• an bn n ­ 0 — lepiej, ale są niepożądane elementy obce
(liczby, zmienne, relacje, . . . )
Język definiujemy na dwa sposoby. Przez
• generator — cokolwiek wyprodukuje, uważamy za należące do języka
• akceptor — cokolwiek zatwierdzi, uważamy za należące do języka
Opis języka programowania przeznaczony dla programisty powinien być generatorem — ma wyjaśniać, jak pisać poprawne programy.
Kompilator języka programowania powinien zawierać akceptor — sprawdzający, czy program na jego wejściu należy do języka.
Wykład 17: powtórka, str. 2
Generatory: gramatyki bezkontekstowe
DEFINICJA: Gramatyka bezkontekstowa G —
M • alfabet terminalny Σ;
• alfabet nieterminalny lub pomocniczy N (rozłączny z Σ);
• skończony zbiór P produkcji postaci A → w,
gdzie A ∈ N i w ∈ (N ∪ Σ)∗;
• wybrany nieterminal S ∈ N nazywany symbolem początkowym albo
aksjomatem gramatyki.
Przykład:
M
Terminale: a, b
Nieterminale: A
Produkcje: A → λ
A → aAa
A → bAb
Wykład 17: powtórka, str. 3
Jak gramatyka definiuje język?
DEFINICJA: Wywodliwość —
M • jeśli w P jest produkcja A → w, to dla dowolnych słów
u, v ∈ (N ∪ Σ)∗, słowo uwv nazywamy bezpośrednio wywodliwym ze
słowa uAv, co oznaczamy uAv ⇒G uwv;
• jesli w1 ⇒G w2 , w2 ⇒G w3 , . . . , wn−1 ⇒G wn , to słowo wn nazywamy
wywodliwym ze słowa w1 , co oznaczamy w1 ⇒∗G wn .
DEFINICJA: Język L(G) generowany przez gramatykę G —
M
składa się z tych słówn wywodliwych
z aksjomatu,
które już nie zawierają
o
def
∗
∗
nieterminali: L(G) = w ∈ Σ S ⇒ G w .
qq
A ⇒∗ bbaabb ∈ L(G)
Przykład:
M
Gramatyka: A → λ
A → aAa
A → bAb
Fakt: n
o
R
∗
M
L(G) = ww w ∈ {a, b}
A ⇒ bAb ⇒ bbAbb ⇒ bbaAabb ⇒ bbaabb
Wykład 17: powtórka, str. 4
Jak gramatyka definiuje język?
Przykład:
M
Gramatyka G: E
E
T
T
F
F
→
→
→
→
→
→
E ⇒ T
⇒ (E )
⇒ (T + T)
⇒ (a + T)
⇒ ( a + a)
⇒ F +T ∗F
L(G) = wyrażenia
T
E +T
F
T ∗F
a
(E )
⇒
⇒
⇒
⇒
F
(E + T)
(F + T)
(a + F)
⇒ F +F ∗F
arytmetyczne zbudowane z a, +, ∗, ( i )
Wykład 17: powtórka, str. 5
Gramatyki prawoliniowe
DEFINICJA:
M
Gramatyka bezkontekstowa G = hΣ, N, P, Si jest prawostronnie liniowa
jeśli każda produkcja w P ma postać:
• albo A → x
(czyli: żadnych nieterminali)
• albo A → xB
(czyli: tylko jeden nieterminal po prawej)
gdzie x ∈ Σ∗ a A, B ∈ N .
Przykład:
M
abc
E
E
C
C
C
C
C
→
→
→
→
→
→
→
aC
bC
λ
aC
bC
0C
1C
E
E
E
→ a
→ (E )
→ E +E
bezkontekstowa
ale nie prawoliniowa
prawoliniowa
Wykład 17: powtórka, str. 6
Rodzaje gramatyk
Przykład:
G1 : E → a C
E
C
C
C
C
C
G1
G2
→
→
→
→
→
→
bC
λ
aC
bC
0C
1C
G2 : I → a
I
I
I
I
I
→
→
→
→
→
b
Ia
Ib
I0
I1
L(G1 ) = język identyfikatorów = L(G2 )

jest prawostronnie liniowa 
 dwie gramatyki różnych typów
jest bezkontekstowa

 mogą określać ten sam język
ale nie prawostronnie liniowa
DEFINICJA:
M
Język L jest
• regularny jeśli ist. gram. prawostronnie liniowa G taka, że L = L(G);
• bezkontekstowy jeśli ist. gram. bezkontekstowa G taka, że L = L(G).
Przykład: Język identyfikatorów L(G2 ) jest regularny.
Wykład 17: powtórka, str. 7
Umowa notacyjna dla gramatyk bezkontekstowych
• ponieważ nieterminale oznaczają pojęcia — sugestywne nazwy
np. „wyrażenie”, „liczba”
• nieterminale ujmujemy w nawiasy kątowe:
np. hwyrażeniei, hliczbai
h... i
• wszystkie produkcje z pojedynczego nieterminalu grupujemy:
piszemy
zamiast
hcyfrai ::= 0 1 . . . 9
hcyfrai→0
hcyfrai→1
...
hcyfrai→9
hliczbai ::= hcyfrai hliczbai hcyfrai
hliczbai→hcyfrai
hliczbai→hliczbai hcyfrai
Wykład 17: powtórka, str. 8
Drzewa wywodu
DEFINICJA:
M
Drzewo wywodu słowa w ∈ Σ∗ w gramatyce bezkontekstowej G =
hΣ, N, P, hSii to takie drzewo, które ma:
• w liściach symbole terminalne składające się na słowo w,
• w pozostałych (wewnętrznych) węzłach nieterminale rozmieszczone
wg takich zasad:
– jeśli w jakimś węźle znajduje się nieterminal hAi a w jego dzieciach od lewej do prawej symbole a1 , a2 , . . . , an ∈ Σ ∪ N , to
hAi → a1 a2 . . . an musi być produkcją z P ,
– w korzeniu znajduje się nieterminal początkowy hSi.
Przykład:
hwyrażeniei
M
Fragment drzewa
jest legalny jeśli
hwyrażeniei + hskładniki
hwyrażeniei → hwyrażeniei + hskładniki
jest produkcją z gramatyki.
Wykład 17: powtórka, str. 9
Drzewa wywodu
Drzewa wywodu słów w gramatyce prawoliniowej są „przeważone” w prawo
tak, że stanowią prawie listy:
hEi
b hCi
hEi ::= a hCi
hCi ::= λ a hCi b hCi 0 hCi 1 hCi
hCi
a
hCi
a
hCi
1
b
hCi
hEi ⇒ a hCi ⇒ a a hCi ⇒ a a 1 hCi ⇒ a a 1 b hCi ⇒ a a 1 b
Wykład 17: powtórka, str. 10
Drzewa wywodu
hzmiennai ::=
hcyfrai ::=
hliczbai ::=
hatomi ::=
hwyrażeniei ::=
hskładniki ::=
ciąg terminali:
34 ∗ (x + 11)
aksjomat
a b . . . z
0 1 ... 9 hcyfrai
hliczbai hcyfrai
hzmiennai hliczbai ( hwyrażeniei )
hwyrażeniei + hskładniki
hskładniki
hatomi hskładniki * hatomi
hwyrażeniei
hskładniki
.......
......
.....
.....
.
........................................................
.
.
.....................hatomi
..
.............
.............
....
.
.........
.
.
.
.
.
.
.
.
.
.
.
.......
.
.
.
.
.
.
.
.
.
......
.
.
hwyrażeniei
.
.
.
.....
..
....
.
.
.
.
.
.
....
.
.
...
.
....
.
.
hskładniki
..
...
.
.. .
.
...
.
.
.
...
...
....hwyrażeniei
...
hatomi
...
...
...
...
...
... hskładniki
...
hliczbai
...
...
....
...
...
...
..
hatomi
hliczbai
...
...
....
.
.....
.....
hzmiennai
hcyfrai hcyfrai .....
...
...
..
..
.
..
hskładniki
hatomi
hliczbai
hliczbai
hcyfrai hcyfrai
3
4
* (
x
+
1
1
)
Wykład 17: powtórka, str. 11
Drzewo wywodu a struktura słowa
hwyrażeniei ::= 0 1 . . . 9 ( hwyrażeniei ) hwyrażeniei + hwyrażeniei hwyrażeniei ∗ hwyrażeniei
.......
hwyrażeniei
.......
.....
.....
.....
hwyrażeniei
....
....
.
hwyrażeniei
hwyrażeniei .........
hwyrażeniei
...
...
2
+
5
∗.
3
...
...
...
... hwyrażeniei
hwyrażeniei
hwyrażeniei
....
....
....
.....
hwyrażeniei
.....
.....
......
hwyrażeniei
Niejednoznaczność wywodu: istnieją dwa różne drzewa wywodu danego
słowa. W tym przypadku sugerują one kolejność działań:
• drzewo górne odpowiada wykonaniu dodawania przed mnożeniem
• drzewo dolne odpowiada wykonaniu mnożenia przed dodawaniem
Wykład 17: powtórka, str. 12
Drzewo wywodu a struktura słowa
Gramatyka fragmentu języka polskiego:
hzdaniei
::=
hgr.podmiotui hgr.orzeczeniai
hgr.podmiotui
::=
hpodmioti
hprzydawkai hgr.podmiotui
hgr.orzeczeniai
::=
hpodmioti
::=
hprzydawkai
::=
horzeczeniei
::=
hdopełnieniei
::=
hokoliczniki
::=
horzeczeniei
horzeczeniei hdopełnieniei
hgr.orzeczeniai hokoliczniki
Anka
Basia Czesiek
gruby stary
bije kocha
Ankę Basię Cześka
w domu nocą
Wykład 17: powtórka, str. 13
Drzewo wywodu a struktura słowa
hzdaniei
hgr.orzeczeniai
hgr.podmiotui
hgr.orzeczeniai
hgr.podmiotui
hgr.orzeczeniai
hgr.podmiotui
hprzydawkaihprzydawkai hpodmioti horzeczenieihdopełnienieihokoliczniki hokoliczniki
stary
gruby Czesiek
bije
Ankę w domu nocą
Wykład 17: powtórka, str. 14
Drzewo wywodu a struktura słowa
hzdaniei
hgrupa podmiotui
hpodmioti
hgrupa orzeczeniai
horzeczeniei
=
CZAS LECI
JAK STRZAŁA
=
CZASOWE MUCHY
LUBIĄ STRZAŁĘ
hokoliczniki
TIME FLIES LIKE AN ARROW
hprzydawkai hpodmioti horzeczeniei hdopełnieniei
hgrupa podmiotui
hgrupa orzeczeniai
hzdaniei
Znaczenie zależy od drzewa rozbioru również w językach naturalnych.
Wykład 17: powtórka, str. 15
Drzewo wywodu a struktura słowa
Z punktu widzenia należenia słowa do języka postać drzewa wywodu nie ma
znaczenia. Z punktu widzenia przekazywanego sensu postać drzewa wywodu
jest bardzo ważna.
Przykład: jak policzyć wartość wczytywanej liczby?
M
hliczbai ::= hcyfrai hcyfrai hliczbai
To sugeruje, że trzeba osobno znaleźć wartość pierwszej cyfry i osobno całej
reszty a następnie jakoś te wartości połączyć: 3|456 = 3 · 103 + 456
— ale skąd z góry wiedzieć,
do jakiej potęgi podnieść 10?
hliczbai ::= hcyfrai hliczbai hcyfrai
To sugeruje, że trzeba osobno znaleźć wartość ostatniej cyfry i osobno całej
reszty a następnie jakoś te wartości połączyć: 345|6 = 345 · 10 + 6
— tak jest łatwiej zaprogramować.
Rozumienie słowa oraz operacje na nim odbywają się faktycznie na jego
drzewie wywodu.
Wykład 17: powtórka, str. 16
Akceptory: automaty skończone
............
...............
.... .......b
... ......a
.
.
.. .
...
...
.
.
....
....
..
.
...
.
...
.
.
.
..
..
❫..
❫..
a
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.....
q
.....
..✐
.............................
q
a✣
✲
s
b
p
b
❫
r
b ..........
.....................q
..✐
............................
...
...
...
✣
...
..
...
....
...
..... .... a
............
a
t
...
...
...
✣
...
..
...
.
.
...
..... ....... b
...........
Funkcja przejścia automatu:
δ
p
q
r
s
t
a
q
s
r
s
r
b
r
q
t
q
t
δ ∗hp, baabi = δ ∗ δhp, bi , aab
D
E
D
E
= δ ∗ r, aab = δ ∗ δhr, ai , ab
D
E
D
E
= δ ∗ r, ab = δ ∗ δhr, ai , b
D
= δ ∗ r, b = δ ∗ δhr, bi , λ
= δ ∗ht, λi = t
D
E
D
E
E
Akceptacja słowa w: jeśli δ ∗hp, wi jest stanem akceptującym.
Wykład 17: powtórka, str. 17
Automaty skończone
DEFINICJA: Deterministyczny automat skończony M —
M • skończony zbiór Q stanów,
• skończony zbiór Σ liter,
• funkcja przejścia δ : Q × Σ → Q,
• wyróżniony stan początkowy q0 ∈ Q,
• wyróżniony zbiór stanów końcowych (akceptujących) F ⊆ Q.
DEFINICJA: Uogólniona funkcja przejścia — δ ∗ : Q × Σ∗ → Q:

q



jeśli w = λ
δ ∗hq, wi def
= δ ∗ δhq, σi , w ′


D
E
jeśli w = σw ′
dla pewnych σ ∈ Σ i w ′ ∈ Σ∗
DEFINICJA: Automat M akceptuje słowo w jeśli δ ∗hq0 , wi ∈ F
DEFINICJA: Język akceptowany przez automat M = hQ, Σ, δ, q0 , F i:
def
L(M ) =
n
w ∈ Σ∗ M akceptuje w
o
=
n
w ∈ Σ∗ δ ∗hq0 , wi ∈ F
o
Wykład 17: powtórka, str. 18
Automaty skończone
Przykład:
JMęzyk liczb naturalnych:
✲
{0} + {1} · {0, 1} ∗ =
{0} ∪ 1w w ∈ {0, 1} ∗
n
o
p
1
............................
.
.... 1
0,
..
...
......
...........................
✸
0
❄
r
n
o
wv w ∈ {a, b} & v ∈ {a, b, 0, 1} ∗
1
❄❄ ........................
.
...
0,.....1....
śm ........
.
...
......
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
❦
Przykład:
JMęzyk identyfikatorów:
{a, b} · {a, b, 0, 1} ∗ =
q
0✲
p
✲
................ .
.... a, ..b,
... 0, 1
...
...
...
..
...
.
..
..
❫
.
a ....
......
.....................q
.....................✶
..........
q
b
0
1
❄❄ ........................
..
...
... 1
a, b,...0,
..
śm ........
.
....
.
.
.
.
.
.
.
.
❦.............
Wykład 17: powtórka, str. 19
Automaty skończone
TWIERDZENIE:
M
Dla każdego automatu skończonego M język L(M ) jest regularny. Dla
każdego języka regularnego L istnieje automat skończony M taki że
L = L(M ).
Przykład:
G
G:
Mramatyka prawoliniowa
hSi ::= λ abbhSi
o
n
n
∗
L(G) = {abb} = (abb) n ­ 0
stan S: rozpoznano pewną ilość słów abb
stan p: rozpoznano pewną ilość słów abb
i jeszcze literę a
stan q: rozpoznano pewną ilość słów abb
i jeszcze słowo ab
stan śm: wystąpił błąd
b....................................
.................................
.
.
.
.
.
.
.
.
.
.
.
.
.
.....
..✢
✸
✲
b
p
a✲
S
q
a
a
❄
...
.......
s
................
................................................... ✲
.............. śm
b
...
...
...
✣
...
..
.
...
..
...
.. b
.... ...a,
.............
Wykład 17: powtórka, str. 20
Automaty skończone
Przykład:
M
Gramatyka prawoliniowa
G:
hSi ::= ahAi bhBi
hAi ::= a bhBi
hBi ::= λ ahAi
.........
..... ....... 1
...
....
..
....
..
...
.
❫..
...
0✸
✲
A
s
S
1s
...........
.... .....0,
... 1
....
...
.
...
..
...
.
.
0 ❫...
..
B
...
.
...
..
✣
.
....
..
...
.
.
...
....... ........ 0
.....
✸
1
C
a✸
✲
S
A
..
....
b .....
...
s ◆.
b
...
▼.....
..a
..
...
B
Przykład:
M
Gramatyka prawoliniowa:
hSi ::= 0hAi 1hBi
hAi ::= 0hCi 1hAi
hBi ::= 0hBi 1hCi
hCi ::= λ 0hCi 1hCi
a✲
a, b
❄
b
✲
śm
...
.
...
...
✣
..
....
...
..
.
...
.. b
...... ......a,
.......
Wykład 17: powtórka, str. 21
Maszyny ze stosem
...............
....0, 0......→
...
...
..
..
...
.
.
.
❫.. .
Słowo na wejściu:
0 0 11
00
q
→
0,
Z
p
✇
λ
✲
→
0
0
Z
✼
0
1,
0Z
część
nieprzeczytana
✛
λ, Z → λ
r
.....
............ ................
..
1, 0 →
...
.
.
.
.
............ ..........
❦......
λ
Kiedy wędrówka po maszynie się „zatnie”, czyli nie ma już żadnej możliwości
pójścia dalej, sprawdzamy, czy słowo zostało zaakceptowane; t.zn., czy
spełnione są następujące warunki:
• na wejściu jest słowo puste (wszystko już przeczytane);
• na stosie jest słowo puste;
• sprawdzanie zakończyło się w stanie końcowym (akceptującym).
Wykład 17: powtórka, str. 22
Maszyny ze stosem
DEFINICJA: Maszyna ze stosem M —
M • skończony zbiór Q stanów,
• skończony zbiór Σ liter wejściowych,
• skończony zbiór Γ symboli stosowych,
• Z ∈ Γ — wyróżniony symbol stosowy oznaczający dno stosu,
˜ Q × Γ∗ (częścio• częściowa funkcja przejścia δ : Q × (Σ ∪ {λ}) × Γ →
wa — t.zn. może być nieokreślona dla niektórych argumentów),
• wyróżniony stan początkowy q0 ∈ Q,
• wyróżniony zbiór stanów końcowych (akceptujących) F ⊆ Q.
DEFINICJA: Język akceptowany przez M —
n
o
M
def
∗
L(M ) = w ∈ Σ δ ∗hq0 , w, Zi = hq ′ , λ, λi dla pewnego q ′ ∈ F
gdzie δ ∗ jest uogólnioną funkcją przejścia.
Wykład 17: powtórka, str. 23
Maszyny ze stosem a języki bezkontekstowe
TWIERDZENIE:
M
Język akceptowany przez dowolną maszynę stosową jest
bezkontekstowy.
Uwaga:
Nie każdy język bezkontekstowy jest akceptowany przez jakąś maszynę stosową; ale każdy jest akceptowany przez jakąś niedeterministyczną maszynę
stosową (nierozpatrywane na tym wykładzie).
„Prawie” każdy „praktyczny” język bezkontekstowy jest akceptowany przez
jakąś maszynę stosową, co umożliwia kompilowanie programów komputerowych.
Wykład 17: powtórka, str. 24
Gramatyki, języki, maszyny
gramatyki
języki
akceptory
prawoliniowe bezkontekstowe
l
l
regularne
bezkontekstowe
l
↑
automaty maszyny ze stosem
Wykład 17: powtórka, str. 25
Notacja beznawiasowa Łukasiewicza
Notacja Łukasiewicza (w świecie nazywana
Polish):
Wyrażenia (arytmetyczne, logiczne, itp.) można
zapisywać bez nawiasów w postaci
operator arg1 arg2 . . . argn
Odwrotna notacja Łukasiewicza (Reverse
Polish):
arg1 arg2 . . . argn operator
Jan Łukasiewicz
1878–1956
stosowana w informatyce.
Wykład 17: powtórka, str. 26
Notacja beznawiasowa Łukasiewicza
Przykład:
M
∗
+
2
+
5
1
∗
7
3
Zwykła notacja (infix): (2 + 5) ∗ (7 ∗ 3 + 1)
Notacja Łukasiewicza (prefix): ∗ + 2 5 + ∗ 7 3 1
Odwrotna notacja polska (postfix): 2 5 + 7 3 ∗ 1 + ∗
Wykład 17: powtórka, str. 27
Obliczanie wyrażeń w ONŁ
Założenie: każdy operator op „wie” ile potrzebuje argumentów: A(op).
Np. A(+) = 2 , A(¬) = 1 , A(if(...) ... else ...) = 3 .
Algorytm:
do {
jeśli na wejściu jest liczba ℓ,
to przełóż ją z wejścia na stos;
jeśli na wejściu jest operator op,
to {
zdejmij ze stosu A(op) liczb,
zastosuj do nich operację op,
jej wynik włóż na stos;
}
} while (jest jeszcze coś na wejściu);
stos
25 + 73 ∗ 1 + ∗
wejście
Wykład 17: powtórka, str. 28
Działania na językach
1. Suma:
n
def
L|M =
o
w w ∈ L lub w ∈ M
2. Złączenie:
def
LM =
o
uv u ∈ L i v ∈ M
n
3. Iteracja (domknięcie Kleenego):
L∗ def
=
n
u1 u2 . . . un u1 , u2 , . . . , un ∈ L i n ­ 0
o
Wykład 17: powtórka, str. 29
Działania na językach
Własności działań:
• Łączność:
K | (L | M ) = (K | L) | M
K(LM ) = (KL)M
• Przemienność:
L|M =M |L
Uwaga: złączenie nie jest przemienne!
• Elementy neutralne:
M |∅=M
ΛM = M Λ = M
∅ def
= {} — język pusty
Λ def
= {λ} — język zawierający tylko słowo puste
• Rozdzielność:
K(L | M ) = KL | KM
(L | M )K = LK | M K
Wykład 17: powtórka, str. 30
Działania na językach
Iteracja:
L∗ def
=
u1 u2 . . . u n u1 , u2 , . . . , u n ∈ L i n ­ 0
L∗ = Λ | L | L2 | L3 | . . . = {λ} | L | LL | LLL | . . .
TWIERDZENIE: (rozwiązywanie równania językowego)
M
Rozwiązaniem równania X = L | XM jest X = LM ∗ .
Dowód:
Jeśli X = LM ∗ to
X = LM ∗ = L (Λ | M | M 2 | M 3 | . . .)
= LΛ | LM | LM 2 | LM 3 | . . .
= L | (LM | LM 2 | LM 3 | . . .)
= L | L (Λ | M | M 2 | . . .) M
= L | LM ∗M = L | XM
Wykład 17: powtórka, str. 31
Uproszczony schemat kompilacji
program
źródłowy
ciąg
leksemów
✕
analiza
leksykalna
drzewo
wywodu
✕
drzewo i
tablice
symboli
✕
analiza
syntaktyczna
analiza
semantyczna
KOMPILATOR
generacja
kodu
✯
kod
qqqqqqqqqq
qqqqq
qqq qqqqq
qqq
docelowy
qqq
qq
qqq
qqq
qqq
q
q
dane do
wyniki
programu
Wykład 17: powtórka, str. 32
Analizator leksykalny czyli skaner — przykład
✲ pocz
B✲
E✲
b
E✲
e
N✲
be
G
en
D
• słowa kluczowe: BEG, END
(wielkość liter nieistotna)
• znaki operacji: +, *
• liczby całkowite
postaci hcyfraihcyfrai∗
• komentarze postaci
/* hcokolwieki */
• separatory postaci
hspacjaihspacjai∗
q
klucz
✶
+✲ oper
*
............................
....hcyfrai
✲ licz
..
.
.
.......................... .
hcyfrai
❦
/✲
ciach
*✲ cgw
.........
.... ......*
...
...
...
....
...
..
.
❫. .
*✲cgwgw /✲
..............
.....
..
... .....................
■
.
✣...
..
..
...................................
.
.. ... ...
✲ separ
.. ..........
.
.
.
..........................
hspacjai
❦
hspacjai
koment
Wykład 17: powtórka, str. 33
Analizator leksykalny czyli skaner — przykład
Funkcja przejścia:
pocz
b
be
e
en
licz
ciach
cgw
cgwgw
separ
b
b
e
e
be
g
n
d
pl
gw cyf ciach sp nieokr
oper oper licz ciach separ
klucz
en
klucz
licz
cgw
cgw cgw cgw cgw cgw cgw cgwgw cgw cgw cgw cgw
cgw cgw cgw cgw cgw cgw cgwgw cgw koment cgw cgw
separ
Uwagi:
• funkcja przejścia automatu skończonego stany × znaki → stany
• zbiór znaków rozszerzony o znak nieokr : „ jakikolwiek inny”
• puste miejsca oraz brakujące wiersze oznaczają „stan śmietnikowy”
Wykład 17: powtórka, str. 34
Po co wydziela się analizę leksykalną?
Włączenie analizy leksykalnej do analizy składniowej jest nietrudne; po co
więc jest wydzielona?
1. Analiza leksykalna jest prostsza niż składniowa
leksyka
syntaktyka
gramatyka prawoliniowa bezkontekstowa
akceptor
automat
maszyna stosowa
2. Analizator leksykalny czyta tekst, więc jego działanie zajmuje dużo
czasu. Warto więc go optymalizować — a to robi się inaczej niż w
składniowym.
3. Czytanie tekstu jest zależne od platformy, analiza składniowa jest niezależna. Rozdzielenie ich poprawia więc przenośność (portability ) kompilatorów.
Wykład 17: powtórka, str. 35
Różne metody analizy syntaktycznej
Rozbiór słowa
— budowanie jego drzewa wywodu w danej gramatyce bezkontekstowej.
Synonimy: rozbiór = analiza syntaktyczna = parsing.
Parser
— program (procedura, podprogram) dokonujący rozbioru.
Budowy drzewa wywodu można dokonywać
• albo od strony korzenia (rozbiór zstępujący ),
• albo od strony liści (rozbiór wstępujący ).
Jest wiele metod rozbioru danego słowa; różnią się
• zakresem stosowalności (do jakich rodzajów gramatyk bezkontekstowych się nadają),
• oraz efektywnością (jak szybko działają i ile potrzebują pamięci).
Programy do automatycznego tworzenia parserów potrafią na ogół dobrać
optymalny (albo przynajmniej niezły) parser do danej gramatyki.
Wykład 17: powtórka, str. 36
Koszty
• Do każdej jednoznacznej gramatyki bezkontekstowej można zbudować parser, działający w czasie O(n3 ), gdzie n jest długością ciągu
terminali na wejściu.
• Ta złożoność wynika z działania przez próbowanie i wycofywanie się
w przypadku złego dopasowania; drzewo wywodu jest wielokrotnie budowane i niszczone.
• Niezbyt bolesne ograniczenia na gramatyki umożliwiają istnienie parsera, działającego w czasie O(n), czyli znacznie szybciej.
• Wszystkie praktycznie stosowane parsery działają w czasie O(n).
Wykład 17: powtórka, str. 37
Rekursywny parser zstępujący
• Analiza top-down.
• Po jednej funkcji rekursywnej dla każdego nieterminala. Funkcja dla
nieterminalu hXi
– wywoływana jest po to, żeby skonstruować drzewo wywodu początkowych leksemów z wejścia, mające w korzeniu nieterminal hXi;
– żeby móc zadecydować, której produkcji z nieterminalu hXi użyć,
jest wywoływana w sytuacji, w której znany (wczytany) jest już
pierwszy liść (leksem) tego drzewa; kończy działanie w sytuacji,
kiedy znany jest już pierwszy leksem spoza korony tego drzewa;
– może zasygnalizować błąd i program ją wywołujący stara się znaleźć inną produkcję do zastosowania.
Wykład 17: powtórka, str. 38
Rekursywny parser zstępujący
Boolean
Boolean
A(drzewo* drz);
B(drzewo* drz);
hBi ::= whBi w
hBi
hBi
w
drz1
Boolean B(drzewo* drz) {
drzewo drz1;
if (nowyleks(’w’))
if (B(&drz1)){
*drz = ...;
return true;
}
else {
*drz = ...;
return true;
}
else return false;
}
hBi
w
Wykład 17: powtórka, str. 39
Rekursywny parser zstępujący
Boolean
A(drzewo* drz);
Boolean
B(drzewo* drz);
hAi ::= yhAihBiz x
hAi
y
hAi
hBi
drz2
.........................................
.................
.........
.......
.........
.....
....
.
.
.
...
..
.
.
...
..
.
...
.
.
...
.
.
...
...
..
..
..
..
..
.
drz1
Boolean A(drzewo* drz) {
drzewo drz1, drz2;
if (nowyleks(’y’))
if (A(&drz1))
if (B(&drz2))
if (nowyleks(’z’)) {
*drz = ...;
return true;
}
else blad("brakuje terminalu z");
else blad("brakuje nieterminalu <B>");
else blad("brakuje nieterminalu <A>");
else
if (nowyleks(’x’)) {
*drz = ...;
return true;
}
else return false;
}
z
hAi
x
Wykład 17: powtórka, str. 40
Przekształcenie gramatyki dla parsera zstępującego
Zmiana kolejności produkcji i „wyłączenie przed nawias”:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hSi + hWi hSi hSi - hWi
hCi hCi * hSi hCi hCi / hSi
hLi ( hWi )
0 1 0 hLi 1 hLi
hWi ::= hSi
n
o
+ hWi - hWi λ
hSi ::= hCi
n
o
* hSi / hSi λ
hCi ::= ( hWi ) hLi
n
o hLi ::= 0 hLi λ n
o
1 hLi λ
Wykład 17: powtórka, str. 41
Parser zstępujący — problemy
Lewostronna rekursja w gramatyce powoduje nieskończone obliczenie
Przykład: inna gramatyka: hWi::=hSi hWi+hSi
M
Boolean fW (drzewo* t) {
if (fS (&t1 )) {
*t =
hWi
;
return TRUE;
}
else
hSi
t1
if (fW (&t1 )) {
if (nowyleks(’+’,&nleks))
if (fS (&t2 )) {
hWi
*t =
hWi
+
;
return TRUE;
}
hSi
t1
t2
else blad("po + brakuje <S>");
else return FALSE;
else return FALSE;
}
Wykład 17: powtórka, str. 42
Leczenie lewostronnej rekursji
Wyjście: do gramatyk wprowadzić specjalną konstrukcję oznaczającą
„ciąg . . . grupowany do lewej”:
Przykład:
M
Żeby wyrazić „wyrażenie to niepusty ciąg składników porozdzielanych plusami i minusami grupowany do lewej” —
hwyrażeniei + hskładniki
zamiast hwyrażeniei::=hskładniki
hwyrażeniei - hskładniki
nn o
o
piszemy hwyrażeniei ::= hskładniki
+ − hskładniki ∗
wyrażenie
✲ składnik
+ ✛
− ✛
✲
Wykład 17: powtórka, str. 43
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi::=hSi hWi + hSi hWi hWi - hSi
hSi::=hCi hSi * hCi hCi hSi / hCi
hCi::=hLi ( hWi )
hLi::=0
1
hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi::=hSi
nn
o
o
+ − hSi ∗
hSi::=hCi
nn
o
o
∗ / hCi ∗
hCi::=( hWi ) hLi
n o n o
hLi::= 0 1
0 1 ∗
Wykład 17: powtórka, str. 44
Parser zstępujący bez nawrotów
Przykład:
hmiarai::=hodległośći
n o n hwagai
o
M hodległośći::=n0 . . . 9o n0 . . . 9o ∗ m
hwagai::= 0 . . . 9 0 . . . 9 ∗ kg
hmiarai
⇒
hodległośći
hmiarai
⇒
hwagai
⇒∗
⇒∗
11111m
11111kg
Do którego nieterminala redukować? — nie da się postanowić na podstawie
pierwszej cyfry, bo nie wiadomo jeszcze, czy na końcu będzie m czy kg.
Parsery zstępujące nadają się nie do wszystkich
gramatyk bezkontekstowych;
nadają się tylko do t.zw. gramatyk LL(1).
Wykład 17: powtórka, str. 45
Rozbiór wstępujący — gramatyki z pierwszeństwem
Rozbiór wstępujący — budujemy drzewo rozbioru od liści.
W ciągu symboli wejściowych musimy znaleźć
podstawę czyli uchwyt najbliższej redukcji, czyli
podciąg który zostanie zredukowany w pierwszym
kroku.
hMi ::= a ( hMi a )
a
Następnie dokonujemy redukcji.
(.... hMi a.....
Znowu wyszukujemy podstawę.
I dokonujemy redukcji.
)....
...
.
.
.
.
..
...
.
.
.
.
.
...
. ..
....
.. .........
.......
.
........................
.
hMi
..a
).....
....
...
.
.
.
.
..
...
....
...
....
.
.
.
.
.
..
..
......
....
......
...........
........................................................................
(.....
Te kroki powtarzamy aż do skonstruowania całego drzewa.
hMi
W jaki sposób znajdujemy podstawę redukcji?
Wykład 17: powtórka, str. 46
Rozbiór wstępujący — gramatyki z pierwszeństwem
W jaki sposób znajdujemy podstawę redukcji?
Relacje wpisane w tablicę związane są z kolejnością
redukowania poszczególnych symboli:
.
• jeśli x = y to symbole x i y będą się redukować
razem (jeśli stoją koło siebie i jeden należy do
podstawy, to drugi też);
• jeśli x ⋖ y to symbol x powinien zaczekać, aż y
zostanie zredukowany (jeśli stoją koło siebie i y
należy do podstawy, to x nie należy do podstawy);
• jeśli x ⋗ y to symbol y powinien zaczekać, aż x
zostanie zredukowany (jeśli stoją koło siebie i x
należy do podstawy, to y nie należy do podstawy);
• jeśli nie ma między nimi żadnej relacji, to nie
powinny stać obok siebie (jeśli stoją koło siebie,
to jest to błąd).
hMi ::= a ( hMi a )
Tablica pierwszeństwa redukcji:
(
hMi
a
)
( hMi a )
.
⋖ = ⋖
.
=
.
⋗ =
⋗
Wykład 17: powtórka, str. 47
Rozbiór wstępujący — gramatyki z pierwszeństwem
W jaki sposób znajdujemy podstawę redukcji?
hMi ::= a ( hMi a )
a
Tablica pierwszeństwa redukcji:
(.... hMi a.....
(.....
)....
...
.
.
..
.
...
.
.
.
.
.
...
.. ..
....
.. ..........
.......
.
.
.........................
(
hMi
a
)
hMi
.
..a
)....
....
...
.
.
.
.
..
...
....
...
....
.
.
.
.
.
..
......
..
......
....
..........
...........................................................................
hMi
( hMi a )
.
⋖ = ⋖
.
=
.
⋗ =
⋗
• Jak skonstruować tablicę pierwszeństw?
• Dla jakich gramatyk da się to zrobić?
Wykład 17: powtórka, str. 48
Konstrukcja tablic pierwszeństwa
Niech G = hΣ, N, P, Si będzie gramatyką bezkontekstową.
DEFINICJA:
M
Niech A ∈ N .
n
o
n
o
fst A def
= x ∈ Σ ∪ Nn istnieje w P jakaś produkcjao A → xv
S
fst+ A def
fst+ B B ∈ N & B ∈ fst A
= fst A ∪
A → wx
lst A def
= x ∈ Σ ∪ Nn istnieje w P jakaś produkcja
o
S
lst+ B B ∈ N & B ∈ lst A
lst+ A def
= lst A ∪
Przykład: M
hMi ::= a ( hMi a )
—
fst hMi = {a, (}
—


fst hMi
Przykład:
)
hMi ::= a hQi a )
M
hQi ::= ( hMi
= {a, hQi}
fst hMi = {a, hQi} ∪ fst+ hQi


= {a, hQi, (}
+
Wykład 17: powtórka, str. 49
Konstrukcja tablic pierwszeństwa
Niech G = hΣ, N, P, Si będzie gramatyką bezkontekstową.
DEFINICJA:
.
M
Relacje =, ⋖, ⋗ w Σ ∪ N określone są następująco:
.
def
x = y ⇐⇒
w P istnieje produkcja A → wxyv
x ⋖ y ⇐⇒ w P istnieje produkcja A → wxBv
taka że y ∈ fst+ B
A
def
. . . x B. . .
y. . .
def
x ⋗ y ⇐⇒
A
w P istnieje produkcja A → wByv
taka że x ∈ lst+ B
. . . B y. . .
...x
lub
A
w P istnieje produkcja A → wBCv
taka że x ∈ lst+ B i y ∈ fst+ C
. . . B C. . .
. . . x y. . .
Wykład 17: powtórka, str. 50
Zakres stosowalności gramatyk z pierwszeństwem
Przykład: hWi ::= hSi hWi + hSi
M
hSi ::= ℓ ( hWi )
Ponieważ ( i hWi sąsiadują w tej samej
.
produkcji, więc ( = hWi.
Ponieważ hWi ∈ fst+ hWi , więc ( ⋖ hWi.
Dla tej gramatyki nie da się więc skonstruować tablicy pierwszeństwa.
Przykład: hAi ::= a hBi a
M
hBi ::= a
Nie wiadomo, do jakiego nieterminalu redukować a.
Dla tej gramatyki nie da się zastosować analizy z
pierwszeństwem.
DEFINICJA:
M
Gramatyka bezkontekstowa G = hΣ, N, P, Si jest gramatyką z pierwszeństwem jeśli
• dla każdych dwóch symboli x, y ∈ Σ ∪ N , zachodzi najwyżej jeden ze
.
związków x = y, x ⋖ y, x ⋗ y (może nie zachodzić żaden),
• nie istnieją dwie różne produkcje o tej samej prawej stronie, ani produkcja o pustej prawej stronie: hAi → λ.
Wykład 17: powtórka, str. 51
Poprawianie na gramatykę z pierwszeństwem
Przykład:
M
hWi ::= hSi hWi + hSi
hSi ::= ℓ ( hWi )
hWi hSi + ℓ ( )
.
.
=
=
⋗
⋗
.
⋖ ⋖
=
⋗
⋗
.
=⋖ ⋖
⋖ ⋖
⋗
⋗
hWi
hSi
+
ℓ
(
)
hWi hSi +
hWi ::= hVi hVi ::= hSi hVi + hSi
hSi ::= ℓ ( hWi )
hWi
hSi
+
ℓ
(
)
hVi
.
=
ℓ
(
⋗
⋖ ⋖
⋗
.
=
hVi
)
.
=
⋗
⋗
⋖
⋖ ⋖
⋗
.
=
⋖
⋗
⋗
Wykład 17: powtórka, str. 52
Użycie tablicy pierwszeństwa do rozbioru
hWi
hWi
hSi
+
ℓ
(
)
hWi ::= hVi hVi ::= hSi hVi + hSi
hSi ::= ℓ ( hWi )
.
=
.
=
hVi
⋖
. .
⋖ =
=
STOS:
⋗
.....................
hVi + hSi
.....
hSi
ℓ
(
...
...
.
hWi ).
hVi
hVi + hSi
hSi
ℓ
ℓ
hSi
+
ℓ
(
⋗
⋖
⋖
⋗
⋖
⋗
.
=
⋖
hVi
⋖
⋗
⋖
)
.
=
⋗
⋖
⋖
⋗
⋖
⋖
⋗
⋖
⋗
⋗
⋗
⋗
⋗
⋗
⋗
⋖
WEJŚCIE: ℓ + ( ℓ + ℓ ) + ℓ Zakończenie pracy:
Na stosie: tylko i jedno drzewo z nieterminalem początkowym w korzeniu.
Na wejściu: tylko .
Wykład 17: powtórka, str. 53
Użycie tablicy pierwszeństwa do rozbioru
inicjalizacje ();
do {
switch (pierwszenstwo [szczyt_stosu()][leks]) {
case nieokr:
blad ("Te symbole nie moga wystepowac obok siebie: ",
znak_z_symb (szczyt_stosu()), znak_z_symb (leks));
break;
case mniejsze:
case rowne:
drz = drzewo_z_terminalu (leks); na_stos (drz);
nast_leks();
break;
case wieksze: redukcja(); break;
}
}
while (wys_stosu != 2 || szczyt_stosu() != wyr || leks != pusty);
drz = ze_stosu (); drukuj_drzewo (drz);
Wykład 17: powtórka, str. 54
Wykonanie redukcji
hWi ::= hVi hVi ::= hSi hVi + hSi
hSi ::= ℓ ( hWi )
• zdejmujemy ze stosu symbole między ⋖ and ⋗;
• wyszukujemy właściwą produkcję za pomocą
automatu skończonego zbudowanego wg gramatyki;
• wkładamy na stos nieterminal z lewej strony tej
produkcji.
hWi → hVi
hVi → hVi+hSi
V2
✛
hVi
3
✛
+
hVi → hSi
hSi → ℓ
hSi → (hWi)
S2
✛
(
2
✛
hWi
W
✛
hVi
V1
✛
hSi
S1
✛
ℓ
1
✛
)
✛
Wykład 17: powtórka, str. 55
Gramatyki z pierwszeństwem — podsumowanie
• Bezpośrednia wstępująca konstrukcja drzewa wywodu z użyciem stosu.
• Zalety:
– prostota;
– o wiele szybsze działanie i mniejsza zajętość pamięci niż w rozbiorach zstępujących;
– możliwość dobrej sygnalizacji błędów.
• Wady:
– konieczność poprawienia gramatyki przez dodanie nowych nieterminali i produkcji — czasem bardzo wielu.
Wykład 17: powtórka, str. 56
PAMIĘĆ
Programowanie niskiego poziomu
rejestr
arytmetyczny
(akumulator)
0
1
2
3
4
5
6
7
8
9
10
11
· · ·
n
• adresowana (czyli numerowana) pamięć złożona z komórek, z których każda może pomieścić bajt; dla
uproszczenia zakładam, że nie bajt
tylko liczbę całkowitą;
• rejestr arytmetyczny także mogący
pomieścić liczbę całkowitą; większość
operacji odbywa się między rejestrem
arytmetycznym a komórką pamięci;
• komendy (patrz niżej) są kodowane
liczbami całkowitymi i wpisywane do
komórek pamięci.
Wykład 17: powtórka, str. 57
PAMIĘĆ
Programowanie niskiego poziomu
0
1
2
3
4
5
6
7
8
9
10
11
rejestr
arytmetyczny
(akumulator)
e
r
o
... ✛
...s....t............................... ..✒
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
......
..✙
...
loadn
......
.
.
.
.
.
.
........d. a KOMENDY PRZESYŁANIA:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
........................ loa
loadn n — załaduj do akumulatora
liczbę n
loada n — załaduj do akumulatora
liczbę z komórki
o adresie n
store n — zapamiętaj zawartość
akumulatora w kom.
o adresie n
· · ·
load = ładować
store = przechowywać, magazynować
n
Wykład 17: powtórka, str. 58
PAMIĘĆ
Programowanie niskiego poziomu
0
1
2
3
4
5
6
7
8
9
10
11
rejestr
arytmetyczny
(akumulator)
....... ....
...............✲
....
....
..............................
.. add KOMENDY ARYTMETYCZNE:
.
.
.
.... sub
..........................
add n — dodaj do akumulatora
mul
liczbę z kom. o adresie n;
wynik w akumulatorze
sub n — odejmij od akumulatora
liczbę z kom. o adresie n;
wynik w akumulatorze
mul n — pomnóż akumulator przez
liczbę z kom. o adresie n;
wynik w akumulatorze
· · ·
n
add = dodawać
subtract = odejmować
multiply = mnożyć
Wykład 17: powtórka, str. 59
PAMIĘĆ
Programowanie niskiego poziomu
0
1
2
3
4
5
6
7
8
9
10
11
rejestr
arytmetyczny
(akumulator)
........................ incr
.
.
.
.
.
.
.
.
.
.
... ....
..✙
....... ... decr
............
KOMENDY DZIAŁAŃ
NA KOMÓRKACH:
incr n — powiększ o 1 zawartość
kom. o adresie n
decr n — zmniejsz o 1 zawartość
kom. o adresie n
increment = zwiększać
decrement = zmniejszać
· · ·
n
Wykład 17: powtórka, str. 60
PAMIĘĆ
Programowanie niskiego poziomu
0
1
2
3
4
5
6
7
8
9
10
11
rejestr
arytmetyczny
(akumulator)
komenda
KOMENDY SKOKÓW:
komenda
.........
komenda ..✛
goto n
— przejdź do komórki
... goto
.
...
o adresie n
komenda
..zergoto
zergoto n — jeśli w akumul. zero,
.
komenda
..plsgoto
.
to przejdź do kom.
komenda
.. mingoto
.
.
.
o adresie n
skok ........
plsgoto n — jeśli akum. dodatni,
komenda
to przejdź do kom.
komenda
mingoto n
—
stop
—
· · ·
n
go to = idź do
o adresie n
jeśli akum. ujemny,
to przejdź do kom.
o adresie n
zatrzymaj działanie
Wykład 17: powtórka, str. 61
Programowanie niskiego poziomu
Prosty adres komendy:
liczba całkowita oznaczająca
• albo samą liczbę,
np. loadn 500 oznacza: załaduj do akumulatora liczbę 500;
• albo adres komórki, której dotyczy komenda,
np. loada 500 oznacza: załaduj do akumulatora liczbę z komórki 500.
Modyfikowany adres komendy:
postaci n+[k] — adres n modyfikowany zawartością komórki o adresie k,
należy tą zawartość do adresu n dodać.
Np. jeśli pod adresem 500 stoi liczba 1, to komenda add 200+[500]
oznacza: dodaj do akumulatora zawartość komórki 201;
a jeśli pod adresem 500 stoi liczba 5, to ta sama komenda add 200+[500]
oznacza: dodaj do akumulatora zawartość komórki 205.
Wykład 17: powtórka, str. 62
Organizacja pamięci
Przykład:
M
void sil(int n, int* w)
{
int w1;
if (n==0) *w = 1;
else
{
sil(n-1,&w1); *w = n*w1;
}
}
s
sil(3,&s);
n ❑ w
w1
3
n
w ✕ w1
2
n
w ✕ w1
1
n
0
w ✕ w1