123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
- ; Generic arithmetic.
- ; The different kinds of numbers.
- (define-enumeration numbers
- (fixnum
- bignum
- rational
- float
- complex
- not-a-number))
- ; Mapping numbers to their representation.
- (define stob-numbers
- (make-vector stob-count (enum numbers not-a-number)))
- ; For now all we have are bignums (and fixnums, of course).
- (vector-set! stob-numbers (enum stob bignum) (enum numbers bignum))
- (define (number->representation x)
- (cond ((fixnum? x)
- (enum numbers fixnum))
- ((stob? x)
- (vector-ref stob-numbers (header-type (stob-header x))))
- (else
- (enum numbers not-a-number))))
- ;----------------
- ; Tables for unary and binary operations. All entries initially return DEFAULT.
- (define (make-unary-table default)
- (make-vector numbers-count
- (lambda (x)
- default)))
-
- ; (unary-table-set! <table> <type> <value>)
- ; (unary-table-set! <table> (<type> ...) <value>)
- (define-syntax unary-table-set!
- (syntax-rules ()
- ((unary-table-set! ?table (?kind ...) ?value)
- (real-unary-table-set! ?table (list (enum numbers ?kind) ...) ?value))
- ((unary-table-set! ?table ?kind ?value)
- (real-unary-table-set! ?table (list (enum numbers ?kind)) ?value))))
- (define (real-unary-table-set! table kinds value)
- (for-each (lambda (kind)
- (vector-set! table kind value))
- kinds))
- (define (unary-dispatch table x)
- ((vector-ref table
- (number->representation x))
- x))
- (define (make-binary-table default)
- (make-vector (* numbers-count numbers-count)
- (lambda (x y)
- default)))
- ; Same as for unary tables, except that we have two indexes or lists of indexes.
- (define-syntax binary-table-set!
- (syntax-rules ()
- ((binary-table-set! ?table (?kind0 ...) (?kind1 ...) ?value)
- (real-binary-table-set! ?table
- (list (enum numbers ?kind0) ...)
- (list (enum numbers ?kind1) ...)
- ?value))
- ((binary-table-set! ?table (?kind0 ...) ?kind1 ?value)
- (real-binary-table-set! ?table
- (list (enum numbers ?kind0) ...)
- (list (enum numbers ?kind1))
- ?value))
- ((binary-table-set! ?table ?kind0 (?kind1 ...) ?value)
- (real-binary-table-set! ?table
- (list (enum numbers ?kind0))
- (list (enum numbers ?kind1) ...)
- ?value))
- ((binary-table-set! ?table ?kind0 ?kind1 ?value)
- (real-binary-table-set! ?table
- (list (enum numbers ?kind0))
- (list (enum numbers ?kind1))
- ?value))))
- (define (real-binary-table-set! table kinds0 kinds1 value)
- (for-each (lambda (kind0)
- (for-each (lambda (kind1)
- (vector-set! table
- (+ (* kind0 numbers-count)
- kind1)
- value))
- kinds1))
- kinds0))
- ; Does this need to be changed to get a computed goto?
- (define (binary-dispatch table x y)
- ((vector-ref table
- (+ (* (number->representation x)
- numbers-count)
- (number->representation y)))
- x
- y))
- (define (binary-lose x y)
- unspecific-value)
- ;----------------
- ; The actual opcodes
- ; Predicates
- (define-primitive number? (any->)
- (lambda (x)
- (not (= (number->representation x)
- (enum numbers not-a-number))))
- return-boolean)
- (define-primitive integer? (any->)
- (lambda (x)
- (let ((type (number->representation x)))
- (or (= type (enum numbers fixnum))
- (= type (enum numbers bignum)))))
- return-boolean)
- (define-primitive rational? (any->)
- (lambda (x)
- (let ((type (number->representation x)))
- (or (= type (enum numbers fixnum))
- (= type (enum numbers bignum))
- (= type (enum numbers rational)))))
- return-boolean)
- (define-primitive real? (any->)
- (lambda (x)
- (let ((type (number->representation x)))
- (not (or (= type (enum numbers complex))
- (= type (enum numbers not-a-number))))))
- return-boolean)
- (define-primitive complex? (any->)
- (lambda (x)
- (not (= (number->representation x)
- (enum numbers not-a-number))))
- return-boolean)
- (define-primitive exact? (any->)
- (lambda (x)
- (enum-case number (number->representation x)
- ((float)
- (goto return-boolean #f))
- ((complex)
- (goto return-boolean (not (float? (complex-real-part x)))))
- ((not-a-number)
- (raise-exception wrong-type-argument 0 x))
- (else
- (goto return-boolean #t)))))
- ;----------------
- ; Arithmetic
- (define-syntax define-binary-primitive
- (syntax-rules ()
- ((define-binary-primitive id table careful integer)
- (define table (make-binary-table binary-lose))
- (define-primitive id (any-> any->)
- (lambda (x y)
- (if (and (fixnum? x)
- (fixnum? y))
- (goto careful
- x
- y
- return
- (lambda (x y)
- (goto return (integer x y))))
- (let ((r (binary-dispatch table x y)))
- (if (vm-eq? r unspecific-value)
- (raise-exception wrong-type-argument 0 x y)
- (goto return r))))))
- (binary-table-set! table (fixnum bignum) (fixnum bignum) integer))))
- (define-binary-primitive + add-table add-carefully integer-add)
- (define-binary-primitive - subtract-table subtract-carefully integer-subtract)
- (define-binary-primitive * multiply-table multiply-carefully integer-multiply)
- (define-binary-primitive quotient quotient-table quotient-carefully integer-quotient)
- (define-binary-primitive remainder remainder-table remainder-carefully integer-remainder)
- (define-binary-primitive arithmetic-shift shift-table shift-carefully integer-shift)
- ; Hm. There is no integer-divide (obviously)
- (define-binary-primitive / divide-table divide-carefully integer-)
- ****************************************************************
- How to structure all this? It would be nice if the interpreter could be
- broken into several modules. The registers and define-primitive would
- need to be separated out.
- ;----------------
- ; Tower predicates.
- ; These need to be changed.
- (define-unary-opcode-extension integer? &integer? #f)
- (define-unary-opcode-extension rational? &rational? #f)
- (define-unary-opcode-extension real? &real? #f)
- (define-unary-opcode-extension complex? &complex? #f)
- (define-unary-opcode-extension number? &number? #f)
- (define-unary-opcode-extension exact? &exact? #f)
- (let ((true (lambda (x) #t)))
- (unary-table-set! &integer? (fixnum bignum) true)
- (unary-table-set! &rational? (fixnum bignum rational) true)
- (unary-table-set! &real? (fixnum bignum rational float) true)
- (unary-table-set! &complex? (fixnum bignum rational float complex) true)
- (unary-table-set! &number? (fixnum bignum rational float complex) true)
- (unary-table-set! &exact? (fixnum bignum rational) true))
- ; The two parts of a complex number must have the same exactness.
- (unary-table-set! &exact? (complex)
- (lambda (z)
- (real-part z)))
- ;----------------
- ; Imaginary operations.
- (define-unary-opcode-extension real-part &real-part (lambda (x) x))
- (define-unary-opcode-extension imag-part &imag-part (lambda (x) 0))
- (unary-table-set! &real-part (complex not-a-number)
- (lambda (x) unimplemented))
- (unary-table-set! &imag-part (complex not-a-number)
- (lambda (x) unimplemented))
- ;----------------
- ; Fractions
- (define-unary-opcode-extension floor &floor)
- (define-unary-opcode-extension numerator &numerator)
- (define-unary-opcode-extension denominator &denominator)
- (define (identity x) x)
- (unary-table-set! &floor (fixnum bignum) identity)
- (unary-table-set! &numerator (fixnum bignum) identity)
- (unary-table-set! &denominator (fixnum bignum) (lambda (x) 1))
- ;----------------
- ; Square root.
- (define-unary-opcode-extension sqrt &sqrt)
- ; The bignum code could whack this.
- ; The VM doesn't do sqrt for positive fixnums. I wonder why?
- ; For negative N, we lose if MAKE-RECTANGULAR loses.
- (unary-table-set! &sqrt (fixnum bignum)
- (lambda (n)
- (if (>= n 0)
- (non-negative-integer-sqrt n) ;Dubious (JAR)
- (let ((s (non-negative-integer-sqrt (- n))))
- (if (eq? s unimplemented)
- s
- (binary-dispatch &make-rectangular
- 0
- s))))))
- ; Courtesy of Mr. Newton.
- (define (non-negative-integer-sqrt n)
- (if (<= n 1) ; for both 0 and 1
- n
- (let loop ((m (quotient n 2)))
- (let ((m1 (quotient n m)))
- (cond ((< m1 m)
- (loop (quotient (+ m m1) 2)))
- ((= n (* m m))
- m)
- (else
- unimplemented))))))
- ;----------------
- ; Make sure this has very low priority, so that it's only tried as a
- ; last resort.
- ;
- ; In fact, I'll comment it out completely. -RK
- ;(define-method &/ (m n)
- ; (if (and (integer? m) (integer? n))
- ; (if (= 0 (remainder m n))
- ; (quotient m n)
- ; (let ((z (abs (quotient n 2))))
- ; (set-exactness (quotient (if (< m 0)
- ; (- m z)
- ; (+ m z))
- ; n)
- ; #f)))
- ; (next-method)))
- ;----------------
- ; The rest have no useful defaults.
- (define-unary-opcode-extension exact->inexact &exact->inexact)
- (define-unary-opcode-extension inexact->exact &inexact->exact)
- (define-binary-opcode-extension + &+)
- (define-binary-opcode-extension - &-)
- (define-binary-opcode-extension * &*)
- (define-binary-opcode-extension / &/)
- (define-binary-opcode-extension = &=)
- (define-binary-opcode-extension < &<)
- (define-binary-opcode-extension quotient "ient)
- (define-binary-opcode-extension remainder &remainder)
-
- (define-binary-opcode-extension make-rectangular &make-rectangular)
- (define-unary-opcode-extension exp &exp)
- (define-unary-opcode-extension log &log)
- (define-unary-opcode-extension sin &sin)
- (define-unary-opcode-extension cos &cos)
- (define-unary-opcode-extension tan &tan)
- (define-unary-opcode-extension asin &asin)
- (define-unary-opcode-extension acos &acos)
- (define-unary-opcode-extension atan &atan)
- ; >, <=, and >= are all extended using the table for <.
- (extend-opcode! (enum op >)
- (lambda (lose)
- (lambda (reason arg0 arg1)
- (let ((res (binary-dispatch &< arg1 arg0)))
- (if (eq? res unimplemented)
- (lose reason arg0 arg1)
- res)))))
- (extend-opcode! (enum op <=)
- (lambda (lose)
- (lambda (reason arg0 arg1)
- (let ((res (binary-dispatch &< arg1 arg0)))
- (if (eq? res unimplemented)
- (lose reason arg0 arg1)
- (not res))))))
- (extend-opcode! (enum op >=)
- (lambda (lose)
- (lambda (reason arg0 arg1)
- (let ((res (binary-dispatch &< arg0 arg1)))
- (if (eq? res unimplemented)
- (lose reason arg0 arg1)
- (not res))))))
|