I mentioned "lenient structs" at the meeting today and like I said they are a simple but useful example of read macros. A lenient struct is a class wrapper around a list with a special print-object method that makes it print like a struct. The only (defined) thing you can do with lenient structs is print them back out again.
Here's the interesting part about lenient structs with respect to read macros: The with-lenient-struct-reader macro installs a custom reader function in a read-table that, when in effect, will cause read-from-string et al to read #S(...) forms as lenient structs instead of regular structs, overriding the system's structure reader function.
Lenient structs are used in antiweb so that an intermediate lisp image process in an antiweb system doesn't need to have the structure in question's defstruct definition in order to read it in, process it (as an atom), store it to a DB, read it back out, and print it out to another process.
;; lenient-struct is so we can read in and print out structs even without a corresponding defstruct (defclass lenient-struct () ((contents :accessor lenient-struct-contents :initform nil :initarg :contents)))
(defmethod print-object ((l lenient-struct) (s stream)) (format s "#S~S" (lenient-struct-contents l)))
(defmacro! with-lenient-struct-reader (&rest body) `(let ((*readtable* (copy-readtable *readtable*))) (let ((,g!read-handler (lambda (stream sub-char numarg) (declare (ignore sub-char numarg)) (unless (char= #( (read-char stream)) ;) (error "bad lenient-struct form")) ;( (make-instance 'lenient-struct :contents (read-delimited-list #) stream t))))) (set-dispatch-macro-character ## #\s ,g!read-handler) (set-dispatch-macro-character ## #\S ,g!read-handler) ,@body)))