; A compiler for Franz lisp
; Copyright (c) 1980 , The Regents of the University of California.
; Section INIT -- initialization and macros
(eval-when (compile eval)
;the version number is maintained by hand, and is written twice
; once for the benefit of the user
(setq compiler-name "Lisp Compiler 5.0")
; and the other time for SCCS's what command
(setq sccs-compiler-name "@(#)Liszt version 5.0")
(setq sectioncarid "@(#)car.l 5.4 11/11/80") ; id for SCCS
(setq original-readtable readtable)
(setq raw-readtable (makereadtable t))
(putprop 'and 'cc-and 'fl-exprcc)
(putprop 'arg 'cc-arg 'fl-exprcc)
(putprop 'atom 'cc-atom 'fl-exprcc)
(putprop 'bigp 'cc-bigp 'fl-exprcc)
(putprop 'bcdp 'cc-bcdp 'fl-exprcc)
(putprop '*catch 'c-*catch 'fl-expr)
(putprop 'comment 'cc-ignore 'fl-exprcc)
(putprop 'cond 'c-cond 'fl-expr)
(putprop 'cons 'c-cons 'fl-expr)
(putprop 'cxr 'c-cxr 'fl-exprcc)
(putprop 'declare 'c-declare 'fl-expr)
(putprop 'do 'c-do 'fl-expr)
(putprop 'dtpr 'cc-dtpr 'fl-exprcc)
(putprop 'eq 'cc-eq 'fl-exprcc)
(putprop 'equal 'cc-equal 'fl-exprcc)
(putprop '= 'cc-equal 'fl-exprcc)
(putprop 'errset 'c-errset 'fl-expr)
(putprop 'fixp 'cc-fixp 'fl-exprcc)
(putprop 'floatp 'cc-floatp 'fl-exprcc)
(putprop 'get 'c-get 'fl-expr)
(putprop 'go 'c-go 'fl-expr)
(putprop 'list 'c-list 'fl-expr)
(putprop 'map 'cm-map 'fl-exprm)
(putprop 'mapc 'cm-mapc 'fl-exprm)
(putprop 'mapcan 'cm-mapcan 'fl-exprm)
(putprop 'mapcar 'cm-mapcar 'fl-exprm)
(putprop 'mapcon 'cm-mapcon 'fl-exprm)
(putprop 'maplist 'cm-maplist 'fl-exprm)
(putprop 'memq 'cc-memq 'fl-exprcc)
(putprop 'not 'cc-not 'fl-exprcc)
(putprop 'null 'cc-not 'fl-exprcc)
(putprop 'numberp 'cc-numberp 'fl-exprcc)
(putprop 'or 'cc-or 'fl-exprcc)
(putprop 'prog 'c-prog 'fl-expr)
(putprop 'progn 'cm-progn 'fl-exprm)
(putprop 'prog1 'cm-prog1 'fl-exprm)
(putprop 'prog2 'cm-prog2 'fl-exprm)
(putprop 'quote 'cc-quote 'fl-exprcc)
(putprop 'return 'c-return 'fl-expr)
(putprop 'rplaca 'c-rplaca 'fl-expr)
(putprop 'rplacd 'c-rplacd 'fl-expr)
(putprop 'setarg 'c-setarg 'fl-expr)
(putprop 'setq 'cc-setq 'fl-exprcc)
(putprop 'stringp 'cc-stringp 'fl-exprcc)
(putprop 'symbolp 'cc-symbolp 'fl-exprcc)
(putprop 'symeval 'cm-symeval 'fl-exprm)
(putprop '*throw 'c-*throw 'fl-expr)
(putprop 'typep 'cc-typep 'fl-exprcc)
(putprop 'zerop 'cm-zerop 'fl-exprm)
(putprop '1+ 'c-1+ 'fl-expr)
(putprop '1- 'c-1- 'fl-expr)
(putprop '+ 'c-+ 'fl-expr)
(putprop '- 'c-- 'fl-expr)
(putprop '* 'c-* 'fl-expr)
(putprop '/ 'c-/ 'fl-expr)
(putprop '\\ 'c-\\ 'fl-expr)
; Section INTERF -- user interface
;--- lisztinit : called upon compiler startup. If there are any args
; on the command line, we build up a call to lcf, which
; will do the compile. Afterwards we exit.
(cond ((greaterp (argv -1) 1) ; build up list of args
(do ((i (1- (argv -1)) (1- i)) (arglis))
(setq user-top-level nil)
(exit (apply 'liszt arglis)))
(setq arglis (cons (argv i) arglis))))
(setq user-top-level nil)))))
(setq user-top-level 'lisztinit)
;--- lcf - v-x : list containing file name to compile and optionaly
; and output file name for the assembler source.
(prog (piport v-root v-ifile v-sfile v-ofile
vp-ifile vp-sfile vps-crap
tem temr starttime startptime startgccount
fl-asm fl-warn fl-verb fl-inter fl-xref fl-uci
; turn on monitoring if it exists
(errset (progn (monitor t) ; turn it on
(setq starttime (syscall 13) ; real time in seconds
(cond ((null (boundp 'internal-macros))
(setq internal-macros nil)))
(cond ((null (boundp 'macros))
(setq liszt-eof-forms nil)
; set up once only g variables
g-current nil ; current function name
g-allf nil ; used in xrefs
g-reguse '((r5 0 . nil) (r4 0 . nil) (r3 0 . nil)
(r2 0 . nil) (r7 0 . nil) (r1 0 . nil))
(setq g-spec (gensym 'S)) ; flag for special atom
(setq special nil) ; t if all vrbs are special
(setq g-functype (gensym)
(d-makespec 't) ; always special
(setq fl-asm t ; assembler file assembled
fl-warn t ; print warnings
fl-macl nil ; compile maclisp file
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-uci nil ; uci lisp compatibility
(do ((i v-x (cdr i))) ; for each argument
(setq tem (aexplodec (car i)))
(cond ((eq '- (car tem)) ; if switch
(do ((j (cdr tem) (cdr 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)
((eq 'w (car j)) (setq fl-warn nil))
((eq 'q (car j)) (setq fl-verb nil))
((eq 'T (car j)) (setq fl-tty 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 'x (car j)) (setq fl-xref t))
((eq 'u (car j)) (setq fl-uci t))
(t (comp-gerr "Unknown switch: "
(setq temr (reverse tem))
(cond ((and (eq 'l (car temr))
(setq v-root (apply 'concat (reverse (cddr temr)))))
(t (comp-gerr "Extra input file name: " (car i)))))
(cond (fl-vms (setq fl-tran nil))) ; no transfer tables in vms
; now see what the arguments have left us
(comp-gerr "No file for input"))
(infile (setq v-ifile v-root))
(t (comp-gerr "Couldn't open the source file :"
; determine the name of the .s file
; strategy: if fl-asm is t (only assemble) use (v-root).s
; direct asm to tty temporarily
(cond (fl-asm (setq v-sfile (concat '"/tmp/jkf"
(t (setq v-sfile (concat v-root '".s"))))
(cond ((not (portp (setq vp-sfile
(car (errset (outfile v-sfile)
(comp-gerr "Couldn't open the .s file: "
; 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
(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 is true, then use (v-root).x
(car (errset (outfile (setq v-xfile
(concat v-root ".x"))))))))
(comp-gerr "Can't open the .x file" (or v-xfile))))))
(cond ((checkfatal) (return 1)))
(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
(cond (fl-macl (setsyntax '\/ 143) ; 143 = vesc
(cond ((equal 143 (status syntax \\))
(setsyntax '\| 138) ; 138 = vdq
(cond ((equal 198 (status syntax \[))
(d-makespec 'ibase) ; to be special
(errset (cond ((null (getd 'macsyma-env))
(fasl '/usr/lib/lisp/machacks)))
(fl-uci (load "/usr/lib/lisp/ucifnc")
(cond (fl-inter (putprop '* 'cc-ignore 'fl-exprcc) ;comment
(cond ((checkfatal) (return 1))) ; leave if fatal errors
(comp-note "Compilation begins with " compiler-name)
(comp-note "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
(If fl-profile then (e-write1 '".globl mcount"))
(cond ((atom (errset ; list for debugging,
(do ((i (read piport '<<end-of-file>>)
(read piport '<<end-of-file>>)))
((eq i '<<end-of-file>>) nil)
(catch (liszt-form i) Comp-error))))
(comp-note "Lisp error during compilation")
(setq er-fatal (1+ er-fatal))
(cond ((checkfatal) (return 1)))
; if doing special character stuff (maclisp) reassert
(comp-note " done include")
(setq piport (car vps-include))
(setq vps-include (cdr vps-include))
(do ((ll liszt-eof-forms (cdr ll)))
(cond ((atom (errset (liszt-form (car ll))))
(comp-note "Lisp error during eof forms")
(setq readtable (makereadtable t))
(close vp-sfile) ; close assembler language file
(comp-note "Compilation complete")
(setq tem (Divide (difference (syscall 13) starttime) 60))
(comp-note " Real time: " (car tem) " minutes, "
(setq temr (Divide (difference (car tem) (car startptime))
(comp-note " CPU time: " (car temr) " minutes, "
(quotient (cadr temr) 60.0) " seconds")
(setq temr (Divide (difference (cadr tem) (cadr startptime))
(comp-note " of which " (car temr) " minutes and "
(quotient (cadr temr) 60.0)
(difference $gccount$ startgccount)
(comp-note "Cross reference being generated")
(print (list 'File v-ifile) vp-xfile)
(do ((ii g-allf (cdr ii)))
(print (car ii) 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
(cond (fl-asm ; assemble file
(comp-note "Assembly begins")
(comp-gerr "Assembler detected error, code: "
(comp-note "Assembler temp file " v-sfile
(t (comp-note "Assembly completed successfully")
(syscall 10 v-sfile))))) ; unlink tmp file
(setq readtable original-readtable)
(errset (progn (monitor) ; turn off monitoring
(cond ((greaterp er-fatal 0)
(comp-note "Compilation aborted")
;--- liszt-form - i : form to compile
; This compiles one form.
(If (and (dtpr i) (eq 'macro (d-functyp (car i))))
then (setq i (apply (car i) i))
; now look at what is left
(cond ((eq (car i) 'def) ; jkf mod
(cond (fl-verb (print (cadr i)) (terpr)(drain)))
((eq (car i) 'declare) (funcall 'complr-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)))
((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))))
(car (errset (infile (concat '"/usr/lib/lisp"
(car (errset (infile (concat tmp
(setq vps-include (cons piport vps-include))
(comp-note " INCLUDEing file: " tmp))
(t (comp-gerr "Cannot open include file: " tmp))))
((eq (car i) 'comment) nil) ; just ignore comments
(t (Push g-funcs `(eval ,i)))))))
;--- d-dodef :: handle the def form
; - form : a def form: (def name (type args . body))
(let ( ((g-fname (g-ftype g-args . body)) (cdr form))
(lambdaform (caddr form))
(If (or (memq '&rest g-args)
`(def ,(cadr form) ,(lambdacvt (cdr lambdaform))))
(If (null (atom g-fname))
then (comp-err "bad function name")
else (setq g-flocal (get g-fname g-localf))
then (comp-note " macro will not be compiled")
(Push g-funcs `(macro ,symlab ,g-fname))
then (If (null (or (eq g-ftype 'lambda)
then (comp-err "bad type for fcn" (or g-ftype)))
elseif (or (eq g-ftype 'lambda)
then (Push g-funcs `(lambda ,symlab ,g-fname))
elseif (eq g-ftype 'nlambda)
then (Push g-funcs `(nlambda ,symlab ,g-fname))
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))
then (comp-note "is a local function")
(e-writel (car g-flocal))
(If (null fl-vms) then (e-write2 '".globl" 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))
(Push g-locs (cons 'lambda 0))
(setq g-currentargs (length g-args))
(mapc '(lambda (x) (Push g-locs nil) (incr g-loccnt))
(d-prelude) ; do beginning stuff
(d-lambbody lambdaform) ; emit code
(cons (cond (g-flocal (cons g-ftype 'local))
;--- d-prelude :: emit code common to beginning of all functions
then (e-write3 'movl 'r10 '"-(sp)") ; (faster than pushl)
(e-write3 'movab `(,(* -4 g-currentargs) r6) 'r10)
(e-write2 '".word" '0x5c0)
then (e-write3 'movab 'mcounts 'r0)
(e-write3 'movab 'linker '#.bind-reg)
(e-write4 'subl3 '$4 Lbot-reg '"-(sp)") ; set up base for (arg)
(e-write3 'movl Np-reg oLbot-reg) ; will stack num of args
(e-write4 'subl3 Lbot-reg Np-reg 'r0) ; arg cnt again
(e-write3 'movab '"0x1400(r0)" np-plus) ; stack lispval
(e-write3 'movl '(0 #.oLbot-reg) '"-(sp)") ; also on runtime stk
; set up old lbot register, base register for variable
(e-write3 'movl '#.Lbot-reg '#.oLbot-reg)
; make sure the np register points where it should since
; the caller might have given too few or too many args
(e-write3 'movab `(,(* 4 g-currentargs) #.oLbot-reg)
;--- d-fini :: emit code at end of function
(If g-flocal then (e-write3 'movl '"(sp)+" 'r10)
;--- d-bindtab :: emit binder table when all functions compiled
(setq g-skipcode nil) ; make sure this isnt ignored
(e-write2 ".set linker_size," (length g-lits))
(e-write2 ".set trans_size," (length g-tran))
(do ((ll (setq g-funcs (nreverse g-funcs)) (cdr ll)))
(If (memq (caar ll) '(lambda nlambda macro eval))
then (e-write2 '".long" (cdr (assoc (caar ll)
else (comp-err " bad type in lit list " (car ll))))
(d-asciiout (nreverse g-lits))
(If g-tran then (d-asciiout (nreverse g-tran)))
(d-asciiout (mapcar '(lambda (x) (If (eq (car x) 'eval)
;--- d-asciiout :: print a list of asciz strings
(do ((lits args (cdr lits))
(setq form (explode (car lits))
(If (greaterp remsiz 60) then (sfilewrite '".ascii \"")
else (sfilewrite '".asciz \""))
(setq thissiz (min 60 remsiz))
(do ((count thissiz (1- count)))
(sfilewrite (concat '\" (ascii 10)))
(setq remsiz (difference remsiz thissiz)))
(If (eq ch-newline (car curform))
else (If (or (eq '\\ (car curform))
(sfilewrite (car curform)))
(setq curform (cdr curform))))))
;--- doevalwhen, process evalwhen directive. This is inadequate.
(setq docom (memq 'compile (cadr v-f))
dolod (memq 'load (cadr v-f)))
(mapc '(lambda (frm) (cond (docom (eval frm)))
((lambda (internal-macros)
;---- dodcl - forms declare form
; process the declare form given. We evaluate each arg
(defun complr-declare fexpr (forms)
(cond ((and (atom (caar i))
(eval (car i))) ; if this is a function
(t (comp-warn "Unknown declare attribute: " (car i))))))
;---> handlers for declare forms
(putprop v-a 'nlambda g-functype))
(putprop v-a 'nlambda g-functype))
(putprop v-a nil g-spec))
(cond ((atom v-a) (putprop v-a 'lambda g-functype))
(t (comp-warn "Bad declare form " v-a
(putprop v-a 'lexpr g-functype))
(nlambda (args) (setq macros (car args))))
(nlambda (args) (mapc '(lambda (ar)
(If (null (get ar g-localf))
;---> end declare form handlers
; converts a lambda expression with &optional, &rest and &aux forms in
; the argument list into a lexpr which will do the desired function.
; the argument list is examined and the following lists are made:
; vbs - list of variables to be lambda bound
; opl - list of optional forms
; vals - list of values to be assigned to the vbs
(prog (arg vbs vals opl rest opflg restflg narg narg2 narg3 auxflg
(do ((ll (car exp) (cdr ll))
(cond ((eq '&rest (car ll))
(setq restflg t opflg nil count (1- count)))
((eq '&optional (car ll))
(setq opflg t count (1- count)))
(cond ((atom (setq arg (car ll)))
(setq opl (cons (cons (ncons arg) count) opl)
(setq vbs (cons (car arg)
opl (cons (cons arg count) opl)))
(t (setq vbs (cons (car arg) vbs)
opl (cons (cons arg count) opl)))))
(setq vbs (cons (car ll) vbs)
rest (cons (car ll) count)))
(cond ((atom (setq arg (car ll)))
(setq avbs (cons (ncons arg) avbs)))
(t (setq avbs (cons arg avbs)))))
(t (setq vbs (cons (car ll) vbs)
vals (cons `(arg ,count) vals)))))
`(cond ((greaterp ,(cdr arg)
(t (setq ,(caar arg) (arg ,(cdr arg)))
,@(cond (rest (setq narg2 (gensym)
`((do ((,narg2 ,narg (1- ,narg2))
(,narg3 nil (cons (arg ,narg2)
((lessp ,narg2 ,(cdr rest))
(setq ,(car rest) ,narg3))))))
,@(cond (auxflg `((let* ,(nreverse avbs)
; this routine is copied from ccb.l so we can make it a local function
;--- d-genlab :: generate a pseudo label