Bei längeren Programmen kann es sinnvoll sein, diese in mehrere, übersichtliche Teile zu gliedern. Dieses Vorgehen kann auch dann Vorteile bringen, wenn eine Anweisungsfolge mehrfach in einem Programm auftritt.
Am Beispiel eines Hauses, das mit ColorPlane erstellt wurde, soll das Prinzip erläutert werden. Betrachte den Quelltext und überlege, welche Programmteile welchen Teilen des Hauses entsprechen!
MODULE Haus; IMPORT C:=ColorPlane; PROCEDURE ProgMain*; VAR ch: CHAR; i: INTEGER; BEGIN C. Open(); C. SetForeColor (200,200,255); C. Bar (100,100, 200,200,1); C. SetBackColor (255,255,255); C. SetForeColor (0,0,0); C. Bar (120,130,140,150,0); C. Box (120,130,140,150,1); C. Bar (120,170,140,190,0); C. Box (120,170,140,190,1); C. Bar (160,170,180,190,0); C. Box (160,170,180,190,1); C. Bar (160,100,180,150,0); C. Box (160,100,180,150,1); C. SetForeColor (255,0,0); FOR i:=1 TO 100 DO C. Line (100+i DIV 2,200+i,200-i DIV 2,200+i,1); END; ch:=C. ReadKey(); END ProgMain; END Haus. |
Der blau markierte Teil entspricht der hellblauen Front des Hauses. Der schwarze Abschnitt in der Mitte lässt die Fenster zeichnen. Im roten Teil wird das Dach vereinbart (Dabei berechnet i DIV 2 den ganzzahligen Anteil bei der Division von i durch 2, z.B. 1 DIV 2=0, 2 DIV 2 = 1, 3 DIV 2 = 1, 101 DIV 2 = 50).
Ohne die Gestalt des Hauses zu verändern, könnte man diese drei Teile aus dem Hauptprogramm (ProgMain) herauslösen, um so die Übersicht zu erhöhen. Man deklariert dazu drei Unterprogramme (Prozeduren) UntererTeil, Fenster, Dach, die die entsprechenden Teile enthalten. In der Hauptprozedur werden dann die entsprechenden Unterprogramme aufgerufen:
MODULE Haus; IMPORT C:=ColorPlane; PROCEDURE UntererTeil; BEGIN C. SetForeColor (200,200,255); C. Bar (100,100, 200,200,1); END UntererTeil; PROCEDURE Fenster; BEGIN C. SetBackColor (255,255,255); C. SetForeColor (0,0,0); C. Bar (120,130,140,150,0); C. Box (120,130,140,150,1); C. Bar (120,170,140,190,0); C. Box (120,170,140,190,1); C. Bar (160,170,180,190,0); C. Box (160,170,180,190,1); C. Bar (160,100,180,150,0); C. Box (160,100,180,150,1); END Fenster; PROCEDURE Dach; VAR i:INTEGER; BEGIN C. SetForeColor (255,0,0); FOR i:=1 TO 100 DO C. Line (100+i DIV 2,200+i,200-i DIV 2,200+i,1); END; END Dach; PROCEDURE ProgMain*; |
Nun soll das Programm so erweitert werden, dass es in der Lage ist, Häuser in beliebiger Größe und an beliebiger Stelle zu zeichnen - man benötigt dafür geeignete Variablen. Da das Programm nun in mehrere Teile zerteilt ist, muss man darauf achten, dass alle Prozeduren die entsprechenden Werte erhalten und geeignet anwenden.
Man führt die Variablen groesse (gemeint ist die Seitenlänge des großen
Quadrats), xpos (x-Wert der linken unteren Ecke des Hauses) und ypos ein und
verändert das Programm entsprechend. Bemerkenswert ist hier die Position, an
der diese Variablen zu deklarieren sind: Geschieht dies am Anfang der Prozedur
"ProgMain" oder einer anderen Prozedur, so stehen sie nur innerhalb
dieser Prozedur zur Verfügung, es handelt sich dann um lokale Variable !
Um sie für alle Prozeduren des Moduls gleichermaßen verfügbar zu machen, muss
man sie vor der ersten Prozedur deklarieren; man nennt sie dann globale
Variable.
MODULE Haus;
IMPORT C:=ColorPlane;
VAR xpos, ypos, groesse:INTEGER;
(*Hier sind xpos, ypos und groesse GLOBAL
DEKLARIERT*)
PROCEDURE UntererTeil;
BEGIN
C.SetForeColor (200, 200, 255);
C. Bar (xpos,ypos,xpos+groesse,ypos+groesse,1);
END UntererTeil;
PROCEDURE Fenster;
BEGIN
C. SetBackColor (255,255,255);
C. SetForeColor (0,0,0);
C. Bar (xpos+(groesse*20) DIV 100 ,ypos+(groesse*30) DIV 100,xpos+(groesse*40) DIV 100,ypos+(groesse*50) DIV 100,0);
C. Box (xpos+(groesse*20) DIV 100 ,ypos+(groesse*30) DIV 100,xpos+(groesse*40) DIV 100,ypos+(groesse*50) DIV 100,1);
C. Bar (xpos+(groesse*20) DIV 100,ypos+(groesse*70) DIV 100,xpos+(groesse*40) DIV 100,ypos+(groesse*90) DIV 100,0);
C. Box (xpos+(groesse*20) DIV 100,ypos+(groesse*70) DIV 100,xpos+(groesse*40) DIV 100,ypos+(groesse*90) DIV 100,1);
C. Bar (xpos+(groesse*60) DIV 100,ypos+(groesse*70) DIV 100,xpos+(groesse*80) DIV 100,ypos+(groesse*90) DIV 100,0);
C. Box (xpos+(groesse*60) DIV 100,ypos+(groesse*70) DIV 100,xpos+(groesse*80) DIV 100,ypos+(groesse*90) DIV 100,1);
C. Bar (xpos+(groesse*60) DIV 100,ypos,xpos+(groesse*80) DIV 100,ypos+(groesse*50) DIV 100,0);
C. Box (xpos+(groesse*60) DIV 100,ypos,xpos+(groesse*80) DIV 100,ypos+(groesse*50) DIV 100,1);
END Fenster;
PROCEDURE Dach;
VAR i:INTEGER;
BEGIN
C. SetForeColor (255,0,0);
FOR i:=1 TO groesse DO
C. Line (xpos+i DIV 2,ypos+groesse+i,xpos+groesse-i DIV 2,ypos+groesse+i,1);
END;
END Dach;
PROCEDURE ProgMain*;
VAR ch: CHAR; (* xpos, ypos, groesse:INTEGER;
Hier wären xpos, ypos und groesse LOKAL DEKLARIERT, wodurch sie die anderen
Prozeduren nicht nutzen könnten*)
BEGIN
xpos:=100; ypos:=100; groesse:=100; (*Die
Werte könnten natürlich auch vom Benutzer eingegeben werden*)
C. Open();
UntererTeil;
Fenster;
Dach;
ch:=C. ReadKey();
END ProgMain;
END Haus.
Wenn man alle Variablen global deklariert, verschlechtert man wieder die Übersicht, die man mit den Unterprogrammen erzielen wollte; sie sollten ja gerade das Programm in kompakte, durchschaubare Abschnitte gliedern. Die Variablen sollten nur dann global deklariert werden, wenn sie wirklich von allen Prozeduren benötigt werden und auch verändert werden müssen.
Wenn globale Variablen nur dann eingesetzt werden sollen, wenn alle
Prozeduren darauf zugreifen, benötigt man noch eine zusätzliche Struktur, die
es erlaubt, EINZELNEN Prozeduren Werte mitzuteilen. Dies erfolgt durch die
Verwendung von Parametern.
MODULE strasse;
IMPORT ColorPlane;
PROCEDURE UntererTeil (re:INTEGER;ho:INTEGER;gr:INTEGER);
VAR j:INTEGER;
BEGIN
j:=1;
ColorPlane. SetForeColor (200,200,255);
ColorPlane. Bar (re,ho, re+gr,ho+gr,1);
END UntererTeil;
PROCEDURE Fenster(re:INTEGER;ho:INTEGER;gr:INTEGER);
BEGIN
ColorPlane. SetBackColor (255,255,255);
ColorPlane. SetForeColor (0,0,0);
ColorPlane. Bar (re+(gr*20) DIV 100,ho+(gr*30) DIV 100,re+(gr*40) DIV 100,ho+(gr*50) DIV 100,0);
ColorPlane. Box (re+(gr*20) DIV 100,ho+(gr*30) DIV 100,re+(gr*40) DIV 100,ho+(gr*50) DIV 100,1);
ColorPlane. Bar (re+(gr*20) DIV 100,ho+(gr*70) DIV 100,re+(gr*40) DIV 100,ho+(gr*90) DIV 100,0);
ColorPlane. Box (re+(gr*20) DIV 100,ho+(gr*70) DIV 100,re+(gr*40) DIV 100,ho+(gr*90) DIV 100,1);
ColorPlane. Bar (re+(gr*60) DIV 100,ho+(gr*70) DIV 100,re+(gr*80) DIV 100,ho+(gr*90) DIV 100,0);
ColorPlane. Box (re+(gr*60) DIV 100,ho+(gr*70) DIV 100,re+(gr*80) DIV 100,ho+(gr*90) DIV 100,1);
ColorPlane. Bar (re+(gr*60) DIV 100,ho,re+(gr*80) DIV 100,ho+(gr*50) DIV 100,0);
ColorPlane. Box (re+(gr*60) DIV 100,ho,re+(gr*80) DIV 100,ho+(gr*50) DIV 100,1);
END Fenster;
PROCEDURE Dach(re:INTEGER;ho:INTEGER;gr:INTEGER);
VAR i:INTEGER;
BEGIN
ColorPlane. SetForeColor (255,0,0);
FOR i:=1 TO gr DO
ColorPlane. Line (re+i DIV 2,ho+gr+i,re+gr-i DIV 2,ho+gr+i,1);
END;
END Dach;
PROCEDURE haus (rechtswert:INTEGER;hochwert:INTEGER;gross:INTEGER);
BEGIN
UntererTeil(rechtswert,hochwert,gross);
Fenster(rechtswert,hochwert,gross);
Dach(rechtswert,hochwert,gross);
END haus;
PROCEDURE ProgMain*;
VAR ch: CHAR;
BEGIN
ColorPlane. Open();
haus (100,100,100);
haus (200,200,50);
haus (250,250,25);
haus (275,275,12);
ch:=ColorPlane. ReadKey();
END ProgMain; END strasse.
Die Prozeduren erhalten hier von den Prozeduren, in denen sie aufgerufen
werden, Werte. Bei der Deklaration der Prozedur haus erkennt man, dass dafür
drei Platzhalter (rechtswert:INTEGER;hochwert:INTEGER;gross:INTEGER) vom Typ
INTEGER bereitgestellt werden (formale Parameter). In der Prozedur
ProgMain wird die Prozedur haus mehrmals mit unterschiedlichen Werten (aktuelle
Parameter) aufgerufen.
Manchmal kann es nützlich sein, wenn ein Unterprogramm, die Parameter, die es erhält, auch in der übergeordneten Prozedur verändern kann, d.h. die aktuellen Parameter sind variabel. Im folgenden Beispiel berechnet die Prozedur haus am Ende die neuen Werte für das nachfolgende haus. Dies wird gekennzeichnet durch ein VAR vor der Deklaration des Parameters.
MODULE strasse;
IMPORT ColorPlane;
PROCEDURE UntererTeil (re:INTEGER;ho:INTEGER;gr:INTEGER);
VAR j:INTEGER;
BEGIN
j:=1;
ColorPlane. SetForeColor (200,200,255);
ColorPlane. Bar (re,ho, re+gr,ho+gr,1);
END UntererTeil;
PROCEDURE Fenster(re:INTEGER;ho:INTEGER;gr:INTEGER);
BEGIN
ColorPlane. SetBackColor (255,255,255);
ColorPlane. SetForeColor (0,0,0);
ColorPlane. Bar (re+(gr*20) DIV 100,ho+(gr*30) DIV 100,re+(gr*40) DIV 100,ho+(gr*50) DIV 100,0);
ColorPlane. Box (re+(gr*20) DIV 100,ho+(gr*30) DIV 100,re+(gr*40) DIV 100,ho+(gr*50) DIV 100,1);
ColorPlane. Bar (re+(gr*20) DIV 100,ho+(gr*70) DIV 100,re+(gr*40) DIV 100,ho+(gr*90) DIV 100,0);
ColorPlane. Box (re+(gr*20) DIV 100,ho+(gr*70) DIV 100,re+(gr*40) DIV 100,ho+(gr*90) DIV 100,1);
ColorPlane. Bar (re+(gr*60) DIV 100,ho+(gr*70) DIV 100,re+(gr*80) DIV 100,ho+(gr*90) DIV 100,0);
ColorPlane. Box (re+(gr*60) DIV 100,ho+(gr*70) DIV 100,re+(gr*80) DIV 100,ho+(gr*90) DIV 100,1);
ColorPlane. Bar (re+(gr*60) DIV 100,ho,re+(gr*80) DIV 100,ho+(gr*50) DIV 100,0);
ColorPlane. Box (re+(gr*60) DIV 100,ho,re+(gr*80) DIV 100,ho+(gr*50) DIV 100,1);
END Fenster;
PROCEDURE Dach(re:INTEGER;ho:INTEGER;gr:INTEGER);
VAR i:INTEGER;
BEGIN
ColorPlane. SetForeColor (255,0,0);
FOR i:=1 TO gr DO
ColorPlane. Line (re+i DIV 2,ho+gr+i,re+gr-i DIV 2,ho+gr+i,1);
END;
END Dach;
PROCEDURE haus (VAR rechtswert:INTEGER;VAR hochwert:INTEGER;VAR gross:INTEGER);
BEGIN
UntererTeil(rechtswert,hochwert,gross);
Fenster(rechtswert,hochwert,gross);
Dach(rechtswert,hochwert,gross);
rechtswert:=rechtswert+gross;
hochwert:=hochwert+gross;
gross:=gross DIV 2;
END haus;
PROCEDURE ProgMain*;
VAR ch: CHAR;x,y,g:INTEGER;
BEGIN
ColorPlane. Open();
x:=100; y:=100; g:=100;
REPEAT hausi (x,y,g) UNTIL g<=1;
ch:=ColorPlane. ReadKey();
END ProgMain; END strasse.