LL(k)-Grammatik

Aus testwiki
Zur Navigation springen Zur Suche springen

Dieser Artikel setzt Vorkenntnisse im Bereich Theoretische Informatik und Compilerbau voraus.


Eine LL(k)-Grammatik (im Gegensatz zu LF(k)-Grammatik auch schwache LL(k)-Grammatik) ist eine spezielle kontextfreie Grammatik, welche die Grundlage eines LL(k)-Parsers bildet.

Eine kontextfreie Grammatik heißt LL(k)-Grammatik für eine natürliche Zahl k, wenn jeder Ableitungsschritt eindeutig durch die nächsten k Symbole der Eingabe (Lookahead) bestimmt ist. Das bedeutet, die Frage, welches Nichtterminalsymbol mit welcher Regel als Nächstes expandiert werden soll, kann eindeutig mit Hilfe der nächsten k Symbole der Eingabe bestimmt werden.

Generell gilt, je größer k gewählt wird, umso mächtiger wird die Sprachklasse, wobei die Ausdrucksstärke von kontextfreien Grammatiken nie erreicht wird. Damit gibt es kontextfreie Sprachen, die für kein k von einer LL(k)-Grammatik erzeugt werden.

(LL(1))(LL(2))(LL(k))(LR(1))=(DPDA)

Dabei steht DPDA für die deterministischen Kellerautomaten. Diese können genau die deterministisch kontextfreien Sprachen erkennen.

Formale Definition LL(k)-Grammatik

Eine kontextfreie Grammatik G=(N,Σ,P,S) ist genau dann eine LL(k)-Grammatik, wenn für alle Linksableitungen der Form

Sl*wAγl{wαγl*wxwβγl*wy

mit (w,x,yΣ*;α,β,γ(NΣ)*;AN) und 𝑓𝑖𝑟𝑠𝑡k(x)=𝑓𝑖𝑟𝑠𝑡k(y) gilt: α=β

Für die in der Definition benutzte Funktion zur Bestimmung der FIRST-Mengen gilt:

aΣ*;|a|k 𝑓𝑖𝑟𝑠𝑡k(a)={a}
aΣ*;|a|>k 𝑓𝑖𝑟𝑠𝑡k(a)={vΣ*a=vw;|v|=k}
A(NΣ)*Σ* 𝑓𝑖𝑟𝑠𝑡k(A)={vΣ*A*w;wΣ*;𝑓𝑖𝑟𝑠𝑡k(w)={v}}

Anwendung

Aktuelle LL-Parser benutzen meist nur einen Lookahead von 1. Daher kann in den folgenden Ausführungen k=1 gesetzt werden.

Bei der praktischen Anwendung ist nur mit großem Aufwand überprüfbar, ob die vorliegende Grammatik die Definition einer LL(k)-Grammatik erfüllt. Es wird stattdessen ein abgewandelter Ansatz benutzt.

Eine kontextfreie Grammatik ist genau dann eine LL(k)-Grammatik, wenn für alle Nichtterminalsymbole A, für alle Produktionen Aβ und Aγ mit βγ und Sl*wAα gilt: firstk(βα)firstk(γα)=. (wΣ*;α,β,γ(NΣ)*;AN)

Erklärung: Das Startsymbol der kontextfreien Grammatik S wurde (in eventuell mehreren Schritten) nach wAα expandiert. Gemäß der Linksableitung wird das Nichtterminalsymbol A als Nächstes ersetzt. Dazu gibt es in der kontextfreien Grammatik aber zwei verschiedene Regeln; Aβ und Aγ. Die Frage, mit welcher Regel A expandiert wird, bestimmt sich aus der Berechnung von firstk(βα) und firstk(γα). Um die Frage eindeutig beantworten zu können, müssen beide Mengen disjunkt sein.

Im Allgemeinen hängt firstk(βα) aber vom Rechtskontext α ab (wenn β*ϵ). Das Ziel ist die Bestimmung von firstk(βα) nur aus den Produktionen, d. h. aus β und aus den Strings, die einem Vorkommen von A folgen können. Für diesen Zweck wird die Funktion followk(A) definiert, die die Menge aller A folgenden Symbole berechnet.

β(NΣ)*:followk(β)={wΣ*α,γ(NΣ)* mit Sl*αβγ und wfirstk(γ)}

Damit kann die eingangs geforderte Bedingung umformuliert werden:

Eine reduzierte kontextfreie Grammatik ist genau dann eine LL(1)-Grammatik, wenn für alle Nichtterminalsymbole A und für alle Produktionen Aβ und Aγ mit βγ gilt: first1({β}follow1(A))first1({γ}follow1(A))=.

Achtung: Dieser Satz kann auf Fälle k>1 nicht angewandt werden.

Die zu einer Produktion Aβ berechnete Menge la(A,β)=first1({β}follow1(A)) wird als Lookahead-Menge bezeichnet.

Beispiel

Für die folgende Grammatik G wird geprüft, ob sie eine LL(1)-Grammatik ist. Dazu müssen die Lookahead-Mengen aller Produktionen mit gleichen linken Regelseiten disjunkt sein.

G=({E,E,T,T,F},{a,(,),+,*},P,E) und die Menge der Produktionen ist:
ETE
E+TE|ϵ
TFT
T*FT|ϵ
F(E)|a

Zunächst werden die first- bzw. follow-Mengen der Nichtterminalsymbole bestimmt, da diese für die Berechnung der Lookahead-Mengen nötig sind.

E E' T T' F
first1 {(,a} {+,ϵ} {(,a} {*,ϵ} {(,a}
follow1 {$,)} {$,)} {+,$,)} {+,$,)} {*,+,$,)}

Es folgt der Vergleich der Lookahead-Mengen für alle Produktionen mit gleichen linken Regelseiten.

Als erstes für die beiden Produktionen +TE und ϵ von E+TE|ϵ

first1({+TE})first1({ϵ})={+}{ϵ}=
first1({+TE})follow1(E)={+}{$,)}=

Als Nächstes für die beiden Produktionen *FT und ϵ von T*FT|ϵ

first1({*FT})first1({ϵ})={*}{ϵ}=
first1({*FT})follow1(T)={*}{+,$,)}=

Als letztes für die beiden Produktionen (E) und a von F(E)|a

first1({(E)})first1({a})={(}{a}=

Da alle betrachteten Schnittmengen leer sind, handelt es sich bei der Grammatik G um eine LL(1)-Grammatik.

Siehe auch

Literatur

  • Donald E. Knuth: Top-down syntax analysis. In: Acta Informatica 1, 1971, Vorlage:ISSN, S. 79–110, (Neuabdruck einer erweiterten Fassung in: Donald E. Knuth: Selected Papers on Computer Languages. Center for the Study of Language and Information, Stanford CA 2003, ISBN 1-575-86381-2, (CSLI lecture notes 139), Kapitel 14).
  • LR(k)-Analyse für Pragmatiker von Andreas Kunert