home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-12-15 | 33.4 KB | 1,085 lines |
- (include-if (null (get 'chead 'version)) "../chead.l")
- (Liszt-file tlev
- "$Header: tlev.l,v 1.17 87/12/15 17:08:51 sklower Exp $")
-
- ;;; ---- t l e v top level interface
- ;;;
- ;;; -[Tue Nov 22 09:21:27 1983 by jkf]-
-
- ;--- lisztinit : called upon compiler startup. If there are any args
- ; on the command line, we build up a call to liszt, which
- ; will do the compile. Afterwards we exit.
- ;
- (def lisztinit
- (lambda nil
- (setq fl-asm nil) ; insure it as correct value in case of int
- (let ((args (command-line-args)))
- (if args
- then (signal 2 'liszt-interrupt-signal) ; die on int
- (signal 15 'liszt-interrupt-signal) ; die on sigterm
- (setq user-top-level nil)
- (exit (apply 'liszt args))
- else (patom compiler-name)
- (patom " [")(patom franz-minor-version-number)(patom "]")
- (terpr poport)
- (setq user-top-level nil)))))
-
- (setq user-top-level 'lisztinit)
-
- ;--- liszt - v-x : list containing file name to compile and optionaly
- ; and output file name for the assembler source.
- ;
- (def liszt
- (nlambda (v-x)
- (prog (piport v-root v-ifile v-sfile v-ofile
- vp-ifile vp-sfile vps-crap
- vps-include vns-include
- asm-exit-status ntem temgc temcp
- rootreal g-arrayspecs out-path
- g-decls g-stdref pre-eval include-files
- g-fname g-trueop g-falseop g-didvectorcode
- tem temr starttime startptime startgccount
- fl-asm fl-warn fl-warnfatal fl-verb fl-inter
- fl-xref fl-uci fl-run fl-case fl-anno g-optionalp
- liszt-process-forms in-line-lambda-number
- g-skipcode g-dropnpcnt g-complrname g-fname)
-
- ;in case "S" switch given, set asm-exit-status
- ; to 0 (so garbage won't be returned).
- (setq asm-exit-status 0)
-
- ; turn on monitoring if it exists
- #+monitoring
- (errset (progn (monitor t) ; turn it on
- (print 'monitor-on)
- (terpr))
- nil)
- (setq starttime (sys:time) ; real time in seconds
- startptime (ptime)
- startgccount $gccount$)
- (setq in-line-lambda-number (sys:time))
- (cond ((null (boundp 'internal-macros))
- (setq internal-macros nil)))
- (cond ((null (boundp 'macros))
- (setq macros nil)))
- (setq er-fatal 0 er-warn 0)
- (setq vps-include nil
- vns-include nil) ;stack of ports and names
- (setq twa-list nil)
- (setq liszt-eof-forms nil)
-
- ; look for lisztrc file and return if error occured
- ; in reading it
- (cond ((eq (do-lisztrc-check) 'error)
- (return 1)))
-
- ; set up once only g variables
- (setq g-comments nil
- g-current nil ; current function name
- g-funcs nil
- g-lits nil
- g-trueloc nil
- g-tran nil
- g-allf nil ; used in xrefs
- g-reguse #+(or for-vax for-tahoe)
- (copy '((r4 0 . nil) (r3 0 . nil)
- (r2 0 . nil); (r7 0 . nil)
- (r1 0 . nil)))
- #+for-68k (copy '((a0 0 . nil) (a1 0 . nil)
- (d1 0 . nil) (d2 0 . nil)
- (d4 0 . nil) (d5 0 . nil)))
- g-trancnt 0
- g-ignorereg nil
- g-trueop #+(or for-vax for-tahoe) 'jneq ;used in e-gotot
- #+for-68k 'jne
- g-falseop #+(or for-vax for-tahoe) 'jeql ;u. in e-gotonil
- #+for-68k 'jeq
- g-compfcn nil
- g-litcnt 0)
- (setq g-spec (gensym 'S)) ; flag for special atom
- (setq g-fname "") ; no function yet
- (setq special nil) ; t if all vrbs are special
- (setq g-functype (gensym)
- g-vartype (gensym)
- g-bindtype (gensym)
- g-calltype (gensym)
- g-bindloc (gensym)
- g-localf (gensym)
- g-arrayspecs (gensym)
- g-tranloc (gensym)
- g-stdref (gensym)
- g-optionalp (gensym))
-
- ; declare these special
-
- (sstatus feature complr)
- (d-makespec 't) ; always special
-
- ; process input form
- (setq fl-asm t ; assembler file assembled
- fl-warn t ; print warnings
- fl-warnfatal nil ; warnings are fatal
- fl-verb t ; be verbose
- fl-macl nil ; compile maclisp file
- fl-anno nil ; annotate
- fl-inter nil ; do interlisp compatablity
- fl-tty nil ; put .s on tty
- fl-comments nil ; put in comments
- fl-profile nil ; profiling
- fl-tran t ; use transfer tables
- fl-vms nil ; vms hacks
- fl-case nil ; trans uc to lc
- fl-xref nil ; xrefs
- fl-run nil ; autorun capability
- fl-uci nil ; uci lisp compatibility
- )
-
- ; look in the environment for a LISZT variable
- ; if it exists, make it the first argument
- (if (not (eq '|| (setq tem (getenv 'LISZT))))
- then (setq v-x (cons (concat "-" tem) v-x)))
-
- (do ((i v-x (cdr i))) ; for each argument
- ((null i))
- (setq tem (aexplodec (car i)))
-
- (cond ((eq '- (car tem)) ; if switch
- (do ((j (cdr tem) (cdr j)))
- ((null j))
- (cond ((eq 'S (car j)) (setq fl-asm nil))
- ((eq 'C (car j)) (setq fl-comments t))
- ((eq 'm (car j)) (setq fl-macl t))
- ((eq 'o (car j)) (setq v-ofile (cadr i)
- i (cdr i)))
- ((eq 'e (car j)) (setq pre-eval (cadr i)
- i (cdr i)))
- ((eq 'i (car j)) (push (cadr i)
- include-files)
- (pop i))
- ((eq 'w (car j)) (setq fl-warn nil))
- ((eq 'W (car j)) (setq fl-warnfatal t))
- ((eq 'q (car j)) (setq fl-verb nil))
- ((eq 'Q (car j)) (setq fl-verb t))
- ((eq 'T (car j)) (setq fl-tty t))
- ((eq 'a (car j)) (setq fl-anno t))
- ((eq 'i (car j)) (setq fl-inter t))
- ((eq 'p (car j)) (setq fl-profile t))
- ((eq 'F (car j)) (setq fl-tran nil))
- ((eq 'v (car j)) (setq fl-vms t))
- ((eq 'r (car j)) (setq fl-run t))
- ((eq 'x (car j)) (setq fl-xref t))
- ((eq 'c (car j)) (setq fl-case t))
- ((eq 'u (car j)) (setq fl-uci t))
- ((eq '- (car j))) ; ignore extra -'s
- (t (comp-gerr "Unknown switch: "
- (car j))))))
- ((null v-root)
- (setq temr (reverse tem))
- (cond ((and (eq 'l (car temr))
- (eq '\. (cadr temr)))
- (setq rootreal nil)
- (setq v-root
- (apply 'concat
- (reverse (cddr temr)))))
- (t (setq v-root (car i)
- rootreal t))))
-
- (t (comp-gerr "Extra input file name: " (car i)))))
-
- ;no transfer tables in vms
- (cond (fl-vms (setq fl-tran nil)))
-
- ; if verbose mode, print out the gc messages and
- ; fasl messages, else turn them off.
- (cond (fl-verb (setq $gcprint t
- $ldprint t))
- (t (setq $gcprint nil
- $ldprint nil)))
-
- ; eval arg after -e
- (if pre-eval
- then (if (null (errset
- (eval (readlist (exploden pre-eval)))))
- then (comp-gerr "-e form caused error: "
- pre-eval)))
-
- ; load file after -i arg
- (if include-files
- then (catch
- (mapc
- '(lambda (file)
- (if (null (errset (load file)))
- then (comp-err
- "error when loading -i file: "
- file)))
- include-files)
- Comp-error))
-
- ; -c says set reader to xlate uc to lc
- (cond (fl-case (sstatus uctolc t)))
-
- ; If we are a cross compiler, then don't try to
- ; assemble our output...
- ;
- #+for-vax
- (if (or (status feature 68k) (status feature tahoe))
- then (setq fl-asm nil))
- #+for-tahoe
- (if (or (status feature vax) (status feature 68k))
- then (setq fl-asm nil))
- #+for-68k
- (if (or (status feature vax) (status feature tahoe))
- then (setq fl-asm nil))
-
- ; now see what the arguments have left us
- (cond ((null v-root)
- (comp-gerr "No file for input"))
- ((or (portp
- (setq vp-ifile
- (car (errset (infile
- (setq v-ifile
- (concat v-root '".l")))
- nil))))
- (and rootreal
- (portp
- (setq vp-ifile
- (car (errset
- (infile (setq v-ifile v-root))
- nil)))))))
- (t (comp-gerr "Couldn't open the source file :"
- (or v-ifile))))
-
-
- ; determine the name of the .s file
- ; strategy: if fl-asm is t (assemble) use (v-root).s
- ; else use /tmp/(PID).s
- ;
- ; direct asm to tty temporarily
- (setq v-sfile "tty")
- (setq vp-sfile nil)
- (if (null fl-tty) then
- (cond (fl-asm (setq v-sfile
- (concat '"/tmp/Lzt"
- (boole 1 65535
- (sys:getpid))
- '".s")))
- (t (setq v-sfile
- (if v-ofile
- then v-ofile
- else (concat v-root '".s")))))
-
- (cond ((not (portp (setq vp-sfile
- (car (errset (outfile v-sfile)
- nil)))))
- (comp-gerr "Couldn't open the .s file: "
- (or v-sfile)))))
-
-
- ; determine the name of the .o file (object file)
- ; strategy: if we aren't supposed to assemble the .s file
- ; don't worry about a name
- ; else if a name is given, use it
- ; else if use (v-root).o
- ; if profiling, use .o
- (cond ((or v-ofile (null fl-asm))) ;ignore
- ((null fl-profile) (setq v-ofile (concat v-root ".o")))
- (t (setq v-ofile (concat v-root ".o"))))
-
- ; determine the name of the .x file (xref file)
- ; strategy: if fl-xref and v-ofile is true, then use
- ; v-ofile(minus .o).x, else use (v-root).x
- ;
- (if fl-xref
- then ; check for ending with .X for any X
- (setq v-xfile
- (if v-ofile
- then (let ((ex (nreverse
- (exploden v-ofile))))
- (if (eq #/. (cadr ex))
- then (implode
- (nreverse
- `(#/x #/.
- ,@(cddr ex))))
- else (concat v-ofile ".x")))
- else (concat v-root ".x")))
- (if (portp
- (setq vp-xfile
- (car (errset (outfile v-xfile)))))
- thenret
- else (comp-gerr "Can't open the .x file: "
- v-xfile)))
- (cond ((checkfatal) (return 1)))
-
- ; g-complrname is a symbol which should be unique to
- ; each fasl'ed file. It will contain the string which
- ; describes the name of this file and the compiler
- ; version.
- (if fl-anno
- then (setq g-complrname (concat "fcn-in-" v-ifile))
- (Push g-funcs
- `(eval (setq ,g-complrname
- ,(get_pname
- (concat v-ifile
- " compiled by "
- compiler-name
- " on "
- (status ctime)))))))
-
-
- (setq readtable (makereadtable nil)) ; use new readtable
-
-
- ; if the macsyma flag is set, change the syntax to the
- ; maclisp standard syntax. We must be careful that we
- ; dont clobber any syntax changes made by files preloaded
- ; into the compiler.
-
- (cond (fl-macl (setsyntax '\/ 'vescape) ; 143 = vesc
-
- (cond ((eq 'vescape (getsyntax '\\))
- (setsyntax '\\ 'vcharacter)))
-
- (cond ((eq 'vleft-bracket (getsyntax '\[))
- (setsyntax '\[ 'vcharacter)
- (setsyntax '\] 'vcharacter)))
- (setq ibase 8.)
- (sstatus uctolc t)
-
- (d-makespec 'ibase) ; to be special
- (d-makespec 'base)
- (d-makespec 'tty)
-
- (errset (cond ((null (getd 'macsyma-env))
- (load 'machacks)))
- nil))
- (fl-uci (load "ucifnc")
- (cvttoucilisp)))
-
- (cond (fl-inter (putprop '* 'cc-ignore 'fl-exprcc) ;comment
- (remprop '* 'fl-expr)
- ))
-
- (cond ((checkfatal) (return 1))) ; leave if fatal errors
-
- (if fl-verb
- then (comp-msg "Compilation begins with " compiler-name )
- (comp-msg "source: " v-ifile ", result: "
- (cond (fl-asm v-ofile) (t v-sfile))))
-
- (setq piport vp-ifile) ; set to standard input
- (setq liszt-root-name v-root
- liszt-file-name v-ifile)
-
-
- (if fl-run then (d-printautorun))
-
- (if fl-profile then (e-write1 '".globl mcount"))
- loop
-
- ; main loop of the compiler. It reads a form and
- ; compiles it. It continues to compile forms from
- ; liszt-process-forms was long at that list is
- ; non-empty. This allows one form to spawn off other
- ; forms to be compiled (an alternative to (progn 'compile))
- ;
- (cond ((atom (list ; list for debugging,
- ; errset for production.
- (do ((i (read piport '<<end-of-file>>)
- (read piport '<<end-of-file>>)))
- ((eq i '<<end-of-file>>) nil)
- (setq liszt-process-forms
- (cons i liszt-process-forms))
- (do ((this (car liszt-process-forms)
- (car liszt-process-forms)))
- ((null liszt-process-forms))
- (unpush liszt-process-forms)
- (catch (liszt-form this) Comp-error)))))
- (catch (comp-err "Lisp error during compilation")
- Comp-error)
- (setq piport nil)
- (setq er-fatal (1+ er-fatal))
- (return 1)))
-
- (close piport)
-
- ; if doing special character stuff (maclisp) reassert
- ; the state
-
- (cond (vps-include
- (comp-note " done include")
- (setq piport (car vps-include)
- vps-include (cdr vps-include)
- v-ifile (car vns-include)
- vns-include (cdr vns-include))
- (go loop)))
-
- (cond (liszt-eof-forms
- (do ((ll liszt-eof-forms (cdr ll)))
- ((null ll))
- (cond ((atom (errset (liszt-form (car ll))))
- (catch
- (comp-note "Lisp error during eof forms")
- Comp-error)
- (setq piport nil)
- (return 1))))))
-
- ; reset input base
- (setq ibase 10.)
- (setq readtable (makereadtable t))
- (sstatus uctolc nil) ; turn off case conversion
- ; so bindtab will not have |'s
- ; to quote lower case
- (d-bindtab)
-
- (d-printdocstuff) ; describe this compiler
-
- (cond ((portp vp-sfile)
- (close vp-sfile))) ; close assembler language file
-
- ; if warnings are to be considered fatal, and if we
- ; have seen to many warnings, make it fatal
- (cond ((and fl-warnfatal (> er-warn 0))
- (comp-gerr "Too many warnings")))
-
- ; check for fatal errors and don't leave if so
- (cond ((checkfatal)
- (if fl-asm ; unlink .s file
- then (sys:unlink v-sfile)) ; if it is a tmp
- (return 1))) ; and ret with error status
-
- (comp-note "Compilation complete")
-
- (setq tem (Divide (difference (sys:time) starttime) 60))
- (setq ntem (ptime))
-
- (setq temcp (Divide (difference (car ntem) (car startptime))
- 3600))
-
- (setq temgc (Divide (difference (cadr ntem) (cadr startptime))
- 3600))
-
- (comp-note " Time: Real: " (car tem) ":" (cadr tem)
- ", CPU: " (car temcp) ":" (quotient (cadr temcp) 60.0)
- ", GC: " (car temgc) ":" (quotient (cadr temgc) 60.0)
- " for "
- (difference $gccount$ startgccount)
- " gcs")
-
- (cond (fl-xref
- (comp-note "Cross reference being generated")
- (print (list 'File v-ifile) vp-xfile)
- (terpr vp-xfile)
- (do ((ii g-allf (cdr ii)))
- ((null ii))
- (print (car ii) vp-xfile)
- (terpr vp-xfile))
- (close vp-xfile)))
-
-
- ; the assember we use must generate the new a.out format
- ; with a string table. We will assume that the assembler
- ; is in /usr/lib/lisp/as so that other sites can run
- ; the new assembler without installing the new assembler
- ; as /bin/as
- (cond (fl-asm ; assemble file
- (comp-note "Assembly begins")
- (cond ((not
- (zerop
- (setq asm-exit-status
- (*process
- (concat
- lisp-library-directory
- "/as "
- #+(or for-vax for-tahoe) "-V" ; use virt mem
- " -o "
- v-ofile
- " "
- v-sfile)))))
- (comp-gerr "Assembler detected error, code: "
- asm-exit-status)
- (comp-note "Assembler temp file " v-sfile
- " is not unlinked"))
- (t (comp-note "Assembly completed successfully")
- (errset (sys:unlink v-sfile)); unlink tmp
- ; file
- (if fl-run
- then (errset
- (sys:chmod v-ofile #O775)))))))
-
- #+(and sun (not unisoft))
- (if (and v-ofile fl-run)
- then (if (null
- (errset (let ((port (fileopen v-ofile "r+")))
- (fseek port 20 0)
- (tyo 0 port)
- (tyo 0 port)
- (tyo 128 port)
- (tyo 0 port)
- (close port))))
- then (comp-err
- "Error while fixing offset in object file: "
- v-ofile)))
-
- (setq readtable original-readtable)
- #+monitoring
- (errset (progn (monitor) ; turn off monitoring
- (print 'monitor-off))
- nil)
- (sstatus nofeature complr)
- (return asm-exit-status))))
-
- (def checkfatal
- (lambda nil
- (cond ((greaterp er-fatal 0)
- (catch (comp-err "Compilation aborted due to previous errors")
- Comp-error)
- t))))
-
- ;--- do-lisztrc-check
- ; look for a liszt init file named
- ; .lisztrc or lisztrc or $HOME/.lisztrc or $HOME/lisztrc
- ; followed by .o or .l or nothing
- ; return the symbol 'error' if an error occured while reading.
- ;
- (defun do-lisztrc-check nil
- (do ((dirs `("." ,(getenv 'HOME)) (cdr dirs))
- (val)
- ($gcprint nil)
- ($ldprint nil))
- ((null dirs))
- (if (setq val
- (do ((name '(".lisztrc" "lisztrc") (cdr name))
- (val))
- ((null name))
- (if (setq val
- (do ((ext '(".o" ".l" "") (cdr ext))
- (file))
- ((null ext))
- (if (probef
- (setq file (concat (car dirs)
- "/"
- (car name)
- (car ext))))
- then (if (atom (errset (load file)))
- then (comp-msg
- "Error loading liszt init file "
- file N
- "Compilation aborted" N)
- (return 'error)
- else (return t)))))
- then (return val))))
- then (return val))))
-
-
- ;--- liszt-form - i : form to compile
- ; This compiles one form.
- ;
- (def liszt-form
- (lambda (i)
- (prog (tmp v-x)
- ; macro expand
- loop
- (setq i (d-macroexpand i))
- ; now look at what is left
- (cond ((not (dtpr i)) (Push g-funcs `(eval ,i)))
- ((eq (car i) 'def)
- (cond (fl-verb (print (cadr i)) (terpr)(drain)))
- (d-dodef i))
- ((memq (car i) '(liszt-declare declare))
- (funcall 'liszt-declare (cdr i)))
- ((eq (car i) 'eval-when) (doevalwhen i))
- ((and (eq (car i) 'progn) (equal (cadr i) '(quote compile)))
- ((lambda (internal-macros) ; compile macros too
- (mapc 'liszt-form (cddr i)))
- t))
- ((or (and (eq (car i) 'includef) (setq tmp (eval (cadr i))))
- (and (eq (car i) 'include ) (setq tmp (cadr i))))
- (cond ((or (portp (setq v-x
- (car (errset (infile tmp) nil))))
- (portp (setq v-x
- (car
- (errset
- (infile
- (concat
- lisp-library-directory
- "/"
- tmp))
- nil))))
- (portp (setq v-x
- (car (errset (infile (concat tmp
- '".l"))
- nil)))))
- (setq vps-include (cons piport vps-include))
- (setq piport v-x)
- (comp-note " INCLUDEing file: " tmp)
- (setq vns-include (cons v-ifile vns-include)
- v-ifile tmp))
- (t (comp-gerr "Cannot open include file: " tmp))))
- ((eq (car i) 'comment) nil) ; just ignore comments
- (t ; we have to macro expand
- ; certain forms we would normally
- ; just dump in the eval list. This is due to hacks in
- ; the mit lisp compiler which are relied upon by certain
- ; code from mit.
- (setq i (d-fullmacroexpand i))
-
- (Push g-funcs `(eval ,i)))))))
-
- ;--- d-dodef :: handle the def form
- ; - form : a def form: (def name (type args . body))
- ;
- (defun d-dodef (form)
- (prog (g-ftype g-args body lambdaform symlab g-arginfo g-compfcn g-decls)
-
-
- (setq g-arginfo 'empty)
-
- loop
- ; extract the components of the def form
- (setq g-fname (cadr form))
- (if (dtpr (caddr form))
- then (setq g-ftype (caaddr form)
- g-args (cadaddr form)
- body (cddaddr form)
- lambdaform (caddr form)
- symlab (gensym 'F))
- else (comp-gerr "bad def form " form))
-
- ; check for a def which uses the mit hackish &xxx forms.
- ; if seen, convert to a standard form and reexamine
- ; the vax handles these forms in a special way.
- #+for-68k
- (if (or (memq '&rest g-args)
- (memq '&optional g-args)
- (memq '&aux g-args))
- then (setq form
- `(def ,(cadr form) ,(lambdacvt (cdr lambdaform))))
- (go loop))
-
- ; check for legal function name.
- ; then look at the type of the function and update the data base.
- (if (null (atom g-fname))
- then (comp-err "bad function name")
- else (setq g-flocal (get g-fname g-localf)) ; check local decl.
- ; macros are special, they are always evaluated
- ; and sometimes compiled.
- (if (and (not g-flocal) (eq g-ftype 'macro))
- then (eval form)
- (if (and (null macros)
- (null internal-macros))
- then (comp-note g-fname
- " macro will not be compiled")
- (return nil))
- (Push g-funcs `(macro ,symlab ,g-fname))
- (if fl-anno then (setq g-arginfo nil)) ; no arg info
- elseif g-flocal
- then (if (null (or (eq g-ftype 'lambda)
- (eq g-ftype 'nlambda)))
- then (comp-err
- "bad type for local fcn: " g-ftype))
- (if (or (memq '&rest g-args)
- (memq '&optional g-args)
- (memq '&aux g-args))
- then (comp-err
- "local functions can't use &keyword's "
- g-fname))
- elseif (or (eq g-ftype 'lambda)
- (eq g-ftype 'lexpr))
- then (push `(lambda ,symlab ,g-fname) g-funcs)
- (putprop g-fname 'lambda g-functype)
- elseif (eq g-ftype 'nlambda)
- then (Push g-funcs `(nlambda ,symlab ,g-fname))
- (putprop g-fname 'nlambda g-functype)
- else (comp-err " bad function type " g-ftype)))
- (setq g-skipcode nil) ;make sure we aren't skipping code
- (forcecomment `(fcn ,g-ftype ,g-fname))
- (if g-flocal
- then (comp-note g-fname " is a local function")
- (e-writel (car g-flocal))
- else (if (null fl-vms) then (e-write2 '".globl" symlab))
- (e-writel symlab))
- (setq g-locs nil g-loccnt 0 g-labs nil g-loc 'reg g-cc nil
- g-ret t g-topsym (d-genlab))
- (if fl-xref then (setq g-refseen (gensym) g-reflst nil))
- (d-clearreg)
- #+for-68k (init-regmaskvec)
- ; set up global variables which maintain knowledge about
- ; the stack. these variables are set up as if the correct
- ; number of args were passed.
- (setq g-compfcn t) ; now compiling a function
- (push nil g-labs) ; no labels in a lambda
- (setq g-currentargs (length g-args))
- (d-prelude) ; do beginning stuff
-
- ; on the vax, we handle & keywords in a special way in
- ; d-outerlambdacomp. This function also sets g-arginfo.
- #+(or for-vax for-tahoe)
- (d-outerlambdacomp g-fname g-args (cddr lambdaform))
-
- #+for-68k
- (progn
- (push (cons 'lambda 0) g-locs)
- (mapc '(lambda (x)
- (push nil g-locs)
- (incr g-loccnt))
- g-args)
- ; set g-arginfo if this is a lambda. If it is a lexpr, then
- ; we don't give all the info we could.
- (setq g-arginfo
- (if (eq g-ftype 'lambda)
- then (cons g-loccnt g-loccnt)))
- (d-lambbody lambdaform))
-
- (d-fini)
- (setq g-compfcn nil) ; done compiling a fcn
- (if fl-xref then
- (Push g-allf
- (cons g-fname
- (cons (cond (g-flocal (cons g-ftype 'local))
- (t g-ftype))
- g-reflst))))
- (if (and fl-anno (not (eq 'empty g-arginfo)))
- then (Push g-funcs `(eval (putprop
- ',g-fname
- (list ',g-arginfo
- ,g-complrname)
- 'fcn-info))))
- ; by storing argument count information during compilation
- ; we can arg number check calls to this function which occur
- ; further on.
- (if (not (eq 'empty g-arginfo))
- then (putprop g-fname (list g-arginfo) 'fcn-info))))
-
- ;--- d-lambdalistcheck :: scan lambda var list for & forms
- ; return
- ; (required optional rest op-p body)
- ; required - list of required args
- ; optional - list of (variable default [optional-p])
- ; rest - either nil or the name of a variable for optionals
- ; op-p - list of variables set to t or nil depending if optional exists
- ; body - body to compile (has &aux's wrapped around it in lambdas)
- ;
- #+(or for-vax for-tahoe)
- (defun d-lambdalistcheck (list body)
- (do ((xx list (cdr xx))
- (state 'req)
- (statechange)
- (arg)
- (req)(optional)(rest)(op-p)(aux))
- ((null xx)
- (list (nreverse req)
- (nreverse optional)
- rest
- (nreverse op-p)
- (d-lambda-aux-body-convert body (nreverse aux))))
- (setq arg (car xx))
- (if (memq arg '(&optional &rest &aux))
- then (setq statechange arg)
- else (setq statechange nil))
- (caseq state
- (req
- (if statechange
- then (setq state statechange)
- elseif (and (symbolp arg) arg)
- then (push arg req)
- else (comp-err " illegal lambda variable " arg)))
- (&optional
- (if statechange
- then (if (memq statechange '(&rest &aux))
- then (setq state statechange)
- else (comp-err "illegal form in lambda list "
- xx))
- elseif (symbolp arg)
- then ; optional which defaults to nil
- (push (list arg nil) optional)
- elseif (dtpr arg)
- then (if (and (symbolp (car arg))
- (symbolp (caddr arg)))
- then ; optional with default
- (push arg optional)
- ; save op-p
- (if (cddr arg)
- then (push (caddr arg) op-p)))
- else (comp-err "illegal &optional form "
- arg)))
- (&rest
- (if statechange
- then (if (eq statechange '&aux)
- then (setq state statechange)
- else (comp-err "illegal lambda variable form "
- xx))
- elseif rest
- then (comp-err
- "more than one rest variable in lambda list"
- arg)
- else (setq rest arg)))
- (&aux
- (if statechange
- then (comp-err "illegal lambda form " xx)
- elseif (and (symbolp arg) arg)
- then (push (list arg nil) aux)
- elseif (and (dtpr arg) (and (symbolp (car arg))
- (car arg)))
- then (push arg aux)))
- (t (comp-err "bizzarro internal compiler error ")))))
-
- ;--- d-lambda-aux-body-convert :: convert aux's to lambdas
- ; give a function body and a list of aux variables
- ; and their inits, place a lambda initializing body around body
- ; for each lambda (basically doing a let*).
- ;
- #+(or for-vax for-tahoe)
- (defun d-lambda-aux-body-convert (body auxlist)
- (if (null auxlist)
- then body
- else `(((lambda (,(caar auxlist))
- ,@(d-lambda-aux-body-convert body (cdr auxlist)))
- ,(cadar auxlist)))))
-
- ;--- d-outerlambdacomp :: compile a functions outer lambda body
- ; This function compiles the lambda expression which defines
- ; the function. This lambda expression differs from the kind that
- ; appears within a function because
- ; 1. we aren't sure that the correct number of arguments have been stacked
- ; 2. the keywords &optional, &rest, and &aux may appear
- ;
- ; funname - name of function
- ; lambdalist - the local argument list, (with possible keywords)
- ; body - what follows the lambdalist
- ;
- ;
- ;
- #+(or for-vax for-tahoe)
- (defun d-outerlambdacomp (funname lambdalist body)
- (let (((required optional rest op-p newbody)
- (d-lambdalistcheck lambdalist body))
- (g-decls g-decls)
- (reqnum 0) maxwithopt labs (maxnum -1) args)
- (d-scanfordecls body)
- ; if this is a declared lexpr, we aren't called
- ;
- (if (and (null optional) (null rest))
- then ; simple, the number of args is required
- ; if lexpr or local function, then don't bother
- (if (and (not g-flocal)
- (not (eq g-ftype 'lexpr)))
- then (d-checkforfixedargs
- funname
- (setq reqnum (setq maxnum (length required)))))
- else ; complex, unknown number of args
- ; cases:
- ; optional, no rest
- ; optional, with rest
- ; no optional, rest + required
- ; no optional, rest + no required
- (setq reqnum (length required)
- maxwithopt (+ reqnum (length optional))
- maxnum (if rest then -1 else maxwithopt))
- ; determine how many args were given
- (e-sub3 '#.lbot-reg '#.np-reg '#.lbot-reg)
- #+for-vax (e-write4 'ashl '$-2 '#.lbot-reg '#.lbot-reg)
- #+for-tahoe (e-write4 'shar '$2 '#.lbot-reg '#.lbot-reg)
- ;
- (if (null optional)
- then ; just a rest
- (let ((oklab (d-genlab))
- (lllab (d-genlab))
- (nopushlab (d-genlab)))
- (if (> reqnum 0)
- then (e-cmp '#.lbot-reg `($ ,reqnum))
- (e-write2 'jgeq oklab)
- ; not enough arguments given
- (d-wnaerr funname reqnum -1)
- (e-label oklab))
- (e-pushnil 1)
- (if (> reqnum 0)
- then (e-sub `($ ,reqnum) '#.lbot-reg)
- else (e-tst '#.lbot-reg))
- (e-write2 'jleq nopushlab)
- (e-label lllab)
- (e-quick-call '_qcons)
- (d-move 'reg 'stack)
- #+for-vax (e-write3 'sobgtr '#.lbot-reg lllab)
- #+for-tahoe (progn (e-sub '($ 1) '#.lbot-reg)
- (e-write2 'bgtr lllab))
- (e-label nopushlab))
- else ; has optional args
- ; need one label for each optional plus 2
- (do ((xx optional (cdr xx))
- (res (list (d-genlab) (d-genlab))))
- ((null xx) (setq labs res))
- (push (d-genlab) res))
- ; push nils for missing optionals
- ; one case for required amount and one for
- ; each possible number of optionals
- (e-write4 'casel
- '#.lbot-reg `($ ,reqnum)
- `($ ,(- maxwithopt reqnum)))
- #+for-tahoe (e-write2 '.align '1)
- (e-label (car labs))
- (do ((xx (cdr labs) (cdr xx))
- (head (car labs)))
- ((null xx))
- (e-write2 '.word (concat (car xx) "-" head)))
- ; get here (when running code) if there are more
- ; than the optional number of args or if there are
- ; too few args. If &rest is given, it is permitted
- ; to have more than the required number
- (let ((dorest (d-genlab))
- (again (d-genlab))
- (afterpush (d-genlab)))
- (if rest
- then ; check if there are greater than
- ; the required number
- ; preserve arg #
- (C-push '#.lbot-reg)
- (e-sub `($ ,maxwithopt) '#.lbot-reg)
- (e-write2 'jgtr dorest)
- (C-pop '#.lbot-reg))
- ; wrong number of args
- (d-wnaerr funname reqnum maxnum)
- (if rest
- then ; now cons the rest forms
- (e-label dorest)
- (e-pushnil 1) ; list ends with nil
- (e-label again)
- (e-quick-call '_qcons)
- (d-move 'reg 'stack)
- ; and loop
- #+for-vax (e-write3 'sobgtr '#.lbot-reg again)
- #+for-tahoe (progn (e-sub '($ 1) '#.lbot-reg)
- (e-write2 'bgtr again))
- ; arg #
- (C-pop '#.lbot-reg)
- (e-goto afterpush))
- ; push the nils on the optionals
- (do ((xx (cdr labs) (cdr xx)))
- ((null xx))
- (e-label (car xx))
- ; if we have exactly as many arguments given
- ; as the number of optionals, then we stack
- ; a nil if there is a &rest after
- ; the optionals
- (if (null (cdr xx))
- then (if rest
- then (e-pushnil 1))
- else (e-pushnil 1)))
- (e-label afterpush))))
- ; for optional-p's stack t's
- (mapc '(lambda (form) (d-move 'T 'stack)) op-p)
-
- ; now the variables must be shallow bound
- ; creat a list of all arguments
- (setq args (append required
- (mapcar 'car optional)
- (if rest then (list rest))
- op-p))
-
- (push (cons 'lambda 0) g-locs)
- (mapc '(lambda (x)
- (push nil g-locs))
- args)
- (setq g-loccnt (length args))
- (d-bindlamb args) ; do shallow binding if necessary
- ;
- ; if any of the optionals have non null defaults or
- ; optional-p's, we have to evaluate their defaults
- ; or set their predicates.
- ; first, see if it is necessary
- (if (do ((xx optional (cdr xx)))
- ((null xx) nil)
- (if (or (cadar xx) ; if non null default
- (caddar xx)); or predicate
- then (return t)))
- then (makecomment '(do optional defaults and preds))
- ; create labels again
- ; need one label for each optional plus 1
- (do ((xx optional (cdr xx))
- (res (list (d-genlab) )))
- ((null xx) (setq labs res))
- (push (d-genlab) res))
- ; we need to do something if the argument count
- ; is between the number of required arguments and
- ; the maximum number of args with optional minus 1.
- ; we have one case for the required number and
- ; one for each optional except the last optional number
- ;
- (let ((afterthis (d-genlab)))
- (e-write4 'casel
- '#.lbot-reg `($ ,reqnum)
- `($ ,(- maxwithopt reqnum 1)))
- #+for-tahoe (e-write2 '.align '1)
- (e-label (car labs))
- (do ((xx (cdr labs) (cdr xx))
- (head (car labs)))
- ((null xx))
- (e-write2 '.word (concat (car xx) "-" head)))
- (e-goto afterthis)
- (do ((ll (cdr labs) (cdr ll))
- (op optional (cdr op))
- (g-loc nil)
- (g-cc nil)
- (g-ret nil))
- ((null ll))
- (e-label (car ll))
- (if (caddar op)
- then (d-exp `(setq ,(caddar op) nil)))
- (if (cadar op)
- then (d-exp `(setq ,(caar op) ,(cadar op)))))
- (e-label afterthis)))
-
- ; now compile the function
- (d-clearreg)
- (setq g-arginfo
- (if (eq g-ftype 'nlambda)
- then nil
- else (cons reqnum (if (>& maxnum 0) then maxnum else nil))))
- (makecomment '(begin-fcn-body))
- (d-exp (do ((ll newbody (cdr ll))
- (g-loc)
- (g-cc)
- (g-ret))
- ((null (cdr ll)) (car ll))
- (d-exp (car ll))))
- (d-unbind)))
-
- #+(or for-vax for-tahoe)
- (defun d-checkforfixedargs (fcnname number)
- (let ((oklab (d-genlab)))
- (makecomment `(,fcnname should-have-exactly ,number args))
- ; calc -4*# of args
- (e-sub '#.np-reg '#.lbot-reg)
- (e-cmp '#.lbot-reg `($ ,(- (* number 4))))
- (e-write2 'jeql oklab)
- (d-wnaerr fcnname number number)
- (e-label oklab)))
-
- ;--- d-wnaerr :: generate code to call wrong number of args error
- ; name is the function name,
- ; min is the minumum number of args for this function
- ; max is the maximum number (-1 if there is no maximum)
- ; we encode the min and max in the way shown below.
- ;
- #+(or for-vax for-tahoe)
- (defun d-wnaerr (name min max)
- (makecomment `(arg error for fcn ,name min ,min max ,max))
- (e-move 'r10 '#.lbot-reg)
- (C-push `($ ,(+ (* min 1000) (+ max 1))))
- (C-push (e-cvt (d-loclit name nil)))
- #+for-vax (e-write3 'calls '$2 '_wnaerr)
- #+for-tahoe (e-write3 'callf '$12 '_wnaerr))
-
- ;--- d-genlab :: generate a pseudo label
- ;
- (defun d-genlab nil
- (gensym 'L))
-
- ;--- liszt-interrupt-signal
- ; if we receive a interrupt signal (commonly a ^C), then
- ; unlink the .s file if we are generating a temporary one
- ; and exit
- (defun liszt-interrupt-signal (sig)
- (if (and fl-asm (boundp 'v-sfile) v-sfile)
- then (sys:unlink v-sfile))
- (exit 1))
-