Presentation is loading. Please wait.

Presentation is loading. Please wait.

Course Overview PART I: overview material PART II: inside a compiler

Similar presentations


Presentation on theme: "Course Overview PART I: overview material PART II: inside a compiler"— Presentation transcript:

1 Course Overview PART I: overview material PART II: inside a compiler
1 Introduction 2 Language processors (tombstone diagrams, bootstrapping) 3 Architecture of a compiler PART II: inside a compiler 4 Syntax analysis 5 Contextual analysis 6 Runtime organization 7 Code generation PART III: conclusion Interpretation 9 Review

2 Arguments We have already discussed how space on the stack is allocated for arguments to routines. We now discuss some specific issues about passing by value versus passing by reference passing of functional and procedural parameters

3 Arguments: by value or by reference
Some programming languages allow two kinds of parameter passing to functions/procedures. Example: in Triangle (similar in Pascal or C++) Var/reference parameter Constant/value parameter let proc S(var n:Integer, i:Integer) ~ n:=n+i; var today: record y:integer, m:Integer, d:Integer end; in begin b := {y ~ 2002, m ~ 2, d ~ 22}; ! b is non-local S(var b.m, 6); end

4 Arguments: by value or by reference
Value parameters: At the call site the argument is an expression. The evaluation of that expression leaves some value on the stack. This value is passed to the procedure/function. Typical instructions for putting a value parameter on the stack: LOADL 6 LOAD 3[L1] Var/reference parameters: Instead of passing a value on the stack, the address of a memory location is pushed. This implies a restriction that only “variable-like” things can be passed to a var parameter. In Triangle there is an explicit keyword var at the call-site, to signal passing a var parameter. In Pascal and C++ the reference is created implicitly (but the same restrictions apply). Typical instructions for putting a var parameter on the stack: LOADA 5[LB] LOADA 10[SB]

5 Functional / Procedural Parameters
In Triangle (and Pascal) a limited version of higher-order programming is possible. One may pass functions/procedures as arguments to other functions/procedures. (Unlike Scheme, they are not first-class values!) Example 1: let func twice(func doIt(Integer x): Integer, Integer i) ~ doIt(doIt(i)); func double(Integer d): Integer ~ d*2; var twenty : Integer in begin twenty := twice(double,5); end A procedural/functional parameter is passed by pushing a “closure” on the stack. A closure consists of two parts: 1. the static link of the procedure/function 2. the address of the procedure/function

6 Functional / Procedural Parameters
Example 2: (illustrates we can pass non-global functions as well) let func twice(func doIt(Integer x): Integer, Integer i) ~ doIt(doIt(i)); func cubed(Integer b): Integer ~ let func multiply(Integer x): Integer ~ x*b in twice(multiply, b); in begin ... ... cubed(4) ... end accesses lexically scoped var See pictures of stack beginning on next slide…

7 Functional / Procedural Parameters
right after calling cubed right before call to twice SB arg b 4 LB arg b 4 link data LB link data arg #1 multiply closure multiply function code ST arg #2 4 ST static link function address

8 Functional / Procedural Parameters
right after call to twice before first call to doIt arg b arg b 4 4 link data link data arg doIt arg doIt multiply closure multiply closure multiply multiply arg i arg i 4 4 LB LB link data link data ST arg #1 4 closure to call multiply closure multiply ST Note: to avoid clutter, dynamic links are not shown. Only some static links are shown.

9 Functional / Procedural Parameters
execution of CALLI instruction (Call Indirect) before first call to doIt right after first call to doIt arg b arg b 4 4 link data link data arg doIt arg doIt multiply closure multiply closure multiply multiply arg i arg i 4 4 LB link data link data arg #1 4 arg x 4 LB closure to call multiply closure link data multiply ST ST

10 Functional / Procedural Parameters
right after first call to doIt just before x*b in multiply arg b arg b 4 4 link data link data arg doIt arg doIt multiply closure multiply closure multiply multiply arg i arg i 4 4 link data link data arg x 4 arg x 4 LB LB link data link data ST value of x LOAD [-1]LB 4 value of b LOAD [-1]L1 4 ST

11 Functional / Procedural Parameters
just before return doIt/multiply just after return doIt/multiply arg b arg b 4 4 link data link data arg doIt arg doIt multiply closure multiply closure multiply multiply arg i arg i 4 4 LB link data link data value of doIt(4) arg x 4 16 LB ST link data value of x*b 16 ST

12 Functional / Procedural Parameters
just before second call to doIt just before x*b in multiply arg b arg b 4 4 link data link data arg doIt arg doIt multiply closure multiply closure multiply multiply arg i arg i 4 4 LB link data link data arg #1 16 arg x 16 LB closure to call multiply closure link data multiply ST value of x LOAD [-1]LB 16 value of b LOAD [-1]L1 4 ST

13 Functional / Procedural Parameters
just after return doIt/multiply = just before return from “twice” just after return from “twice” =just before return from cubed arg b 4 4 LB link data link data arg doIt arg doIt multiply closure multiply closure multiply multiply arg i value of twice(multiply,4) 4 64 LB ST link data value of doIt(16) 64 just after return from cubed ST value of cubed(4) 64 ST

14 Functional / Procedural Parameters
Why does the stack allocation model for functional/procedural parameters work? More precisely, why can closure objects and the static frames they point to be completely in the stack? (In Scheme for example static environments are allocated in the heap.) It is sufficient to ensure that every closure object can never outlive the static frame to which it points. Points upward is OK! multiply closure Points downward would be BAD! multiply closure

15 Recursion How are recursive functions and procedures supported on a low-level machine? => Surprise! The stack memory allocation model already works! Example: let func fac(n:Integer) ~ if (n<=1) then 1 else n*fac(n-1); in begin putint(fac(6)); end Why does it work? Because every activation of a function gets its own activation record on the stack, with its own parameters, locals etc. All procedures and functions are “reentrant”. Older languages (e.g. FORTRAN) that use static allocation for locals have problems with recursion.

16 Recursion: General Idea
Why the stack allocation model works for recursion: Like other function/procedure calls, lifetimes of local variables and parameters for recursive calls behave like a stack. fac(4) ? fac(4) fac(4) fac(3) fac(3) fac(4) fac(3) fac(4) fac(3) fac(2) fac(2) fac(4) ? fac(3) fac(2) fac(1) fac(3) fac(2) fac(2) fac(1)

17 right before recursive
Recursion: In Detail let func fac(n:Integer) ~ if (n<=1) then 1 else n*fac(n-1); in begin putint(fac(6)); end right after entering fac right before recursive call to fac before call to fac SB SB SB arg 1 arg 1 arg n 6 6 6 ST LB LB link data link data ST value of n 6 arg: value of n-1 5 ST

18 right before recursive
Recursion right before recursive call to fac right before next recursive call to fac right before next recursive call to fac SB SB SB arg n arg n arg n 6 6 6 LB link data link data link data value of n value of n value of n 6 6 6 arg arg n arg n 5 5 5 ST LB link data link data value of n value of n 5 5 arg arg 4 4 ST LB link data value of n 4 arg 3 ST

19 Recursion Is the spaghetti of static and dynamic links getting confusing? Let’s zoom in on just a single activation of the fac procedure. The pattern is always the same: just before recursive call in fac to caller context (= previous LB) ? to lexical context (= SB) argument n LB link data n Intermediate results in the computation of n*fac(n-1); n-1 ST

20 just before the return from
Recursion just before the return from the “deepest call”: n=1 after return from deepest call argument n=2 link data n=2 LB caller frame (what’s in here?) ? Next step: multiply argument n=1 result=1 LB ST link data result = 1 ST

21 ? Recursion just before the return from the “second deepest call”: n=2
(after return from deepest call and multiply) to caller context to lexical context (= SB) argument n=2 link data 2*fac(1)=2 LB caller frame (what’s in here?) ? result Next step: return ST From here on down the stack is shrinking, multiplying each time with a bigger n

22 after completing recursive call
Recursion just before recursive call in fac after completing recursive call argument n argument n LB LB link data link data n n recurs. arg: n-1 fac(n-1) ST ST Calling a recursive function is just like calling any other function. After completion it just leaves its result on the top of the stack! A recursive call can happen in the midst of expression evaluation. Intermediate results, local variables, etc. simply remain on the stack, and computation proceeds when the recursive call is completed.


Download ppt "Course Overview PART I: overview material PART II: inside a compiler"

Similar presentations


Ads by Google