You are on page 1of 2

8.

2 Declarations : Single Procedure


Each local name has a symbol-table entry

Computer Science 332


Compiler Construction

Entry contains
Type : .type attribute
Relative address in procedure's activation record (e.g, Java
int takes four bytes, double takes eight) : .width attribute
Code-generating part of compiler uses a global variable offset
that is reset to zero as new procedures are declared
Code-generator proc. enter (name, type, width) creates symboltable entry with this info
Consider just declarations part of program....

Chapter 8: Intermediate Code


Generation
Section 8.2: Procedure Declarations

P
D
D

T
T

D
D;D
id : T
integer
double

{ offset := 0 } // initializaion

8.2 Declarations : Nested Procedures


ML Example:
let fun f(x) =
let fun g(x, y) = x + y
in f(g(3, 4)) end end

{ enter(id.name, T.type, offset);


offset := offset + T.width) }
{ T.type := integer; T.width := 4 }
{ T.type := double; T.width := 8 }

Problem : (look at first production)


offset := 0 code will be performed as last action, instead of
first
Solution: "dummy" non-terminal:

Abstractly:


P
D

P
M


MD

{ offset := 0 }

D
D , D | id : T | fun id ( D ) = S

Each procedure gets its own symbol table


Table for "inner" declaration points to table for "outer"
linked list, searched from end to beginning (recal
environments from CS312)

8.2 Declarations : Nested Procedures

Semantic rules are a little more complicated:


mktable (previous) creates and returns a new s.t., pointing to
previously created one
enter (table, name, type, offset) acts like enter, but using a
specified table
addwidth (table, width) records cumulative width of all
entries in table
enterproc (table, name, newtable) creates new entry for
procedure name in existing table, and assigns newtable to be
the s.t. for this new proc.
Can do it all in one pass, if we use stacks tblptr, offset to keep
track of symbol tables and offsets:

nil

f:

x
g

g:

x
y

8.2 Declarations : Nested Procedures


P

MD


M
D

8.2 Declarations : Nested Procedures

{ addwidth(top(tblptr), top(offset));
pop(tblptr); pop(offset); } // done after M's
// actions
{ t := mktable(nil);
push(t, tblptr); push (0, offset) }

8.2 Declarations : Nested Procedures


D

N


id : T

{ enter (top (tblptr), id.name, T.type, top ( offset));


top(offset) := top( offset) + T.width) }

{ t := mktable( top ( tblptr ) );


push(t, tblptr); push (0, offset) }

D,D


fun id N ( D1 ) = S

{ t := top (tblptr);
addwidth (t, top ( offset ));
pop(tblptr); pop(offset);
enterproc( top ( tblptr), id.name, t ) }
continues ...

Let's try it with


let fun f(x:int) =
let fun g(x:int, y:int) = x
in f(g(3, 4)) end end

+ y

You might also like