Upload
others
View
18
Download
0
Embed Size (px)
Citation preview
Parsing mitBacktracking
Vorlesung “Computerlinguistische Techniken” Alexander Koller
20. Oktober 2015
Kontextfreie GrammatikenT = {Hans, isst, Käsebrot, ein} N = {S, NP, VP, V, N, Det}; Startsymbol: S
Produktionsregeln:S → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Ableitung Parsebaum
S ⇒ NP VP ⇒ Hans VP⇒ Hans V NP ⇒ Hans isst NP⇒ Hans isst Det N⇒ Hans isst ein N⇒ Hans isst ein Käsebrot
S
VP
NP
N
Kasebrot
Det
ein
V
isst
NP
Hans
S
VP
PP
NP
N
pyjamas
PRP$
my
P
in
VP
NP
N
elephant
Det
an
IV
shot
NP
I
S
VP
NP
N
PP
NP
N
pyjamas
PRP$
my
P
in
N
elephant
Det
an
IV
shot
NP
I
1
Parsing
• Gegeben seien eine kfG G und ein Wort w.
• Das Wortproblem ist die Frage, ob w ∈ L(G) ist. Wortproblem wird von Erkenner gelöst.
• Das Parsingproblem ist das Problem, alle Parsebäume von w bzgl. G zu bestimmen.Parsingproblem wird von Parser gelöst.
Parsing: Beispiele
S → a S b S → a b
Ist aabb ∈ L(G)?Wenn ja, was sind die Parsebäume?
G
Parsing: Beispiele
S → a S b S → a b
Ist abab ∈ L(G)?Wenn ja, was sind die Parsebäume?
G
Parsing: Beispiele
S → S S S → a
Ist aaa ∈ L(G)? Wenn ja, was sind die Parsebäume?
G
Parsing: Beispiele
Ist aaaa ∈ L(G)?Wenn ja, was sind die Parsebäume?
S → S S S → a
Ist aaa ∈ L(G)? Wenn ja, was sind die Parsebäume?
G
Recursive-Descent-Parsing
• Wie löst man das Wort- und das Parsingproblem so systematisch, dass man es implementieren kann?
• Ein erster Ansatz für Parsing: Recursive Descent. (Wir lösen hier nur das Wortproblem.)
• Wir nehmen an, dass kfGs in Chomsky-Normalform (CNF) sind: Jede Regel ist von der Form A → B C oder A → a.
Recursive-Descent-Parsing
• Rekursiver Algorithmus, der für A und w die Frage “A ⇒* w?” entscheidet.
w
Recursive-Descent-Parsing
• Rekursiver Algorithmus, der für A und w die Frage “A ⇒* w?” entscheidet.
A?
w
Recursive-Descent-Parsing
• Rekursiver Algorithmus, der für A und w die Frage “A ⇒* w?” entscheidet.
A?
A → B C
w
Recursive-Descent-Parsing
• Rekursiver Algorithmus, der für A und w die Frage “A ⇒* w?” entscheidet.
A?
A → B C
w
Recursive-Descent-Parsing
• Rekursiver Algorithmus, der für A und w die Frage “A ⇒* w?” entscheidet.
A?
A → B CB?
w
w1
Recursive-Descent-Parsing
• Rekursiver Algorithmus, der für A und w die Frage “A ⇒* w?” entscheidet.
A?
A → B CB? C?
w
w1 w2
Recursive-Descent-Parsing
• Der Algorithmus sieht so aus: ‣ Wir wollen wissen, ob A ⇒* w ist.
‣ Wenn w ∈ T und es eine Regel A → w gibt, gib “ja” zurück, sonst “nein”.
‣ Rate eine Regel A → B C, die wir anwenden wollen.
‣ Rate eine Zerlegung w = w1 w2.
‣ Wenn sowohl B ⇒* w1 als auch C ⇒* w2 “ja” gesagt haben, gib “ja” zurück, sonst “nein”.
RD-Parsing: Ein BeispielS → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
A ⇒* a ?
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
A ⇒* a ? B ⇒* b c ?
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
A ⇒* a ? B ⇒* b c ?(ja, da A → a)
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
A ⇒* a ? B ⇒* b c ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
A ⇒* a ? B ⇒* b c ?(ja, da A → a)
✓(nein: es gibt keine
binären Regeln für B)
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
A ⇒* a ? B ⇒* b c ?(ja, da A → a)
✓(nein: es gibt keine
binären Regeln für B)
✗
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?(versuche abc = a· bc, S → A B)
A ⇒* a ? B ⇒* b c ?(ja, da A → a)
✓(nein: es gibt keine
binären Regeln für B)
✗
✗
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein BeispielS → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
S → A B S → A C
A → a C → B C
B → bC → c
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?(versuche bc = b· c, C → B C)
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?(versuche bc = b· c, C → B C)
B ⇒* b ? C ⇒* c ?
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?
(ja, da B → b)
(versuche bc = b· c, C → B C)
B ⇒* b ? C ⇒* c ?
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?
(ja, da B → b)✓
(versuche bc = b· c, C → B C)
B ⇒* b ? C ⇒* c ?
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?
(ja, da B → b)✓
(versuche bc = b· c, C → B C)
B ⇒* b ?(ja, da C → c)C ⇒* c ?
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?
(ja, da B → b)✓
(versuche bc = b· c, C → B C)
B ⇒* b ?(ja, da C → c)
✓C ⇒* c ?
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?
(ja, da B → b)✓
(versuche bc = b· c, C → B C)
B ⇒* b ?(ja, da C → c)
✓C ⇒* c ?
✓
RD-Parsing: Ein Beispiel
S ⇒* a b c ?
A ⇒* a ?(ja, da A → a)
✓
S → A B S → A C
A → a C → B C
B → bC → c
(versuche abc = a· bc, S → A C)
C ⇒* b c ?
(ja, da B → b)✓
(versuche bc = b· c, C → B C)
B ⇒* b ?(ja, da C → c)
✓C ⇒* c ?
✓
✓
Zwei Beobachtungen
• Der RD-Algorithmus ist rekursiv:Um A ⇒* w zu testen, überprüfen wir B ⇒* w1 und C ⇒* w2.
• Der RD-Algorithmus ist nichtdeterministisch: Er “rät” Regeln und Stringzerlegungen. ‣ Implementierung auf echtem Computer muss deshalb alle
Möglichkeiten der Reihe nach durchprobieren.
‣ Revidiert dabei Entscheidungen aus früheren rekursiven Aufrufen -> Backtracking.
Pseudocode
function S(w, i, k): for j = i+1, ..., k-1 do if NP(w, i, j) and VP(w, j, k) then return true else return false end if end for
function NP(w, i, k): if k = i + 1 and w(i) = “Hans” then return true else return false end if
Pseudocode
function S(w, i, k): for j = i+1, ..., k-1 do if NP(w, i, j) and VP(w, j, k) then return true else return false end if end for
function NP(w, i, k): if k = i + 1 and w(i) = “Hans” then return true else return false end if
S ⇒* wi … wk-1 ?
Pseudocode
function S(w, i, k): for j = i+1, ..., k-1 do if NP(w, i, j) and VP(w, j, k) then return true else return false end if end for
function NP(w, i, k): if k = i + 1 and w(i) = “Hans” then return true else return false end if
S ⇒* wi … wk-1 ?
NP ⇒* wi … wj-1 ?
Pseudocode
function S(w, i, k): for j = i+1, ..., k-1 do if NP(w, i, j) and VP(w, j, k) then return true else return false end if end for
function NP(w, i, k): if k = i + 1 and w(i) = “Hans” then return true else return false end if
S ⇒* wi … wk-1 ?
NP ⇒* wi … wj-1 ?
VP ⇒* wj … wk-1 ?
Pseudocode
function S(w, i, k): for j = i+1, ..., k-1 do if NP(w, i, j) and VP(w, j, k) then return true else return false end if end for
function NP(w, i, k): if k = i + 1 and w(i) = “Hans” then return true else return false end if
S ⇒* wi … wk-1 ?
NP ⇒* wi … wj-1 ?
VP ⇒* wj … wk-1 ?
NP ⇒* wi … wk-1 ?
Pseudocode
function S(w, i, k): for j = i+1, ..., k-1 do if NP(w, i, j) and VP(w, j, k) then return true else return false end if end for
function NP(w, i, k): if k = i + 1 and w(i) = “Hans” then return true else return false end if
S ⇒* wi … wk-1 ?
NP ⇒* wi … wj-1 ?
VP ⇒* wj … wk-1 ?
NP ⇒* wi … wk-1 ?
ja falls wi … wk-1 = Hans
Korrektheit und Vollständigkeit
• Warum sollen wir glauben, dass RD-Erkenner für alle Eingaben das richtige Ergebnis liefert?
• Wir müssen beweisen: ‣ Korrektheit: RD-Erkenner behauptet w ∈ L(G) nur dann,
wenn es auch wahr ist.
‣ Vollständigkeit: Wenn w ∈ L(G) ist, dann behauptet das der RD-Erkenner auch.
Probleme und Algorithmen
• Problem: Funktion von irgendwelchen Eingaben zu {0,1}. ‣ Wortproblem von kfGs: gegeben Eingabe (G,w),
gib 1 aus gdw w in L(G), sonst 0.
• Algorithmus: abstrakte Berechnungsvorschrift, die das Problem löst. ‣ RD-Erkenner ist Algorithmus für das Wortproblem.
• Algorithmen kann man in Programmiersprachen implementieren.
Probleme und Algorithmen
Wortproblem(G,w) = 1gdw w ∈ L(G)
Problem
Algorithmus
Programm
function S(w, i, k): for j = i+1, ..., k-1 do if NP(w, i, j) and VP(w, j, k) then return true else return false end if end for
Beweistechnik
• Korrektheit und Vollständigkeit von Parsingalgo. beweist man typischerweise mit vollständiger Induktion: ‣ Korrektheit: … über Länge der Berechnung des Algorithmus
‣ Vollständigkeit: … über Länge der Ableitung.
• Vollständige Induktion: ‣ Zeige, dass Aussage für n = 0 (oder n = 1) wahr ist.
‣ Zeige: Wenn Aussage für beliebiges n wahr ist, dann ist sie auch für n+1 wahr.(alternativ: sei n beliebig, und nimm an, dass Aussage für alle k ≤ n wahr ist),
‣ Daraus folgt dann: Aussage für alle n ≥ 0 (bzw. n ≥ 1) wahr.
Korrektheit des RD-Erkenners
• Korrektheit: Wenn RD-Erkenner w ∈ L(G) behauptet, dann ist es auch wahr.
• Zeige stärkere Aussage: Wenn RD-Erkenner A ⇒* w behauptet, ist das wahr. (Daraus folgt Korrektheit.)
• Induktion über die Länge n der Berechnung (= Anzahl der rekursiven Aufrufe): ‣ Fall n = 1: Algo. hat ohne rekursiven Aufruf direkt “ja” gesagt.
Dann war das, weil es Regel A → w gibt, also ist A ⇒* w.
Korrektheit des RD-Erkenners
• Zeige stärkere Aussage: Wenn RD-Erkenner A ⇒* w behauptet, ist das wahr. (Daraus folgt Korrektheit.) ‣ Fall n → n+1: Algo. hat “ja” gesagt und dabei im ersten Schritt
w = w1 w2 zerlegt und Regel A → B C angewendet, und rekursive Aufrufe B ⇒* w1 und C ⇒* w2 waren beide “ja”.
‣ Rekursive Berechnungen waren beide kürzer: kB, kC ≤ n. Wegen Induktionsannahme gilt deshalb: B ⇒* w1 und C ⇒* w2 sind beide wahr.
‣ Deshalb ist auch A ⇒* w wahr, nämlich wie folgt: A ⇒ B C ⇒* w1 C ⇒* w1 w2 = w.
Vollständigkeit des RD-Erkenners
• Vollständigkeit: Wenn w ∈ L(G) wahr ist, dann behauptet es der RD-Erkenner auch.
• Zeige stärkere Aussage: Wenn A ⇒* w wahr ist, dann sagt RD-Erkenner “ja”. (Daraus folgt Vollständigkeit.)
• Induktion über die Länge n der Ableitung A ⇒* w:
‣ Fall n = 1: A ⇒ w, es gibt also Regel A → w. RD-Erkenner sagt ohne rekursiven Aufruf “ja”.
Vollständigkeit des RD-Erkenners
• Vollständigkeit: Wenn w ∈ L(G) wahr ist, dann behauptet es der RD-Erkenner auch. ‣ Fall n → n + 1: Es gilt A ⇒* w. Diese Ableitung beginnt mit
einem ersten Schritt, A ⇒ B C ⇒* w1 C ⇒* w1 w2 = w.
‣ RD-Erkenner überprüft alle Zerlegungen von w, also insbesondere auch A → B C und w = w1 w2.
‣ Die Ableitungen B ⇒* w1 und C ⇒* w2 haben beide weniger als n Schritte. Nach Induktionsannahme sagt RD-Erkenner für beide rekursive Aufrufe deshalb “ja”.
‣ Daher sagt RD-Erkenner auch für A ⇒*w “ja”.
Top-Down vs. Bottom-Up
• Parser kann den Parsebaum top-down oder bottom-up zu berechnen versuchen.
top-down(z.B. Recursive Descent)
bottom-up
S
VP
NP
N
Kasebrot
Det
ein
V
isst
NP
Hans
S
VP
PP
NP
N
pyjamas
PRP$
my
P
in
VP
NP
N
elephant
Det
an
IV
shot
NP
I
S
VP
NP
N
PP
NP
N
pyjamas
PRP$
my
P
in
N
elephant
Det
an
IV
shot
NP
I
1
S
VP
NP
N
Kasebrot
Det
ein
V
isst
NP
Hans
S
VP
PP
NP
N
pyjamas
PRP$
my
P
in
VP
NP
N
elephant
Det
an
IV
shot
NP
I
S
VP
NP
N
PP
NP
N
pyjamas
PRP$
my
P
in
N
elephant
Det
an
IV
shot
NP
I
1
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
NP
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
NP V
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
NP DetV
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
NP DetV N
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
NP DetV N
NP
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
NP DetV N
NP
VP
Bottom-Up-ParsingS → NP VPNP → Det NVP → V NP
V → isstNP → Hans
Det → einN → Käsebrot
Hans isst ein Käsebrot.
NP DetV N
NP
VP
S
Bottom-up-ParsingS → S S S → a
aa a
Bottom-up-ParsingS → S S S → a
aa a
S
Bottom-up-ParsingS → S S S → a
a
S
a a
S
Bottom-up-ParsingS → S S S → a
a
S S
a a
S
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
S
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
S
aa a
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
S
a
S
a a
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
S
a
S S
a a
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
S
a
S S
S
a a
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
S
a
S S
S
a a
S
Bottom-up-ParsingS → S S S → a
a
S S
S
a a
S
S
a
S S
S
a a
S
S
Shift-Reduce-Parsing
Hans isst ein
NP V
Hans isst ein
NP V Det
Hans isst ein Käsebrot.
NP DetV N
Hans isst ein Käsebrot.
NP DetV N
NP
Shift: nächstes Terminalsymbol lesen
Reduce: Regel auf letzte offene Symbole anwenden
Shift-Reduce-Parsing
• Wir verwenden als Datenstruktur einen Stack von Terminal- und Nichtterminalsymbolen.
• Ein Stack ist eine Liste, in der ich nur an einem Ende (“oben”) lesen und schreiben kann.
• Unser Stack enthält die unverarbeiteten Terminal- und Nichtterminalsymbole. Schreibweise: in Stack s1 s2 s3 ist s3 “oben”.
NP NPVP
NP Spush pop pop push
Shift-Reduce-Parsing
• Shift-Regel:(s, a⋅w) → (s⋅a, w)
• Reduce-Regel:(s⋅w’, w) → (s⋅A, w) falls A → w’ in P
• Start: (ε, w)
• Wende Regeln nichtdeterministisch an. Algorithmus sagt “ja”, wenn er Konfiguration (S, ε) erreicht (d.h. erreichen kann).
Shift-Reduce: Beispiel
Hans isst ein Käsebrot.
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.)
Hans isst ein Käsebrot.
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.)
Hans isst ein Käsebrot.
NP
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)
Hans isst ein Käsebrot.
NP
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.)
Hans isst ein Käsebrot.
NP V
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.)
Hans isst ein Käsebrot.
NP V
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.) → (NP V ein, K.)
Hans isst ein Käsebrot.
NP DetV
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.) → (NP V ein, K.)→ (NP V Det, K.)
Hans isst ein Käsebrot.
NP DetV
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.) → (NP V ein, K.)→ (NP V Det, K.) → (NP V Det K., ε)
Hans isst ein Käsebrot.
NP DetV N
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.) → (NP V ein, K.)→ (NP V Det, K.) → (NP V Det K., ε) → (NP V Det N, ε)
Hans isst ein Käsebrot.
NP DetV N
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.) → (NP V ein, K.)→ (NP V Det, K.) → (NP V Det K., ε) → (NP V Det N, ε)→ (NP V NP, ε)
Hans isst ein Käsebrot.
NP DetV N
NP
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.) → (NP V ein, K.)→ (NP V Det, K.) → (NP V Det K., ε) → (NP V Det N, ε)→ (NP V NP, ε) → (NP VP, ε)
Hans isst ein Käsebrot.
NP DetV N
NP
VP
Shift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
(ε, Hans isst ein K.) → (Hans, isst ein K.) → (NP, isst ein K.)→ (NP isst, ein K.) → (NP V, ein K.) → (NP V ein, K.)→ (NP V Det, K.) → (NP V Det K., ε) → (NP V Det N, ε)→ (NP V NP, ε) → (NP VP, ε) → (S, ε)
Hans isst ein Käsebrot.
NP DetV N
NP
VP
SShift: (s, a⋅w) → (s⋅a, w)Reduce: (s⋅w’, w) → (s⋅A, w)
Shift-Reduce: Beispiel
a
S S
S
a a
S
S
(ε, aaa)→ (a, aa) → (S, aa)→ (Sa, a) → (SSa, ε)→ (SSS, ε) → (SS, ε) → (S, ε)
→ (SS, a)
a
S S
S
a a
S
S
(ε, aaa)→ (a, aa) → (S, aa)→ (Sa, a) → (SS, a) → (S, a)→ (Sa, ε) → (SS, ε) → (S, ε)
S → S S S → a
Shift-Reduce: Korrektheit
• Zeige: ‣ wenn Shift-Reduce-Berechnung (s,w) →* (s’,w’) existiert,
‣ dann gibt es kfG-Ableitung s’w’ ⇒* sw.
• Daraus folgt dann Korrektheit: ‣ SR-Erkenner behauptet w ∈ L(G)
‣ gdw (ε, w) →* (S, ε)
‣ daher S ⇒* w (s.o.)
‣ d.h. w ∈ L(G) ist wahr.
(s,w) →* (s’,w’) ⇒ s’w’ ⇒* sw
• n = 0: sw ⇒* sw trivial
• n → n+1: Betrachte ersten Schritt von (s,w) →* (s’,w’) ‣ erster Schritt shift: (s, aw) → (sa, w) →* (s’,w’)
es gilt: s’w’ ⇒* sa⋅w ⇒* s⋅aw
‣ erster Schritt reduce: (sw’, w) → (sA, w) →* (s’,w’)es gilt: s’w’ ⇒* sAw ⇒ sw’w
Induktion über Länge n der Berechnung (d.h. Anzahl der Shift- und Reduce-Schritte)
IA
IA
Shift-Reduce: Vollständigkeit
• Zeige: ‣ wenn kfG-Ableitung A ⇒* w existiert mit w ∈ T*,
‣ dann gibt es SR-Berechnung (ε, w) →* (A, ε)
• Daraus folgt dann Vollständigkeit: ‣ w ∈ L(G) gilt
‣ gdw kfG-Ableitung S ⇒* w existiert mit w ∈ T*
‣ dann gibt es SR-Berechnung (ε, w) →* (S, ε) (s.o.)
‣ also behauptet SR-Erkenner, dass w ∈ L(G) gilt.
A ⇒* w ⇒ (ε, w) →* (A, ε)
• n = 1: d.h. A → w ∈ P, also (ε, w) → (w, ε) → (A, ε)
• n → n+1: d.h. A ⇒ B C ⇒* B w2 ⇒* w1 w2 = w
‣ IA1: (ε, w1) →* (B, ε); daher auch (ε, w1 v) →* (B, v)
‣ IA2: (ε, w2) →* (C, ε); daher auch (u, w2) →* (u C, ε)
‣ also: (ε, w1 w2) →* (B, w2) →* (B C, ε) → (A, ε)
Induktion über Länge n der kfG-Ableitung(für CNF-Grammatiken; allgemeiner Fall nur mehr Schreibarbeit)
s
rIV1
r
IV2
Probleme: Übersicht
• Parsertypen haben komplementäre Probleme:
• Allgemein nicht zu vermeiden (Ambiguität).
top-down bottom-up
Regeln raten A → w1 vs. A → w2
A → w vs. B → w
Zerlegung raten String aufteilen Shift vs. Reduce entscheiden
Zusammenfassung
• Bottom-up vs. Top-down: ‣ top-down: Recursive Descent
‣ bottom-up: Shift-Reduce
• Korrektheit und Vollständigkeit
• Beide Parsertypen haben komplementäre Probleme beim Parsing verschiedener Grammatiken.