Browse Source

Implement let bindings (and variables)

Yaaay, this looks much more like a lisp now!
Lucas Stadler 8 years ago
parent
commit
ddc7a06ffc
3 changed files with 60 additions and 15 deletions
  1. 55 14
      scm/inc/compiler.scm
  2. 1 1
      scm/inc/program.scm
  3. 4 0
      scm/inc/tests.scm

+ 55 - 14
scm/inc/compiler.scm

@ -43,50 +43,91 @@
43 43
  (emit "sall $~a,  %eax" boolean-shift) ; construct correctly tagged boolean value
44 44
  (emit "xorl $~a, %eax" #b0011111))
45 45
46
(define (emit-expr x si)
46
(define (variable? x) (symbol? x))
47
48
(define (let? x)
49
  (and (list? x) (eq? (car x) 'let) (list? (cadr x)) (list? (caadr x))))
50
51
(define (emit-expr x si env)
47 52
  (cond
48 53
    ((immediate? x)
49 54
     (emit "movl $~a, %eax" (immediate-rep x)))
50
    ((primcall? x) (emit-primitive-call x si))))
55
    ((variable? x)
56
     (emit "movl ~a(%rsp), %eax" (lookup x env)))
57
    ((let? x)
58
     (emit-let (bindings x) (body x) si env))
59
    ((primcall? x) (emit-primitive-call x si env))))
60
61
(define (lookup x env)
62
  (cond
63
    ((null? env) (error 'lookup (format "~a is undefined" x)))
64
    ((eq? x (caar env)) (cadar env))
65
    (else (lookup x (cdr env)))))
66
67
(define (bindings let-expr) (cadr let-expr))
68
(define (body let-expr) (caddr let-expr))
69
70
(define (extend-env name val env)
71
  (cons (cons name (cons val '())) env))
72
73
(define (emit-let bindings body si env)
74
  (let f ((b* bindings) (new-env env) (si si))
75
    (cond
76
      ; if we're done with the bindings, emit the code for the body
77
      ((null? b*) (emit-expr body si new-env))
78
      ; otherwise, continue evaluating bindings in sequence
79
      (else
80
        (let ((b (car b*))) ; current binding
81
          ; emit code for current binding
82
          (emit-expr (rhs b) si env)
83
          ; move it onto the stack
84
          (emit "movl %eax, ~a(%rsp)" si)
85
          ; store current binding in env, continue generating bindings
86
          (f (cdr b*)
87
             (extend-env (lhs b) si new-env)
88
             (- si wordsize)))))))
89
90
(define (lhs binding) (car binding))
91
(define (rhs binding) (cadr binding))
51 92
52
(define (emit-primitive-call x si)
93
(define (emit-primitive-call x si env)
53 94
  (case (primcall-op x)
54 95
    ((add1)
55
     (emit-expr (primcall-operand1 x) si)
96
     (emit-expr (primcall-operand1 x) si env)
56 97
     (emit "addl $~a, %eax" (immediate-rep 1)))
57 98
    ((integer->char)
58
     (emit-expr (primcall-operand1 x) si)
99
     (emit-expr (primcall-operand1 x) si env)
59 100
     (emit "shl $6, %eax")
60 101
     (emit "xorl $15, %eax"))
61 102
    ((char->integer)
62
     (emit-expr (primcall-operand1 x) si)
103
     (emit-expr (primcall-operand1 x) si env)
63 104
     (emit "shrl $6, %eax"))
64 105
    ((zero?)
65
     (emit-expr (primcall-operand1 x) si)
106
     (emit-expr (primcall-operand1 x) si env)
66 107
     (emit "cmpl $0,  %eax") ; x == 0
67 108
     (emit-compare))
68 109
    ((null?)
69
     (emit-expr (primcall-operand1 x) si)
110
     (emit-expr (primcall-operand1 x) si env)
70 111
     (emit "cmpl $~a, %eax" #b00101111)
71 112
     (emit-compare))
72 113
    ((integer?)
73
     (emit-expr (primcall-operand1 x) si)
114
     (emit-expr (primcall-operand1 x) si env)
74 115
     (emit "andl $~a, %eax" #b11)
75 116
     (emit-compare))
76 117
    ((char?)
77
     (emit-expr (primcall-operand1 x) si)
118
     (emit-expr (primcall-operand1 x) si env)
78 119
     (emit "andl $~a, %eax" #b11111111)
79 120
     (emit "cmpl $~a, %eax" #b00001111)
80 121
     (emit-compare))
81 122
    ((boolean?)
82
     (emit-expr (primcall-operand1 x) si)
123
     (emit-expr (primcall-operand1 x) si env)
83 124
     (emit "andl $~a, %eax" #b1111111)
84 125
     (emit "cmpl $~a, %eax" #b0011111)
85 126
     (emit-compare))
86 127
    ((+)
87
     (emit-expr (primcall-operand2 x) si)
128
     (emit-expr (primcall-operand2 x) si env)
88 129
     (emit "movl %eax, ~a(%rsp)" si) ; move second arg on the stack
89
     (emit-expr (primcall-operand1 x) (- si wordsize))
130
     (emit-expr (primcall-operand1 x) (- si wordsize) env)
90 131
     (emit "addl ~a(%rsp), %eax" si))
91 132
    ))
92 133
@ -94,5 +135,5 @@
94 135
  (display ".globl scheme_entry\n\n")
95 136
  (display "scheme_entry:\n")
96 137
97
  (emit-expr x (- wordsize))
138
  (emit-expr x (- wordsize) '())
98 139
  (emit "ret"))

+ 1 - 1
scm/inc/program.scm

@ -1,3 +1,3 @@
1 1
(load "compiler.scm")
2 2
3
(compile-program '(+ 1 2))
3
(compile-program '(let ((x 3) (y 4)) (+ x y)))

+ 4 - 0
scm/inc/tests.scm

@ -107,3 +107,7 @@
107 107
    ["(+ 41 1)" "42\n"]
108 108
    ["(+ 1 41)" "42\n"]
109 109
    ["(+ -10 11)" "1\n"]])
110
111
(do-tests "3.5 - local variables"
112
  '[["(let ((x 3) (y 4)) (+ x y))" "7\n"]
113
    ["(let ((b #t)) (boolean? b))" "#t\n"]])