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.
(list #\a #\x41 "\x41;" #true)lispex run reader-grammar.lspxStandard 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.
| Escape | Meaning |
|---|---|
\" | double quote |
\\ | backslash |
\n | newline |
\t | tab |
\r | carriage 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
| Token | Accepted shape | Errors to watch for |
|---|---|---|
| integer | -?(0|[1-9][0-9]*) | leading zeros such as 01 give E100 |
| rational | an integer numerator, /, and a denominator matching [1-9][0-9]* | zero, negative, or leading-zero denominator gives E100 |
| real | a decimal with a fractional part, an exponent, or both | 1. 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.
| Notation | Meaning |
|---|---|
(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.