Reference for Reading Code

Look up accepted numbers, names, strings, characters, lists, vectors, quotation, and comments.

Use this reference to check how to spell a token and interpret a reading error. The reader checks source notation before the normalizer checks expression shapes.

Compare characters and strings

Save this complete program as reader-grammar.lspx. Use the Native CLI to run it.

LISPEX
(list #\a #\x41 "\x41;" #true)
SH
lispex run reader-grammar.lspx

Standard output is.

(#\a #\A "A" #t)

The exit code is 0, standard error is empty, and no files are created. The first two items are characters, and the third is a string. #true has the same value as #t. Likewise, #false is #f.

Characters and string escapes

A character starts with #\. Follow it with a single Unicode scalar, a hexadecimal code such as x41, or one of the names below. A Unicode scalar is a Unicode code point other than a surrogate.

The fourteen character names are space, newline, linefeed, tab, return, null, nul, delete, rubout, escape, esc, backspace, alarm, and page.

Strings are enclosed in double quotes. Inside a string, these are the six accepted escape forms.

EscapeMeaning
\"double quote
\\backslash
\nnewline
\ttab
\rcarriage return
\xHEX;Unicode scalar written with one or more hexadecimal digits

Invalid escapes, including \a, produce E150. Invalid character names and scalar values also produce E150.

The string escape \x41; ends with a semicolon. The character #\x41 ends at a delimiter or the end of input. A semicolon after that character starts a line comment. Thus #\x41; is accepted as #\A followed by a comment.

Numbers

TokenAccepted shapeErrors to watch for
integer-?(0|[1-9][0-9]*)leading zeros such as 01 give E100
rationalan integer numerator, /, and a denominator matching [1-9][0-9]*zero, negative, or leading-zero denominator gives E100
reala decimal with a fractional part, an exponent, or both1. gives E100. a value outside the finite range gives E314

The notation ? means optional, * means zero or more repetitions, and + means one or more. Brackets describe a range of digits, and | separates alternatives.

The full real pattern is -?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?. At least a fractional part or an exponent must be present. A decimal point needs digits on both sides.

Rationals are reduced when read, so 4/2 becomes the exact integer 2. The integer, rational, and real spellings are distinct.

A leading + makes a name. For example, (define +5 7) binds the name +5 to 7. Radix and exactness prefixes such as #x, #b, #o, #e, and #i produce E100.

Names, lists, and quotation

Names are case-sensitive. Unicode names are handled as written, without normalization. A name such as alpha is read as a symbol. Whether it can be bound or used in code is covered by Reserved and Forbidden Names.

NotationMeaning
(a b)a list
(a . b)a pair whose tail is b
#(1 2)a vector
#u8(1 2)a bytevector
'x(quote x)
`x(quasiquote x)
,x(unquote x)
,@x(unquote-splicing x)

The reader recognizes quotation prefixes. The normalizer checks where unquotation is allowed.

Lists use ( and ). Square and curly brackets produce E100. A dot marks a dotted tail only when followed by a delimiter. Names such as ... and .foo remain symbols. A dot in a vector, as in #(1 . 2), produces E100.

Bytevector elements must be integer literals from 0 through 255. The reader rejects #u8(4/2) with E100 even though 4/2 has the value 2. Unclosed delimiters and misplaced dots are also checked during reading.

Whitespace, comments, and locations

Whitespace separates tokens. A semicolon starts a line comment, and #| ... |# encloses a block comment. Block comments can be nested. The reader rejects #; datum comments and #lang directives with E120.

Diagnostics identify the input and its line and column, counted from one. For a walkthrough of reading, normalization, and evaluation, see How Lispex Reads Code.

Error and Warning Catalog