set-macro-character, get-macro-character
set-macro-character, get-macro-character Function
Syntax:
get-macro-character char &optional readtable → function, non-terminating-p
set-macro-character char new-function &optional non-terminating-p readtable → t
Arguments and Values:
char—a character .
non-terminating-p—a generalized boolean. The default is false.
set-macro-character, get-macro-character
readtable—a readtable designator . The default is the current readtable.
function—nil, or a designator for a function of two arguments.
new-function—a function designator .
Description:
get-macro-character returns as its primary value, function, the reader macro function associated with char in readtable (if any), or else nil if char is not a macro character in readtable. The secondary value, non-terminating-p, is true if char is a non-terminating macro character ; otherwise, it is false.
set-macro-character causes char to be a macro character associated with the reader macro function new-function (or the designator for new-function) in readtable. If non-terminating-p is true, char becomes a non-terminating macro character ; otherwise it becomes a terminating macro character .
Examples:
(get-macro-character #\\{) → NIL, *false*
(not (get-macro-character #\;)) → false
The following is a possible definition for the *single-quote reader macro* in *standard syntax* :
(defun single-quote-reader (stream char)
(declare (ignore char))
(list ’quote (read stream t nil t))) → SINGLE-QUOTE-READER
(set-macro-character #\’ #’single-quote-reader) → T
Here single-quote-reader reads an *object* following the *single-quote* and returns a *list* of **quote** and that *object*. The *char* argument is ignored.
The following is a possible definition for the *semicolon reader macro* in *standard syntax* :
(defun semicolon-reader (stream char)
(declare (ignore char))
;; First swallow the rest of the current input line.
;; End-of-file is acceptable for terminating the comment.
(do () ((char= (read-char stream nil #\Newline t) #\Newline)))
;; Return zero values.
(values)) → SEMICOLON-READER
(set-macro-character #\; #’semicolon-reader) → T
Side Effects:
The readtable is modified.
See Also:
*readtable*Expanded Reference: set-macro-character, get-macro-character
Querying existing macro characters
get-macro-character returns two values: the reader macro function associated with a character (or nil if it is not a macro character), and whether it is non-terminating.
;; The single-quote is a standard terminating macro character
(multiple-value-bind (fn non-term-p)
(get-macro-character #\')
(list (not (null fn)) non-term-p))
=> (T NIL)
;; The semicolon is a standard terminating macro character
(not (null (get-macro-character #\;)))
=> T
;; A letter is not a macro character
(get-macro-character #\a)
=> NIL
=> NIL
Defining a simple reader macro
set-macro-character installs a reader macro function for a character. The function receives the stream and the character that triggered it.
;; Define a reader macro that makes ! read the next object and wrap it in (not ...)
(let ((*readtable* (copy-readtable)))
(set-macro-character #\!
(lambda (stream char)
(declare (ignore char))
(list 'not (read stream t nil t))))
(with-input-from-string (s "!x")
(read s)))
=> (NOT X)
Implementing a single-quote-like reader macro
Here is an example of how the ' (single-quote) reader macro could be defined.
(let ((*readtable* (copy-readtable)))
(set-macro-character #\'
(lambda (stream char)
(declare (ignore char))
(list 'quote (read stream t nil t))))
(with-input-from-string (s "'hello")
(read s)))
=> (QUOTE HELLO)
Terminating vs. non-terminating macro characters
A terminating macro character ends a token when encountered. A non-terminating macro character does not end tokens (like #). Pass t as the third argument to make a non-terminating macro character.
(let ((*readtable* (copy-readtable)))
;; Terminating: ends a token
(set-macro-character #\!
(lambda (stream char)
(declare (ignore stream char))
:bang)
nil) ; terminating (default)
(with-input-from-string (s "abc!def")
(list (read s) (read s))))
=> (ABC :BANG)
Specifying a readtable
Both functions accept an optional readtable argument. This lets you install or query macro characters in a readtable other than the current one.
(let ((rt (copy-readtable)))
(set-macro-character #\@
(lambda (stream char)
(declare (ignore char))
(list 'at (read stream t nil t)))
nil
rt)
;; Query the macro character in that specific readtable
(not (null (get-macro-character #\@ rt))))
=> T