6.3 Jumping Code for Boolean Expressions
6.3.4 Conditional expressions
It is possible to use the jumping code mechanism developed so far to generate efficient code for conditional expressions. If the expression occurs in a context in which its value is required, the translation procedure would be similar to
110 CHAPTER 6. TRANSLATING BOOLEAN EXPRESSIONS
let TranBoolExpr(nodep, regno, Tlabel, Flabel, nojump) be
{ switchon nodep.type into
{ case ‘and’:
TranAnd(nodep, regno, Tlabel, Flabel, nojump); endcase
case ‘or’:
TranOr(nodep, regno, Tlabel, Flabel, nojump); endcase
case ‘not’:
TranNot(nodep, regno, Tlabel, Flabel, nojump); endcase
case ‘<’:
TranRelation(LT, nodep, regno, Tlabel, Flabel, nojump)
endcase case ‘<=’:
TranRelation(LE, nodep, regno, Tlabel, Flabel, nojump)
endcase
....
case name, FuncCall, VecAccess, (etc.): TranArithExpr(nodep, regno)
if nojump=‘true’ then Gen(JUMPFALSE, regno, Flabel)
else Gen(JUMPTRUE, regno, Tlabel)
endcase case ‘true’:
if nojump\=‘true’ then Gen(JUMP, 0, Tlabel)
endcase case ‘false’:
if nojump\=‘false’ then Gen(JUMP, 0, Flabel)
endcase
default: CompilerFail("invalid node in TranBoolExpr")
} }
6.3. JUMPING CODE FOR BOOLEAN EXPRESSIONS 111
Source: test -> firstexpr, secondexpr
let TranCondExpr(nodep, regno, Tlabel, Flabel, nojump) be
{ let Lt, Lf = newlabel(), newlabel()
TranBoolExpr(nodep.test, regno, Lt, Lf, ‘true’)
/* if the test in the conditional expression evaluates to * true, evaluate the expression after the arrow
*/
define(Lt)
TranBoolExpr(nodep.firstexpr, regno, Tlabel, Flabel, nojump)
/* and if control exits from that expression, execute * a jump to either Tlabel or Flabel
*/
Gen(JUMP, 0, (nojump=‘true’ -> Tlabel, Flabel)) /* if the test is false, evaluate the expression
* after the comma */
define(Lf)
TranBoolExpr(nodep.secondexpr, regno, Tlabel, Flabel, nojump)
}
112 CHAPTER 6. TRANSLATING BOOLEAN EXPRESSIONS the procedure which translates a conditional statement, shown in figure 6.5 above. Where a conditional expression is used in a conditional context, the procedure might be as shown in figure 6.10. It would be easy to incorporate both approaches into a single procedure which was informed of the context and selected its strategy accordingly – I haven’t done so here in the interests of clarity.
Summary
This chapter demonstrates the clarity with which quite complicated translation algorithms can be expressed in terms of tree walking. By applying a simple mechanism recursively to every node of a Boolean expression, it is possible to produce code which executes a minimum of instructions in order to discover if the expression has the valuetrueor the valuefalse.
The mechanisms presented in chapter 5 and in this chapter form a solid base for the development of a translator. An enormous proportion of the object code fragments are concerned with calculation of values and with selecting paths of control through the program. If efficient code fragments can be generated for these crucial source program fragments and for the related fragments which perform data structure access (chapter 9), non-local data access and procedure call (section III) then an acceptably efficient object program is assured.
Chapter 7
Translating Statements and
Declarations
Chapters 5 and 6 show the tree-walking mechanism to its best advantage, work- ing on the translation of source program constructs whose efficient implemen- tation is crucial to the efficiency of the object program. Code fragments for statements are rarely so crucial, particularly when the expressions which they contain are efficiently translated. This chapter therefore shows example proce- dures which translate statements by linking together the code fragments dis- cussed in chapters 5, 6 and 9 and in section III.
Most declarations in a program translate into sections of code. Various chapters below discuss the translation of different declarations: record and array decla- rations are discussed in chapters 9 and 11, procedure declarations throughout section III. This chapter shows how the translation of a block or a procedure declaration links statement and declaration fragments together into a complete program.
7.1
Assignment Statement
Chapter 5 shows how to translate an arithmetic expression and chapter 9 shows how to generate code which calculates the address of an element of an array. Fig- ure 7.1 shows ‘TranAssignStat’ and ‘TranAddress’ procedures which use these techniques in translating an assignment statement. I assume (see chapter 9) that the ‘TranVecAccess’ procedure assigns values to two global variables ‘Address’ and ‘Modifier’ whose values can be used in the STORE instruction. To sim- plify the TranAssignStat procedure I haven’t shown the actions which it must carry out when evaluation of the left-hand-side expression requires all the reg- isters and I have assumed a source language which permits the right-hand-side expression to be evaluated before the left-hand-side.
114 CHAPTER 7. TRANSLATING STATEMENTS AND DECLARATIONS
let TranAssignStat(nodep) be
{ let lhs, rhs = nodep.left, nodep.right
let rhszero = false
/* if rhs is zero, don’t evaluate it */
if ZeroConst(rhs) then rhszero := true else TranArithExpr(rhs, 1)
/* store value in object denoted by lhs */ TranAddress(lhs, 2)
if rhszero then Gen(STOZ, 0, Address, Modifier)
else Gen(STORE, 1, Address, Modifier)
}
let TranAddress(nodep, regno) be if nodep.type=name then
Address, Modifier := nodep.descriptor.address, 0
elsf nodep.type=VecAccess then
TranVecAccess(nodep, regno) /* see chapter 9 */
else
CompilerFail("invalid node in TranAddress")
7.1. ASSIGNMENT STATEMENT 115
(i) Statement: x := x+1 Tree: AssignStat
x +
x 1
Code: LOAD 1, x ADDn 1, 1 STORE 1, x
(ii) Statement: A[i] := j*k Tree: AssignStat
VecAccess + j k A i Code: LOAD 1, j MULT 1, k LOAD 2, i ADD 2, #A0
STORE 1, 0(2) /* see chapter 9 */
(iii) Statement: x := 0 Tree: AssignStat
x 0
Code: ST0Z , x
116 CHAPTER 7. TRANSLATING STATEMENTS AND DECLARATIONS
let TranWhileStat(nodep) be
{ let Restart, Lt, Lf = newlabel(), newlabel(), newlabel()
let OldLoop, OldBreak = LoopLabel, BreakLabel
define(Restart) /* ‘Restart’ is beginning of expression */ TranBoolExpr(nodep.expr, 1, Lt, Lf, ‘true’)
/* execute statement if expression is true
* allow loop and break statements within it * jump to re-evaluate expression afterwards */
LoopLabel, BreakLabel := Restart, Lf define(Lt)
TranStatement(nodep.stat) Gen(JUMP, 0, Restart)
/* avoid execution of statement when expression is false
* reset loop and break indicators */
LoopLabel, BreakLabel := OldLoop, OldBreak define(Lf)
}
Figure 7.3: Translating a ‘while’ statement
Figure 7.2 shows samples of the code which this procedure would generate. It recognises an assignment statement whose right-hand-side expression is the con- stant zero and generates a special code fragment for it: it would be fairly simple to make the procedure recognise the other sub-optimisations illustrated in figure 2.12. Even without such improvements, the code produced by TranAssignStat is quite respectable. The discussion of TranVecAccess in chapter 9, however, shows some deficiencies in the code which is produced for an assignment state- ment such as
A[i-1] := A[i+5]
which makes more than one access to a vector: it would require the code optimi- sation techniques discussed in chapter 10 to make any significant improvement in this case.
7.2
‘While’ Statement
Figure 6.5 shows how to translate a conditional (if-then-else) statement given a TranBoolExpr procedure which generates ‘jumping code’ for the expression
7.2. ‘WHILE’ STATEMENT 117
Statement: while a>b | x<y do <statement S> Code: %R: LOAD 1, a SKIPLE 1, b JUMP , %t LOAD 1, x SKIPLT 1, y JUMP , %f %t: .... <statement S> .... JUMP , %R %f: ....
Figure 7.4: Code generated for a ‘while’ statement
let TranLoopStat(nodep) be TranEscape(LoopLabel)
let TranBreakStat(nodep) be TranEscape(BreakLabel)
let TranEscape(label) be if label=empty then
Error("escape statement occurs outside loop")
else
Gen(JUMP, 0, label)
Figure 7.5: Translating ‘break’ and ‘loop’ statements
let TranStatement(nodep) be switchon nodep.type into
{ case AssignStat: TranAssignStat(nodep); endcase case WhileStat: TranWhileStat(nodep); endcase case ForStat: TranForStat(nodep); endcase case GoToStat: TranGotoStat(nodep); endcase
....
default: CompilerFail("invalid node in TranStatement")
}
118 CHAPTER 7. TRANSLATING STATEMENTS AND DECLARATIONS part of the statement. Exactly the same mechanism can be used in translating a conditional iteration statement: figure 7.3 shows a ‘TranWhileStat’ procedure which does just this. Figure 7.4 shows the unremarkable code which it generates. Figure 7.3 also shows, together with the TranLoopStat procedure of figure 7.5, how the use of global variables ‘LoopLabel’ and ‘BreakLabel’ can implement the BCPL loopand breakstatements, which allow premature repetition and termination of the iterative statement within which they are contained. Aloop
statement will transfer control to the label ‘Restart’ which re-evaluates the expression, a break statement to the label ‘Lf’ which provides exit from the
whilestatement as a whole. By saving the values of these variables and resetting them after the statement has been translated, TranWhileStat allows the use of
loopandbreakstatements in nested loops. The code for the escape statements is a single JUMP instruction – it can be so simple because of the mechanism used to handle the BCPL stack, discussed in chapter 14.
The ‘TranStatement’ procedure, part of which is shown in figure 7.6, is a ‘switch’ procedure like TranArithExpr in chapter 5 or TranBoolExpr in chapter 6. It merely inspects the ‘type’ field of a statement node and calls the relevant statement-translating procedure.