From 6038163fa696d2207a6a8b9cc479b83cf80a60de Mon Sep 17 00:00:00 2001 From: David Van Horn Date: Tue, 7 Oct 2025 22:09:39 -0400 Subject: [PATCH] Update assign 5 with working examples. --- .github/workflows/push.yml | 6 ++- www/assignments/5.scrbl | 91 +++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 559a8673..43a0b11e 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -27,12 +27,14 @@ jobs: distribution: 'full' variant: 'CS' version: '8.18' - - name: Install a86 and langs + - name: Install a86, langs, and assignments run: | git clone https://github.com/cmsc430/a86.git - git clone https://github.com/cmsc430/langs.git + git clone https://github.com/cmsc430/langs.git + git clone https://github.com/cmsc430/assignments.git raco pkg install --auto a86/ raco pkg install --auto langs/ + raco pkg install --auto assignments/ - name: Build and test run: | export LINK_DIR=/usr/lib/x86_64-linux-gnu diff --git a/www/assignments/5.scrbl b/www/assignments/5.scrbl index 095265fe..9042c47e 100644 --- a/www/assignments/5.scrbl +++ b/www/assignments/5.scrbl @@ -1,9 +1,13 @@ #lang scribble/manual -@(require "../defns.rkt") +@(require "../defns.rkt" + "../notes/ev.rkt") + @title[#:tag "Assignment 5" #:style 'unnumbered]{Assignment 5: Let There Be (Many) Variables} @(require (for-label a86/ast (except-in racket ...))) +@(ev '(require fraud-plus)) + @bold{Due: @assign-deadline[5]} The goal of this assignment is to extend a compiler with binding forms @@ -77,10 +81,49 @@ 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. +The given code uses the following abstract representation of +@racket[let] expressions: + +@#reader scribble/comment-reader +(racketblock +;; type Expr = ... +;; | (Let [Listof Id] [Listof Expr] Expr) +(struct Let (xs es e) #:prefab) +) + +Notice that all of the variable bindings and their RHS expressions +have been split into two (equal-length) lists. The third component +is the body expression. + +The provided parser has been revised to parse these @racket[let] +expressions (as well as the new operation forms): + +@ex[ +(parse '(let ((x 1)) x)) +(parse '(let () 1)) +(parse '(let ((x 1) (y 2)) (+ x y))) +] + +Recall that there are two parsers: @racket[parse] parses any +expression form, while @racket[parse-closed] only parses closed +expressions. The interpreter and compiler may assume that the program +is closed (i.e. it is parsed with @racket[parse-closed]). + +@ex[ +(parse 'x) +(eval:error (parse-closed 'x)) +(eval:error (parse-closed '(let ((x 1) (y x)) x)))] + + The provided interpreter and compiler work when the @racket[let] expression happens to bind a single variable, but you must revise the code to work for any number of bindings. +@ex[ +(interp (parse '(let ((x 1)) (add1 x)))) +(eval:error (interp (parse '(let ((x 1) (y 2)) (+ x y))))) +(exec (parse '(let ((x 1)) (add1 x)))) +(eval:error (exec (parse '(let ((x 1) (y 2)) (+ x y)))))] @subsection[#:tag-prefix "a5-" #:style 'unnumbered]{Back-Referencing Let} @@ -103,9 +146,53 @@ 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. +The given code uses the following abstract representation of +@racket[let*] expressions: + +@#reader scribble/comment-reader +(racketblock +;; type Expr = ... +;; | (Let* [Listof Id] [Listof Expr] Expr) +(struct Let* (xs es e) #:prefab) +) + +The provided parser works for @racket[let*] +expressions: + +@ex[ +(parse '(let* ((x 1)) x)) +(parse '(let* () 1)) +(parse '(let* ((x 1) (y 2)) (+ x y))) +] + +And the @racket[parse-closed] parser works appropriately, too: + +@ex[ +(parse-closed '(let* ((x 1) (y 2) (z (add1 y))) z))] + + The provided interpreter and compiler work when the @racket[let*] expression happens to bind a single variable, but you must revise the -code to work for any number of bindings. +code to work for any number of bindings: + +@ex[ +(interp (parse '(let* ((x 1)) (add1 x)))) +(eval:error (interp (parse '(let* ((x 1) (y 2)) (+ x y))))) +(exec (parse '(let* ((x 1)) (add1 x)))) +(eval:error (exec (parse '(let* ((x 1) (y 2)) (+ x y)))))] + +Note that when there is only a single binding, @racket[let] and +@racket[let*] are equivalent. + +@subsection[#:tag-prefix "a5-" #:style 'unnumbered]{Testing} + +A small number of test cases have been provided in +@tt{test/test-runner.rkt}. There is function called @racket[test] +that contains I/O-free test cases and another called @racket[test/io] +that contains I/O tests. To run these tests, @tt{raco test +test/interp.rkt} will test the interpreter and @tt{raco test +test/compile.rkt} will test the compiler. You are encouraged to add +your own tests. @section[#:tag-prefix "a5-" #:style 'unnumbered]{Submitting}