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