(include-if (null (get 'chead 'version)) "chead.l") (Liszt-file expr "$Header: /na/franz/liszt/RCS/expr.l,v 1.1 83/01/26 12:14:06 jkf Exp $") ;;; ---- e x p r expression compilation ;;; ;--- d-exp :: compile a lisp expression = d-exp = ; v-form : a lisp expression to compile ; returns an IADR which tells where the value was located. ; ;.. c-*catch, c-*throw, c-boole, c-cond, c-do, c-errset, c-funcall ;.. c-internal-fixnum-box, c-prog, c-progv, c-return, c-rplaca ;.. c-rplacd, c-setarg, cc-and, cc-arg, cc-cxxr, cc-eq ;.. cc-function, cc-memq, cc-not, cc-oneminus, cc-oneplus, cc-or ;.. cc-setq, cc-typep, d-exps, d-fixnumcode, d-fixop, d-lambbody ;.. d-pushargs, d-supercxr, d-superrplacx, d-typecmplx, d-typesimp (defun d-exp (v-form) (prog (first resloc tmp ftyp) begin (If (atom v-form) then (setq tmp (d-loc v-form)) ;locate vrble (If (null g-loc) then (If g-cc then (d-tst tmp)) else (d-move tmp g-loc)) (d-handlecc) (return tmp) elseif (atom (setq first (car v-form))) then (If (and fl-xref (not (get first g-refseen))) then (Push g-reflst first) (putprop first t g-refseen)) (setq ftyp (d-functyp first 'macros-ok)) ; If the resulting form is type macro or cmacro, ; then call the appropriate function to macro-expand ; it. (If (memq ftyp '(macro cmacro)) then (setq tmp v-form) ; remember original form (If (eq 'macro ftyp) then (setq v-form (apply first v-form)) elseif (eq 'cmacro ftyp) then (setq v-form (apply (get first 'cmacro) v-form))) ; If the resulting form is the same as ; the original form, then we don't want to ; macro expand again. We call d-functyp and tell ; it that we want a second opinion (If (and (eq (car v-form) first) (equal tmp v-form)) then (setq ftyp (d-functyp first nil)) else (go begin))) ; retry with what we have (If (and (setq tmp (get first 'if-fixnum-args)) (d-allfixnumargs (cdr v-form))) then (setq v-form (cons tmp (cdr v-form))) (go begin) elseif (setq tmp (get first 'fl-exprcc)) then (d-argnumchk 'hard) (return (funcall tmp)) elseif (setq tmp (get first 'fl-exprm)) then (d-argnumchk 'hard) (setq v-form (funcall tmp)) (go begin) elseif (setq tmp (get first 'fl-expr)) then (d-argnumchk 'hard) (funcall tmp) elseif (setq tmp (or (and (eq 'car first) '( a )) (and (eq 'cdr first) '( d )) (d-cxxr first))) then (d-argcheckit '(1 . 1) (length (cdr v-form)) 'hard) (return (cc-cxxr (cadr v-form) tmp)) elseif (eq 'nlambda ftyp) then (d-argnumchk 'soft) (d-callbig first `(',(cdr v-form)) nil) elseif (or (eq 'lambda ftyp) (eq 'lexpr ftyp)) then (setq tmp (length v-form)) (d-argnumchk 'soft) (d-callbig first (cdr v-form) nil) elseif (eq 'array ftyp) then (d-handlearrayref) elseif (eq 'macro ftyp) then (comp-err "infinite macro expansion " v-form) else (comp-err "internal liszt err in d-exp" v-form)) elseif (eq 'lambda (car first)) then (c-lambexp) elseif (or (eq 'quote (car first)) (eq 'function (car first))) then (comp-warn "bizzare function name " (or first)) (setq v-form (cons (cadr first) (cdr v-form))) (go begin) else (comp-err "bad expression" (or v-form))) (If (null g-loc) then (If g-cc then (d-tst 'reg)) elseif (memq g-loc '(reg r0)) then (If g-cc then (d-tst 'reg)) else (d-move 'reg g-loc)) (If g-cc then (d-handlecc)))) ;--- d-exps :: compile a list of expressions ; - exps : list of expressions ; the last expression is evaluated according to g-loc and g-cc, the others ; are evaluated with g-loc and g-cc nil. ; ;.. c-cond, c-do (defun d-exps (exps) (d-exp (do ((ll exps (cdr ll)) (g-loc nil) (g-cc nil) (g-ret nil)) ((null (cdr ll)) (car ll)) (d-exp (car ll))))) ;--- d-argnumchk :: check that the correct number of arguments are given ; v-form (global) contains the expression to check ; class: hard or soft, hard means that failure is an error, soft means ; warning ;.. d-exp (defun d-argnumchk (class) (let ((info (car (get (car v-form) 'fcn-info))) (argsize (length (cdr v-form)))) (If info then (d-argcheckit info argsize class)))) ;--- d-argcheckit ; info - arg information form: (min# . max#) max# of nil means no max ; numargs - number of arguments given ; class - hard or soft ; v-form(global) - expression begin checked ; ;.. d-argnumchk, d-exp (defun d-argcheckit (info numargs class) (If (and (car info) (< numargs (car info))) then (If (eq class 'hard) then (comp-err (difference (car info) numargs) " too few argument(s) given in this expression:" N v-form) else (comp-warn (difference (car info) numargs) " too few argument(s) given in this expression:" N v-form)) elseif (and (cdr info) (> numargs (cdr info))) then (If (eq class 'hard) then (comp-err (difference numargs (cdr info)) " too many argument(s) given in this expression:" N v-form) else (comp-warn (difference numargs (cdr info)) " too many argument(s) given in this expression:" N v-form)))) ;--- d-pushargs :: compile and push a list of expressions ; - exps : list of expressions ; compiles and stacks a list of expressions ; ;.. c-cons, c-do, c-funcall, c-get, c-internal-bind-vars ;.. c-internal-unbind-vars, c-lambexp, c-list, c-prog, c-setarg ;.. cc-equal, d-callbig, d-dostore, d-dotailrecursion (defun d-pushargs (args) (If args then (do ((ll args (cdr ll)) (g-loc 'stack) (g-cc nil) (g-ret nil)) ((null ll)) (d-exp (car ll)) (Push g-locs nil) (incr g-loccnt)))) ;--- d-cxxr :: split apart a cxxr function name ; - name : a possible cxxr function name ; returns the a's and d's between c and r in reverse order, or else ; returns nil if this is not a cxxr name ; ;.. d-exp (defun d-cxxr (name) (let ((expl (explodec name))) (If (eq 'c (car expl)) ; must begin with c then (do ((ll (cdr expl) (cdr ll)) (tmp) (res)) (nil) (setq tmp (car ll)) (If (null (cdr ll)) then (If (eq 'r tmp) ; must end in r then (return res) else (return nil)) elseif (or (eq 'a tmp) ; and contain only a's and d's (eq 'd tmp)) then (setq res (cons tmp res)) else (return nil)))))) ;--- d-callbig :: call a local, global or bcd function ; ; name is the name of the function we are to call ; args are the arguments to evaluate and call the function with ; if bcdp is t then we are calling through a binary object and thus ; name is ingored. ; ;.. c-bcdcall, c-boole, d-exp, d-fixop (defun d-callbig (name args bcdp) (let ((tmp (get name g-localf)) c) (forcecomment `(calling ,name)) (If (d-dotailrecursion name args) thenret elseif tmp then ;-- local function call (d-pushargs args) (e-write2 'jsb (car tmp)) (setq g-locs (nthcdr (setq c (length args)) g-locs)) (setq g-loccnt (- g-loccnt c)) else (If bcdp ;-- bcdcall then (d-pushargs args) (setq c (length args)) (d-bcdcall c) elseif fl-tran ;-- transfer table linkage then (d-pushargs args) (setq c (length args)) (d-calltran name c) (putprop name t g-stdref) ; remember we've called this else ;--- shouldn't get here (comp-err " bad args to d-callbig : " (or name args))) (setq g-locs (nthcdr c g-locs)) (setq g-loccnt (- g-loccnt c))) (d-clearreg))) ;--- d-calltran :: call a function through the transfer table = d-calltran = ; name - name of function to call ; c - number of arguments to the function ; ;.. c-Internal-bcdcall, cc-equal, d-callbig (defun d-calltran (name c) (e-write3 'movab `(,(* -4 c) #.Np-reg) '#.Lbot-reg) (e-write3 'calls '$0 (concat "*trantb+" (d-tranloc name))) (e-write3 'movl '#.Lbot-reg '#.Np-reg)) ;--- d-calldirect :: call a function directly ; ; name - name of a function in the C code (known about by fasl) ; c - number of args ; ;.. c-internal-bind-vars, c-internal-unbind-vars (defun d-calldirect (name c) (e-write3 'movab `(,(* -4 c) #.Np-reg) '#.Lbot-reg) (e-write3 'calls '$0 name) (e-write3 'movl '#.Lbot-reg '#.Np-reg)) ;--- d-bcdcall :: call a function through a binary data object ; ; at this point the stack contains n-1 arguments and a binary object which ; is the address of the compiled lambda expression to go to. We set ; up lbot right above the binary on the stack and call the function. ; ;.. c-Internal-bcdcall, d-callbig (defun d-bcdcall (n) (e-write3 'movab `(,(* -4 (- n 1)) #.Np-reg) '#.Lbot-reg) (e-write3 'movl '(* -4 #.Lbot-reg) 'r0) ; get address to call to (e-write3 'calls '$0 "(r0)") (e-write3 'movab '(-4 #.Lbot-reg) '#.Np-reg) ; set up np after call ) ;--- d-dotailrecursion :: do tail recursion if possible ; name - function name we are to call ; args - arguments to give to function ; ; return t iff we were able to do tail recursion ; We can do tail recursion if: ; g-ret is set indicating that the result of this call will be returned ; as the value of the function we are compiling ; the function we are calling, name, is the same as the function we are ; compiling, g-fname ; there are no variables shallow bound, since we would have to unbind ; them, which may cause problems in the function. ; ;.. d-callbig (defun d-dotailrecursion (name args) (If (and g-ret (eq name g-fname) (do ((loccnt 0) (ll g-locs (cdr ll))) ((null ll) (return t)) (If (dtpr (car ll)) then (If (or (eq 'catcherrset (caar ll)) (greaterp (cdar ll) 0)) then (return nil)) else (incr loccnt)))) then ; evalate the arguments and pop them back to the location of ; the original args. (makecomment '(tail merging)) (comp-note g-fname ": Tail merging being done: " v-form) (let ((g-locs g-locs) (g-loccnt g-loccnt)) (d-pushargs args)) ; push then forget about (let (base-reg nargs) (If (eq g-ftype 'lexpr) then ; the beginning of the local variables ;has been stacked (e-write3 'addl2 '$4 'sp) ; pop off arg count (e-write4 'addl3 '$4 "(sp)" '#.Lbot-reg) (setq base-reg '#.Lbot-reg) ; will push from bot else (e-write3 'movl '#.oLbot-reg '#.Lbot-reg) (setq base-reg '#.Lbot-reg)) ; will push from lbot (setq nargs (length args)) (do ((i nargs (1- i)) (top (* nargs -4) (+ top 4)) (bot 0 (+ bot 4))) ((zerop i)) (e-write3 'movl `(,top #.Np-reg) `(,bot ,base-reg))) (e-write3 'movab `(,(* 4 nargs) ,base-reg) '#.Np-reg) (e-goto g-topsym)) t)) ; return t to indicate that tailrecursion was successful