1
Grundlagen der Programmierung
Compiler: Parser (5C)
Prof. Dr. Manfred Schmidt-Schauß
Sommersemester 2017
Syntaktische Analyse (Parsen)
Gegeben: eine kontextfreie Grammatik G und ein String w.
Fragen: (1) gehort w zu L(G)?(2) Welchen Syntaxbaum hat w?(3) Welche Bedeutung hat w?
Vorgehen: Konstruiere Herleitungsbaum zu w
Grundlagen der Programmierung 2 Parser – 2/61 –
Syntaktische Analyse eines Programms
Gegeben: Syntax einer Programmierspracheund der Quelltext eines Programms.
Fragen: Ist das Programm syntaktisch korrekt?Was soll dieses Programm bewirken?
Aufgabe: Ermittle”Bedeutung“ des Programms,
Konstruktionsverfahren fur Herleitungsbaume(bzw. Syntaxbaume)
Grundlagen der Programmierung 2 Parser – 3/61 –
Syntaktische Analyse bzgl einer CFG
• Fur jede CFG gibt es einen Parse-Algorithmusmit worst case Laufzeit O(n3)
(n : Anzahl der Eingabesymbole)CYK: Cocke, Younger, Kasami,
falls Grammatik in Chomsky-Normalform(Alle Regeln von der Form N →W mit |W | ≤ 2
oder Earley-Algorithmus
• CYK benutzt dynamisches Programmieren.erzeugt eine Tabelle:pro Paar (N,w) von Nichtterminal N und Subwort w der Eingabeein Eintrag True wenn N →∗
G w, sonst False
Grundlagen der Programmierung 2 Parser – 4/61 –
Syntaktische Analyse bzgl einer CFG
Praxis: Fur jede Programmiersprachegibt es einen Parser, der effizient arbeitet,
d.h. in O(n), oder in O(n ∗ log(n))
Grundlagen der Programmierung 2 Parser – 5/61 –
Parse-Methoden und Beschrankungen
Beschrankung in dieser Vorlesung auf
• einfach implementierbare oder effiziente Parser
• Nur fur eingeschrankte CFGs
• Verarbeitung des Zeichenstroms bzw. des Eingabewortesvon links nach rechts
• evtl. auch mit Vorausschau um einige Zeichen.
Grundlagen der Programmierung 2 Parser – 6/61 –
Parse-Methoden: Vorgehensweisen:
Top-Down: Es wird versucht eine Herleitung vorwarts,vom Startsymbol der Grammatik aus, zu bilden(”forward-chaining“)
Bottom-Up: Es wird versucht eine Herleitung ruckwarts,vom Wort aus, zu bilden; bis das Startsymbol derGrammatik erreicht ist. (
”backward-chaining“).
Grundlagen der Programmierung 2 Parser – 7/61 –
Parse-Methoden: Vorgehensweisen:
Weiteres Unterscheidungsmerkmal:
R : Konstruktion einer Rechtsherleitung
L : Konstruktion einer Linksherleitung
Gangige Kombinationsmoglichkeiten:
• Top-Down-Verfahren zur Konstruktion einer Linksherleitung• Bottom-Up-Verfahren zur Konstruktion einer Rechtsherleitung
Grundlagen der Programmierung 2 Parser – 8/61 –
Beispiel
S ::= ABA ::= 0 | 1B ::= 8 | 9
Frage: Kann”09“ aus dieser Grammatik hergeleitet werden?
Grundlagen der Programmierung 2 Parser – 9/61 –
09-Beispiel: Top-down:
Start mit Startsymbol SRate die Produktionen;
Nutze den zu parsenden String zur SteuerungBilde RestproblemZiel: Eingabestring bis zum Ende verarbeiten.
Grundlagen der Programmierung 2 Parser – 10/61 –
Beispiel
S ::= ABA ::= 0 | 1B ::= 8 | 9
Eingabe 09
09 9 ε
(N + T )∗-Wort S
AB B
Herleitung S
→ AB → 0B → 09
Das ergibt eine Linksherleitung.
Beachte”09“ wird von links nach rechts bearbeitet
Jedes Eingabezeichen bestimmt eindeutig die Produktion
Grundlagen der Programmierung 2 Parser – 11/61 –
Beispiel
S ::= ABA ::= 0 | 1B ::= 8 | 9
Eingabe 09 09
9 ε
(N + T )∗-Wort S AB
B
Herleitung S → AB
→ 0B → 09
Das ergibt eine Linksherleitung.
Beachte”09“ wird von links nach rechts bearbeitet
Jedes Eingabezeichen bestimmt eindeutig die Produktion
Grundlagen der Programmierung 2 Parser – 11/61 –
Beispiel
S ::= ABA ::= 0 | 1B ::= 8 | 9
Eingabe 09 09 9
ε
(N + T )∗-Wort S AB BHerleitung S → AB → 0B
→ 09
Das ergibt eine Linksherleitung.
Beachte”09“ wird von links nach rechts bearbeitet
Jedes Eingabezeichen bestimmt eindeutig die Produktion
Grundlagen der Programmierung 2 Parser – 11/61 –
Beispiel
S ::= ABA ::= 0 | 1B ::= 8 | 9
Eingabe 09 09 9 ε
(N + T )∗-Wort S AB BHerleitung S → AB → 0B → 09
Das ergibt eine Linksherleitung.
Beachte”09“ wird von links nach rechts bearbeitet
Jedes Eingabezeichen bestimmt eindeutig die Produktion
Grundlagen der Programmierung 2 Parser – 11/61 –
09-Beispiel: Bottom-up:
Vorgehen: Regeln ruckwarts auf den Eingabestring anwenden;das Startsymbol der Grammatik ist zu erreichen!
09
← A9 ← AB ← S anders geschrieben:
S→ AB→ A9→ 09Eine Rechtsherleitung wurde konstruiert
Beachte: Manchmal sind mehrere Regeln anwendbarzudem muss man i.a. den Teilstring raten,auf den eine Produktion (ruckwarts) anzuwenden ist
Im Beispiel: Gleicher Herleitungsbaum
S
�� ��A
��
B
��0 9
Grundlagen der Programmierung 2 Parser – 12/61 –
09-Beispiel: Bottom-up:
Vorgehen: Regeln ruckwarts auf den Eingabestring anwenden;das Startsymbol der Grammatik ist zu erreichen!
09 ← A9
← AB ← S anders geschrieben:
S→ AB→ A9→ 09Eine Rechtsherleitung wurde konstruiert
Beachte: Manchmal sind mehrere Regeln anwendbarzudem muss man i.a. den Teilstring raten,auf den eine Produktion (ruckwarts) anzuwenden ist
Im Beispiel: Gleicher Herleitungsbaum
S
�� ��A
��
B
��0 9
Grundlagen der Programmierung 2 Parser – 12/61 –
09-Beispiel: Bottom-up:
Vorgehen: Regeln ruckwarts auf den Eingabestring anwenden;das Startsymbol der Grammatik ist zu erreichen!
09 ← A9 ← AB
← S anders geschrieben:
S→ AB→ A9→ 09Eine Rechtsherleitung wurde konstruiert
Beachte: Manchmal sind mehrere Regeln anwendbarzudem muss man i.a. den Teilstring raten,auf den eine Produktion (ruckwarts) anzuwenden ist
Im Beispiel: Gleicher Herleitungsbaum
S
�� ��A
��
B
��0 9
Grundlagen der Programmierung 2 Parser – 12/61 –
09-Beispiel: Bottom-up:
Vorgehen: Regeln ruckwarts auf den Eingabestring anwenden;das Startsymbol der Grammatik ist zu erreichen!
09 ← A9 ← AB ← S anders geschrieben:
S→ AB→ A9→ 09Eine Rechtsherleitung wurde konstruiert
Beachte: Manchmal sind mehrere Regeln anwendbarzudem muss man i.a. den Teilstring raten,auf den eine Produktion (ruckwarts) anzuwenden ist
Im Beispiel: Gleicher Herleitungsbaum
S
�� ��A
��
B
��0 9
Grundlagen der Programmierung 2 Parser – 12/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002
002 02 2
NT-Wort S
A A A
Herleitung S
A 0A 00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002
002 02 2
NT-Wort S
B B B
Herleitung S
B 0B 00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002
02 2
NT-Wort S A
A A
Herleitung S A
0A 00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002
002 02 2
NT-Wort S
B B B
Herleitung S
B 0B 00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002 02
2
NT-Wort S A A
A
Herleitung S A 0A
00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002
002 02 2
NT-Wort S
B B B
Herleitung S
B 0B 00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002 02 2
NT-Wort S A A AHerleitung S A 0A 00A
? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002
002 02 2
NT-Wort S
B B B
Herleitung S
B 0B 00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002 02 2
NT-Wort S A A AHerleitung S A 0A 00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002
002 02 2
NT-Wort S
B B B
Herleitung S
B 0B 00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002 02 2
NT-Wort S A A AHerleitung S A 0A 00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002 002
02 2
NT-Wort S B
B B
Herleitung S B
0B 00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002 02 2
NT-Wort S A A AHerleitung S A 0A 00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002 002 02
2
NT-Wort S B B
B
Herleitung S B 0B
00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002 02 2
NT-Wort S A A AHerleitung S A 0A 00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002 002 02 2
NT-Wort S B B BHerleitung S B 0B 00B
002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Suche nach der Herleitung
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Kann”002“ hergeleitet werden?
Ziel 002 002 02 2
NT-Wort S A A AHerleitung S A 0A 00A ? Sackgasse
”002“ kann nur aus B hergeleitet werden:
Ziel 002 002 02 2
NT-Wort S B B BHerleitung S B 0B 00B 002
Grundlagen der Programmierung 2 Parser – 13/61 –
Beispiel: Bemerkungen
S ::= A | BA ::= 0A | 1B ::= 0B | 2
Ein deterministischer Top-Down-Parsermuss beim ersten Zeichen von
”002“ entscheiden,
ob A, oder B.
Diese Wahl kann falsch sein.
Misslingt eine Herleitung, so muss der Parser zurucksetzen:
”Backtracking“
Grundlagen der Programmierung 2 Parser – 14/61 –
Parsemethoden
Wir betrachten im folgenden:
rekursiv absteigende Parser:
Allgemeineoptimierte: rekursiv-pradiktive Parser (LL-Parser)
Bottom-Up-Parser (LR-Parser)
Grundlagen der Programmierung 2 Parser – 15/61 –
Struktur eines rekursiv absteigenden Parsers
• Top-Down bzgl. der Grammatik.
• Eingabewort von links nach rechts
• Backtracking, falls Sackgasse
• Konstruktion einer Linksherleitung
Grundlagen der Programmierung 2 Parser – 16/61 –
Struktur eines rekursiv absteigenden Parsers
• Pro Nichtterminal N wird ein Parser PN programmiert.Eingabe: String (bzw. Tokenstrom)Ausgabe: Syntaxbaum zum Prefix der Eingabe; und Reststring
• N → w1 | . . . | wn (das sind alle Regeln zu N)PN probiert alle wi aus
• Prufung, ob ein wi passt:wi = wi1wi2 . . . wim von links nach rechts durchgehenJeweils Parser Pwij aufrufen und Reststring weitergeben
I.a. rekursiver Aufruf, falls wij Nichtterminal.
Grundlagen der Programmierung 2 Parser – 17/61 –
Eigenschaften: rekursiv-absteigender Parser
• Liefert alle Linksherleitungen fur alle Prafixe des Tokenstroms(wenn der Parser terminiert)
• Leicht implementierbar• Leicht erweiterbar auf weitere Einschrankungen• I.a. exponentiell oder sogar:• Terminiert nicht fur linksrekursive Grammatiken,
obwohl eine Herleitung existiert:Beispiel A ::= A+A | A-A | 1 | . . . | 9Eingabe: 1+1 : Aber: nur die erste Regel wird (jeweils rekursiv)versucht:(A,1+1) → (A+A,1+1) → ((A+A)+A, 1+1) → . . .
Grundlagen der Programmierung 2 Parser – 18/61 –
Rekursiv-absteigende Parser
Programme von Programmiersprachen kann man i.a.in O(n) oder O(n ∗ log(n)) parsen,Effiziente rekursiv-absteigende Parser benotigen i.a.:• Erweiterungen wie Vorausschau
• Umbau der Grammatik (Optimierung der Grammatik)
Grundlagen der Programmierung 2 Parser – 19/61 –
Rekursiv-absteigende Parser
Programmierung
Grundlagen der Programmierung 2 Parser – 20/61 –
Funktionale Kombinator-Parser
Bausteine
1 Einfache Parser;z.B erkennt ein Zeichen
2 Kombinatorenzum Zusammenbauen von Parsern aus bereits vorhandenen
3 Kombinatoren zum Aufbau der Ausgabe
Grundlagen der Programmierung 2 Parser – 21/61 –
Funktionale Kombinator-Parser
Aufgaben der kombinierten Parser
1 Lesen und Prufen,
2 Aufbau des Syntaxbaums
3 Berechnung von Ergebnissen
Beispiel
p <* q = (p <*> q) <@ fst
<*> ist ein Kombinator zum Lesen und Prufen.<@ bewirkt die Nachbearbeitung des Ergebnissesp, q sind Parser (-programme)
Grundlagen der Programmierung 2 Parser – 22/61 –
Funktionale Kombinator-Parser
Implementierung von rekursiv-absteigenden Parsern in HaskellVorteile • relativ leicht verstandliche Programmierung
• 1-1-Ubersetzung der Regeln in Programmcode
Pro Nichtterminal N eine FunktionparserN:: String -> [(String, Syntaxbaum)]
Bei Eingabe einer Tokenliste:parserN:: [Token] -> [([Token], Syntaxbaum)]
Grundlagen der Programmierung 2 Parser – 23/61 –
Funktionale Kombinator-Parser
Um Backtracking zu implementieren:
Liste von erfolgreichen Ergebnissen
verzogerte Auswertung ergibt richtige Reihenfolge derAbarbeitung.
kann oft deterministisch gemacht werden
Es gibt erweiterte Kombinatoren zur Fehlererkennung und mitguten Fehlerhinweisen
Grundlagen der Programmierung 2 Parser – 24/61 –
Haskell-Implementierung der Parser-Kombinatoren
Kombinator (kombiniert Parser)Z.B. Alternative, Sequenz, Resultat-Umbau
module CombParser where
import Char
infixr 6 <*>, <*, *>
infixr 4 <|>, <!>
infixl 5 <@
type Parser a b = [a] -> [([a],b)]
erkennt ein Zeichen:
symbol :: Eq s => s -> Parser s s
symbol a [] = []
symbol a (x:xs) | a ==x = [(xs,x)]
| otherwise = []
Grundlagen der Programmierung 2 Parser – 25/61 –
Haskell: Parser-Kombinatoren (2)erkennt einen String:
token :: Eq s => [s] -> Parser s [s]
-- token :: Eq s => [s] -> Parser s [s]
token k xs | k == (take n xs) = [(drop n xs, k)]
| otherwise = []
where n = length k
testet ein Zeichen der Eingabe:
satisfy :: (s -> Bool) -> Parser s s
satisfy p [] = []
satisfy p (x:xs) = [(xs,x) | p x]
epsilon :: Parser s ()
epsilon xs = [(xs,())]
Grundlagen der Programmierung 2 Parser – 26/61 –
Haskell: Parser-Kombinatoren (3)
immer erfolgreich:
succeed :: r -> Parser s r
succeed v xs = [(xs,v)]
immer fehlschlagend:
pfail :: Parser s r
pfail xs = []
Grundlagen der Programmierung 2 Parser – 27/61 –
Haskell: Parser-Kombinatoren (4)
Sequenzkombinator :
(<*>) :: Parser s a -> Parser s b -> Parser s (a,b)
(p1 <*> p2) xs = [(xs2, (v1,v2))
| (xs1,v1) <- p1 xs,
(xs2,v2) <- p2 xs1]
xs: xs2p1 p2︸ ︷︷ ︸
p1 <*> p2
• p1 parst den Anfang der Eingabe;gibt den Reststring xs1 weiter an p2
• p2 parst danach den Anfang des Reststringsgibt den Reststring zuruck
• Gesamtresultat = Tupel aus den zwei Resultaten
Grundlagen der Programmierung 2 Parser – 28/61 –
Haskell: Parser-Kombinatoren (4b)
Alternativkombinator :
(<|>) :: Parser s a -> Parser s a -> Parser s a
(p1 <|> p2) xs = p1 xs ++ p2 xs
Es werden beide Parser p1 und p2
auf die gleiche Eingabe angewendet.Alternativkombinator-2: maximal ein Ergebnis:
(<!>) :: Parser s a -> Parser s a -> Parser s a
(p1 <!> p2) xs = take 1 (p1 xs ++ p2 xs)
Grundlagen der Programmierung 2 Parser – 29/61 –
Haskell: Parser-Kombinatoren (6)
Operation auf dem Ergebnis des Parse :
(<@) :: Parser s a -> (a->b) -> Parser s b
(p <@ f) xs = [(ys, f v) | (ys,v) <- p xs]
f ist der Modifikator des Ergebnisses v des Parsers p.Typischer Fall:p <|> q kann ungetypt sein, wenn p, q verschiedeneErgebnis-Typen liefern.Dann z.B. (p <@ f) <|> (q <@ g) benutzen.
Grundlagen der Programmierung 2 Parser – 30/61 –
Haskell: Parser-Kombinatoren (6)
Kombinatoren, die die Nachverarbeitung miterledigen:ignoriert rechtes Ergebnis:
(<*) :: Parser s a -> Parser s b -> Parser s a
p <* q = p <*> q <@ fst
ignoriert linkes Ergebnis:
(*>) :: Parser s a -> Parser s b -> Parser s b
p *> q = p <*> q <@ snd
Grundlagen der Programmierung 2 Parser – 31/61 –
Haskell: Parser-Kombinatoren (7)
erkennt Folge. d.h. entspricht *:
many :: Parser s a -> Parser s [a]
many p = p <*> many p <@ list
<|> succeed []
many1 p = p <*> many p <@ list
digit :: Parser Char Int
digit = satisfy isDigit <@ f
where f c = ord c - ord ’0’
erkennt Zahl:
natural :: Parser Char Int
natural = many1 digit <@ foldl f 0
where f a b = a*10 + b
Grundlagen der Programmierung 2 Parser – 32/61 –
Haskell: Parser-Kombinatoren (8)
Nimmt nur die erste (maximale) Alternative des many;Vorsicht: ist immer erfolgreich!: nur erlaubt, wenn der Parser dieweggelassenen Alternativen nicht benotigt
manyex :: Parser s a -> Parser s [a]
manyex p = p <*> many p <@ list
<!> succeed []
many1ex p = p <*> manyex p <@ list
option p = p <@ (\x->[x])
<!> epsilon <@ (\x-> [])
Nimmt nur die erste (maximale) Alternative bei Zahlen:
naturalex :: Parser Char Int
naturalex = many1ex digit <@ foldl f 0
where f a b = a*10 + b
Grundlagen der Programmierung 2 Parser – 33/61 –
Haskell: Parser-Kombinatoren (9)
Erkennt Klammerung; Klammern kommen nicht in denSyntaxbaum:
pack:: Parser s a -> Parser s b -> Parser s c -> Parser s b
pack s1 p s2 = s1 *> p <* s2
Zum Beispiel: pack (symbol ’(’) naturalex (symbol ’)’) "7799"
Erkennt Infix-Folge wie z.B. 1+2+3+4+5: Resultat: Liste derArgumente
opSeqInf psymb parg = (parg <*> many (psymb *> parg)) <@ list
Grundlagen der Programmierung 2 Parser – 34/61 –
Einfaches Beispiel
Grammatik-Regeln: S → ABA→ aB → b
Programm: parse S = parse A <*> parse B
parse A = (symbol ’a’)
parse B = (symbol ’b’)
Grundlagen der Programmierung 2 Parser – 35/61 –
Einfaches Beispiel
Grammatik-Regeln: S → ABA→ aB → b
Programm: parse S = parse A <*> parse B
parse A = (symbol ’a’)
parse B = (symbol ’b’)
Grundlagen der Programmierung 2 Parser – 35/61 –
Leicht komplexeres Beispiel
Grammatik-Regeln: S → ABA→ aA | aB → bB | b
Ein typisches Wort der Sprache: “aaaaaabb”
Programm: parseS = parseA <*> parseB
parseA = (symbol ’a’) <*> parseA
<|> (symbol ’a’)
(parseB = (symbol ’b’) <*> parseB)
<|> (symbol ’b’)
Grundlagen der Programmierung 2 Parser – 36/61 –
Leicht komplexeres Beispiel
Grammatik-Regeln: S → ABA→ aA | aB → bB | b
Ein typisches Wort der Sprache: “aaaaaabb”
Programm: parseS = parseA <*> parseB
parseA = (symbol ’a’) <*> parseA
<|> (symbol ’a’)
(parseB = (symbol ’b’) <*> parseB)
<|> (symbol ’b’)
Grundlagen der Programmierung 2 Parser – 36/61 –
Leicht komplexeres Beispiel
Grammatik-Regeln: S → ABA→ aA | aB → bB | b
Typgerecht programmieren mit Modifikatoren undSyntaxbaum-Erzeugung:
parseS = (parseA <*> parseB) <@ (\(x,y)-> [x,y])
parseA = ((symbol ’a’) <*> parseA) <@ (list)
<|> (symbol ’a’) <@ (\x -> (x:[]))
parseB = (((symbol ’b’) <*> parseB) <@ (list))
<|> (symbol ’b’) <@ (\x -> (x:[]))
list (x,xs) = x:xs
Grundlagen der Programmierung 2 Parser – 37/61 –
Leicht komplexeres Beispiel
Zusatzliche Verwendung des Kombinators many
um neue Parser zu generieren:parse S = parseA <*> parseB <@ (\(x,y) -> [x,y])
parseA = many (symbol ’a’)
parseB = many (symbol ’b’)oder, noch besser:
parse S = parseA <*> parseB <@ (\(x,y) -> [x,y])
parseA = manyex (symbol ’a’)
parseB = manyex (symbol ’b’)oder, wenn mindestens ein a bzw b erkannt werden soll
parse S = parseA <*> parseB <@ (\(x,y) -> [x,y])
parseA = many1ex (symbol ’a’)
parseB = many1ex (symbol ’b’)
Grundlagen der Programmierung 2 Parser – 38/61 –
Beispiel: Tupel aus Zahlen parsen
Erkennen von z.B. (111, 2, 33303198737, 0)
klammern = pack (symbol ’(’) kommaListe (symbol ’)’)
kommaListe = ((naturalex) <*> paarKommaliste) <@ list
paarKommaliste = (manyex ((symbol ’,’) *> naturalex))
Grundlagen der Programmierung 2 Parser – 39/61 –
Beispiel: Tupel von Tupeln von Zahlen parsen
Erkennen von z.B. ((1, 2, 3), (55, 66, 789), (3303198737, 0))
....
matrixzeile = klammern
matrix = pack (symbol ’(’) zeilenListe (symbol ’)’)
zeilenListe = ((matrixzeile) <*> paarZeilenliste) <@ list
paarZeilenliste = (manyex((symbol ’,’) *> matrixzeile))
Grundlagen der Programmierung 2 Parser – 40/61 –
Grammatik und formale Sprachen
Grammatiken und Herleitungen
Grundlagen der Programmierung 2 Parser – 41/61 –
Beispiel: Polymorphe Typ-Ausdrucke
Grammatik
AT ::= AT -> AT (klammerfreie ->-Typen)
| (AT)
| [AT] | Var | TCA
TCA ::= TC | (TC AT . . .AT) | (AT1,. . . ,ATn), n > 1
Grammatik ist linksrekursiv!
Grundlagen der Programmierung 2 Parser – 42/61 –
Beispiel: Polymorphe Typ-Ausdrucke
Grammatik
AT ::= AT -> AT (klammerfreie ->-Typen)
| (AT)
| [AT] | Var | TCA
TCA ::= TC | (TC AT . . .AT) | (AT1,. . . ,ATn), n > 1
Grammatik ist linksrekursiv!
Grundlagen der Programmierung 2 Parser – 42/61 –
Beispiel: Polymorphe Typ-Ausdrucke
Vorgehen zur Elimination der Linksrekursion in AT->AT :mit NOAT-> . . . modellieren, wobei NOAT kein Pfeil-Typ.
umgebaute Grammatik;
nicht linksrekursiv und optimiert fur den Parser
AT ::= NOAR { NOARNX | ε }NOARNX ::= -> ATNOAR ::= Var | TCT | KLRUND | KLECKTCT ::= TC NOAR . . .NOARKLRUND ::= (AT,. . . ,AT) Mindestens 2-TupelKLECK ::= [AT]
Grundlagen der Programmierung 2 Parser – 43/61 –
Kombinatorparser mit Fehlerbehandlung
Erweiterte Bibliothek
Kombinatoren zu Fehlererkennung
((p1 <*>!) errStr) p2 Ergibt Fehler mit Text errStrWenn p2 fehlschlagt
((p1 *>!) errStr) p2 Wie <*>! aber nur Ergebnis von p2
((p1 *<!) errStr) p2 Wie <*>! aber nur Ergebnis von p1
Grundlagen der Programmierung 2 Parser – 44/61 –
Kombinatorparser; Beispiele
AT ::= NOAR { NOARNX | ε }NOARNX ::= -> ATNOAR ::= Var | TCT | KLRUND | KLECKTCT ::= TC NOAR . . .NOARKLRUND ::= (AT,. . . ,AT) Mindestens 2-TupelKLECK ::= [AT]
parseKLRUND =
(parseSymbol ’(’ *> (parseINKLRUND
<*! ") erwartet") (parseSymbol ’)’))
<@ id
parseINKLRUND = (parseAT <*> (manyex (((parseSymbol ’,’)
*>! "Typ nach , erwartet") parseAT)))
<@@ (\(t1,t2) er -> if null t2 then t1
else (Fn ("Tup"++(show ((length t2) +1))) (t1:t2) er))
Grundlagen der Programmierung 2 Parser – 45/61 –
Kombinatorparser mit Fehlerbehandlung
Programme und Vorfuhrunghtml-parser.hs
main
prelex (linPosNumbering "<DD> xxx </DD>\n<br> text </br>")
Grundlagen der Programmierung 2 Parser – 46/61 –
Fehler-Meldungen: Bemerkungen
Die Fehlererkennung und -meldung sollte spezifisch sein undmoglichst genau die Ursache und Stelle melden.
Schlecht:”Keine Alternativen mehr gefunden in Zeile... “
Gut”Fehler in Zeile ... Spalte... Moglicher Grund: ... “
Bei deterministischen Parsern(und Kombinatorparser mit Fehlerbehandlung)
Die Fehlerstelle ist klar;die Fehlerursache ist auch meist spezifisch genug
Bei Parsern mit Backtracking und ohne FehlerbehandlungDer richtige Fehlerstelle ist meist unklarDer Backtracking-Parser kann meist nur melden:
keine Alternativen mehr
Grundlagen der Programmierung 2 Parser – 47/61 –
Evaluation nachste Woche
Am Anfang der Vorlesung:am 7.6. von 8:00 bis 10:00
http://r.sd.uni-frankfurt.de/1ccbf5eb
Grundlagen der Programmierung 2 Parser – 48/61 –
Rekursiv-absteigende Parser
Rekursiv-pradiktive Parser
Grundlagen der Programmierung 2 Parser – 49/61 –
Rekursiv-pradiktive Parser
Optimierte rekursiv absteigende Parserfur eingeschrankte Grammatiken ( LL(1) ).
Eigenschaften:• Die anzuwendende Produktion ist immer eindeutig festgelegt
abhangig vom aktuellen Nichtterminal unddem nachsten Symbol (Lookahead-Symbol) der Resteingabe
• kein Zurucksetzen notwendig,• deterministische Abarbeitung der Eingabe von links nach
rechts
Aber: man kann nicht fur jede eindeutige kontextfreie Grammatikeinen rekursiv-pradiktiven Parser konstruieren.
Grundlagen der Programmierung 2 Parser – 50/61 –
Rekursiv-pradiktive Parser
Zweidimensionale Tabelle:
(Lookahead-Symbol, Nichtterminal) 7→ Regel oder Fehlereintrag
⇒ Tabellengesteuerter rekursiv-pradiktiver Parser:
Grundlagen der Programmierung 2 Parser – 51/61 –
Rekursiv-pradiktive Parser
Eindeutigkeitsbedingung:Wenn A→ w1 | . . . | wn alle Regeln zu A sind:
Falls Parser im Zustand A:Fur jedes erst Symbol x der Eingabe:
nur eine Regel A→ wi darf anwendbar sein!
Beispiel:A → bCD | aEF | cG | HH → dabc. . .
Grundlagen der Programmierung 2 Parser – 52/61 –
Rekursiv-pradiktive Parser
Sonderfall:
Es gibt eine Regel A→ wi mit wi →∗ ε:Diese wird ausgewahlt, wenn:
• keine passende rechte Seite fur das Lookahead-Symbol; und• das Lookahead-Symbol kann auf A folgen; und• es gibt nur eine solche ε-Regel fur A
Grundlagen der Programmierung 2 Parser – 53/61 –
Rekursiv-pradiktive Parser, ε-Fall
Beispiel:
S → AB | ACA → bCD | aEF | cG | HH → ε. . .B → dAC → eA
Im Zustand A und bei Eingabesymbol d:A→ H wird ausgewahlt.
Grundlagen der Programmierung 2 Parser – 54/61 –
FIRST- und FOLLOW-Mengen
Vorberechnung zur Steuerung des Parsers.
Wenn Grammatik G gegeben ist:
first(A) := Terminal-Symbole die am Anfang eineserkannten A-Wortes stehen konnen.
(auch ε)
follow(A) := Terminal-Symbole die auf einerkanntes A-Wort folgen konnen.
Diese Mengen kann man in allen rekursiv-absteigenden Parsernzur Eindammung, evtl. zur Vermeidung, von Backtrackingverwenden.
Grundlagen der Programmierung 2 Parser – 55/61 –
Beispiel fur first
Ex ::= PlusPlus ::= SigZ PlusrestPlusRest ::= + SigZ PlusRest | εSigZ ::= B | - BB ::= Z | ( Ex )Z ::= 0 | . . . | 9
Man erhalt als first-Mengen:
Ex Plus Plus SigZ B ZRest
0,...,9, (,- 0,...,9, (,- +, ε 0,...,9, (,- 0,...,9, ( 0,...,9
Grundlagen der Programmierung 2 Parser – 56/61 –
Beispiel fur follow :
Ex ::= PlusPlus ::= SigZ PlusrestPlusRest ::= + SigZ PlusRest | εSigZ ::= B | - BB ::= Z | ( Ex )Z ::= 0 | . . . | 9
Man erhalt als follow- Mengen:
Ex Plus PlusRest SigZ B Z) ) ) +,) +,) +,)
Grammatik ist LL(1) parsebar,da: First-Mengen zu Regelalternativen passen undfirst(PlusRest) ∩ follow(PlusRest) = ∅
Grundlagen der Programmierung 2 Parser – 57/61 –
Beispiel fur follow :
Ex ::= PlusPlus ::= SigZ PlusrestPlusRest ::= + SigZ PlusRest | εSigZ ::= B | - BB ::= Z | ( Ex )Z ::= 0 | . . . | 9
Man erhalt als follow- Mengen:
Ex Plus PlusRest SigZ B Z) ) ) +,) +,) +,)
Grammatik ist LL(1) parsebar,da: First-Mengen zu Regelalternativen passen undfirst(PlusRest) ∩ follow(PlusRest) = ∅
Grundlagen der Programmierung 2 Parser – 57/61 –
Vorgehen des LL(1)-Parsers
Bei Symbol a, und aktuellem Nichtterminal A:• Ist a ∈ first(wi) fur eine Regel A ::= wi, dann nehme diese Regel.
(ε 6∈ first(wi) fur alle i muss gelten. )• Ist a 6∈ first(wi) fur alle Regeln A ::= wi,
dann gibt es maximal eine Regel A ::= w mit first(w) = ∅Falls a ∈ follow(A), dann diese Regel.
• Wenn auch dann keine passende Alternative existiert,wird mit Fehler abgebrochen.
Vorteil: genaue und fruhe Fehlererkennung
Grundlagen der Programmierung 2 Parser – 58/61 –
Beispiel: vereinfachte Grammatik fur Ausdrucke
Expr ::= Term RestRest ::= + Term Rest | − Term Rest | εTerm ::= 0 | . . . | 9
• first(Term Rest) = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}• first(+ Term Rest) = {+},
first(− Term Rest) = {−}• first(Expr ) = first(Term ) = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}• first(Rest) = {+,−, ε}• follow(Expr) = ∅.• follow(Rest) = ∅.• follow(Term) = {+,−}.
U.a. ist follow(Rest) = ∅.Diese Grammatik hat die LL(1)-Eigenschaft.
Grundlagen der Programmierung 2 Parser – 59/61 –
Beispielparser zur Grammatik
Parsebaum: 1+2-3 Syntaxbaum:
PExp
|| %%1 PRest
yy �� &&+ 2 PRest
yy �� %%− 3 PLeer
+
�� ��1 −
~~ ��2 3
Der Parsebaum entspricht der Grammatik,aber noch nicht der gewunschten Struktur
des arithmetischen Ausdrucks.Man braucht eine Nachbearbeitung des Parsebaumes,um den Syntaxbaum zu erstellen!
Grundlagen der Programmierung 2 Parser – 60/61 –
Pradiktiv vs. Kombinatoren
Meistens kann man fur Grammatiken die geeignet sind furrekursiv-pradiktive Parser (LL(1))auch einen deterministischen Kombinator-Parser schreiben.(Nach etwas Analyse und Nachdenken)
Dabei ist im Parserprogrammuberall der Parserkombinator <|> durch <!> ersetzt.und man kann teilweise die um Fehlermeldungen erweitertenKombinatoren verwenden.D.h es ist frei von Backtracking.
Grundlagen der Programmierung 2 Parser – 61/61 –
Top Related