Was ist die beste Programmiersprache?

Download Report

Transcript Was ist die beste Programmiersprache?

Einführungskursus in Pascal
© Günter Riedewald
Die Folien sind eine Ergänzung zum
Kursus und nur für den internen Gebrauch.
Welche Programmiersprache
sollte ein Informatikstudent als
erste lernen?
• Die am häufigsten verwendete
• Die einfachste
• Eine, die die meisten bestimmt noch nicht
beherrschen
• Die beste
Was ist die beste
Programmiersprache?
Andere Frage: Was ist die beste
Zange?
Antwort: Es gibt keine beste Zange.
Für bestimmte Anwendungen gibt es
aber besser und weniger gut
geeignete Zangen.
Einsatzgebiet von Programmiersprachen:
Softwareentwicklung

- Bewertung nach Art, Komplexität,
Problemklassen, Sicherheit, Kosten,...
- Unterschiedliche Paradigmen
(Grundmodelle) der Programmierung
Imperative Programmierung
- Programm als Abfolge einzelner Befehle
(Anweisungen)
- Befehlsausführung bewirkt Änderung von
Speicherinhalten oder Eingabe/Ausgabe
- Reihenfolge der Abarbeitung durch
Programmierer explizit vorgegeben
- System vordefinierter und benutzerdefinierter
Datenstrukturen
- Repräsentanten: Pascal, C, Basic
Beispiel:
(1)
x := 0;
(2)
x := x + 5;
Das sind keine Gleichungen, sondern Anweisungen
zur Änderung des Inhaltes eines Speicherplatzes
symbolisiert durch die Variable x.
Nach (1):
x  0
Nach (2):
x 5
Funktionale Programmierung
- Programm besteht im wesentlichen aus
Funktionsdefinitionen und Aufruf einer Funktion
- Abfolge der Funktionsaufrufe durch funktionale
Abhängigkeiten gegeben
- Wichtigste Datenstrukturen: Listen, Ströme
- Repräsentanten: Haskell, SML, Lisp, Scheme
Logische Programmierung
- Programm als Sammlung logischer Aussagen mit
Anfrage in Form von Horn-Klauseln
- Programmabarbeitung: Versuch des Beweises der
Anfrage mit Variablenbelegung als Nebeneffekt
(entspricht einer Berechnung)
- Wichtigste Datenstrukturen: Terme, Listen
- Repräsentanten: Prolog, Prolog IV
Objektorientierte Programmierung
- Die Welt besteht aus Objekten, die sich
Nachrichten zusenden.
- Eine Nachricht kann den Zustand eines Objekts
(Werte von Variablen, Attributen) ändern.
- Objekte können erschaffen oder gelöscht werden.
- Verwandte Objekte gehören zu einer Klasse.
- Klassen bilden eine Hierarchie.
- Repräsentanten: Java, C++, C#
Beispiel Sortierproblem
1. Imperative Version
procedure insertion(a : array of integer);
var i, j, v: integer;
begin
for i := 2 to N do
begin
v := a[i]; j := i;
while a[j – 1] > v do
begin a[j] := a[j – 1]; j := j – 1 end;
a[j] := v
end
end
Bearbeitungsschritte für {17, 5, 7, 1}
Neue Menge
Alte Menge
17
17
5 17
5 7
1 5
17
7
17
5
5
7
7
7
1
1
1
1
2. Funktionale Version
% Sortierfunktion
DEF sort([]) = []
DEF sort([a|R]) = a insert sort(R)
% [a|R] bezeichnet eine Liste mit dem Kopfelement
% a und der nachfolgenden Restliste R
% Einfuegefunktion
DEF x insert [] = [x]
DEF x insert [a|R] = IF x  a THEN [x|[a|R]]
ELSE [a|(x insert R)]
FI
Sortieren von {17, 5, 7, 1}
sort([17|[5, 7, 1]])
7 insert sort([1])
17 insert sort([5, 7, 1])
sort([1|])
sort([5|7, 1])
1 insert sort([])
5 insert sort([7, 1])
1 insert []
sort([7|1])
[1]
7 insert [1] = 7 insert [1|]
17 insert [1, 5,7]
[1|7 insert []]
[1|17 insert [5, 7]]
[1|[7]] = [1, 7]
5 insert [1, 7]
[1|[5|17 insert [7]]]
[1|[5|[7|17 insert []]]]
[1|5 insert [7]]
[1|[5|7 insert []]] = [1, 5, 7]
[1|[5|[7|[17]]]] =
[1, 5, 7, 17]
3. Logische Version
insertsort([], []).
%Die leere Liste sortiert ergibt wiederum die
% leere Liste.
insertsort([A|R], S) :insertsort(R, SR), insert(A, SR, S).
%Ist eine Liste nicht leer, so wird erst die
% Restliste sortiert und anschliessend das
%Kopfelement in die sortierte Restliste auf
% den richtigen Platz eingefuegt.
insert(X, [A|R], [A|S]) :gt(X, A), !, insert(X, R, S).
%Ist das einzufuegende Element X groesser als das
%Kopfelement der Liste, so muss es in die Restliste
%R eingefuegt werden.
insert(X, S, [X|S]).
%Ist das einzufuegende Element X kleiner oder
%gleich dem Kopfelement, so wird es als neues
%Kopfelement verwendet und die alte Liste S bildet
%die neue Restliste.
Als Anfrage könnte nun z.B. gestellt werden
?- insertsort([17, 5, 7, 1], S).
Das System antwortet mit
yes
S = [1, 5, 7, 17]
4. Objektorientierte Version
Vorgehen:
- Es wird ein Klasse von sortierbaren Objekten
eingeführt.
- Unter den Operationen dieser Klasse befindet
sich eine Operation insertsort zum Sortieren.
- Es sei o ein Objekt der Klasse. Durch
Schicken der Nachricht insertsort an o
o.insertsort
wird der Sortierprozess ausgelöst.
5. Logische Programmierung mit Einschränkungen
Beispiel: Zusammenstellung einer kalorienarmen
Mahlzeit
lightmeal(Vorspeise, Hauptmahlzeit, Nachspeise):I > 0, J > 0, K > 0, I + J + K <= 10,
%Die gesamte Mahlzeit darf nicht mehr als 10
%Kalorien enthalten.
vor(Vorspeise, I), haupt(Hauptmahlzeit, J),
nach(Nachspeise, K).
%Erster Parameter ist Speise, zweiter ist Kalorien
%Vorspeisen
vor(rettich, 1).
vor(nudeln, 6).
%Hauptmahlzeit
haupt(H, I) :- fleisch(H, I).
haupt(H, I) :- fisch(H, I).
fleisch(bulette, 6).
fleisch(schwein, 7).
fisch(seezunge, 2).
fisch(thun, 4).
%Nachspeise
nach(obst, 2).
nach(eis, 6).
%Anfrage
?- lightmeal(V, H, N).
%Antwort des Systems
V = rettich, H = bulette, N = obst.
Ein Ziel des Informatikstudiums
• Bekanntmachung mit allen
Programmierparadigmen, wobei jeweils
konkrete Programmiersprachen zur
Illustration und als konkretes Werkzeug
dienen
• Allgemeine Kenntnisse über
Programmierparadigmen als wichtige
Voraussetzung
- zur Bewertung des Einsatzes einer
Programmiersprache in der
Softwareentwicklung
- zum selbständigen Erlernen neuer
Programmiersprachen
Entscheidung für Pascal als
Anfängersprache
• Repräsentiert das imperative Paradigma
• Pascal als Ausgangspunkt für weitere
imperative Sprachen
• Programme gut strukturiert und lesbar
(verständlich)
• Gute Wartbarkeit der Programme
• Leicht erlernbar
Problemlösung auf dem Rechner
Gegeben: Problem der realen Welt
Gesucht: Lösungsmöglichkeiten unter
Nutzung der Rechentechnik
Vereinfachte Vorgehensweise:
1. Problemanalyse mit Erstellung eines
mathematischen Modells
2. Suche nach einem Lösungsalgorithmus
3. Abbildung in ein Softwaresystem in einer
höheren Programmiersprache –
Programmierung im engeren Sinn
4. Verifikation und Test des Systems
5. Abbildung der Ergebnisse des Systems für reale
Daten in die reale Welt
Zur Erleichterung von Schritt 3 und 4 Einsatz von
Programmentwicklungsumgebungen :
- Dateiverwaltung
- Editor
- Hilfe
- Compiler
- Linker
- Debugger
Rolle des Compilers
Übersetzung eines Softwaresystems geschrieben in
einer höheren Sprache in die Sprache des
jeweiligen Rechners, d.h.,
- Datenstrukturen der höheren Sprache werden in
Datenstrukturen der Maschinensprache übersetzt,
- Anweisungen der höheren Sprache werden in
Anweisungsfolgen der Maschinensprache
transformiert,
und anschließende Einbettung in ein Laufzeitsystem
Pascal
I Historisches
- 1970 durch Niklaus Wirth an der ETH Zürich als
Antwort auf die Mammutsprachen PL/1 und
ALGOL 68 entwickelt
- Normierung als Standard-Pascal 1982 durch ISO
und 1983 durch DIN
- Erste Compiler kostenlos von Wirth
- Kommerzielle Compiler von Borland in Verbindung
mit Sprachänderungen und Bereitstellung von
Programmentwicklungsumgebungen
Standard-Pascal  Turbo Pascal
- Ab Version 5.5 Möglichkeit der Umsetzung des
objektorientierten Paradigmas in Turbo Pascal
Hier: Behandlung des Sprachkerns der Versionen
6.0/7.0 mit Vernachlässigung der objektorientierten
Programmierung
II Programmkonstrukte
II.1 Einführungsbeispiel
Berechnung des größten gemeinsamen Teilers zweier
ganzer Zahlen
Bezeichnung:
ggt(x, y)
größte ganze Zahl, die x und y teilt
Eigenschaften:
- ggt(x, y) existiert immer
- ggt(x, y) = ggt(y, x)
- ggt(-x, y) = ggt(x, y)
 Möglichkeit der Beschränkung auf natürliche
anstatt ganze Zahlen
- ggt(x, 0) = |x|
- ggt(x, x) = x
Vorgehen:
Gegeben: natürliche Zahlen a und b;
Gesucht: ggt(a, b)
Lösungsschritt: Suche nach x und y, wobei
ggt(a, b) = ggt(x, y) und yb
Nach endlich vielen Schritten ist y = 0 und damit
gilt
ggt(a, b) = ggt(x, 0)
Darstellung als Struktogramm
Eingabe a, b
a0, b0, ab
x  a; y  b
x0, y0, xy
y0
ggt(a, b) = ggt(x, y), y0
Verkleinerung
von y;
Änderung von x ggt(a, b) = ggt(x, y)
Ausgabe ggt(a, b)
ggt(a, b) = ggt(x, y), y=0
 ggt(a, b) = x
Verkleinerung von y, Änderung von x
Wegen xy gilt
x = m*y + r, 0ry
Aus r = x – m*y folgt, dass
ggt(x, y) = ggt(r, y) = ggt(y, r)
Verkleinerung von y: Verwendung von r
Änderung von x: Verwendung von y
Verfeinertes Struktogramm
Eingabe a, b
a0, b0, ab
x  a; y  b
x0, y0, xy
y0
ggt(a, b) = ggt(x, y), y0
Berechnung
von r;
x  y; y  r
ggt(a, b) = ggt(x, y)
Ausgabe ggt(a, b)
ggt(a, b) = ggt(x, y), y=0
 ggt(a, b) = x
Anderes mathematisches Modell:
Nutzung der Eigenschaft
a > b  ggt(a, b) = ggt(a – b, b)
Bewertung: Das zweite Modell führt zu effizienteren
Programmen.
Schlussfolgerung:Falls ein Lösungsalgorithmus nicht
vorgeschrieben ist, sollte man erst einmal nach
dem effizientesten suchen (Komplexität).
Pascalprogramm für erstes Modell
program GGT(input, output);
uses crt;
var a, b, x, y, r: integer;
begin clrscr;
read(a); read(b);
x := a; y := b;
while y  0 do
begin r := x mod y; x := y; y := r end;
writeln(´ggt(´,a,´,´,b,´) = ´,x)
end.
Fragen zum Programm:
- Ist das Programm für alle ganzen Zahlen und das
ohne Beachtung der Bedingung a>b anwendbar?
- Was passiert bei falschen Eingaben?
(Programmrobustheit)
- Wie kann man komfortablere Ein- und Ausgaben
programmieren?
- Wie lässt sich die Lesbarkeit verbessern?
(Kommentare)
II Programmkonstrukte
II.2 Programmstruktur
Verbale Beschreibung
Ein Programm besteht aus einem Programmkopf
(darf fehlen), der uses-Klausel (darf ebenfalls
fehlen) und aus einem Block, der seinerseits aus
einem Vereinbarungsteil und einem
Anweisungsteil in dieser Reihenfolge
zusammengesetzt ist.
Darstellung als Syntaxdiagramme
Programm
Programmkopf
Block
.
uses-Klausel
Programmkopf
program
Name
( Name
,
)
;
uses-Klausel
uses
Name
,
;
Block
Vereinbarungsteil
Anweisungsteil
Darstellung durch Syntaxregeln (EBNF)
<Programm> ::=
[<Programmkopf>] [<uses-Klausel>] <Block> .
<Programmkopf> ::=
program <Name> [(<Name> {, <Name>})] ;
<uses-Klausel> ::=
uses <Name> {, <Name>} ;
<Block> ::=
<Vereinbarungsteil> <Anweisungsteil>
Rolle der Programmkomponenten
Namen: Der Name nach program bezeichnet das
Programm. Die weiteren Namen sind Namen von
Dateien.
input meint die Standard-Eingabedatei Tastatur, output
bedeutet die Standard-Ausgabedatei Bildschirm.
uses-Klausel: Sie gibt die Namen von anderen
Programmeinheiten an, aus denen Dienstleistungen
genutzt werden.
Block: Er enthält die eigentliche Berechnung mit
dem Anweisungsteil.
Informationen zur Übersetzung bzw. zur
Feststellung von Fehlern sind im
Vereinbarungsteil enthalten
II.2.1Ausdrücke
Ausdrücke dienen der Berechnung von Werten und
bestehen aus Operanden, Operatoren und ( sowie
).
Einfache Ausdrücke: einstellig (1 Operator und 1
Operand) oder zweistellig (2 Operanden, 1
Operator)
Arten von Ausdrücken: arithmetische Ausdrücke,
logische Ausdrücke, Bitausdrücke,
Funktionsaufrufe
Operanden: Konstanten, Variablen, einfache
Ausdrücke, Ausdrücke
Konstanten: existieren zu unterschiedlichen Typen
und ändern ihren Wert nicht
Beispiele: 25
true 3.14 ´a´
Variablen:
- Modellieren Speicherplätze  Wertänderung
möglich (durch Einlesen oder Zuweisung)
- Charakterisiert durch Name, Wert, Typ, Adresse
- Festlegung des Variablentyps in Vereinbarung
Beispiel:
var x : integer; bedeutet
x ist der Name der Variablen und sie darf Werte vom
Typ integer annehmen. Der Compiler ordnet ihr
einen Speicherplatz mit einer bestimmten Adresse
zu.
x

integer
25
Wertzuweisung: <Variable> := <Ausdruck>
Beispiel: x := 213
Reihenfolge der Berechnung von Operationen
In Mathematik: Punktrechnung geht vor
Strichrechnung. Klammerausdrücke werden
bevorzugt berechnet.
In Pascal:
1. Klammerausdrücke werden bevorzugt
berechnet.
2. Ausführung von Operationen entsprechend
Prioritäten ihrer Operatoren
3. Operationen zu Operatoren gleicher Priorität von
links nach rechts (Linksassoziativität)
Arithmetische Ausdrücke
Die arithmetischen Operatoren sind aus der
nachfolgenden Tabelle ersichtlich:
Operator Operandentypen Ergebnistyp
*/+real x real
real
*/+integer x real
real
* div mod
integer x integer
integer
+/
integer x integer
real
Prioritäten:
- Priorität 0: einstelliges - Priorität 1: * / div mod
- Priorität 2: + -
Beispiele:
- a * b - 4 ist äquivalent mit (a * b) - 4
- i mod n
- 3 div 4 liefert 0, 3/4 liefert 0.75
Logische Ausdrücke
Die logischen Operatoren und die Vergleichsoperatoren sind in der folgenden Tabelle
zusammengestellt:
Operator Operandentypen Ergebnistyp
not
boolean
boolean
and or xor boolean x boolean boolean
= <> <
eTyp x eTyp
boolean
<= > >=
Logische Konstanten: true false
Bedeutungen von and, or und xor:
a
b
a and b a or b a xor b
false false false
false false
false true
false
true true
true false
false
true true
true true
true
true false
Prioritäten:
- Priorität 0: not
- Priorität 1: and
- Priorität 2: or xor
- Priorität 3: = <> < <= > >=
Beispiele:
- a and b or c ist äquivalent zu (a and b) or c
- (0 < x) and (x < 10)
Auswertungsarten:
- Abkürzende Auswertung ({$B-}): Abbruch der
Auswertung beginnend von links, wenn der
Gesamtwert nicht mehr geändert werden kann
- Komplette Auswertung ({$B+}): Vollständige
Auswertung des Ausdrucks.
Beispiel: (n <> 0) and (z/n < 20)
n sei 0. Dann hat n <> 0 den Wert false.
Abkürzende Auswertung: Ergebnis ist false
Komplette Auswertung: Fehler „Division durch 0“
Allgemeine Hinweise zu Ausdrücken
Die Gesetze der Mathematik gelten auf Computern nur in
beschränktem Umfang.
Ursachen dafür sind
- die eingeschränkten Zahlenbereiche
- die beschränkte Stellenanzahl auf dem Computer
- Abbildung von Dezimalzahlen als Binärzahlen in
Kombination mit beschränkter Stellenanzahl.
Beispiele:
- Binäre Darstellung von 0,2: 0,001100110011... Wegen
der beschränkten Stellenzahl im Computer muss die
eigentlich unendlich lange Zahl nach endlich vielen Stellen
abgeschnitten werden, wodurch ein Fehler entsteht.
- y := b + a; z := y – a; liefert für a = 1e+15 und b = 1 den
Wert 0 für z und nicht den erwarteten Wert 1.
Ursache:beschränkte Stellenanzahl für die Mantisse
1 + 1e+15 = 0.000000000000001e+15 + 1e+15 =
1.000000000000001e+15
Bei einer 12-stelligen Mantisse fallen also die letzten 4
Stellen weg.
II.2.2 Anweisungen
Die Aktivitäten eines Programmes werden durch
Anweisungen (statements) beschrieben, die
normalerweise nacheinander (sequentiell)
ausgeführt werden.
Steuerungsanweisungen (control statements)
erlauben Verzweigungen und Wiederholungen in
der Abfolge der Ausführung von Anweisungen.
Anweisungen werden in einfache und strukturierte
(zusammengesetzte) Anweisungen unterteilt.
Einfache Anweisungen
Hierzu gehören Wertzuweisungen,
Prozeduranweisungen (Prozeduraufrufe),
Sprunganweisungen und die leere Anweisung.
Wertzuweisung:
- Struktur: <Variable> := <Ausdruck>
- Bedingung: Variable und Ausdruck haben
denselben Typ (Ausnahme: Variable vom Typ real,
Ausdruck vom Typ integer)
Leere Anweisung: besteht aus keinen Zeichen
Prozeduranweisung: s.u.
Sprunganweisung (selten oder nicht verwenden):
- Struktur: goto <Marke>
- Bedeutung: Unterbrechung der sequentiellen Abarbeitung und Fortsetzung mit markierter Anweisung
- Marke: Name oder Ziffernfolge aus 0..9999
- Markierte Anweisung: <Marke> : <Anweisung>
- Markenvereinbarung: label <Marke> {,<Marke>}
Legt den Block fest, in dem die Marke gültig ist.
Spezielle Sprungprozeduren (bevorzugte Verwendung):
- halt: Abbruch des Programmes
- exit: Sprung an das Blockende
Bemerkungen:
- Die Verwendung von Sprunganweisungen sollte
vermieden werden, da sie schnell zu SpaghettiProgrammen führen kann.
- Es wurde bewiesen, dass Sprunganweisungen
unnötig sind, wenn eine Programmiersprache
Sequenz, Alternative und Iteration realisiert hat.
- Durch Sprunganweisungen kann evtl. die
Effizienz eines Programmes erhöht werden.
Beispiel:
label stop;
var error : boolean;
begin
...
if error then goto stop;
...
stop:end.
Strukturierte Anweisungen
Strukturierte Anweisungen sind zusammengesetzte
Anweisungen.
Hierzu gehören Verbundanweisungen, bedingte
Anweisungen, Schleifen (Laufanweisungen,
Wiederholungsanweisungen) und die withAnweisung.
Verbundanweisung
Struktur: begin <Anweisung> {; <Anweisung>} end
Eine Verbundanweisung zählt als 1 Anweisung und
darf deshalb überall stehen, wo 1 Anweisung
erlaubt ist.
Beispiele:
- begin read(i); write(i) end
2 Anweisungen ergeben 1 Verbundanweisung.
- begin read(i); write(i); end
3 Anweisungen ergeben 1 Verbundanweisung.
Bedingte Anweisungen
if-Anweisung
Struktur: if <Ausdruck> then <Anweisung>
[else <Anweisung>]
Der Ausdruck liefert einen boolean-Wert.
Ausführung:
1. Liefert der Ausdruck true, wird die Anweisung
nach then abgearbeitet.
2. Liefert der Ausdruck false, wird die Anweisung
nach else abgearbeitet oder, wenn nicht vorhanden,
die Anweisung nach der if-Anweisung.
if B then A1 else A2 (z.B. if x<0 then y:= 0 else y:=1)
B
j
n
A1
A2
Problem: Zu welchem if gehört in
if B1then if B2 then A1else A2
else A2?  Mehrdeutigkeit!
Festlegung: zum letzten!
case-Anweisung
Während die if-Anweisung die Auswahl zwischen zwei
Wegen (Anweisungen) anhand eines logischen Wertes
ermöglicht, kann bei einer case-Anweisung zwischen
beliebig vielen Wegen anhand des Ordinalwertes eines
Ausdrucks gewählt werden.
Struktur: case <Ausdruck> of
<Fall> {; <Fall>}
[else <Anweisung> {; <Anweisung>} [;]]
end
<Fall> ::= <Konstante> [..<Konstante>]
{,<Konstante>[..<Konstante>]} : <Anweisung>
Bedingungen:
- Der Ausdruck muss einen Ordinalwert liefern
(s.u.).
- Die Werte der einzelnen Fälle dürfen sich nicht
überlappen.
Abarbeitung:
- Berechnung des Ausdruckes
- Fallauswahl anhand des berechneten Wertes
- Ausführung der Anweisung des Falles
- Ausführung der Anweisung nach der caseAnweisung
case A of
K1 : A1;
K2..K3, K4 : A2;
else A3
end
A
K1
A1
K2..K3
K4
A2
A3
Beispiel:
var c : char;
begin
read(c);
case c of
´0´..´9´: ...;
(* c ist Dezimalziffer *)
´a´..´z´,´A´..´Z´: ...; (* c ist Buchstabe *)
else ...
(* sonstige Faelle *)
end;
...
Schleifen (Laufanweisungen)
Schleifen gestatten die wiederholte Abarbeitung der
gleichen Anweisungsfolge in Abhängigkeit von
einer Bedingung oder eines Zählers.
In Pascal gibt es die while-Anweisung, die repeatAnweisung und die for-Anweisung.
while-Anweisung
Struktur: while <Ausdruck> do <Anweisung>
Bedingung: Ausdruck liefert boolean-Werte
Ausführung: while A do A1
A
j
n
A1
repeat-Anweisung
Struktur: repeat <Anweisung> {; <Anweisung>}
until <Ausdruck>
Bedingung: Ausdruck liefert boolean-Werte
Bedeutung: repeat A1 until A
A1
A
n
j
for-Anweisung (Zählschleife)
Struktur:
for <Variable> := <Ausdruck1> to <Ausdruck2>
do <Anweisung>
bzw.
for <Variable> := <Ausdruck2> downto <Ausdruck1>
do <Anweisung>
Bedingung: Die Ausdrücke liefern Ordinalwerte. Sie
geben die Grenzen des Wertebereichs der Variablen
(Schleifenvariable) an.
Wert(Ausdruck2)  Wert(Ausdruck1)
Ausführung: Die Anweisung wird für jeden Wert des
Wertebereichs nach Zuweisung zur Schleifenvariablen in auf- bzw. absteigender Folge ausgeführt.
for v := a to e do A
v := a
ve
n
j
A
v := succ(v)
Die for-Schleife mit downto verwendet statt succ
pred. Liefern die Ausdrücke integer-Werte, dann
wird mit +1 oder –1 der nächste Wert der
Schleifenvariablen bestimmt.
Beispiel:
for c := ´z´ downto ´a´ do
writeln(c:2, ´ nr.´, ord(c):4);
Zeilenweise Ausgabe der Buchstaben des Bereichs
´a´...´z´ mit ihrer Ordnungszahl in der Reihenfolge
von ´z´ bis ´a´.
II.2.3 Datenstrukturen, Datentypen,
Vereinbarungen
II.2.3.1Datenstrukturen, Datentypen
Die Operationen der Ausdrücke sind nur auf Operanden
bestimmter Typen ausführbar, wobei der Typ Daten einer
bestimmten Struktur bezeichnet.
einfache Datentypen (Ordinaltypen, real)
Datentypen strukturierte Datentypen
weitere Typen (Zeiger, Prozeduren,
Objekte)
Ordinaltyp
integer
char
boolean
Aufzählungstyp
Unterbereichstyp
Strukturierter Typ
Zeichenketten
packed
Feld
Verbund
Menge
Datei
Einfache Datentypen
integer-Typen
Die ganzen Zahlen der Mathematik werden durch
mehrere integer-Typen (Effizienz) dargestellt:
byte
0..255
word
0..65535
shortint
-128..127
integer
-32768..32767
longint
-2147483648..2147483647
real-Typen
real-Datentypen:
- Darstellung der reellen Zahlen aus der Mathematik
- wegen der Beschränkung der Stellenzahl kein
Kontinuum
 Je größer die Zahlen werden, desto größer ist der
Abstand zweier benachbarter real-Zahlen
 real-Zahlen als Näherungen der reellen Zahlen und
Berechnungen mit ihnen sind fehlerbehaftet.
Darstellung: Mantisse mit Vorzeichen und Exponent (E
gefolgt von ganzer Zahl in Repräsentationen)
Typ
single
real
double
extended
comp
Zahlenbereich
1.5E-45 .. 3.4E38
2.9E-39 .. 1.7E38
5.0E-324 .. 1.7E308
3.4E-4932 .. 1.1E4932
-9.2E18 .. 9.2E18
Dezimalstellen
7–8
11 – 12
15 – 16
19 – 20
19 – 20
Bemerkungen:
- Der Typ comp hat nur ganzzahlige Werte und kann
damit als Erweiterung von longint angesehen werden.
- Beachte die Verwendung von Compilerdirektiven!
char-Typ
Der Datentyp char umfasst alle Zeichen des ASCIIZeichensatzes (American Standard Code for
Information Interchange).
char-Konstante: Zeichen eingeschlossen durch
Apostrophe (z. B. ´a´)
Standardfunktionen:
- ord : char  integer liefert die Ordnungszahl eines
Zeichens und ermöglicht damit den Zeichenvergleich.
- chr : integer  char ist die Umkehrung zu ord.
Verwendung: in Ein- und Ausgaben; allgemein in der
Textverarbeitung
boolean-Typ
Dieser Typ umfasst nur die beiden Werte wahr und falsch
repräsentiert durch true und false.
Reihenfolge (als Ordinaltyp notwendig): false true
 false < true
Verwendung: in Ausdrücken, die logische Werte liefern und
die damit als Bedingungen interpretiert werden können
Ordinaltypen
Zu den Ordinaltypen gehören neben integer, char
und boolean auch Unterbereichstypen und
Aufzählungstypen.
Unterbereichstyp: Unterbereich eines Ordinaltyps
definiert durch
<kleinstes Element > .. <größtes Element>
Beispiel: type letter = ´a´..´z´;
Definition des Unterbereichs letter der ASCIIZeichen
Aufzählungstyp: Aufzählung aller möglichen Werte
des Typs in Form einer geordneten Menge von
Namen; Nutzung der Reihenfolge für Vergleiche
Beispiel:
type Farbe = (rot, gruen, blau, gelb, schwarz)
Es gilt z.B. rot < gelb .
Standardfunktionen für Ordinalzahlen:
- Ordinalzahl ord: liefert Ordinalzahl eines Elements,
wobei bei Aufzählungstypen das erste Element die
Zahl 0 hat (z.B. ord(gelb) = 3, ord(false) = 0)
- Nachfolger succ: liefert den direkten Nachfolger
eines Elements (z.B. succ(gelb) = schwarz)
- Vorgänger pred: liefert den unmittelbaren Vorgänger
eines Elements (z.B. pred(true) = false)
Verwendung von Ordinaltypen: an Programmstellen mit
zählender oder aufzählender Arbeitsweise, z. B. zur
Steuerung von Zählschleifen
Strukturierte Datentypen
Zeichenketten
Zeichenkette: Folge von Zeichen
Typbeschreibung: string [ <Konstante>]
Bedeutung:
• Konstante gibt mögliche Länge an
• Nummerierung der Zeichen von 1 bis Konstante
(maximal 255)
• Komponente 0 gibt die wirkliche Länge an
Beispiel:
var titel: string [10];
...
titel := ´Dipl.´+ ´-´+ Ínf.´;
0
1 2 3 4 5 6 7 8 9 10
10 D i p l . – I n f .
+ verkettet Zeichenketten
Operationen:
- Wertzuweisung für string-Variablen
- Vergleich
- Verkettung
- Prozeduren und Funktionen: z.B. length, copy,
concat, pos, str, val, insert, delete
Beispiel: concat(´Dipl.´, ´-´, ´Inf.´) liefert die
Zeichenkette ´Dipl.-Inf.´
Felder (Array)
Entsprechung in der Mathematik: Vektoren, Matrizen,...
 endliche Abbildungen von Indexmengen in
Wertemengen
Typbeschreibung: array [ <Indextyp> {, <Indextyp>}]
of <Komponententyp>
Komponententyp:
- beliebiger Typ
- Typ der Werte der Komponenten
Indextyp:
- Ordinaltyp
- Typ der Indizes
Beispiele:
- type Aperitif = (Bacardi, GinTonic, GinFizz,
Manhattan, OldFashion, OrangeBlossom);
var Rezept : array [Aperitif] of Mischung;...
Rezept[Manhattan] := [Whisky, Wermut,
AngosturaBitter, Eis];
- var x: array [1..10] of real;... x[5] := 3.14;
- type Dreieck = array [1..3, 1..2] of integer;
const t: Dreieck = ((3, 12), (2, 6), (5, -2));
Spalte
Zeile 1
2
3
1
3
2
5
2
12
6
-2
Operationen:
- Wertzuweisung bei gleichem Typ
- Diverse Prozeduren und Funktionen
Verbundtyp (Record)
Analogie zu Feldern, aber
- statt Indizes Selektoren
- i.a. Komponenten von unterschiedlichen Typen
Mathematische Entsprechung:
Wertemengen als Untermengen Cartesischer
Produkte
Typbeschreibung: record {<Selektor>:<Typ>} end
Beispiel:
type Datum = record
Tag : 1..31;
Monat : 1..12;
Jahr : 0..99
end;
Person = record
Name : string [20];
Geburtsdatum : Datum
end;
var x : Person; leute : array [1..100] of Person;
Beispiel (Fortsetzung):
x.Geburtsdatum.Tag := 29;
x.Geburtsdatum.Monat := 2;
Name
Geburtsdatum
x
Tag
Monat
Jahr
29
2
Verkürzte Notation der Zuweisung an die
Komponenten: with-Anweisung
Beispiel (Fortsetzung):
with x, Geburtsdatum do
begin
Tag := 29;
Monat := 2;
end;
Mengen
Realisierung der Mengen und ihrer Operationen aus
der Mathematik
Typbeschreibung:
set of <Ordinaltyp>
Maximale Elementeanzahl: 256
Bedeutung: Eine Variable von einem Mengentyp darf
als Wert jede Menge von Elementen des Ordinaltyps
annehmen (jede Untermenge der Potenzmenge).
Notation einer Menge:
[
]
Ausdruck
..
Ausdruck
,
Beispiel:
type T = set of 1..3
bedeutet die Mengen [], [1], [2], [3], [1, 2], [1, 3],
[2, 3], [1, 2, 3] als mögliche Werte einer Variablen
Beispiel:
type Ingredienz = (AngosturaBitter, Eis, Gin,
Wermut, Whisky, Orangensaft, Zucker,
Zitronensaft, Grenadine);
Mischung = set of Ingredienz;
var Rezept : array [Aperitif] of Mischung;
begin
Rezept[Bacardi] := [Eis, Rum, Zitronensaft,
Grenadine];
Rezept[OrangeBlossom] := [Eis, Orangensaft,
Gin];...
Operationen mit Mengen:
Operator Präze- Signatur
denz
*
1
MTyp x MTyp Mtyp
+
2
´´
2
´´
=
3
MTyp x MTyp  boolean
<>
3
´´
<= (>=)
3
´´
in
3
ETyp x MTyp boolean
MTyp Mengentyp
Bedeutung


 (Differenz)
=

 ()

ETyp Elementetyp
Dateien (Filetyp)
Charakteristika:
- Folge von Datensätzen gleichartiger Struktur
- Beliebige Länge und zur Laufzeit veränderbar
- Sequentielle Verarbeitung von links nach rechts mit
Zeiger auf aktuelle (zu bearbeitende) Position (erste
Position ist 0)
- Arten der Datensätze: getypt, Text, typlos
- Verwendung: vorzugsweise für Ein- und Ausgaben
0
Operationen:
- assign( <Pdateiname>, <Bdateiname>). Zuordnung
eines Dateinamens im Programm zu einem
Dateinamen im Betriebssystem
- reset(<Dateiname>): Zurücksetzen des
Positionszeigers auf 0
- rewrite(<Dateiname>): Erzeugen einer leeren Datei
und Positionierung auf 0
- read(<Dateiname>,...): Lesen aus einer Datei
- write(<Dateiname>,...): Schreiben in eine Datei
- eof(<Dateiname>): Steht Zeiger auf eof (end of file)?
- close(<Dateiname>): Schließen einer Datei
(Abschluss mit eof und Eintragung im
Inhaltsverzeichnis-directory)
- erase(<Dateiname>): Löschen einer geschlossenen
Datei
- rename(<alterName>, <neuerName>):
Umbenennung einer geschlossenen Datei
Dateien-Typdateien
Typbeschreibung: file of <Datensatztyp>
Beispiel:
type Personendatei = file of Person;
var PD : Personendatei;
Operationen:
- read(<Dateiname>, <Variablen vom Satztyp>):
Auslesen von Datensätzen aus der Datei in die
Variablen mit Weitersetzen des Dateizeigers
- write(<Dateiname>, <Variablen vom
Datensatztyp>): Schreiben der Datensätze der
Variablen in die Datei mit Weitersetzen des Zeigers
- seek(<Dateiname>, <Datensatznummer>):
Positionierung des Dateizeigers auf die
Datensatznummer (erste Position ist 0)
- filepos(<Dateiname>): liefert Position des
Dateizeigers
- filesize(<Dateiname>): liefert Anzahl der Datensätze
der Datei
- truncate(<Dateiname>): Abschneiden der Datei an
aktueller Position und Einfügen von eof
Bemerkung: Die letzten vier Operationen dienen
insbesondere für die höheren Operationen
- Hinzufügen
- Änderung
- Löschen
eines Datensatzes.
Dateien-Textdateien
Charakterisierung:
- Datensätze sind Zeichen
- Datei mit Zeilenstruktur
- Typ text
- Automatische Konvertierung von Zahlen beim
Lesen und Schreiben
- Standarddateien input und output sind vom Typ
text
Verwendung: Ein- und Ausgaben von Texten
Operationen:
- readln(<Dateiname>): Setzen des Dateizeigers auf
Anfang der neuen Zeile
- writeln(<Dateiname>): Setzen der end-of-lineMarke
- eoln(<Dateiname>): Steht Zeiger auf Zeilenende
(eoln)?
- seekeoln(<Dateiname>): Überlesen von Blanks
und Tabulatoren mit anschließendem eoln-Test
- seekof(<Dateiname>): Überlesen von Blanks,
Tabulatoren und Zeilenwechsel mit
anschließendem Test auf eof
- flush(<Dateiname>): Schreiben des Puffers in Datei
- settextbuf(<Dateiname>, <Puffer>, <Größe>):
Einrichten eines Puffers für Datei
- append(<Dateiname>): Öffnen der Datei und Setzen
des Zeigers auf eof (Lesen in Datei möglich)
- read(<Dateiname>, <Variable>) mit Variablentyp
string, char, integer oder real: Einlesen einer
Zeichenfolge bzw. einer Zahl mit Konvertierung
- write(<Dateiname>, <Ausdruck mit Formatangabe>)
mit Ausdrucktyp char, string, boolean, integer oder
real: Schreiben der Zeichenfolge mit evtl.
Konvertierung und Schreiben gemäß Format
Formatangabe:
1. Formatangabe fehlt: Ausgabe im Standardformat
2. <Parameter>:<Breite des Datenfeldes> :
Rechtsbündige Ausgabe im Datenfeld
3. <Parameter>:<Breite des Datenfeldes>:<Stellen
nach Dezimalpunkt> : Rechtsbündige Ausgabe
von real-Zahlen mit gewünschter Stellenzahl
nach dem Dezimalpunkt, aber ohne Exponent
Abkürzende Notationen:
- read(<Dateiname>, <Var1>,...,<Varn>) bedeutet
read(<Dateiname>, <Var1>);...read(<Dateiname>,
<Varn>); analog für readln, write, writeln
- read(<Var1>,...,<Varn>) bedeutet
read(input, <Var1>,...,<Varn>)
- readln meint readln(input); analog für eof und eoln
- write(<Aus1>,...,<Ausn>) steht für
write(output, <Aus1>,...,<Ausn>)
- writeln ist writeln(output)
Dateien-Typlose Dateien
Betrachtung einer Datei als Bytefolge ohne Struktur
Typbeschreibung: file
Bemerkung: Standardprozeduren wie rewrite
enthalten den zusätzlichen Parameter
Blockgroesse (bei Fehlen standardmäßig 128;
Angabe der Anzahl der übertragenen Bytes)
Operationen:
- blockread(<Dateiname>, <Puffer>,
<maxBlockanzahl>, <wBlockanzahl>): Lesen von
Blöcken aus der Datei in den Puffer
- blockwrite(<Dateiname>, <Puffer>,
<maxBlockanzahl>, <wBlockanzahl>): Schreiben
aus dem Puffer in die Datei
Bemerkung: Die Blockgröße wird durch reset bzw.
rewrite eingestellt.
Weitere Datentypen
Zeigertypen
Zeiger:
-Variable, deren Wert eine Adresse ist
- In Programmiersprachen: nicht vorhanden oder,
wenn vorhanden, mit expliziten bzw. impliziten
Adressen (z. B. in Turbo-Pascal)
Typbeschreibung: ˆ <Typname>
Gezeigter Wert: <Zeigervariable>ˆ
Beispiel: var x : ˆreal;
Vereinbarung von x als Zeigervariable, wobei die
„gezeigten“ Werte (Bezugsvariable) real-Werte sind
x


Adresse von x
zugeteilt durch Compiler

Wert von x (Adresse)
3.14
gezeigter real-Wert
(Bezugsvariable xˆ)
Frage: Wie kommt eine Zeigervariable zu ihren Werten?
Antwort:
- Zuweisung von Adressen existierender Variablen
- Zuweisung von Adressen von dynamischen Variablen
Beispiele:
1. var i : integer; pi : ˆinteger; ...;pi := @ i;
2. var pi, pii : ˆinteger; ...; pi := pii;
3. var pi : ˆinteger; ...; new(pi); piˆ := 25;
1.
i

pi


25
Vereinfachte
Darstellung
i
25

pi
2.
pi



pii


25

Vereinfachte
Darstellung
pi
pii
25
3.
pi


piˆ 

25
Vereinfachte
Darstellung
pi
piˆ
25
Unterschied von normalen (semistatischen) und
dynamischen Variablen:
- Semistatische Variablen: Existenz über gesamte
Lebensdauer des Blockes, in dem sie vereinbart
sind; Speicherplatz im Kellerspeicher
- Dynamische Variablen: Erzeugung während der
Laufzeit durch new und Beseitigung durch
dispose; Abspeicherung auf dem Haldenspeicher
(heap)
Verwendung von Zeigern
Konstruktion und Manipulation von
Datenstrukturen, deren Struktur sich während der
Laufzeit ändert
Beispiel: Einfach gekettete Listen
Anker
´Meyer´
2000
´Lafitte´
1939
´Held´
1985
nil
type Kette = record Name : string[20];
Jahr : 1900..2003;
Naechster : ˆKette
end;
var Anker, l, h : ˆKette;
Anker
begin new(Anker);
Ankerˆ.Name := ´Meyer´;
´Meyer´
Ankerˆ.Jahr := 2000;
2000
Ankerˆ.Naechst := nil;
nil
l := Anker;
l
new(h); hˆ.Name := ´Lafitte´;
hˆ.Jahr := 1939;
hˆ.Naechster := nil;
l.Naechster := h;
Anker
´Meyer´
2000
l
h
´Lafitte´
1939
nil
l := h;
new(h);hˆ.Name := ´Held´;
hˆ.Jahr := 1985;
hˆ.Naechster := nil;
l.Naechster := h
Anker
l
´Meyer´
2000
´Lafitte´
1939
h
´Held´
1985
nil
Operationen:
- Anhängen eines Elementes
- Löschen eines Elementes
- Verkettung zweier Listen
- Ordnen der Elemente
- Einsortieren eines Elementes
- Suche eines Elementes
II.2.3.2Variablenvereinbarungen und
Typvereinbarungen
Variablenvereinbarungen
Variablenvereinbarungen legen für den folgenden
Block fest,
welchen Typ die Werte der Variablen haben
Wertebereich, Operationen, Größe des durch
Compiler zu reservierenden Speicherplatzes
Typüberprüfungen durch Compiler und damit
Aufdeckung von Fehlern
Aufbau:
var
Name
:
Typ
,
<Variablenvereinbarung> ::= var {<Name>
{,<Name>} : <Typ> ;}+
;
Typvereinbarungen
Datentypen sind entweder vordefiniert oder
nutzerdefiniert. Nutzerdefinierte Datentypen
werden in Typvereinbarungen für den
nachfolgenden Block eingeführt.
Aufbau:
type
Name
=
Typ
;
II.2.4 Prozeduren und Funktionen
In größeren Programmen kommen in der Regel
gleiche oder ähnliche Anweisungsfolgen an
mehreren Stellen des Programmes vor. Außerdem
möchte der Programmierer die Lesbarkeit seines
Programmes dadurch verbessern, dass logisch
zusammengehörende Anweisungsfolgen zu einer
Einheit zusammengefasst werden, wobei nur die
Gesamtwirkung (WAS), aber nicht die Wirkung der
einzelnen Anweisungen (WIE) interessant sind.
 Verwendung von Prozeduren/Funktionen
Prinzip:
- Zusammenfassung von Anweisungen unter einem
Namen, der dann die Folge vertritt, und
Flexibilisierung durch Parameter
 Prozedur/Funktionsvereinbarung
- Verwendung des Namens zusammen mit
passenden Werten für die Parameter an allen
Programmstellen, wo ursprünglich die
Anweisungsfolgen gestanden hätten
 Prozedur/Funktionsaufruf (-anweisung)
Unterschied Prozedur – Funktion: Eine Funktion
liefert einen Wert, der vom Aufruf vertreten wird
Prozeduren
Grammatikregeln (unvollständig):
<Prozedurvereinbarung> ::=
<Prozedurkopf> ; <Prozedurblock> ;
<Prozedurkopf> ::= procedure <Prozedurname>
[<Liste der formalen Parameter>]
<Liste der formalen Parameter> ::=
( [var]<Pname> : <Typname> {; [var]<Pname> :
<Typname>} )
<Prozedurblock> ::= <Block>| forward
<Prozeduraufruf> ::=
<Prozedurname> ( <aktueller Parameter>
{, <aktueller Parameter>} )
<aktueller Parameter> ::= <Variable>| <Ausdruck>
Bedingungen:
- Beim Prozeduraufruf müssen die aktuellen
Parameter in Anzahl, Typ und Reihenfolge mit den
formalen Parametern übereinstimmen.
- Formale Parameter sind Platzhalter. Sie können
daher frei gewählt werden.
Aufrufmodi:
- Steht vor einem formalen Parameter in der Liste
der formalen Parameter var, dann wird an die
Prozedur die Adresse des aktuellen Parameters
vermittelt (call by reference). Damit kann der Wert
des aktuellen Parameters durch die Prozedur
geändert werden.
 Verwendung für Ergebnisparameter; aktueller
Parameter muss Variable sein
- Sonst: Übergabe des Wertes des aktuellen
Parameters an die Prozedur (call by value)
 Verwendung als Eingabeparameter
Beispiel:
var i, k : integer;
procedure count(x : integer; var y : integer);
begin
x := x + 1; y := y + 1
end;
begin ...
i := 3; k := 3;
count(i, k)
end.
(* Aufruf von count *)
Wirkung von count(i, k):
- Einsetzen des Wertes von i für x
 Durch x := x + 1 Berechnung des neuen xWertes 4 ohne Beeinflussung des i-Wertes.
- Anstelle der Adresse von y wird die Adresse von k
verwendet.
 Durch y := y + 1 Berechnung des neuen kWertes 4.
Datenbereiche unmittelbar nach Aufruf von
count(i, k):
i
k
Datenbereich count


x
y
3
3

Datenbereiche unmittelbar nach Beendigung des
Aufrufs von count(i, k):
i
k


3
4
Lokale und nichtlokale Größen
Da ein Prozedurrumpf ein Block ist, können Namen für
diesen Block vereinbart werden.
Lokale Größen
Wenn die Prozedurvereinbarung im Vereinbarungsteil
eines anderen Blockes (übergeordneter Block) steht,
dann dürfen auch die dort vereinbarten Größen im
Prozedurrumpf verwendet werden.
Nichtlokale Größen
Verdeckungsregel:Haben eine lokale und eine nichtlokale
Größe den gleichen Namen, dann ist die nichtlokale
Größe verdeckt, d.h. in der Prozedur nicht zugreifbar.
Beispiel:
procedure p;
var x,y;
procedure q;
var x,s;
begin
x
y
s
end;
...
(* x aus q *)
(* y aus p *)
(* s aus q *)
p: x, y
Graphische Darstellung
der Verschachtelung
q: x, s
p
x,y
q
x,s
Bemerkung: Neben den Parametern können
nichtlokale Größen zur Kommunikation zwischen
Prozeduren verwendet werden. Da das aber zu
ungewollten Effekten führen kann, ist das
schlechter Programmierstil und daher zu
vermeiden!
Standardprozeduren: Zur Vereinfachung der
Programmierung stehen in den Units der
Bibliothek von Pascal Standardprozeduren und –
funktionen zur Verfügung.
Funktionen
Sie unterscheiden sich von Prozeduren dadurch, dass
sie einen Funktionswert von einem einfachen Typ,
string oder Zeigertyp liefern. Ihr Aufruf vertritt
den berechneten Wert und kann deshalb überall
dort stehen, wo ein Wert des entsprechenden Typs
benötigt wird. Hieraus ergeben sich die
Änderungen in der Notation zur Prozedur.
Grammatikregel für Funktionskopf:
<Funktionskopf> ::= function <Funktionsname>
[<Liste der formalen Parameter>] : <Typ>
Bedingungen:
- Der Typ gibt den Typ des Ergebnisses an.
- Im Block der Funktion muss dem Funktionsnamen
ein Wert (Funktionswert) zugewiesen werden.
Beispiel:
function Fak(n : integer): integer;
begin if n <= 1 then Fak := 1
else Fak := n * Fak(n – 1) end;
Beispiel:
Nebeneffekt (side effect) durch nichtlokale Größe
var a, y: integer;
function Daneben(x:integer):integer;
begin a := x + 1; Daneben := a end ;
begin ...
a := 3; y := Daneben(4) + a; (* liefert 10 *)
a := 3; y := a + Daneben(4); (* liefert 8 *)
...
II.2.5 Modularisierung und Units
Große Programme werden heute in kleinere
Einheiten – Module – unterteilt.
Ziele:
- Bessere Übersichtlichkeit und damit weniger
Fehler
- Leichte Austauschbarkeit von Programmteilen
gegen effizientere
- Wiederverwendbarkeit
- Separate Bearbeitung (Entwicklung, Übersetzung)
Unitkonzept
Unit als Dienstleistungsmodul:
- Vereinbart Konstanten, Typen, Variablen,
Prozeduren, Funktionen
- Nutzung in anderen Units bzw. im Programm so,
als ob die Vereinbarungen an Ort und Stelle erfolgt
wären
- Einbindung einer Unit durch uses <Unitname>
Grammatikregeln für Struktur:
<Unit> ::= <Unitkopf> <Schnittstelle>
<Implementation> <Initialisierung> .
<Unitkopf> ::= unit <Name> ;
<Schnittstelle> ::= interface {<usesKlausel>}{<Liste von Konstantenvereinbarungen,
Typvereinbarungen, Prozedur/Funktionsköpfen>}
<Implementation> ::= implementation
{<uses-Klausel>}<Vereinbarungen>
Bedeutung:
- Schnittstelle: Enthält alle Dienstleistungen der
Unit in Form von Konstanten- und
Typvereinbarungen sowie Köpfen von Prozeduren
und Funktionen (Rümpfe in Implementation)
- Implementation enthält nicht öffentliche
Vereinbarungen von Konstanten, Variablen,
Prozeduren und Funktionen
- Die Anweisungen der Initialisierung werden in
Zusammenhang mit der uses-Klausel ausgeführt.
Beispiele:
- unit Typen;
interface
const maxkell = 10;
type kellzeig = ˆkellel;
eltyp = integer;
kellel = record elem : eltyp;
naechst : kellzeig end;
var k : kellzeig; fertig : boolean; kellgroes, d : integer;
implementation
begin end.
- unit kellop;
interface
uses Typen;
procedure push(var k : kellzeig; e :eltyp);
procedure pop(var k : kellzeig);
function istvoll(k : kellzeig): boolean;
...
implementation
procedure push(var k : kellzeig; e :eltyp);
(* Prozedurrumpf *)
...
Arten von Units:
- Nutzerdefinierte Units
- Standardunits: SYSTEM, CRT,...
Gültigkeitsbereiche:
- Die in einer Unit vereinbarten Objekte bilden eine
Umgebung für Units oder Programme, in der ihre
Objekte verwendet werden (Analogie zu
Prozedurschachtelungen).
- Bei Namenskonflikten gilt wie bei Prozeduren das
Verdeckungsprinzip, aber es kann zum verdeckten
Objekt durch Qualifizierung (Voranstellen von
<Unitname>.) zugegriffen werden.
II.3 Fehler in Programmen
Fehlerarten:
- Syntaktische Fehler: Programmnotationen, die nicht
den Grammatikregeln entsprechen
 Aufdeckung durch Compiler mit Angabe der
Fehlerstelle (frühestmöglicher Zeitpunkt der
Fehlererkennung, i.a. nicht der Fehlerverursachung)
- Fehlende Unit
 Aus der Unit benutzte Größen werden als nicht
vereinbart betrachtet.
- Falsch angewendete Anweisungen
(Nichtbeachtung der Semantik)
 Laufzeitfehler wie Division durch Null
- Fehlerhafte Algorithmen
 Falsche Ergebnisse
Einfache Methoden der Suche von Fehlerursachen:
- Schrittweise Programmausführung
- Kontrolldrucke
- Debugging