Algorithmen und Datenstrukturen II

Algorithmen und Datenstrukturen II

1

Juniorprofessor Dr.-Ing. Tim W. Nattkemper Raum: M7-130 Sprechstunde: Di 13:00 ct - 14:00 Tel.: 0521/106-6059 Email: [email protected]

Algorithmen und Datenstrukturen II

2

Syntax und Semantik

Algorithmen und Datenstrukturen II

3

Einfu ¨hrung

Programmiersprachen sind formale Sprachen. Es ist pr¨azise festgelegt, • welche Zeichenreihen u ¨berhaupt Programme einer Sprache L sind (Syntax), • welche Ein-/Ausgabefunktion ein Programm berechnet (Semantik).

Algorithmen und Datenstrukturen II

4

Konkrete/abstrakte Syntax

konkrete Syntax:

genaue textuelle Aufschreibung fu ¨r Programme.

abstrakte Syntax:

Bindeglied zur Semantik; gibt an, wie ein Programm(-stu ¨ck) aufgebaut ist.

Algorithmen und Datenstrukturen II

5

Beispiel 0.1 abstrakt

konkret

assign " !

!

#

x ! " var " !

!

y

Algorithmen und Datenstrukturen II

# $ add

!

#

# $ const #

x := y + 5

Pascal

x=y+5

C, Fortran, Java

LET x = y + 5

Basic (anno 1963)

ADD 5 TO y GIVING x

COBOL

STORE y + 5 TO x

dBase

$ # 5

6

Operatoren und Konstrukte

In der abstrakten Syntax tauchen die primitiven Konstrukte einer Programmiersprache auf, sowie Operatoren, die diese zu neuen Konstrukten kombinieren. primitiv:

Bezeichner, Zahl

Kombination:

var:

Bezeichner

const:

Zahl

add:

Ausdruck × Ausdruck

assign:

Algorithmen und Datenstrukturen II

Bezeichner × Ausdruck

→ Ausdruck → Ausdruck → Ausdruck

→ Anweisung

7

W¨ orter

Definition 0.2 • Ein Alphabet A ist ein endlicher Zeichenvorrat (eine endliche Menge). • Die Mengen aller endlichen Zeichenreihen u ¨ber einem Alphabet A bezeichnen wir mit A∗ . • Das leere Wort der L¨ ange 0 bezeichnen wir mit ε.

Algorithmen und Datenstrukturen II

8

Formale Sprachen

Definition 0.3 Eine Menge L ⊆ A∗ heißt formale Sprache u ¨ber dem Alphabet A. Einen abstrakteren Sprachbegriff kann man kaum definieren. Die einzige Frage, die man sich u ¨ber w ∈ A∗ stellen kann, ist: Gilt w ∈ L oder w %∈ L? Diese Frage nennt man das Wortproblem von L.

Algorithmen und Datenstrukturen II

9

Programmiersprachen

Definition 0.4 Eine Programmiersprache ist ein Paar (L, L), wobei L ⊆ A∗ eine formale Sprache und L : L → (A∗ → A∗ ) die Semantik von L ist. Damit ordnet L jedem L-Programm l ∈ L als seine Bedeutung die Ein-/Ausgabefunktion L(l) zu, wobei Ein- und Ausgabe ebenfalls Zeichenreihen u ¨ber A sind. Fu ¨r L(l) schreiben wir auch kurz Ll.

Algorithmen und Datenstrukturen II

10

Kontextfreie Grammatiken

Definition 0.5 Eine kontextfreie Grammatik ist ein 4-Tupel G = (N, A, P, S), wobei 1. N ein Alphabet von sogenannten Nonterminalsymbolen, 2. A ein Alphabet von sogenannten Terminalsymbolen mit N ∩ A = ∅, 3. P eine endliche Menge von Produktionen (Regeln) der Form V → α mit V ∈ N und α ∈ (V ∪ A)∗ und 4. S ∈ N ein Startsymbol ist.

Algorithmen und Datenstrukturen II

11

Satzformen einer Grammatik

Die Menge S(G) der Satzformen von G ist die kleinste Teilmenge von (N ∪ A)∗ mit den folgenden Eigenschaften: 1. S ∈ S(G). 2. Wenn αV β ∈ S(G) fu ¨r ein Nonterminalsymbol V ∈ N und Zeichenfolgen α, β ∈ (N ∪ A)∗ und wenn V → γ ∈ P eine Regel ist, so gilt auch αγβ ∈ S(G) ( Ableitungsschritt“). ”

Algorithmen und Datenstrukturen II

12

Sprache einer Grammatik

def

Die durch G definierte Sprache ist L(G) = S(G) ∩ A∗ . Den Test, ob ein gegebenes Wort w durch eine Grammatik G erzeugt werden kann, also ob w ∈ L(G) gilt, nennt man das Wortproblem von G.

Algorithmen und Datenstrukturen II

13

Syntax und Semantik von Sprachen: Bohrkopfsteuerung N

W

E O S

N, E, W, S:

Bewegung um 1 Gitterpunkt (north, east, west, south)

O:

Einstellen auf Nullpunkt (origin)

D:

Senken des Bohrkopfes mit Bohrung (drill)

U:

Heben des Bohrkopfes (up)

Algorithmen und Datenstrukturen II

14

Programme zur Maschinensteuerung sind z.B. “ON N N EEDO”

Bohrung am Punkt (2,3) mit Ru ¨ckkehr zum Nullpunkt

“ODU DU DU ”

Dreifach-Bohrung am Nullpunkt

“DU N DU W DU SDU ”

bohrt Gitterquadrat, wo der Kopf gerade steht

Algorithmen und Datenstrukturen II

15

In der ersten Variante unserer Steuersprache lassen wir beliebige Befehlsfolgen zu. Außerdem kann jedes Programm als Eingabe ein Paar von Start-Koordinaten erhalten. L1 = {N, E, W, S, U, D, O}∗ Eingabe: (Int, Int) L1 : L1 → (Int, Int) → [(Int, Int)]

Algorithmen und Datenstrukturen II

16

Maschinenzustand

x

aktuelle x-Koordinate

y

aktuelle y-Koordinate

l

aktueller Hebezustand des Bohrkopfes: 0 gesenkt, 1 oben

cs

Liste bisheriger Bohr-Koordinaten

Algorithmen und Datenstrukturen II

17

Semantik von Befehlen bef :: Befehl → Zustand → Zustand bef b (x, y, l, cs) = case b of O N W S E D U

Algorithmen und Datenstrukturen II





(0, 0, 1, cs) (x, y + 1, l, cs)



(x − 1, y, l, cs)



(x + 1, y, l, cs)

→ →



(x, y − 1, l, cs) (x, y, 0, (x, y) : cs) (x, y, 1, cs)

18

Befehlsfolgen

beff :: Befehl∗ → Zustand → [(Int, Int)] beff [ ](x, y, l, cs) = reverse cs

beff (b : bs)(x, y, l, cs) = beff bs(bef b (x, y, l, cs))

Die Semantik L1 wird beschrieben durch die Funktion prog :: Befehl∗ → (Int, Int) → [(Int, Int)] prog bs (i, j) = beff bs (i, j, 1, [])

Algorithmen und Datenstrukturen II

19

Programmiersprache L1 und ihre Semantik L1 sind sehr naiv. Man sollte zum Beispiel bedenken, dass das Werkstu ¨ck und vielleicht auch die Maschine besch¨adigt werden, wenn mit abgesenktem Bohrkopf Bewegungen ausgel¨ ost werden. Freilich – solange niemand solche Steuerprogramme erzeugt, geht alles gut. Jedoch wollen wir uns nicht darauf verlassen . . .

Algorithmen und Datenstrukturen II

20

Syntaktische vs. semantische Verfeinerung

Generell gibt es zwei M¨ oglichkeiten, eine Sprache (L, L) zu verfeinern: syntaktisch oder semantisch. Semantisch heisst: das “Unglu ¨ck” kann programmiert werden, tritt aber nicht ein. Syntaktisch heisst: das “Unglu ¨ck” wird bereits als syntaktisch fehlerhaftes Programm abgewiesen.

Algorithmen und Datenstrukturen II

21

Aufgabe 0.6 Modifiziere die Semantik L1 (bei unver¨andertem L1 ) in zwei verschiedenen Weisen. Tritt eine Bewegung mit abgesenktem Bohrkopf auf, so wird a) die Ausfu ¨hrung des Programms abgebrochen und nur die Koordinaten der bisherigen Bohrungen ausgegeben, b) die Ausfu ¨hrung des Programms abgebrochen und keine Koordinaten angegeben.

Algorithmen und Datenstrukturen II

22

Forderungen an die Steuersprache Wir entscheiden uns nun fu ¨r die syntaktische Verfeinerung und stellen Forderungen an die Steuersprache L: 1. Auf Befehl D muss stets U oder O folgen. 2. Befehl O ist immer m¨ oglich, U nur unmittelbar nach D. 3. Alle Programme enden mit dem Bohrkopf am Nullpunkt. 4. Auf dem Weg von einer Bohrung zur n¨achsten sind gegenl¨aufige Richtungswechsel unerwu ¨nscht, zum Beispiel . . . N SN S . . . oder . . . N ES . . . , weil sie die Maschine in Schwingung versetzen k¨onnen. Alle diese Forderungen lassen sich durch Einschr¨ankungen von L1 erfu ¨llen, erfordern aber verfeinerte Methoden zur syntaktischen Sprachbeschreibung. Solche Mittel sind Grammatiken.

Algorithmen und Datenstrukturen II

23

Grammatik 1 Grammatik G1 (zur Beschreibung von L1 ) A

= { N, E, W, S, U, D, O}

S

=

moves

P

={

moves → ε| move moves

N

= { moves, move}

move → N |E|W |S|U |D|O}

Hier gilt L(G1 ) = A∗ . Es ist w ∈ L(G1 ) mit w = “W EN DEDEN U DOSU ED"" ¨ Ubung: Leite w mit dieser Grammatik ab. Algorithmen und Datenstrukturen II

24

Verfeinerte Grammatik 2

Verfeinerte Grammatik G2 (beru ¨cksichtigt Forderungen (1) - (3), aber nicht (4)). A, N, S wie G1

P

={

moves → O|DO| move moves

move → N |E|W |S|O|DU |DO}

Frage: Warum brauchen wir die Regel moves → DO u ¨berhaupt?

Algorithmen und Datenstrukturen II

25

Verfeinerte Grammatik 2

Verfeinerte Grammatik G2 (beru ¨cksichtigt Forderungen (1) - (3), aber nicht (4)). A, N, S wie G1

P

={

moves → O|DO| move moves

move → N |E|W |S|O|DU |DO}

Frage: Warum brauchen wir die Regel moves → DO u ¨berhaupt? Antwort: Sonst ist “DO” ∈ / S(G2 ).

Algorithmen und Datenstrukturen II

26

Warum ist nun w = “W EN DEDEN U DOSU ED” ∈ / S(G2 )? Versuch einer Ableitung: moves →

move

moves



W

moves



W

moves

moves



W

E

moves

→3

W

E

N

move moves

W

E

N

?



Hier kann nur DU oder DO erzeugt werden, aber nicht D allein oder DE.

Algorithmen und Datenstrukturen II

27

Verfeinerte Grammatik 3 Verfeinerte Grammatik G3 (beru ¨cksichtigt Forderungen (1) und (4), (2) nur teilweise und (3) gar nicht): A, S N P

wie G1

={

={

moves, ne, nw, se, sw, drill }

moves → ε | ne moves | nw moves | se moves | sw moves ne → N ne | E ne | drill

se → S se | E se | drill

nw → N nw | W nw | drill sw → S sw | W sw | drill

drill → DU |DO }

Algorithmen und Datenstrukturen II

28

RNA-Sekund¨ arstrukturen Ein RNA-Moleku ¨l besteht aus Basen A,C,G,U. Durch Wasserstoff-Bru ¨cken zwischen A–U, G–C, G–U bilden sich Basenpaarungen, die zu einer Sekund¨arstruktur fu ¨hren.

Prim¨arsequenz C A C C U A A G G U C C

Sekund¨arstruktur C A C C U A A G G U C C C

C A

U

C

G

C

G

U

C

← Helix-Bildung schafft Stabilit¨at A

A

Algorithmen und Datenstrukturen II

29

Sekund¨ arstruktur-Grammatik Grammatik zur Beschreibung der Sekund¨arstruktur (Ausschnitt): A={

N={

S=

P={

A, C, G, U }

struct, any, stack, loop }

struct

struct any stack

loop

Algorithmen und Datenstrukturen II



→ →



any | any struct | struct any | stack | ε

A | C | G | U

A stack U | U stack A | G stack C | C stack G |

G stack U | U stack G | loop

any loop | any any any }

30

Ableitung von RNA-Sequenzen

Allein mit den ersten beiden Produktionen kann man alle RNA-Sequenzen ableiten: struct → any struct → A struct → A any struct → AC struct . . . Damit ist L(G) = A∗ . Der Witz der Grammatik ist, dass manche Ableitungen das Vorliegen m¨oglicher Sekund¨arstrukturen anzeigen – dann n¨amlich, wenn sie die Produktionen fu ¨r stack benutzen.

Algorithmen und Datenstrukturen II

31

Ableitung == Struktur

struct →2 C struct →4 C struct CC → C stack CC

→ CA stack UCC →2 CACC stack GGUCC → CACC loop GGUCC →4 CACCUAAGGUCC

Algorithmen und Datenstrukturen II

32

Syntaxbaum struct ! ! any struct ! ! " " C any struct " " " " C any struct " " C stack ! " ! " A U stack ! " ! " C G stack ! " ! " C G stack

U

Algorithmen und Datenstrukturen II

loop ! " ! " any any any ! " ! " A

A

33

Chomsky-Hierarchie

Typ 0:

XaY b

Typ 1:

aXb

Typ 2:

X

Typ 3:

X

Algorithmen und Datenstrukturen II



cXZ

(allgemein)



aZY b

(kontextsensitiv)



aY bZc

(kontextfrei)



aY

(regul¨ar)

34

Komplexit¨ at des Wortproblems

Typ 0:

unentscheidbar

Typ 1:

exponentiell

Typ 2:

polynomiell (Θ(n3 ) oder besser; bei Grammatiken fu ¨r Programmiersprachen in de Θ(n))

Typ 3:

linear

Algorithmen und Datenstrukturen II

35

EBNF, Historisches

• Syntaxbeschreibung von FORTRAN und COBOL (am Anfang) durch Beispiele und Gegenbeispiele. • 1958 formale Beschreibung der Syntax von ALGOL durch John Backus; Backus-Normalform (BNF). • Kleine Verbesserungen in der Notation durch Peter Naur, daher spricht man heute von der Backus-Naur-Form (BNF). • Niklaus Wirth hat die Backus-Naur-Form noch einmal u ¨berarbeitet und erweitert (EBNF – Extended BNF).

Algorithmen und Datenstrukturen II

36

EBNF, Definition

Die Metazeichen der EBNF (vgl. Klaeren [5], S. 104) sind: das Definitionszeichen

=

das Alternativzeichen

|

die Anfu ¨hrungszeichen die Wiederholungsklammern die Optionsklammern

{ }

[ ]

die Gruppenklammern

( )

der Punkt

.

Algorithmen und Datenstrukturen II

37

EBNF, Terme Die Menge ET der EBNF-Terme ist gegeben durch: 1. Ist V eine Folge von Buchstaben und Ziffern, die mit einem Buchstaben beginnt, so gilt V ∈ ET und gilt als Nonterminalsymbol. 2. Ist w eine Folge von beliebigen Symbolen, so ist “w”∈ ET und gilt als ein (!) Terminalsymbol. 3. Fu ¨r α ∈ ET sind auch (a) (α) ∈ ET ,

(b) [α] ∈ ET und (c) {α} ∈ ET .

4. Fu ¨r α1 , . . . , αn ∈ ET sind auch (a) α1 | . . . |αn ∈ ET und

(b) α1 α2 . . . αn ∈ ET . Algorithmen und Datenstrukturen II

38

Eine EBNF-Definition besteht aus einer endlichen Menge von EBNF-Regeln der Form V

=

α.

wobei V ein Nonterminalsymbol entsprechend obiger Konvention und α ein EBNF-Term ist. Das Nonterminalsymbol auf der linken Seite der ersten Regel ist das Startsymbol.

Algorithmen und Datenstrukturen II

39

EBNF-Definition fu ¨r Mini-Java

Algorithmen und Datenstrukturen II

40

program = “class” ident “{” mainMethod “}”. mainMethod = “public”“static”“void”“main”“(”“String”“[”“]” argsIdent “)” block. statement = “int” ident “=” expression “;” | ident “=” expression “;” | “if”“(” condition “)” statement | “while”“(” condition “)” statement | block | “System”“.”“out”“.”“println”“(” expression “)”“;” | “;” | “int”“[”“]” arrayIdent “=”“new”“int”“[” expression “]”“;” | arrayIdent “[” expression “]”“=” expression “;”. block = “{” { statement } “}”. condition = expression ( “==” | “!=” | “=” ) expression. expression = [ ( “+” | “-” ) ] term { ( “+” | “-” ) term }. term = factor { ( “*” | “/” ) factor }. factor = ident | number | “(” expression “)” | “Integer”“.”“parseInt”“(” argsIdent “[” expression “]”“)” | argsIdent “.”“length” | arrayIdent “.”“length” Algorithmen und Datenstrukturen II

41

ident number digit letter argsIdent arrayIdent

| arrayIdent “[” expression “]”. = ( letter | “_” | “$” ) { letter | digit }. = ( “0” | digit { digit | “0” } ). = “1” | “2” | . . . | “9”. = “A” | . . . | “Z” | “a” | . . . | “ z”. = ident. = ident.

Algorithmen und Datenstrukturen II

42

Operationen auf Sprachen

Seien L, L1 und L2 beliebige Sprachen (Wortmengen) u ¨ber einem gemeinsamen Alphabet. Dann definieren wir: def

1. Komplex-Produkt: L1 L2 = {w1 w2 | w1 ∈ L1 , w2 ∈ L2 } (also L∅ = ∅L = ∅; L{ε} = {ε}L = L) def

2. n-fache Iteration: L0 = {ε}, Ln+1 := LLn ! ∗ def 3. Stern-Operation: L = n∈N Ln

Algorithmen und Datenstrukturen II

43

Beispiele

1. {aa, ab} {aa, ε} = {aaaa, abaa, aa, ab} 2. {a, b, c}2 = {a, b, c} {a, b, c} = {aa, ab, ac, ba, bb, bc, ca, cb, cc} 3. {a, b}∗ = {ε, a, b, aa, ab, ba, bb, . . . }

Algorithmen und Datenstrukturen II

44

Semantik der EBNF Die Semantik der EBNF definieren wir durch Rekursion u ¨ber die EBNF-Terme. Sei E eine EBNF-Definition (wobei S das Startsymbol, N die Menge der Nonterminals und A die Menge der Terminals sei) und ET die Menge der EBNF-Terme. Dann ist die von E erzeugte Sprache L(E) definiert als !S"E , wobei ! "E : ET ! P (A∗ )

wie folgt definiert ist (vgl. Klaeren [5], S. 107):   !α" falls V = α. eine Regel in E ist E def 1. Fu ¨r V ∈ N ist !V "E =  ∅ sonst def

2. !“w”"E = {w} # $ def 3. (α) E = !α"E

# $ def 4. [α] E = {ε} ∪ !α"E

Algorithmen und Datenstrukturen II

45

# $ def 5. {α} E = !α"∗E def

6. !α1 . . . αn "E = !α1 "E . . . !αn "E def

7. !α1 | · · · | αn "E = !α1 "E ∪ · · · ∪ !αn "E

Algorithmen und Datenstrukturen II

46

Beispiel

Gegeben sei die EBNF-Definition E mit dem Startsymbol Rna sowie den beiden Regeln Rna = Any [“A”] und

Any =

(“A” | “C” | “G” | “U”).

Durch wiederholte Anwendung der verschiedenen Gleichungen aus der Semantikdefinition ergibt sich die von dieser EBNF definierte Sprache folgendermaßen:

Algorithmen und Datenstrukturen II

47

RNA-Sprache !Rna"E

(1)

=

(6)

=

(1),(4)

=

(3),(2)

=

(7)

=

= = =

Algorithmen und Datenstrukturen II

# $ Any [“A”] E # $ !Any"E [“A”] E # $ % & (“A” | “C” | “G” | “U”) E {ε} ∪ !“A”"E % & !“A” | “C” | “G” | “U”"E {ε} ∪ {A} ' ( !“A”"E ∪ !“C”"E ∪ !“G”"E ∪ !“U”"E {ε, A} % & {A} ∪ {C} ∪ {G} ∪ {U} {ε, A}

{A, C, G, U}{ε, A}

{A, C, G, U, AA, CA, GA, UA}.

48

Beispiel eines syntaktisch korrekten Mini-Java-Programms

Algorithmen und Datenstrukturen II

49

class BubbleSort { public static void main(String[] args) { int[] array = new int[args.length]; int i = 0; while (i < args.length) { array[i] = Integer.parseInt(args[i]); i = i+1; } i = 1; while (i < array.length) { int j = array.length - 1; while (j >= i) { if (array[j] < array[j-1]) { int tmp = array[j]; array[j] = array[j-1]; array[j-1] = tmp; } Algorithmen und Datenstrukturen II

50

j = j-1; } i = i+1; } i = 0; while (i < array.length) { System.out.println(array[i]); i = i+1; } } }

Algorithmen und Datenstrukturen II

51

Syntaxdiagramme

Eine EBNF-Definition kann man folgendermaßen in Syntaxdiagramme u ¨berfu ¨hren:

“w” :

V:

#$ % w !"

%

% V

%

fu ¨r alle w ∈ A.

fu ¨r alle V ∈ N .

% α [α] : Algorithmen und Datenstrukturen II

& % 52

α ' {α} :

α1 . . . αn :

α1 | · · · | αn :

&

% α1

%

% ···

% α1 .. .

% αn

%

% (

% αn

Algorithmen und Datenstrukturen II

53

Beispiel: Syntaxdiagramme fu ¨r Mini-Java

"

program

#

#

class

$ # %

ident

# {!# mainMethod # }! #

'% '% ' % '% % public % static % void % main (& & (& (& ( ' % % ()% String % [)% ])% argsIdent % ))% block & (

mainMethod

Algorithmen und Datenstrukturen II

% 54

% ' %expression % ;) int % ident % =) & ( % ident % =)% expression % ;) %' % if % ()% condition % ))% statement &( ' % % while % ()% condition % ))% statement & ( % block % ' % ' % ' % System % .)% out % .)% println % ()%expression % ))% ;) & ( & ( & ( % ;) % ' % int % [)% ])%arrayIdent % =) & ( % '% ' % new % int % [)%expression % ])% ;) & (& ( %arrayIdent % [)%expression % ])% =)%expression % ;)

statement

%

Algorithmen und Datenstrukturen II

% ( ( ( ( ( ( (

(

55

block

#

()

&' $

#

{

statement

Algorithmen und Datenstrukturen II

%

() &' }

#

56

condition

% expression

Algorithmen und Datenstrukturen II

,-

% != *+ ,&% expression % == *+ ( ,% < *+ ( ,% = *+ ( ,% > *+

%

57

expression

term

# () $ # + &' $ () # &'

#

factor

term

$ term

$ factor

Algorithmen und Datenstrukturen II

%

() % + % $ &' () - % &'

() * % &' () / % &'

#

#

58

factor

# $

# ident

# number

$

# (!# expression # )! $ $ " " $ # Integer # .!# parseInt # (!# argsIdent # [!# expression # ]!# )! # % # % $ " $ # argsIdent # .!# length # % $ " $ # arrayIdent # .!# length # % $ # arrayIdent # [!# expression # ]!

ident

% letter

,-

% _ *+ ,% $ *+

( ( (

Algorithmen und Datenstrukturen II

(

% letter

'

digit

' 59

number

% digit

( (

,-

% 0 *+

Algorithmen und Datenstrukturen II

digit

'

,0 ' *+

% (

60

digit

,-

% 1 % *+ ( ,% ... *+ ( ,% 9 *+

argsIdent

% ident

letter ,-

% % A *+ ( ,% ... *+ ( ,% Z *+ ( ,% a *+ ( ,% ... *+ ( ,% z *+

arrayIdent

%

Algorithmen und Datenstrukturen II

% ident

%

61

Literatur [1] K. Arnold, J. Gosling: JavaT M - Die Programmiersprache. Addison-Wesley, 1996. [2] T.H. Cormen, C.E. Leierson, R.L. Rivest: Introduction to Algorithms. MIT Press, 1990. [3] D. Flanagan: Java in a Nutshell. O’Reilly & Associates Inc., 1996. [4] F. Jobst: Programmieren in Java. Hanser Verlag, 1996. [5] H. Klaeren: Vom Problem zum Programm. 2.Auflage, B.G. Teubner Verlag, 1991. [6] K. Echtle, M. Goedicke: Lehrbuch der Programmierung mit Java. dpunkt-Verlag, 2000.