1
0
Fork 0
cl-sites/www.cs.cmu.edu/Groups/AI/html/cltl/clm/node98.html
2023-10-25 11:23:21 +02:00

516 lines
24 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">
<!Converted with LaTeX2HTML 0.6.5 (Tue Nov 15 1994) by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds >
<HEAD>
<TITLE>8.1. Macro Definition</TITLE>
</HEAD>
<BODY>
<meta name="description" value=" Macro Definition">
<meta name="keywords" value="clm">
<meta name="resource-type" value="document">
<meta name="distribution" value="global">
<P>
<b>Common Lisp the Language, 2nd Edition</b>
<BR> <HR><A NAME=tex2html2746 HREF="node99.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html2744 HREF="node97.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html2738 HREF="node97.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html2748 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html2749 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
<B> Next:</B> <A NAME=tex2html2747 HREF="node99.html"> Macro Expansion</A>
<B>Up:</B> <A NAME=tex2html2745 HREF="node97.html"> Macros</A>
<B> Previous:</B> <A NAME=tex2html2739 HREF="node97.html"> Macros</A>
<HR> <P>
<H1><A NAME=SECTION001210000000000000000>8.1. Macro Definition</A></H1>
<P>
The function <tt>macro-function</tt> determines whether a given symbol
is the name of a macro. The <tt>defmacro</tt> construct provides
a convenient way to define new macros.
<P>
<img align=bottom alt="old_change_begin" src="gif/old_change_begin.gif"><br>
<BR><b>[Function]</b><BR>
<tt>macro-function</tt> <tt><i>symbol</i></tt><P>The argument must be a symbol. If the symbol has a global function definition
that is a macro definition, then the expansion function
(a function of two arguments, the macro-call form and an environment)
is returned.
If the symbol has no global function definition, or has a definition
as an ordinary function or as a special form but not as a macro, then
<tt>nil</tt> is returned. The function <tt>macroexpand</tt>
is the best way to invoke the expansion function.
<P>
It is possible for <i>both</i> <tt>macro-function</tt> and <tt>special-form-p</tt>
to be true of a symbol. This is possible because an implementation is
permitted to implement any macro also as a special form for speed.
On the other hand, the macro definition must be available
for use by programs that understand only the standard special forms
listed in table <A HREF="node59.html#SPECIALFORMTABLE">5-1</A>.
<P>
<tt>macro-function</tt> cannot be used to determine whether a symbol names
a locally defined macro established by <tt>macrolet</tt>;
<tt>macro-function</tt> can
examine only global definitions.
<P>
<tt>setf</tt> may be used with <tt>macro-function</tt> to install
a macro as a symbol's global function definition:
<P><pre>
(setf (macro-function <i>symbol</i>) <i>fn</i>)
</pre><P>
The value installed must be a function that accepts two arguments,
an entire macro call and an environment, and computes the expansion for that call.
Performing this operation causes the symbol to have <i>only</i> that
macro definition as its global function definition; any previous
definition, whether as a macro or as a function, is lost.
It is an error to attempt to redefine the name of a special
form.
<br><img align=bottom alt="old_change_end" src="gif/old_change_end.gif">
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
X3J13 voted in March 1988 (MACRO-FUNCTION-ENVIRONMENT) <A NAME=8261>&#160;</A>
to add an optional environment argument to <tt>macro-function</tt>.
<P>
<BR><b>[Function]</b><BR>
<tt>macro-function</tt> <tt><i>symbol</i></tt> <tt>&amp;optional</tt> <tt><i>env</i></tt><P>The first argument must be a symbol. If the symbol has a function definition
that is a macro definition, whether a local one established in the
environment <i>env</i> by <tt>macrolet</tt> or a global one established as
if by <tt>defmacro</tt>,
then the expansion function
(a function of two arguments, the macro-call form and an environment)
is returned.
If the symbol has no function definition, or has a definition
as an ordinary function or as a special form but not as a macro, then
<tt>nil</tt> is returned. The function <tt>macroexpand</tt> or <tt>macroexpand-1</tt>
is the best way to invoke the expansion function.
<P>
It is possible for <i>both</i> <tt>macro-function</tt> and <tt>special-form-p</tt>
to be true of a symbol. This is possible because an implementation is
permitted to implement any macro also as a special form for speed.
On the other hand, the macro definition must be available
for use by programs that understand only the standard special forms
listed in table <A HREF="node59.html#SPECIALFORMTABLE">5-1</A>.
<P>
<tt>setf</tt> may be used with <tt>macro-function</tt> to install
a macro as a symbol's global function definition:
<P><pre>
(setf (macro-function <i>symbol</i>) <i>fn</i>)
</pre><P>
The value installed must be a function that accepts two arguments,
an entire macro call and an environment, and computes the expansion for that call.
Performing this operation causes the symbol to have <i>only</i> that
macro definition as its global function definition; any previous
definition, whether as a macro or as a function, is lost.
One cannot use <tt>setf</tt> to establish a local macro definition;
it is an error to supply a second argument to <tt>macro-function</tt>
when using it with <tt>setf</tt>.
It is an error to attempt to redefine the name of a special form.
<P>
See also <tt>compiler-macro-function</tt>.
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
<BR><b>[Macro]</b><BR>
<pre>
defmacro <i>name</i> <i>lambda-list</i> <b>[[</b> {<i>declaration</i>}* | <i>doc-string</i> <b>]]</b> {<i>form</i>}*
</pre>
<P><tt>defmacro</tt> is a macro-defining macro that
arranges to decompose the macro-call form in an elegant and useful way.
<tt>defmacro</tt> has essentially the same syntax as <tt>defun</tt>: <i>name</i> is the
symbol whose macro definition we are creating, <i>lambda-list</i> is similar in
form to a lambda-list, and
the <i>form</i>s constitute the body of the expander function.
The <tt>defmacro</tt> construct arranges to install this expander function,
as the global macro definition of <i>name</i>.
<P>
<img align=bottom alt="old_change_begin" src="gif/old_change_begin.gif"><br>
The expander function
is effectively defined in the <i>global</i> environment;
lexically scoped entities established
outside the <tt>defmacro</tt> form that would ordinarily be lexically apparent
are not visible within the body of the expansion function.
<br><img align=bottom alt="old_change_end" src="gif/old_change_end.gif">
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
X3J13 voted in March 1989 (DEFINING-MACROS-NON-TOP-LEVEL) <A NAME=8303>&#160;</A>
to clarify that, while defining forms normally appear at top level,
it is meaningful to place them in non-top-level contexts.
Furthermore, <tt>defmacro</tt> should define the expander function
within the enclosing lexical environment, not within the global
environment.
<P>
X3J13 voted in March 1988 (FLET-IMPLICIT-BLOCK) <A NAME=8307>&#160;</A>
to specify that the body of the expander function defined
by <tt>defmacro</tt> is implicitly enclosed in a <tt>block</tt> construct
whose name is the same as the <i>name</i> of the defined macro.
Therefore <tt>return-from</tt> may be used to exit from the function.
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
The <i>name</i> is returned
as the value of the <tt>defmacro</tt> form.
<P>
If we view the
macro call as a list containing a function name and some argument forms,
in effect the expander function and the list of (unevaluated) argument
forms is given to <tt>apply</tt>.
The parameter specifiers are processed as for any lambda-expression,
using the macro-call argument forms as the arguments.
Then the body forms are evaluated
as an implicit <tt>progn</tt>, and the value of the last form
is returned as the expansion of the macro call.
<P>
If the optional documentation string <i>doc-string</i> is present (if not
followed by a declaration, it may be
present only if at least one <i>form</i> is also specified, as it is
otherwise taken to be a <i>form</i>), then it is attached to the <i>name</i>
as a documentation string of type <tt>function</tt>; see <tt>documentation</tt>.
<P>
<img align=bottom alt="old_change_begin" src="gif/old_change_begin.gif"><br>
Like the lambda-list in a <tt>defun</tt>, a <tt>defmacro</tt> <i>lambda-list</i> may contain
the lambda-list keywords <tt>&amp;optional</tt>, <tt>&amp;rest</tt>, <tt>&amp;key</tt>,
<tt>&amp;allow-other-keys</tt>, and <tt>&amp;aux</tt>.
For <tt>&amp;optional</tt> and <tt>&amp;key</tt> parameters, initialization forms and
supplied-p parameters may be specified, just as for <tt>defun</tt>.
Three additional markers
are allowed in <tt>defmacro</tt> variable lists only.
<br><img align=bottom alt="old_change_end" src="gif/old_change_end.gif">
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
These three markers are now allowed in other constructs as well.
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
<DL COMPACT>
<DT><tt>&amp;body</tt>
<DD>
This is identical in function to <tt>&amp;rest</tt>, but it informs certain
output-formatting and editing functions that the remainder of the form is
treated as a body and should be indented accordingly.
(Only one of <tt>&amp;body</tt> or <tt>&amp;rest</tt> may be used.)
<P>
<DT><tt>&amp;whole</tt>
<DD>
This is followed by a single variable that is bound to the
entire macro-call form; this is the value that the macro definition function
receives as its single argument.
<tt>&amp;whole</tt> and the following variable should appear first in the lambda-list,
before any other parameter or lambda-list keyword.
<P>
<DT><tt>&amp;environment</tt>
<DD>
This is followed by a single variable that is bound
to an environment representing the lexical environment in which the
macro call is to be interpreted. This environment may not be the
complete lexical environment; it should be used only with
the function <tt>macroexpand</tt> for the sake of any local
macro definitions that the <tt>macrolet</tt> construct may have
established within that lexical environment. This is useful primarily
in the rare cases where a macro definition must explicitly expand any macros
in a subform of the macro call before computing its own expansion.
<P>
</DL>
See <tt>lambda-list-keywords</tt>.
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
<i>Notice of correction.</i>
In the first edition, the symbol <tt>&amp;environment</tt> at the
left margin above was inadvertently omitted.
<P>
X3J13 voted in March 1989 (MACRO-ENVIRONMENT-EXTENT) <A NAME=8357>&#160;</A>
to specify that macro environment objects received with the <tt>&amp;environment</tt>
argument of a macro function
have only dynamic extent. The consequences are undefined if such objects are
referred to outside the dynamic extent of that particular
invocation of the macro function.
This allows implementations to use somewhat more efficient techniques
for representing environment objects.
<P>
X3J13 voted in March 1989 (DEFMACRO-LAMBDA-LIST) <A NAME=8361>&#160;</A> to clarify the permitted
uses of <tt>&amp;body</tt>, <tt>&amp;whole</tt>, and <tt>&amp;environment</tt>:
<UL><LI> <tt>&amp;body</tt> may appear at any level of a <tt>defmacro</tt> lambda-list.<p>
<LI> <tt>&amp;whole</tt> may appear at any level of a <tt>defmacro</tt> lambda-list.
At inner levels a <tt>&amp;whole</tt> variable is bound to that part of the argument
that matches the sub-lambda-list in which <tt>&amp;whole</tt> appears. No matter where
<tt>&amp;whole</tt> is used, other parameters or lambda-list keywords may follow it.<p>
<LI> <tt>&amp;environment</tt> may occur only at the outermost level of a <tt>defmacro</tt>
lambda-list, and it may occur at most once, but it may occur anywhere within
that lambda-list, even before an occurrence of <tt>&amp;whole</tt>.
</UL>
<img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
<tt>defmacro</tt>, unlike any other Common Lisp construct that has a lambda-list
as part of its syntax, provides an additional facility known as
<i>destructuring</i>.
<p>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
See <tt>destructuring-bind</tt>, which provides the destructuring facility separately.
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
Anywhere in the lambda-list where a parameter
name may appear, and where ordinary lambda-list syntax (as described
in section <A HREF="node64.html#LAMBDAEXPRESSIONSSECTION">5.2.2</A>) does not
otherwise allow a list, a lambda-list may appear in place
of the parameter name. When this is done, then the argument form
that would match the parameter is treated as a (possibly dotted) list,
to be used as an argument forms list for satisfying the
parameters in the embedded lambda-list.
As an example, one could write the macro definition
for <tt>dolist</tt> in this manner:
<P><pre>
(defmacro dolist ((var listform <tt>&amp;optional</tt> resultform)
&amp;rest body)
...)
</pre><P>
More examples of embedded lambda-lists in <tt>defmacro</tt> are shown below.
<P>
Another destructuring rule is that <tt>defmacro</tt> allows any lambda-list
(whether top-level or embedded) to be dotted, ending
in a parameter name. This situation is treated exactly as if the
parameter name that ends the list had appeared preceded by <tt>&amp;rest</tt>.
For example, the definition skeleton for <tt>dolist</tt> shown above could
instead have been written
<P><pre>
(defmacro dolist ((var listform &amp;optional resultform)
. body)
...)
</pre><P>
<P>
If the compiler encounters a <tt>defmacro</tt>,
the new macro is added to the compilation
environment, and a compiled form of the expansion function is also added
to the output file so that the new macro will be operative at run time.
If this is not the desired effect, the <tt>defmacro</tt> form can be wrapped
in an <tt>eval-when</tt> construct.
<P>
It is permissible to use <tt>defmacro</tt> to redefine a macro
(for example, to install
a corrected version of an incorrect definition), or to redefine
a function as a macro.
It is an error to attempt to redefine the name of a special
form (see table <A HREF="node59.html#SPECIALFORMTABLE">5-1</A>) as a macro.
See <tt>macrolet</tt>, which establishes macro
definitions over a restricted lexical scope.
<P>
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
See also <tt>define-compiler-macro</tt>.
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
<P>
Suppose, for the sake of example, that it were desirable
to implement a conditional construct analogous to the
Fortran arithmetic IF statement. (This of course requires a certain
stretching of the imagination and suspension of disbelief.)
The construct should accept four forms: a <i>test-value</i>,
a <i>neg-form</i>, a <i>zero-form</i>, and a <i>pos-form</i>.
One of the last three forms is chosen to be executed according
to whether the value of the <i>test-form</i> is positive, negative,
or zero.
Using <tt>defmacro</tt>, a definition for such a construct
might look like this:
<P><pre>
(defmacro arithmetic-if (test neg-form zero-form pos-form)
(let ((var (gensym)))
`(let ((,var ,test))
(cond ((&lt; ,var 0) ,neg-form)
((= ,var 0) ,zero-form)
(t ,pos-form)))))
</pre><P>
Note the use of the backquote facility in this definition
(see section <A HREF="node190.html#MACROCHARACTERSSECTION">22.1.3</A>).
Also note the use of <tt>gensym</tt> to generate a new variable name.
This is necessary to avoid conflict with any variables that might
be referred to in <i>neg-form</i>, <i>zero-form</i>, or <i>pos-form</i>.
<P>
If the form is executed by the interpreter, it will cause the
function definition of the symbol <tt>arithmetic-if</tt>
to be a macro associated with which is
a two-argument expansion function roughly equivalent to
<P><pre>
(lambda (calling-form environment)
(declare (ignore environment))
(let ((var (gensym)))
(list 'let
(list (list 'var (cadr calling-form)))
(list 'cond
(list (list '&lt; var '0) (caddr calling-form))
(list (list '= var '0) (cadddr calling-form))
(list 't (fifth calling-form))))))
</pre><P>
The lambda-expression is produced by the <tt>defmacro</tt> declaration.
The calls to <tt>list</tt> are the (hypothetical) result of the backquote (<tt>`</tt>)
macro character and its associated commas.
The precise macro expansion function may depend on the implementation,
for example providing some degree of explicit error checking on the number
of argument forms in the macro call.
<P>
Now, if <tt>eval</tt> encounters
<P><pre>
(arithmetic-if (- x 4.0)
(- x)
(error &quot;Strange zero&quot;)
x)
</pre><P>
this will be expanded into something like
<P><pre>
(let ((g407 (- x 4.0)))
(cond ((&lt; g407 0) (- x))
((= g407 0) (error &quot;Strange zero&quot;))
(t x)))
</pre><P>
and <tt>eval</tt> tries again on this new form.
(It should be clear now that the backquote facility
is very useful in writing macros, since the form to be returned is
normally a complex list structure, typically consisting of a
mostly constant template with a few evaluated forms here and there.
The backquote template provides a ``picture'' of the resulting
code, with places to be filled in indicated by preceding commas.)
<P>
To expand on this example, stretching credibility to its limit,
we might allow the <i>pos-form</i>
and <i>zero-form</i> to be omitted, allowing their values to default to <tt>nil</tt>,
in much the same way that the <i>else</i> form of a Common Lisp <tt>if</tt> construct
may be omitted:
<P><pre>
(defmacro arithmetic-if (test neg-form
<tt>&amp;optional</tt> zero-form pos-form)
(let ((var (gensym)))
`(let ((,var ,test))
(cond ((&lt; ,var 0) ,neg-form)
((= ,var 0) ,zero-form)
(t ,pos-form)))))
</pre><P>
Then one could write
<P><pre>
(arithmetic-if (- x 4.0) (print x))
</pre><P>
which would be expanded into something like
<P><pre>
(let ((g408 (- x 4.0)))
(cond ((&lt; g408 0) (print x))
((= g408 0) nil)
(t nil)))
</pre><P>
The resulting code is correct but rather silly-looking.
One might rewrite the macro definition to produce better code
when <i>pos-form</i> and possibly <i>zero-form</i> are omitted,
or one might simply rely on the Common Lisp implementation to provide
a compiler smart enough to improve the code itself.
<P>
Destructuring is a very powerful facility that allows
the <tt>defmacro</tt> lambda-list to express the structure of
a complicated macro-call syntax. If no lambda-list keywords
appear, then the <tt>defmacro</tt> lambda-list is simply a list,
nested to some extent, containing parameter names at the leaves.
The macro-call form must have the same list structure.
For example, consider this macro definition:
<P><pre>
(defmacro halibut ((mouth eye1 eye2)
((fin1 length1) (fin2 length2))
tail)
...)
</pre><P>
Now consider this macro call:
<P><pre>
(halibut (m (car eyes) (cdr eyes))
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
</pre><P>
This would cause the expansion function to receive the following
values for its parameters:
<pre>
Parameter Value
---------------------------------
mouth m
eye1 (car eyes)
eye2 (cdr eyes)
fin1 f1
length1 (count-scales f1)
fin2 f2
length2 (count-scales f2)
tail my-favorite-tail
---------------------------------
</pre>
The following macro call would be in error because there would be no
argument form to match the parameter <tt>length1</tt>:
<P><pre>
(halibut (m (car eyes) (cdr eyes))
((f1) (f2 (count-scales f2)))
my-favorite-tail)
</pre><P>
The following macro call would be in error because a symbol appears
in the call where the structure of the lambda-list requires a list.
<P><pre>
(halibut my-favorite-head
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
</pre><P>
The fact that the value of the variable <tt>my-favorite-head</tt>
might happen to be a list is irrelevant here. It is the macro call
itself whose structure must match that of the <tt>defmacro</tt> lambda-list.
<P>
The use of lambda-list keywords adds even greater flexibility.
For example, suppose it is convenient within the expansion
function for <tt>halibut</tt> to be able to refer to the list
whose components are called <tt>mouth</tt>, <tt>eye1</tt>, and <tt>eye2</tt> as <tt>head</tt>.
One may write this:
<P><pre>
(defmacro halibut ((<tt>&amp;whole</tt> head mouth eye1 eye2)
((fin1 length1) (fin2 length2))
tail)
</pre><P>
Now consider the same valid macro call as before:
<P><pre>
(halibut (m (car eyes) (cdr eyes))
((f1 (count-scales f1)) (f2 (count-scales f2)))
my-favorite-tail)
</pre><P>
This would cause the expansion function to receive the same
values for its parameters and also a value for the parameter <tt>head</tt>:
<pre>
Parameter Value
------------------------------------------
head (m (car eyes) (cdr eyes))
------------------------------------------
</pre>
The stipulation that
an embedded lambda-list is permitted only
where ordinary lambda-list syntax would permit a parameter name
but not a list is made to prevent ambiguity. For example,
one may not write
<P><pre>
(defmacro loser (x <tt>&amp;optional</tt> (a b <tt>&amp;rest</tt> c) <tt>&amp;rest</tt> z)
...)
</pre><P>
because ordinary lambda-list syntax does permit a list following <tt>&amp;optional</tt>;
the list <tt>(a b <tt>&amp;rest</tt> c)</tt> would be interpreted as describing an
optional parameter named <tt>a</tt> whose default value is that of the
form <tt>b</tt>, with a supplied-p parameter named <tt>&amp;rest</tt> (not legal),
and an extraneous symbol <tt>c</tt> in the list (also not legal). An almost
correct way to express this is
<P><pre>
(defmacro loser (x <tt>&amp;optional</tt> ((a b <tt>&amp;rest</tt> c)) <tt>&amp;rest</tt> z)
...)
</pre><P>
The extra set of parentheses removes the ambiguity. However, the
definition is now incorrect because a macro call such as <tt>(loser (car pool))</tt>
would not provide any argument form for the lambda-list <tt>(a b <tt>&amp;rest</tt> c)</tt>,
and so the default value against which to match the lambda-list would be
<tt>nil</tt> because no explicit default value was specified. This is in error
because <tt>nil</tt> is an empty list; it does not have forms to satisfy the
parameters <tt>a</tt> and <tt>b</tt>. The fully correct definition would be either
<P><pre>
(defmacro loser (x <tt>&amp;optional</tt> ((a b <tt>&amp;rest</tt> c) '(nil nil)) <tt>&amp;rest</tt> z)
...)
</pre><P>
or
<P><pre>
(defmacro loser (x <tt>&amp;optional</tt> ((<tt>&amp;optional</tt> a b <tt>&amp;rest</tt> c)) <tt>&amp;rest</tt> z)
...)
</pre><P>
These differ slightly: the first requires that if the macro call
specifies <tt>a</tt> explicitly then it must also specify <tt>b</tt> explicitly,
whereas the second does not have this requirement. For example,
<P><pre>
(loser (car pool) ((+ x 1)))
</pre><P>
would be a valid call for the second definition but not for the first.
<P>
<BR> <HR><A NAME=tex2html2746 HREF="node99.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html2744 HREF="node97.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html2738 HREF="node97.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html2748 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html2749 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
<B> Next:</B> <A NAME=tex2html2747 HREF="node99.html"> Macro Expansion</A>
<B>Up:</B> <A NAME=tex2html2745 HREF="node97.html"> Macros</A>
<B> Previous:</B> <A NAME=tex2html2739 HREF="node97.html"> Macros</A>
<HR> <P>
<HR>
<P><ADDRESS>
AI.Repository@cs.cmu.edu
</ADDRESS>
</BODY>