Exercise 1: Consider the following procedure swap2.
procedure swap2 (x, y : integer); procedure f() : integer; var z : integer; begin (* f *) z := x; x := y; return z; end; begin (* swap2 *) y := f(); end;
Describe the effect of the procedure call swap2(i, A[i]) under each of the following parameter passing methods:
Answer:
a. Call-by-value: no effect In the procedure swap2(), x will be assigned the value of i, and y will be assigned the value of A[i]. When procedure f() is called, the values of x will be changed to the value of y. When f() returns, it will be changed to the value of x. However, when the procedure swap2() returns, the values of i and A[i] will be unchanged. b. Call-by-reference: the values will be swapped Instead of copying values as in (a) when we call swap2() by reference, x "points" to the memory address which i is located, and y "points" to the memory address where A[i] is located. Thus, any change in x will immediately change i, and any change in y will immediately change A[i]. Note -- this will cause harmful effects on A[i], by putting i out of range, however, upon return from swap2(), and immediate reference of A[i] may not give you what you think, and may cause runtime errors. So, at z=x, z becomes what i is, and at x = y, i becomes what A[i] is, and at return z, y becomes what z is (and what i was). When we return from the function, i and A[i] (old i) are successfully swapped. c. Call-by-value-result: the values will be swapped This will have the same results as (b) except x and y are copies of the values of i and A[i] respectively and contain their own memory. The values of these two are successfully swapped, and on completion of swap2(), x is copied into i and y is copied into A[i] (old i). d. Macro expansion: Unpredictable Has unknown results due to the expansion happens as each line is reached. The piece of code which has the statements "z = x; x= y; return z;" will expand to x=i; i=A[i] and return i; the line "y = f()" becomes "A[i] = f()", but i now has changed to whatever A[i] was storing, which could put the array index out of bounds. At best some new A[i] array element will change, but the original A[i] will remain unchanged.
a. Call-by-value: no effect In the procedure swap2(), x will be assigned the value of i, and y will be assigned the value of A[i]. When procedure f() is called, the values of x will be changed to the value of y. When f() returns, it will be changed to the value of x. However, when the procedure swap2() returns, the values of i and A[i] will be unchanged.
b. Call-by-reference: the values will be swapped Instead of copying values as in (a) when we call swap2() by reference, x "points" to the memory address which i is located, and y "points" to the memory address where A[i] is located. Thus, any change in x will immediately change i, and any change in y will immediately change A[i]. Note -- this will cause harmful effects on A[i], by putting i out of range, however, upon return from swap2(), and immediate reference of A[i] may not give you what you think, and may cause runtime errors. So, at z=x, z becomes what i is, and at x = y, i becomes what A[i] is, and at return z, y becomes what z is (and what i was). When we return from the function, i and A[i] (old i) are successfully swapped.
c. Call-by-value-result: the values will be swapped This will have the same results as (b) except x and y are copies of the values of i and A[i] respectively and contain their own memory. The values of these two are successfully swapped, and on completion of swap2(), x is copied into i and y is copied into A[i] (old i).
d. Macro expansion: Unpredictable Has unknown results due to the expansion happens as each line is reached. The piece of code which has the statements "z = x; x= y; return z;" will expand to x=i; i=A[i] and return i; the line "y = f()" becomes "A[i] = f()", but i now has changed to whatever A[i] was storing, which could put the array index out of bounds. At best some new A[i] array element will change, but the original A[i] will remain unchanged.
Exercise 2:
Consider the following program and describe the effect of running the program with both lexical scoping and dynamic scoping.
program main; var x : integer; procedure sub1; begin writeln ('x=', x) end; procedure sub2; var x : integer; begin x := 10; sub1; end; begin x:= 5; sub2; end.
With lexical scoping, the program will print 'x=5' and with dynamic scoping the program will print 'x=10'.
Exercise 3: Describe the stack contents (the activation records) for the following program at the point where pred(2) is called.
program activations; function pred (m: integer) : integer; begin pred := m-l; end; function f (n: integer): integer; begin if n = 0 then f := 1 else f := n * f (pred(n)) end; begin f(3); end.
activation record for f(3): arg = 3 PC (state info) activation record for f(2): arg = 2 PC (state info) activation record for p(2): arg = 2
Exercise 4: Write and compile the "hello world" program on your favorite C++ compiler. Submit the source code here.
#include <iostream.h> main () { cout << "hello world\n"; return 0; }
Exercise 5: Modify the stack program that we described in class to implement a first-in/first out buffer, based on the following invariants:
#include <iostream.h> #define STACK_SIZE 5 // stack size //******************************************************************** // Class: Stack //******************************************************************** class stack{ protected: int buffer[STACK_SIZE]; // the queue int holds; // number of elements in the queue int first_in; // pointer to front of the queue int last_in; // pointer to last element in the queue; public: stack(); // Constructor inits all private variables void push(int v); // place element in queue int pop(void); // remove element from queue }; //******************************************************************** // Default constructor // inits all private variables //******************************************************************** stack::stack(void) { holds = 0; // init number of elements in the queue first_in = 0; // " pointer to front of queue last_in = 0; // " pointer to end of queue } //******************************************************************** // Method: Pop // removes elements from the front of the queue //******************************************************************** int stack::pop(void){ if (holds == 0){ cout << "**ERROR - Queue is empty. Zero returned.\n"; return(0); } if ( ++first_in > STACK_SIZE-1 ) { first_in = 0; } --holds; return buffer[first_in]; } //******************************************************************** // Method: Push // places an element at the end of the queue //******************************************************************** void stack::push(int v){ if (holds == STACK_SIZE){ cout << "**ERROR - Queue is full. Element: " << v << " rejected.\n"; return; } if ( ++last_in > STACK_SIZE-1) { last_in = 0; } ++holds; buffer[last_in] = v; } //******************************************************************** // Testing class stack //******************************************************************** int main() { stack s; s.push(1); s.push(2); s.push(3); cout << s.pop() << endl; cout << s.pop() << endl; cout << s.pop() << endl; return(0); }