Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
78 views

Intermediate Code Generation-17-19

The document discusses intermediate code generation in compilers. It describes why front-end and back-end components are needed in compilers and some common forms of intermediate code representation, including postfix notation, abstract syntax trees, and three-address code. Postfix notation is discussed in detail, including how it can be generated from source code and extended to represent assignments and control flow structures. Generating target code from the postfix form is also briefly covered.

Uploaded by

AtharvA Pagar
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
78 views

Intermediate Code Generation-17-19

The document discusses intermediate code generation in compilers. It describes why front-end and back-end components are needed in compilers and some common forms of intermediate code representation, including postfix notation, abstract syntax trees, and three-address code. Postfix notation is discussed in detail, including how it can be generated from source code and extended to represent assignments and control flow structures. Generating target code from the postfix form is also briefly covered.

Uploaded by

AtharvA Pagar
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 90

BITS Pilani

BITS Pilani Prof.Aruna Malapati


Department of CSIS
Hyderabad Campus
BITS Pilani
Hyderabad Campus

Intermediate code generation


Today’s Agenda

• Why front end and back end in compilers?

• Different forms of intermediate code generation

• Postfix notation
• Abstract Syntax Tree
• Three Address Code

BITS Pilani, Hyderabad Campus


Recall

• The objective of a compiler is to analyze a source


program and produce target code.
• Front end analyzes the source program and generates
an intermediate code.
• Eack end takes the Intermediate code as input and
generates the target code.

BITS Pilani, Hyderabad Campus


Need for Intermediate code

C Compiler for 80X86 Machine


C Program System instructions for
80X86 systems

C Compiler for SPARC Machine


C Program System instructions for
SPARC systems

BITS Pilani, Hyderabad Campus


Need for Intermediate code

C Compiler
C Program
Front end

Intermediate
code

Compiler Eank Compiler Eank


end for 80X86 end for SPARC
System System

Machine Machine
instructions for instructions for
80X86 systems SPARC systems

BITS Pilani, Hyderabad Campus


Advantages of using
Intermediate Code
• Retargeting to a different machine.

• Optimization of the code at intermediate level.

Front Target
Language 1 end machine 2
Eack
Intermediate end Target
Language 2 Representation machine 1
Target
Language 3 machine 3

BITS Pilani, Hyderabad Campus


Recall

Intermediate code
Front-end Back-end
Target machine code

Enables machine-independent code optimization

BITS Pilani, Hyderabad Campus


Intermediate Representations
• We could translate the source program directly into the
target language.

• However, there are benefits to having an intermediate,


machine-independent representation.
• A clear distinction between the machine-independent and machine-dependent
parts of the compiler
• Retargeting is facilitated; the implementation of language processors for new
machines will require replacing only the back-end
• We could apply machine independent code optimization techniques

BITS Pilani, Hyderabad Campus


Intermediate Representations

• Intermediate representations span the gap between the


source and target languages.

• High Level Representations


• closer to the source language
• easy to generate from an input program
• code optimizations may not be straightforward

• Low Level Representations


• closer to the target machine
• Suitable for register allocation and instruction selection
• easier for optimizations, final code generation

BITS Pilani, Hyderabad Campus


Options for intermediate code

• There are several options for intermediate code.

• Specific to the language being implemented


• P-code for Pascal
• Object code for C
• Bytecode for Java

• Language independent:
• 3-address code

BITS Pilani, Hyderabad Campus


Intermediate forms

• Postfix notation

• Syntax tree (Graphical representation of statements)


• Abstract Syntax Tree
• Parse Tree

• Directed acyclic graph(DAG)


• Three-address code
• Quadruple

BITS Pilani, Hyderabad Campus


Postfix Notation:

• Any expression can be written unambiguously without


parentheses, nor need for stating operator precedence.

• Ideally suited for source languages that primarily deal


with expression like SNOEOL.

• We can easily build interpreters for these expressions,


using a stack.

• This is the procedure followed by most assemblers.

BITS Pilani, Hyderabad Campus


How to generate the postfix
code?
• A semantic stack is used to represent the postfix code being
generated.

• This stack is initially empty.

• Semantic actions are connected with each production (as


seen in semantic analysis).

• Only one semantic action is used to create the semantic


stack:
• push <value> : place a value (address or operator) on
the semantic stack
BITS Pilani, Hyderabad Campus
How to generate the postfix
code?
All logic or arithmetic operations are assumed to be directly
supported by the machine:

+, *, /, -, and, or

BITS Pilani, Hyderabad Campus


How to generate the postfix code?
An example ‘semantic grammar’

E -> E+T {push +} a*(9+d) a9d+*


E -> E-T {push -}
E -> T
T -> T*F {push *}
T -> T/F {push /}
T -> F
F -> i {push i}
F -> (E)
Parentheses have no
effect on resulting postfix
code

BITS Pilani, Hyderabad Campus


Suffix notation

a*(b+c/a)

BITS Pilani, Hyderabad Campus


Suffix notation

a*(b+c/a)

BITS Pilani, Hyderabad Campus


Suffix notation

a*(b+c/a)

BITS Pilani, Hyderabad Campus


Suffix notation

a*(b+c/a)

BITS Pilani, Hyderabad Campus


Suffix notation

a*(b+c/a)

BITS Pilani, Hyderabad Campus


Suffix notation

a*(b+c/a)

BITS Pilani, Hyderabad Campus


Suffix notation

a*(b+c/a)

The Result
• We can treat the stack generated by the prior process as the intermediate representation
of the input, in postfix notation form:

BITS Pilani, Hyderabad Campus


Extending to other structures:

• It is clear postfix notation can be used for representing


mathematical expressions.
• Can it also be extended to handle all other programming
constructs?
E.g., assignment? Control-flow structures?
• If feasible, this notation would offer a good candidate for
intermediate code representation:
• It is simple
• It is easy to interpret
• It is unambiguous

BITS Pilani, Hyderabad Campus


Unary Operators:

• Some operators, such as ‘-’, can be a unary (single


argument) or binary operator.

• If we just map these operators into the postfix notation, it


will be ambiguous whether they operate on one or two
arguments.

• Two solutions:
• 1. Convert to a binary op:
• Map: ‘-a’ to ‘0a-’
• 2. Create a new operator for the unary use of ‘-’:
• map: ‘-a’ to ‘a_’

BITS Pilani, Hyderabad Campus


How to generate the postfix
code:
An example ‘semantic grammar’
E -> E+T {push +}
E -> E-T {push -}
E -> T
T -> T*F {push *}
T -> T/F {push /}
T -> F
F -> i {push i}
F ->(E)
F -> -F {push _} Note that Unary –
has distinct
operator

BITS Pilani, Hyderabad Campus


Extending to other Structures

Assignment:
• An assignment statement:
V=a+b can be represented as follows: Vab+=

• The ‘=‘ operator thus:


• Takes the previous two elements on the stack
• Assumes the earlier one is a memory address
• And places the second value in that location.
a=a*(9+d) aa9d+*=

BITS Pilani, Hyderabad Campus


Flow Control

• Many flow control statements (if-then, while, for, etc.) can


be mapped onto assembler which depends on some sort
of conditional or unconditional jump statement
CMP [A], [B]
JZ L1
• The intermediate code can make use of the same kind of
solution:
label jmp_to
• Jmp_to is a unary operator which takes the prior element
on the stack as a memory address.
Similar for: jump_if_zero and jump_if_false

BITS Pilani, Hyderabad Campus


Generating Target Code from
Postfix form

• Generating Assembler from Postfix form: stack-based


assembler
• The operators used in postfix notation are similar to
those used in most assembler languages.
• The stack data structure is also a basis for most
assemblers
• It should thus be easy to translate from postfix
representation to a given assembler language.

BITS Pilani, Hyderabad Campus


If(f<6) Postfix form
z=p/q;
else if(f==6) f6< ?z p q/=: f6==?z p q*=:z p q-
z=p*q;
1 f 12 JNE 20
else
z=p-q; 2 6 13 z
3 JGE 25 14 p
4 z 16 q
5 p 17 *
6 q 18 =
7 / 19 25 Jump
8 = 20 z
9 25 Jump 21 p
10 f 22 q
11 6 23 -
24 =
Postfix form
Intermediate code 25

BITS Pilani, Hyderabad Campus


Syntax Trees

• A syntax tree shows the structure of a program by


abstracting away irrelevant details from a parse tree.
• Each node represents a computation to be performed;
• The children of the node represents what that
computation is performed on.
• Syntax trees decouple parsing from subsequent
processing.

BITS Pilani, Hyderabad Campus


Syntax Trees: Structure

• Expressions:
• leaves: identifiers or constants;
• internal nodes are labeled with operators;
• the children of a node are its operands.

• Statements:
• a node’s label indicates what kind of statement
it is;
• the children correspond to the components of
the statement.

BITS Pilani, Hyderabad Campus


Abstract Syntax Tree
block
block while(expr)
{
S1; S1 S2 S3 s1;
S2; while
S3;
}
expr S1
If(expr) If-else
s1;
else expr S1 S2
s2;

BITS Pilani, Hyderabad Campus


Abstract Syntax Tree

if(a<b)
{
if-else
p=q;
r=s;
} < stmt-list stmt-list
else
{
a b= = = =
c=d;
e=f
}
p q r s c de f

BITS Pilani, Hyderabad Campus


Syntax Trees: Example

Grammar :
E -> E + T | T
T -> T * F | F
F -> ( E ) | id
Input: id + id * id

BITS Pilani, Hyderabad Campus


Example

BITS Pilani, Hyderabad Campus


Constructing Syntax Trees
• General Idea: construct bottom-up using synthesized attributes.

BITS Pilani, Hyderabad Campus


Directed Acyclic Graph (DAG):
• More compact representation
• Gives clues regarding generation of efficient code

BITS Pilani, Hyderabad Campus


Generating DAG from AST

Pros: Easy restructuring of code and/or expressions


For intermediate code optimization
Cons: Memory intensive

BITS Pilani, Hyderabad Campus


Three Address Code
• Low-level Intermediate Representation.
• Addresses
• Instruction operands are addresses and come in one of
three flavors:
• name : will ultimately be a key in the symbol table
• constant : holds literal value
• temporary : generated by compiler to hold intermediate result
• Instructions are of the form ‘x = y op z,’ where x, y, z are
variables, constants, or “temporaries”.
• At most one operator allowed on RHS, so no ‘built-up”
expressions.
• Instead, expressions are computed using temporaries
(compiler-generated variables).

BITS Pilani, Hyderabad Campus


Three-Address Code - Example

Compile: a : = b * -c + b * -c
Code for syntax tree
t1 := - c
t2 := b * t1
t3 := - c
t4 : = b * t3
t5 := t2 + t4
a := t5
Code for DAG
t1 := - c
t2 := b * t1
t5 := t2 + t2
a := t5
BITS Pilani, Hyderabad Campus
Three-Address Code
Linearized representation of AST

a+a*(b-c)+(b-c)*d

BITS Pilani, Hyderabad Campus


Three address statements

• Assignment statements: x:= y op z , x:=op y


• Indexed assignments: x:= y[i],x[i]:=y
• Pointer assignments: x:=&y,x:=*y,*x:=y
• Copy statements: x:= y
• Unconditional jumps: goto lab
• Conditional jumps: if a relop y goto lab
• Function calls: param x … call p,n
return y

BITS Pilani, Hyderabad Campus


Creating 3AC

• Assume bottom up parser


– Covers a wider range of grammars
– LALR sufficient to cover most programming languages

• Creating 3AC via SDD

• Attributes examples:
– code – code generated for a nonterminal
– temp – name of variable that stores result of nonterminal
• newTemp() – helper function that returns the name of a new
variable

BITS Pilani, Hyderabad Campus


Creating 3AC for expressions
via SDD
production semantic rule
S ➞ id := E S.code := E. code || gencode(id ‘:=‘ E.Temp)
E ➞ E1 + E2 E.Temp := newTemp();
E.code = E1.code || E2.code || gencode(E.Temp ‘:=‘ E1.Temp ‘+’ E2.Temp)
E ➞ E1 * E2 E.Temp := newTemp();
E.code = E1.code || E2.code || gencode(E.Temp ‘:=‘ E1.Temp ‘*’ E2.Temp)
E ➞ - E1 E.Temp := newTemp();
E.code = E1.code || gencode(E.Temp ‘:=‘ ‘uminus’ E1.Temp)
E ➞ (E1) E.Temp := E1.Temp
E.code = ‘(‘ || E1.code || ‘)’
E ➞ id E.Temp := id.Temp; E.code = ‘’

(we use || to denote concatenation of intermediate code fragments)

BITS Pilani, Hyderabad Campus


BITS Pilani, Hyderabad Campus
example a = b * -c + b* -c

assign E.Temp = t5
E.code =‘t1 = -c
+ t2 = b*t1
a t3 = -c
t4 = b*t3
t5 = t2+t4’

E.Temp = t4
E.code =‘t3 = -c
E.Temp = t2 t4 = b*t3’
* *
E.code =‘t1 = -c
E.Temp = t3
t2 = b*t1’
E.code =‘t3 = -c’
b uminus E.Temp = t1 b uminus
E.code =‘t1 = -c’
E.Temp = b E.Temp = b
E.code =‘’ c E.code =‘’ c
E.Temp = c E.Temp = c
E.code =‘’ E.code =‘’
BITS Pilani, Hyderabad Campus
Three address code for
assignment statements
V1=V2+V3-V4

t0=V2+V3
t1=t0-V4
V1=t1

Temporaries are created for storing intermediate results.

BITS Pilani, Hyderabad Campus


Logical expression

• These statements are mainly used for a set of


statements that are executed based on the condition that
is satisfied, i.e to control the flow path.
• The use of logical expression always results in either
true or false which is considered to be 0/1.
• 2 things that are important
• Where control should go when the condition is true and
• Where to go when the condition is false.

BITS Pilani, Hyderabad Campus


SDD for Boolean expressions
production semantic rule
E-> E1 or E2 E.Temp := newTemp();
E.code = E1.code || E2.code || gencode(E.Temp ‘:=‘ E1.Temp ‘OR’ E2.Temp)
E-> E1 and E2 E.Temp := newTemp();
E.code = E1.code || E2.code || gencode(E.Temp ‘:=‘ E1.Temp ‘AND’ E2.Temp)
E-> not E1 E.Temp := newTemp();
E.code = E1.code || gencode(E.Temp ‘:=‘ ‘not’ E1.Temp)
E->(E1) E.Temp := newTemp();
E.code= E1.code
E->id E.Temp := id.Temp; E.code = ‘’”

The three address code for a or b and not c is:


t1 = not c
t2 = b and t1
t3 = a or t2

BITS Pilani, Hyderabad Campus


BITS Pilani, Hyderabad Campus
SDD for relational expressions
production semantic rule
E-> id1 relop id2 E.Temp := newTemp();
E.code = gencode(‘if’ || id1 || relop ||id2 goto nextstat+3)
gencode(E.Temp=0)
gencode(goto nextstat+2)
gencode(E.Temp=1)

A relational expression a < b is equivalent to the conditional statement if a < b then 1


else 0 and three address code for this expression is:

100: if a < b goto 103.


101: t = 0
102: goto 104
103: t = 1
104:

BITS Pilani, Hyderabad Campus


BITS Pilani, Hyderabad Campus
Boolean Expressions: an Example

E a<b or c<d and e<f

E or E

a < b E and E

c < d e < f

BITS Pilani, Hyderabad Campus


Boolean Expressions: an Example

E a<b or c<d and e<f

E or E

a < b E and E

if a < b goto 103 100:


T1 := 0 101:
c < d e < f
goto 104 102:
T1 := 1 103:

BITS Pilani, Hyderabad Campus


Boolean Expressions: an Example

E a<b or c<d and e<f

E or E

a < b E and E

if a < b goto 103 100:


T1 := 0 101:
c < d e < f
goto 104 102:
T1 := 1 103: if c < d goto 107 104:
T2 := 0 105:
goto 108 106:
T2 := 1 107:

BITS Pilani, Hyderabad Campus


Boolean Expressions: an Example

E a<b or c<d and e<f

E or E

a < b E and E

if a < b goto 103 100:


T1 := 0 101:
c < d e < f
goto 104 102:
T1 := 1 103: if c < d goto 107 104: if e < f goto 111 108:
T2 := 0 105: T3 := 0 109:
goto 108 106: goto 112 110:
T2 := 1 107: T3 := 1 111:
112:

BITS Pilani, Hyderabad Campus


Boolean Expressions: an Example

E a<b or c<d and e<f

E or E

a < b E and E

if a < b goto 103 100:


T1 := 0 101:
c < d e < f
goto 104 102:
T1 := 1 103: if c < d goto 107 104: if e < f goto 111 108:
T2 := 0 105: T3 := 0 109:
goto 108 106: goto 112 110:
T2 := 1 107: T3 := 1 111:
112:
T4 := T2 and T3
113:

BITS Pilani, Hyderabad Campus


Boolean Expressions: an Example

E a<b or c<d and e<f

E or E

a < b E and E

if a < b goto 103 100:


T1 := 0 101:
c < d e < f
goto 104 102:
T1 := 1 103: if c < d goto 107 104: if e < f goto 111 108:
T2 := 0 105: T3 := 0 109:
goto 108 106: goto 112 110:
T2 := 1 107: T3 := 1 111:
112:
T4 := T2 and T3
113:
T5 := T1 or T4
BITS Pilani, Hyderabad Campus
Our previous example
a < b or (c<d and e<f)

100: if a < b goto 103


101: T1 := 0
102: goto 104
103: T1 := 1
104: if c < d goto 107 100: if a < b goto 105
105: T2 := 0 101: if !(c < d) goto 103
106: goto 108 102: if e < f goto 105
107: T2 := 1 103: T := 0
108: if e < f goto 111 104: goto 106
109: T3 := 0 105: T := 1
110: goto 112 106:
111: T3 := 1
112: T4 := T2 and T3
113: T5 := T1 and T4

naive Short circuit evaluation


BITS Pilani, Hyderabad Campus
Control Structure: if, else,
while
• Consider the conditional jumps: if E then S1 → S
if E then S1 else S2 |
while E do S1 |

• One option is to create code for E, create code for S, and then
create a jump to the beginning of S or the end of S according to E’s
value.

• But it would be more efficient to create code that while executing E


will jump to the correct location immediately when the value of E is
discovered.

BITS Pilani, Hyderabad Campus


Control Structure: if, else, while.

• The problem is that we do not know where to jump to…


• While parsing E’s tree for “if E 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 E keep labels: E.true and E.false. We
jump to these labels when E’s value is true or false correspondingly.
• Also, for each statement S, we have a label S.next which keeps the
address of the code that follows the statement S.

The semantic • S
equation will be
.E.false = S.next
if E then S
For E.true, we create •
a new label between
.E’s code and S’s code

BITS Pilani, Hyderabad Campus


Control Structures: conditional

production semantic action


S -> if E then S1 E.true = newLabel();
E.false = S.next;
S1.next = S.next;
S.code = E.code || ‘if(‘ E.Temp=0 ‘) goto’ E.false
gen (E.true ‘:’) || S1.code || E.false
to E.true

E.code

E.true: to E.false
S1.code

E.false:

if - then

BITS Pilani, Hyderabad Campus


S.code = E.code || ‘if(‘ E.Temp=0 ‘) goto’
E.false gen (E.true ‘:’) || S1.code ||
E.false

BITS Pilani, Hyderabad Campus


Control Structures:
conditional
production semantic action

S -> if E then S1 else S2 E.true = newlabel();


E.false = newlabel();
S1.next = S.next;
S2.next = S.next;
S.code = E.code || gencode(E.true ‘:’)
|| S1.code || gencode(‘goto’ S.next)
|| gencode(E.false ‘:’) || S2.code
to E.true
E.code
to E.false
E.true:
S1.code

goto S.next

E.false:
S2.code

S.next:

if – then - else
BITS Pilani, Hyderabad Campus
Generating Code for
Control Statements : While loop
Suppose we have the following grammar:-
S  while E do S1

production semantic action


S -> while E do S1 S.begin = newLabel()
S.after = newLabel()
S.code=gencode(S.begin:) || E.code || gen('if' E.temp '=0 goto'
S.after)|| S1.code|| gen('goto' S.begin)||gen(S.after)

BITS Pilani, Hyderabad Campus


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?

BITS Pilani, Hyderabad Campus


Functions to incorporate
backpatching
• makelist(i) – This is used to create a new list containing
three-address location i, and it returns a pointer to the list.
This is the first function which is created to form a true /
false list.

• merge(p1, p2) – This function concatenates lists pointed to


by p1 and p2, returns a pointer to the concatenated list.
This is used to assign the same true / false labels to more
than one address.

• backpatch(p, i) – This function is used to insert ‘i' as the


target label for each of the statements in the list pointed to
by p. Using the information provided by this function labels
are attached to all the statements. BITS Pilani, Hyderabad Campus
Backpatching Boolean
expressions
production semantic action
E -> E1 or M E2 backpatch(E1.falseList,M.instr);
E.trueList = merge(E1.trueList,E2.trueList);
E.falseList = E2.falseList;

E -> E1 and M E2 backpatch(E1.trueList,M.instr);


E.trueList = E2.trueList;
E.falseList = merge(E1.falseList,E2.falseList);

E -> not E1 E.trueList = E1.falseList;


E.falseList = E1.trueList;
E -> (E1) E.trueList = E1.trueList;
E.falseList = E1.falseList;
E -> id1 relop id2 E.trueList = makeList(nextInstr);
E.falseList = makeList(nextInstr+1);
gencode(‘if’ id1.Temp relop id2.Temp ‘goto _’) || gencode (‘goto _’);

E -> true E.trueList = makeList(nextInstr);


gencode (‘goto _’);
E -> false E.falseList = makeList(nextInstr);
gencode(‘goto _’);

M ->  M.instr = nextinstr;


BITS Pilani, Hyderabad Campus
Using a marker
Example: E

E1 or M E2

{ M.instr = nextinstr;}
Use M to obtain the address just before E2 code starts being
gencodeerated

BITS Pilani, Hyderabad Campus


Example
X < 100 or x > 200 and x != y

E
E.t = {100}
E.f = {101}

E or M E

 and
x < 100
M
E E
100: if x< 100 goto _
101: goto _ 

x > 200 x != y

E  id1 relop id2 E.trueList = makeList(nextInstr);


E.falseList = makeList(nextInstr+1);
gencode (‘if’ id1.Temp relop id2.Temp ‘goto _’) ||
gencode(‘goto _’);
BITS Pilani, Hyderabad Campus
Example
X < 100 or x > 200 and x != y

E
E.t = {100}
E.f = {101}
M.i = 102
E or M E

 and
x < 100
M
E E
100: if x< 100 goto _
101: goto _ 

x > 200 x != y

M M.instr = nextinstr;

BITS Pilani, Hyderabad Campus


Example
X < 100 or x > 200 and x != y

E
E.t = {100}
E.f = {101}
M.i = 102
E or M E

 and
x < 100
E.t = {102} M
E.f = {103} E E
100: if x< 100 goto _
101: goto _ 
x != y
102: if x> 200 goto _ x > 200
103: goto _
E  id1 relop id2 E.trueList = makeList(nextInstr);
E.falseList = makeList(nextInstr+1);
gencode (‘if’ id1.Temp relop id2.Temp ‘goto _’) ||
gencode(‘goto _’); BITS Pilani, Hyderabad Campus
Example
X < 100 or x > 200 and x != y

E
E.t = {100}
E.f = {101}
M.i = 102
E or M E

 and
x < 100 M.i = 104
E.t = {102} M
E.f = {103} E E
100: if x< 100 goto _
101: goto _ 
x != y
102: if x> 200 goto _ x > 200
103: goto _

M M.instr = nextinstr;

BITS Pilani, Hyderabad Campus


Example
X < 100 or x > 200 and x != y

E
E.t = {100}
E.f = {101}
M.i = 102
E or M E

 and
x < 100 M.i = 104
E.t = {102} M E.t = {104}
E.f = {103} E E E.f = {105}
100: if x< 100 goto _
101: goto _ 
x != y
102: if x> 200 goto _ x > 200
104: if x!=y goto _
103: goto _ 105: goto _

E  id1 relop id2 E.trueList = makeList(nextInstr);


E.falseList = makeList(nextInstr+1);
gencode (‘if’ id1.Temp relop id2.Temp ‘goto _’) ||
gencode(‘goto _’); BITS Pilani, Hyderabad Campus
Example
X < 100 or x > 200 and x != y

E
E.t = {100}
E.f = {101} E.t = {104}
M.i = 102
E.f = {103,105}
E or M E

 and
x < 100 M.i = 104
E.t = {102} M E.t = {104}
E.f = {103} E E E.f = {105}
100: if x< 100 goto _
101: goto _ 
x != y
102: if x> 200 goto 104 x > 200
104: if x!=y goto _
103: goto _ 105: goto _

E  E1 and M E2 backpatch(E1.trueList,M.instr);
E.trueList = E2.trueList;
E.falseList = merge(E1.falseList,E2.falseList);
BITS Pilani, Hyderabad Campus
Example
X < 100 or x > 200 and x != y

E.t = {100,104}
E
E.f = {103,105}
E.t = {100}
E.f = {101} E.t = {104}
M.i = 102
E.f = {103,105}
E or M E

 and
x < 100 M.i = 104
E.t = {102} M E.t = {104}
E.f = {103} E E E.f = {105}
100: if x< 100 goto _
101: goto 102 
x != y
102: if x> 200 goto 104 x > 200
104: if x!=y goto _
103: goto _ 105: goto _

E  E1 or M E2 backpatch(E1.falseList,M.instr);
E.trueList = merge(E1.trueList,E2.trueList);
E.falseList = E2.falseList;
BITS Pilani, Hyderabad Campus
Example

100: if x<100 goto _ 100: if x<100 goto _ 100: if x<100 goto _


101: goto _ 101: goto _ 101: goto 102
102: if x>200 goto _ 102: if x>200 goto 104 102: if x>200 goto 104
103: goto _ 103: goto _ 103: goto _
104: if x!=y goto _ 104: if x!=y goto _ 104: if x!=y goto _
105: goto _ 105: goto _ 105: goto _

before backpatching After backpatching After backpatching


by the production by the production
E -> E1 and M E2 E -> E1 or M E2

BITS Pilani, Hyderabad Campus


Arrays
1D array
X[i] = A
A = X[i] Where X is starting point and i is the offset from X.
Address of i in terms of base address, low and high (low=0
generally) = base + (i-low)*w (w is size of each address
block in bytes)
Example
a = b[3*c] /* where a and c are integers of size 2 and b is float of size 4 */
T1 = 3 * c
T2 = 4 * T1 /* each b[i] is size 4 */
T3 = &b
T4 = T2 + T3
a = *T4
BITS Pilani, Hyderabad Campus
2d Array

Generate a three address code for expression x=A[i,j] for


an array 10 X 20 assume low1=1 and low2=1.

t1-= i * 20
t1 = t1+j
The TAC for this expression can be written as t2 = c /*base – 84 */
t3 = 4 * t1
t4 = t2[t3]
x= t4

BITS Pilani, Hyderabad Campus


Names in the symbol table

production semantic action


S-> id=E {p=lookup(id.Temp);
if p!= Null then gencode(p=E.Temp) else error}

E->id {p=lookup(id.Temp);
if p!=Null E.Temp=p else error}

BITS Pilani, Hyderabad Campus


Functions

func begin (beginning of the function),


func end (end of a function),
param p (place a value parameter p on stack),
refparam p (place a reference parameter p on stack),
call f, n (call a function f with n parameters),
return (return from a function),
return a (return from a function with a value a)

BITS Pilani, Hyderabad Campus


Example

BITS Pilani, Hyderabad Campus


BITS Pilani, Hyderabad Campus
BITS Pilani, Hyderabad Campus
TAC for function Call

S -> call id ( Elist )


Elist -> Elist , E | E

foo(a+1, b, 7)
t1 := a + 1
t2 := 7
param t1
refparam b
param t2
call foo 4

BITS Pilani, Hyderabad Campus


Data Structure for TAC

• How to present these instructions in a data structure?


– Quadruples
– Triples
– Indirect triples

BITS Pilani, Hyderabad Campus


Implementation of 3-Addr. Code
(1)
a=b*-c+b*-c
With a quadruple
• Operator, argument1, argument2, result

Pros: Easy to rearrange code for global optimization.


Cons: Lots of temporaries.

BITS Pilani, Hyderabad Campus


Implementation of 3-Addr. Code
(2)
a=b*-c+b*-c
With a tripel
Operator, argument1, argument2
• Instead of temporary variables a
reference to the place of the
intermediary result is stored in the
table
• Temporary variables need not to be
stored in the symbol table
• Less flexible against changes in the
code

Pros: Temporaries are implicit.


Cons: Difficult to rearrange code.

BITS Pilani, Hyderabad Campus


Implementation of 3-Addr. Code
(3) a=b*-c+b*-c

• When instructions are moving around during


optimizations: quadruples are better than triples.
• Indirect triples solve this problem

BITS Pilani, Hyderabad Campus

You might also like