Hallo Welt für Fortgeschrittene - Lehrstuhl für Informatik 2

Hallo Welt für Fortgeschrittene
Parsen
Andreas Hammer
Informatik 2  Programmiersysteme  Martensstraße 3  91058 Erlangen
Inhalt
 Einführung
 Theoretische Grundlagen
□ Grammatiken im Allgemeinen
□ Die Chomsky-Hierarchie
□ Die Chomsky-Normalform für kontextfreie Grammatiken
 Vorgehensweisen beim Parsen
□ Bottom-Up-Parsing
 CYK-Algorithmus
□ Top-Down-Parsing
 Allgemeines Prinzip
 Rekursiver Abstiegsparser
 Ein- und Ausgabe in Java, C und C++
 Reguläre Ausdrücke
 Zusammenfassung
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 2/80
Einführung
 Definition des Begriffs „Parser“:
Ein Parser ist ein Computerprogramm, das in der Informatik für die
Zerlegung und Umwandlung einer beliebigen Eingabe in ein für
die Weiterverarbeitung brauchbares Format zuständig ist.
 Beispiele für Parser:
□ Compiler von Programmiersprachen
□ TeX/LaTeX
□ Intelligente Suche
 z.B. „Wie wird morgen das Wetter?“
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 3/80
Einführung - Compiler
 Vereinfachte Funktionsweise:
□ 1. Analysephase
 Lexikalische Analyse (Zerteilung des Textes in Token)
 Syntaktische Analyse
▫ Überprüfung, ob Syntax „stimmt“, dem Standard entspricht
▫ Umwandlung in Syntaxbaum, Analyse mit Parser
▫ Fehler, falls Syntaxprüfung oder Analyse nicht funktioniert (der Code
nicht korrekt ist)
 Semantische Analyse („Macht der Code Sinn?“), weitere Sprachbedingungen prüfen
□ 2. Synthesephase
 Zwischenprodukte (Header inkludieren, Makros einfügen, …)
 Optimierung (wenn gewünscht)
 Endprodukt (Maschinencode) erzeugen
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 4/80
Einführung - Syntaxbaum
 Beispiel für den Syntaxbaum einer natürlichen Sprache
□ „Grammatik“ ist hier, was man klassisch unter Grammatik versteht
Satz
Subjekt
Prädikat
Artikel
Substantiv
Verb
Die
Katze
schläft
□ Erforschung der Struktur von Sprachen u.a. durch Noam
Chomsky (Chomsky-Hierarchie)
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 5/80
Inhalt
 Einführung
 Theoretische Grundlagen
□ Grammatiken im Allgemeinen
□ Die Chomsky-Hierarchie
□ Die Chomsky-Normalform für kontextfreie Grammatiken
 Vorgehensweisen beim Parsen
□ Bottom-Up-Parsing
 CYK-Algorithmus
□ Top-Down-Parsing
 Allgemeines Prinzip
 Rekursiver Abstiegsparser
 Ein- und Ausgabe in Java, C und C++
 Reguläre Ausdrücke
 Zusammenfassung
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 6/80
Theoretische Grundlagen - Grammatiken
 Eine formale Grammatik G = (V, Σ, P, S) besteht aus
□
□
□
□
V: endliche, nichtleere Menge von Variablen
Σ: endliche, nichtleere Menge von Terminalen
S: Startsymbol, S ∈ V
P: endliche Menge von Produktionen der Form
((V ∪ Σ) + \ Σ*) x (V ∪ Σ)*
Anschaulich: Menge von Ableitungsregeln P → Q, wobei
 P aus mindestens einer Variable und optional Terminalen und
 Q aus beliebig vielen Variablen und Terminalen
besteht.
 Allgemeinster Typ: Chomsky-0-Grammatik
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 7/80
Theoretische Grundlagen – Chomsky-Hierarchie (1)
 Hierarchische Klassifikation von Grammatiken, erstmals
1956 durch Noam Chomsky beschrieben
 Unterschied der Hierarchiestufen:
zunehmend stärkere Einschränkungen für die Form
zulässiger Produktionen
 Grammatik G = (V, Σ, P, S)
□ Chomsky-0: wie auf vorheriger Folie
□ Chomsky-1, „kontextsensitiv“:
 Wie Chomsky-0, zusätzlich:
 ∀ (u → v) ∈ P: |u| ≤ |v|
 Erweiterung: S → ε erlaubt, wenn S nie rechts vorkommt
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 8/80
Theoretische Grundlagen – Chomsky-Hierarchie (2)
□ Chomsky-2, „kontextfrei“ (für uns interessant):
 Wie Chomsky-1, zusätzlich:
 Links darf nur eine Variable stehen
□ Chomsky-3, „regulär“:
 Wie Chomsky-2, zusätzlich:
 Alle Produktionen haben die Form
▫
▫
▫
▫
A → aB (rechtsregulär) oder A → Ba (linksregulär)
A→a
A→ε
für A, B ∈ V, a ∈ Σ
□ Im Folgenden: Details der kontextfreien Grammatik
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 9/80
Theoretische Grundlagen - Beispiel
 Beispiel für eine kontextfreie Grammatik:
□ G = (V, Σ, P, S) mit
 V = {A, T, F}
 Σ = {1, 2, 3, 4}
 P:
▫ A→T|A+T
▫ T→F|T*F
▫ F → 1 | 2 | 3 | 4 | (A)
 S=A
□ Erzeugt mathematische Ausdrücke mit Zahlen 1-4, Operatoren
Plus und Mal, wertet diese in der richtigen Reihenfolge aus,
und lässt Klammerung zu
→ Tafel
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 10/80
Theoretische Grundlagen – Chomsky-Normalform
 Für die Anwendung bestimmter Algorithmen muss die
Grammatik in einer dafür geeigneten Normalform vorliegen.
Für CYK: Chomsky-Normalform
 Definition: Eine kontextfreie Grammatik ist in ChomskyNormalform (CNF), wenn jede Regel in der Form
□ A → BC oder
□ A→a
□ S→ε
ist, mit A ∈ V, B, C ∈ V \ {S} und a ∈ Σ.
 Jede kontextfreie Grammatik kann in eine CNF umgewandelt
werden.
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 11/80
Theoretische Grundlagen – Chomsky-Normalform
 Algorithmus zur Umformung einer kontextfreien Grammatik
in CNF:
1. Eliminiere ε-Produktionen
2. Für jedes Terminalsymbol a: Führe eine neue Variable Aa und
eine neue Regel Aa → a ein; ersetze alle Vorkommen von a
durch Aa
3. Eliminiere Kettenregeln
4. Löse Regeln mit mehr als 2 Variablen auf der rechten Seite auf
5. Entferne unerreichbare und unproduktive Variablen
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 12/80
Theoretische Grundlagen – CNF-Umformung (1)
 Elimination von ε-Produktionen:
□ Entferne alle Regeln der Form A → ε
□ Für jede Regel, die auf A abbildet, füge weitere Regel hinzu, in
der A gestrichen wurde
□ Ausnahme: Falls Startsymbol auf ε abbildet (S → ε)
 In diesem Fall: Füge neues Startsymbol S' ein und neue Regeln:
 S' → ε und S' → S

□ Beispiel:
S → A, A → BC, B → b | ε, C → c
→ Tafel
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 13/80
Theoretische Grundlagen – CNF-Umformung (1)
 Elimination von ε-Produktionen:
□ Entferne alle Regeln der Form A → ε
□ Für jede Regel, die auf A abbildet, füge weitere Regel hinzu, in
der A gestrichen wurde
□ Ausnahme: Falls Startsymbol auf ε abbildet (S → ε)
 In diesem Fall: Füge neues Startsymbol S' ein und neue Regeln:
 S' → ε und S' → S

□ Beispiel:
S → A, A → BC, B → b | ε, C → c
wird umgeformt zu:
S → A, A → BC | C, B → b, C → c
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 14/80
Theoretische Grundlagen – CNF-Umformung (2)
 Für jedes Terminalsymbol a:
Einführung einer neuen Variable Aa und einer neuen Regel
Aa → a; ersetze alle Vorkommen von a durch Aa
□ Ziel: Entfernung „gemischter“ Produktionen, die rechts
Terminale und Nicht-Terminale enthalten
□ Beispiel: A → Ab wird zu A → AAb, Ab → b
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 15/80
Theoretische Grundlagen – CNF-Umformung (3)
 Elimination von Kettenregeln:
□ Ziel: Entfernung von Regeln, die später zur Endlosrekursion
führen würden („im Kreis laufen“)
□ Konstruiere Graph aus Regeln, suche darin nach Zyklen
□ Ersetze bei jedem Zyklus die zugehörigen Variablen durch genau
eine davon, ersetze alle Vorkommen der ersetzten Variable durch
die „genau eine“ (S darf nicht ersetzt werden).
□ Ersetze zum Schluss die übrigen Kettenregeln durch die Regeln
A → „alle rechten Seiten“
 Beispiel:
A → BC | E
E → XZ | F
F→A|Z
Z → aE
→
A → BC | A
A → XZ | A
A→A|Z
Z → aE
→
A → BC | XZ | aE
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 16/80
Theoretische Grundlagen – CNF-Umformung (4)
 Auflösung von Regeln mit mehr als 2 Variablen auf der
rechten Seite
□ Vorgehen: Ersetze so lange jeweils 2 benachbarte Symbole AB
auf der rechten Seite durch neue Var. X, füge neue Regel X →
AB hinzu, bis keine Regeln mit mehr als 2 Variablen mehr
existieren
 Beispiel:
A → BCDEF
→ Tafel
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 17/80
Theoretische Grundlagen – CNF-Umformung (4)
 Auflösung von Regeln mit mehr als 2 Variablen auf der
rechten Seite
□ Vorgehen: Ersetze so lange jeweils 2 benachbarte Symbole AB
auf der rechten Seite durch neue Var. X, füge neue Regel X →
AB hinzu, bis keine Regeln mit mehr als 2 Variablen mehr
existieren
 Beispiel:
A → BCDEF
→
A → XDEF, X → AB
→
A → YEF, Y → XD, X → AB
→
A → ZF, Z → YE, Y → XD, X → AB
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 18/80
Theoretische Grundlagen – CNF-Umformung (5)
 Entferne unerreichbare und unproduktive Variablen
(Reduzieren der CNF)
□ Unerreichbar:
 Variablen, die vom Startsymbol aus nie erreicht werden können
 Regeln, deren linke Seite eine unerreichbare Variable ist, kann
ohne Veränderung der Sprache entfernt werden
□ Unproduktiv:
 Variablen, deren Anwendung nie zu einem Wort der Sprache
führen kann
 Diese Regeln können (und sollen) ebenso entfernt werden
 Grammatik ist nun in CNF und reduziert → Bereit für die
Algorithmen
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 19/80
Inhalt
 Einführung
 Theoretische Grundlagen
□ Grammatiken im Allgemeinen
□ Die Chomsky-Hierarchie
□ Die Chomsky-Normalform für kontextfreie Grammatiken
 Vorgehensweisen beim Parsen
□ Bottom-Up-Parsing
 CYK-Algorithmus
□ Top-Down-Parsing
 Allgemeines Prinzip
 Rekursiver Abstiegsparser
 Ein- und Ausgabe in Java, C und C++
 Reguläre Ausdrücke
 Zusammenfassung
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 20/80
Vorgehensweisen beim Parsen
 Bottom-Up-Parsing
□ „von unten nach oben“, für gegebenes Wort wird geprüft, ob es
der Grammatik entspricht
□ Algorithmus: CYK
 Top-Down-Parsing
□ „von oben nach unten“, wende Regeln der Grammatik an,
versuche daraus das Wort zu bilden
□ Mögliche Umsetzung: Rekursiver Abstiegsparser (RDP)
 Beide Male Backtracking möglich, aber nicht performant
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 21/80
Bottom-Up-Parsing – Der CYK-Algorithmus
 Cocke-Younger-Kasami-Algorithmus
Da fehlt doch
Magenta!
□ Unabhängig voneinander in den 1960er Jahren entwickelt
□ Beantwortet die Frage w ∈ L(G)? für kontextfreie Sprachen mit
Wortlänge n und Anzahl Produktionen P in
 Laufzeit
 Platz
O(n3 * |P|)
O(n2 * |P|)
□ Idee:
 Aufteilen des Wortes in Fragmente, die von Produktionen erzeugt
werden → Tafel
 Einzelne Terminale können direkt hergeleitet werden
 Backtracking → Ausprobieren aller Möglichkeiten
 Kann durch Dynamische Programmierung beschleunigt werden
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 22/80
Bottom-Up-Parsing – Der CYK - Algorithmus
 Pseudocode des Algorithmus:
Für i = 1 … n
Für jede Produktion (l → r) ∈ P
Falls r = wi
Setze Vi,1 := Vi,1 ∪ {l}
vi,j: Variablen, aus denen
wi...wj hergeleitet werden
Für d = 2 … n
Für i = 1 … n – d
kann
Setze j := i + d
Für k = 1 … j – 1
Für jedes (B ∈ Vi,k und C ∈ Vk+1,j)
Wenn (l → BC ∈ P)
Vi,j := Vi,j ∪ {l}
Wenn S ∈ V1,n
→ Wort ist enthalten
Sonst
→ Wort ist nicht enthalten
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 23/80
Bottom-Up-Parsing – Der CYK - Algorithmus
 Beispiel:
□ Grammatik:
S → AB|BC
B → CC|b
A → BA|a
C → AB|a
□ Zu prüfendes Wort: ?
□ → Tafel
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 24/80
Bottom-Up-Parsing – Der CYK - Algorithmus
 Beispiel:
□ Grammatik:
S → AB|BC
B → CC|b
A → BA|a
C → AB|a
□ Zu prüfendes Wort: babab
b
a
b
a
b
{B}
{A,C}
{B}
{A,C}
{B}
{S,A}
{S,C}
{S,A}
{S,C}
{S,C}
{B}
{S,C}
{B}
{B}
{B}
□ S ∉ V1,5 → babab ∉ L(G)
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 25/80
Inhalt
 Einführung
 Theoretische Grundlagen
□ Grammatiken im Allgemeinen
□ Die Chomsky-Hierarchie
□ Die Chomsky-Normalform für kontextfreie Grammatiken
 Vorgehensweisen beim Parsen
□ Bottom-Up-Parsing
 CYK-Algorithmus
□ Top-Down-Parsing
 Allgemeines Prinzip
 Rekursiver Abstiegsparser
 Ein- und Ausgabe in Java, C und C++
 Reguläre Ausdrücke
 Zusammenfassung
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 26/80
Top-Down-Parsing
 Gleiches Problem, „umgekehrte“ Lösung
 Arbeitet „von oben nach unten“
□ Tiefensuche: oben → unten, links → rechts
□ Versuche, Regeln der Grammatik anzuwenden, um zu
prüfenden Satz zu bilden
 Grammatik darf keine Linksrekursion enthalten, sonst
Endlosrekursion
 Laufzeit: O(nn)
□ Normal für Backtracking-Algorithmen
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 27/80
Top-Down-Parsing
 Operationen eines Top-Down-Parsers:
□ Expand
Für gefundene Variable eine Regel der Grammatik anwenden
z.B. X → ab (Vorkommen von X mit ab ersetzen)
□ Scan
Vergleiche Ableitungssymbol mit Eingabesymbol
(„Wurde das gleiche Wort gebildet?“)
Wenn gleich: Weiter expanden, wenn nicht:
□ Backtrack
gehe Schritt zurück, versuche nächste Möglichkeit
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 28/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
 Operation:
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 29/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
VP
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 30/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
VP
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 31/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
VP
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 32/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
VP
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
 Operation:
Scan
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 33/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
VP
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 34/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
VP
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze
 Operation:
Scan
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 35/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 36/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze jagt
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 37/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze jagt
 Operation:
Backtrack
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 38/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 39/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst
 Operation:
Scan
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 40/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst
 Operation:
Scan
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 41/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze
 Operation:
Backtrack
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 42/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
NP
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 43/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
NP
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze jagt
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 44/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
NP
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze jagt
 Operation:
Backtrack
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 45/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
NP
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 46/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
V
NP
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst
 Operation:
Scan
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 47/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 48/80
N
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst Die
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 49/80
N
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst die
 Operation:
Backtrack & Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 50/80
N
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst die
 Operation:
Scan
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 51/80
N
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst die Katze
 Operation:
Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 52/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst die Maus
 Operation:
Backtrack & Expand
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 53/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)?
Die
Katze frisst die Maus
 Operation:
Scan
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 54/80
Top-Down-Parsen (Demo)
 Grammatik:
□
□
□
□
□
□
S → NP VP
NP → DET N
VP → V | V NP
DET → Die | die | den
N → Katze | Maus
V → jagt | frisst
S
NP
DET
N
VP
NP
V
DET
N
 Frage:
□ „Die Katze frisst die Maus“
∈ L(G)!
Die
Katze frisst die Maus
 Operation:
Fertig
Die Katze frisst die Maus
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 55/80
Top-Down-Parsen – Rekursiver Abstiegsparser
 Wie setzt man das um?
□ Recursive Descent Parser
 Erinnerung: Grammatik darf keine Linksrekursion besitzen!
□ Regeln der Form S → Sb können aber leicht umgewandelt
werden:
 A → AX|Y wird zu
A → YA'
A' → XA' | ε
 Grundprinzip der Implementierung:
□ Pro Produktion eine eigene Funktion, die nur diese Produktion
prüft
□ Besonders schön für Grammatiken, bei denen man nicht
backtracken muss
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 56/80
Top-Down-Parsen – Rekursiver Abstiegsparser
 Beispiel:
S → AB
A → a | aB
B → b | ba
„Eine Funktion pro Regel“
pos = Position im Wort
len = Länge des Wortes
accept = Globales Flag
 Code:
fun S() {
//S → A
A(); B();
if(pos != len) {
accept = false;
}
}
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 57/80
Top-Down-Parsen – Rekursiver Abstiegsparser
 Code (weiter):
fun A() {
//A → a | aB
if(matches('a')) {
pos++;
if(pos != len) {
B();
}
} else {
accept = false;
}
}
fun B() {
//B → b | ba
if(matches('b')) {
pos++;
if(pos != len) {
if(matches('a')) {
pos++;
} else {
accept = false;
}
}
} else {
accept = false;
}
}
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 58/80
Inhalt
 Einführung
 Theoretische Grundlagen
□ Grammatiken im Allgemeinen
□ Die Chomsky-Hierarchie
□ Die Chomsky-Normalform für kontextfreie Grammatiken
 Vorgehensweisen beim Parsen
□ Bottom-Up-Parsing
 CYK-Algorithmus
□ Top-Down-Parsing
 Allgemeines Prinzip
 Rekursiver Abstiegsparser
 Ein- und Ausgabe in Java, C und C++
 Reguläre Ausdrücke
 Zusammenfassung
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 59/80
Ein- und Ausgabe in Java, C und C++
 Gleiches Schema bei Aufgaben
□ Einlesen von stdin
□ Algorithmen anwenden
□ Ausgeben auf stdout
 Zu lesende und verändernde Daten können groß werden
□ Aufgabe „Class Exercise“ (SS1):
 6.666.666 Zahlen einlesen, 10.000 Anfragen auf die Daten
□ Problem: Effiziente Ein- und Ausgabemechanismen benötigt
Bei großen Datenmengen ist C/C++ besser geeignet als Java
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 60/80
Ein- und Ausgabe in Java
 Einlesen
□ BufferedReader (in java.io.*)
 Initialisierung:
BufferedReader in = new BufferedReader(new
InputStreamReader(System.in));
 Wichtige Methoden:
▫ public int read();
Liest einzelnes Zeichen, gibt bei EOF -1 zurück.
„Wie getc in C.“
▫ public String readLine();
Liest ganze Zeile ein. Newline ist \r, \n oder \r\n
▫ public int read(char[] cbuf, int off, int len)
Schreibt bis zu len Chars nach cbuf+off.
„Wie fgets in C.“
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 61/80
Ein- und Ausgabe in Java
 Einlesen
□ StringTokenizer (in java.util.*)
 Zur Weiterverarbeitung eines eingelesenen Strings („einer Zeile“)
 Initialisierung:
StringTokenizer st = new StringTokenizer(String str,
String delim);
 Wichtige Methoden:
▫ int countTokens();
Gibt die Anzahl der verbleibenden Tokens zurück
▫ boolean hasMoreTokens();
Gibt es verbleibende Tokens? (z.B. Prüfung in while-Schleife)
▫ string nextToken();
Gibt den nächsten Token zurück
▫ ...und viele mehr
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 62/80
Ein- und Ausgabe in Java
 Einlesen
□ Scanner (in java.util.*)
 Noch komfortabler, aber langsamer (reicht trotzdem für fast alle
Aufgaben aus)
 Initialisierung:
Scanner in = new
Scanner(System.in).useLocale(Locale.ENGLISH);
 Wichtige Methoden:
▫ public boolean hasNext[Int, Float, Double, Long]();
Gibt es einen nächsten Int-, Float-, …-Wert?
▫ public int nextInt(), float nextFloat(), …
Gib den nächsten Int-, Float-, …-Wert zurück
▫ public String nextLine();
Gibt komplette Zeile zurück
▫ public String next();
Gibt nächstes Token als String zurück
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 63/80
Ein- und Ausgabe in Java
 Ausgabe
□ System.out.print($ausgabe)
 $ausgabe kann alles sein, was toString() implementiert, nicht nur
primitive Datentypen
 Konkatenieren mit +, Automatisches \n mit System.out.println();
 Beispiel: System.out.print(„Das ist “ + 1 + „ Test“);
□ System.out.printf(String format, $ausgabe);
 Ähnlich wie printf in C
 Formatstring enthält Anweisungen, wie Argumente in $ausgabe
ausgeben werden sollen
 Beispiele: %d = int, %f = float, %.2f = float mit 2 Nachkommastellen, %c = char, %x = int als Hex, ...
 z.B. System.out.printf(„%d, %f, %x“, 1337, 13.37, 51966); gibt
aus: „1337, 13.37, cafe“
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 64/80
Ein- und Ausgabe in C/C++
 Einlesen
□ int scanf(const char *format, … );
(#include <cstdio> / <stdio.h>)
 Ignoriert Whitespace (' ', '\t', '\n')
 Liest Zeichen an im Formatstring angegebenen Stellen
automatisch in Variablen ein, Rest der Zeichen muss genau so
vorkommen
 Falls anderer Stream als stdin:
int fscanf(FILE *stream, const char *format, …);
 Beispiel:
scanf(„%d - %f“, &a, &b);
Bei Eingabe „42 – 13.37“ steht danach in a 42, in b 13.37
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 65/80
Ein- und Ausgabe in C/C++
 Einlesen
□ char *fgets(char *s, int size, FILE *stream);
 Liest, bis size Zeichen oder '\n' erreicht sind/ist nach s
 Buffer s muss groß genug sein!
□ char *strtok(char *str, const char *delim);
 Zerlegung von str bei jedem Vorkommen von delim
 Erster Aufruf: strtok(zuSplittenderString, delim);
 Alle nachfolgenden: strtok(NULL, delim);
 Gibt NULL zurück, wenn kein weiterer Token gefunden wurde
 Weiterverarbeitung z.B. mit atoi (String → int) oder atof (String →
float
 Vorsicht! strtok macht den String „kaputt“!
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 66/80
Ein- und Ausgabe in C/C++
 Einlesen (C++)
□ cin
(#include <iostream>)
□ Benutzung:
cin >> var1 >> var2 >> …;
varX kann z.B. int, double, long, char u.s.w. sein
□ Komfortabler, aber etwas langsamer als scanf oder fgets + strtok
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 67/80
Ein- und Ausgabe in C/C++
 Ausgabe
□ int printf(const char *format, …)
Benutzung wie in Java mit Formatstring und Argumenten
□ putc, puts, fputc, fputs
 putc(int c): gibt einzelnen Char auf stdout aus
 puts(char *s): gibt Char-Array (String) auf stdout aus
 fputc(int c, FILE *stream),
fputs(char *s, FILE *stream): das gleiche mit beliebigen
Streams
 Schneller als printf
□ Nur in C++: cout
 Benutzung: cout << var1 << var2 << …;
 Wie cin, nur eben Ausgabe
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 68/80
Ein- und Ausgabe - Zeitmessung
 5000 x 5000 Integer-Matrix einlesen und ausgeben (in Sekunden)
40
35
30
25
worst
avg
best
20
15
10
5
0
fgets
scanf
cin/cout
Java BufferedReader
Java Scanner
Gcc 4.9.2 / javac 1.7.0_51 auf Quad i5 @ 3.3GHz, Debian x86_64, Kernel 3.18.9
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 69/80
Inhalt
 Einführung
 Theoretische Grundlagen
□ Grammatiken im Allgemeinen
□ Die Chomsky-Hierarchie
□ Die Chomsky-Normalform für kontextfreie Grammatiken
 Vorgehensweisen beim Parsen
□ Bottom-Up-Parsing
 CYK-Algorithmus
□ Top-Down-Parsing
 Allgemeines Prinzip
 Rekursiver Abstiegsparser
 Ein- und Ausgabe in Java, C und C++
 Reguläre Ausdrücke
 Zusammenfassung
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 70/80
Reguläre Ausdrücke
 Regulärer Ausdruck = Zeichenkette, die die Struktur einer
Zeichenkette beschreibt. Dagegen kann dann „gematched“
werden
 Beschreibt die regulären Sprachen (Chomsky-3)
 Zum Filtern oder „erkennen“ von Texten geeignet, weit
flexibler als nur z.B. strtok & atoi
 In Java in der String-Klasse enthalten:
String text = “2015“;
if(text.matches(“[0-9]+“)) {//text ist eine Zahl}
[0-9]+ bedeutet „Es komme mindestens einmal ein Zeichen
aus dem Bereich '0'-'9' vor“
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 71/80
Reguläre Ausdrücke in Java
 Beispiele:
□ [0-9][0-35-9]
 Ziffer von 0-9, gefolgt von einer Ziffer von 0-3 oder 5-9
□ [3-5][a-zA-Z]?
 Ziffer […], optional gefolgt von Groß- oder Kleinbuchstabe
□ [0-9]*[a-z]+
 Keine oder beliebig viele Ziffern, gefolgt von mindestens einem
Buchstaben
□ Das .*Test
 Beliebige, beliebig viele Zeichen zwischen Leerzeichen und T
▫ z.B. „Das ist ein Test“, „Das Test“, „Das Herpaderp Test“, …
□ [^a-e]
 Negation, beliebiges Zeichen außer a-e
□ Römer geht (nach Haus|in das Haus)
 Zusammenfassen von Zeichenfolgen
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 72/80
Reguläre Ausdrücke in Java
 Alternative in Java: Matcher-Klasse
□ Zuerst Reg. Ausdruck zu Pattern umwandeln:
Pattern p = Pattern.compile(String regexp);
□ Danach Matcher-Objekt erzeugen:
Matcher m = p.matcher(String input)
□ Damit sind folgende Methoden möglich:
 bool matches():
 bool find():
 int start():
Matcht kompletten input-String
Versucht, einen Teilstring von input auf das
Muster zu matchen
Gibt Index des ersten passenden chars
zurück
 etc.
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 73/80
Reguläre Ausdrücke in C++11 und Python
 C++11:
□ bool regex_match(string search, string regex):
 Sucht Matches von regex in search, gibt bei Erfolg true zurück
□ bool regex_search(string search, string regex):
 Wie match, aber sucht nach Substrings und matcht diese
□ string regex_replace(string search, string regex,
string replace):
 Ersetzt jedes Vorkommen von regex in search durch replace
 Python:
□ re-Modul, ähnlich wie Matcher in Java:
import re
matcher = re.compile(„RegExp“)
match = matcher.match(„Suchstring“)
 Match ist None, wenn nichts gefunden wurde, oder lässt durch
match.group() bzw. match.groups() auf gefundene(n) String(s) zugreifen
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 74/80
Inhalt
 Einführung
 Theoretische Grundlagen
□ Grammatiken im Allgemeinen
□ Die Chomsky-Hierarchie
□ Die Chomsky-Normalform für kontextfreie Grammatiken
 Vorgehensweisen beim Parsen
□ Bottom-Up-Parsing
 CYK-Algorithmus
□ Top-Down-Parsing
 Allgemeines Prinzip
 Rekursiver Abstiegsparser
 Ein- und Ausgabe in Java, C und C++
 Reguläre Ausdrücke
 Zusammenfassung
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 75/80
Zusammenfassung
 Wichtig für das Verständnis:
Theoretisches Hintergrundwissen
□ Formale Grammatiken (→ Chomsky-Hierarchie)
□ Umformung nach CNF, um div. Algorithmen anwenden zu
können





Entfernen von ε-Produktionen
Neue Terminalregeln
Entfernen von Kettenregeln
Auflösen „längerer“ Regeln
Ziel: Nur noch Regeln der Form
▫
▫
▫
▫
▫
S→ε
A→b
A → Bb
B→c
…
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 76/80
Zusammenfassung
 Bottom-Up-Parsing
□ Fange mit Wort an, finde heraus, wie es entstanden sein
könnte
□ CYK-Algorithmus
 Vorher: Grammatik nach CNF umwandeln
 Laufzeit: O(n3)
 Top-Down-Parsing
□ Fange mit Startsymbol an, versuche Wort zu bilden
→ Backtracking („Trial and Error“)
□ Rekursive Abstiegsparser
 Jede Regel in Funktion umwandeln
 Linksrekursion vermeiden
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 77/80
Zusammenfassung
 Ein-/Ausgabe in Java, C und C++
□
□
□
□
Java im Vergleich am Langsamsten
Bequemste Variante zum Einlesen: java.util.Scanner
Schnellste Variante: fgets + strtok
Schnellste Ausgabe: putc, printf reicht aber fast immer aus
 Reguläre Ausdrücke
□ Flexibler und komfortabler
□ In Java mit Matcher- oder String-Klasse
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 78/80
Ende
Vielen Dank für eure Aufmerksamkeit!
Fragen?
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 79/80
Literaturhinweise
 Mitschrift zur Vorlesung „Berechenbarkeit und Formale
Sprachen“, Prof. Rolf Wanka, WS14/15
 Vortrag „Parsen“, Andreas Ruprecht, 2011
 C/C++ Reference (http://www.cppreference.com/wiki/)
 Java 7 API (http://docs.oracle.com/javase/7/docs/api/)
 Folien zu „Theoretische Informatik“, Uni Mannheim
(http://th.informatik.uni-mannheim.de/teach/Ti-0809/9/ueb/add/CYK-2.pdf )
 Wikipedia (Regulärer Ausdruck, CYK-Algorithmus)
 TopCoder Forums
(http://apps.topcoder.com/forums/?module=Thread&threadID=697463&start=0&mc=14)
 Theoretische Informatik, Ingo Wegener, Teubner Verlag, 3.
Auflage, 2005
 Python Dokumentation (https://docs.python.org)
Hallo Welt für Fortgeschrittene  Parsen  Andreas Hammer  Folie 80/80