1515
1616@(define codeblock-include (make-codeblock-include #'h ))
1717
18+
19+ @(ev '(require rackunit))
1820@(for-each (λ (f) (ev `(require (file ,(path->string (build-path notes "con " f))))))
19- '("interp.rkt " "compile.rkt " "asm/interp.rkt " "asm/printer.rkt " ))
21+ '("interp.rkt " "compile.rkt " "asm/interp.rkt " "asm/printer.rkt " " random.rkt " ))
2022
2123
2224@title[#:tag "Con " ]{Con: branching with conditionals}
2325
26+ @emph{When you come to a fork in the road, take it.}
27+
28+ @table-of-contents[]
29+
30+ @section{Conditional execution}
31+
2432Let's now consider add a notion of @bold{conditionals} to our target
2533language.
2634
2735We'll call it @bold{Con}.
2836
29- We will use the following syntax.. .
37+ We will use the following syntax: @racket[( if (zero? _e0) _e1 _e2)] .
3038
3139Together this leads to the following grammar for Con:
3240
@@ -46,9 +54,9 @@ the new form is an if-expression.
4654
4755@itemlist[
4856
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.}
57+ @item{the meaning of a if expression @racket[ (if (zero? _e0) _e1 _e2)] is the
58+ meaning of @racket[_e1] if the meaning of @racket[_e1] if the meaning of
59+ @racket[_e0] is 0 and is the meaning of @racket[_e2] otherwise.}
5260
5361]
5462
@@ -204,6 +212,9 @@ In total, the code for this example would look like:
204212 if-else-end)
205213]
206214
215+
216+ @section{A Compiler for Con}
217+
207218Notice that the @racket['(mov rax 8 )], @racket['(mov rax 3 )] and
208219@racket['(mov rax 2 )] parts are just the instructions generated by
209220compiling @racket[8 ], @racket[2 ] and @racket[3 ]. Generalizing from
@@ -213,9 +224,9 @@ this, we arrive at the following code for the compiler:
213224(let ((c0 (compile-e e0))
214225 (c1 (compile-e e1))
215226 (c2 (compile-e e2))
216- (l0 (gensym "if-else-begin " ))
217- (l1 (gensym "if-else-end " )))
218- ' (,@c0
227+ (l0 (gensym "if " ))
228+ (l1 (gensym "if " )))
229+ ` (,@c0
219230 (cmp rax 0 )
220231 (jne ,l0)
221232 ,@c1
@@ -226,22 +237,65 @@ this, we arrive at the following code for the compiler:
226237]
227238
228239
229- @ex[
230- (asm-display (compile '(if (zero? 8 ) 2 3 )))
231- ]
232-
240+ This will require extending our representation of x86 instructions; in
241+ particular, we add @racket['jmp ], @racket['jne ], and @racket['cmp ]
242+ instructions:
233243
234244@codeblock-include["con/asm/ast.rkt " ]
235245
236246We omit the printer code, which is mundane. See
237247@link["con/asm/printer.rkt " ]{@tt{asm/printer.rkt}} for details.
238248
249+ The complete compiler code is:
250+
239251@codeblock-include["con/compile.rkt " ]
240252
253+ Let's take a look at a few examples:
254+ @ex[
255+ (asm-display (compile '(if (zero? 8 ) 2 3 )))
256+ (asm-display (compile '(if (zero? 0 ) 1 2 )))
257+ (asm-display (compile '(if (zero? 0 ) (if (zero? 0 ) 8 9 ) 2 )))
258+ (asm-display (compile '(if (zero? (if (zero? 2 ) 1 0 )) 4 5 )))
259+ ]
241260
261+ And confirm they are running as expected:
242262@ex[
263+ (asm-interp (compile '(if (zero? 8 ) 2 3 )))
243264(asm-interp (compile '(if (zero? 0 ) 1 2 )))
244- (asm-interp (compile '(if (zero? 3 ) 1 2 )))
245265(asm-interp (compile '(if (zero? 0 ) (if (zero? 0 ) 8 9 ) 2 )))
246266(asm-interp (compile '(if (zero? (if (zero? 2 ) 1 0 )) 4 5 )))
247267]
268+
269+
270+ @section[#:tag-prefix "con " ]{Correctness and random testing}
271+
272+ The statement of correctness follows the same outline as before:
273+
274+ @bold{Compiler Correctness}: @emph{For all expressions @racket[e] and
275+ integers @racket[i], if (@racket[e],@racket[i]) in @render-term[C 𝑪],
276+ then @racket[(asm-interp (compile e))] equals @racket[i].}
277+
278+ Again, we formulate correctness as a property that can be tested:
279+
280+ @ex[
281+ (define (check-compiler e)
282+ (check-equal? (asm-interp (compile e))
283+ (interp e)
284+ e))]
285+
286+ Generating random Con programs is essentially the same as Blackmail
287+ programs, and are provided in a @link["con/random.rkt " ]{random.rkt}
288+ module.
289+
290+ @ex[
291+ (eval:alts (require "random.rkt " ) (void))
292+ (random-expr)
293+ (random-expr)
294+ (random-expr)
295+ (random-expr)
296+ (for ([i (in-range 10 )])
297+ (check-compiler (random-expr)))
298+ ]
299+
300+
301+
0 commit comments