23.1 Reader Concepts

\DefineSection{ReaderConcepts}

\beginsubsection{Dynamic Control of the Lisp Reader}

Various aspects of the Lisp reader can be controlled dynamically. \Seesection\Readtables\ and \secref\ReaderVars.

\endsubsection%{Dynamic Control of the Lisp Reader}

\beginsubsection{Effect of Readtable Case on the Lisp Reader} \DefineSection{ReadtableCaseReadEffect}

The readtable case of the current readtable affects the Lisp reader in the following ways:

\beginlist \itemitem{\kwd{upcase}}

When the readtable case is \kwd{upcase}, unescaped constituent characters are converted to uppercase, as specified in \secref\ReaderAlgorithm.

\itemitem{\kwd{downcase}}

When the readtable case is \kwd{downcase}, unescaped constituent characters are converted to lowercase.

\itemitem{\kwd{preserve}}

When the readtable case is \kwd{preserve}, the case of all characters remains unchanged.

\itemitem{\kwd{invert}}

When the readtable case is \kwd{invert}, then if all of the unescaped letters in the extended token are of the same case, those (unescaped) letters are converted to the opposite case.

\endlist

\beginsubsubsection{Examples of Effect of Readtable Case on the Lisp Reader} \DefineSection{ReadtableCaseReadExamples}

\code (defun test-readtable-case-reading () (let ((*readtable* (copy-readtable nil))) (format t "READTABLE-CASE Input Symbol-name~ ~%-----------------------------------~ ~%") (dolist (readtable-case '(:upcase :downcase :preserve :invert)) (setf (readtable-case *readtable*) readtable-case) (dolist (input '("ZEBRA" "Zebra" "zebra")) (format t "~&:~A~16T~A~24T~A" (string-upcase readtable-case) input (symbol-name (read-from-string input))))))) \endcode

The output from \f{(test-readtable-case-reading)} should be as follows:

\code READTABLE-CASE Input Symbol-name ------------------------------------- :UPCASE ZEBRA ZEBRA :UPCASE Zebra ZEBRA :UPCASE zebra ZEBRA :DOWNCASE ZEBRA zebra :DOWNCASE Zebra zebra :DOWNCASE zebra zebra :PRESERVE ZEBRA ZEBRA :PRESERVE Zebra Zebra :PRESERVE zebra zebra :INVERT ZEBRA zebra :INVERT Zebra Zebra :INVERT zebra ZEBRA \endcode

\endsubsubsection%{Examples of Effect of Readtable Case on the Lisp Reader}

\endsubsection%{Effect of Readtable Case on the Lisp Reader}

\beginsubsection{Argument Conventions of Some Reader Functions}

\beginsubsubsection{The EOF-ERROR-P argument}

\param{Eof-error-p} in input function calls controls what happens if input is from a file (or any other input source that has a definite end) and the end of the file is reached. If \param{eof-error-p} is true (the default), an error \oftype{end-of-file} is signaled at end of file. If it is false, then no error is signaled, and instead the function returns \param{eof-value}.

Functions such as read that read the representation of an object rather than a single character always signals an error, regardless of \param{eof-error-p}, if the file ends in the middle of an object representation. For example, if a file does not contain enough right parentheses to balance the left parentheses in it, read signals an error. If a file ends in a symbol or a number immediately followed by end-of-file, read reads the symbol or number successfully and when called again will act according to \param{eof-error-p}. Similarly, \thefunction{read-line} successfully reads the last line of a file even if that line is terminated by end-of-file rather than the newline character. Ignorable text, such as lines containing only whitespace\meaning{2} or comments, are not considered to begin an object; if read begins to read an expression but sees only such ignorable text, it does not consider the file to end in the middle of an object. Thus an \param{eof-error-p} argument controls what happens when the file ends between objects.

\endsubsubsection%{The EOF-ERROR-P argument}

\beginsubsubsection{The RECURSIVE-P argument}

If \param{recursive-p} is supplied and not \nil, it specifies that this function call is not an outermost call to read but an embedded call, typically from a reader macro function. It is important to distinguish such recursive calls for three reasons.

\beginlist \itemitem{1.} An outermost call establishes the context within which the \f{\#\param{n}=} and \f{\#\param{n}\#} syntax is scoped. Consider, for example, the expression

\code (cons '#3=(p q r) '(x y . #3#)) \endcode If the single-quote reader macro were defined in this way:

\code (set-macro-character #\\' ;incorrect #'(lambda (stream char) (declare (ignore char)) (list 'quote (read stream)))) \endcode

then each call to the single-quote reader macro function would establish independent contexts for the scope of read information, including the scope of identifications between markers like ``\f{\#3=}'' and ``\f{\#3\#}''. However, for this expression, the scope was clearly intended to be determined by the outer set of parentheses, so such a definition would be incorrect. The correct way to define the single-quote reader macro uses \param{recursive-p}:

\code (set-macro-character #\\' ;correct #'(lambda (stream char) (declare (ignore char)) (list 'quote (read stream t nil t)))) \endcode

\itemitem{2.} A recursive call does not alter whether the reading process is to preserve whitespace\meaning{2} or not (as determined by whether the outermost call was to read or read-preserving-whitespace). Suppose again that single-quote were to be defined as shown above in the incorrect definition. Then a call to read-preserving-whitespace that read the expression \f{'foo\SpaceChar} would fail to preserve the space character following the symbol \f{foo} because the single-quote reader macro function calls read, not read-preserving-whitespace, to read the following expression (in this case \f{foo}). The correct definition, which passes the value true for \param{recursive-p} to read, allows the outermost call to determine whether whitespace\meaning{2} is preserved.

\itemitem{3.} When end-of-file is encountered and the \param{eof-error-p} argument is not \nil, the kind of error that is signaled may depend on the value of \param{recursive-p}. If \param{recursive-p} is true, then the end-of-file is deemed to have occurred within the middle of a printed representation; if \param{recursive-p} is false, then the end-of-file may be deemed to have occurred between objects rather than within the middle of one.

\endlist

\endsubsubsection%{The EOF-ERROR-P argument}

\endsubsection%{Argument Conventions of Some Reader Functions}