I'm writing a small machine simulator in CL, using tagbody/go to
define the outer-most structure.
Each instruction looks something like this:
:state-instruction4
(some-debugging-code)
(... implementation of instruction using 'go' to make state
transitions ...)
My question is: How can I define a macro to replace that by something
like:
(state instruction4)
(... implementation of instruction ...)
where the 'state' defmacro should return two things: a symbol for the
target of the 'go', and a form of debugging code.
I wasn't able to find a way to return multiple values such that one of
them would be outside of forms. I thought perhaps of wrapping the
whole tagbody in a macro and walking and rewriting all the code
inside, but that seemed overly complex. (And made me feel like I was
missing something obvious when I started to try to write it!)
Thank you for any suggestions. Noob-ishly yours,
Scott
> Hello
>
> I'm writing a small machine simulator in CL, using tagbody/go to
> define the outer-most structure.
>
> Each instruction looks something like this:
>
> :state-instruction4
> (some-debugging-code)
> (... implementation of instruction using 'go' to make state
> transitions ...)
>
> My question is: How can I define a macro to replace that by something
> like:
>
> (state instruction4)
> (... implementation of instruction ...)
>
> where the 'state' defmacro should return two things: a symbol for the
> target of the 'go', and a form of debugging code.
This is not possible.
That's what makes lisp macros so powerful: they generate a single
form, therefore they can be expanded blindly in any expression
context, therefore you can do whatever you want _in_ your macros, and
it will work.
If it wasn't the case, lisp macros would be subject to code injection
like any PHP script.
> I wasn't able to find a way to return multiple values such that one of
> them would be outside of forms. I thought perhaps of wrapping the
> whole tagbody in a macro and walking and rewriting all the code
> inside, but that seemed overly complex. (And made me feel like I was
> missing something obvious when I started to try to write it!)
That's the correct way to do it. It's not too hard to do, and thanks
to the above property, it's actually possible: you don't have to know
what each macro expands to to be able to process them safely.
--
__Pascal Bourguignon__ http://www.informatimago.com/
OK, thank you. I had made it harder for myself by attempting to rename
the symbol that the 'go' was jumping to. That seems to make it
necessary to understand the structure of "everything" to be able to
find the go's.
If I just walk the top level though, it isn't too complex.
Scott
Notice that in the top level macro, you can use macrolet and
flet/labels to provide operators to the inferior lexical levels as
deep as needed.
(defmacro state-machine (&body state-clauses)
`(macrolet ((goto (state) `(go ,(generate-state-symbol state))))
,@(expand-state-clauses state-clauses)))
so that you can write:
(state-machine
(state init
...
(cond cond
(goto term))
...)
(state term
...
(cond cond
(goto term))
...))
even if state-machine looks only at the toplevel forms.
> > If I just walk the top level though, it isn't too complex.
>
> Notice that in the top level macro, you can use macrolet and
> flet/labels to provide operators to the inferior lexical levels as
> deep as needed.
Aha, of course! Thank you for your patient explanation. :)
Scott
Note that this is a fairly common idiom in CL macrology. E.g., the
main macro in the HTML-generating HTOUT & CL-WHO is WITH-HTML-OUTPUT,
which defines a whole bunch of helper macrolets -- HTM, FMT, LFD,
ESC, & STR -- which capture/reference bits of the lexical environment
set up by WITH-HTML-OUTPUT (well, really only the output stream variable,
but it *could* have been more) to provide useful abbreviations within
the body of the main macro.
Similarly, "collecting" macros define macrolets for various collection
operators [see EXT:COLLECT in CMUCL].
-Rob
-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607