PROBLEM 1
a)


program main()
var A, B, C: integer; // binding occurrences; let's call them main.A, main.B, main.C


procedure p1() 		 
	var X: integer;	// binding occurrence; let's call it p1.X
begin	
	X:=A;	// applied occurrences of X and A to p1.X and main.A, respectively
	A:=B;	// applied occurrences of A and B to main.A and main.B, respectively
	B:=C;	// applied occurrences of B and C to main.B and main.C, respectively
	C:=X;	// applied occurrences of C and X to main.C and p1.X, respectively
end;


procedure p2()  
	var B: integer;		// binding occurrence; let's call it p2.B
begin
	B:= A; 	// applied occurrences of X and A to p2.B and main.A, respectively	
	p1();	
end;


b) static scoping output: 3, 1, 2

c) dynamic scoping output: 2, 3, 2

d) by using fully qualified expression, i.e., the "path prefix"
leading to the corresponding binding occurrence, e.g., main.B
vs. p2.B, or by some other renaming mechanism which produces unique
names.




PROBLEM 2
a) 	before swap() in main: 	i = 2, 	a[2] = 30;
	after swap() in main: 	i = 30, a[2] = 2;

explanation: when the procedure is called, the REFERENCES to i and
a[2] are passed in the ACTIVATION RECORD on the RUNTIME STACK. Hence,
afterwards i will be 30 and a[2] will be 2.

b) body of swap becomes:
	begin
		tmp := i;   		( tmp = 2)
		i := a[i], 		( i = 30)
		a[i] := tmp;		( a[30] = 2 <== ATTEMPTED,
                                          ... but leads to an ACCESS VIOLATION...)


...since we are attempting to access past end of array.  Hence a
runtime error will be reported in languages that check the array
boundaries (e.g., IndexOutOfBounds).

If they are not checked say when using C/C++ (often compilers allow to 
turn range checking at runtime on or off!), then we may get a
"segmentation fault", "memory violation" because we may access memory
that is "not ours", or we may read a memory location that happens to
be accessible -- but we still access memory that has not been declared 
a part of the array!