Skip to content

Commit

Permalink
Merge pull request #177 from cmsc430/pdarragh
Browse files Browse the repository at this point in the history
Rewrite assignment 4 instructions
  • Loading branch information
dvanhorn authored Mar 11, 2024
2 parents 3a94b34 + 3e6d163 commit 4af1fb2
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 134 deletions.
255 changes: 124 additions & 131 deletions www/assignments/4.scrbl
Original file line number Diff line number Diff line change
@@ -1,194 +1,187 @@
#lang scribble/manual
@title[#:tag "Assignment 4" #:style 'unnumbered]{Assignment 4: Let there be (Many) Variables}

@(require (for-label (except-in racket ...)))
@(require "../../langs/fraud-plus/semantics.rkt")
@(require redex/pict)
@title[#:tag "Assignment 4 (New)" #:style 'unnumbered]{Assignment 4: Let There Be (Many) Variables}

@(require "../notes/ev.rkt")
@bold{Part 1 Due: Wednesday, March 27, 11:59PM EST}

@bold{Due: Wednesday, November 1, 11:59PM EST}
@bold{Part 2 Due: Wednesday, March 27, 11:59PM EST}

The goal of this assignment is to extend a compiler with binding
forms and primitives that can take any number of arguments.

You are given a @tt{fraud-plus.zip} file on ELMS with a starter
compiler similar to the @seclink["Fraud"]{Fraud} language we studied
in class. You are tasked with:
The goal of this assignment is to extend a compiler with binding forms and
primitives that can take any number of arguments.

@itemlist[

@item{incorporating the language features you added in
@seclink["Assignment 3"]{Assignment 3}, scaled up to Fraud,}
This assignment consists of two parts. In Part 1 you must submit test programs
written in the new Fraud+ language. In Part 2 you must implement Fraud+.

@item{extending the addition primitive to handle an arbitrary number of arguments,}
@section[#:tag-prefix "a4-" #:style 'unnumbered]{Part 1}

@item{extending the @racket[let]-binding form of the language to bind any number of variables, and}
For the first part of the assignment, you must write test programs in the
Fraud+ language. These programs should be syntactically well-formed and
@bold{must produce an answer} when evaluated, i.e., these should be programs
that either produce values or are expected to return @tt{'err} according to the
Fraud semantics, but should not cause other errors. (The concept of an
@emph{answer} was introduced in @seclink["errors"]{Extort}.)

@item{adding a @racket[let*]-binding form to the language to allow back-references.}
]
You may write as many test programs as you like, but @bold{each program must be
written in a separate file}. You can put all of your files in one directory and
compress ("zip") that directory to submit it. Each program should be formatted
as usual for a standalone program, i.e., it should have the line @tt{#lang
racket} at the top and your program expression on a line below that.

@section[#:tag-prefix "a4-" #:style 'unnumbered]{From Dupe+ to Fraud+}
Your submission will be graded by running each program on a set of Fraud+
compilers implemented by students in previous semesters, and your goal is to
craft test programs that discover bugs in these implementations. Your programs
will be run on many more compilers than you need to eliminate for a full score;
this is so students do not all need to find the same bugs. Additionally, we do
not know for certain that every compiler has a bug, so it may not be possible
to eliminate all of them. (We randomly select some compilers that pass all of
our tests so that students have the opportunity to write better tests than us.
This has helped us find deficiencies in our compilers before.)

Implement the @racket[abs], unary @racket[-], and @racket[not]
operations and the @racket[cond] and @racket[case] forms from
@seclink["Assignment 3"]{Assignment 3}.

Unlike Assignment 3, the AST struct definitions and parsing code are
provided. Study the relevant parts in @tt{ast.rkt} and @tt{parse.rkt},
understand what is different (if anything) from your own
implementation and implement the relevant functionality in
@tt{interp.rkt}, @tt{interp-prim.rkt}, and @tt{compile.rkt}. You can
start from your previous code, but you will need to update it to work
for the structures provided. What's essentially left for you to do is
to make sure to correctly signal an error (@racket['err]) when these
constructs are applied to the wrong type of argument.

While you're at it, implement the predicates @racket[integer?] and
@racket[boolean?] for checking the type of an argument, modeled by
@racket[char?] which was covered in the lectures.
@section[#:tag-prefix "a4-" #:style 'unnumbered]{Part 2}

For the second part of the assignment, you are given a @tt{fraud-plus.zip} file
on ELMS with a starter compiler similar to the @seclink["Fraud"]{Fraud}
language we studied in class.

The following files have already been updated for you:
Unlike @seclink["Assignment 3"]{Assignment 3}, the following files have already
been updated for you @bold{and should not be changed by you}:
@itemlist[
@item{@tt{ast.rkt}}
@item{@tt{parse.rkt}}
@item{@tt{parse.rkt}}
]

You will need to modify:
So you will only need to modify:
@itemlist[
@item{@tt{compile.rkt}}
@item{@tt{interp.rkt}}
@item{@tt{interp-prim.rkt}}
@item{@tt{compile.rkt}}
@item{@tt{compile-ops.rkt}}
]
to correctly implement these features.
to correctly implement the new features. These features are described below.


You do not necessarily need to change all of these files depending on
your design choices, but you shouldn't alter any other files for
Gradescope to work.
@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Submitting}

@section[#:tag-prefix "a4-" #:style 'unnumbered]{From Binary to Variadic Addition}
Submit a zip file containing your work to Gradescope. Use @tt{make submit.zip}
from within the @tt{fraud-plus} directory to create a zip file with the proper
structure.

In Fraud, we implemented a binary operation for addition. However,
Racket supports an arbitrary number of arguments for @racket[+]. Your
job is to extend the interpreter and compiler to behave similarly.
We will not use your @tt{ast.rkt} or @tt{parse.rkt} files. Part of Assignment 3
was learning to design your own structures, but part of Assignment 4 is
learning to work within the constraints of an existing design!

The following file have already been updated for you:

@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Testing}

You can test your code in several ways:

@itemlist[
@item{@tt{ast.rkt}}
@item{@tt{parse.rkt}}
]

You will need to modify
@item{Using the command line @tt{raco test test/} from the @tt{fraud-plus}
directory to test everything.}

@item{Using the command line @tt{raco test <file>} to only test @tt{<file>}.}
]

Note that only a small number of tests are given to you, so you should
write additional test cases. We recommend using your tests from Part 1!


@section[#:tag-prefix "a4-" #:style 'unnumbered]{Fraud+}

The Fraud+ language extends the Fraud language we studied in class with some
new features:

@itemlist[
@item{@tt{compile.rkt}}
@item{@tt{interp.rkt}}
@item{@tt{interp-prim.rkt}}
]
to correctly implement these features.

@section[#:tag-prefix "a4-" #:style 'unnumbered]{Generalizing Let}
@item{The features added in @seclink["Assignment 3"]{Assignment 3}, namely:

The Fraud language has a let form that binds a single variable in the
scope of some expression. This is a restriction of the more general
form of @racket[let] that binds any number of expressions. So for
example,
@itemlist[

@racketblock[
(let ((x 1) (y 2) (z 3))
_e)
]
@item{@racket[abs], @racket[-], and @racket[not]}
@item{@racket[cond]}
@item{@racket[case]}

simultaneously binds @racket[x], @racket[y], and @racket[z] in the
scope of @racket[_e].
]}

The syntax of a @racket[let] expression allows any number of binders
to occur, so @racket[(let () _e)] is valid syntax and is equivalent to
@racket[_e].
@item{New primitives @racket[integer?] and @racket[boolean?].}

The binding of each variable is only in scope in the body, @bold{not}
in the right-hand-sides of any of the @racket[let].
@item{An extended @racket[+] that accepts any number of arguments.}

For example, @racketblock[(let ((x 1) (y x)) 0)] is a syntax error
because the occurrence of @racket[x] is not bound.
@item{An extended @racket[let] that can bind multiple variables at once.}

The following file have already been updated for you:
@item{Back-referencing @racket[let*] that can bind multiple variables at once.}

@itemlist[
@item{@tt{ast.rkt}}
@item{@tt{parse.rkt}}
]

You will need to modify
@itemlist[
@item{@tt{compile.rkt}}
@item{@tt{interp.rkt}}
]
to correctly implement the generalized form of @racket[let].

@section[#:tag-prefix "a4-" #:style 'unnumbered]{Back-Referencing Let}
@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{From Dupe+ to Fraud+}

Similar to @racket[let] there is also @racket[let*] that also binds any number
of expressions. The difference is that previous bindings are available to
subsequent bindings. For example,
Implement the @racket[abs], unary @racket[-], and @racket[not] operations and
the @racket[cond] and @racket[case] forms from
@seclink["Assignment 3"]{Assignment 3} by modifying @tt{interp.rkt},
@tt{interp-prim.rkt}, @tt{compile.rkt}, and @tt{compile-ops.rkt}. You can
start from your previous code, but you will need to update it to work for the
structures provided. What's essentially left for you to do is to make sure to
correctly signal an error (@racket['err]) when these constructs are
applied to the wrong type of argument.

@racketblock[
(let* ((x 1) (y 2) (z (add1 y)))
_e)
]
While you're at it, implement the predicates @racket[integer?] and
@racket[boolean?] for checking the type of an argument, modeled by the
@racket[char?] predicate that was covered in the lectures.

binds @racket[x] to 1, @racket[y] to 2, and @racket[z] to 3 in
the scope of @racket[_e].

The syntax of a @racket[let*] expression allows any number of binders
to occur, so @racket[(let* () _e)] is valid syntax and is equivalent to
@racket[_e].
@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{From Binary to Variadic Addition}

Unlike @racket[let], @racketblock[(let* ((x 1) (y x)) 0)] is @emph{not} a syntax
error.
In Fraud, we implemented a binary operation for addition. However, Racket
supports an arbitrary number of arguments for @racket[+]. Your job is to extend
the interpreter and compiler to behave similarly.

The following file have already been updated for you:

@itemlist[
@item{@tt{ast.rkt}}
@item{@tt{parse.rkt}}
]
@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Generalizing Let}

You will need to modify
@itemlist[
@item{@tt{compile.rkt}}
@item{@tt{interp.rkt}}
The Fraud language has a @tt{let} form that binds a single variable in the
scope of some expression. This is a restriction of the more general form of
@racket[let] that binds any number of expressions. So, for example,

@racketblock[
(let ((x 1) (y 2) (z 3))
_e)
]
to correctly implement the generalized form of @racket[let*].

HINT: what would a lazy compiler writer do?
simultaneously binds @racket[x], @racket[y], and @racket[z] in the scope of
@racket[_e].

@section[#:tag-prefix "a4-" #:style 'unnumbered]{Testing}
The syntax of a @racket[let] expression allows any number of binders to occur,
so @racket[(let () _e)] is valid syntax and is equivalent to @racket[_e].

You can test your code in several ways:
The binding of each variable is only in-scope within the body, @bold{not} in
the right-hand sides of any of the @racket[let]. So, for example,
@racketblock[(let ((x 1) (y x)) 0)] is a syntax error because the occurrence of
@racket[x] is not bound.

@itemlist[

@item{Using the command line @tt{raco test .} from
the directory containing the repository to test everything.}
@subsection[#:tag-prefix "a4-" #:style 'unnumbered]{Back-Referencing Let}

Similar to @racket[let], there is also @racket[let*] that can also bind any
number of expressions. The difference is that previous bindings are available
in the right-hand sides of subsequent bindings. For example,

@item{Using the command line @tt{raco test <file>} to
test only @tt{<file>}.}
@racketblock[
(let* ((x 1) (y 2) (z (add1 y)))
_e)
]

Note that only a small number of tests are given to you, so you should
write additional test cases.
binds @racket[x] to 1, @racket[y] to 2, and @racket[z] to 3 in
the scope of @racket[_e].

@section[#:tag-prefix "a4-" #:style 'unnumbered]{Submitting}
The syntax of a @racket[let*] expression allows any number of binders to occur,
so @racket[(let* () _e)] is valid syntax and is equivalent to @racket[_e].

Submit a zip file containing your work to Gradescope. Use @tt{make
submit.zip} from within the @tt{fraud-plus} directory to create a zip
file with the proper structure.
Unlike @racket[let], @racketblock[(let* ((x 1) (y x)) 0)] is @emph{not} a
syntax error. However, bindings are only available forward, so
@racketblock[(let* ((x y) (y 1)) 0)] @emph{is} a syntax error.

We will only use the @tt{compile.rkt}, @tt{interp.rkt}, and
@tt{interp-prim.rkt} files for grading, so make sure all your work is
contained there! Note the lack of @tt{ast.rkt}, @tt{parse.rkt}, etc. -
part of assignment 3 was learning to design your own structures, part
of assignment 4 is learning to work within the constraints of an
existing design!
HINT: Think about what a lazy compiler writer would do.
5 changes: 2 additions & 3 deletions www/notes/extort.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

@table-of-contents[]

@section{Errors}
@section[#:tag "errors"]{Errors}

We have added multiple, disjoint types, but mostly swept issues of
errors under the rug by considering type mismatches as meaningless.
Expand Down Expand Up @@ -94,7 +94,7 @@ defined as @racket['err]:
['= (rewrite '=)]
['!= (rewrite '≠)])
(apply centered
(add-between
(add-between
(build-list (- j i)
(λ (n) (begin (judgment-form-cases (list (+ n i)))
(render-judgment-form name))))
Expand Down Expand Up @@ -206,4 +206,3 @@ usual way again:
(check-correctness (Prim1 'add1 (Lit 7)))
(check-correctness (Prim1 'add1 (Lit #f)))
]

0 comments on commit 4af1fb2

Please sign in to comment.