Page:Scheme - An interpreter for extended lambda calculus.djvu/32

From Wikisource
Jump to: navigation, search
This page has been proofread, but needs to be validated.
Sussman and Steele December 22, 1975 31 Implementation of the Interpreter

micro-seconds.

(DEFUN SETTICK (X) (SETQ **TICK** T))
 
(SETQ **QUANTUM** 1000000.  ALARMCLOCK 'SETTICK)

MLOOP is the main loop of the interpreter. It may be thought of as the instruction dispatch in the micro-code of the implementation machine. If an alarmclock tick has occurred, and interrupts are allowed, then the scheduler is called to switch processes. Otherwise the "instruction" specified by **PC** is executed via FASTCALL.

(DEFUN MLOOP ()
       (DO ((**TICK** NIL)) (NIL)       ;DO forever
           (AND **TICK** (ALLOW) (SCHEDULE))
           (FASTCALL **PC**)))

FASTCALL is essentially a FUNCALL optimized for compiled "microcode". Note the way it pulls the SUBR property to the front of the property list if possible for speed.

(DEFUN FASTCALL (ATSYM)
       (COND ((EQ (CAR (CDR ATSYM)) 'SUBR)
              (SUBRCALL NIL (CADR (CDR ATSYM))))
             (T ((LAMBDA (SUBR)
                         (COND (SUBR (REMPROP ATSYM 'SUBR)
                                     (PUTPROP ATSYM SUBR 'SUBR)
                                     (SUBRCALL NIL SUBR))
                               (T (FUNCALL ATSYM))))
                 (GET ATSYM 'SUBR)))))

Interrupts are allowed unless the variable *ALLOW* is bound to NIL in the current environment. This is used to implement the EVALUATE!UNINTERRUPTIBLY primitive.

(DEFUN ALLOW ()
       ((LAMBDA (VCELL)
                (COND (VCELL (CADR VCELL))
                      (T T)))
        (ASSQ '*ALLOW* **ENV**)))

Next comes the scheduler. It is apparently interrupt-driven, but in fact is not. The key here is to think microcode! There is one place in the microcoded instruction interpretation loop which checks to see if there is an interrupt pending; in our "machine", this occurs in MLOOP, where **TICK** is checked on every cycle. This is another case where we must beware of using too much of the power of the host language; just as we must avoid using host recursion directly to implement recursion, so we must avoid using host interrupts directly to implement interrupts. We may not modify any register during a host language interrupt, except one (such as **TICK**) which is