|
1 | 1 | #lang racket |
2 | 2 | (provide (all-defined-out)) |
3 | 3 |
|
| 4 | +(require "ast.rkt") |
| 5 | + |
4 | 6 | ;; An immediate is anything ending in #b000 |
5 | 7 | ;; All other tags in mask #b111 are pointers |
6 | 8 |
|
|
26 | 28 | ;; end in #b000 and we tag with #b001 for boxes, etc. |
27 | 29 |
|
28 | 30 | ;; type CEnv = (Listof (Maybe Variable)) |
29 | | -;; type Imm = Integer | Boolean | Char | ''() |
30 | | - |
31 | | -;; type Prog = |
32 | | -;; | Expr |
33 | | -;; | `(begin ,@(Listof (define (,Variable ,@(Listof Variable)) ,Expr)) |
34 | | -;; ,Expr) |
35 | 31 |
|
36 | 32 | ;; Prog -> Asm |
37 | 33 | (define (compile p) |
38 | 34 | (match p |
39 | | - [(list 'begin `(define (,fs . ,xss) ,es) ... e0) |
40 | | - (let ((ds (compile-defines fs xss es)) |
41 | | - (c0 (compile-entry e0))) |
| 35 | + [(prog defs e) |
| 36 | + (let ((ds (compile-defines defs)) |
| 37 | + (c0 (compile-entry e))) |
42 | 38 | `(,@c0 |
43 | | - ,@ds))] |
44 | | - [e (compile-entry e)])) |
| 39 | + ,@ds))])) |
45 | 40 |
|
46 | 41 | ;; Expr -> Asm |
47 | 42 | ;; Compile e as the entry point |
48 | 43 | (define (compile-entry e) |
49 | 44 | `(entry |
50 | 45 | ,@(compile-tail-e e '()) |
51 | 46 | ret |
52 | | - |
53 | 47 | err |
54 | 48 | (push rbp) |
55 | 49 | (call error) |
|
59 | 53 | ;; Compile an expression in tail position |
60 | 54 | (define (compile-tail-e e c) |
61 | 55 | (match e |
62 | | - [(? symbol? x) (compile-variable x c)] |
63 | | - [(? imm? i) (compile-imm i)] |
64 | | - [`(box ,e0) (compile-box e0 c)] |
65 | | - [`(unbox ,e0) (compile-unbox e0 c)] |
66 | | - [`(cons ,e0 ,e1) (compile-cons e0 e1 c)] |
67 | | - [`(car ,e0) (compile-car e0 c)] |
68 | | - [`(cdr ,e0) (compile-cdr e0 c)] |
69 | | - [`(add1 ,e0) (compile-add1 e0 c)] |
70 | | - [`(sub1 ,e0) (compile-sub1 e0 c)] |
71 | | - [`(zero? ,e0) (compile-zero? e0 c)] |
72 | | - [`(empty? ,e0) (compile-empty? e0 c)] |
73 | | - [`(if ,e0 ,e1 ,e2) (compile-tail-if e0 e1 e2 c)] |
74 | | - [`(+ ,e0 ,e1) (compile-+ e0 e1 c)] |
75 | | - [`(let ((,x ,e0)) ,e1) (compile-tail-let x e0 e1 c)] |
76 | | - [`(fun ,f) (compile-fun f)] |
77 | | - [`(call ,e0 . ,es) (compile-fun-tail-call e0 es c)] |
78 | | - [`(,f . ,es) (compile-tail-call f es c)])) |
| 56 | + [(var-e v) (compile-variable v c)] |
| 57 | + [(? imm? i) (compile-imm i)] |
| 58 | + [(prim-e (? prim? p) es) (compile-prim p es c)] |
| 59 | + [(if-e p t f) (compile-tail-if p t f c)] |
| 60 | + [(let-e (list b) body) (compile-tail-let b body c)] |
| 61 | + [(fun-e f) (compile-fun f)] |
| 62 | + [(call-e f es) (compile-fun-tail-call f es c)] |
| 63 | + [(app-e f es) (compile-tail-call f es c)])) |
79 | 64 |
|
80 | 65 | ;; Expr CEnv -> Asm |
81 | 66 | ;; Compile an expression in non-tail position |
82 | 67 | (define (compile-e e c) |
83 | 68 | (match e |
84 | | - [(? symbol? x) (compile-variable x c)] |
85 | | - [(? imm? i) (compile-imm i)] |
| 69 | + [(var-e v) (compile-variable v c)] |
| 70 | + [(? imm? i) (compile-imm i)] |
| 71 | + [(prim-e (? prim? p) es) (compile-prim p es c)] |
| 72 | + [(if-e p t f) (compile-if p t f c)] |
| 73 | + [(let-e (list b) body) (compile-let b body c)] |
| 74 | + [(fun-e f) (compile-fun f)] |
| 75 | + [(call-e f es) (compile-fun-call f es c)] |
| 76 | + [(app-e f es) (compile-call f es c)])) |
| 77 | + |
| 78 | +;; Our current set of primitive operations require no function calls, |
| 79 | +;; so there's no difference between tail and non-tail call positions |
| 80 | +(define (compile-prim p es c) |
| 81 | + (match (cons p es) |
86 | 82 | [`(box ,e0) (compile-box e0 c)] |
87 | 83 | [`(unbox ,e0) (compile-unbox e0 c)] |
88 | 84 | [`(cons ,e0 ,e1) (compile-cons e0 e1 c)] |
|
92 | 88 | [`(sub1 ,e0) (compile-sub1 e0 c)] |
93 | 89 | [`(zero? ,e0) (compile-zero? e0 c)] |
94 | 90 | [`(empty? ,e0) (compile-empty? e0 c)] |
95 | | - [`(if ,e0 ,e1 ,e2) (compile-if e0 e1 e2 c)] |
96 | 91 | [`(+ ,e0 ,e1) (compile-+ e0 e1 c)] |
97 | | - [`(let ((,x ,e0)) ,e1) (compile-let x e0 e1 c)] |
98 | | - [`(fun ,f) (compile-fun f)] |
99 | | - [`(call ,e0 . ,es) (compile-fun-call e0 es c)] |
100 | | - [`(,f . ,es) (compile-call f es c)])) |
| 92 | + [_ (error |
| 93 | + (format "prim applied to wrong number of args: ~a ~a" p es))])) |
101 | 94 |
|
102 | 95 | ;; Variable (Listof Expr) CEnv -> Asm |
103 | 96 | ;; Statically know the function we're calling |
|
182 | 175 | ,@cs))])) |
183 | 176 |
|
184 | 177 | ;; Variable (Listof Variable) Expr -> Asm |
185 | | -(define (compile-define f xs e0) |
186 | | - (let ((c0 (compile-tail-e e0 (reverse xs)))) |
187 | | - `(,(symbol->label f) |
188 | | - ,@c0 |
189 | | - ret))) |
| 178 | +(define (compile-define def) |
| 179 | + (match def |
| 180 | + [(fundef name args body) |
| 181 | + (let ((c0 (compile-e body (reverse args)))) |
| 182 | + `(,(symbol->label name) |
| 183 | + ,@c0 |
| 184 | + ret))])) |
190 | 185 |
|
191 | 186 | ;; (Listof Variable) (Listof (Listof Variable)) (Listof Expr) -> Asm |
192 | | -(define (compile-defines fs xss es) |
193 | | - (append-map compile-define fs xss es)) |
| 187 | +(define (compile-defines defs) |
| 188 | + (append-map compile-define defs)) |
194 | 189 |
|
195 | 190 | ;; Any -> Boolean |
196 | 191 | (define (imm? x) |
197 | | - (or (integer? x) |
198 | | - (boolean? x) |
199 | | - (char? x) |
200 | | - (equal? ''() x))) |
| 192 | + (or (int-e? x) |
| 193 | + (bool-e? x) |
| 194 | + (char-e? x) |
| 195 | + (nil-e? x))) |
201 | 196 |
|
202 | 197 | ;; Imm -> Asm |
203 | 198 | (define (compile-imm i) |
|
206 | 201 | ;; Imm -> Integer |
207 | 202 | (define (imm->bits i) |
208 | 203 | (match i |
209 | | - [(? integer? i) (arithmetic-shift i imm-shift)] |
210 | | - [(? char? c) (+ (arithmetic-shift (char->integer c) imm-shift) imm-type-char)] |
211 | | - [(? boolean? b) (if b imm-val-true imm-val-false)] |
212 | | - [''() imm-type-empty])) |
| 204 | + [(int-e i) (arithmetic-shift i imm-shift)] |
| 205 | + [(char-e c) (+ (arithmetic-shift (char->integer c) imm-shift) imm-type-char)] |
| 206 | + [(bool-e b) (if b imm-val-true imm-val-false)] |
| 207 | + [(nil-e) imm-type-empty])) |
213 | 208 |
|
214 | 209 | ;; Variable CEnv -> Asm |
215 | 210 | (define (compile-variable x c) |
|
335 | 330 | ,l1))) |
336 | 331 |
|
337 | 332 | ;; Variable Expr Expr CEnv -> Asm |
338 | | -(define (compile-tail-let x e0 e1 c) |
339 | | - (let ((c0 (compile-e e0 c)) |
340 | | - (c1 (compile-tail-e e1 (cons x c)))) |
341 | | - `(,@c0 |
342 | | - (mov (offset rsp ,(- (add1 (length c)))) rax) |
343 | | - ,@c1))) |
| 333 | +(define (compile-tail-let b e1 c) |
| 334 | + (match b |
| 335 | + [(binding v def) |
| 336 | + (let ((c0 (compile-e def c)) |
| 337 | + (c1 (compile-tail-e e1 (cons v c)))) |
| 338 | + `(,@c0 |
| 339 | + (mov (offset rsp ,(- (add1 (length c)))) rax) |
| 340 | + ,@c1))] |
| 341 | + [_ (error "Compile-let can only handle bindings")])) |
344 | 342 |
|
345 | 343 | ;; Variable Expr Expr CEnv -> Asm |
346 | | -(define (compile-let x e0 e1 c) |
347 | | - (let ((c0 (compile-e e0 c)) |
348 | | - (c1 (compile-e e1 (cons x c)))) |
349 | | - `(,@c0 |
350 | | - (mov (offset rsp ,(- (add1 (length c)))) rax) |
351 | | - ,@c1))) |
| 344 | +(define (compile-let b e1 c) |
| 345 | + (match b |
| 346 | + [(binding v def) |
| 347 | + (let ((c0 (compile-e def c)) |
| 348 | + (c1 (compile-e e1 (cons v c)))) |
| 349 | + `(,@c0 |
| 350 | + (mov (offset rsp ,(- (add1 (length c)))) rax) |
| 351 | + ,@c1))] |
| 352 | + [_ (error "Compile-let can only handle bindings")])) |
352 | 353 |
|
353 | 354 | ;; Expr Expr CEnv -> Asm |
354 | 355 | (define (compile-+ e0 e1 c) |
|
0 commit comments