The Reader and Reader Macros
24.1 The Lisp Reader
read converts text into Lisp objects; the evaluator never sees text. The reader is controlled by the readtable and variables like *read-base*, *read-default-float-format*, *read-eval*, and *package*.
` x `, ,x, ,@x | Backquote (function f) #+sbcl form, #-windows form Feature conditionals (*features*) #1=(a. #1#) Circular structure labels #xFF #b101 #o17 #36rZ #S(point:x 1)`
(read-from-string "(+ 1 2)") ; (+ 1 2), 7
(let ((*read-base* 16)) (read-from-string "FF")) ; 255
(let ((*read-eval* nil)) (read-from-string "#.(+ 1 2)")) ; error: protects against read-time eval24.2 Defining Reader Macros
Modify a copy of the readtable ((copy-readtable)) and use the named-readtables library so custom syntax doesn't leak into other code. Reader macros are powerful but can hurt readability and tooling.
;; #[1 2 3] reads as (list 1 2 3)
(defun read-list-literal (stream subchar arg)
(declare (ignore subchar arg))
`(list ,@(read-delimited-list #\] stream t)))
(set-dispatch-macro-character #\# #\[ #'read-list-literal)
(set-macro-character #\] (get-macro-character #\)))
#[1 (+ 1 1) 3] ; (1 2 3)
;; JSON-like {"key" value} syntax building a hash table
(defun read-hash-literal (stream char)
(declare (ignore char))
(let ((items (read-delimited-list #\} stream t)))
`(let ((h (make-hash-table :test 'equal)))
,@(loop for (k v) on items by #'cddr collect `(setf (gethash ,k h) ,v))
h)))
(set-macro-character #\{ #'read-hash-literal)
(set-macro-character #\} (get-macro-character #\)))