home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d5xx
/
d556
/
scheme2c.lha
/
Scheme2C
/
Scheme-src.lzh
/
scsc
/
lambdacode.sc
< prev
next >
Wrap
Text File
|
1991-10-11
|
13KB
|
344 lines
;;; Code generator for $lambda expressions.
;;;
;* Copyright 1989 Digital Equipment Corporation
;* All Rights Reserved
;*
;* Permission to use, copy, and modify this software and its documentation is
;* hereby granted only under the following terms and conditions. Both the
;* above copyright notice and this permission notice must appear in all copies
;* of the software, derivative works or modified versions, and any portions
;* thereof, and both notices must appear in supporting documentation.
;*
;* Users of this software agree to the terms and conditions set forth herein,
;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
;* right and license under any changes, enhancements or extensions made to the
;* core functions of the software, including but not limited to those affording
;* compatibility with other hardware or software environments, but excluding
;* applications which incorporate this software. Users further agree to use
;* their best efforts to return to Digital any such changes, enhancements or
;* extensions that they make and inform Digital of noteworthy uses of this
;* software. Correspondence should be provided to Digital at:
;*
;* Director of Licensing
;* Western Research Laboratory
;* Digital Equipment Corporation
;* 100 Hamilton Avenue
;* Palo Alto, California 94301
;*
;* This software may be distributed (but not offered for sale or transferred
;* for compensation) to third parties, provided such third parties agree to
;* abide by the terms and conditions of this notice.
;*
;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
;* SOFTWARE.
(module lambdacode)
;;; External and in-line declarations.
(include "plist.sch")
(include "expform.sch")
(include "lambdaexp.sch")
(include "miscexp.sch")
(include "gencode.sch")
(include "lap.sch")
;;; ($lambda id body) ==> just about anything.
;;;
;;; The first part of lambda code generation is to decide whether the code is
;;; really going to be generated at this place. If it is, then the actual
;;; code generation will be done in PROCEDURE-EMIT or CLOSED-PROCEDURE-EMIT.
;;; Functions which are identified as INLINE-TAIL will have their label
;;; allocated here. Their code will be generated in LAMBDA-TAILS-GENC.
(define ($LAMBDA-GENC loc exp bindings)
(let* ((id ($lambda-id exp))
(generate (lambda-generate id)))
(cond ((eq? generate 'procedure)
(procedure-emit loc id exp bindings))
((eq? generate 'closed-procedure)
(closed-procedure-emit loc id exp bindings)))))
;;; The most straight forward case to generate is that of a procedure which
;;; does not have a closure pointer.
(define (PROCEDURE-EMIT loc id exp bindings)
(let* ((req (lambda-reqvars id))
(opt (optional-args id))
(formals (append req (if opt (list opt) '())))
(name (cname id))
(save-lap '())
(top (eq? (lambda-nestin id) 'top-level)))
(if (not (eq? loc 'no-value))
(emit-lap `(SET ,(vname loc)
("MAKEPROCEDURE"
,(length req)
,(if opt 1 0)
,(cname name)
"EMPTYLIST"))))
(set! save-lap (save-current-lap '()))
(emit-lap `(PROC ,(cname name) ,@(map vname formals)))
(emit-lap '(LIT "{"))
(emit-lap '(INDENT 8))
(emit-lap `(LOCALS DISPLAY ,free-display))
(stack-trace-emit id)
(lambda-body-genc 'return exp formals
(proc-args-to-display formals free-display) bindings)
(emit-lap `(INDENT 0))
(emit-lap '(LIT "}"))
(done-lap (save-current-lap save-lap))))
;;; The next type of procedure to emit is one which is closed over its free
;;; variables. The pointer to the closure will be added as the last argument
;;; to the function.
(define (CLOSED-PROCEDURE-EMIT loc id exp bindings)
(let* ((req (lambda-reqvars id))
(opt (optional-args id))
(closep (newv 'close 'use 'closurep
'display (lambda-display-closep id)))
(formals (append req
(append (if opt (list opt) '()) (list closep))))
(name (cname id))
(save-lap '()))
(emit-lap `(SET ,(vname loc)
("MAKEPROCEDURE"
,(length req)
,(if opt 1 0)
,(cname name)
,(closed-proc-closure id))))
(set! save-lap (save-current-lap '()))
(emit-lap `(PROC ,(cname name) ,@(map vname formals)))
(emit-lap '(LIT "{"))
(emit-lap '(INDENT 8))
(emit-lap `(LOCALS DISPLAY ,free-display))
(stack-trace-emit id)
(let ((restore (closed-proc-display id closep)))
(if restore
(let ((temp (use-lap-temp)))
(lambda-body-genc temp exp formals
(proc-args-to-display formals free-display)
bindings)
(map emit-lap restore)
(emit-lap `(SET return ,(vname temp))))
(lambda-body-genc 'return exp formals formals bindings)))
(emit-lap `(INDENT 0))
(emit-lap '(LIT "}"))
(done-lap (save-current-lap save-lap))))
;;; The following function is called to load procedure arguments into their
;;; appropriate display slots. It will return a list of the locations holding
;;; the values to be bound to the variables, for use by lambda-body-genc.
(define (PROC-ARGS-TO-DISPLAY formals displayx)
(if formals
(let ((var (car formals)))
(if (id-display var)
(begin (emit-lap `(SET ("DISPLAY" ,displayx) ,(vname var)))
(cons `("DISPLAY" ,displayx)
(proc-args-to-display (cdr formals)
(+ displayx 1))))
(cons var (proc-args-to-display (cdr formals) displayx))))
'()))
;;; The following function is called to make code for creating a closure
;;; with copies of the appropriate slots in the display.
(define (CLOSED-PROC-CLOSURE id)
(let ((lexvars (indirect-lambda-lexical id)))
(if lexvars
`("MAKECLOSURE"
"EMPTYLIST"
,(length lexvars)
,@(map (lambda (v) `("DISPLAY" ,(id-display v))) lexvars))
"EMPTYLIST")))
;;; The following function emits code to save the appropriate portions of the
;;; display. It will return code to restore the display.
(define (CLOSED-PROC-DISPLAY id closep)
(let loop ((i 0) (vars (indirect-lambda-lexical id)))
(if vars
(let ((temp (use-lap-temp))
(displayx (id-display (car vars))))
(emit-lap `(SET ,(vname temp) ("DISPLAY" ,displayx)))
(emit-lap `(SET ("DISPLAY" ,displayx)
("CLOSURE_VAR" ,(vname closep) ,i)))
(cons `(SET ("DISPLAY" ,displayx) ,(vname temp))
(loop (+ i 1) (cdr vars))))
'())))
;;; Code for the stack trace-back is emitted by the following routine when
;;; SC-STACK-TRACE is true.
(define (STACK-TRACE-EMIT lid)
(if sc-stack-trace
(let ((id (lambda-name lid)))
(if (and id (eq? (id-printname id) current-define-name)
(eq? (lambda-nestin lid) 'top-level))
(emit-lap `(PUSHSTACKTRACE
(U_TX (ADR ,(vname current-define-string)))))
(let ((temp (make-c-global))
(name (string-append
(if id
(symbol->string (id-printname id))
(cname lid))
" [inside "
(symbol->string current-define-name)
"]")))
(emit-global-lap
`(DEFSTRING ,(vname temp)
(CSTRING ,name) ,(string-length name)))
(emit-lap
`(PUSHSTACKTRACE (U_TX (ADR ,(vname temp))))))))))
;;; Code for $LAMBDA bodies is generated by the following function. Any
;;; lambda bodies that are designated as "inline-tails" will have their
;;; lambda variables allocated and deallocated here. Any lexical variables
;;; that they reference will also be allocated here.
(define (LAMBDA-BODY-GENC loc exp vars vals bindings)
(let* ((id ($lambda-id exp))
(save-current-code-lambda current-code-lambda)
(save-loc loc)
(save-free-display free-display)
(tails (lambda-inline-tails id)))
(set! current-code-lambda id)
(for-each
(lambda (lid)
(for-each
(lambda (var)
(unless (memq var vars)
(set! vars (append vars (list var)))
(set! vals
(append vals '(undefined)))))
(append (indirect-lambda-lexical lid)
(append (lambda-reqvars lid)
(lambda-optvars lid)))))
tails)
(if (and tails (eq? loc 'tos))
(set! loc (use-lap-temp)))
(reserve-display vars bindings)
(emit-lap `(LABEL ,(code-label id)))
(do ((bindings (lambda-bind-vars vars vals bindings))
(expl ($lambda-body exp) (cdr expl)))
((null? expl)
(lambda-tails-genc loc exp bindings))
(if (cdr expl)
(exp-genc 'no-value (car expl) bindings)
(exp-genc loc (car expl) bindings)))
(when (not (eq? loc save-loc))
(emit-lap `(SET ,(vname save-loc) ,(vname loc)))
(drop-lap-temp loc))
(set! free-display save-free-display)
(set! current-code-lambda save-current-code-lambda)
(if tails
(intersect-with-global-condition-info
(stored-conditions-intersection tails)))))
;;; Code for lambda expressions which are INLINE-TAIL's is generated after the
;;; code for the lambda body which they exit by this function.
(define (LAMBDA-TAILS-GENC loc exp bindings)
(let* ((id ($lambda-id exp))
(tails (lambda-inline-tails id))
(next (if (and tails (not (eq? loc 'return)))
(make-label)
#f))
(save-condition global-condition-info))
(do ((tails tails (cdr tails)))
((null? tails))
(if next (emit-lap `(GOTO ,next)))
(let* ((save-temp (save-lap-temps))
(save-display free-display)
(tail (car tails))
(vars (append (lambda-reqvars tail)
(lambda-optvars tail))))
(set! global-condition-info (retrieve-condition-info tail))
(lambda-body-genc loc (lambda-$lambda tail) vars
(map (lambda (var)
(let ((x (id-display var)))
(if x `("DISPLAY" ,x) var)))
vars)
bindings)
(store-condition-info tail)
(restore-lap-temps save-temp)
(set! free-display save-display)))
(if next (emit-lap `(LABEL ,next)))
(set! global-condition-info save-condition)))
;;; The following function is called to allocate variables to the display.
(define (RESERVE-DISPLAY vars bindings)
(let loop ((vars vars))
(if vars
(let ((var (car vars)))
(if (and (id-display var) (not (memq var bindings)))
(let ((displayx (let ((x free-display))
(set! free-display
(+ free-display 1))
x)))
(set-id-display! var displayx)))
(loop (cdr vars)))
(begin (set! lap-max-display (max lap-max-display free-display))
(set! max-display (max max-display free-display))))))
;;; Variables are bound by calling the following function with the variables,
;;; the cells holding their initial values, and the current bindings. It
;;; will return the new bindings, which is a list of variables which are
;;; currently bound to the value held in either a display slot or a temporary.
(define (LAMBDA-BIND-VARS vars vals bindings)
(do ((vars vars (cdr vars))
(vals vals (cdr vals))
(bindings bindings (if (memq (car vars) bindings)
bindings
(cons (car vars) bindings))))
((null? vals) bindings)
(let ((var (car vars))
(val (car vals)))
(cond ((and (eq? val 'undefined) (memq var bindings)))
((id-display var)
(cond ((eq? val 'undefined))
((id-set! var)
(emit-lap `(SET ("DISPLAY" ,(id-display var))
(CONS ,(vname val) "EMPTYLIST"))))
((not (equal? val `("DISPLAY" ,(id-display var))))
(emit-lap `(SET ("DISPLAY" ,(id-display var))
,(vname val))))))
((and (id-set! var)
(or (not (id-lambda var))
(eq? (lambda-generate (id-lambda var))
'closed-procedure)))
(cond ((eq? val 'undefined)
(set-id-vname! var (use-lap-temp)))
((memq var bindings)
(emit-lap `(SET ,(vname var)
("CONS" ,(vname val)
"EMPTYLIST"))))
(else
(let ((vn (id-vname
(if (eq? var val)
val
(use-lap-temp)))))
(emit-lap `(SET ,vn
("CONS" ,(vname val)
"EMPTYLIST")))
(set-id-vname! var vn)))))
((eq? val 'undefined)
(if (or (not (id-lambda var))
(eq? (lambda-generate (id-lambda var))
'closed-procedure))
(set-id-vname! var (use-lap-temp))))
((not (eq? var val))
(if (not (memq var bindings))
(set-id-vname! var (use-lap-temp)))
(emit-lap `(SET ,(vname var) ,(vname val))))))))