Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

52
Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel

Transcript of Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

Page 1: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

Vorlesung CompilertechnikSommersemester 2008

Lexikalische Analyse

M. Schölzel

Page 2: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

2

Aufgabe des Scanners

Grundlage ist eine endliche Menge von regulären Sprachen (Morphemarten).

Strukturierung der Zeichen des Quelltextes zu Morphemen, wobei jedes Morphem zu (genau) einer regulären Sprache gehören muss.

f o r i d = 0 t o 1 d o \n0

j : = 6 * i d \n

o d \n

for id = 0 to 10 do \n

j := 6 * id \n

od \n

Schlüsselworte

Bezeichner

Operatoren

Integerliterale

Trenner

Scanner, fasst Zeichen zu Morphemen zusammen …

… und reicht Token an den Parser weiter, wobei beim Parsing nur die Morphemart beachtet wird.

(Schlüsselwort,for),(Bezeichner,id),(Operator,=),(Integerliteral,0),(Schlüsselwort,to), (Integerliteral,10),…

Page 3: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

3

Gestaltung der Morphemarten

Problem in diesem Beispiel: Schlüsselworte sind nicht mehr für den Parser unterscheidbar!

Besser: Jedes Schlüsselwort bildet eine eigene Morphemart, die nur dieses Schlüsselwort als Element enthält.

Allgemein: Eine Morphemart sollte nur solche Morpheme enthalten, die während der syntaktischen Analyse wie ein Terminalsymbol behandelt werden können und deren spezifische Bedeutung nicht relevant für die Erzeugung des Syntaxbaums ist.

while do

od

if then

fi

Page 4: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

4

Typische Morphemarten

Bezeichner Integerliterale Gleitkommaliterale Zeichenkettenliterale Relationale Operatoren Eine Morphemart für jeden

arithmetischen/logischen/bitweisen Operator Eine Morphemart für jedes Punktierungssymbol (Klammern,

Semikolon, Komma,…) Kommentare (werden oft vom Scanner nicht an den Parser

weitergereicht) Trenner (werden im Allgemeinen nicht an den Parser

weitergereicht) …

Page 5: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

5

Präzisierung der Begrifflichkeiten

Eine Morphemart ist eine reguläre Wortmenge. Ein Morphem (auch Lexem) ist ein Element einer

Morphemart. Ein Morphem entspricht damit einer im Quelltext durch den Scanner erkannten Zeichenkette.

Ein Token ist ein Zweitupel bestehend aus einer Morphemart und einer dem erkannten Morphem zugeordneten Bedeutung. Der Scanner liefert an den Parser Token, von denen der Parser während der Analysephase nur die Morphemart nutzt. In späteren Phasen wird auch die Bedeutung benötigt.

Die Morphemarten entsprechen damit den Terminalsymbolen der Grammatik, auf der der Parser basiert.

Page 6: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

6

Notation

Modifikation der BNF-Schreibweise Metasymbole beginnen immer mit einem Großbuchstaben. Terminalsymbole werden dargestellt durch

in Gänsefüßchen eingeschlossene Zeichen/Zeichenketten oder Zeichen, die kein Großbuchstabe sind, falls dieses Zeichen das

einzige Morphem seiner Art ist oder kursiv gesetzte Metasymbole, falls dieses Terminalsymbol eine

Morphemart mit mehr als einem Morphem repräsentiert. Beispiel:

Kontextfreie Syntax:REG ::= ALTALT ::= KON | KON "|" ALTKON ::= SYM | SYM . KONSYM ::= Bezeichner | | ( REG ) | ( REG )*

Lexikalische Syntax:Bezeichner := *

Page 7: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

7

Einbettung des Scanners in den Compiler

Der Scanner erhält den gesamten Quelltext als Eingabe und stellt die Funktion nextMor bereit, bei deren Aufruf:

ein Präfix der noch nicht verarbeiteten Eingabe hinsichtlich seiner Morphemart klassifiziert und die Morphemart sowie die erkannte Zeichenkette (oder deren Bedeutung) an den Parser in Form eines Tokens übergeben werden,

die Eingabe um den erkannten Präfix gekürzt wird, so das beim nächsten Aufruf von nextMor diese Zeichen nicht mehr betrachtet werden,

der Scanner einen Fehler erzeugt, wenn kein Präfix einer Morphemart zugeordnet werden kann

ParserQuell-text

Quell-text Scanner

Frontend

Aufruf von nextMor

Rückgabe eines Tokens

Token

Page 8: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

8

Abgrenzung Scanner und Parser

Ohne Scanner müsste der Parser die Verarbeitung aller Zeichen übernehmen:

Mit Scanner kann der Parser mit Morphemarten als Terminalsymbole arbeiten:

Atom ::= Number | Ident | ...Ident ::= Letter | Ident LetterNumber ::= Digit | Digit NumberLetter ::= "a" | ... | "z" | "A" | ... | "Z"Digit ::= "0" | ... | "9"

Kontextfreie SyntaxAtom ::= Number | Ident | ...

Lexikalische Syntax:Number := {0,1,2,3,4,5,6,7,8,9}+

Ident := {a,…,z,A,…,Z}+

Page 9: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

9

Gründe für separate Implementierung des Scanners

Vereinfachung des Parsers durch Verlagerung spezifischer Aufgaben in den Scanner (z.B. Elimination von Trennern und Kommentaren)

Erhöhung der Verarbeitungsgeschwindigkeit durch spezialisierte Techniken im Scanner.

Kapselung von I/O-Operationen im Scanner. Dadurch Erhöhung der Portabilität des Compilers

Grundsätzlich könnte aber auch der Parser die Aufgabe des Scanners übernehmen

Page 10: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

10

Theoretisches Modell für den Scanner

Endlicher Automat A = (Z, , z, F, ) mit: Z – endliche Zustandsmenge – endliches Eingabealphabet z Z – Startzustand F Z – Menge von Endzuständen Z Z – Überführungsrelation

Situation (p,) Z * gekennzeichnet durch: p – aktueller Zustand – anliegende Eingabe (wird von links nach rechts gelesen)

Situationsübergänge: := {((p,a), (q,)) | a und * und (p,a,q) } oder kurz: (p,a) (q,)

Akzeptierte Sprache: L(A) = { | (z,) * (q,) und q F} Dieses Modell dient nur der Spezifikation der

Morphemarten. Zur Verwendung bei der Implementierung des Scanners so

oft nicht eingesetzt, da dort auf "einfache Weise" entschieden werden muss, wann ein Morphem endet.

Page 11: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

11

Determinisierung eines endlichen Automaten

Ein endlicher Automat ist deterministisch, falls für alle a und z Z gilt, dass aus (z,a,q) und (z,a,p) folgt, dass q = p.

Gegeben ist ein nichtdeterministischer Automat A = (ZA,,zA,FA,A)

Ein deterministischer Automat D = (ZD,,{zA},FD,D) mit L(D) = L(A) wird konstruiert durch die bzgl. Mengeninklusion kleinsten Mengen ZD und D für die gilt

ZD = ZD {{zA}} {{p | (r,a,p) D und r q}| a und q ZD}

D = D {(q,a,p) | q,p ZD und a und (z,a,z') A, wobeiz q und z' p}

Außerdem: FD := {q | q ZD und q FA }

Page 12: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

12

Determinisierung eines Beispielautomaten

1

2b

a

0 b

a

b

a

3

4

b a

b

b

b

a

a

a

Page 13: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

13

Erkennung der Morpheme mit einem endlichen Automaten

Spezifikation der endlichen Automaten A1,…,An zur Erkennung der Morphemarten L(A1),…,L(An)

Der Scanner der Quellsprache Q muss dann folgende Sprache erkennen:L = {w0w1…wk | ij: 0 i k 1 j n und wi L(Aj)}

Konstruktion des Automaten A = (Z, , z, F, ) mit L(A) = L aus den Automaten Ai = (Zi, , zi, Fi, i) :

Z ist Vereinigung der disjunkten Mengen Z1,…,Zn z ist neuer Startzustand F := F1 … Fn := 1 … n {(z,a,z') | i: (zi,a,z') i}

{(z,a,z') | ij : z Fi und (zj,a,z') j} Simulation des Laufs von A bei gegebener Eingabe w Problem: Erkennung der wi in w

Page 14: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

14

Determinismus vs. Nichtdeterminismus

Zwei Möglichkeiten zur Simulation eines endlichen Automaten A:

Konstruktion eines deterministischen endlichen Automaten A' zu A. Verarbeitung der Eingabe damit in Echtzeit möglich.

Simulation des nichtdeterministischen Automaten A. Verarbeitung der Eingabe durch gleichzeitige Simulation aller möglichen Pfade.

Als akzeptierender Lauf eines Automaten A = (Z, , z, F, ) bei Eingabe w = a0…an wird eine Folge von Zuständen z0,z1,…,z|w| bezeichnet, für die gilt:

z0 = z ist Startzustand z|w| F Für alle 0 i |w|-1: (zi,ai,zi+1)

Page 15: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

15

Simulation eines deterministischen Automaten

Speichern des aktuellen Zustands in einer Variablen z

Der Startzustand sei 0 Nächstes Eingabesymbol wird durch nextChar()

abgerufen (Rückgabe = 0, falls kein weiteres Zeichen existiert)

Folgezustand ist durch nächstes Eingabesymbol eindeutig bestimmt:Lauf := 0z := 0while(c = nextChar()) do if p: (z,c,p) then z := p else Error Lauf := Lauf zodIf z F then Akzeptieren else Verwerfen

Page 16: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

16

Simulation eines nichtdeterministischen Automaten

Verwendung zweier Stapelspeicher Abwechselnd speichern Stapel 1 und Stapel 2 die möglichen

Zustände, in denen sich der nichtdeterminsitische Automat befinden kann:s1 : stacks2 : stackLauf := {0}

s1.push(0)while(c = nextChar()) do while(s1 nicht leer) do p := s1.pop nz := Für alle q Z für die ein (p,c,q) existiert do s2.push(q) nz := nz {q} od Lauf := Lauf nz od Tausche Inhalte von s1 und s2odIf s1 enthält einen Endzustand then Akzeptieren else Verwerfen

Page 17: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

17

Motivation der Modifikationen des Automatenmodells

Das Automatenmodell für den Scanner muss von einer Zeichenkette einen Präfix als Morphem erkennen. Es muss also entschieden werden, wann das Ende eines Morphems erreicht ist:

Für Morphemarten mit explizitem Abschluss einfach; Ende wird am letzten zum Morphem gehörenden Zeichen erkannt, z.B. Zeichenkettenliterale in Gänsefüßchen.

Für Morphemarten mit implizitem Abschluss schwieriger; Ende wird erst erkannt wenn Zeichen gesehen wurden, die auf das Morphem folgen. Deshalb Einschränkung auf den Fall: Ende ist erkennbar, wenn das nächste, nicht zum Morphem gehörende Zeichen gesehen wurde.

Vereinheitlichung: Morphemarten mit explizitem Abschluss werden wie Morphemarten mit implizitem Abschluss behandelt.

Konsequenzen: Der modifizierte Automat arbeitet mit einem „Look-Ahead“-Symbol.

Beim Übergang in einen akzeptierenden Endzustand darf das anliegende Look-Ahead-Symbol nicht gelesen werden.

Um am Ende der Eingabe ein Morphem mit implizitem Abschluss zu erkennen, wird an die Eingabe ein spezielles Endesymbol angehangen, das die Morphemart {} bildet.

Der Startzustand ist niemals ein Endzustand, weil in der Praxis die Erkennung des leeren Wortes zu einer Endlosschleife im Scanner führen würde.

Page 18: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

18

Modifizierter deterministischer endlicher Automat für eine Morphemart

Wir betrachten reduzierte deterministische endliche Automaten, d.h. jeder Zustand ist vom Startzustand aus erreichbar und von jedem Nicht-Endzustand ist ein Endzustand erreichbar

Zulässige Situationsübergänge: (p,a) (q,), falls q F und (p,a,q) (p,a) (q,a), falls q F und (p,a,q)

Die akzeptierten Morpheme eines Automaten sind dann { | ( )+: (z,) * (q,) und q F}

Grundsätzlich kann die lexikalische Analyse des gesamten Textes

durch einen einzigen Automaten zur Erkennung aller Morphemarten oder

mehrere Automaten, von denen jeder genau eine Morphemart erkennt, durchgeführt werden.

Grundlage für ein rein mechanisches Vorgehen ist jedoch immer die separate Konstruktion der Automaten für jede Morphemart

Page 19: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

19

Transformation in modifizierten Automaten

Ein deterministischer endlicher Automat A = (ZA,,zA,FA,A) kann in einen modifizierten Automaten M = (ZM, {},zA,FM,M) transformiert werden durch:

ZM := ZA {e}, wobei e ZA

M := A {(q,a,e) | q FA und p ZA: (q,a,p) A} FM := {e}

M ist wieder deterministisch Da beim Übergang in den Endzustand das bis

dahin erkannte Morphem nicht mit dem Look-Ahead-Symbol a im Automaten A fortgesetzt werden kann, ist a kein Präfix eines anderen Morphems dieser Art.

Page 20: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

20

Beispiel: Relationale Operatoren

An eine Kante dürfen auch mehrere Zeichen geschrieben werden

Alphabet sei X mit der Menge aller druckbaren ASCII-Zeichen und dem EOF

0 1 2< =

>

3

5

=

6 7=

>

0 1 2< =

3

>

x - {=,>}

x

x

45

x

=

6 7=x

>

x - {=}

Page 21: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

21

Beispiel: Bezeichner

0 1{a,…,z,A,…,Z}

{a,…,z,A,…,Z,0…,9}

0 1{a,…,z,A,…,Z}

{a,…,z,A,…,Z,0…,9}

2X - {a,…,z,A,…,Z,0…,9}

Page 22: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

22

Beispiel: Schlüsselworte und Trenner

0 1i f

2 0 1i f

2X

3

0 1t h

42e

3n

0 1t h

52e

3Xn

4

0 1e l

42s

3e

0 1e l

52s

3Xe

4

0 1

0 1

{Blank, Tab, Newline}

2X - {Blank Tab, Newline}

{Blank, Tab, Newline}

{Blank, Tab, Newline}

{Blank, Tab, Newline}

0 1EOF

0 2EOF

1X

Page 23: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

23

Beispiel: Gleitkommazahlen

0 1{0,…,9} .

2

{0,…,9}

3{0,…,9} E

4

{0,…,9}

E

{+,-}5 6{0,…,9}

{0,…,9}

7{0,…,9}

{0,…,9}

0 1{0,…,9} .

2

{0,…,9}

3{0,…,9}

E 4

{0,…,9}

E

{+,-}5 6{0,…,9}

{0,…,9}

7{0,…,9}

{0,…,9}

8X - {0,…,9,E} X - {0,…,9}

X - {0,…,9}

Page 24: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

24

Eigenschaften der Transformation in modifizierten Automaten

Es sei M ein modifizierter Automat, der aus dem deterministischen Automaten A erzeugt wurde. Falls L(M), dann ist auch L(A).

Falls L(A), dann auch L(M) (in jedem Fall für die Fortsetzung ) Aber: Nicht für jede Fortsetzung wird ein Morphem L(A) erkannt Zum Beispiel: Modifizierter Automat für {-, <, -->} läuft bei

Eingabe ---> in Sackgasse Ähnliche Fälle treten in realen Programmiersprachen auf; Beispiel

aus C: a = b+++++c; Scanner benötigt Trenner für korrekte Erkennung der Morpheme + und ++

Schwierigkeit: Modifizierter Automat muss des Ende eines Morphems erkennen

Mit einem Lookahead von 1 kann der transformierte Automat diese Entscheidung nicht immer treffen und kann in eine Sackgasse laufen.

Lösung, die manchmal hilft: Zerlegung einer Morphemart in mehrere Morphemarten; man erhält mehrere Automaten

Generelles Problem: Zerlegung der Eingabe in eine Folge von Morphemen durch Simulation eines Automaten je Morphemart

Page 25: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

25

Zerlegung der Eingabe in Morpheme

Variante 1 Die einzelnen Automaten werden sequentiell mit derselben

Eingabe simuliert Beim ersten akzeptierenden Automaten wird die Simulation

beendet und das erkannte Morphem an den Parser übergeben. Problem: Reihenfolge kann wichtig sein: z.B. wenn der Präfix

eines Bezeichners ein Schlüsselwort ist Variante 2

Die einzelnen Automaten werden parallel simuliert Der Automat, der die längste Eingabe akzeptiert hat, legt das

Token für den Parser fest Variante 3

Aus den einzelnen Automaten A1,…,An wird ein Automat konstruiert, der die Sprache L(A1) … L(An) akzeptiert und ein Wort nur dann als Morphem akzeptiert, wenn dieses nicht echter Präfix eines anderen akzeptierten Wortes ist. Dadurch wird es beispielsweise möglich --> auch dann zu erkennen, wenn – erkannt werden soll.

Page 26: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

26

Variante 1 (Sequentielle Simulation)

Es seien A1,…,An die deterministischen Automaten für die Morphemarten M1,…,Mn.

Die Funktion nextMor ist dann definiert als:

Der nächste Aufruf der Funktion nextMor durch den Parser erfolgt dann mit der Zeichenkette , wobei =

( ), falls : und ( ) und

( ) : :1 und ( )

, falls :1 und ( )

i i

j

j

M L A

nextMor j j i L A

error j j n L A

b b b a b

a g g a g

b b a b

ìï $ Îïïïïï= " " £ < Þ Ïíïïï " " £ £ Þ Ïïïïî

ð

ð

ð

Page 27: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

27

Variante 2 (Parallele Simulation)

Es seien A1,…,An die deterministischen Automaten für die Morphemarten M1,…,Mn.

Die Funktion nextMor ist dann definiert als:

Der nächste Aufruf der Funktion nextMor durch den Parser erfolgt dann mit der Zeichenkette , wobei =

( ), falls : und ( ) und

:1 und ( ) ( ) :

oder | | | |

, falls :1 und ( )

i i

j

j

M i L A

j j i n L AnextMor

error j j n L A

b b b a b

g g a ga

g b

b b a b

ì $ $ Îïïïïï " " £ ¹ £ Þ Ïïïï= íï <ïïïï " " £ £ Þ Ïïïîï

ð

ð

ð

Page 28: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

28

Variante 3 (voll-parallele Simulation)

Es seien Ai = (Zi, , zi, Fi, i) die deterministischen (unmodifizierten) Automaten für die Morphemarten Mi mit 1 i n.

Es wird ein neuer Automat A = (Z, , z, F, ) konstruiert: Z := Z1 … Zn {z} := 1 … n {(z,a,p) | ia: (zi,a,p) i} F := F1 … Fn

A in einen deterministischen Automaten D umgewandelt

Page 29: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

29

Variante 3 (Fortsetzung)

Für jeden Zustand q von D gilt: i: |q Zi| 1. Ein Lauf von D ist also eine parallele Simulation der Automaten Ai.

Ein Präfix eines Wortes a wird als Morphem der Art i akzeptiert, wenn

D durch Lesen von in den Zustand q gelangt und q Fi und von q kein akzeptierender Zustand mit einem beliebigen

nichtleeren Präfix von erreichbar ist. Insbesondere für die Realisierung des letzten Punktes muss in

der Implementierung des Automaten D oft mehr von der Eingabe gelesen werden, als zum akzeptierten Morphem gehört. D.h. es werden solange Eingabezeichen verarbeitet, wie ein Situationsübergang möglich ist und der letzte akzeptierende Zustand gespeichert.

Ein Fehler tritt auf, wenn kein Situationsübergang mehr möglich ist und bis dahin auch kein akzeptierender Zustand erreicht wurde.

Page 30: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

30

Implementierung eines Scanners

Manuell Entweder syntaxgebunden nach Variante 1 oder 2:

Kodierung der det. modifizierten Automaten als Quelltext einer Programmiersprache

nur für sehr kleine Scanner geeignet Modifikation des Verhaltens sehr schwierig

oder syntaxgesteuert nach Variante 1 oder 2: Det. modifizierte Automaten werden durch eine Tabelle

gesteuert Nur für kleine Scanner geeignet Einfache Modifikation des Verhaltens

oder individuell an die Morpheme angepasst Werkzeugunterstütz durch einen Scannergenerator

Spezifikation der Morphemarten und Morpheme (z.B. durch reguläre Ausdrücke)

Exemplarisch betrachten wir Flex (arbeitet nach Variante 3)

Page 31: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

31

Syntaxgebundene manuelle Implementierung

int isRelOp(int pos) { int state = 0; // Startzustand while(1) { switch(state) { case 0: switch(currChar(pos)) { case '<': state = 1; pos = moveNext(pos); break; case '=': state = 5; pos = moveNext(pos); break; case '>': state = 6; pos = moveNext(pos); break; default : return 0; }; break; case 1: switch(currChar(pos)) { case '=' : state = 2; pos = moveNext(pos); break; case '>' : state = 3; pos = moveNext(pos); break; default : state = 4; break; }; break; case 2: state = 4; break; case 3: state = 4; break;

...

case 4: return pos; ... } }}

Vollständiger Quelltext Ausführbares Programm

0 1 2< =

3>

x - {=,>}

x

x

45 x

=

6 7=

x

>

x - {=}

Page 32: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

32

Steuertabelle für einen Beispielautomaten

Modifizierter det. endlicher Automat für die Morphemart RelOp

Erkennung der Morpheme {<=, <>, <, =, >=, >}

0 1 2< =

3

>

x - {=,>}

x

x

45

x

=

6 7=x

>

x - {=}

< = > X-{<,=,>}0 1 5 6 Error

1 4 2 3 4

2 4 4 4 4

3 4 4 4 4

4 Accept

5 4 4 4 4

6 4 7 4 4

7 4 4 4 4

Page 33: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

33

Syntaxgesteuerte manuelle Implementierung

int isRelOp(int pos) { int state = 0; // Startzustand while(state != Err && transTableRelOp[state][0] != Acc) { state = transTableRelOp[state][mapRelOp(currChar(pos))]; if(state != Err && transTableRelOp[state][0] != Acc) pos = moveNext(pos); }

if(state == Err) return 0; //Fehler return pos;}

#define Err -1#define Acc -2

int transTableRelOp[][4] = {{1 ,5 ,6 ,Err}, // Zustand 0 {4 ,2 ,3 ,4 }, // Zustand 1 {4 ,4 ,4 ,4 }, // Zustand 2 {4 ,4 ,4 ,4 }, // Zustand 3 {Acc,Acc,Acc,Acc}, // Zustand 4 {4 ,4 ,4 ,4 }, // Zustand 5 {4 ,7 ,4 ,4 }, // Zustand 6 {4 ,4 ,4 ,4 } // Zustand 7 };

int mapChar(char c) { switch(char) { case '<': return 0; case '=': return 1; case '>': return 2; default : return 3; }}

Vollständiger Quelltext Ausführbares Programm

Page 34: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

34

Verarbeitung der Eingabe (sequentiell)

Für jede Tokenart T1 bis Tn existiert eine Funktionen der Form int isT1(int pos); ...; int isTn(int pos);

Verarbeitung der Eingabe durch:

char* inputBuff; int pos;

nextMor(){ TToken t; int nextPos;

if(nextPos = isSep(pos)) pos = nextPos;

if(nextPos = isT1(pos)) { t.type = T1; cpy(&t.val,&inputBuff[pos],nextPos-pos); pos = nextPos; return t; }

...

...

if(nextPos = isTn(pos)) { t.type = Tn; cpy(&t.val,&inputBuff[pos],nextPos-pos); pos = nextPos; return t; } exit(1); // Fehler}

Vollständiger Quelltext Ausführbares Programm

Page 35: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

35

Verarbeitung der Eingabe (parallel)

Für jede Tokenart T1 bis Tn existiert eine Funktionen der Form int isT1(int pos); ...; int isTn(int pos);

Verarbeitung der Eingabe durch:

char* inputBuff; int pos;

nextMor(){ TToken t; int nextPos; int maxPos = 0;

if(nextPos = isT1(pos) && nextPos > maxPos) { t.type = T1; cpy(t.val,&inputBuff[pos],nextPos-pos); maxPos = nextPos } ... if(nextPos = isTn(pos) && nextPos > maxPos) { t.type = Tn; cpy(t.val,&inputBuff[pos],nextPos-pos); maxPos = nextPos; } if(maxPos == 0) exit(1); // Fehler pos = nextPos; return t;}

Vollständiger Quelltext Ausführbares Programm

Page 36: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

36

Lex

Generierung des C-Quelltextes eines Scanners Spezifiziert werden die Morphemarten durch

reguläre Ausdrücke Jeder Morphemart kann eine Aktion in Form von C-

Quelltext annotiert werden, die bei der Erkennung eines Morphems dieser Art ausgeführt wird

Lex- Quelltextname.l

Lex- Quelltextname.l

Lex-Aufruf:

lex name.l

Scanner als C-Datei:Lex.yy.c

Scanner als C-Datei:Lex.yy.c

C-CompilerAufruf:

gcc lex.yy.c

Ausführ-bare

Datei:a.exe

Ausführ-bare

Datei:a.exe

Page 37: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

37

Struktur eines Lex-Quelltextes

Deklarationssektion Deklaration von Bezeichnern des C-Programms Deklaration von Morphemarten Deklaration von regulären Ausdrücken

Regel-Sektion Besteht aus einer Folge von: Muster {Aktion} Muster definiert eine Morphemart durch einen regulären

Ausdruck Aktion ist C-Quelltext, der ausgeführt wird, wenn der Scanner

ein Morphem der entsprechenden Art erkannt hat C-Funktionssektion

Deklaration von C-Funktionen, die in den generierten Quelltext kopiert werden

Deklarationen%%Regeln%%C-Funktionen

Page 38: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

38

Ablauf der Generierung einer C-Datei

…%%Muster 1 {Aktion 1}…Muster n {Aktion n}%%…

…%%Muster 1 {Aktion 1}…Muster n {Aktion n}%%…

Scanner als C-Datei:Lex.yy.c

Scanner als C-Datei:Lex.yy.c

NFA für Muster 1

NFA für Muster n

……

DFA

Simulator für DFA

Steuer-tabelle

desDFA

EingabepufferAnfang Look-Ahead

Page 39: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

39

Reguläre Ausdrücke

Reguläre Ausdrücke Jedes Zeichen a ist ein regulärer Ausdruck für die

Sprache {a}. Wenn und reguläre Ausdrücke für die Sprachen L()

und L() sind, dann ist: | ein regulärer Ausdruck für die Sprache L() L() ein regulärer Ausdruck für die Sprache L() L() * ein regulärer Ausdruck für die Sprache L()*

Außerdem erlauben wir die Klammerung eines regulären Ausdrucks

Wir legen fest, dass in regulären Ausdrücken der Operator * die höchste, die zweithöchste und die niedrigste Priorität hat

Wir verzichten auf den regulären Ausdruck für die leere Sprache

Page 40: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

40

Beispiel für reguläre Ausdrücke

Es sei: Digit := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 Digits := (Digit) (Digit)*

Letter := a | … | z | A | … | Z Die Morpheme sind dann definiert als:

Bezeichner := (Letter) (Letter)*

FNumber := Digits ((. Digits) | (((. Digits E)| E) ((+ | -) Digits | Digits)))

RelOp := < | > | = | (< =) | (> =) | (< >) := EOF Sep := Blank | Tab | CR If := i f Then := t h e n Else := e l s e

Page 41: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

41

Transformation eines regulären Ausdrucks in einen Automaten

Das Prinzip sollte aus der Theoretischen Informatik bekannt sein. Wir wiederholen nur die Transformation ohne Korrektheitsbeweis.

Wir definieren eine Funktion RegToAut als:

*

({0,1}, ,0,{1},{(0, ,1)}), falls

( ( ), ( )), falls ( ) :

( ( ), ( )), falls |

( ( )), falls

a a

Concat RegToAut RegToAutRegToAut

Union RegToAut RegToAut

Kleene RegToAut

a

b g a b ga

b g a b g

b a b

ì S = Î Sïïïïï = ·ïïï= íï =ïïïï =ïïïî

Page 42: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

42

Automaten zur Erkennung eines Zeichens

Automat für den regulären Ausdruck a mit a : ({0,1},,0,{1},{(0,a,1)})

0a

1

Page 43: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

43

Vereinigung zweier Automaten

(Z, , z, F, ) := Union((Z, , z, F, ),(Z, , z, F, )) ist definiert als:

Zustandsmengen Z und Z disjunkt machen, danach folgende Mengen erzeugen:

Z := Z Z {z}, wobei z Z Z := {(z,a,p) | (z,a,p) oder (z,a,p) } F := F F {z | z F oder z F}

0a

1

0b

1

0a

1

2 b3

4a

b

0c

1

1

3

4a

b

5c

6

0c

b

a

L = {a,b}

L = {a}

L = {b}

L = {c} L = {a,b,c}

Page 44: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

44

Kleene-Abschluss

(Z, , z, F, ) := Kleene((Z,,z,F,)) ist definiert als: Z := Z

:= {(p,a,q) | p F und (z,a,q) } F := F {z}

1

3

6

0

c

b

a

L = {a,b,c}

1

3

6

c

b

a

L = {a,b,c}*

0

a

b

c

ab

c

b

c a

Page 45: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

45

Verkettung zweier Automaten

(Z, , z, F, ) := Concat((Z, , z, F, ),(Z, , z, F, )) ist definiert als: Zustandsmengen Z und Z disjunkt machen, danach folgende Mengen

erzeugen: Z := Z Z := {(p,a,q) | p F und (z,a,q) } F := F {p | p F und z F}

1

3

6

0

c

b

a

L = {a,b,c}

1

3

6

c

b

a

L = {a,b,c}*

0

a

b

c

ab

c

b

c a

a

b

ca

b

c

a

b

c

L = {a,b,c} {a,b,c}*

Page 46: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

46

Automatenmodell in Lex

Erzeugung eines Automaten für alle n Morphemarten entsprechend Variante 3 durch:

Union(A1,Union(A2,Union(…,Union(An-1,An)…)) Von Union konstruierte Automaten sind im

Allgemeinen nichtdeterministisch Transformation in deterministischen Automaten D Simulation von D entsprechend Variante 3 Damit ergeben sich Prioritäten wie folgt:

Scanner erkennt Morpheme maximaler Länge Gibt es mehrere Morpheme maximaler Länge, dann wird

das erkannt, dessen Muster zuerst spezifiziert wurde

Page 47: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

47

Wichtige Operatoren zur Bildung Regulärer Ausdrücke in Flex

Operator Matched mit. jedem Zeichen

\n Newline

Exp1Exp2 Exp1 gefolgt von Exp2

Exp* Kleene-Abschluss von Exp

Exp+ einer micht leeren Folge von Ausdrücken, die mit Exp matchen

Exp? oder Exp

^ Beginn einer neuen Zeile

$ Ende einer Zeile

Exp1 | Exp2 Exp1 oder Exp2

"text" mit der Zeichenkette text

[] einem der Zeichen zwischen den eckigen Klammern oder jedem Zeichen, das nicht zwischen den eckigen Klammern steht, wenn das erste Zeichen ^ ist. Bereichsangaben sind mit – möglich.

() Klammerung

\x dem Zeichen x. Falls das Zeichen x eine besondere Bedeutung hat, wird diese dadurch aufgehoben

Page 48: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

48

Wichtige Funktionen und Variablen in Flex

Funktion Wirkung

int yylex(void) Entspricht nextMor; Rückgabewert ist der Morphemwert

char* yytext Zeiger auf das erkannte Morphem

int yylen Länge des erkannten Morphems

yylval Bedeutung des erkannten Morphems

int yywrap(void) Rückgabe 0: Scannen fortsetzen; Neue Datei sollte geöffnet werdenRückgabe 1: Scannen beenden

FILE* yyin Eingabestrom des Scanners

typedef union YYSTYPE Typdefinition für Morpheme

Page 49: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

49

Einbinden eines Flex-Scanners in ein Projekt

Eingabe öffnen und yyin zuweisen. Aufruf der Funktion yylex, um das nächste Token

anzufordern. Rückgabe von yylex ist die Morphemart

(entspricht dem Wert in der return-Anweisung der Aktion des matchenden Musters)

Bedeutung des Morphems ist in yylval gespeichert (muss ebenfalls durch die Aktion veranlasst werden).

Auf die textuelle Darstellung kann mittels yytext zugegriffen werden (wird vom Scanner bereitgestellt).

Page 50: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

50

Beispiel: Lex-Datei

digit [0-9]digits {digit}+letter [a-zA-Z]%%[\t \n]+ {/*Keine Aktion, dadurch werden Morpheme dieser Art überlesen*/};{digits}((\.{digits})|(((\.{digits}E)|E)((\+|\-){digit}|{digit}){digit}*)) {return 1;}if {return 1;}then {return 1;}else {return 1;}{letter}({digit}|{letter})* {return 1;}"<" {return 1;}"<=" {return 1;}"=" {return 1;}"<>" {return 1;}">" {return 1;}">=" {return 1;}. {return 0; /*Zur Erkennung von Fehlern bei der Spezifikation der Ausdrücke*/}%%#include <stdio.h>int main(int argc, char* argv[]){ while(yylex()) printf("Erkannt: %s\n", yytext);}int yywrap(){ return 1;}

[Quelltext] [Ausführbare Datei]

Page 51: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

51

Möglichkeiten/Grenzen von Flex

Eingangsbeispiel {-, -->, <}[Quelltext] [Ausführbare Datei]

Die in flex zu Grunde liegende Semantik der Simulation von Automaten kann unerwünschte Effekte verursachen:

Kommentare Falsch: "(*".*"*)" Richtig: "{*"([^*\n]*(\*+[^}\n])*)*\*+"}"

[Quelltext] [Ausführbare Datei]

Morphemart {aa, aaa} [Quelltext] [Ausführbare Datei]

Page 52: Vorlesung Compilertechnik Sommersemester 2008 Lexikalische Analyse M. Schölzel.

Ende der lexikalischen Analyse

Weiter zur syntaktischen Analyse