Folge 23.1: while-Schleifen

Schritt 1 - Was ist eine while-Schleife?

Eine while-Schleife besteht - unabhängig von der Progammiersprache - aus folgenden Komponenten:
  1. Schleifenanfang
  2. Schleifenbedingung, die erfüllt sein muss, damit die Schleife durchlaufen wird
  3. Schleifenkörper, endliche Folge von Anweisungen, die durchlaufen werden.
  4. Schleifenende

Wurde das Schleifenende erreicht, so wird wieder zum Schleifenanfang "gesprungen". Dann wird die Schleifenbedingung erneut überprüft, und wenn sie erfüllt ist, wird wieder der Schleifenkörper ausgeführt etc.

Schritt 2 - Analyse einer while-Schleife

Betrachten wir folgende while-Schleife in einer programmiersprachen unabhängigen Darstellung:
i = 1
s = 0
solange i < 100
start 
   s = s + i
   i = i + 1
ende

Offensichtlich soll hier die Summe der Zahlen von 1 bis 100 gebildet werden. Der Schleifenanfang besteht aus dem Wort "solange". In Pascal verwendet man das Wort "While" für den Schleifenanfang, wobei Groß- und Kleinschreibung keine Rolle spielen, wir dürfen also auch "WHILE" schreiben oder "while". In Java muss das Schlüsselwort "while" - alles kleingeschrieben - verwendet werden, um den Anfang einer while-Schleife zu kennzeichnen.

Die Schleifenbedingung besteht in dem einfachen Vergleich i < 100. Wenn der Wert der Variable i kleiner ist als 100, so ist die Schleifenbedingung erfüllt.

Der Schleifenkörper besteht aus den beiden Zuweisungen s = s + i und i = i + 1.

Das Schleifenende besteht hier aus dem Schlüsselwort "ende". In Pascal verwendet man das Schlüsselwort "end", um das Ende einer while-Schleife zu kennzeichnen, in Java schreibt man eine schließende geschweifte Klammer }.

Schritt 3 - Umsetzung in Stackmaschinencode

Die Befehle aus Schritt 2 können folgendermaßen in Stackmaschinencode übersetzt werden:
push 1
assign i
push 0
assign s
whilestart
varpush i
push 100
lt
varpush s
varpush i
add
assign s
varpush i
push 1
add
assign i
whileend

Wir wollen nun eingehend besprechen, wie der Stackinterpreter diese Zeilen abarbeitet.

1. Schleifenanfang

Der Stackinterpreter holt sich ja immer den nächsten Befehl aus dem Codebuffer. Steht in einer Zeile z.B. der Stackmaschinenbefehl

push 17

so weiß der Interpreter, dass er die Stackmaschine veranlassen muss, den push-Befehl auszuführen.:

if (bef == 1) 
   masch.push(buff.gibNumArgument());

Steht in einer Zeile dagegen

add

so ruft der Interpreter den add-Befehl der Stackmaschine auf:

if (bef == 2) masch.add();

Sieht der Interpreter dagegen den Befehl

whilestart

so führt der Interpreter den Befehl aus:

if (bef == 8) buff.merkeWhile();

Hierzu muss der Codebuffer eine Methode zur Verfügung stellen, die ungefährt folgendermaßen arbeitet:

Die Nummer der Zeile, in der das Wort whilestart steht, wird in einem Attribut gespeichert, zum Beispiel zeileWhilestart. Anschließend wird der Stackcode solange durchsucht, bis die Zeile mit dem Wort whileend gefunden wurde. Die Nummer der Zeile, in der dieses Wort steht, wird in einem anderen Attribut gespeichert, zum Beispiel zeileWhileend.

Übung 23.1 (2 Punkte)

Ergänzen Sie die Klasse Codebuffer so, dass auch die neuen Stack-Befehle durch Zahlen repräsentiert werden:

1 = push, 2 = add, 3 = sub, 4 = mul, 5 = div, 6 = assign, 7 = varpush, 8 = whilestart, 9 = whileend.

21 = lt, 22 = gt, 23 = eq, 24 = neq.


Übung 23.2 (2 Punkte)

Ergänzen Sie die Klasse Codebuffer um zwei Attribute zeileWhilestart und zeileWhileend sowie um eine Methode

public void merkeWhile()

welche so wie oben im Text angegeben arbeitet.


Übung 23.E1 (2 Punkte)

nur für Schüler(innen), die die Erweiterungsteile aus Folge 21 und 22 bearbeitet haben

Ergänzen Sie die graphische Anzeigen-Methode der Klasse Codebuffer so, dass die whilestart-Zeile und die whileend-Zeile farbig hervorgehoben werden. Die aktuelle Codezeile soll natürlich auch noch zu sehen sein, allerdings in einer anderen Farbe.

Hier sehen Sie den Screenshot eines Applets, in dem der Codebuffer entsprechend erweitert wurde. Der Interpreter hat soeben den whilestart-Befehl erkannt, und als Nächstes soll der varpush i - Befehl abgearbeitet werden. Der Stack ist deswegen leer, weil ja nach jedem assign-Befehl das oberste Stack-Element entfernt wird.

Übung 23.3 (1 Punkt)

Ergänzen Sie die Klasse Stackinterpreter so, dass auf den Befehl mit der Nummer 8 (whilestart) korrekt reagiert wird: Aufruf der Methode buff.merkeWhile().


Übung 23.4 (1 Punkt)

Ergänzen Sie die Klasse Stackinterpreter so, dass auf den Befehl mit der Nummer 9 (whileend) korrekt reagiert wird: Aufruf der Methode buff.starteWhile().

In der Übung 23.4 sollen Sie den Stackinterpreter dazu bringen, dass er wieder an den Anfang der while-Schleife springt. Allerdings führt nicht der Interpreter die Hauptarbeit durch, sondern er delegiert die Arbeit an den Codebuffer, indem er den Codebuffer-Befehl starteWhile() aufruft. Dieser Befehl sorgt dafür, dass der Programmzähler (in meinen Beispielen habe ich ihn aktuell genannt) wieder auf den Anfang der while-Schleife gesetzt wird, strenggenommen auf die darauf folgende Zeile.

weiter mit Folge 23.2: Schleifenbedingung

Diese HTML-Seite wurde erstellt von Ulrich Helmich am 23. Juli 2006.






IMPRESSUM