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
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ env:
- PANDOC=~/.pandoc
- PANDOC_DEB="https://github.com/jgm/pandoc/releases/download/2.7.3/pandoc-2.7.3-1-amd64.deb"
matrix:
- RACKET_VERSION=7.3
- RACKET_VERSION=7.4
cache:
directories:
- $PANDOC
Expand Down Expand Up @@ -46,4 +46,4 @@ deploy:
script: rsync -rvzp $TRAVIS_BUILD_DIR/www/cmsc430 dvanhorn@junkfood.cs.umd.edu:$WWW_DIR/fall2019
on:
branch: master
condition: "$RACKET_VERSION='7.3'"

96 changes: 82 additions & 14 deletions www/notes/con.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,17 @@ Let's consider some examples:

@itemlist[

@item{...}
@item{@racket['(if (zero? 0) (add1 2) 4)] means @racket[3].}
@item{@racket['(if (zero? 1) (add1 2) 4)] means @racket[4].}
@item{@racket['(if (zero? (if (zero? (sub1 1)) 1 0)) (add1 2) 4)] means @racket[4].}
@item{@racket['(if (zero? (add1 0)) (add1 2) (if (zero? (sub1 1)) 1 0))] means @racket[1].}

]


The semantics...
The semantics is inductively defined as before. There are @emph{two}
new rules added for handling if-expressions: one for when the test
expression means @racket[0] and one for when it doesn't.

@(define ((rewrite s) lws)
(define lhs (list-ref lws 2))
Expand Down Expand Up @@ -135,33 +140,96 @@ according to @render-term[C 𝑪𝒓]:
@(show-judgment 𝑪 0 1)
}

The interpreter ...
The interpreter has an added case for if-expressions, which
recursively evaluates the test expression and branches based on its
value.

@codeblock-include["con/interp.rkt"]

We can confirm the interpreter computes the right result for the
examples given earlier:

@ex[
'...
(interp '(if (zero? 0) (add1 2) 4))
(interp '(if (zero? 1) (add1 2) 4))
(interp '(if (zero? (if (zero? (sub1 1)) 1 0)) (add1 2) 4))
(interp '(if (zero? (add1 0)) (add1 2) (if (zero? (sub1 1)) 1 0)))
]

Correctness...
@;{
@bold{Interpreter Correctness}: @emph{For all Con expressions
@racket[e] and integers @racket[i], if (@racket[e],@racket[i]) in
@render-term[C 𝑪], then @racket[(interp e)] equals
@racket[i].}
}
The argument for the correctness of the interpreter follows the same
structure as for @seclink["Blackmail"]{Blackmail}, but with an added case for
if-expressions.

@section{An Example of Con compilation}

Suppose we want to compile @racket['(if (zero? 8) 2 3)]...

We already know how to compile the @racket['8], @racket['2], and
@racket['3] part.
We already know how to compile the @racket[8], @racket[2], and
@racket[3] part.

What needs to happen?

@itemlist[
@item{Execute the code for @racket[8] leaving the result in @racket['rax],}
@item{check whether @racket['rax] holds zero,}
@item{if it does, execute the code for @racket[2],}
@item{if it doesn't, execute the code for @racket[3].}
]

We can determine whether @racket[8] evaluates to @racket[0] using a
comparison instruction: @racket['(cmp rax 0)]. To do the conditional
execution, we will need to jump to different parts of the code to
either execute the code for @racket[2] or @racket[3]. There are
several ways we could accomplish this, but we take the following
approach: immediately after the comparison, do a conditional jump to
the code for the else branch when non-zero. Should the jump not occur,
the next instructions will carry out the evaluation of the then
branch, then (unconditionally) jump over the else branch code.

To accomplish this, we will need two new labels: one for the else
branch code and one for the end of the else branch code. The
@racket[gensym] function can be used to generate symbols that have not
appeared before.

In total, the code for this example would look like:

@racketblock[
'((mov rax 8)
(cmp rax 0)
(jne if-else-begin)
(mov rax 2)
(jmp if-else-end)
if-else-begin
(mov rax 3)
if-else-end)
]

Notice that the @racket['(mov rax 8)], @racket['(mov rax 3)] and
@racket['(mov rax 2)] parts are just the instructions generated by
compiling @racket[8], @racket[2] and @racket[3]. Generalizing from
this, we arrive at the following code for the compiler:

@racketblock[
(let ((c0 (compile-e e0))
(c1 (compile-e e1))
(c2 (compile-e e2))
(l0 (gensym "if-else-begin"))
(l1 (gensym "if-else-end")))
'(,@c0
(cmp rax 0)
(jne ,l0)
,@c1
(jmp ,l1)
,l0
,@c2
,l1))
]


@ex[
(asm-display (compile '(if (zero? 8) 2 3)))
]

What needs to happen? ...

@codeblock-include["con/asm/ast.rkt"]

Expand Down
35 changes: 11 additions & 24 deletions www/notes/con/compile.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -22,27 +22,14 @@
[`(if (zero? ,e0) ,e1 ,e2)
(let ((c0 (compile-e e0))
(c1 (compile-e e1))
(c2 (compile-e e2)))
(match (gen-if-labels)
[(list if-f if-x)
`(,@c0
(cmp rax 0)
(jne ,if-f)
,@c1
(jmp ,if-x)
,if-f
,@c2
,if-x)]))]))

;; -> [List Label Label]
;; Guaranteed to be unique on each call
(define gen-if-labels
(let ((i 0))
(λ ()
(set! i (add1 i))
(list (lab "f" i)
(lab "x" i)))))

;; String Integer -> Symbol
(define (lab s i)
(string->symbol (string-append "if_" s "_" (number->string i))))
(c2 (compile-e e2))
(l0 (gensym "if"))
(l1 (gensym "if")))
`(,@c0
(cmp rax 0)
(jne ,l0)
,@c1
(jmp ,l1)
,l0
,@c2
,l1))]))
20 changes: 10 additions & 10 deletions www/schedule.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,26 @@
(list @wk{9/3}
@seclink["Assignment 1"]{A1}
@elem{@secref["OCaml to Racket"] (cont.)}
@secref["Abscond"])
@itemlist[@item{@secref["Abscond"]} @item{@secref["Blackmail"]}])

(list @wk{9/10}
"A2" @;seclink["Assignment 2"]{A2}
@secref["Blackmail"]
@secref["Con"])
@seclink["Assignment 2"]{A2}
@secref["Con"]
@secref["Dupe"])

(list @wk{9/17}
"A3" @;seclink["Assignment 3"]{A3}
@secref["Dupe"]
@secref["Extort"])
"A3" @;seclink["Assignment 3"]{A3}
@secref["Extort"]
@secref["Fraud"])

(list @wk{9/24}
"A4" @;seclink["Assignment 4"]{A4}
@secref["Fraud"]
@secref["Grift"])
@secref["Grift"]
@secref["Hustle"])

(list @wk{10/1}
"A5" @;seclink["Assignment 5"]{A5}
@secref["Hustle"]
@elem{TBD}
'cont)

(list @wk{10/8}
Expand Down