prefix macro, similar to '?

Common Lisp macros typically use included-prefix notation: (operator stuff...)

However, the special quote macro ' uses concatenated-prefix notation: operator stuff , or alternatively operator(stuff).

I would like to create a custom macro in SBCL Common Lisp, let's call it !, that uses concatenation-prefix syntax to operate on a following list (or even atom), in a similar manner to ' . So I could invoke it anywhere, eg (setq foo !(bar) ), without it being infixed in parentheses itself.

How can this be done? What would the defmacro syntax look like? Thanks.


I see 2 ways to do it.

The first, simple variant is suitable, if you need it only for a single or very limited number of cases and you're satisfied with using just a single symbol as a prefix (like ! in the example case). You can create a read-macro, more specifically set a macro-character to substitute such operator for, say, addition:

(set-macro-character #! (lambda (stream char)
                           (declare (ignore char))
                           (cons '+ (let ((next (read stream t nil t)))
                                 (if (consp next) next
                                     (list next)))))
CL-USER> !1
1
CL-USER> !(1 2)
3

The other, more complex and more flexible way is to define a macro, inside which apply a custom transformation, that will turn concatenated-prefix code into included-prefix. This trick uses the fact, that ordinary Lisp reader will read the in the same way both foo(bar) and foo (bar) , ie it will split them into 2 elements.

The simple version of such macro may look like this:

(defmacro with-prefix-syntax (&body body)
  `(progn ,@(loop :for tail :on body :while body
                  :collect (if (and (not (atom (second tail)))
                                    (fboundp (first tail)))
                               (prog1 (cons (first tail) (second tail)
                                 (setf tail (rest tail)))
                               (first tail)))))

It will transform only top-level forms:

CL-USER> (macroexpand-1 '(with-prefix-syntax
                           print(1)))
(PROGN (PRINT 1))
CL-USER> (macroexpand-1 '(with-prefix-syntax
                           1))
(PROGN 1)
CL-USER> (macroexpand-1 '(with-prefix-syntax
                           print(1)
                           2))
(PROGN (PRINT 1) 2)

But not work in the lower levels:

CL-USER> (macroexpand-1 '(with-prefix-syntax
                           print(1)
                           (+ print(2))))
(PROGN (PRINT 1) (+ PRINT (2)))

Though it's rather easy to make it recursively transform all the layers (which is left as an exercise to the reader :)

链接地址: http://www.djcxy.com/p/52358.html

上一篇: Vim:动态语法

下一篇: 前缀宏,类似于'?