Skip to content

Commit dd17cec

Browse files
authored
Merge pull request #196 from cmsc430/fall-2025
Fall 2025
2 parents 1767af6 + 16bd45c commit dd17cec

File tree

3 files changed

+103
-286
lines changed

3 files changed

+103
-286
lines changed

www/assignments/3.scrbl

Lines changed: 56 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@
88

99
The goal of this assignment is to extend the language developed in
1010
@secref{Dupe} with some simple unary numeric and boolean operations
11-
and two forms of control flow expressions: @racket[cond]-expressions
12-
and @racket[case]-expressions.
11+
and a new form of control flow expressions: @racket[cond]-expressions.
1312

14-
@section[#:tag-prefix "a3-" #:style 'unnumbered]{Dupe+}
13+
@section[#:tag "a3-dupe-plus" #:style 'unnumbered]{Dupe+}
1514

1615
The Dupe+ language extends Dupe in the follow ways:
1716

1817
@itemlist[
1918
@item{adding new primitive operations,}
20-
@item{adding @racket[cond], and}
21-
@item{adding @racket[case].}
19+
@item{adding @racket[cond].}
2220
]
2321

2422
@subsection[#:tag-prefix "a3-" #:style 'unnumbered]{Primitives}
@@ -27,7 +25,7 @@ The following new primitves are included in Dupe+:
2725

2826
@itemlist[
2927
@item{@racket[(abs _e)]: compute the absolute value of @racket[_e],}
30-
@item{@racket[(- _e)]: flips the sign of @racket[_e], i.e. compute @math{0-@racket[_e]}, and}
28+
@item{@racket[(- _e)]: flip the sign of @racket[_e], i.e. compute @math{0-@racket[_e]}, and}
3129
@item{@racket[(not _e)]: compute the logical negation of @racket[_e]; note that the negation of @emph{any} value other than @racket[#f] is @racket[#f] and the negation of @racket[#f] is @racket[#t].}
3230
]
3331

@@ -42,10 +40,10 @@ The following new conditional form is included in Dupe+:
4240
]
4341

4442
A @racket[cond] expression has any number of clauses @racket[[_e-pi
45-
_e-ai] ...], followed by an ``else'' clause @racket[[else _en]]. For
46-
the purposes of this assignment, we will assume every @racket[cond]
47-
expression ends in an @racket[else] clause, even though this is not
48-
true in general for Racket. The parser should reject any
43+
_e-ai] ...], followed by an ``else'' clause @racket[[else _e-an]].
44+
For the purposes of this assignment, we will assume every
45+
@racket[cond] expression ends in an @racket[else] clause, even though
46+
this is not true in general for Racket. The parser will reject any
4947
@racket[cond]-expression that does not end in @racket[else].
5048

5149

@@ -56,43 +54,61 @@ does not evaluate to @racket[#f] is found, in which case, the corresponding expr
5654
@racket[cond] expression. If no such @racket[_e-pi] exists, the
5755
expression @racket[_e-an]'s value is the value of the @racket[cond].
5856

59-
@subsection[#:tag-prefix "a3-" #:style 'unnumbered]{Case expressions}
6057

61-
The following new case form is included in Dupe+:
58+
@section[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing Dupe+}
6259

63-
@racketblock[
64-
(case _ev
65-
[(_d1 ...) _e1]
66-
...
67-
[else _en])
68-
]
60+
You must extend the interpreter and compiler to implement Dupe+. (The
61+
parser for Dupe+ is given to you.) You are given a file
62+
@tt{dupe-plus.zip} on ELMS with a starter compiler based on the
63+
@secref{Dupe} language we studied in class.
6964

70-
The @racket[case] expression form is a mechanism for dispatching
71-
between a number of possible expressions based on a value, much like
72-
C's notion of a @tt{switch}-statement.
65+
You may use any a86 instructions you'd like, however it is possible to
66+
complete the assignment using @racket[Cmp], @racket[Je], @racket[Jg],
67+
@racket[Jmp], @racket[Label], @racket[Mov], and @racket[Sub].
7368

74-
The meaning of a @racket[case] expression is computed by evaluating
75-
the expression @racket[_ev] and then proceeding in order through each
76-
clause until one is found that has a datum @racket[_di] equal to
77-
@racket[_ev]'s value. Once such a clause is found, the corresponding
78-
expression @racket[_ei] is evaluated and its value is the value of the
79-
@racket[case] expression. If no such clause exists, expression
80-
@racket[_en] is evaluated and its value is the value of the
81-
@racket[case] expression.
69+
@section[#:tag-prefix "a3-" #:style 'unnumbered #:tag "parse"]{Parsing Dupe+}
8270

83-
Note that each clause consists of a parenthesized list of
84-
@emph{datums}, which in the setting of Dupe means either integer or
85-
boolean literals.
71+
The AST type and parser for Dupe+ are given to you.
8672

87-
@section[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing Dupe+}
73+
Here's the AST definition for the added primitives and @racket[cond]:
8874

89-
You must extend the parser, interpreter, and compiler to implement
90-
Dupe+. You are given a file @tt{dupe-plus.zip} on ELMS with a starter
91-
compiler based on the @secref{Dupe} language we studied in class.
75+
@#reader scribble/comment-reader
76+
(racketblock
77+
;; type Expr =
78+
;; ...
79+
;; | (Cond [Listof Expr] [Listof Expr] Expr)
9280

93-
You may use any a86 instructions you'd like, however it is possible to
94-
complete the assignment using @racket[Cmp], @racket[Je], @racket[Jg],
95-
@racket[Jmp], @racket[Label], @racket[Mov], and @racket[Sub].
81+
;; type Op =
82+
;; ...
83+
;; | 'abs | '- | 'not
84+
85+
(struct Cond (cs e) #:prefab)
86+
)
87+
88+
There is one new kind of expression constructor: @racket[Cond]. A
89+
@racket[Cond] AST node contains three parts: two equal length lists of
90+
expression and an expression. The two lists represent the clauses,
91+
where the first list contains all of the left-hand-side parts of the
92+
clauses and the other contains all of the right-hand-side parts.
93+
94+
Here are some examples of how concrete expressions are parsed into
95+
ASTs using this representation:
96+
97+
@itemlist[
98+
99+
@item{@racket[(abs 1)] parses as @racket[(Prim1 'abs (Lit 1))],}
100+
101+
@item{@racket[(not #t)] parses as @racket[(Prim1 'not (Lit #t))],}
102+
103+
@item{@racket[(cond [else 5])] parses as @racket[(Cond '() '() (Lit 5))],}
104+
105+
@item{@racket[(cond [(not #t) 3] [else 5])] parses as @racket[(Cond
106+
(list (Prim1 'not (Lit #t))) (list (Lit 3)) (Lit 5))],}
107+
108+
@item{@racket[(cond [(not #t) 3] [7 4] [else 5])] parses as
109+
@racket[(Cond (list (Prim1 'not (Lit #t)) (Lit 7)) (list (Lit 3)
110+
(Lit 4)) (Lit 5))],}
111+
]
96112

97113
@subsection[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing primitives}
98114

@@ -103,8 +119,7 @@ these using the limited a86 instruction set.
103119

104120
To do this, you should:
105121
@itemlist[
106-
@item{Study @tt{ast.rkt} and the new forms of expression (i.e. new AST nodes)
107-
then update the comment at the top describing what the grammmar should look like.}
122+
@item{Study @tt{ast.rkt} to understand how these new forms of expression are represented.}
108123

109124
@item{Study @tt{parse.rkt} and add support for parsing these
110125
expressions. (See @secref[#:tag-prefixes '("a3-")]{parse} for guidance.)}
@@ -126,7 +141,6 @@ To do this, you should:
126141

127142
@itemlist[
128143
@item{Study @tt{ast.rkt} to add appropriate AST nodes.}
129-
@item{Extend @tt{parse.rkt} to parse such expressions. (See @secref[#:tag-prefixes '("a3-")]{parse} for guidance.)}
130144
@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[cond] expressions.}
131145

132146
@item{Make examples of @racket[cond]-expressions and potential translations of them
@@ -138,108 +152,6 @@ expressions based on your examples.}
138152
@item{Check your implementation by running the tests in @tt{test/all.rkt}.}
139153
]
140154

141-
@section[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing case}
142-
143-
Implement the @racket[case] expression form as described earlier.
144-
To do this, you should:
145-
146-
@itemlist[
147-
@item{Study @tt{ast.rkt} to add appropriate AST nodes.}
148-
@item{Extend @tt{parse.rkt} to parse such expressions. (See @secref[#:tag-prefixes '("a3-")]{parse} for guidance.)}
149-
@item{Update @tt{interp-prim.rkt} and @tt{interp.rkt} to correctly interpret @racket[case] expressions.}
150-
151-
@item{Make examples of @racket[case]-expressions and potential translations of them
152-
to assembly.}
153-
154-
@item{Update @tt{compile.rkt} to correctly compile @racket[case] expressions based on your examples.}
155-
156-
@item{Check your implementation by running the tests in @tt{test/all.rkt}.}
157-
]
158-
159-
@section[#:tag-prefix "a3-" #:style 'unnumbered #:tag "parse"]{A Leg Up on Parsing}
160-
161-
In the past, designing the AST type and structure definitions has
162-
given students some grief. Getting stuck at this point means you
163-
can't make any progress on the assignment and making a mistake at this
164-
level can cause real trouble down the line for your compiler.
165-
166-
For that reason, let us give you a strong hint for a potential design
167-
of the ASTs and examples of how parsing could work. You are not
168-
required to follow this design, but you certainly may.
169-
170-
Here's a potential AST definition for the added primitives,
171-
@racket[cond], and @racket[case]:
172-
173-
@#reader scribble/comment-reader
174-
(racketblock
175-
;; type Expr =
176-
;; ...
177-
;; | (Cond [Listof CondClause] Expr)
178-
;; | (Case Expr [Listof CaseClause] Expr)
179-
180-
;; type CondClause = (Clause Expr Expr)
181-
;; type CaseClause = (Clause [Listof Datum] Expr)
182-
183-
;; type Datum = Integer | Boolean
184-
185-
;; type Op =
186-
;; ...
187-
;; | 'abs | '- | 'not
188-
189-
(struct Cond (cs e) #:prefab)
190-
(struct Case (e cs el) #:prefab)
191-
(struct Clause (p b) #:prefab)
192-
)
193-
194-
There are two new kinds of expression constructors: @racket[Cond] and
195-
@racket[Case]. A @racket[Cond] AST node contains a list of
196-
cond-clauses and expression, which the expression of the @racket[else]
197-
clause. Each cond-clause is represented by a @racket[Clause]
198-
structure containing two expressions: the left-hand-side of the
199-
clause which is used to determine whether the right-hand-side is
200-
evaluated, and the right-hand-side expression.
201-
202-
The @racket[Case] AST node contains three things: an expression that
203-
is the subject of the dispatch (i.e. the expression that is evaluated
204-
to determine which clause should be taken), a list of case-clauses
205-
(not to be confused with cond-clauses), and an @racket[else]-clause
206-
expression. Each case-clause, like a cond-clause, consists of two
207-
things. Hence we re-use the @racket[Clause] structure, but with
208-
different types of elements. The first element is a list of
209-
@emph{datums}, each being either an integer or a boolean.
210-
211-
Now, we won't go so far as to @emph{give} you the code for
212-
@racket[parse], but we can give you some examples:
213-
214-
@itemlist[
215-
216-
@item{@racket[(abs 1)] parses as @racket[(Prim1 'abs (Lit 1))],}
217-
218-
@item{@racket[(not #t)] parses as @racket[(Prim1 'not (Lit #t))],}
219-
220-
@item{@racket[(cond [else 5])] parses as @racket[(Cond '() (Lit 5))],}
221-
222-
@item{@racket[(cond [(not #t) 3] [else 5])] parses as @racket[(Cond
223-
(list (Clause (Prim1 'not (Lit #t)) (Lit 3))) (Lit 5))],}
224-
225-
@item{@racket[(cond [(not #t) 3] [7 4] [else 5])] parses as
226-
@racket[(Cond (list (Clause (Prim1 'not (Lit #t)) (Lit 3)) (Clause
227-
(Lit 7) (Lit 4))) (Lit 5))],}
228-
229-
@item{@racket[(case (add1 3) [else 2])] parses as @racket[(Case (Prim1
230-
'add1 (Lit 3)) '() (Lit 2))].}
231-
232-
@item{@racket[(case 4 [(4) 1] [else 2])] parses as @racket[(Case (Lit
233-
4) (list (Clause (list 4) (Lit 1))) (Lit 2))],}
234-
235-
@item{@racket[(case 4 [(4 5 6) 1] [else 2])] parses as @racket[(Case (Lit
236-
4) (list (Clause (list 4 5 6) (Lit 1))) (Lit 2))], and}
237-
238-
@item{@racket[(case 4 [(4 5 6) 1] [(#t #f) 7] [else 2])] parses as @racket[(Case (Lit
239-
4) (list (Clause (list 4 5 6) (Lit 1)) (Clause (list #t #f) (Lit 7))) (Lit 2))].}
240-
]
241-
242-
243155
@section[#:tag-prefix "a3-" #:style 'unnumbered]{Testing}
244156

245157
You can test your code in several ways:

0 commit comments

Comments
 (0)