Created
January 22, 2019 12:37
-
-
Save jda0/2b7a283aa394383215d163da6911cd87 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Preliminary notes: | |
1. Where necessary the following function was used to convert parser output to | |
canonical form (to detect equivalent syntax trees up to associativity of | |
statement composition): | |
tx :: Stm -> Stm | |
tx (Comp (Comp a b) c) = tx (Comp a (Comp b c)) | |
tx (Comp a b) = (Comp (tx a) (tx b)) | |
tx (If b s1 s2) = (If b (tx s1) (tx s2)) | |
tx (While b s) = (While b (tx s)) | |
tx (Block dv dp s) = Block dv dp (tx s) | |
tx s = s | |
2. If your submission was already a module, the filename has automatically been | |
changed to <MODULE_NAME>.hs to allow it to be found by the automarker. | |
================================================================================ | |
Test description: Skip statement | |
Input file: 1-skip.w...PASS (1/1 marks) | |
--- | |
Test description: Single and multi-line comments | |
Input file: 2-comments.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with N | |
Input file: 3-ass-n.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with lowercase alphabetical identifiers | |
Input file: 4-ass-v.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with lowercase alphanumeric identifiers | |
Input file: 5-ass-v-alphanum.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Add | |
Input file: 6-ass-add.w...FAIL (0/1 marks) | |
Expected output: | |
Comp (Ass "x" (Add (N 1) (N 5))) (Comp (Ass "y" (Add (Add (Add (Add (Add (N 4) (N 7)) (N 34)) (N 32)) (N 147)) (N 42))) (Ass "z" (Add (Add (Add (Add (N 333) (N 27)) (N 0)) (N 7)) (N 8)))) | |
Actual output: | |
Comp (Ass "x" (Add (N 1) (N 5))) (Comp (Ass "y" (Add (N 4) (Add (N 7) (Add (N 34) (Add (N 32) (Add (N 147) (N 42))))))) (Ass "z" (Add (N 333) (Add (N 27) (Add (N 0) (Add (N 7) (N 8))))))) | |
--- | |
Test description: Ass with bracketed Add | |
Input file: 7-ass-add-b.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Sub | |
Input file: 8-ass-sub.w...FAIL (0/1 marks) | |
Expected output: | |
Comp (Ass "x" (Sub (Sub (Sub (Sub (N 100) (N 5)) (N 7)) (N 4)) (N 2))) (Comp (Ass "y" (Sub (Sub (Sub (Sub (N 654) (N 43)) (N 12)) (N 0)) (N 145))) (Ass "z" (Sub (N 7) (N 2)))) | |
Actual output: | |
Comp (Ass "x" (Sub (N 100) (Sub (N 5) (Sub (N 7) (Sub (N 4) (N 2)))))) (Comp (Ass "y" (Sub (N 654) (Sub (N 43) (Sub (N 12) (Sub (N 0) (N 145)))))) (Ass "z" (Sub (N 7) (N 2)))) | |
--- | |
Test description: Ass with bracketed Sub | |
Input file: 9-ass-sub-b.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Mult | |
Input file: 10-ass-mult.w...FAIL (0/1 marks) | |
Expected output: | |
Comp (Ass "x" (Mult (Mult (Mult (Mult (Mult (Mult (Mult (N 5) (N 6)) (N 7)) (N 8)) (N 9)) (N 10)) (N 11)) (N 12))) (Comp (Ass "y" (Mult (Mult (N 4) (N 7)) (N 3))) (Ass "z" (Mult (N 333) (N 27)))) | |
Actual output: | |
Comp (Ass "x" (Mult (N 5) (Mult (N 6) (Mult (N 7) (Mult (N 8) (Mult (N 9) (Mult (N 10) (Mult (N 11) (N 12))))))))) (Comp (Ass "y" (Mult (N 4) (Mult (N 7) (N 3)))) (Ass "z" (Mult (N 333) (N 27)))) | |
--- | |
Test description: Ass with bracketed Mult | |
Input file: 11-ass-mult-b.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Aexp | |
Input file: 12-ass.w...FAIL (0/3 marks) | |
Expected output: | |
Comp (Ass "a" (N 9)) (Comp (Ass "b" (N 17)) (Comp (Ass "c" (N 13)) (Comp (Ass "d" (Add (V "a") (V "b"))) (Comp (Ass "e" (Sub (V "c") (V "a"))) (Comp (Ass "f" (Mult (V "b") (V "c"))) (Comp (Ass "g" (Add (N 1) (V "f"))) (Comp (Ass "h" (Add (V "g") (N 7))) (Comp (Ass "i" (Add (Add (Add (V "a") (V "b")) (V "c")) (V "d"))) (Comp (Ass "j" (Sub (Sub (V "d") (V "c")) (V "a"))) (Comp (Ass "k" (Mult (Mult (Mult (V "a") (V "b")) (V "c")) (V "d"))) (Comp (Ass "l" (Sub (Add (V "a") (V "g")) (Mult (V "c") (V "e")))) (Comp (Ass "m" (Sub (Add (Mult (V "a") (V "b")) (V "c")) (V "d"))) (Comp (Ass "n" (Add (Sub (V "h") (Mult (V "b") (V "c"))) (V "d"))) (Comp (Ass "o" (Add (Add (Add (Add (Sub (Add (Sub (Add (Sub (Add (V "a") (V "b")) (V "c")) (Mult (N 2) (V "d"))) (V "e")) (V "f")) (Mult (N 7) (V "g"))) (V "h")) (N 5)) (Mult (Mult (V "i") (V "j")) (V "k"))) (V "l"))) (Ass "p" (V "o")))))))))))))))) | |
Actual output: | |
Comp (Ass "a" (N 9)) (Comp (Ass "b" (N 17)) (Comp (Ass "c" (N 13)) (Comp (Ass "d" (Add (V "a") (V "b"))) (Comp (Ass "e" (Sub (V "c") (V "a"))) (Comp (Ass "f" (Mult (V "b") (V "c"))) (Comp (Ass "g" (Add (N 1) (V "f"))) (Comp (Ass "h" (Add (V "g") (N 7))) (Comp (Ass "i" (Add (V "a") (Add (V "b") (Add (V "c") (V "d"))))) (Comp (Ass "j" (Sub (V "d") (Sub (V "c") (V "a")))) (Comp (Ass "k" (Mult (V "a") (Mult (V "b") (Mult (V "c") (V "d"))))) (Comp (Ass "l" (Add (V "a") (Sub (V "g") (Mult (V "c") (V "e"))))) (Comp (Ass "m" (Add (Mult (V "a") (V "b")) (Sub (V "c") (V "d")))) (Comp (Ass "n" (Sub (V "h") (Add (Mult (V "b") (V "c")) (V "d")))) (Comp (Ass "o" (Add (V "a") (Sub (V "b") (Add (V "c") (Sub (Mult (N 2) (V "d")) (Add (V "e") (Sub (V "f") (Add (Mult (N 7) (V "g")) (Add (V "h") (Add (N 5) (Add (Mult (V "i") (Mult (V "j") (V "k"))) (V "l")))))))))))) (Ass "p" (V "o")))))))))))))))) | |
--- | |
Test description: Ass with bracketed Aexp | |
Input file: 13-ass-b.w...PASS (3/3 marks) | |
--- | |
Test description: Test whether correct version of “false” used (i.e. not “FALSE” or “False”) | |
Input file: 14-if-true.w...PASS (1/1 marks) | |
--- | |
Test description: Test whether correct version of “true” used (i.e. not “TRUE” or “True”) | |
Input file: 15-if-false.w...PASS (1/1 marks) | |
--- | |
Test description: Nested If with Le | |
Input file: 16-if-le-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Nested If with Eq | |
Input file: 17-if-eq-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Nested If with Neg | |
Input file: 18-if-neg-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Nested If with left-associative And | |
Input file: 19-if-and-nest.w...FAIL (0/1 marks) | |
Expected output: | |
If (And TRUE TRUE) (Ass "x" (N 1)) (If (And (And TRUE TRUE) TRUE) (Ass "y" (N 3)) (If (And (And FALSE TRUE) FALSE) (Ass "z" (N 5)) (If (And FALSE FALSE) (Ass "a" (N 7)) (Ass "a" (N 8))))) | |
Actual output: | |
If (And TRUE TRUE) (Ass "x" (N 1)) (If (And TRUE (And TRUE TRUE)) (Ass "y" (N 3)) (If (And FALSE (And TRUE FALSE)) (Ass "z" (N 5)) (If (And FALSE FALSE) (Ass "a" (N 7)) (Ass "a" (N 8))))) | |
--- | |
Test description: Nested If with Bexp | |
Input file: 20-if-nest.w...FAIL (0/4 marks) | |
Expected output: | |
If (Le (N 1) (N 2)) (Ass "a" (N 1)) (If (Le (N 4) (N 3)) (Ass "b" (N 3)) (If (Eq (N 5) (N 5)) (Ass "c" (N 5)) (If (Eq (N 6) (N 7)) (Ass "d" (N 7)) (If (Neg (Eq (N 8) (N 9))) (Ass "e" (N 9)) (If (Neg (Eq (N 10) (N 10))) (Ass "f" (N 11)) (If (And (Le (N 11) (N 12)) (Le (N 13) (N 14))) (Ass "g" (N 13)) (If (And (Le (N 15) (N 16)) (Le (N 18) (N 17))) (Ass "h" (N 15)) (If (And (Neg (Le (N 20) (N 19))) (Eq (N 21) (N 21))) (Ass "i" (N 17)) (If (And (And (Neg (Eq (N 22) (N 23))) (Le (N 24) (N 25))) (Neg (Eq (N 26) (N 26)))) (Ass "j" (N 17)) (Ass "j" (N 18))))))))))) | |
Actual output: | |
If (Le (N 1) (N 2)) (Ass "a" (N 1)) (If (Le (N 4) (N 3)) (Ass "b" (N 3)) (If (Eq (N 5) (N 5)) (Ass "c" (N 5)) (If (Eq (N 6) (N 7)) (Ass "d" (N 7)) (If (Neg (Eq (N 8) (N 9))) (Ass "e" (N 9)) (If (Neg (Eq (N 10) (N 10))) (Ass "f" (N 11)) (If (And (Le (N 11) (N 12)) (Le (N 13) (N 14))) (Ass "g" (N 13)) (If (And (Le (N 15) (N 16)) (Le (N 18) (N 17))) (Ass "h" (N 15)) (If (And (Neg (Le (N 20) (N 19))) (Eq (N 21) (N 21))) (Ass "i" (N 17)) (If (And (Neg (Eq (N 22) (N 23))) (And (Le (N 24) (N 25)) (Neg (Eq (N 26) (N 26))))) (Ass "j" (N 17)) (Ass "j" (N 18))))))))))) | |
--- | |
Test description: Bracketed If with Le | |
Input file: 21-if-le-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with Eq | |
Input file: 22-if-eq-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with Neg | |
Input file: 23-if-neg-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with And | |
Input file: 24-if-and-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with Bexp | |
Input file: 25-if-b.w...PASS (4/4 marks) | |
--- | |
Test description: Nested While with Le | |
Input file: 26-while-le-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Nested While with Eq | |
Input file: 27-while-eq-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Nested While with Neg | |
Input file: 28-while-neg-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Nested While with left-associative And | |
Input file: 29-while-and-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with Le | |
Input file: 30-while-le-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with Eq | |
Input file: 31-while-eq-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with Neg | |
Input file: 32-while-neg-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with And | |
Input file: 33-while-and-b.w...PASS (1/1 marks) | |
--- | |
Test description: Nested While with Bexp | |
Input file: 34-while-nest.w...PASS (4/4 marks) | |
--- | |
Test description: Bracketed While with Bexp | |
Input file: 35-while-b.w...PASS (4/4 marks) | |
--- | |
Test description: Block procedure declarations (alphanumeric identifiers) | |
Input file: 36-block-dp-alphanum.w...PASS (1/1 marks) | |
--- | |
Test description: Block variable declarations | |
Input file: 37-block-dv.w...PASS (3/3 marks) | |
--- | |
Test description: Block procedure declarations (alphabetic identifiers) | |
Input file: 38-block-dp.w...PASS (2/2 marks) | |
--- | |
Test description: Block with simple statement | |
Input file: 39-block-skip.w...PASS (1/1 marks) | |
--- | |
Test description: Nested blocks | |
Input file: 40-block-skips.w...PASS (1/1 marks) | |
--- | |
Test description: Call statements | |
Input file: 41-call.w...PASS (1/1 marks) | |
--- | |
Test description: Factorial program – iterative version | |
Input file: 42-fact-iter.w...PASS (6/6 marks) | |
--- | |
Test description: Factorial program – recursive version | |
Input file: 43-fact-rec.w...PASS (10/10 marks) | |
--- | |
Test description: Simple mutual recursion program with brackets final proc | |
Input file: 44-mutual2-b.w...PASS (2/2 marks) | |
--- | |
Test description: Simple mutual recursion program without brackets on final proc | |
Input file: 45-mutual2.w...FAIL (0/6 marks) | |
Expected output: | |
Block [] [("p",If (Le (N 1) (V "x")) (Comp (Ass "x" (Sub (V "x") (N 1))) (Call "q")) Skip),("q",If (Le (N 1) (V "x")) (Comp (Ass "x" (Sub (V "x") (N 1))) (Call "p")) Skip)] (Call "p") | |
Actual output: | |
No valid parse found. Printing GHCI output: | |
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help | |
[1 of 1] Compiling Proc ( Proc.hs, interpreted ) | |
Ok, modules loaded: Proc. | |
*Proc> *** Exception: Maybe.fromJust: Nothing | |
*Proc> Leaving GHCi. | |
--- | |
Test description: Mutual recursion program based on J. Terry’s forum post | |
Input file: 46-mutual.w...FAIL (0/10 marks) | |
Expected output: | |
Block [("x",N 5)] [("a",If (Neg (Le (V "x") (N 3))) (Comp (Ass "y" (Add (V "y") (N 1))) (Comp (Ass "x" (Sub (V "x") (N 1))) (Call "b"))) Skip),("b",Comp (Ass "y" (Add (V "y") (N 100))) (Call "a"))] (Comp (Block [("x",N 6)] [("a",Ass "x" (N 50))] (Comp (Ass "y" (N 0)) (Comp (Call "b") (Ass "xinner" (V "x"))))) (Ass "xouter" (V "x"))) | |
Actual output: | |
No valid parse found. Printing GHCI output: | |
GHCi, version 8.0.2: http://www.haskell.org/ghc/ :? for help | |
[1 of 1] Compiling Proc ( Proc.hs, interpreted ) | |
Ok, modules loaded: Proc. | |
*Proc> *** Exception: Maybe.fromJust: Nothing | |
*Proc> Leaving GHCi. | |
--- | |
Test description: Procedure scoping example program | |
Input file: 47-scope.w...PASS (6/6 marks) | |
--- | |
total part2 mark: 73 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Test description: Ass with N | |
[dynamic] Input file: 3-ass-n.w...PASS (1/1 marks) | |
[mixed] Input file: 3-ass-n.w...PASS (1/1 marks) | |
[static] Input file: 3-ass-n.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with lowercase alphabetical identifiers | |
[dynamic] Input file: 4-ass-v.w...PASS (1/1 marks) | |
[mixed] Input file: 4-ass-v.w...PASS (1/1 marks) | |
[static] Input file: 4-ass-v.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Add | |
[dynamic] Input file: 6-ass-add.w...PASS (1/1 marks) | |
[mixed] Input file: 6-ass-add.w...PASS (1/1 marks) | |
[static] Input file: 6-ass-add.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Sub | |
[dynamic] Input file: 8-ass-sub.w...PASS (1/1 marks) | |
[mixed] Input file: 8-ass-sub.w...PASS (1/1 marks) | |
[static] Input file: 8-ass-sub.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Mult | |
[dynamic] Input file: 10-ass-mult.w...PASS (1/1 marks) | |
[mixed] Input file: 10-ass-mult.w...PASS (1/1 marks) | |
[static] Input file: 10-ass-mult.w...PASS (1/1 marks) | |
--- | |
Test description: Ass with left-associative Aexp | |
[dynamic] Input file: 12-ass.w...PASS (1/1 marks) | |
[mixed] Input file: 12-ass.w...PASS (1/1 marks) | |
[static] Input file: 12-ass.w...PASS (1/1 marks) | |
--- | |
Test description: Test whether correct version of “false” used (i.e. not “FALSE” or “False”) | |
[dynamic] Input file: 14-if-true.w...PASS (1/1 marks) | |
[mixed] Input file: 14-if-true.w...PASS (1/1 marks) | |
[static] Input file: 14-if-true.w...PASS (1/1 marks) | |
--- | |
Test description: Test whether correct version of “true” used (i.e. not “TRUE” or “True”) | |
[dynamic] Input file: 15-if-false.w...PASS (1/1 marks) | |
[mixed] Input file: 15-if-false.w...PASS (1/1 marks) | |
[static] Input file: 15-if-false.w...PASS (1/1 marks) | |
--- | |
Test description: Nested If with Bexp | |
[dynamic] Input file: 20-if-nest.w...PASS (1/1 marks) | |
[mixed] Input file: 20-if-nest.w...PASS (1/1 marks) | |
[static] Input file: 20-if-nest.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with Le | |
[dynamic] Input file: 21-if-le-b.w...PASS (1/1 marks) | |
[mixed] Input file: 21-if-le-b.w...PASS (1/1 marks) | |
[static] Input file: 21-if-le-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with Eq | |
[dynamic] Input file: 22-if-eq-b.w...PASS (1/1 marks) | |
[mixed] Input file: 22-if-eq-b.w...PASS (1/1 marks) | |
[static] Input file: 22-if-eq-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with Neg | |
[dynamic] Input file: 23-if-neg-b.w...PASS (1/1 marks) | |
[mixed] Input file: 23-if-neg-b.w...PASS (1/1 marks) | |
[static] Input file: 23-if-neg-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with And | |
[dynamic] Input file: 24-if-and-b.w...PASS (1/1 marks) | |
[mixed] Input file: 24-if-and-b.w...PASS (1/1 marks) | |
[static] Input file: 24-if-and-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed If with Bexp | |
[dynamic] Input file: 25-if-b.w...PASS (1/1 marks) | |
[mixed] Input file: 25-if-b.w...PASS (1/1 marks) | |
[static] Input file: 25-if-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with Le | |
[dynamic] Input file: 30-while-le-b.w...PASS (1/1 marks) | |
[mixed] Input file: 30-while-le-b.w...PASS (1/1 marks) | |
[static] Input file: 30-while-le-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with Eq | |
[dynamic] Input file: 31-while-eq-b.w...PASS (1/1 marks) | |
[mixed] Input file: 31-while-eq-b.w...PASS (1/1 marks) | |
[static] Input file: 31-while-eq-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with Neg | |
[dynamic] Input file: 32-while-neg-b.w...PASS (1/1 marks) | |
[mixed] Input file: 32-while-neg-b.w...PASS (1/1 marks) | |
[static] Input file: 32-while-neg-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with And | |
[dynamic] Input file: 33-while-and-b.w...PASS (1/1 marks) | |
[mixed] Input file: 33-while-and-b.w...PASS (1/1 marks) | |
[static] Input file: 33-while-and-b.w...PASS (1/1 marks) | |
--- | |
Test description: Bracketed While with Bexp | |
[dynamic] Input file: 35-while-b.w...PASS (1/1 marks) | |
[mixed] Input file: 35-while-b.w...PASS (1/1 marks) | |
[static] Input file: 35-while-b.w...PASS (1/1 marks) | |
--- | |
Test description: Factorial program – iterative version | |
[dynamic] Input file: 42-fact-iter.w...PASS (1/1 marks) | |
[mixed] Input file: 42-fact-iter.w...PASS (1/1 marks) | |
[static] Input file: 42-fact-iter.w...PASS (1/1 marks) | |
--- | |
Test description: Factorial program – recursive version | |
[dynamic] Input file: 43-fact-rec.w...PASS (20/20 marks) | |
[mixed] Input file: 43-fact-rec.w...PASS (20/20 marks) | |
[static] Input file: 43-fact-rec.w...FAIL (0/20 marks) | |
"Declared variables:" | |
["x","y","z"] | |
"Initial state" | |
[5,0,0] | |
"Expected output:" | |
[1,120,0] | |
" Actual output:" | |
[5,1,0] | |
--- | |
Test description: Simple mutual recursion program without brackets on final proc | |
[dynamic] Input file: 45-mutual2.w...FAIL (0/5 marks) | |
"Declared variables:" | |
["x"] | |
"Initial state" | |
[5] | |
"Expected output:" | |
[0] | |
" Actual output:" | |
[5] | |
[mixed] Input file: 45-mutual2.w...FAIL (0/5 marks) | |
"Declared variables:" | |
["x"] | |
"Initial state" | |
[5] | |
"Expected output:" | |
[0] | |
" Actual output:" | |
[5] | |
[static] Input file: 45-mutual2.w...FAIL (0/5 marks) | |
"Declared variables:" | |
["x"] | |
"Initial state" | |
[5] | |
"Expected output:" | |
[0] | |
" Actual output:" | |
[5] | |
--- | |
Test description: Mutual recursion program based on J. Terry’s forum post | |
[dynamic] Input file: 46-mutual.w...PASS (5/5 marks) | |
[mixed] Input file: 46-mutual.w...FAIL (0/5 marks) | |
"Declared variables:" | |
["xinner","xouter","y"] | |
"Initial state" | |
[0,0,0] | |
"Expected output:" | |
[3,5,403] | |
" Actual output:" | |
[0,5,0] | |
[static] Input file: 46-mutual.w...FAIL (0/5 marks) | |
"Declared variables:" | |
["xinner","xouter","y"] | |
"Initial state" | |
[0,0,0] | |
"Expected output:" | |
[6,3,302] | |
" Actual output:" | |
[6,5,0] | |
--- | |
Test description: Procedure scoping example program | |
[dynamic] Input file: 47-scope.w...PASS (25/25 marks) | |
[mixed] Input file: 47-scope.w...PASS (25/25 marks) | |
[static] Input file: 47-scope.w...PASS (25/25 marks) | |
--- | |
Test description: Variable scoping example program | |
[dynamic] Input file: 48-var-scope.w...PASS (25/25 marks) | |
[mixed] Input file: 48-var-scope.w...PASS (25/25 marks) | |
[static] Input file: 48-var-scope.w...PASS (25/25 marks) | |
--- | |
part 3 (dynamic) mark: 95 | |
part 3 (mixed) mark: 90 | |
part 3 (static) mark: 70 | |
--- | |
total part 3 mark: 86.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Proc where | |
import Prelude hiding (Num, and, lookup, map) | |
import Control.Applicative hiding (empty) | |
import Control.Arrow (second) | |
import Control.Monad | |
import Data.Functor.Identity (Identity) | |
import Data.Map.Lazy | |
import Data.Maybe | |
import Text.Megaparsec hiding (State, parse) | |
import qualified Text.Megaparsec.Lexer as L | |
import Text.Megaparsec.String | |
-- # Revisions | |
{- | |
- V1.2.1 01 May 2017 | |
- Added State call fallback to prevent errors when using undeclared | |
variables known to a previous State. Further improvements - | |
especially reducing the memory footprint of the semantic functions - | |
could be made by replacing `Store` with `State` entirely except in | |
`Block`s. [:323] | |
- `Block`-private `Scope`s are now empty to reduce memory footprint, | |
as only the keys are needed to make a comparison. Further memory | |
footprint reductions could be made by changing the structure of | |
private `Store`s to ([Var], [Pname]) [:369, :377] | |
- Changed the scoping of `proc`s to be performed after all `var`s | |
and `proc`s have been declared to allow recursion and look- | |
forward. [:378 - :372] | |
- Mixed-scope state applicator now falls back on the current state if | |
the child scope cannot be found due to recursion (`Store` is only | |
set in the top-most declaration) [:368, :414] | |
- Removed some unused symbols | |
- TODO: Replace usage of `map` with `fmap` in next version [:398] | |
- TODO: Improve documentation | |
-} | |
-- | |
-- # Grammar | |
{- | |
The grammar for Proc is as follows: | |
I ::= I Ib | Ia | |
Ia ::= a | b | ... | z | _ | |
Ib ::= Ia | 0 | 1 | ... | 9 | |
V ::= I | |
P ::= I | |
A ::= Aa + A | Aa - A | Aa | |
Aa ::= Ab * Aa | Ab | |
Ab ::= N | V | ( A ) | |
B ::= Ba & B | Ba | |
Ba ::= Neg Ba | Bb | |
Bb ::= TRUE | FALSE | ( B ) | A <= A | A = A | |
Dv ::= var V := A ; Dv | E | |
Dp ::= proc P := Sa ; Dp | E | |
Sb ::= if B then S else S | while B do S | begin Dv Dp S end | |
Ss ::= skip | call P | x := A | ( S ) | |
Sa ::= Sb | Ss | |
Sc ::= Sa ; S | |
S ::= Sb | Sc | Sa | |
-} | |
-- | |
-- # Parser | |
-- ## Typedefs | |
type Num = Integer | |
type Var = String | |
type Pname = String | |
type DecV = [(Var, Aexp)] | |
type DecP = [(Pname, Stm)] | |
data Aexp = N Num | V Var | Mult Aexp Aexp | Add Aexp Aexp | |
| Sub Aexp Aexp | |
deriving (Show) | |
data Bexp = TRUE | FALSE | Neg Bexp | And Bexp Bexp | |
| Le Aexp Aexp | Eq Aexp Aexp | |
deriving (Show) | |
data Stm = Skip | Ass Var Aexp | Comp Stm Stm | |
| If Bexp Stm Stm | While Bexp Stm | |
| Block DecV DecP Stm | Call Pname | |
deriving (Show) | |
-- ## Lexer setup | |
spaceConsumer :: ParsecT Dec String Identity () | |
spaceConsumer = L.space sp lc bc where | |
sp = void spaceChar | |
lc = L.skipLineComment "//" | |
bc = L.skipBlockComment "/*" "*/" | |
lexeme :: ParsecT Dec String Identity a | |
-> ParsecT Dec String Identity a | |
lexeme = L.lexeme spaceConsumer | |
symbol :: String -> ParsecT Dec String Identity String | |
symbol' :: String -> ParsecT Dec String Identity String | |
symbol = L.symbol spaceConsumer | |
symbol' = L.symbol' spaceConsumer | |
-- ## Lexeme Parsers | |
-- ### Parentheses | |
parens :: ParsecT Dec String Identity a | |
-> ParsecT Dec String Identity a | |
parens x = lexeme (between (symbol "(") (symbol ")") x) | |
<?> "parens" | |
-- ### Integers | |
num :: Parser Num | |
num = lexeme L.integer <?> "num" | |
-- ### Identity Names | |
-- Form of this function body inspired by | |
-- https://hackage.haskell.org/package/dotenv-0.3.0.3/src/src/Configuration/Dotenv/Parse.hs | |
ident :: ParsecT Dec String | |
Data.Functor.Identity.Identity String | |
ident = liftM2 (:) (letterChar <|> char '_') | |
(many $ try | |
(letterChar <|> char '_' <|> digitChar)) | |
<?> "ident" | |
var :: Parser Var | |
var = lexeme ident <?> "var" | |
pname :: Parser Pname | |
pname = lexeme ident <?> "pname" | |
-- ## Declaration Block Parsers | |
-- ### Variable Declaration Blocks | |
decv :: Parser DecV | |
decv = many (try decv') <?> "decv" where | |
decv' = (,) <$> var' <*> a' <* symbol ";" <?> "decvi" | |
var' = symbol' "var" *> var <* symbol' ":=" | |
<?> "decvv" | |
a' = aexp <?> "decva" | |
-- ### Procedure Declaration Blocks | |
decp :: Parser DecP | |
decp = many (try decp') <?> "decp" where | |
decp' = (,) <$> var' <*> s' <* symbol ";" <?> "decpi" | |
var' = symbol' "proc" *> pname <* symbol' "is" | |
<?> "decpv" | |
s' = stm' <?> "decps" | |
-- ## Expression Parsers | |
-- ### Arithmetic Expressions | |
aexp :: Parser Aexp | |
aexp = aexp0 <?> "aexp" where | |
-- Lowest precedence | |
aexp0 = try (Add <$> aexp1 <* symbol "+" <*> aexp0) | |
<|> try (Sub <$> aexp1 <* symbol "-" <*> aexp0) | |
<|> aexp1 | |
aexp1 = try (Mult <$> aexp2 <* symbol "*" <*> aexp1) | |
<|> aexp2 | |
-- Highest precedence & symbols | |
aexp2 = (N <$> num) | |
<|> (V <$> var) | |
<|> parens aexp | |
-- ### Boolean Expressions | |
bexp :: Parser Bexp | |
bexp = bexp0 <?> "bexp" where | |
-- Lowest precedence | |
bexp0 = try (And <$> bexp1 <* symbol "&" <*> bexp0) | |
<|> bexp1 | |
bexp1 = try (Neg <$ symbol "!" <*> bexp1) | |
<|> bexp2 | |
-- Highest precedence & symbols | |
bexp2 = (TRUE <$ symbol' "true") | |
<|> (FALSE <$ symbol' "false") | |
<|> parens bexp | |
<|> try (Le <$> aexp <* symbol "<=" <*> aexp) | |
<|> try (Eq <$> aexp <* symbol "=" <*> aexp) | |
-- ## Statement Parsers | |
-- ### Block Statements | |
stmb :: Parser Stm | |
stmb = (If <$ symbol' "if" <*> bexp | |
<* symbol' "then" <*> stm | |
<* symbol' "else" <*> stm | |
<?> "if") | |
<|> (While <$ symbol' "while" <*> bexp | |
<* symbol' "do" <*> stm | |
<?> "while") | |
<|> (Block <$ symbol' "begin" <*> decv | |
<*> decp <*> stm | |
<* symbol' "end" | |
<?> "block") | |
-- ### Inline Statements | |
stma :: Parser Stm | |
stma = (Skip <$ symbol' "skip" | |
<?> "skip") | |
<|> (Call <$ symbol' "call" <*> pname | |
<?> "call") | |
<|> (try (Ass <$> var <* symbol ":=" <*> aexp) | |
<?> "ass") | |
<|> parens stm <?> "parens'" | |
-- ### Single Statements | |
stm' :: Parser Stm | |
stm' = stmb <|> stma | |
-- ### Composite Statements | |
comp :: Parser Stm | |
comp = try (Comp <$> stm' <* symbol ";" | |
<*> stm) | |
<?> "comp" | |
-- ### General Statements | |
stm :: Parser Stm | |
stm = stmb <|> comp <|> stma | |
-- ### Outermost Statement Parser | |
prog :: Parser Stm | |
prog = spaceConsumer *> stm | |
-- ## Parser Applicators | |
parse :: String -> Stm | |
parse = fromJust . parseMaybe prog | |
parseDebug :: String -> IO () | |
parseDebug x = case runParser prog "" x of | |
Left err -> putStr (parseErrorPretty err) | |
Right f -> print f | |
-- | |
-- # Semantic Functions | |
-- ## Typedefs | |
{-# ANN module "HLint: ignore Use camelCase" #-} | |
type T = Bool | |
type Z = Integer | |
type State = Var -> Z | |
data Scope = Scope (Map Pname (Stm, Maybe Scope)) | |
(Map Var (Maybe Z)) State | |
-- ## Expression Evaluation | |
-- ### Arithmetic Expressions | |
aexpEval :: Aexp -> Scope -> Maybe Z | |
aexpEval = aee where | |
aee (N a) _ = Just a | |
aee (V a ) s = svLookup s a | |
aee (Mult a b) s = f' (*) a b s | |
aee (Add a b) s = f' (+) a b s | |
aee (Sub a b) s = f' (-) a b s | |
f' g a b s = pure g <*> aee a s <*> aee b s | |
-- ### Boolean Expressions | |
bexpEval :: Bexp -> Scope -> T | |
bexpEval = bee where | |
bee TRUE _ = True | |
bee FALSE _ = False | |
bee (And a b) s = bee a s && bee b s | |
bee (Neg a ) s = not $ bee a s | |
bee (Le a b) s = justAee a s <= justAee b s | |
bee (Eq a b) s = justAee a s == justAee b s | |
justAee a = fromJust . aexpEval a | |
-- ## Scope Manipulation | |
-- ### Scope Lookup | |
svLookup :: Scope -> Var -> Maybe Z | |
spLookup :: Scope -> Pname -> (Stm, Maybe Scope) | |
svLookup (Scope _ vs s) v = fromMaybe (Just $ s v) $ lookup v vs | |
spLookup (Scope ps _ _) = (!) ps | |
-- ### Insert Procedures | |
-- ### Insert Variables | |
-- ## Generic State Applicator | |
s_generic :: (Stm -> Scope -> Scope) | |
-> Stm -> State -> State | |
s_generic a f s v = fromJust $ svLookup (g' a f s v) v where | |
g' :: (Stm -> Scope -> Scope) | |
-> Stm -> State -> Var -> Scope | |
g' a' f' s' v' = a' f' (Scope empty | |
(singleton v' . Just . s' $ v') s') | |
-- ## Default Scope Applicator | |
siDefault :: (Stm -> Scope -> Scope) -> Stm -> Scope -> | |
Scope | |
siDefault _ Skip _ = Scope empty empty $ const 0 | |
siDefault _ (Ass v a) | |
(Scope ps vs s) = Scope ps | |
(insert v (aexpEval a (Scope ps vs s)) vs) s | |
siDefault i (Comp a b) s = i b (i a s) | |
siDefault i (If c f g) s = i (if bexpEval c s then f else g) s | |
siDefault i (While c f) s = if bexpEval c s | |
then i (While c f) (i f s) | |
else s | |
siDefault i (Block v p f) | |
s@(Scope ps vs sc) = | |
let addPs :: DecP -> (Scope, Scope) -> (Scope, Scope) | |
addPs [] ss = ss | |
addPs ((q, qf) : qs) | |
(Scope po vo so, | |
Scope pp vp sp) = addPs qs | |
(Scope (insert q (qf, Nothing) po) vo so, | |
Scope (insert q (Skip, Nothing) pp) vp sp) | |
addVs :: DecV -> (Scope, Scope) -> (Scope, Scope) | |
addVs [] ss = ss | |
addVs ((u, ua) : us) | |
(so@(Scope po vo to), | |
Scope pp vp tp) = addVs us (Scope po | |
(insert u (aexpEval ua so) vo) to, | |
Scope pp | |
(insert u Nothing vp) tp) | |
rescopePs :: (Scope, Scope) -> (Scope, Scope) | |
rescopePs | |
(so@(Scope po vo to), | |
sp) = (Scope (setScope so po) vo to, sp) | |
setScope ss = map (second (Just . fromMaybe ss)) | |
sa :: (Scope, Scope) | |
sa = rescopePs . | |
addPs p $ addVs v | |
(s, Scope empty empty $ const 0) | |
(Scope pps pvs _) = snd sa | |
(Scope fp fv _) = i f $ fst sa | |
in Scope (difference fp pps `union` ps) | |
(difference fv pvs `union` vs) sc | |
siDefault _ _ _ = undefined | |
-- ## Dynamic-scope State Applicator | |
s_dynamic :: Stm -> State -> State | |
s_dynamic = s_generic d' where | |
d' :: Stm -> Scope -> Scope | |
d' (Call p) s = let (p', _) = spLookup s p | |
in d' p' s | |
d' f s = siDefault d' f s | |
-- ## Mixed-scope State Applicator | |
s_mixed :: Stm -> State -> State | |
s_mixed = s_generic m' where | |
m' :: Stm -> Scope -> Scope | |
m' (Call p) | |
s@(Scope _ vs sc) = let (p', s') = spLookup s p | |
(Scope ps' _ _) = fromMaybe s s' | |
in m' p' (Scope ps' vs sc) | |
m' f s = siDefault m' f s | |
-- ## Static-scope State Applicator | |
s_static :: Stm -> State -> State | |
s_static = s_generic s' where | |
s' (Call _) s = s | |
s' f s = siDefault s' f s | |
-- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment