malcolm@spar.SPAR.SLB.COM (Malcolm Slaney) (04/05/88)
Can anybody point me towards some code that will take any Common Lisp expression and macroexpand all of the macros. I would like as output a s'exp that just has the functions from Steele. I don't think this is too hard but if somebody else has already done it I would prefer to reuse the code. (Don't special forms make this non trivial???) I want to use this as part of a tool to record storage usage. I'll first do the necessary macroexpands, then wrap a form around each primitive Common Lisp form that records the memory usage and then write a tool that will pretty print the information. Thanks for the help. Malcolm Slaney malcolm@spar.slb.com
mao@hpclmao.HP.COM (Mike Ogush) (04/07/88)
/ malcolm@spar.SPAR.SLB.COM (Malcolm Slaney) writes: >Can anybody point me towards some code that will take any Common Lisp >expression and macroexpand all of the macros. I would like as output >a s'exp that just has the functions from Steele. I don't think this is too >hard but if somebody else has already done it I would prefer to reuse the >code. (Don't special forms make this non trivial???) > >I want to use this as part of a tool to record storage usage. I'll first >do the necessary macroexpands, then wrap a form around each primitive Common >Lisp form that records the memory usage and then write a tool that will >pretty print the information. > >Thanks for the help. > > Malcolm Slaney > malcolm@spar.slb.com >---------- > When I was learning Common LISP, I wrote just such a function so I could see exactly what s-expressions were being expanded into: (defun fully-expand-macro (exp) (if (consp exp) (let ((car-exp (car exp))) (if (and (symbolp car-exp) (macro-function car-exp)) (fully-expand-macro (macroexpand exp)) (cons car-exp (mapcar #'fully-expand-macro (cdr exp))))) exp) ) Hope this helps Mike Ogush Computer Languages Lab Hewlett-Packard Company ...!hplabs!hpda!mao or mao%hpclmao@hplabs.hp.com
larus@paris.Berkeley.EDU (James Larus) (04/07/88)
How about: (defun macroexpand-all (f) (cond ((atom f) f) ((and (symbolp (car f)) (macro-function (car f))) (macroexpand-all (macroexpand f))) (t (mapcar #'macroexpand-all f)))) /Jim larus@ginger.Berkeley.EDU ucbvax!larus
skef@SPICE.CS.CMU.EDU (Skef Wholey) (04/08/88)
Jim Larus writes:
From: larus@paris.Berkeley.EDU (James Larus)
Subject: Re: Common Lisp Macro Expander Wanted
How about:
(defun macroexpand-all (f)
(cond ((atom f) f)
((and (symbolp (car f)) (macro-function (car f)))
(macroexpand-all (macroexpand f)))
(t (mapcar #'macroexpand-all f))))
This is no good, because it doesn't know the syntax of special forms.
For example, this call causes an error:
(macroexpand-all '(let ((with-open-file t)) blag))
because it tries to descend blindly into the LET binding list as if it
were a macro call, which it obvously ain't.
It isn't too hard to write a code walker that Does The Right Thing for
special forms in Common Lisp, but unfortunately some implementations
ignore the rules stated in CLtL and make this more difficult than it
ought to be. Older versions of Symbolics CL were pretty nasty in this
respect, because they had macros expanding into implementation-dependent
special forms and didn't supply macroexpansion functions for all the
things specified as macros in CLtL. I believe this should have been
fixed by now, but I can't easily check this.
I have this suspicion that dozens of good CL code-walkers have been
written independently, but none have made it into the public domain
because they were written in profit-oriented institutions. Does anyone
out there have one to donate?
--Skef
gateley@mips.csc.ti.com (John Gateley) (04/10/88)
In article <23539@ucbvax.BERKELEY.EDU> larus@paris.Berkeley.EDU.UUCP writes: >How about: > > (defun macroexpand-all (f) > (cond ((atom f) f) > ((and (symbolp (car f)) (macro-function (car f))) > (macroexpand-all (macroexpand f))) > (t (mapcar #'macroexpand-all f)))) > > >/Jim >larus@ginger.Berkeley.EDU >ucbvax!larus Almost works, but you have to check special forms to make sure that they are macro expanded only in the proper places, and then there is always lambda to deal with. (Hint: Dont macro expand the argument list for lambdas, and the same is true for the variables in a let). I cant find anything in CLtL which verifies this, but I think this is correct.
girgenso@ifistg.UUCP (04/11/88)
Here are some functions to expand all macros in a lisp expression. I hope this will help. Andreas Girgensohn girgenso%ifistg.uucp%unido.uucp@uunet.uu.net ------------------------------- cut here ------------------------------- (defun macroexpand-all (form &optional env) (setq form (macroexpand form env)) (if (atom form) form (case (car form) ((catch if multiple-value-call multiple-value-prog1 progn progv setq tagbody throw unwind-protect) (macroexpand-lambda-call form env)) ((declare go quote) form) ((block eval-when return-from the) (let ((body (macroexpand-body (cddr form) env))) (if (eq body (cddr form)) form (list* (car form) (cadr form) body)))) ((flet labels macrolet) (macroexpand-flet form env)) (function (let ((func (macroexpand-lambda (cadr form) env))) (if (eq func (cadr form)) form (list (car form) func)))) ((compiler-let let let*) (macroexpand-let form env)) (t (if (or (consp (car form)) (not (special-form-p (car form)))) (macroexpand-lambda-call form env) form))))) ; unknown special form (defun macroexpand-lambda-call (form env) (let ((func (macroexpand-lambda (car form) env)) (args (macroexpand-body (cdr form) env))) (if (and (eq func (car form)) (eq args (cdr form))) form (cons func args)))) (defun macroexpand-lambda (func env) (if (atom func) func (let ((arglist (macroexpand-lambda-list (cadr func) env)) (body (macroexpand-body (cddr func) env))) (if (and (eq arglist (cadr func)) (eq body (cddr func))) func (list* (car func) arglist body))))) (defun macroexpand-lambda-list (list env) env list) (defun macroexpand-body (body env) (if (atom body) body (let ((first (macroexpand-all (car body) env)) (rest (macroexpand-body (cdr body) env))) (if (and (eq first (car body)) (eq rest (cdr body))) body (cons first rest))))) (defun macroexpand-flet (form env) (let ((fdefs (macroexpand-flet-definitions (cadr form) env)) (body (macroexpand-body (cddr form) env))) (if (and (eq fdefs (cadr form)) (eq body (cddr form))) form (list* (car form) fdefs body)))) (defun macroexpand-flet-definitions (defs env) (if (atom defs) defs (let ((first (macroexpand-lambda (car defs) env)) (rest (macroexpand-flet-definitions (cdr defs) env))) (if (and (eq first (car defs)) (eq rest (cdr defs))) defs (cons first rest))))) (defun macroexpand-let (form env) (let ((bdgs (macroexpand-bindings (cadr form) env)) (body (macroexpand-body (cddr form) env))) (if (and (eq bdgs (cadr form)) (eq body (cddr form))) form (list* (car form) bdgs body)))) (defun macroexpand-bindings (bdgs env) (if (atom bdgs) bdgs (let ((first (if (atom (car bdgs)) (car bdgs) (let ((values (macroexpand-body (cdar bdgs) env))) (if (eq values (cdar bdgs)) (car bdgs) (cons (caar bdgs) values))))) (rest (macroexpand-bindings (cdr bdgs) env))) (if (and (eq first (car bdgs)) (eq rest (cdr bdgs))) bdgs (cons first rest)))))
ilan@lcuxlm.UUCP (04/17/88)
In article <46438@ti-csl.CSNET>, gateley@mips.csc.ti.com (John Gateley) writes: > > Almost works, but you have to check special forms to make sure that > they are macro expanded only in the proper places, and then there is > always lambda to deal with. (Hint: Dont macro expand the argument list > for lambdas, and the same is true for the variables in a let). I cant find > anything in CLtL which verifies this, but I think this is correct. I think it turns out that a fully-fledged macroexpanding preprocessor looks very much like the first pass of a compiler - and among things you end up having to treat each special-form specially (that's why they're special). Do you have any ides of how to handle local macros (defined by MACROLET)? We ended up just ignoring them - essentially because (1) MACRO-FUNCTION only knows about global macros (because it's a top-level function and (2) to be useful MACROEXPAND would need the correct &ENVIRONMENT arg set up. All in all a hassle... but maybe I'm missing something... like a screw... --ilan caron ..!ucbvax!vax135!lcuxlj!ilan -- --Ilan Caron 201-580-5664 ..!allegra!lcuxlj!ilan #<Standard Disclaimer>
aboulang@bbn.com (Albert Boulanger) (04/18/88)
You can pick up PCL (portable common loops)from XEROX and use its code walker... Albert Boulanger aboulanger@bbn.com Albert Boulanger BBN Labs Inc. ABoulanger@bbn.com (arpa) Phone: (617)873-3891
gateley@mips.csc.ti.com (John Gateley) (04/18/88)
In article <1683@lcuxlm.UUCP> ilan@lcuxlm.UUCP writes: > [...] >Do you have any ides of how to handle local macros (defined >by MACROLET)? We ended up just ignoring them - essentially because >(1) MACRO-FUNCTION only knows about global macros (because it's a >top-level function and (2) to be useful MACROEXPAND would need the >correct &ENVIRONMENT arg set up. All in all a hassle... but maybe >I'm missing something... like a screw... > >--ilan caron ..!ucbvax!vax135!lcuxlj!ilan >--Ilan Caron 201-580-5664 ..!allegra!lcuxlj!ilan >#<Standard Disclaimer> You mentioned that it is just like the first pass of a compiler, and that is the answer to your question. You just have to pass around an argument which contains an environment mapping symbols to local macro functions. When you reach a form which is a local macro function, you just eval the macro function applied to the form (Yucch ... eval). Macrolet just extends the environment. Of course, you have to worry about scoping to do it correctly (where a local macro name might be shadowed by something else). Hope this helps John Gateley