Folge 22: Variablenverwaltung

Schritt 1 - Berechnungen mit Variablen

Betrachten Sie folgenden Java-Quelltext:
radius = 10.0;
pi = 3.14;
umfang = 2 * pi * radius;

Nicht besonders beeindruckend, oder? Hier wird der Umfang eines Kreises berechnet. Das Programm muss dazu drei Dinge wissen:

  1. Die Formel zur Berechnung des Umfanges
  2. Den Radius des Kreises
  3. Den Wert der Konstante pi

Hier haben wir ein gutes Beispiel für eine Berechnung, bei der Variablen eine wichtige Rolle spielen. In der Berechung des Kreisumfangs werdem folgende drei Variablen verwendet: radius, pi und umfang.

Schritt 2 - Was sind Variablen?

Eine Variable besteht aus drei Komponenten
  1. Bezeichnung oder Variablenname
  2. Datentyp (Anzahl und Organisation der Bytes)
  3. Wert

Die Variable radius aus dem obigen Beispiel hat z.B. die Bezeichnung "radius", der Datentyp ist double, und der Wert ist 10.0.

Schritt 3 - StackInterpreter mit Variablen

Unsere Klasse StackInterpreter soll jetzt mit Variablen umgehen können; der Interpreter soll in der Lage sein, Berechnungen wie z.B. den Umfang eines Kreises auszuführen.

Um die Sache nicht unnötig zu verkomplizieren, beschränken wir uns bei dem Interpreter auf einen Typ von Variablen, nämlich double. So müssen wir für jede Variable nur noch die Bezeichnung und den aktuellen Wert speichern. Da bei einer Berechnung häufig mehrere Variablen benötigt werden, muss unser Interpreter ebenfalls in der Lage sein, mehrere solcher Variablen zu verwalten. Wir werden diese Variablen in einer Liste speichern; allerdings nicht direkt in der Klasse Stackinterpreter, sondern in einem Objekt der Klasse Variablenliste, welche wir noch erzeugen müssen.

Schritt 4 - Die Klasse Variablenliste

Die Klasse Variablenliste ist für die Verwaltung von Variablen zuständig. Bevor wir auf die Einzelheiten der Implementation eingehen, wollen wir uns überlegen, welche Methoden eine Variablenliste benötigt.

Methoden der Variablenliste

Der Abstrakte Datentyp Variablenliste wird durch folgende Operationen definiert:

Init(): Erzeugt eine leere Variablenliste.

SetzeWert(name,wert): Die Variable mit dem Namen name wird auf den Wert wert gesetzt. Falls name noch nicht existiert, wird eine neue Variable mit diesem Namen und dem Wert wert erzeugt.

GibWert(n): Der Wert der Variable mit dem Namen name wird als Funktionsergebnis zurückgeliefert. Falls die Variable nicht existiert, wird der Wert 0 zurückgegeben.


Übung 22.1 (3 Punkte)

Erstellen Sie eine Klasse Variablenliste (oder Varlist), die in der Lage ist, mindestens 16 verschiedene Variablen zu verwalten. Die oben genannten Methoden sollten zur Verfügung gestellt werden. Ob Sie die Methoden so benennen, wie oben vorgeschlagen, ist Ihnen überlassen. Sie dürfen auch gern englische Bezeichnungen wie setValue() und getValue() verwenden, falls Sie Ihre anderen Klassen auch mit englischsprachigen Methoden ausgestattet haben.

Achten Sie darauf, dass Ihnen keinerlei Vorgaben gemacht worden sind, wie Sie die Klasse Variablenliste intern implementieren. Nach dem Prinzip der Datenkapselung sind solche Details nicht nur überflüssig, sondern manchmal sogar störend.

Tipp:

Eine Klasse Variable könnte ganz sinnvoll sein, dann könnten Sie nämlich die Variablenliste mit einem Array von Variablen ausstatten. Notwendig ist das jedoch nicht; außerhalb der Klasse Variablenliste wird keine Klasse Variable benötigt.

Lesen Sie vorher den Lexikon-Eintrag Unterklassen! Das könnte ganz nützlich sein.


Schritt 5 - Code für eine Berechnung mit Variablen

Schauen wir uns noch einmal die Berechnung des Kreisumfangs an:

radius = 10.0;
pi = 3.14;
umfang = 2 * pi * radius;

Wir müssen jetzt einen Stackmaschinen-Code entwickeln, der die Stackmaschine veranlasst, genau diese Berechnung durchzuführen.

Anweisung 1: radius = 10.0;

Die Variable mit dem Namen radius soll den Wert 10 erhalten. Dazu muss erst mal die Zahl 10 auf den Stack gepusht werden, und dann muss eine Anweisung kommen, die die Stackmaschine dazu veranlasst, a) eine neue Variable namens "radius" anzulegen und b) dieser Variablen den Wert 10 zuzuweisen.

Folgender Stackmaschinencode leistet das Gewünschte:

push 10.0
assign radius

Der Stackmaschinenbefehl assign bewirkt Folgendes: Der Wert des obersten Stackelementes wird der angegebenen Variablen zugewiesen. Dann wird das oberste Stackelement gelöscht.

Man könnte rein theoretisch natürlich auch folgenden Stackmaschinencode benutzen:

assign radius 10

Das wäre ein Befehl mit zwei Argumenten, nämlich dem Variablennamen und dem Variablenwert. Ein solches direktes Vorgehen würde aber dem Charakter einer Stackmaschine widersprechen. Bei einer Stackmaschine werden alle wichtigen Operationen immer mit dem oder auf das oberste Stackelement ausgeführt - denken Sie nur an die add-Operation. Daher ist der assign-Befehl so konstruiert, dass grundsätzlich der Wert des obersten Stackelements in die Variable geschrieben wird. Also muss der Wert 10 zunächst in den Stack gepusht werden.

Anweisung 2: pi = 3.14

Diese Anweisung ist nach dem gleichen Muster aufgebaut wie die erste, also können wir den Code für die Stackmaschine direkt hinschreiben:

push 3.14
assign pi

Anweisung 3: umfang = 2 * pi * radius

Zuerst muss die Berechnung auf der rechten Seite der Zuweisung codiert werden. Das ist nicht allzu schwer:

push 2
varpush pi
varpush radius
mul
mul

Zunächst wird die Zahl 2 direkt auf den Stack gepusht. Dann muss der Wert der Variable pi auf den Stack gepusht werden, anschließend der Wert der Variable radius. Dazu wird der varpush-Befehl verwendet, der Folgendes leistet: In der Variablenliste wird nachgeschaut, welchen Wert die Variable hat. Dann wird dieser Wert auf den Stack gepusht. Da eine Variable wie radius oder pi im Laufe einer Berechnung mehrmals verwendet werden darf, wird die Variable nicht aus der Variablenliste gelöscht, sondern verbleibt in ihr.

Nach der Berechnung der rechten Seite der Zuweisung steht das Ergebnis der Berechnung im obersten Stackelement. Dieser Wert muss nun an die Variable umfang zugewiesen werden:

assign umfang

Damit ist der Stackmaschinencode komplett. Fassen wir noch einmal zusammen:

push 10.0
assign radius
push 3.14
assign pi
push 2
varpush pi
varpush radius
mul
mul
assign umfang

Übung 22.2 (2 Punkte)

Schreiben Sie den Stackmaschinencode für folgende Berechnung auf:

groesse = 185;
gewicht = 95;
idealgewicht = (groesse - 100) * 0.90;
differenz = gewicht - idealgewicht;

Am Ende der Berechnung soll der Wert von differenz im obersten (und einzigen) Stackelement stehen.



Übung 22.3 (3 Punkte)

Stellen Sie eine sinnvolle Verbindung zwischen den Klassen Stackinterpreter und Variablenliste her, so dass der StackInterpreter Berechnungen mit Variablen ausführen kann. Den Codebuffer müssen Sie übrigens auch erweitern, da es ja jetzt zwei neue Stackmaschinenbefehle gibt: assign und varpush.



So sieht das Klassendiagramm des Stackinterpreter-Projekts nach der Übung 22.3 aus, falls die Klasse Variable als eigenständige Klasse implementiert wurde. Es gibt auch noch die Möglichkeit, Variable als Klasse innerhalb der Klasse Variablenliste zum implementieren. Wer mehr über diese Möglichkeit wissen möchte, klickt bitte auf den Lexikon-Eintrag Unterklassen.

weiter mit dem Erweiterungsteil für Fortgeschrittene

Wenn Sie den Erweiterungsteil der Folge 21 bearbeitet haben, sollten Sie auch diesen Erweiterugsteil der Folge 22 bearbeiten; immerhin sind noch drei weitere Punkte zu holen. Es geht "nur" darum, auch die Variablenliste mit einem graphischen Interface auszustatten und dann in den Interpreter einzubinden.

weiter mit Folge 23: while-Schleifen

Bisher konnte unser Stackinterpreter nur rein lineare Programm abarbeiten. Wir wollen in dieser Folge den Interpreter dazu bewegen, while-Schleifen abzuarbeiten. Damit sind dann schon größere Berechnungen möglich, z.B. die Summe der Zahlen von 1 bis 10.

Diese HTML-Seite wurde erstellt von Ulrich Helmich am 22. Juli 2006 und stark überarbeitet am 14. Mai 2008.




(C) Ulrich Helmich, Mai 2008





IMPRESSUM