Trick
60: Wiederholungstaten
Alles Wichtige über
Schleifen in FLEX
Aufgabe: Einfachstmöglich eine
Befehlsfolge immer wieder abarbeiten,
bis ein bestimmter Wert oder eine Bedingung auftritt.
Warum: Das zyklische Durchlaufen
von Befehlsfolgen gehört zu den
häufigsten Übungen beim Programmieren. Dafür muß
es einfache
Rezepte geben, die man routinemäßig anwenden kann.
So etwas nennt man auch "Schleife", weil dabei wieder und
wieder zum Anfangspunkt einer Befehlsfolge zurückgekehrt wird.
Lösung:
Zuerst etwas Theorie
Richtige Programmiersprachen (so
eine ist FLEX nicht) haben drei
oder vier Lösungen.
Schematisch sehen sie folgendermaßen aus:
1. Die
for-Schleife for(anfangswert;
bedingung; schrittbefehl)
---------------- <befehle>
Das ist wohl die
beliebteste Form.
Der "for"-Befehl setzt
einen Anfangswert, eine Bedingung
und einen
Schrittbefehl. Die dann folgenden <befehle> werden so oft
ausgeführt, und
jeweils danach der Schrittbefehl, wie die bedingung
noch gilt.
Falls die bedingung
gleich schon zu Anfang nicht gilt, werden
die
<befehle> gar nicht ausgeführt.
2. Die
while-Schleife while(bedingung)
------------------ <befehle>
<befehle> werden
so lange immer wieder ausgeführt, wie bedingung
gilt. Gilt die
bedingung schon am Anfang nicht, passiert nichts.
3. Die
do-Schleife do
--------------- <befehle>
while(bedingung)
<befehle> werden
ausgeführt, dann bedingung geprüft, und wenn
erfüllt, abermals
<befehle>, bis bedingung nicht mehr gilt.
Die Befehle werden
also mindestens einmal ausgeführt, im
Gegensatz zu 2.
4. Die
goto-Schleife wenn nicht
bedingung dann goto weiter
----------------- :marke
<befehle>
wenn
bedingung dann goto marke
:weiter
Die erste Zeile
läßt man weg, wenn die <befehle> mindestens einmal
ausgeführt werden
sollen.
Diese Form wird von
Informatikern gering geschätzt, weil sie
wenig
übersichtlich ist und deshalb auch fehlerträchtig, vor allem
ist sie kaum
prüfbar, z.B. von einem Compiler oder Interpreter.
Es gab Bestrebungen,
sie in Acht und Bann zu tun, dazu ist es aber
nicht gekommen.
Wichtig zu wissen: Alle 4 Formen
sind logisch gleichwertig. Was man
mit einer davon machen kann, kann
man auch mit jeder der anderen drei
Formen machen, allenfalls mit einer
zusätzlichen Bedingungsprüfung.
Programmierer können sich
folglich entscheiden, auf eine oder
mehr als eine davon ganz zu
verzichten. Ob eine Konstruktion
übersichtlich und
verständlich ist, hängt aber nicht nur von
ihrem Typ ab, sondern auch von der
Art, wie sie umgesetzt ist,
wozu auch Kommentare gehören.
So *kann* selbst der Typ 4 durchaus
übersichtlich und
verständlich realisiert werden, der Typ 1 dagegen
erzwingt geradezu ein hohes
Maß an Übersichtlich- und Durchschau-
barkeit, aber die Formulierung der
Bedingung kann manchmal recht
abstrakt und schwer durchschaubar
sein - Gewohnheitssache.
Form 1 ist scheinbar suboptimal in
Fällen, wo die Anzahl der
Schleifendurchläufe nicht von
einem Zähler abhängt. Mit geschickter
Wahl der Bedingung kann man das
aber leicht umgehen und dann den
Schrittbefehl und sogar den
Anfangswert weglassen - damit hat man
dasselbe wie Form 2.
Alle vier Formen stehen in der
Gefahr, daß bei ungenügend durch-
dachten Bedingungen Endlosschleifen
entstehen können. Es ist sogar
grundsätzlich unmöglich,
dies softwaretechnisch auszuschließen.
FLEX kennt leider nur den Typ 4,
wobei es scheinheiligerweise nicht
goto heißt, sondern jump. Man
muß also überlegen, wie man damit
geschickt und
sicherheitsbewußt umgeht, aber schwer ist das nicht.
Wir zeigen es an zwei Beispielen,
die man als Schemata leicht
übernehmen und verinnerlichen
kann.
A. Schleife mit Zähler
======================
Für die Zahlen von 1 bis 100
sollen bestimmte Dinge ausgeführt
werden, die hier symbolisch durch
<befehle> dargestellt sind:
z=1
:loop
<befehle>
z+1
if z<101 jump loop
Innerhalb der <befehle> kann
z auch noch vorkommen, muß aber nicht.
Aufzupassen ist, z nicht innerhalb
der <befehle> zu *verändern*, es
sei denn, aus genau überlegten
Gründen. Beim if-Befehl wird der
momentane Wert von z genommen, egal
wie er zustandekam.
Hinweis: Als Name für eine
Schleifenvariable nehmen Programmierer
gewohnheitsmäßig oft das
i. In FLEX gibt es das nicht, da ist z
die einzige ganzzahlige Variable
und Z die einzige Gleitkommavariable.
Mit den sonstigen Variablen kann
man jedoch auch gut rechnen, nur
nicht ganz so direkt wie mit z und
Z.
Ersatzweise kann man z.B. so
arbeiten - mit $i statt i:
$i=1
:loop
<befehle>
eval $i+1
ins $i
if <101 jump loop
--- Ende :loop ---
Hier steht vor dem <101 kein $i!
Es wird vielmehr der Inhalt der
internen Variablen genommen, und
das ist in dem Moment eben noch
der Wert von $i. Verbal kann man
die letzten drei Zeilen so ausdrücken:
Addiere 1 auf den Wert von $i,
setze das Ergebnis in die Variable $i,
vergleiche diesen Wert mit der Zahl
101, und wenn er kleiner ist,
springe zur Marke :loop.
Variante: Die Endzahl kann auch in
einer #u-Variablen stehen oder in
einem Datenfeld. Dann sieht die
Endprüfung so aus:
if <#nnn ...
also z.B. if <#uxy jump
loop oder if <#123 jump
loop
Empfehlung: Eine Sprungmarke, die als Schleifenbeginn dient, benennt
man entweder :loop oder mit
einem Namen, in dem :loop vorkommt.
So wird visuell immer sofort klar,
was da vorliegt. Einen Anfangswert,
wenn einer gebraucht wird, immer in
der direkt vorangehenden Zeile
setzen. Zur visuellen
Verdeutlichung *kann* man einen Kommentar, wie
hier --- Ende :loop ---
unter das Schleifenende setzen.
Hinweis: Wenn zwei gleiche
Sprungmarken in einem FLEX vorkommen, dann
gilt nur die erste.
B. Schleife mit beliebiger
logischer Bedingung
==============================================
In FLEX sehr viel
häufiger als Zählschleifen! Aber genaugenommen
ist A. sowieso nur ein
Spezialfall von B.
Beispiel:
Ergebnismenge abarbeiten
Die Sätze einer
Ergebnismenge sollen abgearbeitet werden, d.h. für
jeden Satz sind
bestimmte Befehle auszuführen. Dabei wird kein
Zähler gebraucht.
Hier das Muster:
first
:eloop
<befehle>
next
if yes jump
eloop
Im Hilfetext zu "next"
(h xnext eingeben) findet man auch das
Muster, mit dem man
die gesamte Datenbank abarbeiten kann.
Und wo ist jetzt der Trick? Ob man
wirklich hier von Tricks sprechen
will, sei dahingestellt. Es sind
zwei Dinge zu nennen, die dem
Einsteiger wie auch dem in anderen
Sprachen bewanderten Programmierer
als Aha-Erlebnis erscheinen
können:
1.
Eine FLEX-Schleife kann mehr als
einen Rücksprung zum Schleifenanfang
haben. Das ist nicht nur praktisch,
es ist hinsichtlich der Durchschau-
barkeit und Fehlerträchtigkeit
auch mit Vorsicht zu genießen!
2.
Der Rücksprung zum
Schleifenanfang kann nicht nur durch einen Zahlen-
vergleich ausgelöst werden,
sondern durch jeden der zahlreichen if-
Befehle, die FLEX bereithält.
Zusatz-Trick: Ausbruch aus
Endlosschleifen
Mit dem Einbau dieser zwei Zeilen
in das Innere einer Schleife:
keycheck
if yes jump
weiter
kann man erreichen, daß man
sie mit Druck auf Esc abbrechen kann.
Wenn dann mal stundenlang einfach
nichts zu geschehen scheint, entnervt
Esc drücken - und dann die
Schleifenlogik nochmal durchdenken!