Skip to content

Commit bedefe7

Browse files
committed
Assignment 7.
1 parent 042f2b6 commit bedefe7

File tree

2 files changed

+239
-0
lines changed

2 files changed

+239
-0
lines changed

www/assignments.scrbl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@
99
@include-section{assignments/4.scrbl}
1010
@include-section{assignments/5.scrbl}
1111
@include-section{assignments/6.scrbl}
12+
@include-section{assignments/7.scrbl}
13+
14+
@;{assignment 8: quote in general, and quasiquote}
15+
@;{assignment 9: standard library, IO}

www/assignments/7.scrbl

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
#lang scribble/manual
2+
@title[#:tag "Assignment 7" #:style 'unnumbered]{Assignment 7: Symbols, interning, and gensym}
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: Tues, Nov 12, 11:59PM}
11+
12+
@(define repo "FIXME")
13+
14+
The goal of this assignment is to (1) implement symbols and the
15+
@racket[eq?] primitive operation, (2) to implement symbol interning by
16+
program transformation.
17+
18+
Assignment repository:
19+
@centered{@link[repo repo]}
20+
21+
You are given a repository with a starter compiler similar to the
22+
@seclink["Loot"]{Loot} language we studied in class.
23+
24+
The given code also implements all the ``plus'' features we've
25+
developed in past assignments.
26+
27+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Symbols}
28+
29+
Your first task is to implement symbols for the Loot+ language.
30+
You've used symbols extensively throughout the semester, so their use
31+
should be familiar to you. A symbol evaluates to itself:
32+
33+
@ex[
34+
'foo
35+
]
36+
37+
Your first task is to implement a symbol data type. The given code
38+
includes syntax checking for programs that may contain symbols and
39+
run-time support for printing symbols. The compiler has been stubbed
40+
for compiling symbols. You will need to implement
41+
@racket[compile-symbol] in @tt{compile.rkt}.
42+
43+
A symbol can be represented much like a string: as a continuous
44+
sequence of characters in memory, along with a length field. The type
45+
tag is different, since strings and symbols should be disjoint data
46+
types.
47+
48+
Once you implement @racket[compile-symbol], you should be able to
49+
write programs that contain symbols.
50+
51+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Pointer equality}
52+
53+
Your next task is to implement the @racket[eq?] primitive operation,
54+
which compares two values for pointer equality. Immediate values
55+
(characters, integers, booleans, empty list, etc.) should be
56+
pointer-equal to values that are ``the same.'' So for example:
57+
58+
@ex[
59+
(eq? '() '())
60+
(eq? 5 5)
61+
(eq? #\a #\a)
62+
(eq? #\t #\t)
63+
]
64+
65+
On the other hand, values that are allocated in memory such as boxes,
66+
pairs, procedures, etc., are only @racket[eq?] to each other if they
67+
are allocated to the same location in memory. So for example, the
68+
following could all produce @racket[#f]:
69+
70+
@ex[
71+
(eq? (λ (x) x) (λ (x) x))
72+
(eq? (cons 1 2) (cons 1 2))
73+
(eq? (box 1) (box 1))
74+
]
75+
76+
However these must be produce @racket[#t]:
77+
78+
@ex[
79+
(let ((x (λ (x) x)))
80+
(eq? x x))
81+
(let ((x (cons 1 2)))
82+
(eq? x x))
83+
(let ((x (box 1)))
84+
(eq? x x))
85+
]
86+
87+
Applying @racket[eq?] to any two values from disjoint data types
88+
should produce @racket[#f]:
89+
90+
@ex[
91+
(eq? 0 #f)
92+
(eq? #\a "a")
93+
(eq? '() #t)
94+
(eq? 'fred "fred")
95+
]
96+
97+
The given compiler is stubbed for the @racket[eq?] primitive. You
98+
must implement @racket[compile-eq?].
99+
100+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Interning symbols}
101+
102+
One thing you may notice at this point is that because symbols are
103+
allocated in memory, the behavior @racket[eq?] with your compiler
104+
differs from Racket's behavior.
105+
106+
In Racket, two symbols which are written the same way in a given
107+
program are @racket[eq?] to each other.
108+
109+
@ex[
110+
(eq? 'x 'x)
111+
]
112+
113+
But your compiler will (probably) produce @racket[#f].
114+
115+
The problem is that Racket ``interns'' symbols, meaning that all
116+
occurrences of a symbol are allocated to the same memory location.
117+
(Languages like Java also do this with string literals.)
118+
119+
Extend your compiler so that @racket[eq?] behaves correctly on
120+
symbols. Note, you should @emph{not change the way @racket[eq?]
121+
works}, rather you should change how symbols are handled by the
122+
compiler.
123+
124+
The most effective way to implement symbol interning is to apply a
125+
program transformation to the given program to compile. This
126+
transformation should replace multiple occurrences of the same symbol
127+
with a variable that is bound to that symbol, and that symbol should
128+
be allocated exactly once.
129+
130+
So for example,
131+
132+
@racketblock[
133+
(eq? 'fred 'fred)
134+
]
135+
136+
could be transformed to:
137+
138+
@racket[
139+
(let ((x 'fred))
140+
(eq? x x))
141+
]
142+
143+
The latter should result in @racket[#t] since the @racket['fred]
144+
symbol is allocated exactly once.
145+
146+
The compiler uses a @racket[intern-symbols] function, which does
147+
nothing in the given code, but should be re-defined to perform the
148+
symbol interning program transformation. Note: you probably want to
149+
define a few helper functions to make @racket[intern-symbols] work.
150+
151+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Generating symbols}
152+
153+
Finally, implement the @racket[gensym] primitive, which generates a
154+
symbol distinct from all other symbols.
155+
156+
To keep things simple, you should implement the nullary version of
157+
@racket[gensym], i.e. it should take zero arguments and produce a new
158+
symbol.
159+
160+
The following program should always produce @racket[#f]:
161+
162+
@ex[
163+
(eq? (gensym) (gensym))
164+
]
165+
166+
But the following should always produce @racket[#t]:
167+
168+
169+
@ex[
170+
(let ((x (gensym)))
171+
(eq? x x))
172+
]
173+
174+
Note: Racket's @racket[gensym] will generate a new name for a symbol,
175+
usually something like @racket['g123456], where each successive call
176+
to @racket[gensym] will produce @racket['g123457], @racket['g123458],
177+
@racket['g123459], etc. Yours does not have to do this (although it's
178+
fine if it does). All that matters is that @racket[gensym] produces a
179+
symbol that is not @racket[eq?] to any other symbol but itself.
180+
181+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Bonus}
182+
183+
Should you find yourself having completed the assignment with time to
184+
spare, you could try implementing @racket[compile-tail-apply], which
185+
compiles uses of @racket[apply] that appear in tail position. It is
186+
currently defined to use the non-tail-call code generator, which means
187+
@racket[apply] does not make a proper tail call.
188+
189+
Keep in mind that this language, the subexpression of @racket[apply]
190+
are arbitrary expressions: @racket[(apply _e0 _e1)] and that
191+
@racket[_e0] may evaluate to a closure, i.e. a function with a saved
192+
environment. Moreover, the function may have been defined to have
193+
variable arity. All of these issues will conspire to make tail calls
194+
with @racket[apply] tricky to get right.
195+
196+
This isn't worth any credit, but you might learn something.
197+
198+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Testing}
199+
200+
You can test your code in several ways:
201+
202+
@itemlist[
203+
204+
@item{Using the command line @tt{raco test .} from
205+
the directory containing the repository to test everything.}
206+
207+
@item{Using the command line @tt{raco test <file>} to
208+
test only @tt{<file>}.}
209+
210+
@item{Pushing to github. You can
211+
see test reports at:
212+
@centered{@link["https://travis-ci.com/cmsc430/"]{
213+
https://travis-ci.com/cmsc430/}}
214+
215+
(You will need to be signed in in order see results for your private repo.)}]
216+
217+
Note that only a small number of tests are given to you, so you should
218+
write additional test cases.
219+
220+
@bold{There is separate a repository for tests!} When you push your
221+
code, Travis will automatically run your code against the tests. If
222+
you would like to run the tests locally, clone the following
223+
repository into the directory that contains your compiler and run
224+
@tt{raco test .} to test everything:
225+
226+
@centered{@tt{https://github.com/cmsc430/assign07-test.git}}
227+
228+
This repository will evolve as the week goes on, but any time there's
229+
a significant update it will be announced on Piazza.
230+
231+
@section[#:tag-prefix "a7-" #:style 'unnumbered]{Submitting}
232+
233+
Pushing your local repository to github ``submits'' your work. We
234+
will grade the latest submission that occurs before the deadline.
235+

0 commit comments

Comments
 (0)