NAME (print clearly): |
Question | Mark |
1. Dynamic scope [6 marks] | |
2. Tail recursion [6 marks] | |
3. Variadic functions [6 marks] | |
4. Higher order functions [6 marks] | |
5. Macros [6 marks] | |
6. CFGs and ambiguity [6 marks] | |
7. CFGs, precedence, and associativity [6 marks] | |
8. Context senstive checking and symbol tables [6 marks] | |
9. Type checking, conversions, and compatibility [6 marks] | |
10. Attributes and binding [6 marks] | |
11. Smart pointers [6 marks] | |
12. Type implementations and implications [6 marks] | |
Exam Total [72 marks] |
Question 1: Dynamic scope [6]
The table below shows one bash program and its resulting output and one lisp program and its resulting output.
Using the provided code/output as your evidence, explain which of the languages (if any) are using dynamic scoping and which are using lexical scoping. Be sure to use the provided code/output to clearly justify your answer.
x=10 function f() { echo "at the start of f: x is ${x}" local x=20 g echo "back in f after running g: x is ${x}" } function g() { echo "at the start of g: x is ${x}" x=30 } function main() { echo "at the start of main: x is ${x}" f echo "at the end of main: x is ${x}" } main | (defvar x 10) (defun f () (format t "at the start of f: x is ~A~%" x) (let ((x 20)) (g) (format t "back in f after running g: x is ~A~%" x))) (defun g () (format t "at the start of g: x is ~A~%" x) (setf x 30)) (defun main () (format t "at the start of main: x is ~A~%" x) (f) (format t "at the start of main: x is ~A~%" x)) (main) |
at the start of main: x is 10 at the start of f: x is 10 at the start of g: x is 20 back in f after running g: x is 30 at the end of main: x is 10 | at the start of main: x is 10 at the start of f: x is 10 at the start of g: x is 20 back in f after running g: x is 30 at the start of main: x is 10 |
Question 2: Tail recursion [6]
This semester we discussed systematic transformations of iterative functions into tail-recursive ones.
Based on those discussions, provide a tail-recursive equivalent of the following (C++) function:
int q2(int x, int y) { int r = 0; int i = 1; while (i < y) { r = i + f(r); x = g(x); i++; } return r; } |
Question 3: Variadic functions [6]
In lab6 we considered a way to implement variadic functions in C++ using a recursive template format.
Suppose we wanted something more like lisp's approach, where we could have a parameter specifier indicating any number of additional arguments could be passed, and they would all be gathered in the final parameter, e.g.
void myFunc(int x, int y, variadic int R[], int RSize) // all the "extra" arguments must be of type int // and are collected as the elements of array R // whose size is then stored in RSize |
Discuss the benefits and problems that would arise from such an addition to the C++ language.
Question 4: Higher order functions [6]
In lab 6 we used templates to develop a C++ apply function, e.g. r = apply(pow, x, y); or r = apply(sqrt, x);.
Outline the strengths and weaknesses of such an apply function as compared to common lisp's version of apply.
Question 5: Macros [6]
Mark Shannon makes the following statement in support of macro systems (as part of Python Enhancement Proposal 638):
Question 6: CFGs and ambiguity [6]
The grammar below is ambiguous.
Briefly explain the source of the ambiguity, and provide a revised set of rules to remove the ambiguity while still accepting the same set of assignment expressions.
(The VARNAME token is an alphabetic string representing a variable name and the ASSIGNOP token is simply the = character.)
assignment --> VARNAME assignment --> assignment ASSIGNOP assignment |
Question 7: CFGs, precedence, and associativity [6]
Study the following set of context free grammar rules with three operator tokens (XOP, YOP, ZOP) and four expression nonterminals (expression, exprA, exprB, exprC), then identify the relative precedence level and the associativity for each of the three operators and explain how you arrived at your answer.
expression --> exprB expression --> exprB XOP expression exprA --> exprA ZOP exprC exprA --> exprC exprB --> exprA YOP exprB exprB --> exprA |
Question 8: Context sensitive checking and symbol tables [6]
Consider the following set of context free grammar rules (with tokens represented in uppercase and nonterminals in lowercase) and identify the correct spots in the correct rules where:
statements --> statement statments --> statement statements statement --> assignment statement --> declaration assignment --> VARNAME ASSIGNOP value declaration --> scopetype VARNAME scopetype --> GLOBAL scopetype --> LOCAL value --> VARNAME value --> NUMBER |
Question 9: Type checking, conversions, and compatibility [6]
Erlang is a dynamically typed language that allows us to define function behaviour in terms of what the function does for different combinations of parameters, e.g. a function to compute the nth fibonacci number could be expressed as
% rules for fib(N) % the conditions for a rule are left of the ->, % the result for the rule is to the right of the -> fib(0) -> 0; fib(N) when is_integer(N), N < 1 -> 0; fib(N) when is_integer(N), N < 3 -> 1; fib(N) when is_integer(N) -> fibhelper(N, 0, 1). % rules for fibhelper(N, pp, p) where N is how many N's we have left to count % and pp, p are the two most recent fib numbers calculated fibhelper(1, _, P) -> P; fibhelper(N, PP, P) -> fibhelper(N-1, P, PP+P). |
What we're interested in is that _ parameter: it is used to indicate a parameter whose value we don't care about (i.e. it can be ignored in this rule). In this particular rule it says the value of the PP parameter is irrelevant if the value of the N parameter is 1.
Suppose it were possible in lisp to pass a don't care value when calling a function, e.g. (foo 13 _ 4.6).
Discuss the possible benefits of this (if any), and the implications for runtime type checking by the caller.
Question 10: Attributes and binding [6]
In lectures we discussed a variety of types of attribute (name, value, type, storage, scope, lifetime) and the options to either statically or dynamically bind each of them.
For each of the six kinds of attribute, name a language where that attribute can be dynamically bound and provide a brief justification (justifying the claim that the named language can bind that attribute dynamically).
Question 11: Smart pointers [6]
In our final lecture we discussed smart pointers in the context of C++.
While a lisp programmer doesn't generally need to worry about how memory is handled, the developers of lisp compilers/interpretters do need to deal with how items (e.g. lists) are dynamically allocated/deallocated in the heap, and how to keep track of when deallocation should take place.
If we were to use C++ as the language in which we wrote our lisp compiler, would smart pointers be a sensible choice, or would we be better off using standard raw pointers for the implementation? Discuss/justify your answer.
Question 12: Type implementations and implications [6]
When considering structs/records as a data type, we discussed the problems relating to memory alignment and the ordering of fields within the structure.
Suppose we were designing a new C-like language, and someone proposed the following as a solution to this problem:
Discuss the problems/drawbacks with such a solution.