CS 334
|
Do problem 8.18 on page 8-34. Note that each successive function is nested inside the previous. I.e., env contains a, which contains b, which contains c. Also env calls a, which calls b, which calls c, which then calls b again.
a. After the first call to procedure a, there is an activation record for env and on top of that, one for a. The access (static) and control (dynamic) links for a both point to env.
a'. After the second call to b, we have the following:
______ | b |-- _______ | | c | | _______ | | b | | _______ | | a |<- _______ | env | _______All static links go down to the previous activation record except for the one shown from b to a. All dynamic links go down one.
b. procedure b is found in procedure c by following up two static links from c's activation record. This gives us the activation record for a. In there we find a slot for b that holds the < ip,ep > pair where ip is the instruction pointer for b and ep is a pointer to the activation record for a.
Do problem 8.24 on page 8-36.
Blocks in C (or Algol or Ada or ...) are guaranteed to always have the same static and dynamic links (because they can only be called from the surrounding code - no remote calls are possible). Thus, you could drop the static link as redundant. You typically do allocate a new activation record for each block, as if there are several disjoint blocks, the computer can reuse stack space by pushing and popping the activation records on top of the same old activation record. You can also drop the return address because the block always returns to the same location. I.e., either the code for the block can be embedded in the surrounding code or the last line of the code for the block can be a jump to the hard-wired location of the next instruction.
Of course, you may allocate all of the space at once by essentially flattening the code containing the block (essentially erase the block boundaries). However, then you lose the advantages of reusing the space. Most of the time you don't care, but if the blocks introduce large arrays then pushing and popping the activation records can save a lot of space. If you aren't going to allocate the space dynamically then you might as well not even allow local blocks.
Do problem 9.20 on page 9-39.
frontq(enqueue(enqueue(create,x),y)) = if emptyq(enqueue(create,x)) then y else frontq(enqueue(create,x)) = frontq(enqueue(create,x)) = if emptyq(create) then x else frontq(create) = x because emptyq(create) is true
frontq(enqueue(deque(enqueue(create,x)),y)) = if emptyq(deque(enqueue(create,x))) then y else frontq(deque(enqueue(create,x))) [but deque(enqueue(create,x)) = if emptyq(create) then create else ..., so] = if emptyq(create) then y else frontq(deque(enqueue(create,x))) = y
frontq(dequeue(enque(enqueue(create,x)),y)) = frontq(enqueue(deque(enqueue(create,x)),y))because empty(enqueue(deque(enqueue(create,x)),y) = false, but we know by above that this last expression is equal to y.
When you evaluate a function call (with a user-defined function), you should not evaluate the parameter, instead package the (unevaluated) actual parameter and the current environment into a Thunk and insert it into the environment in the same way that you used to insert the value of the actual parameter into the environment. Make sure that the THUNK is handled properly when its value is needed.
Click here for solution.
Recall the signature EQ and functor PairEQ from Lecture 15. Please write a functor ListEQ that takes a structure P:EQ and constructs another structure matching signature EQ such that the elements of type t are lists of elements from type P.t, and two elements are equal if they are the same length and corresponding elements are equal according to P.eq.
Test your functor by applying it to structure IntEQ from lecture 15 to construct a structure named ListIntEQ. Show that that ListIntEQ works properly by building elements of type ListIntEQ and applying the function ListIntEQ.eq to the elements.
signature EQ = sig type t val eq : t * t -> bool end; structure IntEQ : EQ = struct type t = int val eq : t*t->bool = op = end; functor ListEQ(P : EQ) : EQ = struct type t = P.t list fun eq([],[]) = true | eq((fst1::rest1),(fst2::rest2)) = P.eq(fst1,fst2) andalso eq(rest1,rest2) | eq _ = false; end; structure IntListEQ : EQ = ListEQ(IntEQ);