Das Schneider CPC Systembuch

Grundlagen

Programmstrukturen

So verschieden die einzelnen Programmiersprachen auch sind, so gibt es doch einige grundlegende Iterationen - Schleifen: StrukturStrukturen, die fast allen gemein sind. Dabei kann man den Befehlsumfang eines Interpreters, Compilers oder Assemblers grob in drei Gruppen einteilen:

Die 'Aktionen' umfassen alle Befehle, die 'etwas bewirken', wie etwa 'PRINT', 'PLOT' oder Wertzuweisungen wie 'LET'.

'Steueranweisungen' sind Befehle, die normalerweise die Programm-Ausführung nicht beeinflussen, wie beispielsweise 'TRON' und 'TROFF' zur Fehlersuche in Einleitung: BASIC
Anhang: Basic
Basic
oder 'ORG', der Befehl, der in fast allen Assemblern die Startadresse für den zu generierenden Maschinencode festlegt.

Unter dem Begriff 'Grundlagen: ProgrammstrukturenProgrammstrukturen' werden all die Befehle zusammengefasst, die den Ablauf eines Programmes verändern. Ein Programm, das nur aus strukturierenden Befehlen besteht, würde genau nichts bewirken. Die Iterationen - Schleifen: StrukturStrukturen verändern aber das lineare Ablaufen des Programmes und bestimmen so die Reihenfolge, in der die Aktionen abgearbeitet werden. Beispiele sind 'GOTO', 'GOSUB', 'WHILE-WEND' etc.

Verzweigungen - der einfache Sprung

Die einfachste Iterationen - Schleifen: StrukturStruktur überhaupt, die fast jede Sprache bereithält, ist der Sprung.

Normalerweise wird der Programmtext Befehl für Befehl abgearbeitet. Dafür benutzt die Befehlshol-Einheit des Mikroprozessors oder des Basic-Interpreters einen Zeiger. Der Zeiger zeigt auf einen Befehl, der Befehl wird eingelesen und der Zeiger weitergestellt. Dann wird der Befehl bearbeitet. Dieser Zyklus läuft, mit geringen Variationen, immer wieder gleich ab:

  • angezeigten Befehl einlesen
  • Zeiger weiterstellen
  • Befehl ausführen

Beim Sprungbefehl wird der Befehls-Zeiger in der Befehls-Ausführphase auf die angegebene Stelle eingestellt. Er wird mit einer neuen Adresse geladen. In Einleitung: BASIC
Anhang: Basic
Basic
muss man dafür Zeilennummern angeben, in Assembler Speicheradressen, die aber fast ausschließlich mit symbolischen Name, den sogenannten Label bezeichnet werden:

Einleitung: BASIC
Anhang: Basic
Basic
: Assembler: ----------- oder: ------------------------- 50 GOTO 100 #BF00 LABEL1: JP LABEL2

Mit solchen unbedingten Sprüngen (unbedingt = ohne Bedingung) kann man aber nur endlose Schleifen bilden (indem man immer wieder zurückspringt) oder zwei Programmpfade zusammenführen:

Endlos-Schleife             Zusammenführen von Programmpfaden:
---------------             -----------------------------------
50 PRINT "#";      oder:    50 LET C=100+250 : REM Berechnung 1
60 GOTO 50                  60 GOTO 80
                            70 LET C=125+175 : REM Berechnung 2
                            75 '
                            80 PRINT C       : REM Gemeinsame Druckroutine
                            90 END

Man kann eine Verzweigung aber auch an eine Bedingung knuepfen und spricht dann vom bedingten Sprung. Hiermit sind prinzipiell bereits alle Probleme loesbar. Beispielsweise kann man so Schleifen mit Abbruchkriterium herstellen:

100 LET I=1                   oder:    ZAEHLE: LD   Operationen: BD5B / 349A / 349A:  FLO SUBA,1
110 PRINT I                            Z1:     PUSH AF
120 LET I=I+1                                  Maschinencode über HIMEM: CALLCALL PRINT
130 IF I<25 THEN GOTO 110                      POP  AF
140 STOP                                       INC  Operationen: BD5B / 349A / 349A:  FLO SUBA
                                               CP   25
                                               JR   C,Z1
                                               RET

Bedingte Bearbeitung von Befehlen

Die einfachen Sprungbefehle gehören in der Informatik so mit zum Unbeliebtesten, was man sich denken kann. Mit ihrer Hilfe ist es nämlich möglich, ein Programm völlig unverständlich zu gestalten: Sprung hierhin, dahin, dorthin. Keiner weiß Bescheid.

Jede höhere Sprache stellt deshalb Strukturierungsmittel bereit, die sich zwar alle auf bedingte Sprünge zurückführen lassen, bei denen aber Sinn und Zweck der Verzweigungen offensichtlicher wird.

Einleitung: BASIC
Anhang: Basic
Basic
kennt sogar überhaupt keinen echten, bedingten Sprung. Im obigen Beispiel wurde der nur mit Hilfe eines Basic-typischen Strukturierungs-Mittels simuliert. Mit den Befehlen IF, THEN und ELSE lassen sich Programmteile nur dann bearbeiten, wenn eine bestimmte Bedingung erfüllt ist:

 4 REM HI-LO-Spiel
 5 REM -----------
10 z=Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - Interrupt
Besonderheiten der Z80 im Schneider CPC: normaler Interrupt
Die Besonderheiten des FDC 765 im Schneider CPC: INT
INT
(RND*1000) 20 INPUT "rate:",LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
30 IF LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
=z THEN PRINT "richtig.":GOTO 10 40 IF LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
<z THEN PRINT "zu klein." ELSE PRINT "zu groß." 50 GOTO 20

In HI-LO gilt es eine Zahl 'z' zu erraten. Nach der Eingabe von 'LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
' muss das Programm drei Fälle unterscheiden. In Zeile 30 wird getestet, ob die Zahl erraten wurde. Nur wenn 'LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
' gleich 'z' ist, wird der Programmteil nach THEN abgearbeitet. Dieser besteht aus zwei Befehlen.

Ist 'LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
=z' verzweigt das Programm zurück nach Zeile 10 (endlose Schleife). Wenn nicht, wird Zeile 40 abgearbeitet. Hier wird untersucht, ob 'LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
' kleiner als 'z' ist. Ist das der Fall, wird im THEN-Pfad die Meldung "zu klein" ausgegeben. Wenn nicht, werden die Befehle ab ELSE abgearbeitet.

In Einleitung: BASIC
Anhang: Basic
Basic
können Fallabfragen auch geschachtelt werden. Das obige Beispiel lässt sich dann wie folgt verkürzen:

 4 REM HI-LO-Spiel
 5 REM -----------
10 z=Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - Interrupt
Besonderheiten der Z80 im Schneider CPC: normaler Interrupt
Die Besonderheiten des FDC 765 im Schneider CPC: INT
INT
(RND*1000) 20 INPUT "rate:",LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
30 IF LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
=z THEN PRINT "richtig.":GOTO 10 ELSE IF LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
<z THEN PRINT "zu klein." ELSE PRINT "zu groß." 50 GOTO 20

Die Einrückungen werden vom Basic-Interpreter natürlich nicht ausgewertet sondern dienen nur dazu, optisch darzustellen, welches THEN und ELSE zu welcher IF-Abfrage gehört. Der Basic-Interpreter benutzt leider einen etwas unglücklichen Algorithmus um festzustellen, welches ELSE zu welchem IF gehört. Und zwar sucht er in der Programmzeile immer nach dem nächsten ELSE. Im folgenden Programm wird der erste ELSE-Pfad abgearbeitet, wenn Test_1 aber auch Test_2 mit Falsch beantwortet wird:

 5 REM dieses Vergleichsprogramm funktioniert nicht im Schneider-Basic
 6 REM        ------------------
10 INPUT "zwei Zahlen bitte:",Operationen: BD5B / 349A / 349A:  FLO SUBa,LOW KERNEL JUMPBLOCK: 000B:  LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
20 IF Operationen: BD5B / 349A / 349A: FLO SUBa<=LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
THEN IF Operationen: BD5B / 349A / 349A: FLO SUBa=LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
THEN PRINT "Operationen: BD5B / 349A / 349A: FLO SUBa und LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
sind gleich" ELSE PRINT "Operationen: BD5B / 349A / 349A: FLO SUBa ist kleiner als LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
" ELSE PRINT "Operationen: BD5B / 349A / 349A: FLO SUBa ist größer als LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
" 30 END

Der zweite ELSE-Pfad kann niemals abgearbeitet werden. Durch das Einrücken ist zwar sinnfällig gemacht, dass, wenn der erste Erklärung der Anschlussbelegung: TestTest (Operationen: BD5B / 349A / 349A: FLO SUBa<=LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
) fehlschlägt, das zweite ELSE bearbeitet werden soll. Einleitung: BASIC
Anhang: Basic
Basic
nimmt aber das nächstbeste ELSE, dass es nach dem Erklärung der Anschlussbelegung: TestTest finden kann. Nicht sehr glücklich, weil so Fallabfragen im Locomotive Einleitung: BASIC
Anhang: Basic
Basic
des Schneider CPC nur sehr begrenzt schachtelbar sind.

Andere Basic-Interpreter oder auch Übergabe von Argumenten und Ergebnissen: PASCAL:PASCAL sind da besser:

program vergleich (input,output);
  var Operationen: BD5B / 349A / 349A:  FLO SUBa,LOW KERNEL JUMPBLOCK: 000B:  LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
:integer; begin writeln ('zwei Zahlen bitte:'); readln (Operationen: BD5B / 349A / 349A: FLO SUBa,LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
); if Operationen: BD5B / 349A / 349A: FLO SUBa<=LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
then if Operationen: BD5B / 349A / 349A: FLO SUBa=LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
then writeln ('Operationen: BD5B / 349A / 349A: FLO SUBa und LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
sind gleich') else writeln ('Operationen: BD5B / 349A / 349A: FLO SUBa ist kleiner als LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
') else writeln ('Operationen: BD5B / 349A / 349A: FLO SUBa ist größer als LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
') end.

Übergabe von Argumenten und Ergebnissen: PASCAL:PASCAL macht es sich leicht, indem nach 'then' und 'else' nur ein einziger Befehl folgen darf, der Bedingungs-abhängig abgearbeitet werden soll. Werden mehr benötigt, dann können beliebig viele Einzeloperationen mit 'begin' und 'end' zu einem einzigen Befehl geklammert werden. Die innere Fall-Abfrage im obigen Beispiel 'if Operationen: BD5B / 349A / 349A: FLO SUBa=LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
b
then ... else ...' zählt dabei in Übergabe von Argumenten und Ergebnissen: PASCAL:PASCAL als ein Befehl, und muss deshalb nicht mit 'begin' und 'end' geklammert werden (schaden würde es aber auch nichts).

Jede IF-Verzweigung kann nach einem einfachen Schema in bedingte Sprünge zerlegt werden:

 4 REM HI-LO-Spiel
 5 REM -----------
10 z=Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - Interrupt
Besonderheiten der Z80 im Schneider CPC: normaler Interrupt
Die Besonderheiten des FDC 765 im Schneider CPC: INT
INT
(RND*1000) 20 INPUT "rate:",LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
30 IF LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
=z THEN PRINT "richtig.":GOTO 10 ELSE IF LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
<z THEN PRINT "zu klein." ELSE PRINT "zu groß." 50 GOTO 20 Zeile 30 -----> 30 CASE (LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
e
=z) : IFTRUEGOTO 38 32 CASE (e<z) : IFTRUEGOTO 36 34 PRINT "zu groß" : GOTO 50 36 PRINT "zu klein" : GOTO 50 38 PRINT "richtig." : GOTO 10

Da es in Einleitung: BASIC
Anhang: Basic
Basic
kein echtes, bedingtes GOTO gibt, wurde es für dieses Beispiel extra erfunden. Mit CASE wird eine Aussage in 'falsch' oder 'richtig' ausgewertet und irgendein Die Z80: Wirkung der Z80-Befehle auf die FlagsFlag entsprechend gesetzt. Der bedingte Sprung IFTRUEGOTO erfogt nur, wenn das Die Z80: Wirkung der Z80-Befehle auf die FlagsFlag auf 'wahr' steht.

Indirekter Sprung - Verzweigung via Tabelle

Wenn mehrere Fälle zu unterscheiden sind, empfiehlt sich oft ein indirekter Sprung. Hierbei muss sich aus der Bedingung ein Zeiger berechnen lassen, mit dessen Hilfe aus einer Tabelle das Sprungziel ausgelesen werden kann.

In Einleitung: BASIC
Anhang: Basic
Basic
steht hierfür der Befehl 'ON_bedingung_GOTO' zur Verfügung. Besonders in Menüs wird man oft davon Gebrauch machen:

10 PRINT " 1 = Laden  2 = Speichern  3 = Überprüfung  4 = Exit"
20 INPUT " bitte wählen Sie.",wahl
30 IF wahl<1 OR wahl>4 THEN GOTO 20
40 ON wahl GOTO 2000,3000,4000,5000
...

Hierbei wird in Zeile 30 zuerst getestet, ob die Eingabe im gültigen Bereich liegt. In Einleitung: BASIC
Anhang: Basic
Basic
wäre eine Überschreitung des Bereiches nicht schlimm. Ist der Wert zu groß, so macht Einleitung: BASIC
Anhang: Basic
Basic
mit dem nächsten Befehl weiter, was sehr nützlich sein kann, wenn man sehr umfangreiche Menüs zu bearbeiten kann:

 5 REM Verteiler in einem Textverarbeitungsprogramm
 6 REM --------------------------------------------
10 LET i$ = INKEY$: IF i$="" THEN GOTO 10
20 LET wahl=ASC(i$)
30 IF wahl >= 32 THEN GOTO 5000 : REM kein Controlcode -> Zeichen drucken
40 '
50 Controlcode behandeln
60 '
70 ON wahl+1  GOTO  200, 300, 400, 500, 600, 700, 800, 900
80 ON wahl-7  GOTO 1000,1100,1200,1300,1400,1500,1600,1700
90 ON wahl-15 GOTO 1800,1900,2000,2100,2200,2300,2400,2500
95 ON wahl-23 GOTO 2600,2700,2800,2900,3000,3100,3200,3300
...

Bei einer Bereichs-Unterschreitung um Eins macht Einleitung: BASIC
Anhang: Basic
Basic
auch mit dem nächsten Befehl weiter. Bei mehr bleibt der Basic-Interpreter aber mit einer Fehlermeldung stehen:

ON 0 GOTO 200 [ENTER]
Erklärung zu den Bezeichnungen: READY
Erklärungen zu den Anschlussbezeichnungen: READY
Ready
ON -1 GOTO 200 [ENTER] Improper argument Erklärung zu den Bezeichnungen: READY
Erklärungen zu den Anschlussbezeichnungen: READY
Ready

Vor allem aber in Assembler- oder compilierten Programme ist diese sogenannte 'Plausibilitäts-Kontrolle' unerlässlich. In Assembler muss man sich eben um fast alles selbst kümmern. Wenn man nicht kontrolliert, dass der 'wahl'-Zeiger auch wirklich in die Tabelle möglicher Sprung-Adressen zeigt, und nicht darüber oder darunter, landet das Programm im Nirwana, sobald der Anwender ungültige Eingaben macht:

    ; Verzweigung via Tabelle in Maschinencode:
    ; -----------------------------------------

    MENUE:  LD   HL,MENTXT     ; Menü auf dem Bildschirm ausgeben.
            Maschinencode über HIMEM: CALLCALL MESSEG
    ;
    MEN1:   Maschinencode über HIMEM: CALLCALL INKEY         ; Warte, dass Anwender eine Taste drückt.
    ;
            SUB  "0"           ; ASCII-Code für "0" bis "9"
                            ; in ein Datentypen: Bytes
Datenbreite: Bytes
Byte
0 .. 9 wandeln und JR C,MEN1 ; falls Code zu klein (kleiner als Code für '0') ; CP 10 ; Erklärung der Anschlussbelegung: TestTeste, ob Code zu groß (größer als '9') JR NC,MEN1 ; ADD Operationen: BD5B / 349A / 349A: FLO SUBA,Operationen: BD5B / 349A / 349A: FLO SUBA ; Zeiger in die Adressen-Tabelle berechnen LD HL,BASIS ; (Basis + 2*Erklärungen zu den Anschlussbezeichnungen: INDEXIndex = Zeiger auf Sprungadresse) LD LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
E
,Operationen: BD5B / 349A / 349A: FLO SUBA LD D,0 ADD HL,DE ; LD LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
E
,(HL) ; Adresse aus der Tabelle nach Die Tonausgabe: Das Kontrollregister (Reg. 7)
Die Tonausgabe: Die möglichen Hüllkurvenformen (Reg. 13)
Register
DE holen INC HL LD D,(HL) ; EX DE,HL ; Routine anspringen JP (HL) ; MENTXT: DEFM ".... 10 MENUE-OPTIONEN MIT NUMMERN VON 0 BIS 9 ... " DEFB 0 ; BASIS: DEFW ADR0 ; Tabelle mit 10 Adressen (je 2 Datentypen: Bytes
Datenbreite: Bytes
Bytes
) für die DEFW ADR1 ; Behandlungs-Routinen der 10 Menü-Optionen .... DEFW ADR9 ...

Iterationen - Schleifen

Eins der einfachsten Strukturierungsmittel ist die Schleife. Der Befehlssatz der Die ICs im Überblick: Die CPU Z80
Das Innenleben der CPC-Rechner: Die CPU Z80
Die Anschlussbelegungen der wichtigsten ICs im CPC: Die CPU Z80
Z80
(und praktisch jedes anderen Mikroprozessors auch) enthält keine expliziten Schleifenbefehle. Wer in Assembler programmiert, muss sich seine Schleifen immer mit Hilfe von bedingten Sprüngen 'zu Fuss' programmieren.

Um Schleifen optisch besser erkennbar zu machen, werden die Befehle innerhalb der Schleife oft eingerückt. Aber praktisch keine Programmiersprache wertet dieses Einrücken auch aus. Es dient ausschließlich der besseren Überschaubarkeit.

Schleifen dienen dazu, den in ihnen enthaltenen Programmteil mehrfach auszuführen und müssen normalerweise ein Endkriterium haben. Fehlt dies, wird die Schleife unendlich oft durchlaufen. Kommen in einem Programm mehrere Schleifen vor (was ja sehr wahrscheinlich ist), so dürfen sie nicht 'verschränkt' werden:

Erlaubt:               Erlaubt:                   Unsinnig:

aufeinander folgende   ineinander geschachtelte   verschränkte
Schleifen:             Schleifen:                 Schleifen:

prog: befehl           prog: befehl               prog: befehl
      befehl                 start1 -----------+        befehl
      start1 ----+              befehl         |        start1 --------+
         befehl  |              befehl         |           befehl      |
         befehl  |              start2 -----+  |           befehl      |
         befehl  |                 befehl   |  |           start2 -------+
      ende1  ----+                 befehl   |  |              befehl   | |
      befehl                    ende2  -----+  |              befehl   | |
      start2 ----+           ende1  -----------+        ende1  --------+ |
         befehl  |           befehl                     befehl           |
      ende2  ----+           befehl                        ende2  -------+
      ...                    ...                           ???

Das Einleitung: BASIC
Anhang: Basic
Basic
der Schneider CPCs kennt nur zwei unterschiedliche Schleifenstrukturen (Im Vergleich zu Assembler aber schon recht komfortabel):

100 FOR Operationen: BD5B / 349A / 349A:  FLO SUBA=1 TO 10 STEP 1       oder:  200 Operationen: BD5B / 349A / 349A:  FLO SUBA=1
110 PRINT Operationen: BD5B / 349A / 349A:  FLO SUBA                           210 WHILE A>0
120   NEXT Operationen: BD5B / 349A / 349A:  FLO SUBA                          220   PRINT Operationen: BD5B / 349A / 349A:  FLO SUBA
130 END                               230   Operationen: BD5B / 349A / 349A:  FLO SUBA=Operationen: BD5B / 349A / 349A:  FLO SUBA/2
                                      240 WEND
                                      250 END

Die FOR/NEXT-Schleife bietet dabei den zusätzlichen Service, eine so genannte LAUFVARIABLE nach jedem Schleifendurchgang automatisch weiterzustellen. Im Schleifenkopf muss dabei der Laufbereich (von...bis) und die Schrittweite angegeben werden. Das Schleifenende wird durch den Befehl NEXT festgelegt.

FOR/NEXT-Schleifen weisen leider von Einleitung: BASIC
Anhang: Basic
Basic
zu Einleitung: BASIC
Anhang: Basic
Basic
Unterschiede auf. Mindestens drei Variationen sind möglich. Deshalb sind FOR/NEXT-Schleifen bei 'strukturierten' Programmierern auch nicht sehr beliebt.

Laufindex
10 FOR i=1 TO 10:PRINT i:NEXT i
20 PRINT i

Welchen Wert hat im obigen Programm die Unterprogramme: VariablenVariable Operationen: BD5B / 349A / 349A: FLO SUBA nach dem letzten Schleifendurchlauf, 10? Falsch. Wenn Sie das Programm abtippen, können Sie sich davon überzeugen, dass Operationen: BD5B / 349A / 349A: FLO SUBA zum Schluss den Wert 11 enthält. Bei manchen anderen Interpretern ist aber auch der Wert 10 möglich. Das hängt davon ab, wie der Interpreter das Schleifenende testet: Zuerst die Laufvariable weiterstellen und dann auf Überschreitung der Grenze Erklärung der Anschlussbelegung: Testtesten (wie Locomotive Einleitung: BASIC
Anhang: Basic
Basic
im CPC) oder erst auf Erreichen der Grenze Erklärung der Anschlussbelegung: Testtesten und nur gegebenenfalls den Iterationen - Schleifen: LaufindexLaufindex weiterstellen?

Struktur

Ein weiterer Unterschied ergibt sich in der Art, wie der Interpreter den Zusammenhalt zwischen dem Schleifenkopf (FOR-Statement), dem Schleifenende (NEXT) und der Laufvariablen wahrt. Locomotive Einleitung: BASIC
Anhang: Basic
Basic
trägt in seinem privaten Return- und Schleifenstapel jede gestartete Schleife ein. Der Eintrag enthält unter Anderem einen Zeiger auf das FOR-Statement und einen Zeiger auf NEXT. Es ist deshalb nicht möglich, einer Schleife zwei verschiedene Schleifen-Endpunkte zuzuordnen, was beispielsweise nach einer Fall-Abfrage interessant sein könnte. Das folgende Programm läuft auf dem Schneider CPC nicht! Beispielsweise aber auf dem Sinclair SPECTRUM:

 80 INPUT "Startwert";S
 90 INPUT "  Endwert";LOW KERNEL JUMPBLOCK: 000E:  LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
E
100 FOR Operationen: BD5B / 349A / 349A: FLO SUBA=S TO LOW KERNEL JUMPBLOCK: 000E: LOW PCBC INSTRUCTION
LOW KERNEL JUMPBLOCK: 001E: LOW PCHL INSTRUCTION
E
110 IF Alle noch folgenden Anschlüsse fallen unter die Rubrik STEUER- oder auch CONTROLBUS:: INT - Interrupt
Besonderheiten der Z80 im Schneider CPC: normaler Interrupt
Die Besonderheiten des FDC 765 im Schneider CPC: INT
INT
(Operationen: BD5B / 349A / 349A: FLO SUBA/77) <> Operationen: BD5B / 349A / 349A: FLO SUBA/77 THEN NEXT Operationen: BD5B / 349A / 349A: FLO SUBA:END 120 PRINT Operationen: BD5B / 349A / 349A: FLO SUBA;"ist durch 77 teilbar" 130 NEXT Operationen: BD5B / 349A / 349A: FLO SUBA 140 END

Beim Spectrum werden die Schleifenparameter nämlich an die Laufvariable gebunden. Hier ist die NEXT-Adresse nicht angegeben, nur die Adresse des FOR-Statements. Dadurch verzweigt dessen Einleitung: BASIC
Anhang: Basic
Basic
bei jedem NEXT Operationen: BD5B / 349A / 349A: FLO SUBA zur entsprechenden FOR-Deklaration, wenn die Schleifenbedingung erfüllt ist.

Das folgende Programm kann, je nach Basic-Interpreter, recht unterschiedliche Wirkungen entfalten. Die Wirkung wird aber nur in den seltensten Fällen die sein, die man von ihm erwartet:

10 FOR Operationen: BD5B / 349A / 349A:  FLO SUBA=10 TO 100 STEP 10
20   FOR Operationen: BD5B / 349A / 349A:  FLO SUBA=Operationen: BD5B / 349A / 349A:  FLO SUBA TO Operationen: BD5B / 349A / 349A:  FLO SUBA+9 STEP 1
30     PRINT Operationen: BD5B / 349A / 349A:  FLO SUBA
40   NEXT Operationen: BD5B / 349A / 349A:  FLO SUBA
50 NEXT Operationen: BD5B / 349A / 349A:  FLO SUBA
abweisende Schleifen

Alle Schleifen lassen sich in zwei unterschiedliche Kategorien einordnen: Die Iterationen - Schleifen: abweisende Schleifenabweisenden Schleifen, bei denen der Schleifeninhalt kein einziges Mal abgearbeitet wird, wenn das Abbruchkriterium bereits vor dem ersten Durchlauf erreicht ist, und die nicht Iterationen - Schleifen: abweisende Schleifenabweisenden Schleifen, deren Inhalt mindestens einmal durchlaufen wird, bevor eine Endabfrage über weitere Wiederholungen entscheidet.

Für diese beiden Kategorien gibt es auch die nicht ganz ernst gemeinten Bezeichnungen 'Beamtenschleife' (erst nachfragen, ob man wirklich was tun muss) und 'Funktionaersschleife' (Hauptsache, es wird was getan. Nachfragen, ob es sinnvoll war, kann man ja immer noch.).

Auch hierin können sich die FOR/NEXT-Schleifen von Basic-Interpreter zu Basic-Interpreter unterscheiden. Das Einleitung: BASIC
Anhang: Basic
Basic
des Schneider CPC ist als 'Beamtenschleife' realisiert, was folgendes Beispiel zeigt:

100 FOR Operationen: BD5B / 349A / 349A:  FLO SUBA=100 TO 99 STEP +1
110   PRINT Operationen: BD5B / 349A / 349A:  FLO SUBA
120 NEXT Operationen: BD5B / 349A / 349A:  FLO SUBA

RUN [ENTER]
Break in 130
Erklärung zu den Bezeichnungen: READY
Erklärungen zu den Anschlussbezeichnungen: READY
Ready

In diesem Fall wird die Schleife kein einziges Mal durchlaufen, und auch der Schleifenindex nicht vor der Endabfrage erhöht. Operationen: BD5B / 349A / 349A: FLO SUBA enthält nach 'Durchlauf' der Schleife den Wert 100.

Für die WHILE/WEND-Schleife gibt es da schon verlässlichere Kriterien. Auch sie ist eine Iterationen - Schleifen: abweisende Schleifenabweisende Schleife. Der Schleifeninhalt wird so lange durchlaufen, wie die im Schleifenkopf angegebene Bedingung erfüllt ist (While = deutsch: während).

Während unser Einleitung: BASIC
Anhang: Basic
Basic
also nur Iterationen - Schleifen: abweisende Schleifenabweisende Schleifen kennt, muss man hierfür in Assembler zusätzlichen Aufwand treiben:

nicht abweisend:                       abweisend:

START:  LD   LOW KERNEL JUMPBLOCK: 000B:  LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
B
,0 START: LD LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
B
,0 LOOP: PUSH BC INC LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
B
Maschinencode über HIMEM: CALLCALL PRINT JR ENDE POP BC LOOP: PUSH BC DEC LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
B
Maschinencode über HIMEM: CALLCALL PRINT JR NZ,LOOP POP BC RET ENDE: DEC LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
B
JR NZ,LOOP RET PRINT: LD Operationen: BD5B / 349A / 349A: FLO SUBA,"*" Maschinencode über HIMEM: CALLCALL #BB5A ; TEXT VDU: BB5A: TXT OUTPUTTXT OUTPUT RET

Hier ist der Unterschied besonders krass. Das Ergebnis beider Schleifen ist das selbe, solange der Startwert für LOW KERNEL JUMPBLOCK: 000B: LOW KL LOW PCHL
LOW KERNEL JUMPBLOCK: 001B: LOW KL FAR PCHL
LOW KERNEL JUMPBLOCK: 003B: LOW EXT INTERRUPT
B
nicht mit Real: NullNull festgesetzt wird. Dann erhält man nämlich in der nicht abweisenden Version 256 Sternchen, während die abweisende Version kein einziges druckt.

Valid HTML   Valid CSS