Просмотр исходного кода

Implement let bindings (and variables)

Yaaay, this looks much more like a lisp now!
Lucas Stadler лет назад: 8
Родитель
Сommit
ddc7a06ffc
3 измененных файлов с 60 добавлено и 15 удалено
  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
  (emit "sall $~a,  %eax" boolean-shift) ; construct correctly tagged boolean value
43
  (emit "sall $~a,  %eax" boolean-shift) ; construct correctly tagged boolean value
44
  (emit "xorl $~a, %eax" #b0011111))
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
  (cond
52
  (cond
48
    ((immediate? x)
53
    ((immediate? x)
49
     (emit "movl $~a, %eax" (immediate-rep x)))
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
  (case (primcall-op x)
94
  (case (primcall-op x)
54
    ((add1)
95
    ((add1)
55
     (emit-expr (primcall-operand1 x) si)
96
     (emit-expr (primcall-operand1 x) si env)
56
     (emit "addl $~a, %eax" (immediate-rep 1)))
97
     (emit "addl $~a, %eax" (immediate-rep 1)))
57
    ((integer->char)
98
    ((integer->char)
58
     (emit-expr (primcall-operand1 x) si)
99
     (emit-expr (primcall-operand1 x) si env)
59
     (emit "shl $6, %eax")
100
     (emit "shl $6, %eax")
60
     (emit "xorl $15, %eax"))
101
     (emit "xorl $15, %eax"))
61
    ((char->integer)
102
    ((char->integer)
62
     (emit-expr (primcall-operand1 x) si)
103
     (emit-expr (primcall-operand1 x) si env)
63
     (emit "shrl $6, %eax"))
104
     (emit "shrl $6, %eax"))
64
    ((zero?)
105
    ((zero?)
65
     (emit-expr (primcall-operand1 x) si)
106
     (emit-expr (primcall-operand1 x) si env)
66
     (emit "cmpl $0,  %eax") ; x == 0
107
     (emit "cmpl $0,  %eax") ; x == 0
67
     (emit-compare))
108
     (emit-compare))
68
    ((null?)
109
    ((null?)
69
     (emit-expr (primcall-operand1 x) si)
110
     (emit-expr (primcall-operand1 x) si env)
70
     (emit "cmpl $~a, %eax" #b00101111)
111
     (emit "cmpl $~a, %eax" #b00101111)
71
     (emit-compare))
112
     (emit-compare))
72
    ((integer?)
113
    ((integer?)
73
     (emit-expr (primcall-operand1 x) si)
114
     (emit-expr (primcall-operand1 x) si env)
74
     (emit "andl $~a, %eax" #b11)
115
     (emit "andl $~a, %eax" #b11)
75
     (emit-compare))
116
     (emit-compare))
76
    ((char?)
117
    ((char?)
77
     (emit-expr (primcall-operand1 x) si)
118
     (emit-expr (primcall-operand1 x) si env)
78
     (emit "andl $~a, %eax" #b11111111)
119
     (emit "andl $~a, %eax" #b11111111)
79
     (emit "cmpl $~a, %eax" #b00001111)
120
     (emit "cmpl $~a, %eax" #b00001111)
80
     (emit-compare))
121
     (emit-compare))
81
    ((boolean?)
122
    ((boolean?)
82
     (emit-expr (primcall-operand1 x) si)
123
     (emit-expr (primcall-operand1 x) si env)
83
     (emit "andl $~a, %eax" #b1111111)
124
     (emit "andl $~a, %eax" #b1111111)
84
     (emit "cmpl $~a, %eax" #b0011111)
125
     (emit "cmpl $~a, %eax" #b0011111)
85
     (emit-compare))
126
     (emit-compare))
86
    ((+)
127
    ((+)
87
     (emit-expr (primcall-operand2 x) si)
128
     (emit-expr (primcall-operand2 x) si env)
88
     (emit "movl %eax, ~a(%rsp)" si) ; move second arg on the stack
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
     (emit "addl ~a(%rsp), %eax" si))
131
     (emit "addl ~a(%rsp), %eax" si))
91
    ))
132
    ))
92
133
94
  (display ".globl scheme_entry\n\n")
135
  (display ".globl scheme_entry\n\n")
95
  (display "scheme_entry:\n")
136
  (display "scheme_entry:\n")
96
137
97
  (emit-expr x (- wordsize))
138
  (emit-expr x (- wordsize) '())
98
  (emit "ret"))
139
  (emit "ret"))

+ 1 - 1
scm/inc/program.scm

1
(load "compiler.scm")
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
    ["(+ 41 1)" "42\n"]
107
    ["(+ 41 1)" "42\n"]
108
    ["(+ 1 41)" "42\n"]
108
    ["(+ 1 41)" "42\n"]
109
    ["(+ -10 11)" "1\n"]])
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"]])