@@ -56,12 +56,17 @@ Let's consider some examples:
5656
5757@itemlist[
5858
59- @item{... }
59+ @item{@racket['(if (zero? 0 ) (add1 2 ) 4 )] means @racket[3 ].}
60+ @item{@racket['(if (zero? 1 ) (add1 2 ) 4 )] means @racket[4 ].}
61+ @item{@racket['(if (zero? (if (zero? (sub1 1 )) 1 0 )) (add1 2 ) 4 )] means @racket[4 ].}
62+ @item{@racket['(if (zero? (add1 0 )) (add1 2 ) (if (zero? (sub1 1 )) 1 0 ))] means @racket[1 ].}
6063
6164]
6265
6366
64- The semantics...
67+ The semantics is inductively defined as before. There are @emph{two}
68+ new rules added for handling if-expressions: one for when the test
69+ expression means @racket[0 ] and one for when it doesn't.
6570
6671@(define ((rewrite s) lws)
6772 (define lhs (list-ref lws 2 ))
@@ -135,33 +140,96 @@ according to @render-term[C 𝑪𝒓]:
135140@(show-judgment 𝑪 0 1 )
136141}
137142
138- The interpreter ...
143+ The interpreter has an added case for if-expressions, which
144+ recursively evaluates the test expression and branches based on its
145+ value.
139146
140147@codeblock-include["con/interp.rkt " ]
141148
142149We can confirm the interpreter computes the right result for the
143150examples given earlier:
144151
145152@ex[
146- '...
153+ (interp '(if (zero? 0 ) (add1 2 ) 4 ))
154+ (interp '(if (zero? 1 ) (add1 2 ) 4 ))
155+ (interp '(if (zero? (if (zero? (sub1 1 )) 1 0 )) (add1 2 ) 4 ))
156+ (interp '(if (zero? (add1 0 )) (add1 2 ) (if (zero? (sub1 1 )) 1 0 )))
147157]
148158
149- Correctness...
150- @;{
151- @bold{Interpreter Correctness}: @emph{For all Con expressions
152- @racket[e] and integers @racket[i], if (@racket[e],@racket[i]) in
153- @render-term[C 𝑪], then @racket[(interp e)] equals
154- @racket[i].}
155- }
159+ The argument for the correctness of the interpreter follows the same
160+ structure as for @seclink["Blackmail " ]{Blackmail}, but with an added case for
161+ if-expressions.
156162
157163@section{An Example of Con compilation}
158164
159165Suppose we want to compile @racket['(if (zero? 8 ) 2 3 )]...
160166
161- We already know how to compile the @racket['8 ], @racket['2 ], and
162- @racket['3 ] part.
167+ We already know how to compile the @racket[8 ], @racket[2 ], and
168+ @racket[3 ] part.
169+
170+ What needs to happen?
171+
172+ @itemlist[
173+ @item{Execute the code for @racket[8 ] leaving the result in @racket['rax ],}
174+ @item{check whether @racket['rax ] holds zero,}
175+ @item{if it does, execute the code for @racket[2 ],}
176+ @item{if it doesn't , execute the code for @racket[3 ].}
177+ ]
178+
179+ We can determine whether @racket[8 ] evaluates to @racket[0 ] using a
180+ comparison instruction: @racket['(cmp rax 0 )]. To do the conditional
181+ execution, we will need to jump to different parts of the code to
182+ either execute the code for @racket[2 ] or @racket[3 ]. There are
183+ several ways we could accomplish this , but we take the following
184+ approach: immediately after the comparison, do a conditional jump to
185+ the code for the else branch when non-zero. Should the jump not occur,
186+ the next instructions will carry out the evaluation of the then
187+ branch, then (unconditionally) jump over the else branch code.
188+
189+ To accomplish this , we will need two new labels: one for the else
190+ branch code and one for the end of the else branch code. The
191+ @racket[gensym] function can be used to generate symbols that have not
192+ appeared before.
193+
194+ In total, the code for this example would look like:
195+
196+ @racketblock[
197+ '((mov rax 8 )
198+ (cmp rax 0 )
199+ (jne if-else-begin)
200+ (mov rax 2 )
201+ (jmp if-else-end)
202+ if-else-begin
203+ (mov rax 3 )
204+ if-else-end)
205+ ]
206+
207+ Notice that the @racket['(mov rax 8 )], @racket['(mov rax 3 )] and
208+ @racket['(mov rax 2 )] parts are just the instructions generated by
209+ compiling @racket[8 ], @racket[2 ] and @racket[3 ]. Generalizing from
210+ this , we arrive at the following code for the compiler:
211+
212+ @racketblock[
213+ (let ((c0 (compile-e e0))
214+ (c1 (compile-e e1))
215+ (c2 (compile-e e2))
216+ (l0 (gensym "if-else-begin " ))
217+ (l1 (gensym "if-else-end " )))
218+ '(,@c0
219+ (cmp rax 0 )
220+ (jne ,l0)
221+ ,@c1
222+ (jmp ,l1)
223+ ,l0
224+ ,@c2
225+ ,l1))
226+ ]
227+
228+
229+ @ex[
230+ (asm-display (compile '(if (zero? 8 ) 2 3 )))
231+ ]
163232
164- What needs to happen? ...
165233
166234@codeblock-include["con/asm/ast.rkt " ]
167235
0 commit comments