1
Boolean expressions
production semantic action
E E1 or E2 E1.trueLabel = E.trueLabel; E1.falseLabel = freshLabel(); E2.trueLabel = E.trueLabel; E2.falseLabel = E.falseLabel;E.code = E1.code || gen (E1.falseLabel ‘:’) || E2.code
E E1 and E2 E1.trueLabel = freshLabel(); E1.falseLabel = E.falseLabel;E2.trueLabel = E.trueLabel; E2.falseLabel = E.falseLabel;E.code = E1.code || gen (E1.trueLabel ‘:’) || E2.code
E not E1 E1.trueLabel = E.falseLabel; E1.falseLabel = E.trueLabel; E.code = E1.code;
E (E1) E1.trueLabel = E.trueLabel; E1.falseLabel = E.falseLabel; E.code = E1.code;
E id1 relop id2 E.code=gen (‘if’ id1.var relop id2.var ‘goto’ E.trueLabel)||gen(‘goto’ E.falseLabel);
E true E.code = gen(‘goto’ B.trueLabel)
E false E.code = gen(‘goto’ B.falseLabel);
Generate code that jumps to E.trueLabel if E’s value is true and to B.falseLabel if E’s value is false.
2
Boolean expressionsproduction semantic action
E E1 or E2 E1.trueLabel = E.trueLabel; E1.falseLabel = freshLabel();E2.trueLabel = E.trueLabel;E.falseLabel = E.falseLabel;E.code = E1.code || gen (E1.falseLabel ‘:’) || E2.code
3
Boolean Expressions: an Example
E
E E
a < b
or
E
c < d
E
e < f
and
4
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:
5
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:
6
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:
7
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
8
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
9
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.
10
Boolean expressionsproduction 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
11
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)
12
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)
13
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
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
15
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
• 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
• BackPatching is putting the address instead
of labels when the proper label is determined. Backpatching Algorithms perform three types of operations– makelist(i) – creates a new list containing only i, an
index into the array of quadruples and returns pointer to the list it has made.
– merge(i,j) – concatenates the lists pointed to by i and j ,and returns a pointer to the concatenated list.
– backpatch(p,i) – inserts i as the target label for each of the statements on the list pointed to by p.
• 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.16
17
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 →
23
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;
24
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:
25
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}
26
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
27
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}
28
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
29
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}
30
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}
31
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}
32
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
33
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
34
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
35
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
36
Summary
• Three address code is our IR.• Intermediate code generation is executed while parsing (via
semantic actions). • Creating code for Boolean expressions and for control
statements is more involved. • We typically use short circuit evaluation, value of an
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”.
37
Recap
• Lexical analysis– regular expressions identify tokens (“words”)
• Syntax analysis– context-free grammars identify the structure of the program
(“sentences”)
• Contextual (semantic) analysis– type checking defined via typing judgements– can be encoded via attribute grammars
• Syntax directed translation– attribute grammars
• Intermediate representation – many possible IRs– generation of intermediate representation– 3AC
38
Journey inside a compiler
LexicalAnalysi
s
Syntax Analysi
s
Sem.Analysi
s
Inter.Rep.
Code Gen.
float position;
float initial;
float rate;
position = initial + rate * 60
<float> <ID,position> <;> <float> <ID,initial> <;> <float> <ID,rate> <;> <ID,1> <=> <ID,2> <+> <ID,3> <*> <60>
TokenStream
39
Journey inside a compiler
LexicalAnalysi
s
Syntax Analysi
s
Sem.Analysi
s
Inter.Rep.
Code Gen.
<ID,1> <=> <ID,2> <+> <ID,3> <*> <60>
60
<id,1>
=
<id,3>
<id,2>
+
*
AST
id symbol type data
1 position float …
2 initial float …
3 rate float …
symbol table
S ID = EE ID | E + E | E * E | NUM
40
Journey inside a compiler
LexicalAnalysi
s
Syntax Analysi
s
Sem.Analysi
s
Inter.Rep.
Code Gen.
60
=
<id,3>
<id,2>
+
*
<id,1>
inttofloat
60
<id,1>
=
<id,3>
<id,2>
+
*
AST AST
coercion: automatic conversion from int to floatinserted by the compiler
id symbol type
1 position float
2 initial float
3 rate float
symbol table
41
Journey inside a compiler
LexicalAnalysi
s
Syntax Analysi
s
Sem.Analysi
s
Inter.Rep.
Code Gen.
t1 = inttofloat(60)t2 = id3 * t1t3 = id2 + t2id1 = t3
3AC
60
=
<id,3>
<id,2>
+
*
<id,1>
inttofloat
production semantic rule
S id = E S.code := E. code || gen(id.var ‘:=‘ E.var)
E E1 op E2 E.var := freshVar(); E.code = E1.code || E2.code || gen(E.var ‘:=‘ E1.var ‘op’ E2.var)
E inttofloat(num) E.var := freshVar(); E.code = gen(E.var ‘:=‘ inttofloat(num))
E id
E.var := id.var; E.code = ‘’
t1 = inttofloat(60)t2 = id3 * t1
t3 = id2 * t2id1 = t3
(for brevity, bubbles show only code generated by the node and not all accumulated “code” attribute)
note the structure:translate E1translate E2
handle operator
42
Journey inside a compiler
Inter.Rep.
Code Gen.
LexicalAnalysi
s
Syntax Analysi
s
Sem.Analysi
s
3AC Optimized
t1 = inttofloat(60)t2 = id3 * t1t3 = id2 + t2id1 = t3
t1 = id3 * 60.0id1 = id2 + t1
value known at compile timecan generate code with converted value
eliminated temporary t3
43
Journey inside a compiler
Inter.Rep.
Code Gen.
LexicalAnalysi
s
Syntax Analysi
s
Sem.Analysi
s
Optimized
t1 = id3 * 60.0id1 = id2 + t1
Code Gen
LDF R2, id3MULF R2, R2, #60.0LDF R1, id2ADDF R1,R1,R2STF id1,R1
44
Problem 3.8 from [Appel]
A simple left-recursive grammar: E E + id E id
A simple right-recursive grammar accepting the same language:
E id + E E id
Which has better behavior for shift-reduce parsing?
45
Answer
The stack never has more than three items on it. In general, withLR-parsing of left-recursive grammars, an input string of length O(n)requires only O(1) space on the stack.
E E + idE id
Input
id+id+id+id+id
id (reduce) E E + E + id (reduce) E E + E + id (reduce) E E + E + id (reduce) E E + E + id (reduce) E
stack
left recursive
46
Answer
The stack grows as large as the input string. In general, with LR-parsingof right-recursive grammars, an input string of length O(n) requires O(n) space on the stack.
E id + EE id
Input
id+id+id+id+id
id id + id + id id + id + id + id + id id + id + id id + id + id + id id + id + id + id + id + id + id + id + id (reduce) id + id + id + id + E (reduce) id + id + id + E (reduce) id + id + E (reduce) id + E (reduce) E
stack
right recursive
47
Next…
• Runtime Environments
Top Related