From: Ron Garret on
Just for the record, the design that I finally settled on as the Right
Thing for symbol reader macros was this:


(let ( (r (copy-readtable nil)) )
(defun read-symbol (stream)
(let ( (*readtable* r) )
(read-preserving-whitespace stream))))

(defvar *enable-symbol-reader-macros* t)

(defun symbol-reader-macro-reader (stream char)
(unread-char char stream)
(let ( (s (read-symbol stream)) )
(if *enable-symbol-reader-macros*
(let ( (f (get s 'symbol-reader-macro)) )
(if f (funcall f stream s) s))
s)))

(defun set-macro-symbol (symbol readfn)
(setf (get symbol 'symbol-reader-macro) readfn)
t)

(map nil (lambda (c)
(set-macro-character c 'symbol-reader-macro-reader t))
"ABCDEFGHIJKLMNOPQRSTUVWXYZ")


This invokes the symbol reader macro only if the first letter of the
symbol's name is actually entered as a capital letter. I ran into too
many problems with symbol reader macros popping up where I didn't want
them in legacy code when I didn't segregate the name space this way.

There's also this related little hack:


(defvar *enable-prefix-funcall-syntax* t)

(defun prefix-funcall-syntax-reader (stream char)
(unread-char char stream)
(let ( (s (read-symbol stream)) )
(if (and *enable-prefix-funcall-syntax*
; Disable for #+foo(baz)
(not (eql (symbol-package s) (find-package :keyword)))
(eql (peek-char nil stream nil nil) #\())
(cons s (read stream))
s)))

(map nil (lambda (c) (set-macro-character c
'prefix-funcall-syntax-reader t))
"abcdefghijklmnopqrstuvwxyz")


This lets you write function calls using traditional f(x) syntax. It
requires that there be no space between the function name and the open
paren. So f(x) reads as (f x), but f (x) reads as two sexprs, f and (x).

rg