Skip to content

Commit 675211a

Browse files
authored
Merge pull request #22 from dvanhorn/next
Assignment 4 and Dupe polish.
2 parents 55043f7 + d6920e2 commit 675211a

6 files changed

Lines changed: 692 additions & 74 deletions

File tree

www/assignments.scrbl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
@include-section{assignments/1.scrbl}
77
@include-section{assignments/2.scrbl}
88
@include-section{assignments/3.scrbl}
9-
9+
@include-section{assignments/4.scrbl}

www/assignments/3.scrbl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ which are defined as:
173173
;; | 'add1
174174
;; | 'sub1
175175
;; | 'zero?
176+
;; | 'if
176177
;; | 'cond
177178
;; | 'else
178179
;; | 'abs

www/assignments/4.scrbl

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
#lang scribble/manual
2+
@title[#:tag "Assignment 4" #:style 'unnumbered]{Assignment 4: Let there be Variables, 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, Sept 26, 11:59PM}
11+
12+
@(define repo "https://classroom.github.com/a/HuBPd1o9")
13+
14+
The goal of this assignment is to extend a compiler with binding forms
15+
and a character data type.
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["Fraud"]{Fraud} language we studied in class. You are tasked
22+
with:
23+
24+
@itemlist[
25+
26+
@item{incorporating the Con+ features you added in
27+
@seclink["Assignment 3"]{Assignment 3},}
28+
29+
@item{extending the language to include a character data type,}
30+
31+
@item{extending the @racket[let]-binding form of the language to bind
32+
any number of variables, and}
33+
34+
@item{updating the parser to work for Fraud+.}
35+
36+
]
37+
38+
@section[#:tag-prefix "a4-" #:style 'unnumbered]{From Con+ to Fraud+}
39+
40+
Implement the @racket[abs] and unary @racket[-] operations and the
41+
@racket[cond] form from @seclink["Assignment 3"]{Con+}. You can start
42+
from your previous code, but you will need to update it to work for
43+
Fraud+.
44+
45+
In particular, functions should signal an error when applied to the
46+
wrong type of argument and your @racket[cond] form should work with
47+
@emph{arbitrary} question expressions. In other words, @racket[cond]
48+
should work like @racket[if] in @seclink["Dupe"]{Dupe}.
49+
50+
The formal semantics of @racket[cond] are defined as:
51+
52+
@(define ((rewrite s) lws)
53+
(define lhs (list-ref lws 2))
54+
(define rhs (list-ref lws 3))
55+
(list "" lhs (string-append " " (symbol->string s) " ") rhs ""))
56+
57+
@(require (only-in racket add-between))
58+
@(define-syntax-rule (show-judgment name i j)
59+
(with-unquote-rewriter
60+
(lambda (lw)
61+
(build-lw (lw-e lw) (lw-line lw) (lw-line-span lw) (lw-column lw) (lw-column-span lw)))
62+
(with-compound-rewriters (['+ (rewrite '+)]
63+
['- (rewrite '–)]
64+
['= (rewrite '=)]
65+
['!= (rewrite '≠)])
66+
(apply centered
67+
(add-between
68+
(build-list (- j i)
69+
(λ (n) (begin (judgment-form-cases (list (+ n i)))
70+
(render-judgment-form name))))
71+
(hspace 4))))))
72+
73+
@(show-judgment 𝑭-𝒆𝒏𝒗 0 1)
74+
@(show-judgment 𝑭-𝒆𝒏𝒗 1 2)
75+
@(show-judgment 𝑭-𝒆𝒏𝒗 2 3)
76+
77+
78+
The following files have already been updated for you:
79+
@itemlist[
80+
@item{@tt{ast.rkt}}
81+
@item{@tt{syntax.rkt}}
82+
@item{@tt{interp.rkt}}
83+
]
84+
85+
You will need to modify @tt{compile.rkt} to correctly implement these
86+
features.
87+
88+
89+
@section[#:tag-prefix "a4-" #:style 'unnumbered]{Adding a Bit of Character}
90+
91+
Racket has a Character data type for representing single letters. A
92+
Racket character can represent any of the 1,114,112 Unicode
93+
@link["http://unicode.org/glossary/#code_point"]{code points}.
94+
95+
The way a character is most often written is an octothorp, followed by
96+
a backslash, followed by the character itself. So for example the
97+
character @tt{a} is written @racket[#\a]. The character @tt{λ} is
98+
written @racket[#\λ]. The character @tt{文} is written @racket[#\文].
99+
100+
A character can be converted to an integer and @emph{vice versa}:
101+
102+
@ex[
103+
(char->integer #\a)
104+
(char->integer #\λ)
105+
(char->integer #\文)
106+
(integer->char 97)
107+
(integer->char 955)
108+
(integer->char 25991)
109+
]
110+
111+
However, integers in the range of valid code points are acceptable to
112+
@racket[integer->char] and using any other integer will produce an
113+
error:
114+
115+
@ex[
116+
(eval:error (integer->char -1))
117+
(eval:error (integer->char 55296))
118+
]
119+
120+
There are a few other ways to write characters (see the Racket
121+
@link["https://docs.racket-lang.org/reference/reader.html#%28part._parse-character%29"]{Reference}
122+
for the details), but you don't have to worry much about this since
123+
the lexer takes care of reading characters in all their different
124+
forms and the run-time system given to you takes care of printing
125+
them.
126+
127+
Your job is extend the compiler to handle the compilation of
128+
characters and implement the operations @racket[integer->char],
129+
@racket[char->integer], and @racket[char?]. The operations should
130+
work as in Racket and should signal an error (i.e. @racket['err])
131+
whenever Racket produces an error. While you're at it, implement
132+
the predicates @racket[integer?] and @racket[boolean?], too.
133+
134+
The following files have already been updated for you:
135+
136+
@itemlist[
137+
138+
@item{@tt{ast.rkt}}
139+
140+
@item{@tt{syntax.rkt}}
141+
142+
@item{@tt{interp.rkt}}
143+
144+
@item{@tt{main.c}}
145+
146+
]
147+
148+
You will need to modify @tt{compile.rkt} to correctly implement these
149+
features. Note that you must use the same representation of
150+
characters as used in the run-time system and should not change
151+
@tt{main.c}.
152+
153+
@section[#:tag-prefix "a4-" #:style 'unnumbererd]{Generalizing Let}
154+
155+
The Fraud language has a let form that binds a single variable in the
156+
scope of some expression. This is a restriction of the more general
157+
form of @racket[let] that binds any number of expressions. So for
158+
example,
159+
160+
@racketblock[
161+
(let ((x 1) (y 2) (z 3))
162+
_e)
163+
]
164+
165+
simultaneously binds @racket[x], @racket[y], and @racket[z] in the
166+
scope of @racket[_e].
167+
168+
The syntax of a @racket[let] expression allows any number of binders
169+
to occur, so @racket[(let () _e)] is valid syntax and is equivalent to
170+
@racket[_e].
171+
172+
The binding of each variable is only in scope in the body, @bold{not}
173+
in the right-hand-sides of any of the @racket[let].
174+
175+
For example, @racketblock[(let ((x 1) (y x)) 0)] is a syntax error
176+
because the occurrence of @racket[x] is not bound.
177+
178+
The following files have already been updated for you:
179+
180+
@itemlist[
181+
182+
@item{@tt{ast.rkt}}
183+
184+
@item{@tt{interp.rkt}}
185+
186+
]
187+
188+
Update @tt{syntax.rkt} to define two functions:
189+
190+
@itemize[
191+
192+
@item{@code[#:lang "racket"]{expr? ; Any -> Boolean}, which consumes
193+
anything and determines if it is a well-formed expression, i.e. it
194+
must be an instance of an @tt{Expr} @emph{and} each @racket[let]
195+
expression must bind a distinct set of variables.}
196+
197+
@item{@code[#:lang "racket"]{closed? ; Expr -> Boolean}, which consumes
198+
an @tt{Expr} and determines if it is closed, i.e. every variable
199+
occurrence is bound.}
200+
201+
]
202+
203+
Update @tt{compile.rkt} to correctly compile the generalized form of
204+
@racket[let]. The compiler may assume the input is a closed
205+
expression.
206+
207+
@section[#:tag-prefix "a4-" #:style 'unnumbered]{Extending your Parser}
208+
209+
210+
Extend your Con+ parser for the Fraud+ language based on the following
211+
grammar:
212+
213+
@verbatim{
214+
<expr> ::= integer
215+
| character
216+
| variable
217+
| ( <compound> )
218+
| [ <compound> ]
219+
220+
<compound> ::= <prim> <expr>
221+
| if <expr> <expr> <expr>
222+
| cond <clause>* <else>
223+
| let <bindings> <expr>
224+
225+
<prim> ::= add1 | sub1 | abs | - | zero? | integer->char | char->integer
226+
| char? | integer? | boolean?
227+
228+
<clause> ::= ( <expr> <expr> )
229+
| [ <expr> <expr> ]
230+
231+
<else> ::= ( else <expr> )
232+
| [ else <expr> ]
233+
234+
<bindings> ::= ( <binding>* )
235+
| [ <binding>* ]
236+
237+
<binding> ::= ( variable <expr> )
238+
| [ variable <expr> ]
239+
}
240+
241+
There is a lexer given to you in @tt{lex.rkt}, which provides two
242+
functions: @racket[lex-string] and @racket[lex-port], which consume a
243+
string or an input port, respectively, and produce a list of tokens,
244+
which are defined as follows:
245+
246+
@margin-note{Note that the @tt{Token} type has changed slightly from
247+
@secref{Assignment 3}: @racket['add1] is now @racket['(prim add1)],
248+
@racket['cond] is now @racket['(keyword cond)], etc.}
249+
250+
@#reader scribble/comment-reader
251+
(racketblock
252+
;; type Token =
253+
;; | Integer
254+
;; | Char
255+
;; | Boolean
256+
;; | `(variable ,Variable)
257+
;; | `(keyword ,Keyword)
258+
;; | `(prim ,Prim)
259+
;; | 'lparen ;; (
260+
;; | 'rparen ;; )
261+
;; | 'lsquare ;; [
262+
;; | 'rsquare ;; ]
263+
;; | 'eof ;; end of file
264+
265+
;; type Variable = Symbol (other than 'let, 'cond, etc.)
266+
267+
;; type Keyword =
268+
;; | 'let
269+
;; | 'cond
270+
;; | 'else
271+
;; | 'if
272+
273+
;; type Prim =
274+
;; | 'add1
275+
;; | 'sub1
276+
;; | 'zero?
277+
;; | 'abs
278+
;; | '-
279+
;; | 'integer->char
280+
;; | 'char->integer
281+
;; | 'char?
282+
;; | 'boolean?
283+
;; | 'integer?
284+
)
285+
286+
The lexer will take care of reading the @tt{#lang racket} header and
287+
remove any whitespace.
288+
289+
You must complete the code in @tt{parse.rkt} to implement the parser
290+
which constructs an s-expression representing a valid Fraud+
291+
expression, if possible, from a list of tokens. The @racket[parse]
292+
function should have the following signature and must be provided by
293+
the module:
294+
295+
@#reader scribble/comment-reader
296+
(racketblock
297+
;; parse : [Listof Token] -> Expr
298+
)
299+
300+
As an example, @racket[parse] should produce @racket['(add1 (sub1 7))]
301+
if given
302+
303+
@racketblock['(lparen (prim add1) lparen (prim sub1) 7 rparen rparen eof)]
304+
305+
306+
You should not need to make any changes to @tt{lex.rkt}.
307+
308+
The given @tt{interp-file.rkt} and @tt{compile-file.rkt} code no
309+
longer use @racket[read], but instead use the parser. This means you
310+
neither will work until the parser is complete.
311+
312+
313+
@bold{The code you are given includes two(!) implementations of the
314+
Con+ parser.} One implementation follows the imperative approach; the
315+
other follows the functional approach.
316+
317+
You may extend either, or you may throw out the given code and start
318+
from the code you wrote previously.
319+
320+
321+
@section[#:tag-prefix "a4-" #:style 'unnumbered]{Testing}
322+
323+
You can test your code in several ways:
324+
325+
@itemlist[
326+
327+
@item{Using the command line @tt{raco test .} from
328+
the directory containing the repository to test everything.}
329+
330+
@item{Using the command line @tt{raco test <file>} to
331+
test only @tt{<file>}.}
332+
333+
@item{Pushing to github. You can
334+
see test reports at:
335+
@centered{@link["https://travis-ci.com/cmsc430/"]{
336+
https://travis-ci.com/cmsc430/}}
337+
338+
(You will need to be signed in in order see results for your private repo.)}]
339+
340+
Note that only a small number of tests are given to you, so you should
341+
write additional test cases.
342+
343+
@bold{We have removed @tt{random.rkt}} and instead provide a
344+
@tt{random-exprs.rkt} module which provides @racket[exprs], a list
345+
of 500 closed expressions. It is used in the
346+
@tt{test/compile-rand.rkt} file to randomly test compiler correctness.
347+
This should help speed up the testing process since the random
348+
generation is slow.
349+
350+
@section[#:tag-prefix "a4-" #:style 'unnumbered]{Submitting}
351+
352+
Pushing your local repository to github ``submits'' your work. We
353+
will grade the latest submission that occurs before the deadline.
354+

0 commit comments

Comments
 (0)