• Keine Ergebnisse gefunden

Literatur II

N/A
N/A
Protected

Academic year: 2022

Aktie "Literatur II"

Copied!
44
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Compilerbau

Martin Plümicke

SS 2021

(2)

Agenda

I. Überblick Vorlesung Literatur

II. Compiler Überblick

III. Überblick Funktionale Programmierung Einleitung

Haskell-Grundlagen

IV. Compiler Scanner

(3)

Literatur

Bauer and Höllerer.

Übersetzung objektorientierter Programmiersprachen.

Springer-Verlag, 1998, (in german).

Alfred V. Aho, Ravi Lam, Monica S.and Sethi, and Jeffrey D. Ullman.

Compiler: Prinzipien, Techniken und Werkzeuge.

Pearson Studium Informatik. Pearson Education Deutschland, 2.

edition, 2008.

(in german).

Alfred V. Aho, Ravi Sethi, and Jeffrey D. Ullman.

Compilers Principles, Techniques and Tools.

Addison Wesley, 1986.

Reinhard Wilhelm and Dieter Maurer.

Übersetzerbau.

Springer-Verlag, 2. edition, 1992.

(in german).

(4)

Literatur II

James Gosling, Bill Joy, Guy Steele, Gilad Bracha, and Alex Buckley.

The JavaR Language Specification.

The Java series. Addison-Wesley, Java SE 8 edition, 2014.

Tim Lindholm, Frank Yellin, Gilad Bracha, and Alex Buckley.

The JavaR Virtual Machine Specification.

The Java series. Addison-Wesley, Java SE 8 edition, 2014.

Bryan O’Sullivan, Donald Bruce Stewart, and John Goerzen.

Real World Haskell.

O’Reilly, 2009.

Peter Thiemann.

Grundlagen der funktionalen Programmierung.

Teubner, 1994.

(5)

Compiler Überblick

(6)

Compiler Überblick

(7)

Compiler Überblick

(8)

Compiler Überblick

(9)

Compiler Überblick

(10)

Compiler Überblick

(11)

Scanner

(12)

Programmiersprachen

Programmiersprachen werden als formale Sprachen über einem Alphabet von Tokens definiert.

(13)

Lexeme, Tokens

Für jede Programmiersprache wird eine Menge von Strings festgelegt, über die die erlaubte Struktur dann definiert wird. Man nennt diese Strings Lexeme.

Verschiedene Lexeme, die eine ähnliche Bedeutung haben, fasst man zu Klassen von Lexemen zusammen. Die Klassen heißen Tokens.

Um Tokens bilden zu können, muss man jedes Lexem (String) durch eine reguläre Spracheüber den Symbolen eines Zeichensatzes (z.B. ASCII, latin-1, UTF-8, . . . ) beschreiben.

(14)

Lexeme, Tokens

Für jede Programmiersprache wird eine Menge von Strings festgelegt, über die die erlaubte Struktur dann definiert wird. Man nennt diese Strings Lexeme.

Verschiedene Lexeme, die eine ähnliche Bedeutung haben, fasst man zu Klassen von Lexemen zusammen. Die Klassen heißen Tokens.

Um Tokens bilden zu können, muss man jedes Lexem (String) durch eine reguläre Spracheüber den Symbolen eines Zeichensatzes (z.B. ASCII, latin-1, UTF-8, . . . ) beschreiben.

(15)

Reguläre Ausdrücke

Sei Σein Alphabet, dann ist die Menge der regulären Ausdrücke über Σ :R(Σ)definiert als kleinste Menge mit folgenden Eigenschaften.

a) ε∈R(Σ) b) Σ⊆R(Σ)

c) a∈R(Σ)∧b∈R(Σ)⇒ab∈R(Σ) a|b∈R(Σ)

a ∈R(Σ) (a)∈R(Σ)

Beispiel: Σ ={a,b,c}

R(Σ) ={ε,a,b,c,ab,ac,aa, . . . ,

abac,aaa, . . . ,a|b,a|c,b|c,aa|bc, . . . ,aa|bc|aa,a,b,aaaa, (a),(b),(a|c),(a|c),(a|c)a, . . .}

(16)

Reguläre Ausdrücke

Sei Σein Alphabet, dann ist die Menge der regulären Ausdrücke über Σ :R(Σ)definiert als kleinste Menge mit folgenden Eigenschaften.

a) ε∈R(Σ) b) Σ⊆R(Σ)

c) a∈R(Σ)∧b∈R(Σ)⇒ab∈R(Σ) a|b∈R(Σ)

a ∈R(Σ) (a)∈R(Σ)

Beispiel: Σ ={a,b,c}

R(Σ) ={ε,a,b,c,ab,ac,aa, . . . ,

abac,aaa, . . . ,a|b,a|c,b|c,aa|bc, . . . ,aa|bc|aa,a,b,aaaa, (a),(b),(a|c),(a|c),(a|c)a, . . .}

(17)

Reguläre Sprache

Sei α∈R(Σ)ein regulärer Ausdruck, so ist die reguläre SpracheL(α) definiert durch die kleinste Menge mit folgenden Eigenschaften:

1. L(ε) =ε(=” ”)

2. α∈Σ⇒ L(α) ={α}

3. I α=βγ⇒ L(α) ={ww0|w ∈ L(β),w0 ∈ L(γ)}

I α=β|γ⇒ L(α) =L(β)∪ L(γ)

I α=β ⇒ L(α) ={ε} ∪ {ww0|w ∈ L(β),w0 ∈ L(β)}

4. α= (β)⇒ L(α) =L(β)

(18)

Deterministische endliche Automat (DEA)

Unter einem DEA versteht man

A=(Q,Σ, δ,s,F) mit

I Q = Zustandsmenge (endlich)ˆ I Σ= Alphabetˆ

I δ = Übergangsfunktion:ˆ Q×Σ→Q I s ∈Q = Anfangszustandˆ

I F ⊆Q = Menge der Finalzuständeˆ

DEAs kann man grafisch darstellen: I Zustände: q1

I Startzustand: q0 I Finalzustand: f1

I Übergangsfunktion:

(19)

Deterministische endliche Automat (DEA)

Unter einem DEA versteht man

A=(Q,Σ, δ,s,F) mit

I Q = Zustandsmenge (endlich)ˆ I Σ= Alphabetˆ

I δ = Übergangsfunktion:ˆ Q×Σ→Q I s ∈Q = Anfangszustandˆ

I F ⊆Q = Menge der Finalzuständeˆ

DEAs kann man grafisch darstellen:

I Zustände: q1

I Startzustand: q0 I Finalzustand: f1

I Übergangsfunktion:

(20)

Reg. Ausdruck nach DEA

Man kann reguläre Ausdruck in DEA’s übersetzen, die die Sprachen der regulären Ausdruck erkennen:

reg.Ausdruckreg2autoNEANEA2DEA⇒ DEA

(21)

Beispiel: a(ba)∗

NEA:

DEA:

q1, q2,

q5 3

5 2 { q3, q4 }

{ q5, q2 }

(22)

Beispiel: a(ba)∗

NEA:

DEA:

q1, q2,

q5 3

5 2 { q3, q4 }

{ q5, q2 }

(23)

Beispiel: a(ba)∗

NEA:

DEA:

q1, q2,

q5 3

5 2 { q3, q4 }

{ q5, q2 }

(24)

Lex–Spezifikation

r1 { action1 } r2 { action2 } . . .

rn { actionn }

ri = regulärer Ausdruckˆ

actioni = Aktion in bestimmter Programmierspracheˆ

(25)

Beispiel

public|protected |private{ } // (TokenZugriffsrechte) static{ } // (TokenSTATIC)

abstract{ }// (Token ABSTRACT) class { }// (TokenCLASS)

while { }// (TokenWHILE) do { }// (TokenDO)

if { }// (TokenIF)

(a|. . .|z|A|. . .|Z)(a|. . .|z|A|. . .|Z|0|. . .|9) { }// (TokenIDENTIFIER)

; { }// (Token SEMIKOLON)

“Σ” { }// (Token STRING)

(26)

Principle of longest match

Es wird immer so weit gelesen, dass nach dem nächsten Zeichen kein regulärer Ausdruck der Lex–Spezifikation mehr passen würde.

Genügt das längste passende Lexem immernoch mehreren regulären Ausdrücken, so wird der reguläre Ausdruck genommen, der den kleinsten Index hat.

Beispiel:

whilei → TokenIdentifier while → TokenWHILE

(27)

Principle of longest match

Es wird immer so weit gelesen, dass nach dem nächsten Zeichen kein regulärer Ausdruck der Lex–Spezifikation mehr passen würde.

Genügt das längste passende Lexem immernoch mehreren regulären Ausdrücken, so wird der reguläre Ausdruck genommen, der den kleinsten Index hat.

Beispiel:

whilei → TokenIdentifier while → TokenWHILE

(28)

Arbeitsweise eines Scanners

(29)

NEA der Lex–Spezifikation (Übergangstabelle)

(30)

Beispiel Mini-Java

[ \t\n]

while [a-z][a-z]*

(31)

Beispiel Mini-Java

ε

\t

f1

q3

\n

" "

w h i l e

q0 f2

ε

ε q1

q2 q4

a

z ε

ε

ε ε q0

ε

ε

ε

ε

a

f3 z

ε ε

ε ε

ε

ε ε ε

ε

q5 ε q6

q7

q8

q9

q10

ε

(32)

1. Ansatz: Scanner direkt implementieren I

module Lexer (Token(..),lexer) where import Data.Char

data Token = LetToken

| InToken

| SymToken Char

| VarToken String

| IntToken Int deriving (Eq,Show)

(33)

1. Ansatz: Scanner direkt implementieren II

lexer :: String -> [Token]

lexer [] = []

lexer (c:cs)

| isSpace c = lexer cs

| isAlpha c = lexVar (c:cs)

| isDigit c = lexInt (c:cs)

lexer (’+’:cs) = SymToken ’+’ : lexer cs lexer (’-’:cs) = SymToken ’-’ : lexer cs lexer (’*’:cs) = SymToken ’*’ : lexer cs lexer (’/’:cs) = SymToken ’/’ : lexer cs lexer (’(’:cs) = SymToken ’(’ : lexer cs lexer (’)’:cs) = SymToken ’)’ : lexer cs

(34)

1. Ansatz: Scanner direkt implementieren III

lexInt cs = IntToken (read num) : lexer rest where (num,rest) = span isDigit cs lexVar cs =

case span isAlpha cs of

("let",rest) -> LetToken : lexer rest ("in",rest) -> InToken : lexer rest (var,rest) -> VarToken var : lexer rest

(35)

2. Ansatz: Scanner-Tools

I lex (Programmiersprache C, Standard-Tool Unix) I JLex (Programmiersprache Java,

https://www.cs.princeton.edu/˜appel/modern/java/JLex/) I Alex (Programmiersprache Haskell,

http://www.haskell.org/alex)

(36)

Alex-Spezifikation

{

Haskell-code }

$abk1 = regExp1

$abk2 = regExp2 ...

$abkn = regExpn

%wrapper "wrapper" tokens :=

lex--Spezifikation {

Haskell-code }

(37)

Alex-Spezifikation

{

Haskell-code }

$abk1 = regExp1

$abk2 = regExp2 ...

$abkn = regExpn

%wrapper "wrapper" tokens :=

lex--Spezifikation {

Haskell-code }

(38)

Alex-Spezifikation

{

Haskell-code }

$abk1 = regExp1

$abk2 = regExp2 ...

$abkn = regExpn

%wrapper "wrapper"

tokens := lex--Spezifikation {

Haskell-code }

(39)

Alex-Spezifikation

{

Haskell-code }

$abk1 = regExp1

$abk2 = regExp2 ...

$abkn = regExpn

%wrapper "wrapper"

tokens :=

lex--Spezifikation

{

Haskell-code }

(40)

Alex-Spezifikation

{

Haskell-code }

$abk1 = regExp1

$abk2 = regExp2 ...

$abkn = regExpn

%wrapper "wrapper"

tokens :=

lex--Spezifikation {

Haskell-code }

(41)

Alex-Spezifikation Beispiel

{ }

%wrapper "basic"

$digit = 0-9 -- digits

$alpha = [a-zA-Z] -- alphabetic characters tokens :-

$white+ ;

"--".* ;

let { \s -> LetToken } in { \s -> InToken }

$digit+ { \s -> IntToken (read s) }

[\=\+\-\*\/\(\)] { \s -> SymToken (head s) }

$alpha [$alpha $digit \_ \’]* { \s -> VarToken s } -- Each action has type :: String -> Token

(42)

Alex-Spezifikation Beispiel II

{

-- The token type:

data Token = LetToken

| InToken

| SymToken Char

| VarToken String

| IntToken Int deriving (Eq,Show)

main = do

s <- getContents

print (alexScanTokens s) }

(43)

Wrapper

Es gibt in Alex einige vordefinierte Wrapper:

I Thebasic wrapper I Theposnwrapper I Themonadwrapper

I ThemonadUserState wrapper I Thegscanwrapper

I Thebytestring wrappers

(44)

Types der token actions (basic Wrapper)

String -> Token

Referenzen

ÄHNLICHE DOKUMENTE

I head in der Funktion parser führt dazu, dass nur die erste Lösung bestimmt wird. I Nicht-strikte Auswertung führt zu trotzdem

Speicher–Allocation und Konstruktion von Datenobjekten und die Freigabe von Speicherplatz (garbage–collection) geschieht ohne Einwirkung des Programmierers... Grundlegende

Top-down: Linksableitungen (man erhält eine Ableitung, bei der immer das am weitesten links stehende Nichtterminal abgeleitet wird) Bottom–Up: Rechtsableitungen (man erhält

I ANTLR generiert zu jeder Regel in der Grammatik eine eigene Klasse I Der Aufbau der Klasse wird direkt von dieser Regel abgeleitet. I Der ParseTree baut sich aus diesen Klasse

Die intendierte Funktion von Paulis Schimpf und Ernst als Reservoir von Predig- texempeln stellt eine spezifische historische Kontextualisierungsmöglichkeit der

Beispiel: Für 25 „Tokens“ kann das Kind den eigentlichen Verstärker erhalten. Beispiele für Verstärker, die das Kind mit den „Tokens“

Regular Grammars Generate..

&#34;Theoretische Informatik kurzgefaßt&#34; von Uwe Schöning angeleht und wurden aus den Unterlagen zu der Vorlesung &#34;Informatik IV – Theoretische Informatik&#34; an der TU