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.