Assignment title: Information


​​ CSC8503 Principles of Programming Languages Semester 1, 2016 Assignment 2 Due Date: 11:55pm AEST (13:55 UTC/GMT) Sunday 8 May 2016 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. The file should compile without error messages in GHCI or Hugs. Submit just this text file electronically as directed on the course Study Desk page. Use the specified function names 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. Part marks are available for all questions. 1. [2 marks] Write a function remo :: Eq a => a -> [a] -> [a] that removes from a list (second argument) the first item that matches the value of the first argument. For example: remo 'a' "mamamaa" ⇒ "mmamaa" remo 1 [1,2,3,1] ⇒ [2,3,1] 2. [2 marks] Write a function alt :: [a] -> [a] that takes a list as argument and returns a list that contains the first, third, fifth etc element of that list. That is return every second item of the list, starting with the fisrt element. For example: alt "abc" ⇒ "ac" alt "abcd" ⇒ "ac" alt [1..8] ⇒ [1,3,5,7] 1 3. (a) [1 mark] Write a recursive function maxList :: Ord a => [a] -> a that returns the largest value held in the argument list. You can assume that there is always at least one element in the list. For example: maxList [1] ⇒ 1 maxList [1,2,5,4,2,4] ⇒ 5 maxList [1,2,5,4,2,4,10] ⇒ 10 Hint: you may wish to use the standard prelude function max :: Ord a => a -> a -> a (b) [1 mark] Recode the list maximum problem to use foldl. Call your function maxListF. This function will not recursively call itself. 4. [3 marks] Write the function crypt :: String -> String -> Either String Int crypt cipher plaintext encrypts plaintext using the translation contained in cipher. The plain text includes only the 26 lower case letters plus the punctuation characters '.' (full stop) and ' ' (space). The cipher is a string of 28 printable characters which indicate how each plain text character is translated. The plain text character 'a' is encoded as the first character of cipher. The plain text 'b' is encoded as the second character of cipher, and so on. Every character in cipher must be distinct — there can be no repeated entries. If the string "ZqXwCeVrBtyUaszxImOKlFfdPcQv" is used as the cipher then crypt applies the following translation: plain text a b c d e f g h i j k l m n o p q r s t u v w x y z . encrypted text Z q X w C e V r B t y U a s z x I m O K l F f d P c Q v crypt returns either an encrypted string (value Left encrypted) or an error code (value Right code). The Either data type is defined in the Standard Prelude as data Either a b = Left a | Right b The possible errors and their associated codes are as follows: 1 The cipher text is not 28 characters long. 2 The cipher text contains some non-printable characters. 3 The cipher text contains some repeated characters. 4 The plain text contains characters that are not either lower case alphabetic or space or full stop. Hints: You may find the following following standard prelude functions useful: map, lookup, zip. You are free to use functions in Data.Char such as isPrint. 2 5. This question assumes the following tree data type that you should define in your script: data Tree a = Node a (Tree a) (Tree a) | Null deriving Show (a) [1 mark] Write the function insert Ord a => a -> Tree a -> Tree a that inserts a value into a tree so that the tree is ordered. That is, for each node in the tree, if the node has value v then all nodes in its left sub-tree have values less than or equal to v, and all nodes in its right sub-tree have values greater than v. insert 'a' Null ⇒ Node 'a' Null Null insert 1 (Node 5 Null Null) ⇒ Node 5 (Node 1 Null Null) Null (b) [1 mark] Write the function trav :: Tree a -> [a] that returns a list of items in the tree retrieved in a left to right depth-dirst traversal. trav (Node 10 (Node 5 Null Null) (Node 15 Null Null)) ⇒ [5,10,15] (c) [1 mark] Using insert and trav, write the function tsort :: Ord a => [a] -> [a] that sorts a list into ascending order by traversing the tree formed by inserting the list elements into an ordered tree. Hint: You may wish to write an separate function (say) insertAll :: Ord a => [a] -> Tree a to assist in defining tsort insertAll list would create the ordered tree containing the elements in list. 3 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 These have the same semantics as the C operators of the same kind. The value of preincrement expression ++x is the current value of x, plus one , while the value of postincrement 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,b; { a := 1; display a; b := a++; display b; display a; b := ++a; display b; 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: • Create new token name (say) INC in spl.y, and modify lexer.c to recognise the corresponding ++ 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'. 4 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' 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 procedurelocal 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 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. 5