6. Primitives useful for writing macros
The Q macro system allows arbitrary program transformation
by running user-defined "macro
functions at compile time functions.
However, most of the time one only needs
simple textual replacement, perhaps with parameters, as suggested
by experience with the C pre-processor. The parse
primitive function provides this functionality.
6.1 parse
The "parse" routine takes any number of strings and/or
expressions. If there is only a single
string argument, "parse" parses the string,
and yields the resulting parse tree expression.
If there are multiple arguments, `parse' effectively parses their
concatenation: when it gets to the end of one argument,
it continues with the next. If one of the arguments is
an expression, it is substituted in place.
The "increment" macro incr
is a simple example:
| :(macro incr :Y) = parse Y ":=" Y "+1
|
The application:
is re-writtenat compile-time to:
6.2 The quote
macro
The primitive macro quote
puts quotes around its operands.
Unless there are unquote operators (using `$'),
the result is constant.
For example:
For example:
becomes:
which (if a
is has the value "4-5"
)
evaluates to the 2-element vector:
| ["~/Q/mi/parse*" "3+4-5"]
|
The quote
macro is the primitive used by all commands
that do not evaluate their arguments.
For example, the command "cd" is defined as:
| :(macro cd :x@)= parse "__cd (quote " x@ ")"
|
(The first `x@' means the list of all the remaining arguments.
The second "splices" the list `x' into `quote''s argument list.)
The body of cd
is the call: parse "__cd (quote " x@ ")"
.
First, parse
scans the string "__cd (quote ".
It then inserts the result of x@
(which is a list of
expressions, usually just one), and finishes with the
final quote bracket.
Thus:
is macro-expanded into (the parse of):
which becomes:
where __cd
is a non-macro function that does the actual work of cd
.
6.3 Features of quote
Parentheses, quoted strings, and backquotes
are included in the resulting strings. Hence:
| quote (3+4) "is"\: 10
==> ["(3+4)" "\"is\"\\:" "10"]
|
This is so avoid losing essential quoting and grouping information.
Also not that quote
works of vectors of strings,
not individual strings. If there are multiple expressions in
parentheses, the result is multiple strings:
| quote (a b)
==> ["(a)" "(b)"]
|
Concatenation of string vectors yields a distributive "join":
| quote /(a b)/(c d)/
==>
["/(a)/(c)/" "/(a)/(d)/" "/(b)/(c)/" "/(b)/(d)/"]
|
This mechanism subsumes the {...}
-feature of csh.
For example, csh's:
| cc -o foo{,.c} # csh, not Q!
|
could be expressed as:
The same distribution is done for the result of an expression
in $
. If a
has the value ["" ".c"]
,
then quote foo$a
evaluates to
["foo" "foo.c"]
.
If a
is only a simple string (such as "\n.c"
),
it is split at newlines (so we get the same result as before).
This document was generated
by Per Bothner on December, 4 2001
using texi2html