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
/
expform.sc
< prev
next >
Wrap
Text File
|
1991-10-11
|
21KB
|
537 lines
;;; The "first pass" of this Scheme compiler reads the source files and
;;; performs the following operations:
;;;
;;; - macro and special form expansion
;;; - alpha-conversion
;;; - lexical variable usage recording
;;;
;;; At the end of this pass, all bindings and control flows should be visible
;;; in the tree.
;;;
;* 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 expform)
;;; Pick up external declarations.
(include "plist.sch")
(include "expform.sch")
(include "lambdaexp.sch")
;;; During compilation, variable binding information is kept in the following
;;; global variables. Each is an a-list with entries of the form:
;;;
;;; (external-name alpha-converted-name)
;;;
;;; LEXICAL-BOUND-VARS contains the variables which are bound at the current
;;; lexical level. LEXICAL-FREE-VARS contains the variables which are
;;; lexically bound at higher lexical levels. GLOBAL-FREE-VARS contains those
;;; variables which are bound at the "top-level".
(define GLOBAL-FREE-VARS '())
(define LEXICAL-FREE-VARS '())
(define LEXICAL-BOUND-VARS '())
;;; Information relating to the current lambda expression is kept in the
;;; following variables. CURRENT-LAMBDA-ID is the identifier for the current
;;; lambda expression.
(define CURRENT-LAMBDA-ID 'top-level)
;;; Alpha-conversion requires the generation of unique names. The sequence
;;; number which is used is kept in MAKE-ALPHA-SEQ.
(define MAKE-ALPHA-SEQ 0)
;;; Source processing starts with the following function which is entered with
;;; a generator function for the source. It will return a list of forms which
;;; is the result of the first pass.
(define (EXPAND-FORMS)
(let ((results '()))
(do ((exp (read-text) (read-text)))
((eof-object? exp) (set! results (reverse results)))
(set! lexical-free-vars '())
(set! current-lambda-id 'top-level)
(set! exp (exp-form exp exp-form))
(if exp (set! results (cons exp results))))
(for-each
(lambda (var-alpha)
(let ((var (car var-alpha))
(alpha (cadr var-alpha)))
(if (and (eq? (id-use alpha) 'global)
(not (id-module alpha)))
(begin (set! current-define-name
(id-undefref alpha))
(report-warning
"Variable assumed to be TOP-LEVEL:"
var)
(set-id-use! alpha 'top-level)
(set-id-module! alpha 'top-level)
(set-id-vname! alpha
(string-append
(hex28 "" (lchexname var))
"_v"))
(set! quote-constants
(cons (list var alpha)
quote-constants))))))
global-free-vars)
results))
;;; The expressions are recursively expanded by the following function which
;;; is called with the expression and the expansion function. The expansion
;;; process is similar to macro expansion, but it does the alpha-conversion
;;; using the functions stored under the property EXPAND.
(define (EXP-FORM exp exp-func)
(cond ((symbol? exp)
(bound exp))
((or (number? exp) (string? exp) (char? exp)
(member exp '(#t #f)))
(exp-func (list 'quote exp) exp-func))
((islist exp 1)
(let ((func (if (symbol? (car exp)) (get (car exp) 'expand) '())))
(apply (if func func call-exp) (list exp exp-func))))
(else
(expand-error "" exp))))
;;; A similar function is used to expand a list of functions.
(define (EXP-FORM-LIST exp-list func)
(if (islist exp-list 0)
(map (lambda (exp) (func exp func)) exp-list)
(expand-error 'expression-list exp-list)))
;;; During the alpha-conversion phase, all variables will be replaced with
;;; unique variables. Information about each variable will be saved as
;;; properties of the alpha-converted variable. The items saved are:
;;;
;;; PRINTNAME: original program variable name.
;;; VNAME: C name to access the item as a variable.
;;; CNAME: C name to access the item as a procedure.
;;; MODULE: module name containing the item.
;;; USE: tag indicating what the variable signifies. The possible
;;; tags are: LABEL, LAMBDA, LEXICAL, CONSTANT, GLOBAL, TOP-LEVEL,
;;; TEMPORARY, CLOSUREP, and MACRO.
;;; TYPE: data type which is either false indicating a TSCP or the
;;; appropriate C datatype.
;;; DISPLAY: boolean that indicates that the variable is be allocated in a
;;; display cell.
;;; BOUNDID: id of the lambda expression where this variable is bound.
;;; LAMBDA: id of the lambda expression which is this var's value.
;;; EXTERNAL: indicates that variable is external to this compile and is
;;; referenced.
;;; DEFINED: indicates that variable is defined by a top-level define in
;;; this module.
;;; VALUE: value for identifiers which are constants.
;;; SET!: boolean indicating that the variable has been SET!.
;;; REFS: counter for # of times a lambda bound variable is referenced.
;;; CALLS: counter for # of times a lambda bound variable is called as a
;;; function.
;;; ALIAS: label alias (see emit-lap).
;;; GOTOS: counter for # of branches to a label.
;;; UNDEFREF current-define-name for first use when undefined.
(define (ID-PRINTNAME id) (id-printname id))
(define (SET-ID-PRINTNAME! id name) (set-id-printname! id name))
(define (ID-VNAME id) (id-vname id))
(define (SET-ID-VNAME! id name) (set-id-vname! id name))
(define (ID-CNAME id) (id-cname id))
(define (SET-ID-CNAME! id name) (set-id-cname! id name))
(define (ID-MODULE id) (id-module id))
(define (SET-ID-MODULE! id name) (set-id-module! id name))
(define (ID-USE id) (id-use id))
(define (SET-ID-USE! id tag) (set-id-use! id tag))
(define (ID-TYPE id) (id-type id))
(define (SET-ID-TYPE! id tag) (set-id-type! id tag))
(define (ID-DISPLAY id) (id-display id))
(define (SET-ID-DISPLAY! id flag) (set-id-display! id flag))
(define (ID-BOUNDID id) (id-boundid id))
(define (SET-ID-BOUNDID id value)(set-id-boundid id value))
(define (ID-LAMBDA id) (id-lambda id))
(define (SET-ID-LAMBDA! id lambda-id) (set-id-lambda! id lambda-id))
(define (ID-EXTERNAL id) (id-external id))
(define (SET-ID-EXTERNAL! id flag) (set-id-external! id flag))
(define (ID-DEFINED id) (id-defined id))
(define (SET-ID-DEFINED! id flag) (set-id-defined! id flag))
(define (ID-VALUE id) (id-value id))
(define (SET-ID-VALUE! id x) (set-id-value! id x))
(define (ID-SET! id) (id-set! id))
(define (SET-ID-SET!! id flag) (set-id-set!! id flag))
(define (ID-REFS id) (id-refs id))
(define (SET-ID-REFS! id cnt) (set-id-refs! id cnt))
(define (ID-CALLS id) (id-calls id))
(define (SET-ID-CALLS! id cnt) (set-id-calls! id cnt))
(define (ID-ALIAS id) (id-alias id))
(define (SET-ID-ALIAS! id label) (set-id-alias! id label))
(define (ID-GOTOS id) (id-gotos id))
(define (SET-ID-GOTOS! id cnt) (set-id-gotos! id cnt))
(define (ID-UNDEFREF id) (id-undefref id))
(define (SET-ID-UNDEFREF! id var) (set-id-undefref! id var))
;;; Variables which represent globally defined items will have their property
;;; GLOBAL set to their alphatized variable. This allows rapid global lookup.
(define (ID-GLOBAL id) (id-global id))
(define (SET-ID-GLOBAL! id alpha) (set-id-global! id alpha))
;;; Names are generated for externally visible variables by the following
;;; function.
(define (ASSIGN-KNOWN-NAME var)
(let* ((use (id-use var))
(module (id-module var))
(name (lchexname (id-printname var))))
(cond ((memq use '(lexical closurep))
(let ((lcvar (lchexname var)))
(cond ((id-lambda var)
(set-id-cname! var
(string-append module-name "_" lcvar))
(set-id-vname! var (string-append lcvar "_v")))
(else
(set-id-vname! var lcvar)))))
((and (eq? use 'global) (id-type var)))
(else
(set-id-vname! var (string-append (hex28 module name) "_v"))
(set-id-cname! var (string-append (hex28 module name)))))))
;;; This function is called to establish the linkage between a variable and a
;;; lambda expression.
(define (NAME-A-LAMBDA name exp)
(set! exp ($lambda-id exp))
(if exp
(begin (set-id-lambda! name exp)
(set-lambda-name! exp name))))
;;; Often one wants the VNAME or CNAME of an arbitrary expression. These
;;; functions will produce it.
(define (VNAME exp)
(if (symbol? exp)
(begin (if (and (eq? (id-use exp) 'lambda) (lambda-name exp))
(set! exp (lambda-name exp)))
(id-vname exp))
exp))
(define (CNAME exp)
(if (symbol? exp)
(begin (if (and (eq? (id-use exp) 'lambda) (lambda-name exp))
(set! exp (lambda-name exp)))
(id-cname exp))
exp))
;;; This function is called to convert a name into its "lower case hex" format.
(define (LCHEXNAME name)
(if (symbol? name) (set! name (symbol->string name)))
(do ((c '())
(i 0 (+ 1 i))
(new (list 1)))
((= i (string-length name)) (list->string (cdr new)))
(set! c (string-ref name i))
(cond ((char=? c #\_)
(set-cdr! (last-pair new) (list #\_ #\_)))
((and (char>=? c #\A) (char<=? c #\Z))
(set-cdr! (last-pair new)
(list (integer->char (+ (char->integer c) 32)))))
((or (and (char>=? c #\a) (char<=? c #\z))
(and (char>=? c #\0) (char<=? c #\9) (> i 0)))
(set-cdr! (last-pair new) (list c)))
(else
(set-cdr! (last-pair new) (cons #\_ (char->dl c 16 2)))))))
;;; This function is one of those that you hope you never have to write, but
;;; inevitably you must. It exists because vcc will only recognize the first
;;; 31 characters of a variable name. In order to force the first 31
;;; characters of a generated name to be unique, it is necessary that the
;;; lchexnames of the module and variable be less than or equal to 28
;;; characters. If it doesn't fit, then a name is generated consisting of
;;; the last 9 characters of the module name, the last 10 characters of the
;;; name, and the hex crc-32 of the module and name.
(define (HEX28 module name)
(if (<= (+ (string-length module) (string-length name)) 28)
(if (equal? module "") name (string-append module "_" name))
(let ((value (format '() "~a_~a_~a"
(substring module
(max 0 (- (string-length module) 9))
(string-length module))
(substring name
(max 0 (- (string-length name) 10))
(string-length name))
(crc-32x2 (string->list
(string-append module name)) 0 0))))
(if (char-numeric? (string-ref value 0))
(string-set! value 0 #\_))
value)))
;;; Compute a crc-32 for a list of characters using a per character table and
;;; return a string with the hex value. The crc is computed in two 16-bit
;;; integers to avoid having to use floating point numbers.
(define (CRC-32x2 chars crc-left crc-right)
(if (null? chars)
(let loop ((cl '()) (left crc-left) (right crc-right))
(if (and (zero? left) (zero? right))
(if (null? cl) "0" (list->string cl))
(loop (cons (string-ref "0123456789abcdef"
(remainder right 16))
cl)
(quotient left 16)
(+ (bit-lsh (remainder left 16) 12)
(quotient right 16)))))
(let ((char (char->integer (car chars))))
(crc-32x2 (cdr chars)
(bit-xor (bit-rsh crc-left 8)
(vector-ref t-left char)
(vector-ref t-left (remainder crc-right 256)))
(bit-xor (bit-or (bit-lsh (bit-and crc-left 255) 8)
(bit-rsh crc-right 8))
(vector-ref t-right char)
(vector-ref t-right (remainder crc-right 256)))))))
(define T-LEFT '#(
#x0000 #x7707 #xEE0E #x9909 #x076D #x706A #xE963 #x9E64
#x0EDB #x79DC #xE0D5 #x97D2 #x09B6 #x7EB1 #xE7B8 #x90BF
#x1DB7 #x6AB0 #xF3B9 #x84BE #x1ADA #x6DDD #xF4D4 #x83D3
#x136C #x646B #xFD62 #x8A65 #x1401 #x6306 #xFA0F #x8D08
#x3B6E #x4C69 #xD560 #xA267 #x3C03 #x4B04 #xD20D #xA50A
#x35B5 #x42B2 #xDBBB #xACBC #x32D8 #x45DF #xDCD6 #xABD1
#x26D9 #x51DE #xC8D7 #xBFD0 #x21B4 #x56B3 #xCFBA #xB8BD
#x2802 #x5F05 #xC60C #xB10B #x2F6F #x5868 #xC161 #xB666
#x76DC #x01DB #x98D2 #xEFD5 #x71B1 #x06B6 #x9FBF #xE8B8
#x7807 #x0F00 #x9609 #xE10E #x7F6A #x086D #x9164 #xE663
#x6B6B #x1C6C #x8565 #xF262 #x6C06 #x1B01 #x8208 #xF50F
#x65B0 #x12B7 #x8BBE #xFCB9 #x62DD #x15DA #x8CD3 #xFBD4
#x4DB2 #x3AB5 #xA3BC #xD4BB #x4ADF #x3DD8 #xA4D1 #xD3D6
#x4369 #x346E #xAD67 #xDA60 #x4404 #x3303 #xAA0A #xDD0D
#x5005 #x2702 #xBE0B #xC90C #x5768 #x206F #xB966 #xCE61
#x5EDE #x29D9 #xB0D0 #xC7D7 #x59B3 #x2EB4 #xB7BD #xC0BA
#xEDB8 #x9ABF #x03B6 #x74B1 #xEAD5 #x9DD2 #x04DB #x73DC
#xE363 #x9464 #x0D6D #x7A6A #xE40E #x9309 #x0A00 #x7D07
#xF00F #x8708 #x1E01 #x6906 #xF762 #x8065 #x196C #x6E6B
#xFED4 #x89D3 #x10DA #x67DD #xF9B9 #x8EBE #x17B7 #x60B0
#xD6D6 #xA1D1 #x38D8 #x4FDF #xD1BB #xA6BC #x3FB5 #x48B2
#xD80D #xAF0A #x3603 #x4104 #xDF60 #xA867 #x316E #x4669
#xCB61 #xBC66 #x256F #x5268 #xCC0C #xBB0B #x2202 #x5505
#xC5BA #xB2BD #x2BB4 #x5CB3 #xC2D7 #xB5D0 #x2CD9 #x5BDE
#x9B64 #xEC63 #x756A #x026D #x9C09 #xEB0E #x7207 #x0500
#x95BF #xE2B8 #x7BB1 #x0CB6 #x92D2 #xE5D5 #x7CDC #x0BDB
#x86D3 #xF1D4 #x68DD #x1FDA #x81BE #xF6B9 #x6FB0 #x18B7
#x8808 #xFF0F #x6606 #x1101 #x8F65 #xF862 #x616B #x166C
#xA00A #xD70D #x4E04 #x3903 #xA767 #xD060 #x4969 #x3E6E
#xAED1 #xD9D6 #x40DF #x37D8 #xA9BC #xDEBB #x47B2 #x30B5
#xBDBD #xCABA #x53B3 #x24B4 #xBAD0 #xCDD7 #x54DE #x23D9
#xB366 #xC461 #x5D68 #x2A6F #xB40B #xC30C #x5A05 #x2D02
))
(define T-RIGHT '#(
#x0000 #x3096 #x612C #x51BA #xC419 #xF48F #xA535 #x95A3
#x8832 #xB8A4 #xE91E #xD988 #x4C2B #x7CBD #x2D07 #x1D91
#x1064 #x20F2 #x7148 #x41DE #xD47D #xE4EB #xB551 #x85C7
#x9856 #xA8C0 #xF97A #xC9EC #x5C4F #x6CD9 #x3D63 #x0DF5
#x20C8 #x105E #x41E4 #x7172 #xE4D1 #xD447 #x85FD #xB56B
#xA8FA #x986C #xC9D6 #xF940 #x6CE3 #x5C75 #x0DCF #x3D59
#x30AC #x003A #x5180 #x6116 #xF4B5 #xC423 #x9599 #xA50F
#xB89E #x8808 #xD9B2 #xE924 #x7C87 #x4C11 #x1DAB #x2D3D
#x4190 #x7106 #x20BC #x102A #x8589 #xB51F #xE4A5 #xD433
#xC9A2 #xF934 #xA88E #x9818 #x0DBB #x3D2D #x6C97 #x5C01
#x51F4 #x6162 #x30D8 #x004E #x95ED #xA57B #xF4C1 #xC457
#xD9C6 #xE950 #xB8EA #x887C #x1DDF #x2D49 #x7CF3 #x4C65
#x6158 #x51CE #x0074 #x30E2 #xA541 #x95D7 #xC46D #xF4FB
#xE96A #xD9FC #x8846 #xB8D0 #x2D73 #x1DE5 #x4C5F #x7CC9
#x713C #x41AA #x1010 #x2086 #xB525 #x85B3 #xD409 #xE49F
#xF90E #xC998 #x9822 #xA8B4 #x3D17 #x0D81 #x5C3B #x6CAD
#x8320 #xB3B6 #xE20C #xD29A #x4739 #x77AF #x2615 #x1683
#x0B12 #x3B84 #x6A3E #x5AA8 #xCF0B #xFF9D #xAE27 #x9EB1
#x9344 #xA3D2 #xF268 #xC2FE #x575D #x67CB #x3671 #x06E7
#x1B76 #x2BE0 #x7A5A #x4ACC #xDF6F #xEFF9 #xBE43 #x8ED5
#xA3E8 #x937E #xC2C4 #xF252 #x67F1 #x5767 #x06DD #x364B
#x2BDA #x1B4C #x4AF6 #x7A60 #xEFC3 #xDF55 #x8EEF #xBE79
#xB38C #x831A #xD2A0 #xE236 #x7795 #x4703 #x16B9 #x262F
#x3BBE #x0B28 #x5A92 #x6A04 #xFFA7 #xCF31 #x9E8B #xAE1D
#xC2B0 #xF226 #xA39C #x930A #x06A9 #x363F #x6785 #x5713
#x4A82 #x7A14 #x2BAE #x1B38 #x8E9B #xBE0D #xEFB7 #xDF21
#xD2D4 #xE242 #xB3F8 #x836E #x16CD #x265B #x77E1 #x4777
#x5AE6 #x6A70 #x3BCA #x0B5C #x9EFF #xAE69 #xFFD3 #xCF45
#xE278 #xD2EE #x8354 #xB3C2 #x2661 #x16F7 #x474D #x77DB
#x6A4A #x5ADC #x0B66 #x3BF0 #xAE53 #x9EC5 #xCF7F #xFFE9
#xF21C #xC28A #x9330 #xA3A6 #x3605 #x0693 #x5729 #x67BF
#x7A2E #x4AB8 #x1B02 #x2B94 #xBE37 #x8EA1 #xDF1B #xEF8D
))
;;; This function converts the character "c" into numeric string of length
;;; "len" in base "base".
(define (CHAR->DL c base len)
(set! c (char->integer c))
(do ((dl '()))
((zero? len) dl)
(set! dl (cons (string-ref "0123456789abcdef" (remainder c base)) dl))
(set! c (quotient c base))
(set! len (- len 1))))
;;; Variables are initially bound and their alpha-converted value is returned
;;; by the following function. It takes the variable name and an optional
;;; list of properties and values. It returns the alphabetized name.
(define (NEWV var . pl)
(let* ((oldalpha (id-global var))
(use (cadr (memq 'use pl)))
(alpha '()))
(if (and oldalpha (memq use '(global macro lexical)))
(begin (if (and (id-module oldalpha)
(or (eq? (id-use oldalpha) 'macro)
(eq? use 'global)))
(if (id-defined oldalpha)
(report-error
"Duplicately defined symbol:" var)
(report-warning
"Duplicately defined symbol:" var)))
(if (eq? use 'global)
(begin (set! alpha oldalpha)
(set-id-lambda! alpha '())
(set-id-module! alpha '())
(set-id-vname! alpha '())
(set-id-cname! alpha '()))
(set! alpha (make-alpha var))))
(set! alpha (make-alpha var)))
(set-id-printname! alpha var)
(do ((pl pl (cddr pl)))
((null? pl)
(case (id-use alpha)
((global macro top-level)
(set-id-global! var alpha)
(if (not (eq? alpha oldalpha))
(set! global-free-vars
(cons (list var alpha) global-free-vars))))
((lexical)
(set! lexical-bound-vars
(cons (list var alpha) lexical-bound-vars)))
((label constant lambda temporary closurep)
(let ((dsa (downshift alpha)))
(set-id-printname! alpha alpha)
(if (eq? (id-use alpha) 'lambda)
(set-id-cname! alpha (hex28 module-name dsa))
(set-id-cname! alpha (hex28 "" dsa)))
(set-id-vname! alpha (hex28 "" dsa)))))
alpha)
(put alpha (car pl) (cadr pl)))))
;;; All variable names will be alpha-converted by taking the first character
;;; of their name and following it with an id number.
(define (MAKE-ALPHA var)
(let* ((c (string-ref (symbol->string var) 0))
(alpha (string->symbol (format '() "~A~A" c make-alpha-seq))))
(set! make-alpha-seq (+ make-alpha-seq 1))
(if (id-printname alpha)
(make-alpha var)
alpha)))
;;; The following function looks up a variable in the current bindings. If it
;;; is not found, then it will be added to GLOBAL-FREE-VARS. TOP-LEVEL
;;; variables which are referenced will have a symbol pointer added to the
;;; constant list so that their value can be looked up.
(define (BOUND var)
(let* ((varalist (assq var lexical-bound-vars))
(varlex (or varalist (assq var lexical-free-vars)))
(varglob (or varlex (id-global var))))
(cond (varalist
(cadr varalist))
(varlex
(set! varlex (cadr varlex))
varlex)
(varglob
(if (and (eq? (id-use varglob) 'top-level)
(not (assoc var quote-constants)))
(set! quote-constants
(cons (list var varglob) quote-constants)))
varglob)
(else
(newv var 'use 'global 'undefref current-define-name)))))
;;; Syntax errors are reported by the following function which will return
;;; (begin #t) as its value.
(define (EXPAND-ERROR form exp)
(report-error "Illegal" form "syntax:" exp)
'(begin #t))