Ausgewählte Kapitel der Basic-Programmierung Teil 3: Strukturen und Prozeduren

100 'OMIKRON.Basic 
110 'Spagetti Version 
120 '
130 Kontostand=3000
140-Start
150 CLS
160 PRINT "Guten Tag"
170 PRINT "Ihr Kontostand beträgt ";Kontostand
180 INPUT "Wieviel Geld möchten Sie abheben ?";Geld
190 IF Kontostand-Geld<=0 THEN GOTO Nix_Abheben
200 FOR I=Kontostand TO Kontostand-Geld STEP -1
210 PRINT @(20,20);I;"   ": NEXTI
220 Kontostand=Kontostand-Geld: GOTO Ende
230-Nix_Abheben
240 PRINT "Soviel Geld haben Sie nicht"
250-Ende
260 INPUT "Wollen Sie noch etwas abheben ?";Antwort$
270 IF Antwort$="n" OR Antwort$="N" THEN
280 PRINT "Auf Wiedersehen": END ELSE GOTO Start ENDIF
290 '

Listing 1: Der berüchtigte Spaghetticode

Dieses Kapitel unserer zweimonatlichen Serie, stellt eines der wichtigsten im modernen Basic dar. Die Betonung liegt hierbei auf modern, denn ältere Basic Versionen haben davon wenig bis gar nichts zu bieten.

Struktur, was ist das eigentlich?

Im alltäglichen Leben ist dieser Begriff klar; eine Landschaftsstruktur beispielsweise stellt den Aufbau und die Gestalt der Landschaft dar. Beim Programmieren ist dies nicht viel anders. Auch ein Programm hat eine äußere Form, ein Gerüst, ein Aussehen. Dem Anwender eines Programmes mag dies völlig egal sein, Hauptsache es funktioniert. Der Programmierer hingegen denkt darüber anders. Ihm bedeutet die Form seines Programmes sehr viel, denn er muß es verstehen können. Dies verdeutlicht Beispiel 1 und 2. Man muß deutlich darauf hinweisen, daß beide Listings die gleiche Wirkung haben, aber schauen Sie doch einmal welches Programm man besser verstehen kann.

Versuchen Sie bitte, bevor Sie die nächsten Zeilen lesen, den Sinn von Listing 1 zu entschlüsseln, oder sollte man besser sagen 'zu erraten'.

Listing 2 zeigt eine andere Lösung. Sie ist wesentlich übersichtlicher und auch noch von anderen Programmierern zu lesen.

Beide Programme stellen eine Art Kontoverwaltung dar. Der Benutzer wird nach der Summe gefragt, die er abheben will. Ist nicht mehr genug Geld auf dem Konto, so rückt die Bank nichts raus. Ansonsten zählt der Rechner den Kontostand um den betreffenden Betrag herunter. Sie werden feststellen, daß das erste Listing ziemlich unübersichtlich ist. Wäre auf diese Art ein größeres Programm geschrieben, würde man sich hoffnungslos darin verstricken.

Ordnung ist das...

Zu den einzelnen Formen der Strukturierung möchten wir nicht vergessen eine Möglichkeit aufzuzeigen, um Programmteile auf dem Papier darzustellen. Dies hat mehrere Gründe.

100 ' OMIKRON.Basic 
110 '
120 Kontostand=3000 
130 '
140 REPEAT 
150		CLS
160		PRINT "Guten Tag"
170		PRINT "Ihr Kontostand	beträgt	";Kontostand
180		INPUT "Wieviel möchten Sie abheben?";Geld
190		IF Kontostand-Geld>=0 THEN
200 		FOR I=Kontostand TO Kontostand-Geld STEP -1 
210 			PRINT @(20,20);I;"	"
220			NEXT I
230			Kontostand=Kontostand-Geld
240		ELSE
250 		PRINT " Soviel Geld haben Sie nicht mehr !"
260		ENDIF
270 	INPUT "Wollen Sie noch etwas abheben ? [j|n]";Antwort$
280 UNTIL Antwort$="n" OR Antwort$="N"
290 PRINT "Auf Wiedersehen"
300 '
310 END

Listing 2: So sieht es schon besser aus

Bei der Programmierung sollte man generell versuchen sein Programm, sei es auch noch so lang, in einzelne, kleinere Unterprogramm zu unterteilen. Erstens kann man solche Unterprogramme mehrfach, von verschiedenen Stellen des Programms aufrufen und spart sich somit das mehrfache Schreiben gleicher Programmteile, zweitens wird ein Programm sofort übersichtlicher, wenn man es in Einzelprobleme aufteilt. Solche Unterprogramme kann man dann so universell gestalten, daß man sie auch in anderen Programmen verwenden kann, also der erste Schritt in Richtung modularer Programmierung.

Erst aufs Papier

Bei der Entwicklung komplizierterer Programme wird ein jeder feststellen, daß man dieses nicht einfach so schreiben kann. Dazu ist meist die Entwicklung auf dem Papier der eigentlichen Programmierung vorangestellt. Dazu gibt es mehrere Möglichkeiten. Für höhere Programmiersprachen ist das Nassi-Shneidermann Diagramm, kurz Struktogramm genannt, am geeignetsten, bei Assembler ein Flußdiagramm.

Das Struktogramm

Beginnen wir ganz einfach. Ein Programm wie das in Listing 3 besteht nur aus einer Reihe von fortlaufenden Befehlen, die der Reihe nach, also von oben nach unten abgearbeitet werden. In einem Struktogramm sieht das folgendermaßen aus (Bild 1). Jeder Kasten stellt einen Befehl, bzw. eine Anweisungsgruppe dar.

Wichtig ist, daß in solchen Diagrammen natürlich keine Basicsyntax stehen muß, sondern eher Klartext, z. B. 'Eingabe Wert' statt 'INPUT A'. Dies ist äußerst praktisch, da man dann ein Struktogramm ohne Probleme in verschiedenen Hochsprachen umsetzen kann, also egal ob Pascal, Modula-2, Basic oder C.

Bild 1: mehrere Anweisungen hintereinander
100 ' Beispiel ohne Schleifen 
110 '
120 INPUT "Gib zwei Zahlen ein:	";A,B
130 C=A+B
140 PRINT A;" +";B;" +";" =";C
150 '
160 END

Listing 3: Ein einfaches Programm ohne Schleifen

Wiederhole bis Bedingung

Aber kommen wir zurück zu weiteren Formen des Struktogramms. Da wäre zunächst eine Schleife - genannt die REPEAT UNTIL-Schleife. Sie wiederholt einen Programmblock, also mehrere zusammenhängende Befehle, solange, bis eine Bedingung erfüllt ist.

REPEAT
	Anweisung 1 
	Anweisung 2 
	Anweisung 3 
UNTIL Bedingung
Bild 2: REPEAT...UNTIL, Wiederhole bis Ende

Im Struktogramm ist dies wie in Bild 2 gekennzeichnet. Der Basic-Interpre-ter läuft zunächst in die Schleife hinein, führt die Anweisungen aus und trifft dann die Entscheidung, ob er wieder zum Schleifenanfang (vor Anweisung 1) verzweigen, oder die Schleife verlassen soll. Man spricht deshalb auch von einer nichtabweisenden Schleife. Im Beispiel hierzu (Listing 4) werden per Zufall Rechtecke mit wechselnden Füllmustern gezeichnet, und zwar solange, bis irgendeine Taste gedrückt wurde.

Bild 3: WHILE...WEND, Wenn Bedingung dann Wiederhole

Wenn Bedingung dann Wiederhole

Die nächste Schleife ist prinzipiell sehr ähnlich, nur prüft sie bereits am Anfang, ob die Bedingung erfüllt ist und läuft nur dann in den Programmblock innerhalb der Schleife hinein. Ist die Bedingung nicht erfüllt, so wird das Programm hinter dem Blockende fortgesetzt. Der Name 'WHILE WEND'. Das zugehörige Struktogramm sehen Sie in Bild 3.

WHILE Bedingung 
	Anweisung 1 
	Anweisung 2 
	Anweisung 3 
WEND

Auch wenn diese Schleifen ähnlich erschienen, so ist der Unterschied doch sehr wichtig (siehe Listing 5 und 5a).

100 ' Beispiel REPEAT UNTIL 
110 ' OMIKRON. Basic 
120 '
130 REPEAT
140		'	Hauptprogramm
150 	FILL STYLE =2, RND(20)+1
160 	PBOX RND(400), RND(200), RND(200)+1, RND(200)+1 
170 UNTIL INKEY$ <>""
180

Listing 4: Zeichne bis Tastendruck in OMIKRON

' Beispiel REPEAT UNTIL 
' GFA Basic
'
Repeat
	' Hauptprogramm 
	Deffill ,2,Random(20)+1 
	X1=Random(400) 
	Y1=Random(400)
	X2=Random(600)+1 
	Y2=Random(400)+1 
	Pbox X1,Y1,X2,Y2
Until Inkey$<>""

Listing 4a: Zeichne bis Tastendruck in GFA

100 ' WHILE WEND 
110 ' OMIKRON. Basic 
120 '
130 Pfad$="\*.*": MOUSEON 
140 FILESELECT (Pfad$,Name$,Ok)
150 IF Ok THEN
160 	OPEN "I",1,Name$
170		WHILE NOT E0F(1)
180			A$= INPUT$(1,1)
190			PRINT A$;
200			REM LPRINT A$;'Auf Drucker
210 	WEND 
220 ENDIF 
230

Listing 5: Der Filegucker in OMIKRON

' WHILE WEND 
' GFA Basic
'
Fileselect "*.*","",Name$
If Exist(Name$) Then 
	Open "I",#1,Name$
	While Not Eof(#1) 
		A$=Input$(1,#1)
		Print A$;
		Rem LPRINT A$;'Auf Drucker 
	Wend
Endif

Listing 5a: Der Filegucker in GFA

In diesem Beispiel wird zunächst mittels der Fileselectorbox ein File angewählt. Dieses File, welches zweckmäßigerweise ein Textfile sein sollte, wird sodann geöffnet und Buchstabe für Buchstabe gelesen und gleich wieder auf den Bildschirm ausgegeben. Hat man einen Drucker, so kann man das File auch sofort auf den Drucker geben. Aber zurück zur WHILE WEND Schleife. Sie ist in diesem Fall sehr wichtig, da Sie mit Hilfe der EOF (End Of File) Funktion erkennt, ob das File schon zu Ende ist oder man noch ein Zeichen lesen kann. Ist noch ein Zeichen zu lesen, so wird die Schleife durchlaufen und, wie oben beschrieben, ein von Diskette gelesenes Zeichen auf den Bildschirm gedruckt. Ist man bereits an das Fileende gekommen, so wird die Schleife umgangen. Wichtig ist dies, da ansonsten das Programm mit einer Fehlermeldung abbrechen würde. Wo nichts ist, kann man auch nichts lesen.

Von Bis

Eine spezielle Form der Schleife ist die FOR NEXT-Schleife. Sie sorgt dafür, daß ein Programmblock eine, vorgegebene Anzahl mal durchlaufen wird. Sie ist die sogenannte Urbasic Schleife, die schon seit Geburt der Sprache Basic darin enthalten ist.

FOR Variable = Startwert TO Endwert 
	Anweisung 1 
	Anweisung 2 
	Anweisung 3 
NEXT Variable

Ein kleines Beispiel:

For I= 1 To 10 
	Print I 
Next I

Eine Variable, in diesem Fall I, wird als Kontrollvariable benutzt. Sie bekommt einen Startwert und zählt diesen bis zum Endwert hoch und zwar standardmäßig um Eins. Benötigt man eine andere Schrittweite, so kann man diese optional verändern, z. B.:

For I= 1 To 10 Step 3

oder

For Zaehler=10 To 9 Step -0.33

Im ersten Beispiel bekommt die Variable T den Wert 1 und wird bei jedem Durchlauf um 3 erhöht. Sie nimmt also die Werte '1,4,7,10' an.

Im zweiten Beispiel wird eine andere Variable verwendet 'Zaehler'. Sie erhält den Startwert 10 und zählt bei jedem Durchlauf um exakt 0,33 herunter. Sie nimmt folglich die Werte '10, 9.67, 9.34, 9.01' an. Weiter herunter zählt sie nicht mehr, da der nächste Wert '8.68' schon kleiner als '9' ist.

In Listing 6 sehen Sie zwei ineinander geschachtelte FOR...NEXT-Schleifen.

Erst wenn die Innere durchlaufen ist (hier von Spalte = 1... 15) springt der Interpreter wieder in die Außere und erhöht die dortige Variable (Reihe). Auf diese Art wird eine einfache Multiplikationstabelle auf dem Bildschirm ausgegeben. Vielleicht versucht sich jemand einmal an einer Logarithmentabelle.

'Beispiel For..Next 
' GFA. Basic
'
Cls
Print Tab(30);"Multiplikationstabelle"
'
For Reihe=1 To 15 
	For Spalte=1 To 15
		Print At(5+Spalte*4,2+Reihe);
		Print Using "####",Reihe*Spalte 
	Next Spalte 
Next Reihe

Listing 6a: Das 1x1 in GFA

100 ' Beispiel For..Next 
110 ' OMIKRON. Basic 
120 '
130 CLS
140 PRINT TAB (30);"Multiplikationstabelle"
150 '
160 FOR Reihe=1 TO 15 
170 	FOR Spalte=1 TO 15
180 		PRINT @(2+Reihe,5+Spalte*4); USING "####";Reihe*Spalte 
190 	NEXT Spalte 
200 NEXT Reihe 
210 HCOPY TEXT
220 LPRINT CHR$(10); CHR$(10); CHR$(10)
230 LLIST

Listing 6: Das 1x1 in OMIKRON

Abweisend oder nicht?

Jetzt ist es wieder einmal soweit. Unsere zwei Interpreter GFA- und OMIKRON. zeigen unterschiedliches Verhalten. Während OMIKRON.Basic eine abweisende FOR NEXT-Schleife enthält, zeigt sie sich bei GFA-Ba-sic nichtabweisend. Im Klartext heißt das: in GFA-Basic wird eine FOR NEXT Schleife immer mindestens einmal durchlaufen, egal, ob die Endbedingung schon überschritten ist oder nicht. Darauf muß man im Einzelfall achten, da das Programm sonst leicht Fehler verursacht.

Ein Beispiel:

Start = 7 
Ende = 5
For I= Start To Ende 
	Print I 
Next I
Bild 4: So sieht die Tabelle aus

Obwohl der Endwert schon überschritten ist, läuft GFA-Basic in die Schleife hinein und führt die Befehle darin aus, ob die Bedingung erfüllt war oder nicht.

OMIKRON.Basic kümmert sich selbst darum und läuft nur wenn es soll.

Wenn dann ansonsten

Ein anderes Bestandteil der strukturierten Programmierung ist die 'IF THEN ELSE' Abfrage. Die direkte Übersetzung 'WENN DANN ANSONSTEN' sagt schon viel über den Zweck aus.

IF Bedingung Then 
	Anweisung A1 
	Anweisung A2
	...
ELSE 
	Anweisung B1 
	Anweisung B2
	...
ENDIF

Im Struktogramm wird dies noch deutlicher (siehe Bild 5). Wenn die Bedingung erfüllt ist, verzweigt das Programm in Block A, ansonsten in Block B. Auch hier wird das Struktogramm immer von oben nach unten durchlaufen. Ein Sprung nach oben ist nicht möglich. Benötigt man den ELSE-Block nicht, so läßt man ihn einfach weg, und der Platz innerhalb Block B bleibt leer.

Ein weiteres Beispiel (Listing 7) zeigt zwei IF-Abfragen, die wiederum von einer REPEAT...UNTIL-Schleife umgeben sind. Hört sich kompliziert an, doch das Listing überzeugt vom Gegenteil. Es handelt sich hierbei um ein einfaches Malprogramm, welches bei gedrückter linker Maustaste auf dem Bildschirm zeichnet und bei gedrückter linker Maustaste auf dem Bildschirm löscht.

Wie man in Listing 1+2 sehen kann, tut das Einrücken innerhalb der Schleifen der Lesbarkeit der Programme unheimlich gut. GFA-Basic rückt ja bekanntlich automatisch ein. Der Anfänger wird dies zu schätzen wissen, da er Fehler leichter findet und alles gleich ordentlich aussieht. Allerdings hat dies zur Folge, daß nur noch ein Befehl in jeder Zeile stehen darf. Das führt dazu, daß jede Befehlsfolge, egal ob sinnvoll oder nicht in viele Zeilen aufgeteilt werden muß. Das Programm geht somit in die Länge und der Programmiererfreiheit ist Einhalt geboten. Aber jedem das Seine.

~~~~~~~~~~~~~~~~~~~~~ ' The Minimum Painter ' GFA Basic Repeat If Mousek=1 Then Deffill 1 Pbox Mousex,Mousey,Mousex+4,Mousey+4 Endif If Mousek=2 Then Deffill 0 Pbox Mousex,Mousey,Mousex+4,Mousey+4 Endif Until Mousek=3 ~~~~~~~~~~~~~~~~~~~~~

Listing 7a: Der Minimum Painter in GFA

' The Minimum Painter 
' OMIKRON. Basic 
REPEAT
	IF MOUSEBUT =1 THEN FILL COLOR =1: MOUSEOFF : PBOX MOUSEX, MOUSEY ,4,4 
	IF MOUSEBUT =2 THEN FILL COLOR =0: MOUSEOFF : PBOX MOUSEX, MOUSEY ,4,4 
	MOUSEON 
UNTIL MOUSEBUT =3

Listing 7: Der Minimum Painter in OMIKRON

Endlos schleifen

GFA-Basic bietet noch eine weitere Schleifenvariante, die spezielle Endlosschleife.

DO
	Anweisung 1 
	Anweisung 1
	...
	Anweisung n 
LOOP
Bild 5: IF...THEN...ELSE, die Fallabfrage

Der Block (Anweisung 1 bis Anweisung n) wird unendlich oft wiederholt. In OMIKRON Basic existiert sie nicht, läßt sich das leicht mit einer der anderen Schleifen imitieren.

REPEAT
	Anweisung 1 
	Anweisung 2
	...
	...
	Anweisung n 
Until 0

oder etwas verständlicher ausgedrückt

REPEAT
...
...
UNTIL immer_und_ewig

'immer_und__ewig' ist in diesem Fall eine Variable, die, da sie wohl kaum benutzt wird, den Wert Null enthält.

Bild 6: Der Minimum Painter im Struktogramm

Alles zusammen

Nun wollen wir einmal ein komplexeres Programm schreiben, welches mehrere der eben besprochenen Schleifentypen beinhaltet (siehe Listing 8).

Das Programm zerlegt eine Zahl in seine Primfaktoren, also in Zahlen, die sich durch keine anderen mehr teilen lassen. Der Aufbau im Struktogramm ist in Bild 8 zu sehen. Auch wenn es etwas länger ist, so erkennt man doch den Zusammenhang zwischen dem Programm im Rechner und auf dem Papier.

  *** Primfaktorzerlegung *** 
  Bitte geben Sie eine Zahl ein 
? 653426

 653426 =	2 * 239	* 1367

Weiter [J/N]

Bild 7: So wird eine Zahl in Primfaktoren zerlegt

Man sieht: Erst jetzt kommen die Vorzüge des Struktogramms zum Vorschein. Bei der Umsetzung geht man einfach der Reihe nach vor, von oben nach unten versteht sich.

Vergleichen Sie doch einfach das Struktogramm mit dem Listing oder versuchen Sie es doch selbst einmal umzusetzen.

~~~~~~~~~~~~~~~~~~~~~ ' Beispiel Primfaktorzerlegung ' OMIKRON, und GFA Basic ' keine Unterschiede While Upper$(Antwort$)<>"N" Cls Print " *** Primfaktorzerlegung ***" Print " Bitte geben Sie eine Zahl ein " Input Prim Print Print Prim;" = "; While Prim>1 Teiler=2 While Prim Mod Teiler<>0 Teiler=Teiler+1 Wend ' If Prim=Teiler Then Print Teiler Else Print Teiler;" * "; Endif ' Prim=Prim/Teiler Wend Print Print "Weiter [J/N]" Antwort$=Input$(1) Wend ~~~~~~~~~~~~~~~~~~~~~

Listing 8: Primzahlenzerlegung ohne Kopfzerbrechen

Kombination

Wie schon in den letzten Listings zu sehen war, werden natürlich immer viele dieser Strukturelemente in einem Programm benötigt. Zwar kann man einige durch programmiertechnische Verrenkungen ersetzen, doch sollte man darauf lieber verzichten, da sonst der berüchtigte Spaghetticode entsteht.

Als Fazit wäre anzumerken, daß mit solchen Fähigkeiten das Programmieren in Basic wieder Spaß macht. Man sollte versuchen, alle diese angebotenen Möglichkeiten zu nutzen, denn diese bekommt man ansonsten nur in Sprachen wie PASCAL, C oder MODULA 2 geboten.

HS + MM

Bild 8: Das Struktogramm zur Primfaktorzerlegung


Aus: ST-Computer 11 / 1987, Seite 98

Links

Copyright-Bestimmungen: siehe Über diese Seite