home *** CD-ROM | disk | FTP | other *** search
- ;;; This is when the actual code generation occurs. It is entered with a
- ;;; list of expressions. Code is not as optimal as it might be, but then
- ;;; that's what the C compiler is for.
- ;;;
-
- ;* 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 gencode)
-
- ;;; External and in-line declarations.
-
- (include "plist.sch")
- (include "expform.sch")
- (include "lambdaexp.sch")
- (include "miscexp.sch")
- (include "lap.sch")
-
- ;;; Top-level globals.
-
- (define CURRENT-CODE-LAMBDA 'top-level)
-
- (define CURRENT-DEFINE-STRING '()) ; id which is the string defining the
- ; current top-level DEFINE.
-
- (define INIT-MODULES '())
-
- (define FREE-DISPLAY 0)
-
- (define MAX-DISPLAY 0)
-
- (define EMPTY-CONDITION-INFO '(()) )
-
- (define GLOBAL-CONDITION-INFO empty-condition-info)
-
- (define ERROR-ID #f)
-
- (define $_CAR-ERROR-ID #f)
-
- (define $_CDR-ERROR-ID #f)
-
- (define (GENERATE-CODE expl)
- (let ((bindings '())
- (initname (if main-program-name
- "main"
- (string-append module-name "__init")))
- (constant-lap '()))
- (set! current-code-lambda 'top-level)
- (set! current-define-name 'top-level)
- (save-current-lap #f)
- (set! max-display 0)
- (set! free-display 0)
- (set! error-id (bound 'error))
- (set! $_car-error-id (bound '$_car-error))
- (set! $_cdr-error-id (bound '$_cdr-error))
- (set! global-lap-code '())
- (emit-global-lap `(LIT "/* SCHEME->C */"))
- (emit-global-lap `(LIT))
- (emit-global-lap `(LIT "#include " #\< ,c-include-file #\>))
- (emit-global-lap '(LIT))
- (set! init-modules '())
- (if main-program-name
- (begin (emit-lap '(LIT "main( argc, argv )"))
- (emit-lap '(LIT " int argc; char *argv[];")))
- (emit-lap `(LIT "void " ,initname "()")))
- (emit-lap '(LIT "{"))
- (emit-lap '(indent 8))
- (emit-lap '(LOCALS DISPLAY 0))
- (emit-lap '(LIT "static int init = 0;"))
- (emit-lap '(LIT "if (init) return;"))
- (emit-lap '(LIT "init = 1;"))
- (if main-program-name
- (emit-lap `(INITHEAP ,heap-size "argc" "argv"
- ,(cname (id-global main-program-name))))
- (emit-lap `(INITHEAP ,heap-size 0 0 0)))
- (emit-lap '(LIT "init_constants();"))
- (set! constant-lap (emit-constants))
- (done-lap constant-lap)
- (emit-lap
- `(LIT "init_modules( "
- (CSTRING ,(string-append "(" module-name
- " SCHEME->C COMPILER " scc-version ")"))
- " );"))
- (for-each (lambda (exp)
- (set! global-condition-info empty-condition-info)
- (exp-genc 'no-value exp bindings))
- expl)
- (if main-program-name
- (let ((name (id-global main-program-name)))
- (emit-global-lap
- `(LIT "void " ,module-name "__init(){}"))
- (if name
- (emit-lap `(LIT ,(cname name)
- "( CLARGUMENTS( argc, argv ) );"))
- (report-error "Main procedure is not defined"))
- (emit-lap '(LIT "SCHEMEEXIT();")))
- (emit-lap '(SET RETURN "void")))
- (emit-lap '(indent 0))
- (emit-lap '(LIT "}"))
- (if (not (= 0 free-display))
- (report-error "Compiler error - display index is not 0"))
- (generate-init_modules)
- (done-lap (save-current-lap '()))))
-
- ;;; Code for each expression is generated by the following function. It
- ;;; returns the code which evaluates to the expression.
-
- (define (EXP-GENC loc exp bindings)
- (cond ((symbol? exp) (symbol-genc loc exp bindings))
- ((eq? (car exp) '$call) ($call-genc loc exp bindings))
- ((eq? (car exp) '$set) ($set-genc loc exp bindings))
- ((eq? (car exp) '$lambda) ($lambda-genc loc exp bindings))
- ((eq? (car exp) '$if) ($if-genc loc exp bindings))
- ((eq? (car exp) '$define) ($define-genc loc exp bindings))
- ((eq? (car exp) '$lap) (report-error "Illegal use of LAP"))
- (else
- (report-error "GENERATE-CODE compiler error" exp))))
-
- ;;; Labels are needed during the code generation and are constructed by the
- ;;; following function. ID-BOUNDREFS is used to keep track of the number of
- ;;; references.
-
- (define (MAKE-LABEL) (newv 'l 'use 'label 'gotos 0))
-
- ;;; Code labels are automatically constructed for all lambda expressions by
- ;;; the following function. Labels that are not used are removed during
- ;;; peep-hole optimization of the lap code.
-
- (define (CODE-LABEL id)
- (let ((label (lambda-code-label id)))
- (if (not label)
- (begin (set! label (make-label))
- (set-lambda-code-label! id label)))
- label))
-
- ;;; Global names are sometimes needed in the C-code and are emitted by the
- ;;; following function.
-
- (define (MAKE-C-GLOBAL)
- (newv 'temp 'use 'temporary))
-
- ;;; The optional argument (if any) of a function is returned by the following
- ;;; function.
-
- (define (OPTIONAL-ARGS id)
- (if (lambda-optvars id)
- (car (lambda-optvars id))
- '()))
-
- ;;; Variables are "looked-up" in the current bindings by the following
- ;;; function. It returns the code the access the value bound to the
- ;;; variable.
-
- (define (LOOKUP var bindings)
- (let ((offset 0)
- (code '()))
- (cond ((var-is-constant var)
- (vname var))
- ((var-is-global var)
- (emit-extern var)
- (or (vname var)
- (and (id-type var) (cname var))
- (report-error "SYMBOL does not have a value cell"
- (id-printname var))))
- ((var-in-stack var)
- (let ((displayx (id-display var)))
- (cond ((id-set! var)
- `(PAIR_CAR ,(if displayx
- `("DISPLAY" ,displayx)
- (vname var))))
- (displayx `("DISPLAY" ,displayx))
- (else (vname var)))))
- ((var-is-top-level var)
- `(SYMBOL_VALUE ,(vname var)))
- (else (report-error "Variable is not bound" (vname var))))))
-
- (define (VAR-IN-STACK var)
- (eq? (id-use var) 'lexical))
-
- (define (VAR-IS-GLOBAL var)
- (eq? (id-use var) 'global))
-
- (define (EMIT-EXTERN var)
- (if (id-lambda var)
- (set! var (lambda-name (id-lambda var))))
- (when (not (id-external var))
- (set-id-external! var #t)
- (cond ((and (id-lambda var)
- (assq (id-type var)
- '((void . EXTERNVOIDP)
- (pointer . EXTERNPOINTERP)
- (tscp . EXTERNTSCPP)
- (char . EXTERNCHARP)
- (int . EXTERNINTP)
- (shortint . EXTERNSHORTINTP)
- (longint . EXTERNLONGINTP)
- (unsigned . EXTERNUNSIGNEDP)
- (shortunsigned . EXTERNSHORTUNSIGNEDP)
- (longunsigned . EXTERNLONGUNSIGNEDP)
- (float . EXTERNFLOATP)
- (double . EXTERNDOUBLEP))))
- => (lambda (type)
- (emit-global-lap `(,(cdr type) ,(cname var)))))
- ((assq (id-type var)
- '((pointer . EXTERNPOINTER)
- (tscp . EXTERNTSCP)
- (char . EXTERNCHAR)
- (int . EXTERNINT)
- (shortint . EXTERNSHORTINT)
- (longint . EXTERNLONGINT)
- (unsigned . EXTERNUNSIGNED)
- (shortunsigned . EXTERNSHORTUNSIGNED)
- (longunsigned . EXTERNLONGUNSIGNED)
- (float . EXTERNFLOAT)
- (double . EXTERNDOUBLE)))
- => (lambda (type)
- (emit-global-lap `(,(cdr type) ,(vname var)))))
- (else
- (if (id-lambda var)
- (emit-global-lap `(EXTERNTSCPP ,(cname var))))
- (if (var-is-global var)
- (let ((vmodule (id-module var)))
- (if (vname var)
- (emit-global-lap `(EXTERNTSCP ,(vname var))))
- (if (and (not (equal? module-name vmodule))
- (not (member vmodule '("" "sc")))
- (not (member vmodule init-modules)))
- (set! init-modules
- (cons (id-module var) init-modules)))))))))
-
- (define (VAR-IS-CONSTANT var) (eq? (id-use var) 'constant))
-
- (define (VAR-IS-TOP-LEVEL var) (eq? (id-use var) 'top-level))
-
- ;;; When all code has been emitted, this function is called to emit the
- ;;; procedure "init_modules" which calls the initialization code for all
- ;;; modules used by this program.
-
- (define (GENERATE-INIT_MODULES)
- (let ((save-lap (save-current-lap '())))
- (emit-lap '(LIT "static void init_modules( compiler_version )"))
- (emit-lap '(LIT " char *compiler_version;"))
- (emit-lap '(LIT"{"))
- (emit-lap '(indent 8))
- (for-each
- (lambda (with-module)
- (emit-lap
- `(LIT ,(string-append with-module "__init();"))))
- (append init-modules with-modules))
- (emit-lap `(MAXDISPLAY ,max-display))
- (emit-lap '(indent 0))
- (emit-lap `(LIT "}"))
- (done-lap (save-current-lap save-lap))))
-
- ;;; All storage and initialization for constants is emitted at the start of
- ;;; the module's initialization function. Since vectors and lists are
- ;;; constructed from the heap, they must be registered with the run-time
- ;;; system.
-
- (define CONSTANT-SYMBOLS '())
-
- (define CONSTANT-SYMBOL-PORT '())
-
- (define (EMIT-CONSTANTS)
- (let ((save-lap (save-current-lap '())))
- (set! constant-symbols '())
- (set! constant-symbol-port (open-output-string))
- (emit-lap '(LIT "static void init_constants()"))
- (emit-lap '(LIT "{"))
- (emit-lap '(INDENT 8))
- (emit-lap '(LOCALS))
- (for-each
- (lambda (const-var)
- (let ((var (cadr const-var))
- (const (car const-var))
- (temps (save-lap-temps)))
- (emit-constant var const)
- (if (and (not (string? const)) (not (number? const))
- (not (char? const)))
- (emit-lap `(CONSTANTEXP (ADR ,(vname var)))))
- (restore-lap-temps temps)))
- quote-constants)
- (emit-lap '(INDENT 0))
- (emit-lap '(LIT "}"))
- (save-current-lap save-lap)))
-
- (define (EMIT-CONSTANT var const)
- (cond ((fixed? const)
- (display "_TSCP( " constant-symbol-port)
- (if (or (> const 2) (< const -2))
- (begin (write (+ (* 4 (quotient const 10))
- (quotient (* 4 (remainder const 10)) 10))
- constant-symbol-port)
- (write (abs (remainder (* 4 (remainder const 10)) 10))
- constant-symbol-port))
- (write (remainder (* 4 (remainder const 10)) 10)
- constant-symbol-port))
- (display " )" constant-symbol-port)
- (set-id-vname! var (get-output-string constant-symbol-port)))
- ((float? const)
- (let ((temp (make-c-global)))
- (emit-global-lap `(DEFFLOAT ,(vname temp) ,const))
- (emit-global-lap `(DEFSTATICTSCP2 ,(vname var)
- ,(vname temp)))))
- ((char? const)
- (display "_TSCP( " constant-symbol-port)
- (write (+ (* (char->integer const) 256) 18)
- constant-symbol-port)
- (display " )" constant-symbol-port)
- (set-id-vname! var (get-output-string constant-symbol-port)))
- ((string? const)
- (let ((temp (make-c-global)))
- (emit-global-lap `(DEFSTRING ,(vname temp) (CSTRING ,const)
- ,(string-length const)))
- (emit-global-lap `(DEFSTATICTSCP2 ,(vname var)
- ,(vname temp)))))
- ((symbol? const)
- (let ((temp (make-c-global)))
- (emit-global-lap `(DEFSTRING ,(vname temp)
- (CSTRING ,(symbol->string const))
- ,(string-length
- (symbol->string const))))
- (emit-global-lap `(DEFSTATICTSCP ,(vname var)))
- (emit-lap `(SET ,(vname var)
- (STRINGTOSYMBOL (U_TX (ADR ,(vname temp))))))
- (set! constant-symbols
- (cons (list const var) constant-symbols))))
- ((pair? const)
- (if (eq? (id-use var) 'constant)
- (emit-global-lap `(DEFSTATICTSCP ,(vname var))))
- (emit-constant-list (vname var) const))
- ((vector? const)
- (emit-constant var (vector->list const))
- (emit-lap `(SET ,(vname var) (LISTTOVECTOR ,(vname var)))))
- (else (report-error "EMIT-CONSTANT compile error:" const))))
-
- (define (EMIT-CONSTANT-LIST varname const)
- (cond ((pair? const)
- (emit-constant-list varname (cdr const))
- (emit-lap `(SET ,varname
- (CONS ,(emit-constant-element (car const))
- ,varname))))
- (else
- (emit-lap `(SET ,varname
- ,(emit-constant-element const))))))
-
- (define (EMIT-CONSTANT-ELEMENT const)
- (cond ((eq? const #t) "TRUEVALUE" )
- ((eq? const '()) "EMPTYLIST" )
- ((eq? const #f) "FALSEVALUE")
- ((equal? const "") "EMPTYSTRING")
- ((equal? const '#()) "EMPTYVECTOR")
- ((or (fixed? const) (char? const))
- (emit-constant 'emit-constant-kludge const))
- ((pair? const)
- (let ((temp (use-lap-temp)))
- (emit-constant-list (vname temp) const)
- (drop-lap-temp temp)
- (id-vname temp)))
- ((vector? const)
- (let ((temp (use-lap-temp)))
- (emit-constant temp const)
- (drop-lap-temp temp)
- (id-vname temp)))
- ((and (symbol? const) (assq const constant-symbols))
- => (lambda (symbol.const) (vname (cadr symbol.const))))
- (else
- (let ((temp (make-c-global)))
- (emit-constant temp const)
- (id-vname temp)))))
-