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.
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.
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.
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.
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.
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
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
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.
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.
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
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
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.
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.
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
GFA-Basic bietet noch eine weitere Schleifenvariante, die spezielle Endlosschleife.
DO
Anweisung 1
Anweisung 1
...
Anweisung n
LOOP
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.
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.
Listing 8: Primzahlenzerlegung ohne Kopfzerbrechen
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