CSC8503 Principles of Programming Languages Semester 1, 2015
Assignment 2
Due Date: 11:55pm AEST (13:55 UTC/GMT) Monday 10 May 2015
Weighting: 20%
Total marks: 20
Please submit this assignment using the assignment submission facility on the course
Study Desk. Submit a single file, either a ZIP or TAR archive. The archive
should contain (1) for Part A, a Haskell source file containing the function definitions,
and (2) for Part B, your version of all the files that are in the SPL distribution that you
downloaded.
Just add the Haskell file (call it say ass2.hs) to your collection of SPL files and zip or
tar them into an archive that you submit.
Part A – Haskell – 12 marks
Complete the following Haskell function definitions. Unless stated otherwise do not use library
functions that are not in the Haskell standard prelude. This constraint is so that you
gain practice in simple Haskell recursive programming. The Haskell 2010 standard prelude
definition is available at
https://www.haskell.org/onlinereport/haskell2010/haskellch9.html
Place all definitions in a single file. Submit just this text file electronically as
directed on the course Study Desk page. Use the specified function name as your
code will be tested by a Haskell function expecting that function name.
The testing program may use many more test cases than the ones shown in the specification.
So, please test your functions extensively to ensure that you maximise your marks.
1. [2 marks]
Write the function insertAt :: Int -> a -> [a] -> [a].
insertAt n x xs will insert the element x into the list xs at position n items from the
beginning of xs. In other words, skip n items in xs, then insert the new element.
You can assume that n will be a non-negative number. If n is greater than the length of
the list xs then add it to the end of the list.
For example
insertAt 3 ’-’ "abcde" ⇒ "abc-de"
insertAt 2 100 [1..5] ⇒ [1,2,100,3,4,5]
Hint: Use standard prelude functions ++ and splitAt.
2. [2 marks] Write a function uniq :: Eq a => [a] -> [a] that removes duplicate entries
from a sorted (in ascending order) list. The resulting list should be sorted, and no value
in it can appear elsewhere in the list.
For example:
1
https://www.haskell.org/onlinereport/haskell2010/haskellch9.html
uniq [1,2,2] ⇒ [1,2]
uniq [1,2,3] ⇒ [1,2,3]
3. [1 mark] Write a function
join :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,c)].
join takes two lists of pairs, and returns a single list of triples. A triple is generated only
when there exists a member of both argument lists that have the same first element. The
list elements are not sorted. This is the same semantics as the relational algebra natural
join operation.
For example:
join [(2,"S"),(1,"J")] [(2,True),(3,False)]
⇒ [(2,"S",True)]
join [(2,"S"),(1,"J")] [(2,1),(2,2),(3,4)]
⇒ [(2,"S",1),(2,"S",2)]
Hint: use list a comprehension.
4. [1 mark] This question extends the join function from question 3. Write the function
ljoin :: Eq a => [(a,b)] -> [(a,c.
CSC8503 Principles of Programming Languages Semester 1, 2015.docx
1. CSC8503 Principles of Programming Languages Semester 1,
2015
Assignment 2
Due Date: 11:55pm AEST (13:55 UTC/GMT) Monday 10 May
2015
Weighting: 20%
Total marks: 20
Please submit this assignment using the assignment submission
facility on the course
Study Desk. Submit a single file, either a ZIP or TAR archive.
The archive
should contain (1) for Part A, a Haskell source file containing
the function definitions,
and (2) for Part B, your version of all the files that are in the
SPL distribution that you
downloaded.
Just add the Haskell file (call it say ass2.hs) to your collection
of SPL files and zip or
tar them into an archive that you submit.
Part A – Haskell – 12 marks
Complete the following Haskell function definitions. Unless
stated otherwise do not use library
functions that are not in the Haskell standard prelude. This
constraint is so that you
gain practice in simple Haskell recursive programming. The
Haskell 2010 standard prelude
2. definition is available at
https://www.haskell.org/onlinereport/haskell2010/haskellch9.ht
ml
Place all definitions in a single file. Submit just this text file
electronically as
directed on the course Study Desk page. Use the specified
function name as your
code will be tested by a Haskell function expecting that
function name.
The testing program may use many more test cases than the
ones shown in the specification.
So, please test your functions extensively to ensure that you
maximise your marks.
1. [2 marks]
Write the function insertAt :: Int -> a -> [a] -> [a].
insertAt n x xs will insert the element x into the list xs at
position n items from the
beginning of xs. In other words, skip n items in xs, then insert
the new element.
You can assume that n will be a non-negative number. If n is
greater than the length of
the list xs then add it to the end of the list.
For example
insertAt 3 ’-’ "abcde" ⇒ "abc-de"
insertAt 2 100 [1..5] ⇒ [1,2,100,3,4,5]
Hint: Use standard prelude functions ++ and splitAt.
2. [2 marks] Write a function uniq :: Eq a => [a] -> [a] that
removes duplicate entries
from a sorted (in ascending order) list. The resulting list should
3. be sorted, and no value
in it can appear elsewhere in the list.
For example:
1
https://www.haskell.org/onlinereport/haskell2010/haskellch9.ht
ml
uniq [1,2,2] ⇒ [1,2]
uniq [1,2,3] ⇒ [1,2,3]
3. [1 mark] Write a function
join :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,c)].
join takes two lists of pairs, and returns a single list of triples.
A triple is generated only
when there exists a member of both argument lists that have the
same first element. The
list elements are not sorted. This is the same semantics as the
relational algebra natural
join operation.
For example:
join [(2,"S"),(1,"J")] [(2,True),(3,False)]
⇒ [(2,"S",True)]
join [(2,"S"),(1,"J")] [(2,1),(2,2),(3,4)]
⇒ [(2,"S",1),(2,"S",2)]
Hint: use list a comprehension.
4. [1 mark] This question extends the join function from
question 3. Write the function
4. ljoin :: Eq a => [(a,b)] -> [(a,c)] -> [(a,b,Maybe c)].
This is the left outer join from relational algebra. If a tuple
(database row) from the first
(left) argument does not have a matching tuple from the second
argument, include that
tuple in the resulting tuple, but place a “null” value in place of
the un-matched value. For
this implementation we use a Maybe data type, and use the
Nothing value to denote Null.
For example
ljoin [(2,"S"),(1,"J")] [(2,1),(2,2),(3,4)]
⇒ [(2,"S",Just 1),(2,"S",Just 2),(1,"J",Nothing)]
5. [2 marks] Consider the following definition for a binary tree.
data Tree a = Leaf a | Node (Tree a) (Tree a)
A binary tree is balanced if, at every node, the difference
between the number
of leaves appearing in the left and right subtree is at most one.
(A tree which
contains just one leaf is considered balanced.)
Write the function isBalanced :: Tree a -> Bool that decides if
the tree is balanced.
Hint: first write a function size::Tree a -> Int that counts leaves
in a tree.
isBalanced (Node (Node (Leaf 1)(Leaf 3)) (Leaf 2)) ⇒ True
isBalanced (Node (Node (Leaf 1)(Node (Leaf 1)(Leaf 3))) (Leaf
2))
⇒ False
5. 6. [2 marks] Write a function isNumber :: String -> Bool that
tests if a string contains
a valid number. A valid number is defined in EBNF as:
number → .digit+ | digit+ [ .digit∗ ]
For example, .5, 1.5, 1, 1. are all valid numbers. As usual, +
signifies one or more
occurrences, and * denotes zero or more.
You may use the isDigit function from the Data.Char module.
Hint: you may wish to write functions someDigits, manyDigits
:: String -> Bool
to test for .digit+ and digit∗ .
2
7. [2 marks] Write a function getElems :: [Int] -> [a] -> [Maybe
a] which takes a
list of integers signifying the position of an element in a list,
and a list. It returns those
elements that correspond to the positions specified. Because a
position may be greater
than the list size the returned element is a Maybe data type. If
the position specified is
greater the the maximum list position then Nothing is returned,
else Just value.
For example
getElems [2,4] [1..10] ⇒ [Just 3,Just 5]
getElems [2,4] [1..4] ⇒ [Just 3,Nothing]
6. Part B – SPL – 8 marks
You are required to make a number of modifications to the SPL
compiler. The SPL laboratories
provide an introduction to the implementation of SPL and the
SPL Reference Manual supplies
extra information.
The SPL source code and other resources are available at
https://tau.usq.edu.au/courses/CSC8503/resources.html
Important: get a fresh copy of the SPL distribution before
starting work as it has
been modified slightly from earlier versions used in the
tutorials.
Each of the following questions is independent in that they do
not rely on any of the other
modifications. In marking the assignment, they will be tested
independently.
I will be compiling and running your SPL system so your code
must compile and run. If you are
unable to get some parts working and GCC or Bison compile
errors exist, then comment out
the error-producing code so that I can compile and execute what
you do have working.
Make sure you include all necessary files including the
Makefile. I should be able to just type
‘make’ and your system will be compiled on my machine.
1. [3 marks] Implement an autoincrement operator for variables.
The syntax for these new
operations is described by the extended factor grammar rule
factor → ++id | id++ | id | num | ( expression ) | - expression
7. These have the same semantics as the C operators of the same
kind. The value of pre-
increment expression ++x is the current value of x, plus one ,
while the value of post-
increment expression x++ is the current value of x. Evaluation
of both operators would
increase the stored value of x by one. Consider the following
program.
var a; { a := 1;
display a;
display a++;
display a;
display ++a;
display a;
}
On execution it should produce as output the sequence 1, 1, 2,
3, 3.
You will need to modify the lexer lexer.c and the parser spl.y as
follows:
3
https://tau.usq.edu.au/courses/CSC8503/resources.html
• Create new token name (say) INC in spl.y, and modify lexer.c
to recognise the cor-
8. responding ++ symbol. Look at the way two-character symbols
like ‘>=’ are handled.
Make sure that you update dispToken().
• Add grammar rules for the two new factor alternatives in
spl.y.
• Generate the increment code for the two increment operators.
Use the current rule
for factor : IDENT as a basis. You will need to generate add and
move operations.
You’ll probably need a new temporary register, whose number
will be stored in a
variable like reg, to store the operand ‘1’.
2. [2 marks] Implement a do ... until post-tested loop. The
statement has syntax:
do statement+ until condition ;
Note that the body is a list of statements. This is different from
the ‘while’ loop whose
body is a compound statement. Also note the trailing semicolon.
You will need to modify the lexer lexer.c and the parser spl.y as
follows:
• Create new token name (say) UNTIL in spl.y, and modify
lexer.c to recognise the
corresponding until reserved word. Make sure that you update
dispToken().
• Add the ‘until’ loop grammar rule to spl.y.
• Add actions to the loop rule to generate corresponding code.
Use the existing ‘while’
9. code for guidance, but beware the semantics are different. Most
importantly, the
condition test follows the body of the loop, so the conditional
jump address does not
need to be backpatched into the jump instruction. Also, unlike
the ‘while’ loop, this
loop terminates when the condition is true.
3. [3 marks] Implement simple global constant identifiers. (Do
not implement procedure-
local constants.) The declaration has the form
const id = num ;
There may be zero or more constant declaration statements.
For example you could declare const max = 100;.
You will need to do the following:
• Create new token name (say) CONST in spl.y, and modify
lexer.c to recognise the
corresponding const reserved word. Make sure that you update
dispToken().
• Add grammar rules to spl.y for (1) a constant declaration and
(2) a list of constant
declarations; modify the program rule to include the constant
declarations.
• Modify the symbol table to record the constant identifier’s
value. Modify st.h to
add a new identifier class and add a ‘value’ attribute to the attr
structure. Modify
list st in st.c so that the value and not the address of constant
identifiers is
10. displayed.
• Add actions to spl.y. You should
– Add a symbol table entry when a constant declaration is
recognised.
– Generate the correct machine code instruction to load a
constant value into a
register when a constant IDENT in the factor rule is recognised.
4
CSC8503 Principles of Programming Languages Semester 1,
2015
Assignment 3
Due Date: 11:55pm AEST (13:55 UTC/GMT) Sunday 7 June
2015
Weighting: 20%
Total marks: 20
Please submit this assignment using the assignment submission
facility on the course
Study Desk. Submit a single file, either a ZIP or TAR archive.
The archive
should contain (1) for Part A, a Prolog source file containing
the function definitions,
and (2) for Part B, your version of all the files that are in the
SPL distribution that you
downloaded.
Just add the Prolog file (call it say ass3.pl) to your collection of
11. SPL files and zip or
tar them into an archive that you submit.
Part A – Haskell – 12 marks
Write Prolog rules as described in the questions below. You
may use any Prolog builtin predi-
cates. You may need to write auxiliary “helper” rules in some
cases.
Your code may be tested by an automated script, so be sure to
do as follows:
• Place all definitions in a single file that can be read without
error by a Prolog inter-
preter. If you add comment lines, prefix them with a % (prolog
comment symbol)
• Submit just this text file electronically as directed on the
course Study Desk page.
(Do not submit a word processed or PDF file.)
• Use the rule name and arguments exactly as specified.
• Do NOT submit your test facts. Do not submit (say) a set of
parent facts that you
used to test your work.
Questions
1. Assume the Prolog knowledge base contains a set of facts:
parent(parent,child) describes biological parent–child
relationships. Assume that the
Prolog knowledge base describes only families where all
siblings share the same two parents.
You are required to write rules that describe the cousin
12. relationship. Consider the following
definitions1:
• First cousins are the children of two siblings. First cousins
have grandparents in
common.
• Second cousins are the children of first cousins. Second
cousins have great grandpar-
ents in common.
(a) [1 mark] Write the rule cousin1(Child1,Child2) that is true
if Child1 and Child2
are first cousins.
1See https://en.wikipedia.org/wiki/Cousin for more explanation
1
https://en.wikipedia.org/wiki/Cousin
(b) [1 mark] Write the rule cousin2(Child1,Child2) that is true
if Child1 and Child2
are second cousins.
(c) [1 mark] Write the general rule cousin(N,Child1,Child2) that
is true if Child1 and
Child2 are Nth cousins. So
cousin1(Child1,Child2) ≡ cousin(1,Child1,Child2) and
cousin2(Child1,Child2) ≡ cousin(2,Child1,Child2) and so on for
third and fourth
and even higher level cousins.
Hint: start by writing a sibling(Child1,Child2) rule.
13. 2. [2 marks] Write the rule single that removes duplicate entries
from a list.
single(L1,L2) if every value in L2 is in L1 and every value in
L1 is in L2 and there is
at most one occurrence of any value in L2. The order of values
in L1 is unsorted, and no
ordering of values in L2 is required.
?- single([a,a,b,2,1,a,2,3],L).
L = [b, 1, a, 2, 3].
3. [2 marks] Write the tr rule to translate all occurrences of a
list element value to another
value.
tr(A,B,L,M) if list M is the same as list L, except that every
occurrence of A in L is replaced
by B. For instance:
?- tr(1,2,[1,4,1,5],L).
L = [2, 4, 2, 5].
4. [2 marks] A time, in hours and minutes, is described by the
time structure. For example,
9 hours and 33 minutes would be encoded as time(9,33).
Write the rule tgreater that compares two times.
tgreater(T1,T2) if time T1 is a bigger value (is later than) time
T2. For example:
?- tgreater(time(9,33), time(10,42)).
14. false.
?- tgreater(time(11,33), time(10,42)).
true.
?- tgreater(time(11,33), time(11,33)).
false.
2
5. A binary tree is defined by the structure node(left,right),
where left and right can be
either another node or any Prolog data item.
(a) [1 mark] Write the rule size(Tree,Size) that takes as input a
tree and returns the
number of leaf items in the tree. For example:
?- size(node(1,2),X).
X = 2.
?- size(node(1,[2,3,4]),X).
X = 2.
?- size(node(node(a,b),[2,3,4]),X).
X = 3.
(b) [1 mark] Write the rule isBalanced(Tree) that determines if
the tree is balanced.
15. A binary tree is balanced if, at every node, the difference
between the number of
leaves appearing in the left and right subtree is at most one. (A
tree which contains
just one leaf is considered balanced.)
For example:
?- isBalanced(1).
true.
?- isBalanced(node(1,2)).
true.
?- isBalanced(node(1,node(1,node(1,2)))).
false.
(c) [1 mark] Write the rule trav(Tree,List) that performs a left
to right tree traversal;
List is the list of leaf node values in the tree.
For example:
?- trav(x,L).
L = [x].
?- trav(node(1,node(2,node(a,b))),L).
L = [1, 2, a, b] .
Part B – SPL – 8 marks
16. You are required to make a number of modifications to the SPL
compiler. The SPL laboratories
provide an introduction to the implementation of SPL and the
SPL Reference Manual supplies
extra information.
The SPL source code and other resources are available at
https://tau.usq.edu.au/courses/CSC8503/resources.html
Important: get a fresh copy of the SPL distribution before
starting work as it has
been modified slightly from earlier versions used in the
tutorials.
I will be compiling and running your SPL system so your code
must compile and run. If you are
unable to get some parts working and GCC or Bison compile
errors exist, then comment out
the error-producing code so that I can compile and execute what
you do have working.
Make sure you include all necessary files including the
Makefile. I should be able to just type
‘make’ and your system will be compiled on my machine.
3
https://tau.usq.edu.au/courses/CSC8503/resources.html
The Task
You are required to implement functions in SPL. There are a
number of requirements.
17. 1. [2 marks] Add a function declaration. This will have exactly
the same syntax as a
procedure declatration, except it is introduced by the reserved
work ‘function’ rather
than ‘procedure’. Make sure that you record in the symbol table
entry that the name of
the subprogram is a function and not a procedure.
2. [2 marks] Add a ‘return’ statement. The syntax is described
by the extended statement
grammar rule
statement → return expression ; | . . .
Execution of this statement results in the evaluation of the
expression and immediate
return from the function.
It is legal for a function to have multiple return statements.
If there are no return statements in a function it will terminate
(like a procedure) after
the last statement of the function body. The return value will be
undefined.
3. [2 marks] Add a function call expression. The syntax is
described by the extended factor
grammar rule
factor → id ( [identlist ] ) | . . .
Evaluation of this expression results in the value the ‘return’
expression that caused the
function to return.
4. Perform the following semantic checks.
(a) [1 mark] Produce an error message if the ‘return’ statement
appears in a procedure
or in the main program. (The return statement is only legal in a
18. function.)
(b) [1 mark] Produce an error message if either
• a function is called with a procedure call statement or
• a procedure is called with a function evaluation expression.
Notes
• Questions 1–3 require changes to the parser (new grammar
rules) as well as semantic
actions to implement the new functionality.
• Question 4 involves only semantic checks.
• The activation record must be altered to include a return
value. I suggest that you place
the return value between the frame pointer and the local
variables. To implement this you
need to (at least)
1. Change the offset address stored in the symbol table for all
local variables (look at
the use of varlocn).
2. Reserve storage for the return address (see proc_begin()).
4