LEXIKALISCHE ANALYSE
LEXIKALISCHE ANALYSE
LEXIKALISCHE ANALYSE
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
2. Kapitel<br />
<strong>LEXIKALISCHE</strong> <strong>ANALYSE</strong> <br />
Compilerbau <br />
Prof. Dr. Wolfgang Schramm
Lexikalische Analyse (Scanner) 1/2 <br />
1 <br />
Aufgabe <br />
– Erkennen von lexikalischen Elementen. <br />
– Erstellung einer internen Darstellung für lexikalische Elemente. <br />
Einordnung <br />
¤<br />
Der Scanner ist i.allg. Unterprogramm des Parsers. <br />
Erweiterungen: <br />
¤<br />
¤<br />
¤<br />
Kopie des Quellprogramms (evtl.) mit Meldungen erzeugen. <br />
ImplemenNerung von Makrotechniken. <br />
Fehlerbehandlung (Einfügen, Löschen, Vertauschen von Zeichen). <br />
Bsp: -‐7.6F+8 è -‐7.6E+8
Lexikalische Analyse (Scanner) 2/2 <br />
2 <br />
liefere nächstes lex.<br />
Element<br />
Quell-<br />
Scanner<br />
Parser<br />
pro-<br />
gramm<br />
Strukturbaum<br />
Eintragen<br />
Nächstes lexikalisches<br />
Element<br />
Symboltabelle<br />
Eintragen/<br />
Nachschlagen
TheoreNscher Hintergrund der lexikalischen Analyse 1/2 <br />
3 <br />
1. Die Struktur lexikalischer Symbole kann durch reguläre Ausdrücke beschrieben <br />
werden. Das heißt, die Menge der Zeichenke^en, die auf ein Token abgebildet <br />
werden, ist die zum Ausdruck gehörige reguläre Sprache. <br />
2. Reguläre Sprachen werden durch rechtslineare oder durch linkslineare <br />
GrammaNken erzeugt. <br />
3. Reguläre Sprachen werden von nichtdeterminisNschen endlichen Automaten <br />
(NEA) erkannt. <br />
NFA<br />
4. Zu jedem nichtdeterminisNschen endlichen Automaten kann man auch einen <br />
determinisNschen endlichen Automaten (DEA) konstruieren, der die gleiche <br />
Sprache erkennt. <br />
DFA
TheoreNscher Hintergrund der lexikalischen Analyse 2/2 <br />
4 <br />
Kurz gesagt:<br />
Man braucht einen Formalismus zur Spezifikation der Token.<br />
Reguläre Ausdrücke<br />
Man braucht einen Mechanismus zur Erkennung der Token.<br />
DFA,<br />
Zustandsdiagramme
DefiniNonen für Beschreibung formaler Sprachen 1/3 <br />
5 <br />
Terminalsymbole <br />
¤<br />
Die Terminalsymbole (Lexeme, Token) sind Elemente einer Menge T von <br />
GrammaNksymbolen. Terminalsymbole sind die kleinsten syntakNschen <br />
Grundeinheiten einer formalen Sprache mit selbstständiger Bedeutung. Ein <br />
Satz ist die Aneinanderreihung von Terminalsymbolen. <br />
Nonterminalsymbole <br />
¤<br />
Die Nonterminalsymbole sind Elemente einer Menge N von GrammaNk-symbolen,<br />
die zur Darstellung von Zwischenzuständen des Spracher-zeugungsprozesses<br />
dienen. <br />
ProdukKonen <br />
¤<br />
Die ProdukNonen sind Vorschrifen für das Ersetzen einer Symbolke^e α durch <br />
eine andere Symbolke^e β (α → β ).
DefiniNonen für Beschreibung formaler Sprachen 2/3 <br />
6 <br />
Eine (Chomsky-) Grammatik zur Beschreibung von Syntax ist durch ein 4-Tupel:<br />
G = (T, N, P, S)<br />
definiert.<br />
T: Menge der Terminalsymbole.<br />
N: Menge der Nonterminalsymbole.<br />
Lies: Element<br />
von<br />
Epsilon<br />
(leeres Wort)<br />
P: Menge von Produktionen α → β mit α, β ∈ (N ∪ T) * und N ∩ T = ∅, α ≠ ε <br />
S: Ein ausgezeichnetes Nonterminalsymbol - das Startsymbol mit S ∈ N.<br />
Kleene Stern
DefiniNonen für Beschreibung formaler Sprachen 3/3 <br />
7 <br />
Die Sprache L(G) einer GrammaKk ist die Menge der Terminalsymbolke^en, die <br />
über das Startsymbol S nach den Regeln von P hergeleitet werden kann. <br />
* <br />
L (G) = { s | S → s mit s ∈ T * }
Die Chomsky GrammaNk-‐Typen <br />
8 <br />
Eine GrammaNk G = (T, N, P, S) heißt <br />
• vom Typ 0 oder unbeschränkt (rekursiv aufzählbar), <br />
wenn sie nach den Regeln von P hergeleitet werden kann. <br />
• vom Typ 1 oder kontextsensiKv, <br />
wenn in jeder Regel α → β die linke Seite nicht länger als die rechte ist: |α|<br />
≤ |β|; die Regel A → ε mit A ∈ N ist zulässig, wenn A auf keiner rechten <br />
Seite vorkommt. <br />
• vom Typ 2 oder kontexWrei, <br />
wenn jede Regel die Form A → α hat, mit A ∈ N und α ∈ (N ∪ T) * . <br />
• vom Typ 3 oder regulär, <br />
wenn jede Regel eine der Formen A → α, A → αB oder A → Bα hat, mit A, <br />
B ∈ N und α ∈ T * .
Die Chomsky Sprachhierarchie <br />
9 <br />
o<br />
Wenn L i die Menge aller Sprachen ist, die von den GrammaNken des Chomsky-‐Typs i <br />
erzeugt werden kann, dann ist <br />
Rekursiv aufzählbare Sprachen<br />
Kontextsensitive Sprachen<br />
Kontextfreie Sprachen<br />
Reguläre Sprachen<br />
L 0 ⊃ L 1 ⊃ L 2 ⊃ L 3
Alphabet und Sprache in der InformaNk 1/3 <br />
10 <br />
o Im Sinne der MathemaNk und InformaNk ist eine Sprache eine <br />
Menge von Zeichenreihen. Die Sprache wird dabei auf Lexik und <br />
Syntax reduziert. Für Lexik wird der Begriff Alphabet verwendet. <br />
o Ein Alphabet ist eine nicht leere, endliche Menge A von Zeichen a <br />
∈ A. <br />
A1 = {A, ..., Z} <br />
A2= {a} <br />
A3 = {A, ..., Z, a, ..., z, 0, ..., 9}<br />
A4= {#, 0}
Alphabet und Sprache in der InformaNk 2/3 <br />
11 <br />
o Die Menge aller Zeichenreihen A* über einem Alphabet ist <br />
definiert durch: <br />
¤<br />
¤<br />
¤<br />
ε ∈ A* die leere Zeichenreihe ist eine Zeichenreihe. <br />
x ∈A*, a ∈ A* ⇒ x ° a ∈ A* („° “ ist der Verke^ungsoperator). <br />
Andere Zeichenreihen gibt es nicht. <br />
Konkatenation<br />
ATA, ATTTNBNM ∈ A1* <br />
a, aa, aaa .... ∈ A2* <br />
Paul, Omega, x12 ∈ A3* #, #0#000 ∈ A4* <br />
o Eine Sprache L (L, wie engl. language) ist eine Teilmenge aller <br />
Zeichenreihen über einem Alphabet A: L ⊂ A* <br />
Deutsche Sprache ⊂ {A, ..., Z, a, ..., z, ß, 0, ..., 9, ?, !, ...}*
Alphabet und Sprache in der InformaNk 3/3 <br />
12 <br />
Wie werden die Zeichenreihen einer besNmmten Sprache <br />
beschrieben? <br />
a) Aufzählung aller Zeichenreihen oder Wörter, die zur Sprache gehören (das ist nur bei <br />
endlichen Sprachen möglich!). <br />
L 1 = {a, aaa, aaaaa} <br />
b) MathemaKsche Charakterisierung der zur Sprache gehörenden Wörter als Menge <br />
(sog. formale Sprachen). <br />
L 2 = {a n | n ≥ 3} oder L 3 = {a n b n c n | n ≥ 1} <br />
c) GrammaKken: sind eine endliche konstrukNve Beschreibung einer im allgemeinen <br />
unendlichen Menge. <br />
Damit werden Programmiersprachen beschrieben.
Kontexzreie GrammaNk 1/2 <br />
13 <br />
Eine GrammaKk zur Beschreibung von Syntax ist ein 4-‐Tupel: <br />
G = (T, N, P, S) <br />
T: Menge von Token, sog. Terminalsymbole (TS). <br />
N: Menge von Nonterminalsymbolen (NTS). <br />
P: Menge von ProdukKonen (oder ProdukNonsregeln), wobei jede <br />
ProdukNon aus einem Nonterminalsymbol (linke Seite der <br />
ProdukNon) einem Pfeil (→) und einer Folge von <br />
Terminalsymbolen und/oder Nonterminalsymbolen (rechte <br />
Seite der ProdukNon) besteht. <br />
S: Ein ausgezeichnetes Nonterminalsymbol -‐ das Startsymbol.
Kontexzreie GrammaNk 2/2 <br />
14 <br />
Die Sprache L(G) einer GrammaKk besteht aus allen aus dem Startsymbol S <br />
abgeleiteten Zeichenke^en (Wörtern), die nur Terminalsymbole enthalten. <br />
Ein Wort ist eine Folge von Terminalsymbolen, die durch wiederholtes <br />
Anwenden von Regeln erzeugt werden kann, wobei das Startsymbol S der <br />
Ausgangspunkt der Erzeugung ist. <br />
GrammaNken werden in zweierlei Hinsicht genutzt: <br />
¤<br />
Um Worte einer Sprache zu erzeugen. <br />
Ableiten<br />
¤<br />
Um festzustellen, ob ein gegebenes Wort zur Sprache gehört. <br />
Analysieren<br />
Es gibt verschiedene Formalismen zur Beschreibung von GrammaNken: <br />
¤<br />
¤<br />
¤<br />
¤<br />
Reguläre Ausdrücke (einfacher Mechanismus, nicht für alles geeignet) <br />
Backus Naur Form (BNF). <br />
Erweiterte Bauckus Naur Form (EBNF). <br />
Syntaxdiagramme.
Reguläre Sprachen -‐ DefiniNon <br />
15 <br />
Die regulären Sprachen über dem Alphabet A werden durch folgende Regeln <br />
indukNv definiert: <br />
i. ∅ und {ε} sind reguläre Sprachen. <br />
ii.<br />
iii.<br />
iv.<br />
Für jedes a ∈ A ist {a} eine reguläre Sprache. <br />
Seien B und C reguläre Sprachen, dann sind auch <br />
B ∪ C, BC und B * reguläre Sprachen. <br />
Nichts sonst ist eine reguläre Sprache über A. <br />
Ein regulärer Ausdruck r beschreibt eine reguläre Sprache L(r).
Reguläre Ausdrücke -‐ DefiniNon <br />
16 <br />
Reguläre Ausdrücke über dem Alphabet A werden durch folgende Regeln indukNv <br />
definiert: <br />
i. ∅ ist ein regulärer Ausdruck, der die reguläre Sprache ∅ beschreibt. <br />
ε ist ein regulärer Ausdruck, der die reguläre Sprache { ε } beschreibt <br />
ii.<br />
iii.<br />
iv.<br />
Für jedes a ∈ A ist a ein regulärer Ausdruck; er beschreibt die Sprache {a}. <br />
Wenn a und b reguläre Ausdrücke sind, die die Sprachen A und B <br />
beschreiben, so ist auch <br />
-‐<br />
-‐<br />
-‐<br />
(a | b ) ein regulärer Ausdruck, der A ∪ B beschreibt, <br />
ab ein regulärer Ausdruck, der AB beschreibt, <br />
a * ein regulärer Ausdruck, der A * beschreibt. <br />
Nichts sonst ist eine regulärer Ausdruck
Reguläre Ausdrücke – vereinfachende NotaNonen 1/2 <br />
17 <br />
Benennung von regulären Ausdrücken <br />
Eine reguläre DefiniNon hat die Form <br />
d 1 → r 1 <br />
d 2 → r 2 <br />
Name<br />
Name<br />
Regulärer Ausdruck über<br />
einem Alphabet A<br />
Regulärer Ausdruck über A<br />
und d 1<br />
. . <br />
d 3 → r 3 <br />
Name<br />
. . . . . <br />
etc. <br />
Regulärer Ausdruck über A<br />
und d 1 , d 2<br />
In r i dürfen nur die Namen d 1 , d , . . ., d i-‐1 vorkommen.
Reguläre Ausdrücke – vereinfachende NotaNonen 2/2 <br />
18 <br />
o Zur Unterscheidung von Namen und Symbolen, werden Namen fe^ <br />
geschrieben. <br />
Priorität<br />
o Die Auswahl ermöglicht die Wahl zwischen 2 AlternaNven: <br />
a | b oder auch a + b (eher ungewöhnlich). <br />
o Die Sequenz (KonkatenaNon) beschreibt das hintereinander Schreiben: ab. <br />
o Die IteraKon ermöglicht das Wiederholen von Satzbausteinen: a* (0, 1 oder <br />
n-‐mal) oder a + (1 oder n-‐mal) ≡ aa* . <br />
o OpNonale Satzbausteine: a? Abkürzung für a | ε (eher ungewöhnlich). <br />
o Zusätzlich besteht die Möglichkeit der Klammerung zur Strukturierung. <br />
Ansonsten gilt „Punkt-‐ vor Strichrechnung“. <br />
o Zeichenklassen: Sta^ char → a | b | c | etc. schreibt man als Abkürzung <br />
auch char → [a – z].
Reguläre Ausdrücke -‐ Beispiele <br />
19 <br />
o Binärzahlen beginnen mit 1, danach kann eine beliebig lange Folge <br />
von 1 und 0 kommen: <br />
1 (1 + 0)* ⇒ 1, 10, 1010, 100000001111 <br />
o Will man auch noch die 0, als einzige mit diesem Symbol startende <br />
Zahl: <br />
0 + 1 (1 + 0)* ⇒ 0, 1, 10, 1010, 100000001111 <br />
o Bezeichner einer Programmiersprache müssen mit einem <br />
Buchstaben beginnen, dürfen nach dem ersten Buchstaben aber <br />
auch Ziffern enthalten: <br />
(a + b + ... + z) (a + b + ... + z + 0 + ... + 9)* ⇒ a, COI, ma07, u2 <br />
o Verwendung von Regulären Ausdrücken in der InformaNk: <br />
¤<br />
¤<br />
Festlegung von Datenformaten für Programmeingaben. <br />
Festlegen von Mustern zum Suchen in Texten.
Zustandsdiagramme <br />
20 <br />
Zustandsdiagramme (transiNon diagrams) sind <br />
• eine graphische NotaNon für determinisNsche endliche Automaten. <br />
• beschreiben die AkNon, die der Scanner bei der Anforderung des nächsten <br />
Token durch den Parser ausführt. <br />
• Die Elemente von Zustandsdiagrammen sind <br />
• Kreise, welche die Zustände bezeichnen. <br />
• Gerichtete Kanten, welche die Zustände miteinander verbinden. <br />
• Die von einem Zustand herausführenden Kanten haben eine Markierung (label). <br />
Das sind die Zeichen, mit denen man in den nächsten Zustand gelangt. <br />
• Es gibt einen ausgezeichneten Startzustand und mindestens einen <br />
ausgezeichneten Endzustand. <br />
Gerichteter,<br />
markierter<br />
Graph
Zustandsdiagramme – Beispiel 1 <br />
21 <br />
a<br />
start<br />
a<br />
0 1<br />
b<br />
b<br />
2
Zustandsdiagramme – Beispiel 2: relaNonale Operatoren <br />
22 <br />
start<br />
< =<br />
0 1<br />
2<br />
return (relop, LE)<br />
><br />
3<br />
return (relop, NE)<br />
=<br />
other<br />
4<br />
*<br />
return (relop, LT)<br />
><br />
5<br />
=<br />
other<br />
6<br />
return (relop, EQ)<br />
return (assop, ...)<br />
7<br />
= 8<br />
other<br />
9<br />
*<br />
return (relop, GE)<br />
return (relop, GT)
Endlicher Automat <br />
23 <br />
Eingabe<br />
aktueller Zustand<br />
Steuerung
Erkennung von Token 1/3 <br />
24 <br />
Der Scanner liest das Quellprogramm zeichenweise ein, um aus den einzelnen Zeichen<br />
die Token aufzubauen.<br />
Dazu wird das Quellprogramm blockweise (gepufferte E/A) von Datei in den<br />
Arbeitsspeicher geladen.<br />
Quellprogramm<br />
Puffer<br />
Scanner arbeitet hier
Erkennung von Token 2/3 <br />
25 <br />
Eingrenzen der Lexeme im Puffer mit Hilfe zweier Zeiger:<br />
vorher:<br />
i f ( a < b<br />
anfang<br />
ende<br />
nachher:<br />
i f ( a < b<br />
anfang<br />
ende<br />
Rück-setzen:<br />
i f ( a < b<br />
anfang ende Nächstes Token
Erkennung von Token 3/3 <br />
26 <br />
Fortsetzung:<br />
i f ( a < b<br />
anfang<br />
ende<br />
Problem: Wenn das Pufferende erreicht ist, ohne dass bis dahin ein Token erkannt<br />
wurde.<br />
Lösung: 2 Puffer, die abwechselnd gefüllt werden. Die beiden Zeiger laufen über<br />
beide Puffer im Kreis.
Token, Lexeme und Pa^ern <br />
27 <br />
Token<br />
interne Darstellung (für Parser) – Aufbau ist durch Regeln<br />
beschrieben.<br />
Pattern Menge von Strings, die durch eine Regel beschrieben werden und<br />
mit einem Token verknüpft sind.<br />
Lexem konkrete Ausprägung eines Pattern für einen Token.<br />
Merke: Verschiedene Strings (Pattern) können auf dasselbe Token<br />
abgebildet werden.<br />
Bsp.: const pi = 3.1416;<br />
Token = id<br />
Lexem = pi
Token, Lexeme und Pa^ern -‐ Beispiele <br />
28 <br />
Token Ausprägung (Lexem) Pattern-Beschreibung<br />
const final final<br />
if if if<br />
rel_op = < oder oder >=<br />
id pi, count Buchstabe gefolgt von<br />
Buchstaben-Ziffern<br />
Kombination<br />
num 3.1416, 0, 6.0E23 numerische Konstante<br />
literal “any string“ Zeichen zwischen “<br />
und “ außer “
Interne Darstellung lexikalischer Elemente 1/3 <br />
29 <br />
Für jedes Lexem wird ein Paar ( Kategorie, Index) erzeugt.<br />
Typische Kategorien: Bezeichner id<br />
Zahlen num<br />
Zeichenketten string<br />
Schlüsselworte key<br />
Beispiel:<br />
if (max == 4711)<br />
name = “Madonna“;<br />
Operatoren mulop<br />
addop<br />
relop<br />
Trennzeichen delimiter
Interne Darstellung lexikalischer Elemente 2/3 <br />
30 <br />
Der Index kennzeichnet ein lexikalisches Element entweder innerhalb seiner<br />
Kategorie oder er ist eine Referenz in die Symboltabelle.<br />
Beispiel: (relop, 1) à <<br />
(relop, 2) à =<br />
(relop, 6) à ><br />
Kategorie:<br />
Vergleichsoperator<br />
à EQUAL -<br />
Operation<br />
(mulop, 1) à *<br />
(mulop, 2) à /
31 <br />
Interne Darstellung lexikalischer Elemente -‐ <br />
Symboltabelle 3/3 <br />
Symbol Attribute<br />
Index<br />
3 if<br />
... ...<br />
14 max<br />
... ...<br />
40 4711<br />
... ...<br />
51 name<br />
... ...<br />
63 “Madonna“<br />
Beispiel:<br />
if (max == 4711)<br />
name = “Madonna“;<br />
Beispiel:<br />
(key, 3)<br />
(id, 14)<br />
(rel_op, 3)<br />
(num, 40)<br />
(id, 51)<br />
(string, 63)
ImplemenNerung eines Übergangsdiagramms 1/3 <br />
32 <br />
Direkte Umsetzung mittels einer Variablen state.<br />
Die Zustände werden ab 0 beginnend über alle Zustandsdiagramme<br />
durchnummeriert.<br />
letter | digit<br />
start<br />
letter<br />
0 1<br />
other<br />
2<br />
< =<br />
3 4<br />
5<br />
Idee: Scanner versucht Diagramme in der Reihenfolge<br />
andere<br />
ihrer Auflistung<br />
Diagramme<br />
zu<br />
durchlaufen.<br />
Falls ein Fehler auftritt, erfolgt der Übergang zum Start des nächsten Diagramms.<br />
Dabei ist der Zeiger end im Puffer auf start zurückzusetzen.
ImplemenNerung eines Übergangsdiagramms 2/3 <br />
33 <br />
iniNalisiere start, state <br />
while kein markierter Endzustand erreicht do <br />
case state of <br />
0: lies_zeichen (zeichen) <br />
if zeichen ist Buchstabe then state := 1 <br />
else fehler <br />
1: lies_zeichen (zeichen) <br />
if zeichen ist Buchstabe oder Ziffer then state := 1 <br />
else state := 2 <br />
2: setze ende eine PosiNon zurück // Endzustand erreicht <br />
teste in Symboltabelle, ob Schlüsselwort / Bezeichner gefunden, falls noch nicht <br />
vorhanden, trage es ein, gib entsprechendes Element zurück; markiere Endzustand.
34 <br />
end<br />
end<br />
ImplemenNerung eines Übergangsdiagramms 3/3 <br />
3: lies_zeichen (zeichen)<br />
if zeichen = ‘
NichtdeterminisNsche endliche Automaten <br />
35 <br />
o<br />
Ein nichtdeterminisNscher endlicher Automat (NEA oder NFA) ist ein <br />
o<br />
Tupel M = (A, MOVE, S, s 0 , F), wobei <br />
• A ein endliches Alphabet von Eingabezeichen ist, <br />
• S eine endliche Menge von Zuständen (state) ist, <br />
• s 0 ∈ S der Anfangszustand ist, <br />
• F ⊆ S die Menge der Endzustände (final states) ist, und <br />
• MOVE die ÜbergangsrelaKon, die (Zustands, Symbol)-‐Paare mit einer Menge <br />
von Zuständen verbindet, ist. <br />
MOVE : (state, symbol) à {state} bzw. MOVE : S x (A ∪ {ε} )à {S}
NFA -‐ Beispiel <br />
36 <br />
Hinweise:<br />
• Dasselbe Eingabesymbol kann mehrere Übergänge eines Zustands markieren.<br />
• Die Übergänge können sowohl mit ε als auch mit Eingabesymbolen markiert<br />
sein.<br />
NFA der die Sprache: (a | b)*abb erkennt.<br />
a<br />
start<br />
0<br />
a<br />
b<br />
b<br />
1 2 3<br />
b
NFA -‐ Anmerkungen <br />
37 <br />
o<br />
o<br />
Ein NFA akzepNert einen Eingabestring x, genau dann wenn es einen Pfad vom <br />
Startzustand zu einem Endzustand im Zustandsdiagramm gibt, dessen <br />
Kantenmarkierungen zusammen gefasst x ergeben. <br />
Da die Zustandsübergänge nicht eindeuNg sind, gibt es immer mehrere <br />
mögliche AlternaNven bei der Auswahl eines Übergangs. Wenn man den <br />
„falschen“ Übergang auswählt, kann es passieren, dass ein eingeschlagener <br />
Pfad in die Irre führt (à MehrdeuNgkeit, d.h. Nicht-‐determinismus). Der NFA <br />
muss „raten“, welchen Pfad er einschlagen soll. Hat der NFA „falsch geraten“, <br />
würde ein korrekter Eingabestring nicht akzepNert. Man muss dann sehr viele <br />
AlternaNven (à Backtracking) ausprobieren, um zu einer Entscheidung zu <br />
kommen.
DeterminisNsche endliche Automaten <br />
38 <br />
o<br />
Ein determinisNscher endlicher Automat (DEA oder DFA) ist ein spezieller Fall <br />
eines nichtdeterminisNschen endlichen Automaten, für den gilt: <br />
• Es gibt keinen Zustand mit einem ε-Übergang, d.h. keinen Übergang ohne ein <br />
Eingabesymbol zu verarbeiten. <br />
• Für jeden Zustand s und jedes Eingabesymbol a gibt es höchstens eine Kante <br />
von s ausgehend, die mit a markiert ist. <br />
Die ÜbergangsfunkKon MOVE verbindet die (Zustands, Symbol)-‐Paare mit <br />
einem Zustand. <br />
MOVE : (state, symbol) à state bzw. MOVE : S x A à S.
DFA -‐ Beispiel <br />
39 <br />
Hinweise:<br />
• Dasselbe Eingabesymbol kann nur einen Übergang eines Zustands markieren.<br />
• Die Übergänge können nicht mit e markiert sein.<br />
DFA, der die Sprache: (a | b)*abb erkennt.<br />
b<br />
b<br />
start<br />
0<br />
a<br />
b<br />
b<br />
1 2 3<br />
a<br />
a<br />
a
RA, NFA und DFA <br />
40 <br />
o<br />
Warum betrachtet man überhaupt die NFA? <br />
o<br />
Für die (direkte) ImplemenNerung eines Scanners benöNgt man einen DFA und <br />
den kann man immer angeben. <br />
o<br />
o<br />
Für Erzeugung (Generierung) man eines Scanners benöNgt man reguläre <br />
Ausdrücke (RA) als Metasprache. <br />
Dann kommen folgende Sätze zur Anwendung: <br />
1. Zu jedem regulären Ausdruck r gibt es einen NFA, der die von r beschriebene <br />
reguläre Menge akzepNert. <br />
2. Wird eine Sprache von einem NFA akzepNert, so gibt es einen DFA, der L <br />
akzepNert.
Generierung eines Scanners mit LEX <br />
41 <br />
lex.l<br />
Lex-<br />
Spezifikation<br />
Reguläre Ausdrücke für<br />
Sprache L<br />
Lex<br />
lex.yy.c<br />
Scanner in C-<br />
Code<br />
Scanner<br />
C-Compiler<br />
yyin<br />
Quellpro-gramm<br />
in L<br />
yylex<br />
Scanner<br />
Tokenfolge
Lex DeklaraNonsdatei -‐ Struktur <br />
42 <br />
Deklarationen<br />
- in der Wirtssprache (globale Vereinbarungen)<br />
- Ersetzungsdeklarationen<br />
- Startzustände (Anfangsbedingungen)<br />
- Zeichensatzdeklarationen<br />
- Festlegungen für Lex-Tabellen<br />
%%<br />
Tokendefinitionen<br />
- Lex-Regeln und Aktionen (in der Wirtssprache)<br />
%%<br />
Hilfsprozeduren (zusätzlicher Programmcode in der Wirtssprache)
Lex -‐ DeklaraNonsteil <br />
43 <br />
Deklarationen sind z.B. Konstanten als Tokendarstellungen<br />
%{<br />
#define IDENTIFIER 1000<br />
#define REL_OP 1100<br />
#define LT_OP 1101<br />
. . .<br />
%}<br />
und reguläre Definitionen<br />
sign [+-]<br />
digit [0-9]<br />
letter<br />
[A-Za-z]<br />
globale<br />
Deklarationen<br />
C-Makroprozessoranweisungen<br />
Lex Deklarationen<br />
Basiselemente
Lex – Regeln und AkNonen <br />
44 <br />
Paare (Reguläre Ausdrücke; auszuführende Aktion)<br />
Lex -‐ Regelbearbeitung <br />
45 <br />
o Lex versucht mit seinem Regelsystem im (sequenNellen) Eingabestrom (Datei <br />
yyin) das nächste Lexem zu finden. <br />
o Bei einem Regeldurchlauf können auch mehrere oder gar kein Lexem gefunden <br />
werden. <br />
o Das Ergebnis kann sein: <br />
o Die Regel, die das längst mögliche Lexem beschreibt, wird als erste Wahl <br />
ermi^elt und der rechte Teil der Regel (AkNonen in C) wird ausgeführt. <br />
o Mehrere Regeln können gleich lange Lexeme erkennen. In diesem Fall wird die <br />
zuerst platzierte Regel erste Wahl und ausgeführt. <br />
o Mit dem nächsten Eingabezeichen kann das Regelsystem kein Lexem <br />
erkennen. Der Text wird dann solange zeichenweise in die Standardausgabe <br />
(Datei yyout) kopiert, bis das Regelsystem ein neues Lexem findet.
Lex -‐ NotaNon der RA 1/4 <br />
46 <br />
Zeichen vs. Metazeichen<br />
Die Zeichen zur Beschreibung der regulären Ausdrücke nennt man Metazeichen bzw.<br />
Metasymbole.<br />
Metasymbole:<br />
. $ ^ [ ] - ? * + | ( ) / { } < > “ \<br />
Alle anderen Zeichen stehen für sich selbst. Will man ein Metasymbol als normales<br />
Zeichen benutzen à einschließen in “ “
Lex -‐ NotaNon der RA 2/4 <br />
47 <br />
Metasymbol Bedeutung Beispiel<br />
[ ] Zeichenklassen [aby&]<br />
- Bereich [A-Z]<br />
^ Komplement [^0-9]<br />
? optional [-+]?<br />
| Alternative a|bc<br />
+ ein- oder mehrmals {digit}+<br />
* 0 oder mehrmals {letter}*<br />
() normale Klammerung (a|bc)*
Lex -‐ NotaNon der RA 3/4 <br />
48 <br />
Metasymbol Bedeutung Beispiel<br />
. alle Zeichen außer<br />
newline (\n)<br />
^ $ Ausdruck am Zeilenan- ^hallo \t$<br />
fang oder –ende<br />
/ Vorausschau -/{digit}+<br />
{ } Kennzeichen eines {digit}<br />
regulären Symbols<br />
“ \ Escape-Zeichen “....“ \“<br />
Whitespaces müssen in Anführungszeichen gesetzt werden.<br />
Konkatenation: Hintereinanderschreiben<br />
Es gibt weitere Bedeutungen der Metasymbole!
Lex -‐ NotaNon der RA 4/4 <br />
49 <br />
Metasymbol Bedeutung Beispiel<br />
{ } Anzahl der Wieder- [A-Z] {3}<br />
holungen eines<br />
regulären Ausdrucks A {2, 5}<br />
Pattern wird nur im Zustand<br />
betrachtet.<br />
A {1, }<br />
A {0, }<br />
erkennt end of file nur in flex
Prioritäten der Metasymbole <br />
50 <br />
|<br />
{ }<br />
Konkatenation<br />
* + ?<br />
( ) /<br />
<br />
“ \<br />
Die anderen Metasymbole werden nur alleine verwendet.
Einige FunkNonen der Lex-‐Bibliothek <br />
51 <br />
yylex(): Aufruf von Lex.<br />
input(): Liefert das nächste Zeichen des Eingabestroms.<br />
unput(c):<br />
yymore():<br />
Schreibt das Zeichen c in den Eingabestrom zurück (d.h. in den<br />
sog. Rückstell-Stack)<br />
Dieses Zeichen wird beim nächsten Regeldurchlauf oder input<br />
()-Aufruf zurück geliefert.<br />
Funktion verhindert das Löschen der Variablen yytext bei<br />
Regelabschluss. Die Zeichenkette, die durch die nächste Regel<br />
erkannt wird, wird an das Ende der aktuellen yytext-<br />
Zeichenkette angehängt.<br />
yyless(anz): Rückstellen von Zeichen des Eingabestroms. Von den erkannten<br />
Zeichen sollen nur die Zeichen 1..anz erhalten bleiben, der Rest<br />
wird in den Rückstellstack zurück geschoben.
52 <br />
identifier<br />
integer<br />
Pascal-Kommentar<br />
Whitespace<br />
float<br />
Beispiele für Lex-‐Regeln <br />
[A-Za-z][A-Za-z0-9_]*<br />
[-+]?[0-9]+<br />
\{[^\}]*\}<br />
[ \t\n]<br />
[-+]?[0-9]+(/.[0-9]+)?<br />
(E[-+]?[0-9]+)?
Lex-‐Beispielprogramm 1/2 <br />
53 <br />
%{<br />
/* Zählen: Lexeme, Zeichen und Zeilen */<br />
int anz_zeichen = 0, anz_lexeme = 0, anz_zeilen = 0;<br />
%}<br />
%%<br />
[^ \t\n]+ {/* kein Blank, Tab, nl */<br />
++anz_lexeme;<br />
anz_zeichen += yyleng; }<br />
. { /* bel. Zeichen außer nl */<br />
++anz_zeichen; }<br />
\n { /* nl */<br />
++anz_zeichen; ++anz_zeilen;}<br />
%%
Lex-‐Beispielprogramm 2/2 <br />
54 <br />
main () {<br />
yylex(); /* Aufruf von Lex */<br />
/* Lex erkennt o. spezifizierte Token bis<br />
eof der Eingabe */<br />
printf (“Anz. Zeichen =\t%d\n“<br />
“Anz. Zeilen =\t%d\n“<br />
“Anz. Lexeme =\t%d\n“,<br />
anz_zeichen, anz_zeilen, anz_lexeme);<br />
}
55 <br />
Lex -‐ Auswertung der Kontextbeziehungen des <br />
Eingabestrings <br />
Linker<br />
Kontext<br />
Eingabestring<br />
Rechter<br />
Kontext<br />
Zugriff auf linken Kontext:<br />
• Merkvariablen auf der Aktionsseite (im C-Code).<br />
• Anfangsbedingungen (Startzustände- start states)<br />
Zugriff auf rechten Kontext:<br />
• Lookahead-Metasymbol / (in Lex-Regeln)<br />
• yyless(anz) – Funktionsausfruf (Aktionsseite – C-Code)<br />
• REJECT – Makroaufruf (Aktionsseite – C-Code)
Lex – REJECT-‐Mechanismus <br />
56 <br />
• REJECT – Makroaufruf<br />
Weist die Regel und die erkannten Inputzeichen zurück.<br />
Danach wird die nächste passende Regel gesucht.<br />
Gibt es in mehreren Regeln REJECT-Aufrufe, werden diese jeweils zurückgewiesen und<br />
die nächsten passenden Regeln der Reihe nach gesucht.<br />
Terminierung: entweder eine Regel ohne REJECT-Aufruf oder „konsumieren“ des ersten<br />
Zeichens des Inputs per default-Regel.
Lex – REJECT Beispiel <br />
57 <br />
%%<br />
[a-z]* { /* Regel 1 */<br />
printf("Regel 1 mit %s\n", yytext);<br />
REJECT;<br />
}<br />
[a-z][a-z] { /* Regel 2 */<br />
printf("Regel 2 mit %s\n", yytext);<br />
REJECT;<br />
}<br />
[a-z] { /* Regel 3 */<br />
printf("Regel 3 mit %s\n", yytext);<br />
REJECT;<br />
}<br />
%%