diff --git a/www/assignments/6.scrbl b/www/assignments/6.scrbl index aace6dc9..3d092889 100644 --- a/www/assignments/6.scrbl +++ b/www/assignments/6.scrbl @@ -1,9 +1,98 @@ #lang scribble/manual -@(require "../defns.rkt") -@title[#:tag "Assignment 6" #:style 'unnumbered]{Assignment 6: List primitives and n-ary primitives} +@(require "../defns.rkt" + "../notes/ev.rkt") +@title[#:tag "Assignment 6" #:style 'unnumbered]{Assignment 6: List and vector primitives} @(require (for-label a86 (except-in racket ...))) +@(require racket/port) + @bold{Due: @assign-deadline[6]} -Details of this assignment will be released later in the semester. +@;{ All this to silence some Makefile output on Linux -- should probably be taken care of at the Makefile level } +@(ev '(begin (define p (current-output-port)) + (current-output-port (open-output-string)) + (require hoax-plus) + (current-output-port p))) + +The goal of this assignment is to gain proficiency with our +representation of memory-allocated values by implementing a number of +list and vector primitives. + +@section[#:tag-prefix "a6-" #:style 'unnumbered]{Overview} + +For this assignment, you are given a @tt{hoax-plus.zip} file on ELMS +with a starter compiler similar to the @seclink["Hoax"]{Hoax} +language we studied in class. + + +@section[#:tag-prefix "a6-" #:style 'unnumbered]{Hoax+} + +The Hoax+ language extends the Hoax language we studied in class with four +new unary primitives: + +@itemlist[ +@item{@racket[length]: given a list, computes its length.} +@item{@racket[reverse]: given a list, computes a list with elements in the reverse order of the given list.} +@item{@racket[list->vector]: given a list, computes a vector with elements in the order of the given list.} +@item{@racket[vector->list]: given a vector, computes a list with elements in the order of the given vector.} +] + +Unlike past assignments, you do not need to bring forward in any +features from earlier assignments. + +@section[#:tag-prefix "a6-" #:style 'unnumbered]{List and vector primitves} + + +The new primitives have been added to the parser and the interpreter. +The behavior of compiled primitives should be consistent with the +interpreter: + +@ex[ +(interp (parse '(length '()))) +(interp (parse '(length (cons 1 (cons 2 '()))))) +(interp (parse '(length #f))) +(interp (parse '(reverse '()))) +(interp (parse '(reverse (cons 1 (cons 2 '()))))) +(interp (parse '(reverse #f))) +(interp (parse '(list->vector '()))) +(interp (parse '(list->vector (cons 1 (cons 2 '()))))) +(interp (parse '(list->vector #f))) +(interp (parse '(vector->list (make-vector 0 #t)))) +(interp (parse '(vector->list (make-vector 2 #t)))) +(interp (parse '(vector->list #f))) +] + +The interpreter is consistent with Racket's own behavior, so if you're +unsure about what your compiler should do, you can look to Racket (or +the interpreter) for guidance: + +@ex[ +(length '()) +(length (cons 1 (cons 2 '()))) +(eval:error (length #f)) +(reverse '()) +(reverse (cons 1 (cons 2 '()))) +(eval:error (reverse #f)) +(list->vector '()) +(list->vector (cons 1 (cons 2 '()))) +(eval:error (list->vector #f)) +(vector->list (make-vector 0 #t)) +(vector->list (make-vector 2 #t)) +(eval:error (vector->list #f)) +] + +@subsection[#:tag-prefix "a6-" #: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 "a6-" #:style 'unnumbered]{Submitting} + +To submit, use @tt{make} from within the @tt{hoax-plus} directory to +create a zip file containing your work and submit it to Gradescope. diff --git a/www/defns.rkt b/www/defns.rkt index 2d675351..c8786986 100644 --- a/www/defns.rkt +++ b/www/defns.rkt @@ -59,8 +59,8 @@ "Thursday, September 25, 11:59PM" "Thursday, October 2, 11:59PM" "Thursday, October 23, 11:59PM" - "Thursday, October 30, 11:59PM" - "Thursday, November 6, 11:59PM" + "Tuesday, November 4, 11:59PM" + "Tuesday, November 11, 11:59PM" "Thursday, November 20, 11:59PM" "Thursday, December 4, 11:59PM") (sub1 i))) diff --git a/www/notes/diagrams.rkt b/www/notes/diagrams.rkt index c4928cdb..a8b37ae1 100644 --- a/www/notes/diagrams.rkt +++ b/www/notes/diagrams.rkt @@ -8,6 +8,17 @@ (define n 40) +(define (make-str-cells s) + (hc-append + (foldl (λ (c p) + (hc-append p + (cc-superimpose (rectangle (/ n 2) n) ((current-code-tt) (string c))))) + (cc-superimpose (rectangle n n) (code #,(string-length s))) + (string->list s)) + (if (even? (string-length s)) + (rectangle 0 n) + (cc-superimpose (rectangle (/ n 2) n) (code 0))))) + (define (make-imm-cell i) (cc-superimpose (code #,i) @@ -17,6 +28,9 @@ (cb-superimpose (rectangle n n) (code cons))) +(define (make-str-cell) + (cb-superimpose (rectangle n n) + (code str))) (define (make-box-cell) (cb-superimpose (rectangle n n) @@ -72,13 +86,16 @@ [`(cons ,_) (make-cons-cell)] [`(box ,_) (make-box-cell)] [`(vect ,_) (make-vect-cell)] + [`(str ,_) (make-str-cell)] + [(? string?) (make-str-cells v)] [_ (make-imm-cell v)])) (define (add-arrows spec cells p) ;(printf "~a~n" spec) (match spec ['() p] - [(cons `(_ ,i) s) + [(cons `(,_ ,(? integer? i)) s) + (add-arrows s cells (fwd-pts-to (list-ref cells (sub1 (- (length cells) (length s)))) @@ -99,17 +116,62 @@ heap))) (define heap/arrows/label - (vc-append - 0 - heap/arrows - (text "heap"))) + (vc-append 10 + (vc-append + 0 + heap/arrows + (text "heap")) + (text "← lower addresses, higher addresses →"))) (define rax/label - (vc-append 0 rax (text "rax"))) + (vc-append 10 (vc-append 0 rax (text "rax")) + (text " "))) (inset - (fwd-pts-to rax (list-ref heap i) (hc-append n rax/label heap/arrows/label)) - (* n 2))])) + (fwd-pts-to rax (list-ref heap i) + (hc-append n rax/label heap/arrows/label)) + 0 (* n 2) 0 0)])) + +#; +(define cons-quiz + (list (make-heap-diagram + '((cons 4) + 3 + '() + 2 + (cons 0) + 1 + (cons 2))) + (make-heap-diagram + '((cons 0) + 1 + (cons 2) + 2 + (cons 4) + 3 + '())) + (make-heap-diagram + '((cons 4) + '() + 3 + (cons 0) + 2 + (cons 2) + 1)) + (make-heap-diagram + '((cons 0) + (cons 2) + 1 + (cons 4) + 2 + '() + 3)) + )) + + + +;(text "← lower addresses, higher addresses →") + #; (make-heap-diagram '((cons 0) diff --git a/www/notes/hoax.scrbl b/www/notes/hoax.scrbl index c65bb4e2..2b2b7961 100644 --- a/www/notes/hoax.scrbl +++ b/www/notes/hoax.scrbl @@ -899,6 +899,18 @@ So, suppose we want to create the string @racket["abc"]: (Pop rbx) (Ret)))) +This creates a string in memory like this: + +@make-heap-diagram['((str 0) "abc")] + + +In this diagram, we use half-sized boxes to indicate that only 4 bytes +are used per codepoint. Also the contents of the array are not +values, but codepoints (shown as the letters the codepoint encodes). +In odd length strings, we write @racket[0] for the padded element, but +in reality there are arbitrary bits at that memory location, which is +fine because they will never be read. + At first glance, this looks remarkably similar to creating a vector, however there are some imporant things to notice: @@ -926,6 +938,18 @@ you are seeing here.} ] +Notice that a string like @racket["fred"] is not represented the same +as a vector of characters @racket[#(#\f #\r #\e #\d)], which uses more +space. Compare: + +@make-heap-diagram['((str 0) "fred")] + +versus: + +@make-heap-diagram['((vect 0) 4 #\f #\r #\e #\d)] + + + Now let's set things up like we did before to be able to interactively write examples in order to arrive at the code for @racket[string-length], @racket[string-ref], and @racket[make-string]: