Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion www/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ $(course): scribble zips


langs = abscond blackmail con dupe dodger evildoer extort fraud hustle hoax iniquity iniquity-gc jig knock loot mug mountebank neerdowell outlaw
assigns = hoax-plus
assigns = dupe-plus dupe-plus-plus fraud-plus hoax-plus iniquity-plus knock-plus loot-exceptions

zips:
mkdir -p $(course)/code/
Expand Down
12 changes: 6 additions & 6 deletions www/assignments.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@

@local-table-of-contents[#:style 'immediate-only]

@include-section{assignments/1.scrbl}
@include-section{assignments/2.scrbl}
@include-section{assignments/0.scrbl}
@include-section{assignments/3.scrbl}
@include-section{assignments/4.scrbl}
@include-section{assignments/5.scrbl}
@include-section{assignments/6.scrbl}
@include-section{assignments/7.scrbl}
@include-section{assignments/7-overloading.scrbl}
@include-section{assignments/8.scrbl}
@;include-section{assignments/9.scrbl}
@;include-section{assignments/10.scrbl}
@include-section{assignments/9.scrbl}
@include-section{assignments/10.scrbl}


@;{assignment 8: quote in general, and quasiquote}
@;{assignment 9: standard library, IO}
@;{assignment 9: quote in general, and quasiquote}
@;{assignment 10: standard library, IO}
7 changes: 7 additions & 0 deletions www/assignments/0.scrbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#lang scribble/manual
@(require "../defns.rkt")
@title[#:tag "Assignment 1" #:style 'unnumbered]{Assignment 1}

@bold{Due: @assign-deadline[1]}

Details of this assignment will be released later.
15 changes: 6 additions & 9 deletions www/assignments/1.scrbl
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
#lang scribble/manual
@(require "../defns.rkt")
@title[#:tag "Assignment 1" #:style 'unnumbered]{Assignment 1: Racket primer}
@title[#:tag "Practice 1" #:style 'unnumbered]{Practice 1: Racket primer}

@bold{Due: @assign-deadline[1]}
@bold{Starter code:} @link["code/racket-basics.zip"]{@tt{racket-basics.zip}}

The goal of this assignment is to gain practice programming in Racket.

@bold{This is a collaborative assignment.} You may work with anyone
you'd like on this assignment, but each person must submit their
@tt{submit.zip} file on Gradescope.

You are given a @tt{racket-basics.zip} file (in ELMS, linked in the
description for Assignment 1) that contains a README, a Makefile, and
a number of Racket modules. In each module there are several function
Use the starter code in
@link["code/racket-basics.zip"]{@tt{racket-basics.zip}}, which contains
a README, a Makefile, and a number of Racket modules. In each module
there are several function
``stubs,'' i.e. incomplete function definitions with type signatures,
descriptions, and a small set of tests. Each function has a bogus
(but type correct) body marked with a ``TODO'' comment. Your job is
Expand Down
265 changes: 262 additions & 3 deletions www/assignments/10.scrbl
Original file line number Diff line number Diff line change
@@ -1,9 +1,268 @@
#lang scribble/manual
@(require "../defns.rkt")
@title[#:tag "Assignment 10" #:style 'unnumbered]{Assignment 10: Patterns}
@(require "../notes/ev.rkt"
"../notes/utils.rkt")
@(require (for-label (except-in racket ...)))

@(require (for-label a86 (except-in racket ...)))
@title[#:tag "Assignment 10" #:style 'unnumbered]{Assignment 10: Exceptions}

@bold{Due: @assign-deadline[10]}

Details of this assignment will be released later in the semester.
@bold{Starter code:} @link["code/loot-exceptions.zip"]{@tt{loot-exceptions.zip}}

@(ev '(require loot-exceptions))

The goal of this assignment is to add an exception handling mechanism
to the Loot compiler.

An exception handler consists of a predicate and a function. When a
value is raised to a handler, the predicate is applied and if it
produces a true value, the raised value is handled by applying the
function to it. If the predicate returns @racket[#f], the value is
raised to the next exception handler. An error is signalled if a
raised value is never handled by an exception handler.

Use the starter code in
@link["code/loot-exceptions.zip"]{@tt{loot-exceptions.zip}}, which is
like Loot, but the parser, AST, and interpreter have been extended to
include these new features. You have to extend the compiler to match
the specification of the interpreter.

The key features that need to be added are:

@itemlist[

@item{@racket[(raise _e)] evaluates @racket[_e] and then raises the
value to the most recently installed exception handler, thereby
abandoning whatever computation surrounds the @racket[(raise _e)]
expression up to the next exception handler. If there is no exception
handler installed, an error is signalled.}

@item{@racket[(with-handlers ([_e1 _e2]) _e)] evaluates
@racket[_e1], then @racket[_e2]. The values of @racket[_e1] and
@racket[_e2] are installed as the current exception handler predicate
and function, respectively, while @racket[_e] is evaluated.

Should @racket[_e] produce a value @racket[_v], the exception handler
is removed and the @racket[with-handlers] expression evaluates to
@racket[_v]. But if in evaluating @racket[_e], a value is raised that
reaches this exception handler, the predicate is applied. If the
predicate returns a true value, the result of the
@racket[with-handlers] expression is computed by applying the handler
function to the raised value. If the predicate returns false, the
value continues being raised, thereby abandoning whatever computation
surrounds the @racket[with-handlers] expression up to the next
exception handler.}

]

@section[#:tag-prefix "a10-" #:style 'unnumbered]{Examples}

@ex[
(interp (parse '(raise 1)))
]

This signals an error because there is no exception handler installed
that handles the raised value @racket[1].

@ex[
(interp
(parse
'(with-handlers ([(lambda (x) #t) (lambda (x) 0)])
1)))
]

This evaluates to @racket[1] because even though an exception handler
is installed, the body of the @racket[with-handlers] expression never
raises.

@ex[
(interp
(parse
'(with-handlers ([(lambda (x) #t) (lambda (x) 0)])
(raise 1))))
]

This evaluates to @racket[0] because the predicate returns
@racket[#t] when applied to @racket[1], so the result of the
@racket[with-handlers] expression is computed by applying the handler
function to @racket[1].

@ex[
(interp
(parse
'(with-handlers ([(lambda (x) #f) (lambda (x) 0)])
(raise 1))))
]

This signals an error because although there is an exception handler
installed when @racket[1] is raised, the predicate returns
@racket[#f], so the value continues to be raised to the enclosing
exception handler, but there is no such handler.

@ex[
(interp
(parse
'(with-handlers ([(lambda (x) #t) (lambda (x) 2)])
(with-handlers ([(lambda (x) #f) (lambda (x) 0)])
(raise 1)))))
]

This evaluates to @racket[2] because @racket[1] is raised to the most
recent handler, which does not handle it, and then to the next handler,
which does handle it.

Note that when a value is raised, it abandons the computation at the
point of the raise.

@ex[
(interp
(parse
'(with-handlers ([(lambda (x) #t) (lambda (x) x)])
(+ (raise 1) (add1 #f)))))
]

Here the addition computation is abandoned when @racket[1] is raised.
Consequently, the expression @racket[(add1 #f)] is never evaluated and
the whole expression evaluates to @racket[1].

Since the handler predicate and function are arbitrary functions, they
too can raise exceptions, which will be handled by the surrounding
exception handlers.

@ex[
(interp
(parse
'(with-handlers ([(lambda (x) (if (zero? x) #t (raise 0)))
(lambda (x) x)])
(raise 1))))
]

This signals an error because in applying the predicate to
@racket[1], the value @racket[0] is raised, and there is no enclosing
handler.

It's important to note that the most recently installed handler is a
dynamic property; it is not a lexical property. A @racket[raise]
expression may occur lexically outside of the @racket[with-handlers]
form that ends up handling it.

@ex[
(interp
(parse
'(define (f x) (raise x))
'(with-handlers ([(lambda (x) #t) (lambda (x) x)])
(f 3))))
]

Here, calling @racket[f] triggers the raising of @racket[3], which is
handled by the @racket[with-handlers] expression, producing
@racket[3].

@section[#:tag-prefix "a10-" #:style 'unnumbered]{Differences with Racket's exception system}

There are important differences between Loot exceptions and Racket's
exception system.

In Loot, errors are distinct from exceptions. For example,
@racket[(add1 #f)] signals an error. It does not raise an exception
and therefore it cannot be handled with an exception handler:

@ex[
(interp
(parse
'(with-handlers ([(lambda (x) #t) (lambda (x) 1)])
(add1 #f))))
]

Racket, on the other hand, uses its exception mechanism to signal
errors:

@ex[
(with-handlers ([(lambda (x) #t) (lambda (x) 1)])
(add1 #f))
]

Consequently, Racket evaluates this expression to @racket[1] for this
example.

This simplifies things in Loot because the only way something can be
raised is an explicit @racket[raise] expression and anything that used
to be an error continues to be an error.

Since there are subtle differences between Loot exceptions and Racket
exceptions, use the interpreter for guidance on what a particular
example should do.

Another difference is syntactic: Racket allows each
@racket[with-handlers] form to have any number of predicate and
function clauses, but for our purposes, each @racket[with-handlers]
has exactly one predicate and function.

@section[#:tag-prefix "a10-" #:style 'unnumbered]{Implementation hints}

An implementation of exception handling for Loot can be fairly
succinct, but tricky.

The basic idea is that a handler is installed by
@racket[with-handlers] by pushing some information on the stack before
executing the code for the body expression. This information will
include the predicate value and function value for the handler.

If execution of the body makes it through to the end, a value is being
returned normally, and the handler information can be popped off the
stack. However, if at some point during execution of the body there is
a raise, then the compiler needs to start the process of handling the
raised value, applying the predicate, and so on. A basic problem is
that there may be an arbitrary amount of stuff pushed on to the stack
between the handler information and the point where the raise occurs.

For example:

@ex[
(define (f x)
(if (zero? x)
(raise x)
(+ x (f (sub1 x)))))

(with-handlers ([(lambda (x) #t) (lambda (x) 1)])
(f 100))
]

The handler is pushed on the stack. As the recursion unfolds, return
pointers, arguments, and intermediate results will be pushed on the
stack. This continues until reaching the base case, at which point the
raise occurs.

Everything on the stack up to the handler should be discarded because
the raise discards the computation that has built up to this point:
all those pending function calls will never be returned to. Instead,
control needs to transfer back to the @racket[with-handlers]
expression and execute the code that follows it.

A simple approach is to designate a register to hold a pointer to the
current handler on the stack. When executing a @racket[raise], the
stack can be popped back to the handler, giving access to the
predicate, the function, and the return label used to jump back to the
@racket[with-handlers] expression.

This works when there is exactly one exception handler, but nested
handlers require one more piece of information: a pointer to the parent
handler.

So each handler can be represented by four things pushed on the stack:

@itemlist[
@item{a predicate,}
@item{a function,}
@item{a return label, and}
@item{a pointer to the parent handler on the stack, if there is one.}
]

A designated register can then hold a pointer to the current handler.

@section[#:tag-prefix "a10-" #:style 'unnumbered]{Submitting}

Submit a zip file containing your work to Gradescope. Use
@tt{make submit.zip} from within the @tt{loot-exceptions} directory to
create a zip file with the proper structure.
15 changes: 6 additions & 9 deletions www/assignments/2.scrbl
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
#lang scribble/manual
@(require "../defns.rkt")
@title[#:tag "Assignment 2" #:style 'unnumbered]{Assignment 2: Assembly primer}
@title[#:tag "Practice 2" #:style 'unnumbered]{Practice 2: Assembly primer}

@bold{Due: @assign-deadline[2]}
@bold{Starter code:} @link["code/a86-basics.zip"]{@tt{a86-basics.zip}}

The goal of this assignment is to gain practice programming in a86.

@bold{This is a collaborative assignment.} You may work with anyone
you'd like on this assignment, but each person must submit their
@tt{submit.zip} file on Gradescope.

You are given a @tt{a86-basics.zip} file (in ELMS, linked in the
description for Assignment 2), that contains a README, a Makefile, and
a number of Racket modules. In each module there are several
Use the starter code in
@link["code/a86-basics.zip"]{@tt{a86-basics.zip}}, which contains a
README, a Makefile, and a number of Racket modules. In each module
there are several
``stubs,'' i.e. incomplete definitions with type signatures,
descriptions, and a small set of tests. Each definition has a bogus
(but type correct) body marked with a ``TODO'' comment. Your job is
Expand Down
10 changes: 6 additions & 4 deletions www/assignments/3.scrbl
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#lang scribble/manual
@(require "../defns.rkt")
@title[#:tag "Assignment 3" #:style 'unnumbered]{Assignment 3: Primitives, conditionals}
@title[#:tag "Assignment 2" #:style 'unnumbered]{Assignment 2: Primitives, conditionals}

@(require (for-label a86/ast (except-in racket ...)))

@bold{Due: @assign-deadline[3]}
@bold{Due: @assign-deadline[2]}

@bold{Starter code:} @link["code/dupe-plus.zip"]{@tt{dupe-plus.zip}}

The goal of this assignment is to extend the language developed in
@secref{Dupe} with some simple unary numeric and boolean operations
Expand Down Expand Up @@ -58,8 +60,8 @@ expression @racket[_e-an]'s value is the value of the @racket[cond].
@section[#:tag-prefix "a3-" #:style 'unnumbered]{Implementing Dupe+}

You must extend the interpreter and compiler to implement Dupe+. (The
parser for Dupe+ is given to you.) You are given a file
@tt{dupe-plus.zip} on ELMS with a starter compiler based on the
parser for Dupe+ is given to you.) Use the starter code in
@link["code/dupe-plus.zip"]{@tt{dupe-plus.zip}}, which is based on the
@secref{Dupe} language we studied in class.

You may use any a86 instructions you'd like, however it is possible to
Expand Down
Loading
Loading