1616@(define codeblock-include (make-codeblock-include #'h ))
1717
1818@(for-each (λ (f) (ev `(require (file ,(path->string (build-path notes "con " f))))))
19- '("interp.rkt " "compile.rkt " "asm/interp.rkt " "asm/printer.rkt " ))
19+ '("interp.rkt " "compile.rkt " "asm/interp.rkt " "asm/printer.rkt " " random.rkt " ))
2020
2121
2222@title[#:tag "Con " ]{Con: branching with conditionals}
2323
24+ @emph{When you come to a fork in the road, take it.}
25+
26+ @table-of-contents[]
27+
28+ @section{Conditional execution}
29+
2430Let's now consider add a notion of @bold{conditionals} to our target
2531language.
2632
2733We'll call it @bold{Con}.
2834
29- We will use the following syntax.. .
35+ We will use the following syntax: @racket[( if (zero? _e0) _e1 _e2)] .
3036
3137Together this leads to the following grammar for Con:
3238
@@ -46,9 +52,9 @@ the new form is an if-expression.
4652
4753@itemlist[
4854
49- @item{the meaning of a if expression @tt{ (if (zero? e0) e1 e2)} is the
50- meaning of @math{e1} if the meaning of @tt{e1} if the meaning of
51- @tt{e0} is 0 and is the meaning of @math{e2} otherwise.}
55+ @item{the meaning of a if expression @racket[ (if (zero? _e0) _e1 _e2)] is the
56+ meaning of @racket[_e1] if the meaning of @racket[_e1] if the meaning of
57+ @racket[_e0] is 0 and is the meaning of @racket[_e2] otherwise.}
5258
5359]
5460
@@ -204,6 +210,9 @@ In total, the code for this example would look like:
204210 if-else-end)
205211]
206212
213+
214+ @section{A Compiler for Con}
215+
207216Notice that the @racket['(mov rax 8 )], @racket['(mov rax 3 )] and
208217@racket['(mov rax 2 )] parts are just the instructions generated by
209218compiling @racket[8 ], @racket[2 ] and @racket[3 ]. Generalizing from
@@ -213,9 +222,9 @@ this, we arrive at the following code for the compiler:
213222(let ((c0 (compile-e e0))
214223 (c1 (compile-e e1))
215224 (c2 (compile-e e2))
216- (l0 (gensym "if-else-begin " ))
217- (l1 (gensym "if-else-end " )))
218- ' (,@c0
225+ (l0 (gensym "if " ))
226+ (l1 (gensym "if " )))
227+ ` (,@c0
219228 (cmp rax 0 )
220229 (jne ,l0)
221230 ,@c1
@@ -226,22 +235,65 @@ this, we arrive at the following code for the compiler:
226235]
227236
228237
229- @ex[
230- (asm-display (compile '(if (zero? 8 ) 2 3 )))
231- ]
232-
238+ This will require extending our representation of x86 instructions; in
239+ particular, we add @racket['jmp ], @racket['jne ], and @racket['cmp ]
240+ instructions:
233241
234242@codeblock-include["con/asm/ast.rkt " ]
235243
236244We omit the printer code, which is mundane. See
237245@link["con/asm/printer.rkt " ]{@tt{asm/printer.rkt}} for details.
238246
247+ The complete compiler code is:
248+
239249@codeblock-include["con/compile.rkt " ]
240250
251+ Let's take a look at a few examples:
252+ @ex[
253+ (asm-display (compile '(if (zero? 8 ) 2 3 )))
254+ (asm-display (compile '(if (zero? 0 ) 1 2 )))
255+ (asm-display (compile '(if (zero? 0 ) (if (zero? 0 ) 8 9 ) 2 )))
256+ (asm-display (compile '(if (zero? (if (zero? 2 ) 1 0 )) 4 5 )))
257+ ]
241258
259+ And confirm they are running as expected:
242260@ex[
261+ (asm-interp (compile '(if (zero? 8 ) 2 3 )))
243262(asm-interp (compile '(if (zero? 0 ) 1 2 )))
244- (asm-interp (compile '(if (zero? 3 ) 1 2 )))
245263(asm-interp (compile '(if (zero? 0 ) (if (zero? 0 ) 8 9 ) 2 )))
246264(asm-interp (compile '(if (zero? (if (zero? 2 ) 1 0 )) 4 5 )))
247265]
266+
267+
268+ @section[#:tag-prefix "con " ]{Correctness and random testing}
269+
270+ The statement of correctness follows the same outline as before:
271+
272+ @bold{Compiler Correctness}: @emph{For all expressions @racket[e] and
273+ integers @racket[i], if (@racket[e],@racket[i]) in @render-term[C 𝑪],
274+ then @racket[(asm-interp (compile e))] equals @racket[i].}
275+
276+ Again, we formulate correctness as a property that can be tested:
277+
278+ @ex[
279+ (define (check-compiler e)
280+ (check-equal? (asm-interp (compile e))
281+ (interp e)
282+ e))]
283+
284+ Generating random Con programs is essentially the same as Blackmail
285+ programs, and are provided in a @link["con/random.rkt " ]{random.rkt}
286+ module.
287+
288+ @ex[
289+ (eval:alts (require "random.rkt " ) (void))
290+ (random-expr)
291+ (random-expr)
292+ (random-expr)
293+ (random-expr)
294+ (for ([i (in-range 10 )])
295+ (check-compiler (random-expr)))
296+ ]
297+
298+
299+
0 commit comments