Frontend: enforce semantics
lexical analysis
parsing
semantic alalysis
Backend: generating code
optimization
code generation
Two Separation:
static structure (compile-time)
dynamic structure (run-time)
The goal is to solve two problems simultaneously:
runtime correctness
runtime speed
Two Assumptions: for simplicity for now
execution is sequential (concurrency violates this)
when procedural is called, control always return to the point immediately after the call (exception, call/cc)
Activation: the act of invoking a procedure P is called activation of P
Lifetime:
for procedure: all the steps from invoking P to P returns control
for variable: portion of execution where variable x is defined
Lifetime is dynamic (run-time) concept and scope is static concept
We can use a stack to track activation, since activations can be arranged into a tree.
Frame (Activation Record): data kept so that when F()
calls G()
, frame has the proper information to complete execution of G()
and resume execution of F()
. So frame store things both related to G()
and F()
Compiler must determine the layout of activation record and generate code that correctly access location in the activation record. So activation layout and code generation must be designed together.
Memory Layout:
code: usually fixed size and read only
data: static with fixed address (global data), readable and writable
frame: for each currently active procedure
heap: managed by malloc
and free
Stack Machine: only stack memory, no heap
n-register stack machine: keep top n location of the stack in register
1-register stack machine: the only register is called accumulator (it accumulates result from the stack)
In a pure stack machine,
add
has 3 operation: 2 reads from stack and 1 write to stack. However, in 1-register stack machine,add
has only 1 operation: 1 read from stack since the other input number and the returning number is already on the register.
Table of Content