Programmiersprachenentwurf
7. Übung – Lösungen Übersetzung in Zwischencode
☞
Die Compiler-Version mit den in dieser Übung entwickelten Erweiterungen finden Sie auf der Kurs-Seite als das Lösungsmaterial – „pl0Compiler1“
1. Aufgabe
Geben Sie für die folgenden arithmetischen Ausdrücke ihre Übersetzung an in Postfixcode, in Quadrupelcode und in Tripelcode mit der in der Vorlesung skizzierten Notation:
a) A + B ∗ ( C - D / E ) b) − A + B ∗ ( C - D / E ) c) A * ( B ∗ C - C / D ) d) A ∗ B ∗ C - D/E
Postfix-Code:
a) b) c) d) LOAD A
LOAD B LOAD C LOAD D LOAD E DIV
SUB MPY ADD
LOAD A NEG
LOAD B LOAD C LOAD D LOAD E DIV
SUB MPY ADD
LOAD A LOAD B LOAD C MPY
LOAD D LOAD E DIV
SUB MPY
LOAD A LOAD B MPY
LOAD C MPY
LOAD D LOAD E DIV
SUB
Quadrupel-Code:
a) b) DIV D E $HV1
SUB C $HV1 $HV2 MPY B $HV2 $HV3 ADD A $HV3 $HV4
NEG A $HV1
DIV D E $HV2 SUB C $HV2 $HV3 MPY B $HV3 $HV4 ADD $HV1 $HV4 $HV5
c) d) MPY B C $HV1
DIV D E $HV2
MPY A B $HV1 MPY $HV1 C $HV2
2 Tripel-Code:
a) b) DIV D E
SUB C (1) MPY B (2) ADD A (3)
NEG A
DIV D E
SUB C (2) MPY B (3) ADD (1) (4)
c) d)
MPY B C
DIV D E SUB (1) (2) MPY A (3)
MPY A B
MPY (1) C
DIV D E
SUB (2) (3)
2. Aufgabe
Geben Sie zu den folgenden Postfix-Codefolgen äquivalente arithmetische Ausdrücke an :
a) LOAD 5 b) LOAD ALPHA
LOAD ALPHA LOAD 4
MPY LOAD 3
LOAD BETA ADD
LOAD 3 MPY
LOAD 4 LOAD 4
MPY LOAD 3
ADD MPY
SUB DIV
a) 5 ∗ ALPHA − (BETA + 3∗4) b) ALPHA ∗ (4+3) / (4∗3)
3. Aufgabe
Im Material zu dieser Übung finden Sie die PL0-Programme
− minmax.pl0 Minimum und Maximum von drei Zahlen
− faculty.pl0 iteratives Berechnen der Fakultät
übersetzen Sie die Programme und analysieren sie, das Listing, den generierten Zwischencode sowie die Symboltabellen-Inhalte während der Compilierung in den Dateien
− _Listing.pl0
− _Code.pl0
− _Tables.pl0
Quellprogramm minmax.pl0
/* PL/0-example: minmax.pl0 */
/* computes the minimum and maximum of 3 numbers */
/* --- */
const a=15, b=7, c=10;
var min, max;
begin
if a<b then begin min:=a;
max:=b end;
if a>=b then begin min:=b;
max:=a end;
if c<min then min:=c;
if c>max then max:=c end.
Symboltabellen zu minmax.pl0
Symboltabelle zum Zeitpunkt der Übersetzung des Hauptprogramm-Rumpfes. Da es keine Un- terprogramme gibt, gibt es nur einen Zustand der Symboltabelle:
--- Symbol Table for block Main :
index name kind level addr size --- 1 a constObj 15
2 b constObj 7 3 c constObj 10
4 min varObj 0 3 5 max varObj 0 4
4 Erzeugter Zwischencode zu minmax.pl0
L0 : JPU L1 Sprung zum Rumpf des Hauptprogramms L1 : INC 5 DSA für das Hauptprogramm reservieren
L2 : LIT 15
if a<bL3 : LIT 7 L4 : LS
L5 : JPC L10
wenn nicht a<b, weiter zur Abfrage „if a>=b“L6 : LIT 15
min:=a;L7 : STO 0 , 3
L8 : LIT 7
max:=b;L9 : STO 0 , 4
L10 : LIT 15
ist a>=b ?L11 : LIT 7
L12 : GE
L13 : JPC L18
wenn nicht a>=b , weiter zur Abfrage „if c<min“L14 : LIT 7
min:=b;L15 : STO 0 , 3
L16 : LIT 15
max:=a;L17 : STO 0 , 4
L18 : LIT 10
ist c<min ?L19 : LOD 0 , 3
L20 : LS
L21 : JPC L24
wenn nicht c<min, weiter zur Abfrage „if c>max“L22 : LIT 10
min:=c;L23 : STO 0 , 3
L24 : LIT 10
c>max ?L25 : LOD 0 , 4
L26 : GT
L27 : JPC L30
wenn nicht c>max, weiter zum ProgrammendeL28 : LIT 10
max:=c;L29 : STO 0 , 4
L30 : RET Programmende
Quellprogramm faculty.pl0
/* PL/0-example: faculty.pl0 */
/* computes the faculty of a number */
/* --- */
const c=6;
var n,f;
procedure faculty;
var i;
begin f := 1;
i := 2;
while i<=n do begin
f := f*i;
i := i+1 end
end;
begin n := c;
call faculty;
end.
Symboltabellen zu faculty.pl0
1. Symboltabelle zum Zeitpunkt der Übersetzung des Rumpfes der procedure faculty ---
Symbol Table for block faculty :
index name kind level addr size --- 1 c constObj 6
2 n varObj 0 3 3 f varObj 0 4
4 faculty procObj 0 2 4 5 i varObj 1 3
2. Symboltabelle zum Zeitpunkt der Übersetzung des Hauptprogramm-Rumpfes --- Symbol Table for block Main :
index name kind level addr size --- 1 c constObj 6
2 n varObj 0 3 3 f varObj 0 4
4 faculty procObj 0 2 4
6
Erzeugter Zwischencode mit zusätzlichen Kommentaren
L0: JPU L21
Sprung zum Rumpf des Hauptprogramms L1: JPU L2 Sprung zum Rumpf des Unterprogramms L2: INT 4 DSA für das UP reservierenL3: LIT 1
"F:=1;"L4: STO 1,4
L5: LIT 2
"i:=2;"L6: STO 0,3
L7: LOD 0,3
"while i <= n do"L8: LOD 1,3 L9: LE
L10: JPC L20
falls while-Bedingung erfüllt, weiter mit „return“L11: LOD 1,4
"f:=f*i;L12: LOD 0,3 L13: MPY L14: STO 1,4
L15: LOD 0,3
"i:=i+1"L16: LIT 1 L17: ADD L18: STO 0,3
L19: JPU L7 Zurück zum Anfang der while-Schleife L20: RET Rückkehr aus dem Unterprogramm
L21: INT 5
DSA für das Hauptprogramm reservierenL22: LIT 6
"n:=c;"L23: STO 0,3
L24: CAL 0,L2
"call fak;"L25: RET
Ende des Hauptprogramms4. Aufgabe
In den Aufgaben der Übung 4 wurde die PL/0-Syntax um eine repeat-Anweisung erweitert.
Diese Erweiterung ist nun durch semantische Operationen zur Generierung von Postfixcode zu ergänzen.
− Skizzieren Sie an, welchen Aufbau der zu erzeugende Zwischencode haben muß.
− Fügen Sie die notwendigen semantischen Operationen zur Generierung dieses Code in den PL/0-Compiler ein
Struktur des Code für die reapeat-Anweisung
Rumpf der repeat-Anweisung
until-Bedingung auswerten
falls Bedingung nicht erfüllt, zurück zum Anfang des Anweisungsrumpfes
Code der nächsten Anweisung
Syntaxanalyse mit Zwischencodegenerierung case repeatSym:
fixup1 = cx;
getSym(); // get symbol after "while"
statement( followSymSet | UNTIL_ELSE, lev );
while (sym == semicolon) { getSym();
statement( followSymSet | UNTIL_ELSE, lev );
}
if (sym==untilSym) getSym(); // test if "until" is present else error(36);
condition(followSymSet,lev); // parse the until-condition generate (jpc, 0, fixup1);
break;
8
Beispiel einer Anweisungsfolge mit generiertem Zwischencode
const a=10, b=15;
var min, max, i, j, k;
...
min := 0;
max := 100;
...
repeat
min := min+a;
max := max-a until min>max;
L37 : LIT 0 min:=0;
L38 : STO 0 , 3
L39 : LIT 100 max:=100;
L40 : STO 0 , 4
L41 : LOD 0 , 3 min:=min+a;
L42 : LIT 10 L43 : ADD
L44 : STO 0 , 3
L45 : LOD 0 , 4 max:=max-a;
L46 : LIT 10 L47 : SUB
L48 : STO 0 , 4
L49 : LOD 0 , 3 min>max ? L50 : LOD 0 , 4
L51 : GT
L52 : JPC L41 wenn nein, dann zurück zum Beginn des Anw.-Rumpfes
5. Aufgabe
In den Aufgaben der Übung 4 wurde die if-then-Anweisung der PL/0-Syntax um eine else- Alternative erweitert und der Parser entsprechend erweitert. Diese Erweiterung ist nun durch semantische Operationen zur Generierung von Postfixcode zu ergänzen.
− Geben Sie an, welchen Aufbau der zu erzeugende Zwischencode haben muß.
− Fügen Sie die notwendigen semantischen Operationen zur Generierung dieses Code in den PL/0-Compiler ein
Struktur des Code für if <condition> then <statement1> else <statement2>
Code zur Auswertung der condition
jump on false L1
Code zur Auswertung des statement1
jump L2
Code zur Auswertung des statement2
nachfolgender Code L1:
L2:
10 Syntaxanalyse mit Zwischencodegenerierung case ifSym:
getSym(); // analysze condition condition( STAT_START | IDENT | DO_THEN_OF, lev );
if (sym==thenSym) getSym();
else error(16);
fixup1 = cx;
generate (jpc, 0, 0);
statement(followSymSet | UNTIL_ELSE, lev);
if (sym==elseSym) {
fixup2 = cx; // generate jump over "else" part generate (jpu, 0, 0);
code[fixup1].a = cx; // update jump of the then-part getSym(); // proceed to the else-statement statement(followSymSet, lev);
code[fixup2].a = cx; // update jump of the "else" part }
else // if there is no else alternative code[fixup1].a = cx; // generate jump over "else" part break;
Beispiel einer if ... then ... else ... -Anweisung mit generiertem Zwischencode
const a=10, b=15;
var min, max, i, j, k;
...
if a > b then begin
min := b;
max := a end
else begin
min := a;
max := b end;
L53 : LIT 10 a>b ? L54 : LIT 15
L55 : GT
L56 : JPC L62 wenn nein, weiter beim else-Zweig L57 : LIT 15 min:=b;
L58 : STO 0 , 3
L59 : LIT 10 max:=a;
L60 : STO 0 , 4
L61 : JPU L66 fertig, Sprung zur nächsten Anweisung L62 : LIT 10 min:=a;
L63 : STO 0 , 3
L64 : LIT 15 max:=b;
L65 : STO 0 , 4
L66 : ... nächste Anweisung
6. Aufgabe
In den Aufgaben der Übung 4 wurde die PL/0-Syntax um eine case-Anweisung erweitert. Die- se Erweiterung ist nun durch semantische Operationen zur Generierung von Postfixcode zu er- gänzen.
− Geben Sie an, welchen Aufbau der zu erzeugende Zwischencode haben muß.
− Fügen Sie die notwendigen semantischen Operationen zur Generierung dieses Code in den PL/0-Compiler ein
Struktur des Code für die case-Anweisung:
expr auswerten und retten
Liegt Alternative 1 vor ? wenn nein, weiter bei L0
Code für die 1. Alternative
jump Lx
Liegt Alternative 2 vor ? wenn nein, weiter bei L1
Code für die 2. Alternative
jump Lx
...
L0:
L1:
case expr end
: statement
; of
number
12 Syntaxanalyse mit Zwischencodegenerierung case caseSym:
// create internal variable for the case expression for (i=0;i<CMAX;i++) id[i] = ' '; id[CMAX]='\0';
strncpy(id, "$switch", 7);
tx++; // increment symbol table index symTable[tx].kind = varObj; // object type --> table entry strcpy(symTable[tx].name, id);
symTable[tx].level = lev; // declaration level symTable[tx].size = 1; // variable size
generate (inc,0,1); // save area for switch value sx=tx; // remember symbol table index getSym(); // get next symbol after "case"
// analyze switch expression and generate STO-operation // to bring the result into $switch
expression( followSymSet | DO_THEN_OF, lev );
generate (sto,0,symTable[sx].addr); //save switch value if (sym == ofSym) getSym(); // test if "of" is present else error(37);
fx=0; // index for fixup vector = 0 while (sym == number) // loop for all cases
{
// Generate test for this case alternative generate (lit, 0,num);
generate (lod, 0, symTable[sx].addr);
generate (eq,0,0);
fixup1 = cx;
generate (jpc,0,0);
getSym(); // read next token
if(sym==colon) getSym(); // test if ":" is present else error(34);
statement(followSymSet, lev);
fixup_vector[fx++] = cx; // prepare JPU to the end generate (jpu,0,0);
code[fixup1].a = cx; // update JPC for this alternative if(sym==semicolon) getSym();// test if ";" is present else error(5);
}
if (sym == endSym) getSym(); // test if "end" is present else error(17);
for (i=0; i<fx; i++) // update JPU at end of each alternative code[fixup_vector[i]].a = cx;
break;
Beispiel einer case -Anweisung mit generiertem Zwischencode const a=10, b=15;
var min, max, i, j, k;
...
case a+b of
15 : min:=0;
20 : min:=1;
25 : begin min:=2;
max:=3;
end;
30 : max:=4;
end;
L2 : INC 1 Platz für switch-Kriterium auf dem Datenstack reservieren L3 : LIT 10 Kriterium a+b berechnen
L4 : LIT 15 L5 : ADD
L6 : STO 0 , 8 und auf dem Stack sichern L7 : LIT 15 Kriterium = 15 ?
L8 : LOD 0 , 8 L9 : EQ
L10 : JPC L14 Falls nein, weiter zum nächsten Kriterium L11 : LIT 0 min:=0;
L12 : STO 0 , 3
L13 : JPU L37 fertig, zur nächsten Anweisung springen L14 : LIT 20 Kriterium = 20 ?
L15 : LOD 0 , 8 L16 : EQ
L17 : JPC L21 Falls nein, weiter zum nächsten Kriterium L18 : LIT 1 min:=1;
L19 : STO 0 , 3
L20 : JPU L37 fertig, zur nächsten Anweisung springen L21 : LIT 25 Kriterium=25 ?
L22 : LOD 0 , 8 L23 : EQ
L24 : JPC L30 Falls nein, weiter zum nächsten Kriterium L25 : LIT 2 min:=2;
L26 : STO 0 , 3
L27 : LIT 3 max:=3;
L28 : STO 0 , 4
L29 : JPU L37 fertig, zur nächsten Anweisung springen L30 : LIT 30 Kriterium = 30 ?
L31 : LOD 0 , 8 L32 : EQ
L33 : JPC L37 Falls nein, weiter zur nächsten Anweisung L34 : LIT 4 max:=4;