You are here
2
Executable
code
exe
Source
text
txt
Compiler
Lexica
lA
naly
sis
Syn
tax
An
aly
sis
Sem
an
ticA
naly
sis
Inte
r.R
ep
. (IR)
Cod
e
Gen
.
chara
cters
toke
ns A
ST
(Abstra
ct Synta
x Tre
e)
An
nota
ted
AS
T
3
GENERIC
Intermediate Representation• “neutral” representation between the front-end and the back-
end– Abstracts away details of the source language– Abstract away details of the target language
• A compiler may have multiple intermediate representations and move between them
Java C Objective CAda
arm x86 ia64 …
…
5
Example: Annotated AST
• makeNode – creates new node for unary/binary operator
• makeLeaf – creates a leaf• id.place – pointer to symbol table
production semantic rule
S id := E➞ S.nptr = makeNode(‘assign’, makeLeaf(id,id.place), E.nptr)
E E1 + E2 ➞ E.nptr = makeNode(‘+’,E1.nptr,E2.nptr)
E E1 * E2➞ E.nptr = makeNode(‘*’,E1.nptr,E2.nptr)
E -E1➞ E.nptr = makeNode(‘uminus’,E1.nptr)
E (E1) ➞ E.nptr = E1.nptr
E id➞ E.nptr = makeLeaf(id,id.place)
6
Example
* *
uminus uminus
cid cid
bid bid
assign
+
aid
b id 0
c id 1
1 uminus 2
2 0 * 3
b id 4
c id 5
5 uminus 6
6 4 * 7
7 3 + 8
a id 9
8 9 assign 10
· · · 11
a = b * -c + b* -c
7
Three Address Code (3AC)
• Every instruction operates on three addresses– result = operand1 operator operand2
• Close to low-level operations in the machine language – Operator is a basic operation
• Statements in the source language may be mapped to multiple instructions in three address code
8
Three address code: example
assign
a +
*
b uminus
c
*
b uminus
c
t5:=at2 + t4:=t5
b * t3:=t4
– c:=t3
b * t1:=t2
– c:=t1
9
Three address code: example instructions
instruction meaning
x := y op z assignment with binary operator
x := op y assignment unary operator
x:= y assignment
x := &y assign address of y
x:=*y assignment from deref y
*x := y assignment to deref x
instruction meaning
goto L unconditional jump
if x relop y goto L conditional jump
10
Array operations
• Are these 3AC operations?
t1 := &y ; t1 = address-of yt2 := t1 + i ; t2 = address of y[i]X := *t2 ; value stored at y[i]
t1 := &x ; t1 = address-of xt2 := t1 + i ; t2 = address of x[i]*t2:= y ; store through pointer
x := y[i]
x[i] := y
11
Three address code: exampleint main(void) {
int i;
int b[10];
for (i = 0; i < 10; ++i)
b[i] = i*i;
}
i := 0 ; assignmentL1: if i >= 10 goto L2 ; conditional jump t0 := i*i t1 := &b ; address-of operation t2 := t1 + i ; t2 holds the address of b[i] *t2 := t0 ; store through pointer i := i + 1 goto L1L2:
(example source: wikipedia)
12
Three address code
• Choice of instructions and operators affects code generation and optimization
• Small set of instructions– Easy to generate machine code– Harder to optimize
• Large set of instructions– Harder to generate machine code
• Typically prefer small set and smart optimizer
13
Creating 3AC
• Assume bottom up parser– Covers a wider range of grammars– LALR sufficient to cover most programming languages
• Creating 3AC via syntax directed translation• Attributes examples:
– code – code generated for a nonterminal– var – name of variable that stores result of nonterminal
• freshVar() – helper function that returns the name of a fresh variable
14
Creating 3AC: expressions
production semantic rule
S id := E➞ S.code := E. code || gen(id.var ‘:=‘ E.var)
E E1 + E2➞ E.var := freshVar(); E.code = E1.code || E2.code || gen(E.var ‘:=‘ E1.var ‘+’ E2.var)
E E1 * E2➞ E.var := freshVar(); E.code = E1.code || E2.code || gen(E.var ‘:=‘ E1.var ‘*’ E2.var)
E - E1➞ E.var := freshVar(); E.code = E1.code || gen(E.var ‘:=‘ ‘uminu’ E1.var)
E (E1)➞ E.var := E1.varE.code = ‘(‘ || E1.code || ‘)’
E id➞ E.var := id.var; E.code = ‘’
(we use || to denote concatenation of intermediate code fragments)
15
example
assign
a+
*
b uminus
c
*
b uminus
c
E.var = cE.code =‘’
E.var = bE.code =‘’
E.var = t2E.code =‘t1 = -c t2 = b*t1’
E.var = t1E.code =‘t1 = -c’
E.var = bE.code =‘’
E.var = cE.code =‘’
E.var = t3E.code =‘t3 = -c’
E.var = t4E.code =‘t3 = -c t4 = b*t3’
E.var = t5E.code =‘t1 = -c t2 = b*t1 t3 = -c t4 = b*t3 t5 = t2+t4’
a = b * -c + b* -c
16
Creating 3AC: control statements
• 3AC only supports conditional/unconditional jumps
• Add labels • Attributes
– begin – label marks beginning of code– after – label marks end of code
• Helper function freshLabel() allocates a new fresh label
17
Creating 3AC: control statements
S while E do S1
production semantic rule
S while E do S1 S.begin := freshLabel();S.after = freshLabel();S.code := gen(S.begin ‘:’) || E.code || gen(‘if’ E.var ‘=‘ ‘0’ ‘goto’ S.after) || S1.code || gen(‘goto’ S.begin) || gen(S.after ‘:’)
E.codeS.begin
:
if E.var = 0 goto S.after
S1.code
goto S.begin
· · · S.after:
18
Representing 3AC• Quadruple (op,arg1,arg2,result)• Result of every instruction is written into a new temporary variable• Generates many variable names• Can move code fragments without complicated renaming• Alternative representations may be more compact
at5:=(5)
t5t4t2+(4)
t4t3b*(3)
t3cuminus(2)
t2t1b*(1)
t1cuminus(0)
resultarg 2arg 1opt1 = - ct2 = b * t1
t3 = - ct4 = b * t3
t5 = t2 * t4
a = t5
19
Allocating Memory
• Type checking helped us guarantee correctness• Also tells us
– How much memory allocate on the heap/stack for varaibles
– Where to find fields (based on lengths)– Compute address of an element inside array (size of
stride based on type of element)
20
Allocating Memory
• Global variable “offset” with memory allocated so far
production semantic rule
P D➞ { offset := 0}
D D D➞
D T id;➞ { enter(id.name, T.type, offset); offset += T.width }
T integer➞ { T.type := int; T.width = 4 }
T float ➞ { T.type := float; T.width = 8}
T T1[num]➞ { T.type = array (num.val,T1.Type); T.width = num.val * T1.width; }
T *T1➞ { T.type := pointer(T1.type); T.width = 4}
Allocating MemoryP
D2D1
D4
T1 id
int count
T2 id
float money
D5
T3 id
balancesT4 [ num ]
int 42T2.type = floatT2.width = 4
id.name = money
T1.type = intT1.width = 4
id.name = count
enter(count, int, 0) offset = offset + 4
enter(money, float, 4) offset = offset + 4
D6
22
Adjusting to bottom-up
production semantic rule
P ➞ M D
M ➞ { offset := 0}
D D D➞
D T id;➞ { enter(id.name, T.type, offset); offset += T.width }
T integer➞ { T.type := int; T.width = 4 }
T float ➞ { T.type := float; T.width = 8}
T T1[num]➞ { T.type = array (num.val,T1.Type); T.width = num.val * T1.width; }
T *T1➞ { T.type := pointer(T1.type); T.width = 4}
Allocating Memory
P
D2D1
D4
T1 id
int count
T2 id
float money
D5
T3 id
balancesT4 [ num ]
int 42T1.type = intT1.width = 4
id.name = count
enter(count, int, 0) offset = offset + 4
D6M
offset = 0
24
Generating IR code
• Option 1 accumulate code in AST attributes
• Option 2emit IR code to a file during compilation– If for every production the code of the left-hand-side is
constructed from a concatenation of the code of the RHS in some fixed order
25
Expressions and assignments
production semantic action
S id := E➞ { p:= lookup(id.name); if p ≠ null then emit(p ‘:=‘ E.var) else error }
E E1 op E2➞ { E.var := freshVar(); emit(E.var ‘:=‘ E1.var op E2.var) }
E - E1➞ { E.var := freshVar(); emit(E.var ‘:=‘ ‘uminus’ E1.var) }
E ( E1)➞ { E.var := E1.var }
E id➞ { p:= lookup(id.name); if p ≠ null then E.var :=p else error }
26
Boolean Expressions
production semantic action
E E1 op E2➞ { E.var := freshVar(); emit(E.var ‘:=‘ E1.var op E2.var) }
E not E1➞ { E.var := freshVar(); emit(E.var ‘:=‘ ‘not’ E1.var) }
E ( E1)➞ { E.var := E1.var }
E true➞ { E.var := freshVar(); emit(E.var ‘:=‘ ‘1’) }
E false➞ { E.var := freshVar(); emit(E.var ‘:=‘ ‘0’) }
• Represent true as 1, false as 0• Wasteful representation, creating variables for true/false
27
Boolean expressions via jumps
production semantic action
E id1 op id2➞ { E.var := freshVar(); emit(‘if’ id1.var relop id2.var ‘goto’ nextStmt+2);emit( E.var ‘:=‘ ‘0’);emit(‘goto ‘ nextStmt + 1);emit(E.var ‘:=‘ ‘1’)}
This is useful for short circuit evaluation. Let us start with an example.
29
Boolean Expressions: an Example
E
E E
a < b
or
E
c < d
E
e < f
and
if a < b goto 103 100:T1 := 0 101:goto 104 102:T1 := 1 103:
30
Boolean Expressions: an Example
E
E E
a < b
or
E
c < d
E
e < f
and
if a < b goto 103 100:T1 := 0 101:goto 104 102:T1 := 1 103:
if c < d goto 107 104:T2 := 0 105:goto 108 106:T2 := 1 107:
31
Boolean Expressions: an Example
E
E E
a < b
or
E
c < d
E
e < f
and
if a < b goto 103 100:T1 := 0 101:goto 104 102:T1 := 1 103:
if c < d goto 107 104:T2 := 0 105:goto 108 106:T2 := 1 107:
if e < f goto 111 108:T3 := 0 109:goto 112 110:T3 := 1 111:
112:
32
Boolean Expressions: an Example
E
E E
a < b
or
E
c < d
E
e < f
and
if a < b goto 103 100:T1 := 0 101:goto 104 102:T1 := 1 103:
if c < d goto 107 104:T2 := 0 105:goto 108 106:T2 := 1 107:
if e < f goto 111 108:T3 := 0 109:goto 112 110:T3 := 1 111:
112:113:T4 := T2 and T3
33
Boolean Expressions: an Example
E
E E
a < b
or
E
c < d
E
e < f
and
if a < b goto 103 100:T1 := 0 101:goto 104 102:T1 := 1 103:
if c < d goto 107 104:T2 := 0 105:goto 108 106:T2 := 1 107:
if e < f goto 111 108:T3 := 0 109:goto 112 110:T3 := 1 111:
112:113:T4 := T2 and T3
T5 := T1 or T4
34
Short circuit evaluation
• Second argument of a boolean operator is only evaluated if the first argument does not already determine the outcome
• (x and y) is equivalent to: “if x then y else false”;• (x or y) is equivalent to: “if x then true else y”;
• Is short circuit evaluation equivalent to standard evaluation?
• We use it if the language definition dictates its use.
35
More examples
int denom = 0;if (denom && nom/denom) { oops_i_just_divided_by_zero();}
if ( (file=open(“c:\grades”) or (die) ) printfile(file,…);
36
Our previous examplea < b or (c<d and e<f)
100: if a < b goto 103101: T1 := 0102: goto 104103: T1 := 1104: if c < d goto 107105: T2 := 0106: goto 108107: T2 := 1108: if e < f goto 111109: T3 := 0110: goto 112111: T3 := 1112: T4 := T2 and T3
113: T5 := T1 and T4
100: if a < b goto 105101: if !(c < d) goto 103102: if e < f goto 105103: T := 0104: goto 106105: T := 1106:
naive Short circuit evaluation
Control Structure: if, else, while.
• Consider the conditional jumps:
• One option is to create code for B, create code for S, and then create a jump to the beginning of S or the end of S according to B’s value.
• But it would be more efficient to create code that while executing B will jump to the correct location immediately when the value of B is discovered.
if B then S1
if B then S1 else S2
while B do S1
S →
||
Control Structure: if, else, while. • The problem is that we do not know where to jump to…• While parsing B’s tree for “if B then S”, we don’t know S’s
code and where it starts or ends. Yet, we must generate jumps to these locations.
• Solution: for each expression B keep labels: B.trueLabel and B.falseLabel. We jump to these labels when B’s value is true or false correspondingly.
• Also, for each statement S, we have a label S.nextLabel which keeps the address of the code that follows the statement S.
S
if B then S
•The semantic equation will be B.false = S.next .
•For B.true, we create a new label between B’s code and S’s code .
next התכונה• While parsing statement S, generate the code with its
next label.
• The attribute S.next is inherited: the child gets it. • The attribute code is generated: the parent gets it. • The label S.next is symbolic. The address will only be
known after we parse S.
production semantic action
P S S.next = freshLabel();P.code = S.code || label(S.next)
S S1 S2 S1.next = freshLabel();S2.next = S.next;S.code = S1.code || label(S1.next) || S2.code
40
Control Structures: conditional
production semantic actionS if B then S1 B.trueLabel = freshLabel();
B.falseLabel = S.next;S1.next = S.next;S.code = B.code || gen (B.trueLabel ‘:’) || S1.code
Are S1.next, B.falseLabel inherited or synthesized? Is S.code inherited or synthesized?
41
Control Structures: conditional
production semantic action
S if B then S1 else S2
B.trueLabel = freshLabel();B.falseLabel = freshLabel();S1.next = S.next;S2.next = S.next;S.code = B.code || gen(B.trueLabel ‘:’) || S1.code || gen(‘goto’ S.next) || gen(B.falseLabel ‘:’) || S2.code
B.trueLabel and B.falseLabel considered inherited
42
S if B then S1 else S2
B.code
S1.code
goto S.next
S2.code
…
B.trueLabel:
B.falseLabel:S.next:
B.trueLabel = freshLabel();B.falseLabel = freshLabel();S1.next = S.next;S2.next = S.next;S.code = B.code || gen(B.trueLabel ‘:’) || S1.code || gen(‘goto’ S.next) || gen(B.falseLabel ‘:’) || S2.code
43
Boolean expressions
production semantic action
B B1 or B2 B1.trueLabel = B.trueLabel; B1.falseLabel = freshLabel(); B2.trueLabel = B.trueLabel; B2.falseLabel = B.falseLabel;B.code = B1.code || gen (B1.falseLabel ‘:’) || B2.code
B B1 and B2 B1.trueLabel = freshLabel(); B1.falseLabel = B.falseLabel;B2.trueLabel = B.trueLabel; B2.falseLabel = B.falseLabel;B.code = B1.code || gen (B1.trueLabel ‘:’) || B2.code
B not B1 B1.trueLabel = B.falseLabel; B1.falseLabel = B.trueLabel; B.code = B1.code;
B (B1) B1.trueLabel = B.trueLabel; B1.falseLabel = B.falseLabel; B.code = B1.code;
B id1 relop id2 B.code=gen (‘if’ id1.var relop id2.var ‘goto’ B.trueLabel)||gen(‘goto’ B.falseLabel);
B true B.code = gen(‘goto’ B.trueLabel)
B false B.code = gen(‘goto’ B.falseLabel);
Generate code that jumps to B.trueLabel if B’s value is true and to B.falseLabel if B’s value is false.
44
Boolean expressions
• How can we determine the address of B1.falseLabel?
• Only possible after we know the code of B1 and all the code preceding B1
production semantic action
B B1 or B2 B1.trueLabel = B.trueLabel; B1.falseLabel = freshLabel();B2.trueLabel = B.trueLabel;B.falseLabel = B.falseLabel;B.code = B1.code || gen (B1.falseLabel ‘:’) || B2.code
45
Example
S
if B then S1
B1 B2and
falsetrue
B1.trueLabel = freshLabel();B1.falseLabel = B.falseLabel;B2.trueLabel = B.trueLabel;B2.falseLabel = B.falseLabel;B.code = B1.code || gen (B1.trueLabel ‘:’) || B2.code
B.code = gen(‘goto’ B1.trueLabel)
B.code = gen(‘goto’ B2.falseLabel)
46
Example
S
if B then S1
B1 B2and
falsetrue
B.trueLabel = freshLabel();B.falseLabel = S.next;S1.next = S.next;S.code = B.code || gen (B.trueLabel ‘:’) || S1.code
B1.trueLabel = freshLabel();B1.falseLabel = B.falseLabel;B2.trueLabel = B.trueLabel;B2.falseLabel = B.falseLabel;B.code = B1.code || gen (B1.trueLabel ‘:’) || B2.code
B.code = gen(‘goto’ B1.trueLabel)
B.code = gen(‘goto’ B2.falseLabel)
47
Computing the labels
• We can build the code while parsing the tree bottom-up, leaving the jump targets vacant.
• We can compute the values for the labels in a second traversal of the AST
• Can we do it in a single pass?
48
So far…
• Three address code.• Intermediate code generation is executed with parsing (via
semantic actions). • Creating code for Boolean expressions and for control
statements is more involved. • We typically use short circuit evaluation, value of
expression is implicit in control location. • We need to compute the branching addresses.• Option 1: compute them in a second AST pass.
49
Backpatching (תיקון לאחור)
• Goal: generate code in a single pass
• Generate code as we did before, but manage labels differently
• Keep targets of jumps empty until values are known, and then back-patch them
• New synthesized attributes for B– B.truelist – list of jump instructions that eventually get
the label where B goes when B is true.– B.falselist – list of jump instructions that eventually get
the label where B goes when B is false.
50
Backpatching
• For every label, maintain a list of instructions that jump to this label
• When the address of the label is known, go over the list and update the address of the label
• Previous solutions do not guarantee a single pass– The attribute grammar we had before is not S-attributed
(e.g., next is inherited), and is not L-attributed (because the inherited attributes are not necessarily from left siblings).
Why is it difficult?
• Think of an if-then-else statement. • To compute S1.next, we need to know the code of all
blocks S1, B, S2, in order to compute the address that follows them.
• On the other hand, to compute the code of S1, we need to know S1.next, or S.next, which is not known before S1 is computed.
• So we cannot compute S1’s code with all jump targets, but we can compute it up to “leaving space” for future insertion of S1.next.
• Using backpatching we maintain a list of all empty spaces that need to jump to S1.next.
• When we know S1.next, we go over this list and update the jump targets with S1.next’s value.
if B
S
then elseS1 S2
52
Functions for list handling
• makelist(addr) – create a list of instructions containing addr
• merge(p1,p2) – concatenate the lists pointed to by p1 and p2, returns a pointer to the new list
• backpatch(p,addr) – inserts i as the target label for each of the instructions in the list pointed to by p
Accumulating the code
• Assume a bottom-up parsing so that the code is created in the correct order from left to right, bottom-up.
• The semantic analysis is actually executed during parsing and the code is accumulated.
• Recall that we associated two labels B.trueLabel and B.falseLabel for each expression B, which are the labels to which we should jump if B turns out true or false.
• We will now replace these with two lists B.truelist and B.falselist, which record all instructions that should be updated with the address of B.trueLabel or B.falseLabel when we discover their values.
• In addition, we also replace S.next with S.nextlist, maintaining all instructions that should jump to S.next, when we know what it is.
Accumulating Code (cont’d)
• B.truelist and B.falselist are generated attributes: the descendants tell the parent where there is code to fix.
• When ascending to the parent of B, we know what are the relevant addresses and we can backpatch them into all the instruction locations that are in the list.
• Similarly for S.nextlist.• We will need a function nextinstr() that retruns
the address of the next instruction.
Computing Boolean expressions • Recall the code jumps to B.true ot B.false according to B’s
value.• Previously:
• Now with backpatching:
{ B.code := gen ( ' if ' id1.var relop.op id2.var ' goto ' B.true ) ||
gen ( ' goto ' B.false ) }
B → id1 relop id2
{ B.code := gen ( ' goto ' B.true ) } B → true
{ B.code := gen ( ' goto ' B.false ) } B → false
{ B.truelist := makelist ( nextinstr ) ; B.falselist := makelist ( nextinstr + 1 ) ; emit ( ' if ' id1.var relop.op id2.var ' goto_ ' ) || emit ( ' goto_ ' ) }
B → id1 relop id2
{ B.truelist := makelist ( nextinstr ) ; emit ( ' goto_ ' ) } B → true{ B.falselist := makelist ( nextinstr ) ; emit ( ' goto_ ' ) } B → false
Computing Boolean expressions• Recall the code jumps to B.true ot B.false according to B’s
value.• Previously:
• Now with backpatching:
{ B1.true := B.false ; B1.false := B.true ; B.code := B1.code } B → not B1
{ B1.true := B.true ; B1.false := B.false ; B.code := B1.code } B → ( B1 )
{ B.truelist := B1.falselist ; B.falselist := B1.truelist } B → not B1
{ B.truelist := B1.truelist ; B.falselist := B1.falselist } B → ( B1 )
Computing Boolean expressions• Recall the code jumps to B.true ot B.false according to B’s
value.• Previously:
• Now with backpatching:
{ B1.true := B.true ; B1.false := newlable() ; B2.true := B.true ;
B2.false := B.false ; B.code := B1.code || gen ( B1.false ' : ') || B2.code }
B → B1 or B2
{ B1.true := newlabel (); B1.false := B.false ; B2.true := B.true ;
B2.false := B.false ; B.code := B1.code || gen ( B1.true ' : (' || B2.code }
B → B1 and B2
{ backpatch ( B1.falselist, M.instr ) ;
B.truelist := merge ( B1.truelist, B2.truelist ) ; B.falselist := B2.falselist }
B → B1 or M B2
{ backpatch ( B1.truelist, M.instr ) ; B.truelist := B2.truelist ;
B.falselist := merge ( B1.falselist, B2.falselist ) }
B → B1 and M B2
{ M.instr := nextinstr } M →
58
Backpatching Boolean expressionsproduction semantic action
B B1 or M B2 backpatch(B1.falseList,M.instr);B.trueList = merge(B1.trueList,B2.trueList);B.falseList = B2.falseList;
B B1 and M B2 backpatch(B1.trueList,M.instr);B.trueList = B2.trueList;B.falseList = merge(B1.falseList,B2.falseList);
B not B1 B.trueList = B1.falseList;B.falseList = B1.trueList;
B (B1) B.trueList = B1.trueList;B.falseList = B1.falseList;
B id1 relop id2 B.trueList = makeList(nextInstr);B.falseList = makeList(nextInstr+1);emit (‘if’ id1.var relop id2.var ‘goto _’) || emit(‘goto _’);
B true B.trueList = makeList(nextInstr);emit (‘goto _’);
B false B.falseList = makeList(nextInstr);emit (‘goto _’);
M M.instr = nextinstr;
59
Using a marker
• { M.instr = nextinstr;}• Use M to obtain the address just before B2 code starts
being generated
B1 or
B
M B2
Example:
60
ExampleX < 100 or x > 200 and x != y
B
B
x < 100
B
x > 200
B
x != y
B
and
or M
M
100: if x< 100 goto _101: goto _
B id1 relop id2 B.trueList = makeList(nextInstr);B.falseList = makeList(nextInstr+1);emit (‘if’ id1.var relop id2.var ‘goto _’) || emit(‘goto _’);
B.t = {100}B.f = {101}
61
ExampleX < 100 or x > 200 and x != y
B
B
x < 100
B
x > 200
B
x != y
B
and
or M
M
100: if x< 100 goto _101: goto _
B.t = {100}B.f = {101}
M M.instr = nextinstr;
M.i = 102
62
ExampleX < 100 or x > 200 and x != y
B
B
x < 100
B
x > 200
B
x != y
B
and
or M
M
100: if x< 100 goto _101: goto _
B.t = {100}B.f = {101} M.i = 102
B id1 relop id2 B.trueList = makeList(nextInstr);B.falseList = makeList(nextInstr+1);emit (‘if’ id1.var relop id2.var ‘goto _’) || emit(‘goto _’);
102: if x> 200 goto _103: goto _
B.t = {102}B.f = {103}
63
ExampleX < 100 or x > 200 and x != y
B
B
x < 100
B
x > 200
B
x != y
B
and
or M
M
100: if x< 100 goto _101: goto _
B.t = {100}B.f = {101} M.i = 102
102: if x> 200 goto _103: goto _
B.t = {102}B.f = {103}
M M.instr = nextinstr;
M.i = 104
64
ExampleX < 100 or x > 200 and x != y
B
B
x < 100
B
x > 200
B
x != y
B
and
or M
M
100: if x< 100 goto _101: goto _
B.t = {100}B.f = {101} M.i = 102
102: if x> 200 goto _103: goto _
B.t = {102}B.f = {103}
M.i = 104
B id1 relop id2 B.trueList = makeList(nextInstr);B.falseList = makeList(nextInstr+1);emit (‘if’ id1.var relop id2.var ‘goto _’) || emit(‘goto _’);
104: if x!=y goto _105: goto _
B.t = {104}B.f = {105}
65
ExampleX < 100 or x > 200 and x != y
B
B
x < 100
B
x > 200
B
x != y
B
and
or M
M
100: if x< 100 goto _101: goto _
B.t = {100}B.f = {101} M.i = 102
102: if x> 200 goto 104103: goto _
B.t = {102}B.f = {103}
M.i = 104
104: if x!=y goto _105: goto _
B.t = {104}B.f = {105}
B B1 and M B2 backpatch(B1.trueList,M.instr);B.trueList = B2.trueList;B.falseList = merge(B1.falseList,B2.falseList);
B.t = {104}B.f = {103,105}
66
ExampleX < 100 or x > 200 and x != y
B
B
x < 100
B
x > 200
B
x != y
B
and
or M
M
100: if x< 100 goto _101: goto 102
B.t = {100}B.f = {101} M.i = 102
102: if x> 200 goto 104103: goto _
B.t = {102}B.f = {103}
M.i = 104
104: if x!=y goto _105: goto _
B.t = {104}B.f = {105}
B.t = {104}B.f = {103,105}
B B1 or M B2 backpatch(B1.falseList,M.instr);B.trueList = merge(B1.trueList,B2.trueList);B.falseList = B2.falseList;
B.t = {100,104}B.f = {103,105}
67
Example
100: if x<100 goto _101: goto _102: if x>200 goto _103: goto _104: if x!=y goto _105: goto _
100: if x<100 goto _101: goto _102: if x>200 goto 104103: goto _104: if x!=y goto _105: goto _
100: if x<100 goto _101: goto 102102: if x>200 goto 104103: goto _104: if x!=y goto _105: goto _
Before backpatching After backpatchingby the productionB B1 and M B2
After backpatchingby the productionB B1 or M B2
68
Backpatching for statementsproduction semantic action
S if (B) M S1 backpatch(B.trueList,M.instr);S.nextList = merge(B.falseList,S1.nextList);
S if (B) M1 S1 N else M2 S2
backpatch(B.trueList,M1.instr);backpatch(B.falseList,M2.instr);temp = merge(S1.nextList,N.nextList);S.nextList = merge(temp,S2.nextList);
S while M1 (B) M2 S1
backpatch(S1.nextList,M1.instr);backpatch(B.trueList,M2.instr);S.nextList = B.falseList;emit(‘goto’ M1.instr);
S { L } S.nextList = L.nextList;
S A S.nextList = null;
M M.instr = nextinstr;
N N.nextList = makeList(nextInstr); emit(‘goto _’);
L L1 M S backpatch(L1.nextList,M.instr); L.nextList = S.nextList;
L S L.nextList = S.nextList
69
Generate code for procedures
• we will see handling of procedure calls in much more detail later
n = f(a[i]);
t1 = i * 4t2 = a[t1] // could have expanded this as well param t2t3 = call f, 1n = t3
70
Extend grammar for procedures
• type checking– function type: return type, type of formal parameters– within an expression function treated like any other
operator
• symbol table– parameter names
D define T id (F) { S } F | T id, FS return E; | …E id (A) | … A | E, A
expressions
statements
71
Summary
• Three address code.• Intermediate code generation is executed with parsing (via
semantic actions). • Creating code for Boolean expressions and for control
statements is more involved. • We typically use short circuit evaluation, value of
expression is implicit in control location. • We need to compute the branching addresses.• Option 1: compute them in a second AST pass.• Option 2: backpatching (a single pass): maintain lists of
incomplete jumps, where all jumps in a list have the same target. When the target becomes known, all instructions on its list are “filled in”.