VAR a: ARRAY[5,10,20] OF LONG; r: LONG; i,j,k: INTEGER; ... WHILE (j<10) AND (NOT ((j>i) OR (j>k)) ) DO r := a[i,j,20-j]; j := j + 1; ENDErzeugen Sie für das obige Programmstück Quadrupel-Code nach der Kontrollfluß-methode. Ein
LONG
ist 8 Byte und ein
INTEGER
4 Byte groß. Die Untergrenze aller Indexbereiche ist
0.
Wbegin: if j<10 goto ANDtrue goto Wfalse ANDtrue: if j>i goto Wfalse goto ORfalse ORfalse: if j>k goto Wfalse goto Wtrue Wtrue: t1 := i * 10 t2 := t1 + j t3 := t2 * 20 t4 := 20 - j t5 := t3 + t4 t6 := t5 * 8 t7 := t6 + adr(a) t8 := @t7 r := t8 t9 := j + 1 j := t9 goto Wbegin Wfalse:
a[i1,i2,...,ik]
durch
die folgende Formel berechnet:
Der Zugriff auf((...((i1*n2+i2)*n3+i3)...)*nk+ik)*w+adr(a)
mit
nj
: Anzahl der Elemente der j-ten Dimension
w
: Anzahl der Speichereinheiten für ein Element
adr(a)
: Anfangsadresse des Arraysa
im Speicher
a[i,j,20-j]
ergibt daher die Formel
((i*10+j)*20+(20-j))*8+adr(a)
weil die Definition des Arrays a[5,10,20] OF LONG
lautete, der dritte Index durch 20-j
berechnet wird
und außerdem ein LONG
8 Byte groß ist. Der Quadrupelcode für diesen Ausdruck ist
dann erfolgt der Zugriff auf den Wert der Array-Eintragst1 := i * 10 t2 := t1 + j t3 := t2 * 20 t4 := 20 - j t5 := t3 + t4 t6 := t5 * 8 t7 := t6 + adr(a)
t8 := @t7
Bei der Übersetzung boolscher Ausdrücke werdem im Großen und Ganzen nur Labels und Sprünge erzeugt. Dazwischen kommt der Code der für die restlichen Programmstücke benötigt wird.
WHILE (j<10) AND (NOT ((j>i) OR (j>k)) ) DO
übersetzen. Wie wir in Abbildung 7.10 "Übersetzung von
Kontrollanweisungen bei der Kontrollfluß-Methode" des Skriptums
sehen, werden bei der WHILE-
Produktion drei neue Label
erzeugt. Sie erhalten die Werte
begin := Wbegin
B.true := Wtrue
B.false := Wfalse
Zwei von ihnen werden damit an die Bedingung B
vererbt. An dieser Stelle in der Produktion sehen wir auch, wie der
resultierende Code aussehen soll. Wir müssen zuerst das Label
begin
generieren,
dann den Code der Bedingung B.c
, das Label
B.true
, den Code
für die Schleife, ein "goto Wbegin
" und zuletzt das Label
B.false
.
In unserem Fall kommt dieses Codefragment heraus:
Wbegin: <B.c> Wtrue: <S1.c> goto Wbegin Wfalse:
Die Bedingung B
aus der obigen Produktion ist - wie wie
aus der Klammerung sehen - eine AND
-Verknüpfung aus
den beiden Bedingungen
B1: (j<10)
und
B2: (NOT ((j>i) OR (j>k)) )
Aus Abbildung 7.7 "Übersetzung Boolescher Ausdrücke nach der Kontrollfluß-Methode" sehen wir, welche Labels dafür erzeugt bzw. vererbt werden
B1.true := newlabel = ANDtrue
B1.false := B.false = Wfalse
B2.true := B.true = Wtrue
B2.false := B.false = Wfalse
und welcher Code dafür erzeugt wird:
<B1.c> ANDtrue: <B2.c>
Den Code für B1.c
können wir gleich
hinschreiben (siehe Bedingungen). Dieser
ist ganz einfach
if j<10 goto ANDtrue goto Wfalse
Der Code für B2.c
ist etwas schwieriger, weil er
einen weiteren, verschachtelten Booleschen Ausdruck verbirgt: NOT und
OR
Ein NOT-
Ausdruck wird ganz einfach übersetzt (beachten
Sie die Produktion in Abbildung 7.7 des Skriptums): Das TRUE-Label der
eingeschlossenen Bedingung bekommt den Wert des FALSE-Labels und
umgekehrt. Die vererbten Attribute an dieser Stelle haben also jetzt
die Werte
B.true := Wfalse
B.false := Wtrue
Der generierte Code wird einfach durchgereicht.
Der OR-Ausdruck besteht aus den beiden Bedingungen
B1: (j>i)
und
B2: (j>k)
In der Produktion für den OR-
Ausdruck sehen wir, daß neue
Labels erzeugt werden. Wir erhalten folgende Werte:
B1.true := B.true = Wfalse
B1.false := newlabel = ORfalse
B2.true := B.true = Wfalse
B2.false := B.false = Wtrue
Der zurückgelieferte Code besteht aus dem Code der ersten Bedingung, dem Label B1.false und dem Code der zweiten Bedingung, also:
<B1.c> ORfalse: <B2.c>
Nach der Belegung der Labels gilt für B1.c
if j>i goto Wfalse goto ORfalse
Nach der Belegung der Labels gilt für B2.c
if j>k goto Wfalse goto Wtrue
Bei den relationalen Operatoren wird jetzt endlich wirklich Code erzeugt und zwar nach dem Muster
if <E1.c> <rop.x> <E2.c> goto <B.true> goto <B.false>
Für <E1.c>
bzw. <E2.c>
wird
dann der Code für den jeweilige Ausdruck eingefügt, der ja
auch eine Berechnung oder eine Konstante sein
kann. <rop.x>
ist das Zeichen für den
relationalen Operator.
Achtung! Wie wir hier sehen, werden ganz stur irgendwelche Sprungbefehle auf irgendwelche Labels erzeugt. Die Werte der entsprechenden vererbten Attribute werden jedoch nicht berücksichtigt. Dadurch kommt es immer wieder zu Sprüngen auf die nachfolgende Adresse. Diese Sprungbefehle dürfen jedoch zu diesem Zeitpunkt nicht entfernt werden. Der Code wird ja erzeugt!
Jetzt setzen wir die restlichen Codestücke zusammen und erhalten die vollständige Lösung.