|
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 |
|
57 | 52 | ;; Compile an expression in tail position |
58 | 53 | (define (compile-tail-e e c) |
59 | 54 | (match e |
60 | | - [(? symbol? x) (compile-variable x c)] |
61 | | - [(? imm? i) (compile-imm i)] |
62 | | - [`(box ,e0) (compile-box e0 c)] |
63 | | - [`(unbox ,e0) (compile-unbox e0 c)] |
64 | | - [`(cons ,e0 ,e1) (compile-cons e0 e1 c)] |
65 | | - [`(car ,e0) (compile-car e0 c)] |
66 | | - [`(cdr ,e0) (compile-cdr e0 c)] |
67 | | - [`(add1 ,e0) (compile-add1 e0 c)] |
68 | | - [`(sub1 ,e0) (compile-sub1 e0 c)] |
69 | | - [`(zero? ,e0) (compile-zero? e0 c)] |
70 | | - [`(empty? ,e0) (compile-empty? e0 c)] |
71 | | - [`(if ,e0 ,e1 ,e2) (compile-tail-if e0 e1 e2 c)] |
72 | | - [`(+ ,e0 ,e1) (compile-+ e0 e1 c)] |
73 | | - [`(let ((,x ,e0)) ,e1) (compile-tail-let x e0 e1 c)] |
74 | | - [`(,f . ,es) (compile-tail-call f es c)])) |
| 55 | + [(var-e v) (compile-variable v c)] |
| 56 | + [(? imm? i) (compile-imm i)] |
| 57 | + [(prim-e (? prim? p) es) (compile-prim p es c)] |
| 58 | + [(if-e p t f) (compile-tail-if p t f c)] |
| 59 | + [(let-e (list b) body) (compile-tail-let b body c)] |
| 60 | + [(app-e f es) (compile-tail-call f es c)])) |
75 | 61 |
|
76 | 62 | ;; Expr CEnv -> Asm |
77 | 63 | ;; Compile an expression in non-tail position |
78 | 64 | (define (compile-e e c) |
79 | 65 | (match e |
80 | | - [(? symbol? x) (compile-variable x c)] |
81 | | - [(? imm? i) (compile-imm i)] |
| 66 | + [(var-e v) (compile-variable v c)] |
| 67 | + [(? imm? i) (compile-imm i)] |
| 68 | + [(prim-e (? prim? p) es) (compile-prim p es c)] |
| 69 | + [(if-e p t f) (compile-if p t f c)] |
| 70 | + [(let-e (list b) body) (compile-let b body c)] |
| 71 | + [(app-e f es) (compile-call f es c)])) |
| 72 | + |
| 73 | +;; Our current set of primitive operations require no function calls, |
| 74 | +;; so there's no difference between tail and non-tail call positions |
| 75 | +(define (compile-prim p es c) |
| 76 | + (match (cons p es) |
82 | 77 | [`(box ,e0) (compile-box e0 c)] |
83 | 78 | [`(unbox ,e0) (compile-unbox e0 c)] |
84 | 79 | [`(cons ,e0 ,e1) (compile-cons e0 e1 c)] |
|
88 | 83 | [`(sub1 ,e0) (compile-sub1 e0 c)] |
89 | 84 | [`(zero? ,e0) (compile-zero? e0 c)] |
90 | 85 | [`(empty? ,e0) (compile-empty? e0 c)] |
91 | | - [`(if ,e0 ,e1 ,e2) (compile-if e0 e1 e2 c)] |
92 | 86 | [`(+ ,e0 ,e1) (compile-+ e0 e1 c)] |
93 | | - [`(let ((,x ,e0)) ,e1) (compile-let x e0 e1 c)] |
94 | | - [`(,f . ,es) (compile-call f es c)])) |
| 87 | + [_ (error |
| 88 | + (format "prim applied to wrong number of args: ~a ~a" p es))])) |
95 | 89 |
|
96 | 90 | ;; Variable (Listof Expr) CEnv -> Asm |
97 | 91 | ;; Statically know the function we're calling |
|
132 | 126 | ,@cs))])) |
133 | 127 |
|
134 | 128 | ;; Variable (Listof Variable) Expr -> Asm |
135 | | -(define (compile-define f xs e0) |
136 | | - (let ((c0 (compile-tail-e e0 (reverse xs)))) |
137 | | - `(,(symbol->label f) |
138 | | - ,@c0 |
139 | | - ret))) |
| 129 | +(define (compile-define def) |
| 130 | + (match def |
| 131 | + [(fundef name args body) |
| 132 | + (let ((c0 (compile-e body (reverse args)))) |
| 133 | + `(,(symbol->label name) |
| 134 | + ,@c0 |
| 135 | + ret))])) |
140 | 136 |
|
141 | 137 | ;; (Listof Variable) (Listof (Listof Variable)) (Listof Expr) -> Asm |
142 | | -(define (compile-defines fs xss es) |
143 | | - (append-map compile-define fs xss es)) |
| 138 | +(define (compile-defines defs) |
| 139 | + (append-map compile-define defs)) |
144 | 140 |
|
145 | 141 | ;; Any -> Boolean |
146 | 142 | (define (imm? x) |
147 | | - (or (integer? x) |
148 | | - (boolean? x) |
149 | | - (char? x) |
150 | | - (equal? ''() x))) |
| 143 | + (or (int-e? x) |
| 144 | + (bool-e? x) |
| 145 | + (char-e? x) |
| 146 | + (nil-e? x))) |
151 | 147 |
|
152 | 148 | ;; Imm -> Asm |
153 | 149 | (define (compile-imm i) |
|
156 | 152 | ;; Imm -> Integer |
157 | 153 | (define (imm->bits i) |
158 | 154 | (match i |
159 | | - [(? integer? i) (arithmetic-shift i imm-shift)] |
160 | | - [(? char? c) (+ (arithmetic-shift (char->integer c) imm-shift) imm-type-char)] |
161 | | - [(? boolean? b) (if b imm-val-true imm-val-false)] |
162 | | - [''() imm-type-empty])) |
| 155 | + [(int-e i) (arithmetic-shift i imm-shift)] |
| 156 | + [(char-e c) (+ (arithmetic-shift (char->integer c) imm-shift) imm-type-char)] |
| 157 | + [(bool-e b) (if b imm-val-true imm-val-false)] |
| 158 | + [(nil-e) imm-type-empty])) |
| 159 | + |
163 | 160 |
|
164 | 161 | ;; Variable CEnv -> Asm |
165 | 162 | (define (compile-variable x c) |
|
285 | 282 | ,l1))) |
286 | 283 |
|
287 | 284 | ;; Variable Expr Expr CEnv -> Asm |
288 | | -(define (compile-tail-let x e0 e1 c) |
289 | | - (let ((c0 (compile-e e0 c)) |
290 | | - (c1 (compile-tail-e e1 (cons x c)))) |
291 | | - `(,@c0 |
292 | | - (mov (offset rsp ,(- (add1 (length c)))) rax) |
293 | | - ,@c1))) |
| 285 | +(define (compile-tail-let b e1 c) |
| 286 | + (match b |
| 287 | + [(binding v def) |
| 288 | + (let ((c0 (compile-e def c)) |
| 289 | + (c1 (compile-tail-e e1 (cons v c)))) |
| 290 | + `(,@c0 |
| 291 | + (mov (offset rsp ,(- (add1 (length c)))) rax) |
| 292 | + ,@c1))] |
| 293 | + [_ (error "Compile-let can only handle bindings")])) |
294 | 294 |
|
295 | 295 | ;; Variable Expr Expr CEnv -> Asm |
296 | | -(define (compile-let x e0 e1 c) |
297 | | - (let ((c0 (compile-e e0 c)) |
298 | | - (c1 (compile-e e1 (cons x c)))) |
299 | | - `(,@c0 |
300 | | - (mov (offset rsp ,(- (add1 (length c)))) rax) |
301 | | - ,@c1))) |
| 296 | +(define (compile-let b e1 c) |
| 297 | + (match b |
| 298 | + [(binding v def) |
| 299 | + (let ((c0 (compile-e def c)) |
| 300 | + (c1 (compile-e e1 (cons v c)))) |
| 301 | + `(,@c0 |
| 302 | + (mov (offset rsp ,(- (add1 (length c)))) rax) |
| 303 | + ,@c1))] |
| 304 | + [_ (error "Compile-let can only handle bindings")])) |
302 | 305 |
|
303 | 306 | ;; Expr Expr CEnv -> Asm |
304 | 307 | (define (compile-+ e0 e1 c) |
|
0 commit comments