0% found this document useful (0 votes)
108 views

Intermediate Code Generation

This document discusses intermediate code generation in compilers. It explains that the front-end of a compiler translates source code into an intermediate representation, from which the back-end generates target machine code. Three common types of intermediate representations are described: graphical, postfix notation, and three-address code. Three-address code is discussed in detail, including the use of quadruples and syntax-directed translation to generate three-address statements from source code. The document also covers symbol tables for managing variable declarations and scopes.

Uploaded by

Ishana Adhikari
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
108 views

Intermediate Code Generation

This document discusses intermediate code generation in compilers. It explains that the front-end of a compiler translates source code into an intermediate representation, from which the back-end generates target machine code. Three common types of intermediate representations are described: graphical, postfix notation, and three-address code. Three-address code is discussed in detail, including the use of quadruples and syntax-directed translation to generate three-address statements from source code. The document also covers symbol tables for managing variable declarations and scopes.

Uploaded by

Ishana Adhikari
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

Compiler Construction Intermediate-Code-Generation

Intermediate Code Generation


Reading: chapter 8

How the syntax-directed methods can be used to translate


into an intermediate form of programming language.

By Bishnu Gautam 1
Compiler Construction Intermediate-Code-Generation

Intermediate Code Generation

Intermediate Target
Front end code Back end machine code

The front end translate the source program into an intermediate


representation from which the backend generates target code

Intermediate codes are machine independent codes, but they are close
to machine instructions.

By Bishnu Gautam 2
Compiler Construction Intermediate-Code-Generation

Intermediate Representations

There are three kinds of intermediate representations:


1. Graphical representations (e.g. Syntax tree or Dag)
2. Postfix notation: operations on values stored on operand stack
(similar to JVM bytecode)
3. Three-address code: (e.g. triples and quads )Sequence of statement
of the form
x = y op z

Note: we discuss only three-address code representation

By Bishnu Gautam 3
Compiler Construction Intermediate-Code-Generation

Three-Address Code (Quadruples)


A quadruple is: x = y op z
where x, y and z are names, constants or compiler-generated temporaries and
op is any operator. (only one operator on the right side of the statement)
Postfix notation (much better notation because it looks like a machine
code instruction)
op y,z,x apply operator op to y and z, and store the result in x.

We use the term “three-address code” because each statement usually


contains three addresses (two for operands, one for the result).
Thus the source language like x + y * z might be translated into a
sequence
t1 = y * z
t2 = x + t1
where t1 and t2 are the compiler generated temporary name.
By Bishnu Gautam 4
Compiler Construction Intermediate-Code-Generation

Three-Address Statements
• Assignment statements: x = y op z, op is binary
• Assignment statements: x = op y, op is unary
• Indexed assignments: x = y[i], x[i] = y
• Pointer assignments: x = &y, x = *y, *x = y
• Copy statements: x = y
• Unconditional jumps: goto label
• Conditional jumps: if x relop y goto label
• Function calls: param x… call p, n return y

By Bishnu Gautam 5
Compiler Construction Intermediate-Code-Generation

Syntax-Directed Translation into


Three-Address Code
Productions Synthesized attributes:
S → id = E S.code three-address code for evaluating S
| while E do S S.begin label to start of S or nil
E→E+E S.after label to end of S or nil
|E*E E.code three-address code for evaluating E
|-E E.place a name that holds the value of E
|(E)
| id To represent three address statements
| num
gen(E.place ‘=’ E1.place ‘+’ E2.place)

Code generation
t3 = t1 + t2
By Bishnu Gautam 6
Compiler Construction Intermediate-Code-Generation
Syntax-Directed Translation into
Three-Address Code
Productions Semantic rules
S → id = E S.code = E.code || gen(id.place ‘=’ E.place); S.begin = S.after = nil
S → while E (see next slide)
do S1 Returns a new temporary name
E → E1 + E2 E.place = newtemp();
E.code = E1.code || E2.code || gen(E.place ‘=’ E1.place ‘+’ E2.place)
E → E1 * E2 E.place = newtemp();
E.code = E1.code || E2.code || gen(E.place ‘=’ E1.place ‘*’ E2.place)
E → - E1 E.place = newtemp();
E.code = E1.code || gen(E.place ‘=’ ‘uminus’ E1.place)
E → ( E1 ) E.place = E1.place
E.code = E1.code
E → id E.place = id.name
E.code = ‘’
E → num E.place = newtemp();
E.code = gen(E.place ‘=’ num.value)
By Bishnu Gautam 7
Compiler Construction Intermediate-Code-Generation

Syntax-Directed Translation into


Three-Address Code
Returns a new label
Production Semantic rule
S → while E do S1 S.begin = newlabel()
S.after = newlabel()
S.code = gen(S.begin ‘:’) ||
E.code ||
gen(‘if’ E.place ‘=‘ ‘0’ ‘goto’ S.after) ||
S1.code ||
gen(‘goto’ S.begin) ||
S.begin: E.code gen(S.after ‘:’)
if E.place = 0 goto S.after
S.code
goto S.begin
S.after: …
By Bishnu Gautam 8
Compiler Construction Intermediate-Code-Generation

Syntax-Directed Translation into


Three-Address Code : Example
i=2*n+k
while i do
i=i-k

t1 = 2
t2 = t1 * n
t3 = t2 + k
i = t3
L1: if i = 0 goto L2
t4 = i - k
i = t4
goto L1
L2: By Bishnu Gautam 9
Compiler Construction Intermediate-Code-Generation

Declarations: Names and Scopes


Declarations list size units as bytes, in a uniform-size environment
offsets and counts could be given in units of slots, where a slot (4
bytes on 32-bit machines) holds anything.
We need local symbol tables to record global declarations as well as
local declarations in procedures, blocks, and structs to resolve names.
The address consist of an offset from the base of static data area or the
field for local data in an activation record.
Before the first declaration the offset is set to 0. when new name is
created, that name entered in the symbol table with offset equal to the
current value of offset, and offset is incremented by the width of data
object denoted by that name.
By Bishnu Gautam 10
Compiler Construction Intermediate-Code-Generation

Declarations: Symbol Table


Operations
• mktable(previous) returns a pointer to a new table that
is linked to a previous table in the outer scope
• enter(table, name, type, offset) creates a new entry in
table
• addwidth(table, width) accumulates the total width of
all entries in table
• enterproc(table, name, newtable) creates a new entry
in table for procedure with local scope newtable
• lookup(table, name) returns a pointer to the entry in
the table for name by following linked tables
By Bishnu Gautam 11
Compiler Construction Intermediate-Code-Generation

Grammar for Declarations &


Statements
Productions Productions (cont’d)
P→D;S E→E+E
D→D;D |E*E
| id : T |-E Synthesized attributes:
| proc id ; D ; S |(E) T.type pointer to type
T → integer | id T.width storage width of type (bytes)
| real |E^ E.place name of temp holding value of E
| array [ num ] of T |&E
|^T | E . id
Global data to implement scoping:
| record D end A→A,E
tblptr stack of pointers to tables
S→S;S |E
offset stack of offset values
| id := E
| call id ( A )
Grammar that generate Pascal like declarations and statements
By Bishnu Gautam 12
Compiler Construction Intermediate-Code-Generation
Translation Schemes for
Declarations
P→ { t := mktable(nil); push(t, tblptr); push(0, offset) }
D;S
D → id : T
{ enter(top(tblptr), id.name, T.type, top(offset));
top(offset) := top(offset) + T.width }
D → proc id ;
{ t := mktable(top(tblptr)); push(t, tblptr); push(0, offset) }
D1 ; S
{ t := top(tblptr); addwidth(t, top(offset));
pop(tblptr); pop(offset);
enterproc(top(tblptr), id.name, t) }
D → D1 ; D2
… …->
By Bishnu Gautam 13
Compiler Construction Intermediate-Code-Generation
Translation Schemes for
…… Declarations
T → integer { T.type := ‘integer’; T.width := 4 }
T → real { T.type := ‘real’; T.width := 8 }
T → array [ num ] of T1
{ T.type := array(num.val, T1.type);
T.width := num.val * T1.width }
T → ^ T1
{ T.type := pointer(T1.type); T.width := 4 }
T → record
{ t := mktable(nil); push(t, tblptr); push(0, offset) }
D end
{ T.type := record(top(tblptr)); T.width := top(offset);
addwidth(top(tblptr), top(offset)); pop(tblptr); pop(offset) }

By Bishnu Gautam 14
Compiler Construction Intermediate-Code-Generation
Translation Schemes for
Assignments Statements
S→S;S
S → id := E
{ p := lookup(top(tblptr), id.name);
if p = nil then
error()
else if p.level = 0 then // global variable
emit(id.place ‘:=’ E.place)
else // local variable in subroutine frame
emit(fp[p.offset] ‘:=’ E.place) }

By Bishnu Gautam 15
Compiler Construction Intermediate-Code-Generation
Translation Schemes for
Expressions
E → E1 + E2 { E.place := newtemp();
emit(E.place ‘:=’ E1.place ‘+’ E2.place) }
E → E1 * E2 { E.place := newtemp();
emit(E.place ‘:=’ E1.place ‘*’ E2.place) }
E → - E1 { E.place := newtemp();
emit(E.place ‘:=’ ‘uminus’ E1.place) }
E → ( E1 ) { E.place := E1.place }
E → id { p := lookup(top(tblptr), id.name);
if p = nil then error()
else if p.level = 0 then // global variable
E.place := id.place
else // local variable in frame
E.place := fp[p.offset] } … …->
By Bishnu Gautam 16
Compiler Construction Intermediate-Code-Generation
Translation Schemes for
…… Expressions
E → E1 ^ { E.place := newtemp();
emit(E.place ‘:=’ ‘*’ E1.place) }
E → & E1 { E.place := newtemp();
emit(E.place ‘:=’ ‘&’ E1.place) }
E → id1 . id2 { p := lookup(top(tblptr), id1.name);
if p = nil or p.type != Trec then error()
else
q := lookup(p.type.table, id2.name);
if q = nil then error()
else if p.level = 0 then // global variable
E.place := id1.place[q.offset]
else // local variable in frame
E.place := fp[p.offset+q.offset] }
By Bishnu Gautam 17
Compiler Construction Intermediate-Code-Generation

Addressing Array Elements


One-Dimensional Arrays
A : array [10..20] of integer;
… …
base
low i width of array element: w

… := A[i] = baseA + (i - low) * w


=i*w+c
where c = baseA - low * w
with low = 10; w = 4

t1 := c // c = baseA - 10 * 4
t2 := i * 4
t3 := t1[t2] By Bishnu Gautam 18
… := t3
Compiler Construction Intermediate-Code-Generation

Addressing Array Elements


Multi-Dimensional Arrays
A : array [1..2,1..3] of integer;

… := A[i,j] = baseA + ((i1 - low1) * n2 + i2 - low2) * w


= ((i1 * n2) + i2) * w + c
where c = baseA - ((low1 * n2) + low2) * w
with low1 = 1; low2 = 1; n2 = 3; w = 4
t1 := i * 3
t1 := t1 + j
t2 := c // c = baseA - (1 * 3 + 1) * 4
t3 := t1 * 4
t4 := t2[t3] See on the book for translation scheme for
… := t4 addressing array elements – page 484 Ist ed
By Bishnu Gautam 19
Compiler Construction Intermediate-Code-Generation

Translating Logical and Relational


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

if a < b goto L1
a<b t1 := 0
goto L2
L1: t1 := 1
L2:

See translation scheme on the book page 490, Fig 8.20


By Bishnu Gautam 20
Compiler Construction Intermediate-Code-Generation

Translating Procedure Calls


S → call id ( Elist )
Elist → Elist , E
|E

S → call id ( Elist ) { for each item p on queue do


emit(‘param’ p);
emit(‘call’ id.place |queue|) }
Elist → Elist , E { append E.place to the end of queue }
Elist → E { initialize queue to contain only E.place }

call foo(a+1, b, 7) t1 := a + 1
t2 := 7
param t1
param b
param t2
By Bishnu Gautam 21
call foo 3
Compiler Construction Intermediate-Code-Generation

Exercise

8.1(c), 8.2 (a), 8.3(c), 8.7, 8.12 & 8.14 from book

By Bishnu Gautam 22

You might also like