|
| 1 | +#lang scribble/manual |
| 2 | +@title[#:tag "Assignment 5" #:style 'unnumbered]{Assignment 5: A Heap of Characters} |
| 3 | + |
| 4 | +@(require (for-label (except-in racket ...))) |
| 5 | +@(require "../notes/fraud-plus/semantics.rkt") |
| 6 | +@(require redex/pict) |
| 7 | + |
| 8 | +@(require "../notes/ev.rkt") |
| 9 | + |
| 10 | +@bold{Due: Thurs, Oct 3, 11:59PM} |
| 11 | + |
| 12 | +@(define repo "https://classroom.github.com/a/Qsw0mqpL") |
| 13 | + |
| 14 | +The goal of this assignment is to extend a compiler with data types |
| 15 | +that require memory allocation and dereferencing. |
| 16 | + |
| 17 | +Assignment repository: |
| 18 | +@centered{@link[repo repo]} |
| 19 | + |
| 20 | +You are given a repository with a starter compiler similar to the |
| 21 | +@seclink["Hustle"]{Hustle} language we studied in class. You are tasked |
| 22 | +with: |
| 23 | + |
| 24 | +@itemlist[ |
| 25 | + |
| 26 | +@item{incorporating the Fraud+ features you added in |
| 27 | +@seclink["Assignment 4"]{Assignment 4},} |
| 28 | + |
| 29 | +@item{extending the language to include a string data type,} |
| 30 | + |
| 31 | +@item{implementing a number of primitives,} |
| 32 | + |
| 33 | +@item{updating the parser to work for Hustle+.} |
| 34 | + |
| 35 | +] |
| 36 | + |
| 37 | +@section[#:tag-prefix "a5-" #:style 'unnumbered]{From Fraud+ to Hustle+} |
| 38 | + |
| 39 | +Implement all the features of Fraud+, extended to Hustle+. |
| 40 | + |
| 41 | + |
| 42 | +@section[#:tag-prefix "a5-" #:style 'unnumbered]{Strung out} |
| 43 | + |
| 44 | +In the last assignment, you implemented a character data type for |
| 45 | +representing single letters. In this assignment, you will implement a |
| 46 | +String data type for representing arbitrarily long sequences of |
| 47 | +characters. |
| 48 | + |
| 49 | +Strings are disjoint from all other data types and are essentially a |
| 50 | +fixed-size array of characters. Literal strings are written by |
| 51 | +enclosing the characters within the string in double quotes (@tt{"}). |
| 52 | +Strings can include double quotes by using the escape sequence |
| 53 | +@tt{\"}. |
| 54 | +
|
| 55 | +You must add the following operations to Hustle+: |
| 56 | +
|
| 57 | +@itemlist[ |
| 58 | +@item{@code[#:lang "racket"]{string? ; Any -> Boolean}, which determines if its argument is a string.} |
| 59 | +@item{@code[#:lang "racket"]{string-ref ; String Natural -> Char}, which |
| 60 | +extracts the character at the given index (using 0-based counting). An error is signalled if |
| 61 | +the index is out of bounds for the given string.} |
| 62 | +@item{@code[#:lang "racket"]{string-length ; String -> Natural}, which computes the length of the string.} |
| 63 | +@item{@code[#:lang "racket"]{make-string ; Natural Char -> Natural}, which constructs a string of the given |
| 64 | +length, filled with the given character.} |
| 65 | +] |
| 66 | +
|
| 67 | +The run-time system has been updated to account for a string type. It |
| 68 | +assumes a representation where the length of the string is stored in |
| 69 | +memory, followed by the characters of the string, in order. You are |
| 70 | +free to change the representation if you'd like, but you will have to |
| 71 | +update the run-time system to properly print strings. Otherwise, no |
| 72 | +changes to the run-time system should be necessary. |
| 73 | +
|
| 74 | +@section[#:tag-prefix "a5-" #:style 'unnumbered]{More operations} |
| 75 | +
|
| 76 | +Add the following operations to the Hustle+ language: |
| 77 | +
|
| 78 | +@itemize[ |
| 79 | +
|
| 80 | +@item{@code[#:lang "racket"]{box? ; Any -> Boolean}, which determines |
| 81 | +if a value is a box.} |
| 82 | +
|
| 83 | +@item{@code[#:lang "racket"]{empty? ; Any -> Boolean}, which |
| 84 | +determines if a value is the empty list.} |
| 85 | +
|
| 86 | +@item{@code[#:lang "racket"]{cons? ; Any -> Boolean}, which determines |
| 87 | +if a value is a pair.} |
| 88 | +
|
| 89 | +@item{@code[#:lang "racket"]{= ; Number Number -> Boolean}, which determines if |
| 90 | +two numbers are equal.} |
| 91 | +
|
| 92 | +@item{@code[#:lang "racket"]{< ; Number Number -> Boolean}, which determines if |
| 93 | +the first number is less than the second.} |
| 94 | +
|
| 95 | +@item{@code[#:lang "racket"]{<= ; Number Number -> Boolean}, which determines if |
| 96 | +the first number is less than or equal to the second.} |
| 97 | +
|
| 98 | +@item{@code[#:lang "racket"]{char=? ; Number Number -> Boolean}, which determines if |
| 99 | +two characters are equal.} |
| 100 | +
|
| 101 | +@item{@code[#:lang "racket"]{boolean=? ; Boolean Boolean -> Boolean}, which determines if |
| 102 | +two booleans are equal.} |
| 103 | +
|
| 104 | +] |
| 105 | +
|
| 106 | +@section[#:tag-prefix "a5-" #:style 'unnumbered]{Extending your Parser, yet again!} |
| 107 | +
|
| 108 | +
|
| 109 | +Extend your Fraud+ parser for the Hustle+ language based on the following |
| 110 | +grammar: |
| 111 | +
|
| 112 | +@verbatim{ |
| 113 | +<expr> ::= integer |
| 114 | + | character |
| 115 | + | boolean |
| 116 | + | variable |
| 117 | + | string |
| 118 | + | ( <compound> ) |
| 119 | + | [ <compound> ] |
| 120 | +
|
| 121 | +<compound> ::= <prim1> <expr> |
| 122 | + | <prim2> <expr> <expr> |
| 123 | + | if <expr> <expr> <expr> |
| 124 | + | cond <clause>* <else> |
| 125 | + | let <bindings> <expr> |
| 126 | +
|
| 127 | +<prim1> ::= add1 | sub1 | abs | - | zero? | integer->char | char->integer |
| 128 | + | char? | integer? | boolean? | string? | box? | empty? | cons? |
| 129 | + | box | unbox | car | cdr | string-length |
| 130 | +
|
| 131 | +<prim2> ::= make-string | string-ref | = | < | <= |
| 132 | + | char=? | boolean=? | + |
| 133 | +
|
| 134 | +<clause> ::= ( <expr> <expr> ) |
| 135 | + | [ <expr> <expr> ] |
| 136 | +
|
| 137 | +<else> ::= ( else <expr> ) |
| 138 | + | [ else <expr> ] |
| 139 | +
|
| 140 | +<bindings> ::= ( <binding>* ) |
| 141 | + | [ <binding>* ] |
| 142 | +
|
| 143 | +<binding> ::= ( variable <expr> ) |
| 144 | + | [ variable <expr> ] |
| 145 | +} |
| 146 | +
|
| 147 | +There is a lexer given to you in @tt{lex.rkt}, which provides two |
| 148 | +functions: @racket[lex-string] and @racket[lex-port], which consume a |
| 149 | +string or an input port, respectively, and produce a list of tokens, |
| 150 | +which are defined as follows (only the new parts are shown): |
| 151 | +
|
| 152 | +@#reader scribble/comment-reader |
| 153 | +(racketblock |
| 154 | +; type Token = |
| 155 | +; ... |
| 156 | +; | `(prim1 ,Prim1) |
| 157 | +; | `(prim2 ,Prim2) |
| 158 | +; | String |
| 159 | +
|
| 160 | +; type Prim1 = |
| 161 | +; | 'add1 |
| 162 | +; | 'sub1 |
| 163 | +; | 'zero? |
| 164 | +; | 'abs |
| 165 | +; | '- |
| 166 | +; | 'integer->char |
| 167 | +; | 'char->integer |
| 168 | +; | 'char? |
| 169 | +; | 'boolean? |
| 170 | +; | 'integer? |
| 171 | +; | 'string? |
| 172 | +; | 'box? |
| 173 | +; | 'empty? |
| 174 | +; | 'cons? |
| 175 | +; | 'box |
| 176 | +; | 'unbox |
| 177 | +; | 'car |
| 178 | +; | 'cdr |
| 179 | +; | 'string-length |
| 180 | +
|
| 181 | +; type Prim2 = |
| 182 | +; | 'make-string |
| 183 | +; | 'string-ref |
| 184 | +; | '= |
| 185 | +; | '< |
| 186 | +; | '<= |
| 187 | +; | 'char=? |
| 188 | +; | 'boolean=? |
| 189 | +; | '+ |
| 190 | +; | '- |
| 191 | +) |
| 192 | +
|
| 193 | +The lexer will take care of reading the @tt{#lang racket} header and |
| 194 | +remove any whitespace. |
| 195 | +
|
| 196 | +You must complete the code in @tt{parse.rkt} to implement the parser |
| 197 | +which constructs an s-expression representing a valid Hustle+ |
| 198 | +expression, if possible, from a list of tokens. The @racket[parse] |
| 199 | +function should have the following signature and must be provided by |
| 200 | +the module: |
| 201 | +
|
| 202 | +@#reader scribble/comment-reader |
| 203 | +(racketblock |
| 204 | +;; parse : [Listof Token] -> Expr |
| 205 | +) |
| 206 | +
|
| 207 | +As an example, @racket[parse] should produce @racket['(add1 (sub1 7))] |
| 208 | +if given |
| 209 | +
|
| 210 | +@racketblock['(lparen (prim1 add1) lparen (prim1 sub1) 7 rparen rparen eof)] |
| 211 | +
|
| 212 | +You should not need to make any changes to @tt{lex.rkt}. |
| 213 | +
|
| 214 | +@section[#:tag-prefix "a5-" #:style 'unnumbered]{Testing} |
| 215 | +
|
| 216 | +You can test your code in several ways: |
| 217 | +
|
| 218 | +@itemlist[ |
| 219 | +
|
| 220 | + @item{Using the command line @tt{raco test .} from |
| 221 | + the directory containing the repository to test everything.} |
| 222 | +
|
| 223 | + @item{Using the command line @tt{raco test <file>} to |
| 224 | + test only @tt{<file>}.} |
| 225 | +
|
| 226 | + @item{Pushing to github. You can |
| 227 | + see test reports at: |
| 228 | + @centered{@link["https://travis-ci.com/cmsc430/"]{ |
| 229 | + https://travis-ci.com/cmsc430/}} |
| 230 | +
|
| 231 | + (You will need to be signed in in order see results for your private repo.)}] |
| 232 | +
|
| 233 | +Note that only a small number of tests are given to you, so you should |
| 234 | +write additional test cases. |
| 235 | +
|
| 236 | +@bold{There is separate a repository for tests!} The testing set-up |
| 237 | +is slightly different for this assignment. There is a whole other |
| 238 | +repository that contains tests. When you push your code, Travis will |
| 239 | +automatically run your code against the tests. If you would like to |
| 240 | +run the tests locally, clone the following repository into the |
| 241 | +directory that contains your compiler and run @tt{raco test .} to test |
| 242 | +everything: |
| 243 | +
|
| 244 | +@centered{@tt{https://github.com/cmsc430/assign05-test.git}} |
| 245 | +
|
| 246 | +This repository will evolve as the week goes on, but any time there's |
| 247 | +a significant update it will be announced on Piazza. |
| 248 | +
|
| 249 | +@section[#:tag-prefix "a5-" #:style 'unnumbered]{Submitting} |
| 250 | +
|
| 251 | +Pushing your local repository to github ``submits'' your work. We |
| 252 | +will grade the latest submission that occurs before the deadline. |
| 253 | +
|
0 commit comments