Home
Up
Intro
Contents
Chapter
1
2
3
4
5
6
7
8
9
10
Design
Assert
Timing
EBNF
Report
Pas
Last Changed: Nov. 19, 1997
This is a conversion from Oberon text to HTML. The converter software is still under development,
and some features or information may be missing in this converted version.
HTML hypertext facilities are not yet active in this document.
To exploit the interactive facilities, use Oberon System 3 and the source of this text,
available as ASCII-coded Oberon System 3 documents. A previous version is also available for Oberon V4.
To access this and other additional material use
ftp.
For the convenience of our students, most of this information and the related material is in German.
Sorry if this is not one of your languages.
Einführung in die Programmiersprache Oberon.
07 Prozeduren, Funktionen
Durch Prozeduren und Funktionen können Module strukturiert werden.
Eine Prozedur fasst eine Gruppe von Anweisungen in einem Block zusammen und
macht sie unter einem Namen verfügbar, unter dem dieser Anweisungsblock
aktiviert werden kann. Eine Prozedur wird durch eine Prozedurdeklaration
eingeführt. Diese kann neben dem Anweisungsblock auch formale Parameter
und lokale Deklarationen enthalten. Aufgerufen wird eine Prozedur durch ihren
Namen, evtl. gefolgt von einer aktuellen Parameterliste.
Wie bei allen Deklarationen kann auch bei Prozedur-Deklarationen eine Export-Markierung
beigefügt werden. Es gelten die übliche Regeln: innerhalb des
Moduls, in dem die Prozedur deklariert ist, wird eine Prozedur unter ihrem
Namen aufgerufen. Soll sie in einem anderen Modul aufgerufen werden, so das
Modul, in dem die Prozedur deklariert ist, importiert werden, und die Prozedur
wird mit mit ihrem qualifizierten Namen Modulname.Prozedurname
aufgerufen.
Prozeduraufruf:
Prozedurname
[aktuelle Parameterliste ]
aktuelle Parameterliste:
(
[Parameter {, Parameter }] )
Wir haben Prozeduraufrufe bereits kennengelernt. Die Anweisung System.Time
ruft die Prozedur Time im Modul System auf. Dies ist eine parameterlose Prozedur.
Die Anweisung Texts.WriteString(w,'Hallo') ruft
die Prozedur WriteString im Modul Texts auf. Dabei werden zwei Parameter
übergeben: der Writer w und der String 'Hallo'. Parameter können
auf zwei Arten übergeben werden. Für Parameter wie den String
in diesem Beispiel muss tatsächlich der Wert (in diesem Fall 'Hallo')
übergeben werden. Ist beim Aufruf der aktuelle Parameter ein Ausdruck,
so wird zunächst der Ausdruck ausgewertet und das Resultat als Parameter
übergeben, zum Beispiel bei einem Aufruf Texts.WriteInt(w,i+j,10).
Für andere Parameter wie den Writer w soll lediglich eine Referenz
auf den aktuellen Parameter übergeben werden. Die aufgerufene Prozedur
soll tatsächlich mit dem aktuellen Writer arbeiten und ihn gegebenenfalls
auch verändern.
Bei der Prozedurdeklaration wird festgelegt, welche Parameter als Wert und
welche als Referenz übergeben werden. Parameter, die als Referenz übergeben
werden, sind mit VAR gekennzeichnet. Beim Aufruf müssen hier Variable
als aktuelle Parameter eingesetzt werden. Parameter, die nicht mit VAR gekennzeichnet
sind, werden als Wert übergeben. Hier können als aktuelle Parameter
auch Konstanten oder Ausdrücke eingesetzt werden. Implizit wird für
jeden Wert-Parameter eine lokale Variable erzugt, die nur innerhalb der Prozedur
sichtbar ist und nur dort seine Gültigkeit hat. Der aktuelle Parameter
wird bei Prozeduraufruf ausgewertet und das Resultat wird in dieser impliziten
lokalen Variablen übergeben.
Prozedur-Syntax:
PROCEDURE
[Ziel] Prozedur-Name [formale Parameterliste];
Deklarations-Folge
[BEGIN
Anweisungs-Folge ]
END Prozedur-Name;
formale Parameterliste
( [
formaler Parameter { ; formaler
Parameter } ] ) [ : Ergebnistyp ]
formaler Parameter
[
VAR ] Name { , Name} : Typ
Für Texts.WriteString und Texts.WriteInt
sind die Deklarationsköpfe im Modul Texts entsprechend
PROCEDURE WriteString*(VAR W:
Writer; s: ARRAY OF CHAR);
PROCEDURE WriteInt*(VAR W: Writer;
x, n: LONGINT);
Beim Prozeduraufruf werden die aktuellen Parameter den formalen ihrer Position
in der Liste nach zugeordnet. Bei Wert-Parametern werden die entsprechenden
aktuellen Ausdrücke ausgewertet und das Ergebnis dem jeweiligen formalen
Parameter zugewiesen, die dann lokale Variable darstellen. Die aktuelle Parameterliste
muss der formalen entsprechen.
Oberon-2 ergänzt die Oberon-Syntax durch einen optionalen Parameter,
den Zielparameter. Dieser kann vor dem Prozedurnamen angegeben werden. Der
Zielparameter wird besonders behandelt, um einen bestimmten Programmierstil
der objektorientierten Programmierung zu unterstützen. Wir kommen darauf
in einem späteren Kapitel zurück.
Der Deklarationsteil einer Prozedur entspricht im wesentlichen dem eines
Moduls. Jedoch können Deklarationen aus einer Prozedur nicht exportiert
werden. Prozeduren definieren lokale Sichtbarkeits- oder Gültigkeitsbereiche.
Der Gültigkeitsbereich beginnt beim Ort der Deklaration und erstreckt
sich bis zum Ende der Prozedur. Namen dürfen nur innerhalb des Gültigkeitsbereichs
ihrer Deklaration benutzt werden. Kein Name darf sich innerhalb seines Gültigkeitsbereichs
auf mehr als ein Objekt beziehen. Die Gültigkeitsbereich können
jedoch geschachtelt sein: eine (Unter-)prozedur definiert einen neuen Gültigkeitsbereich.
Wird ein Name deklariert, der bereits im umgebenden Block definiert ist,
so gilt bis zum Ende der Prozedur die lokale Deklaration; die vorherige wird
damit bis zum Ende des lokalen Blocks unsichtbar.
Der Anweisungsteil entspricht dem eines Moduls. Er wird dann ausgeführt,
wenn die Prozedur aufgerufen wird. Es gibt keine automatische Initialisierung
von Prozeduren. Lokale Variable haben zu Beginn der Prozedur undefinierte
Werte und hören mit dem Ende der Prozedur auf zu existieren: die Lebensdauer
der lokalen Variablen endet mit der Ausführungsdauer der Prozedur.
Im Gegensatz dazu bleiben globale Variable eines Moduls erhalten, bis das
Modul explizit entladen wird.
Eine Prozedur kann durch eine RETURN-Anweisung verlassen werden. Eine Prozedur
kann mehr als eine RETURN-Anweisung enthalten. Prozeduren können einen
Ergebnistyp haben; man spricht dann von Funktionsprozeduren, zur Unterscheidung
von eigentlichen Prozeduren. Funktionsprozeduren müssen mit einer RETURN-Anweisung
verlassen werden. Bei Funktionsprozeduren muss auf die RETURN-Anweisung ein
Ausdruck folgen, der verträglich mit dem Ergebnistyp ist. Dieser Ausdruck
wird ausgewertet und das Ergebnis als Resultat der Funktionsprozedur übergeben.
RETURN-Anweisung
RETURN { Ausdruck }
Beispiel
PROCEDURE MIN(
a,b:REAL): REAL;
BEGIN
IF a<b THEN RETURN
a ELSE RETURN b END
END MIN;
Eine Prozedur kann auch in ihrem eigenen Anweisungsteil aufgerufen werden.
Dies führt dann zu einer Rekursion. Von der Schreibweise ist dies in
der Regel eine sehr kompakte Darstellung. Von der Ausführung bedeutet
ein Prozeduraufruf aber, dass Platz für lokale Variable bereitgestellt
werden muss, die Kontrolle an eine Kopie der Prozedur übergeben werden
muss, und eine gesicherte Rückkehr zur aufrufenden Kopie vorbereitet
werden muss. In der Regel ist dies aufwendiger, als eine sequentielle Ausführung
von Anweisungen. Wenn Rekursionen vermieden werden können, sollte dies
getan werden. Insbesondere kann eine Rekursion immer dann vermieden werden,
wenn sie durch die letzte Anweisung einer Anweisungsfolge ausgelöst
wird.
Übungen:
1.) In vielen Programmbibliotheken gibt es Prozeduren
zu Berechnung einer Potenzfunktion. Wie würden Sie eine Funktionsprozedur
XPwrI programmieren,
die für x>=0, i>=0 die Potenz
xi berechnet.
PROCEDURE XPwrI(x:LONGREAL; i:LONGINT):
LONGREAL;
2.) Schreiben Sie die drei Generatoren aus dem vorherigen Kapitel als Funktionsprozeduren
RandLGM, RandPRB, RandUNIX und testen Sie diese Prozeduren.
3a.) Schreiben Sie einen Pseudo-Zufallszahlengenerator, der eine uniforme
Verteilung auf [0,1] simuliert. Benutzen Sie dazu RandLGM. Implementieren
Sie diesen Generator als Funktionsprozedur.
3b.) Schreiben Sie eine Funktionsprozedur, die exponentialverteilte Pseudo-Zufallszahlen
erzeugt. Benutzen Sie dazu den Generator aus 3a. Die Rate soll dabei ein
Parameter der Funktionsprozedur sein.
4.) Programmieren Sie die Simulation einer einfachen Warteschlange mit exponentieller
Ankunfts- und Bedienzeit. Simulieren Sie dann den Ablauf für 20 Kunden
mit a) Ankuftsrate=Bedienrate; b) Ankuftsrate=Bedienrate/2.
5.) Programmieren Sie eine "Schönschreibprozedur", die -werteabhängig-
eine reelle Zahl in einem gut lesbaren Format ausschreibt. Beispiel:
Wert Ausgabe
0.0E0
0
1.2E1
12
1.2345E2 123.45
Falls Sie dazu mathematische Funktionen brauchen, finden Sie diese evtl.
im Modul Math. Hinweis: Sie sollten für diese Aufgabe einen Font mit
fester Zeichenbreite wählen.
Übungen:
Vergleichen Sie die beiden folgenden Implementierungen
der Fakultätsfunktion. Welchen Aufwand bedeuten sie?
PROCEDURE Fak1(i:INTEGER):LONGINT;
BEGIN
ASSERT(i>=0);
IF i<=1 THEN RETURN 1
ELSE RETURN i*Fak1(i-1)
END;
END Fak2;
PROCEDURE Fak2(i:INTEGER):LONGINT;
VAR res:LONGINT;
BEGIN
ASSERT(i>=0);
res:=1;
WHILE i>1 DO res:=res*i; DEC(i) END;
RETURN res
END Fak2;
Eine Reihe von Prozeduren sind in Oberon vordefiniert. Eine Liste
der vordefinierten Prozeduren finden Sie im Oberon-Report. Die nächste
Quelle sind exportierte Prozeduren in bereits vorhandenen Modulen. Nur der
letzte Ausweg ist, Prozeduren selbst neu zu schreiben.
Einführung in die Programmiersprache Oberon. Kurs/Kap07.Text
gs (c) G. Sawitzki, StatLab Heidelberg
<http://statlab.uni-heidelberg.de/projects/oberon/kurs/>
Home
Up
Intro
Contents
Chapter
1
2
3
4
5
6
7
8
9
10
Design
Assert
Timing
EBNF
Report
Pas