Skip to content

Commit decee0f

Browse files
committed
Update to Fraud.
1 parent 6a5aea9 commit decee0f

5 files changed

Lines changed: 95 additions & 63 deletions

File tree

www/notes/fraud.scrbl

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020

2121
@title[#:tag "Fraud"]{Fraud: local binding and variables}
2222

23+
@emph{To be is to be the value of a variable.}
24+
25+
@table-of-contents[]
26+
27+
@section{Variables}
28+
2329
@;defmodule[(file "/Users/dvanhorn/git/cmsc430-www/www/notes/fraud/interp.rkt")]
2430
@;declare-exporting[(file "/Users/dvanhorn/git/cmsc430-www/www/notes/fraud/interp.rkt")]
2531
@;defidform/inline[interp]
@@ -373,22 +379,39 @@ address of a variable occurrence is count of variable names that occur
373379
before it in the list. When a variable is bound (via-@racket[let])
374380
the list grows:
375381

382+
@codeblock-include["fraud/translate.rkt"]
383+
384+
Notice that @racket[translate] is a kind of mini-compiler that
385+
compiles @tt{Expr}s to @tt{IExpr}s. It's only job is to eliminate
386+
variable names by replacing variable occurrences with their lexical
387+
addresses. It does a minor amount of syntax checking while it's at it
388+
by raising a (compile-time) error in the case of unbound variables.
389+
390+
The interpreter for @tt{IExpr}s will still have an environment data
391+
structure, however it will be simpler the association list we started
392+
with. The run-time environment will consist only of a list of values;
393+
the lexical address of (what used to be a) variable indicates the
394+
position in this list. When a value is bound by a @racket[let], the
395+
list grows:
396+
376397
@codeblock-include["fraud/interp-lexical.rkt"]
377398

399+
Try to convince yourself that the two version of @racket[interp]
400+
compute the same function.
378401

379402

380403
@section{An Example of Fraud compilation}
381404

382-
Suppose we want to compile @racket['(let ((x 7)) (add1 x))]. There
383-
are two new forms we need to compile: the @racket['(let ((x ...))
384-
...)] part and the @racket['x] part in the body.
405+
Suppose we want to compile @racket[(let ((x 7)) (add1 x))]. There
406+
are two new forms we need to compile: the @racket[(let ((x ...))
407+
...)] part and the @racket[x] part in the body.
385408

386-
We already know how to compile the @racket['(add1 ...)] part and the
409+
We already know how to compile the @racket[(add1 ...)] part and the
387410
@racket[7] part.
388411

389412
What needs to happen? Compiling the @racket[7] part will emit
390413
instructions that, when run, leave @racket[7] in the @racket['rax]
391-
register. Compiling the @racket['(add1 ...)] part relies on the
414+
register. Compiling the @racket[(add1 ...)] part relies on the
392415
result of evaluating it's subexpression to be in @racket['rax] when it
393416
increments it. So, compile the variable binding needs to stash the
394417
@racket[7] somewhere and compiling the variable occurrence needs to
@@ -401,16 +424,16 @@ a let, after the right-hand side has been run, the result should be
401424
pushed. When evaluating a variable occurrence, the bound value is on
402425
the stack. After exiting the let, the stack can be popped.
403426

404-
Suppose we want to compile @racket['(let ((x 7)) (let ((y 2)) (add1
427+
Suppose we want to compile @racket[(let ((x 7)) (let ((y 2)) (add1
405428
x)))]. Using the intuition developed so far, we should push 7, push
406429
8, and then run the body. But notice that the value of @racket['x] is
407-
no longer on the top of the stack; @racket['y] is. So to retrieve the
408-
value of @racket['x] we need jump past the @racket['y]. But
409-
calculating these offsets is pretty straightforward. In this example
410-
there is one binding between the binding of @racket['x] and this
411-
occurrence. Since we push every time we enter a let and pop every
412-
time we leave, the number of bindings between an occurrence and its
413-
binder is exactly the offset from the top of the stack we need use.
430+
no longer on the top of the stack; @racket[y] is. So to retrieve the
431+
value of @racket[x] we need jump past the @racket[y]. But calculating
432+
these offsets is pretty straightforward. In this example there is one
433+
binding between the binding of @racket[x] and this occurrence. Since
434+
we push every time we enter a let and pop every time we leave, the
435+
number of bindings between an occurrence and its binder is exactly the
436+
offset from the top of the stack we need use.
414437

415438
@filebox-include-fake[codeblock "fraud/asm/ast.rkt"]{
416439
#lang racket

www/notes/fraud/interp-lexical.rkt

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,14 @@
11
#lang racket
22
(provide (all-defined-out))
3-
(require (only-in "interp.rkt" prim? value? interp-prim))
3+
(require (only-in "interp.rkt" prim? value? interp-prim)
4+
"translate.rkt")
45

5-
;; type LEnv = (Listof Variable)
66
;; type VEnv = (Listof Value)
77

88
;; Expr -> Answer
99
(define (interp e)
1010
(interp-env (translate e) '()))
1111

12-
;; Expr -> IExpr
13-
(define (translate e)
14-
(translate-e e '()))
15-
16-
;; Expr LEnv -> IExpr
17-
(define (translate-e e r)
18-
(match e
19-
[(? value? v) v]
20-
[(list (? prim? p) e)
21-
(list p (translate-e e r))]
22-
[`(if ,e0 ,e1 ,e2)
23-
`(if ,(translate-e e0)
24-
,(translate-e e1)
25-
,(translate-e e2))]
26-
[(? symbol? x)
27-
`(address ,(lexical-address x r))]
28-
[`(let ((,x ,e0)) ,e1)
29-
`(let ((_ ,(translate-e e0 r)))
30-
,(translate-e e1 (cons x r)))]))
31-
3212
;; IExpr VEnv -> Answer
3313
(define (interp-env e r)
3414
(match e
@@ -50,31 +30,3 @@
5030
['err 'err]
5131
[v
5232
(interp-env e1 (cons v r))])]))
53-
54-
;; Variable LEnv -> Natural
55-
(define (lexical-address x r)
56-
(match r
57-
['() (error "unbound variable")]
58-
[(cons y r)
59-
(match (symbol=? x y)
60-
[#t 0]
61-
[#f (add1 (lexical-address x r))])]))
62-
63-
(module+ test
64-
(require rackunit)
65-
(check-equal? (translate '(let ((x 0)) x))
66-
'(let ((_ 0)) (address 0)))
67-
(check-equal? (translate '(let ((x 0)) (let ((y 1)) x)))
68-
'(let ((_ 0)) (let ((_ 1)) (address 1))))
69-
(check-equal? (translate '(let ((x 0)) (let ((y 1)) y)))
70-
'(let ((_ 0)) (let ((_ 1)) (address 0))))
71-
(check-equal? (translate '(let ((x 0))
72-
(let ((y x))
73-
y)))
74-
'(let ((_ 0)) (let ((_ (address 0))) (address 0))))
75-
76-
(check-equal? (interp 5) 5)
77-
(check-equal? (interp '(let ((x 0)) x)) 0)
78-
(check-equal? (interp '(let ((x 0)) (let ((y 1)) x))) 0)
79-
(check-equal? (interp '(let ((x 0)) (let ((y 1)) y))) 1)
80-
(check-equal? (interp '(let ((x 0)) (let ((y x)) y))) 0))
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#lang racket
2+
(require rackunit)
3+
(require "../interp-lexical.rkt")
4+
(check-equal? (interp 5) 5)
5+
(check-equal? (interp '(let ((x 0)) x)) 0)
6+
(check-equal? (interp '(let ((x 0)) (let ((y 1)) x))) 0)
7+
(check-equal? (interp '(let ((x 0)) (let ((y 1)) y))) 1)
8+
(check-equal? (interp '(let ((x 0)) (let ((y x)) y))) 0)

www/notes/fraud/test/translate.rkt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#lang racket
2+
(require "../translate.rkt")
3+
(require rackunit)
4+
(check-equal? (translate '(let ((x 0)) x))
5+
'(let ((_ 0)) (address 0)))
6+
(check-equal? (translate '(let ((x 0)) (let ((y 1)) x)))
7+
'(let ((_ 0)) (let ((_ 1)) (address 1))))
8+
(check-equal? (translate '(let ((x 0)) (let ((y 1)) y)))
9+
'(let ((_ 0)) (let ((_ 1)) (address 0))))
10+
(check-equal? (translate '(let ((x 0))
11+
(let ((y x))
12+
y)))
13+
'(let ((_ 0))
14+
(let ((_ (address 0)))
15+
(address 0))))

www/notes/fraud/translate.rkt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#lang racket
2+
(provide (all-defined-out))
3+
(require (only-in "interp.rkt" prim? value? interp-prim))
4+
5+
;; type LEnv = (Listof Variable)
6+
7+
;; Expr -> IExpr
8+
(define (translate e)
9+
(translate-e e '()))
10+
11+
;; Expr LEnv -> IExpr
12+
(define (translate-e e r)
13+
(match e
14+
[(? value? v) v]
15+
[(list (? prim? p) e)
16+
(list p (translate-e e r))]
17+
[`(if ,e0 ,e1 ,e2)
18+
`(if ,(translate-e e0)
19+
,(translate-e e1)
20+
,(translate-e e2))]
21+
[(? symbol? x)
22+
`(address ,(lexical-address x r))]
23+
[`(let ((,x ,e0)) ,e1)
24+
`(let ((_ ,(translate-e e0 r)))
25+
,(translate-e e1 (cons x r)))]))
26+
27+
;; Variable LEnv -> Natural
28+
(define (lexical-address x r)
29+
(match r
30+
['() (error "unbound variable")]
31+
[(cons y r)
32+
(match (symbol=? x y)
33+
[#t 0]
34+
[#f (add1 (lexical-address x r))])]))

0 commit comments

Comments
 (0)