This page follows the lexical syntax of R7RS-small (sections 2 and 7.1.1) and notes where R5RS and R6RS differ. A Scheme reader turns characters into tokens, and the tokens into data; a program is data that the evaluator reads as code. The same reader reads read’s input, so a token that is valid in a program is valid data and the reverse.
Delimiters, whitespace and the reserved characters
A token ends at a delimiter: whitespace, a vertical line |, (, ), " or ;. R6RS also makes [ and ] delimiters and lexemes. Whitespace may occur between any two tokens, but not inside one, and is significant only inside strings and | | symbols.
| Characters | Meaning |
|---|---|
( ) | Open and close a list (and, for a call, a procedure call or a special form) |
[ ] | Reserved in R7RS and R5RS. Lexemes of R6RS, read as parentheses by Chez, Guile, CHICKEN, Gambit, Larceny and others |
{ } | Reserved in R7RS and R6RS. Curly-infix in SRFI 105, a bracket in several implementations |
' | Quote the next datum: 'x reads as (quote x) |
` | Quasiquote: `x reads as (quasiquote x) |
, and ,@ | Unquote and unquote-splicing inside a quasiquote |
" | Opens and closes a string |
; | Starts a comment to the end of the line |
| | Opens and closes a symbol written between vertical lines |
\ | Only inside a character, a string or a | | symbol |
# | Starts one of the forms below, depending on the character after it |
. | A lone period separates the last element of an improper list ((a . b)) and marks a rest parameter; two or more periods are an identifier |
The viewer ends a token at whitespace, ( ) [ ] { }, ", ;, |, ', ` and ,. Treating the quote marks as delimiters differs from the grammar of the reports, in which they cannot appear inside an identifier either, so no valid program changes.
Comments
| Form | Meaning | Since |
|---|---|---|
; text | Comment to the end of the line. By convention ; trails code on a line, ;; comments a line of code and ;;; heads a section | All |
#| text |# | Block comment; blocks nest, so #| a #| b |# c |# is one comment | R6RS, R7RS (SRFI 30) |
#;datum | Datum comment: the next datum (after optional whitespace and comments) is skipped, whatever its length | R6RS, R7RS (SRFI 62) |
#!fold-case, #!no-fold-case | Directives that count as comments but turn case folding on or off for the rest of the port. They must be followed by a delimiter | R7RS |
#!r6rs | Marks a file as R6RS source; counts as a comment | R6RS |
#!/usr/bin/… | Shebang line; a comment in practice, and in SRFI 22 scripts | Implementations |
#! … !# | Block comment of Guile and others, used to end a multi-line shebang | Implementations |
An unterminated #| runs to the end of the text, and the viewer does the same. A #; before ) or at the end of the text comments nothing. The viewer finds the end of a datum comment by reading the datum: a list with its nested brackets, strings, | | symbols, characters, quote marks, nested comments and prefixes such as #u8 and #0=. Several #; in a row each skip one datum.
#|
The FACT procedure computes the factorial
of a non-negative integer.
|#
(define fact
(lambda (n)
(if (= n 0)
#;(= n 1)
1 ;Base case: return 1
(* n (fact (- n 1))))))
Identifiers
An identifier is a sequence of letters, digits and extended identifier characters that does not start like a number. R7RS requires these extended characters: ! $ % & * + - . / : < = > ? @ ^ _ ~. The first character may not be a digit, +, - or . unless the identifier is a peculiar identifier: +, -, ..., or a sign or dot followed by characters that cannot begin a number (->string, +soup+, -x, .foo). +5 and -i are numbers. 1+ and -1+ begin like numbers, so the grammar of the reports does not allow them as identifiers (the R7RS source has the two names commented out), but MIT/GNU Scheme, Guile, CHICKEN and others read them as the names of the procedures that add and subtract one, and the viewer does too. Implementations may allow Unicode letters and symbols beyond ASCII.
Identifiers are case-sensitive in R6RS and R7RS, and were not in R5RS and earlier (FOO and foo were the same). R7RS lets a program ask for folding with #!fold-case. All standard names are in lower case.
Vertical-line symbols
Any characters, including whitespace, between two vertical lines make a symbol: |two words|, || (the empty symbol). Inside the bars, \| is a bar, and the escapes of strings are allowed: \a \b \t \n \r and \x<hex>;. So |H\x65;llo| is the symbol Hello and |\t\t| is the same as |\x9;\x9;|.
Keyword-style identifiers
Several implementations read an identifier of the shape #:key (Guile, Racket), key: (Gambit, CHICKEN, SRFI 88) or :key as a self-evaluating keyword object. The viewer colours these three shapes as literals.
Other symbol syntaxes
Guile writes a symbol with any characters as #{any text}#; the viewer reads it as one plain token, up to 4096 characters. Chez and Racket read #%name for a primitive, which the viewer takes as an ordinary identifier.
Booleans
#t and #f are true and false; R7RS also accepts the long forms #true and #false. R5RS and R6RS also read #T and #F, and the viewer colours them too. The token must end at a delimiter, so #tx is not a boolean.
Characters
A character is #\ followed by one character, by a name, or by x and hexadecimal digits. The character after #\ is taken whatever it is, so #\(, #\), #\;, #\" and #\# are characters. A character must be followed by a delimiter or the end of the text.
| Name | Character | Report |
|---|---|---|
#\alarm | U+0007 | R6RS, R7RS |
#\backspace | U+0008 | R6RS, R7RS |
#\delete | U+007F | R6RS, R7RS |
#\escape | U+001B | R7RS (R6RS: #\esc) |
#\newline | U+000A | R5RS, R6RS, R7RS |
#\null | U+0000 | R7RS (R6RS: #\nul) |
#\return | U+000D | R6RS, R7RS |
#\space | U+0020 | R5RS, R6RS, R7RS |
#\tab | U+0009 | R6RS, R7RS |
#\linefeed, #\vtab, #\page | U+000A, U+000B, U+000C | R6RS only |
#\x41 | U+0041; hex digits, any case, up to the Unicode limit | R6RS, R7RS |
Case matters in names (#\Space is an error in R6RS and R7RS, and #\space the same as #\SPACE in R5RS) but not in hex digits. #\x alone is the letter x; #\xFF is U+00FF. Implementations add names such as #\nul, #\altmode, #\rubout, the ASCII control names, and the form #\U+41 (Gambit). The viewer colours the whole token, whichever name follows, as a string-class literal, as it does for the same form in Common Lisp.
Strings
A string is characters between double quotes. A line ending inside a string is part of the string. The escapes are these:
| Escape | Meaning | Report |
|---|---|---|
\a | Alarm, U+0007 | R6RS, R7RS |
\b | Backspace, U+0008 | R6RS, R7RS |
\t | Tab, U+0009 | R6RS, R7RS |
\n | Newline, U+000A | R6RS, R7RS |
\r | Return, U+000D | R6RS, R7RS |
\v, \f | Vertical tab U+000B, form feed U+000C | R6RS only |
\", \\ | The quote and the backslash | All |
\| | A vertical line | R7RS |
\x41; | The character with that hexadecimal value; the semicolon is required | R6RS, R7RS |
\ then optional space and tab, a line ending, optional space and tab | Line continuation: all of it is removed, so a long string can be broken over lines | R6RS, R7RS |
R5RS knew only \" and \\. The viewer colours the whole of a string as a string and each escape as a literal; it accepts any character after a backslash as a two-character escape, a hex escape with or without the closing semicolon, and the \uXXXX and \UXXXXXXXX forms that Guile and others read. An unterminated string runs to the end of the text.
Inside the first or second argument of format, simple-format, printf or fprintf, the viewer also marks the format directives (~a, ~s, ~d, ~%, ~~ and the other ~ sequences with prefix arguments) as directives. format is not in the reports; it comes from SRFI 28 and from each implementation.
Numbers
A number is an optional prefix and then a complex number. The prefix is a radix, an exactness, or both in either order:
| Prefix | Meaning |
|---|---|
#b, #o, #d, #x | Binary, octal, decimal (the default), hexadecimal |
#e, #i | Exact, inexact |
#e#x, #x#e | Both, in either order |
Prefixes and every letter in a number may be in upper or lower case. Decimal points and exponents are possible only in radix 10.
| Kind | Syntax | Examples |
|---|---|---|
| Integer | Digits of the radix, with an optional sign | 42 -7 +0 #xFF #b-101 #o17 |
| Rational | Integer, /, integer | 1/2 -22/7 #x1/F |
| Decimal | Digits with a point, or digits with an exponent, or a point and digits; the exponent marker is e (R5RS and R6RS also s f d l) and a sign is allowed | 1.5 .5 -3. 1e10 1.5e-3 6.02E+23 |
| Infinity and NaN | +inf.0 -inf.0 +nan.0 -nan.0, with a sign, always inexact | +inf.0 -nan.0 |
| Rectangular complex | Real, then a signed unsigned-real and i; or a signed real, +i, -i, or an infinity or NaN followed by i | 1+2i -1.5-0.5i +i 3-i +inf.0i 1+inf.0i |
| Polar complex | Real, @, real | 1@2 -1.5@+3.14 |
| With exactness | A prefix as above | #e1.5 (exact 3/2) #i3/4 (0.75) #x#e-1F #e#x1F |
Syntax that older or other reports add, and that the viewer colours as a number:
- R5RS allows
#in place of trailing digits for imprecise values:1#.#,12##. R7RS no longer requires it. - R5RS and R6RS allow
s,f,dandlas exponent markers (short, single, double and long precision), and R6RS allows a mantissa width after a bar:1.5|53. R7RS did not adopt either.
Tokens that look nearly like numbers but are not are identifiers, and the viewer leaves them plain: +, -, ..., 1+, -1+, 1e, 12abc, .e5, 1/2/3, +inf.1. A number may not be longer than 400 characters for the viewer to read it in full; a longer run of digits is still a number.
Quote marks and abbreviations
| Written | Reads as | Since |
|---|---|---|
'datum | (quote datum) | All |
`datum | (quasiquote datum) | All |
,datum | (unquote datum) | All |
,@datum | (unquote-splicing datum) | All |
#'datum | (syntax datum) | R6RS |
#`datum | (quasisyntax datum) | R6RS |
#,datum | (unsyntax datum) | R6RS |
#,@datum | (unsyntax-splicing datum) | R6RS |
The viewer colours each mark as a directive, and reads the datum that follows as data after ', as a template with holes after `, and as code after a , inside a quasiquote and after the syntax forms of R6RS.
Vectors, bytevectors and other compound forms
| Written | Meaning | Since |
|---|---|---|
(a b c) | A list; (a . b) a pair; (a b . c) an improper list; () the empty list | All |
#(a b c) | A vector. It evaluates to itself, without a quote, from R7RS (R5RS: needs a quote) | All |
#u8(1 2 255) | A bytevector: bytes between 0 and 255; evaluates to itself | R7RS (SRFI 4 spelling) |
#vu8(1 2 255) | A bytevector | R6RS |
#s8( ), #u16( ), #s16( ), #u32( ), #s32( ), #u64( ), #s64( ), #f32( ), #f64( ) | The other homogeneous numeric vectors of SRFI 4 (SRFI 160) | Implementations |
#2a((1 2) (3 4)) | A multi-dimensional array literal (SRFI 58, 163) | Implementations |
Datum labels
#0=datum labels a datum and #0# refers to it, so that shared and circular structure can be written: #0=(a b c . #0#) is a circular list of three elements. The number is a sequence of decimal digits. A reference must come after its label, and a datum cannot be only a reference to itself. This is in R7RS (and SRFI 38) and is read by several earlier systems.
Other reader forms of single implementations
#!eof,#!default,#!unspecific,#!void,#!undefined,#!unbound– objects written with#!in Guile, MIT/GNU, Gambit and others. The viewer colours them as literals.#!optional,#!rest,#!key– markers in a lambda list (MIT/GNU, Gambit, Guile). Coloured as directives.#<unspecified>,#<eof>,#<procedure car>– printed representations, which cannot be read back. A REPL transcript contains them. Coloured as literals when the closing bracket is on the same line within 200 characters.#<<END…END– CHICKEN’s here string, and#<#ENDthe same with interpolation; coloured as a string up to the line that holds only the tag.#>…<#– CHICKEN’s block of C code (also#>!,#>?); the viewer colours the C inside as C.#,(constructor args)– SRFI 10 read-time constructors.
How the viewer colours a file
The viewer reads a file the way the reader does: it never starts a token inside a string, a comment or a | | symbol. Then it colours each token for what it is, and keeps one context for every open list, so that it knows what each name in a form means.
| Colour class | What it marks |
|---|---|
| Comment | ; lines, #| |# blocks (nested), #; data, a #!/ first line and #! … !# blocks |
| String | strings, character literals (#\a #\space #\x41), here strings, and the text between the escapes and directives of a string |
| Number | every number form of the table above |
| Keyword | syntax: define, lambda, let and every other syntax keyword of R5RS, R6RS and R7RS, else, =>, ..., the define- forms, the syntax of the common implementations, and the words only except prefix rename in an import set and fields mutable immutable parent protocol in an R6RS record |
| Function | every procedure of the three reports and of the SRFIs listed under SRFI, wherever it appears; the name at the head of a call; the name in a define, a named let, a record constructor, predicate, accessor and modifier |
| Variable | the names a form binds: lambda parameters, let variables, do variables, defined variables, pattern variables of syntax-rules, record field names, guard variables, and earmuffed names such as *count* |
| Type | record type names, <name> class names, R6RS condition types such as &error, and the library names in import, library and define-library |
| Literal | #t #f #true #false, string escapes, keyword-style identifiers, #!eof and its relatives, printed objects, and the identifiers of cond-expand features |
| Directive | the quote marks ' ` , ,@ #' #` #, #,@, #!fold-case and its relatives, vector prefixes (#u8), datum labels (#0= #0#), format directives, and #>…<# markers |
Quoted data is not coloured as code: in '(if a b) nothing is a keyword, and in a quasiquote only the unquoted parts are code. A name that merely follows an opening bracket is a call, so a user-defined procedure is coloured as a function; a user-defined macro is coloured as a function unless its name starts define-. A colour follows the standard name wherever it stands, so list used as a variable is still coloured as the procedure.
(define-record-type point
(make-point x y)
point?
(x point-x set-point-x!)
(y point-y))
(define-syntax swap!
(syntax-rules ()
((_ a b) (let ((tmp a)) (set! a b) (set! b tmp)))))
(let loop ((i 0) (acc '()))
(if (< i 3)
(loop (+ i 1) (cons (make-point i #\a) acc))
(reverse acc)))
Not described
Known, not yet covered
- Viewer: the character names of Gambit, Guile, MIT/GNU and others beyond those in the table are not checked, since the viewer colours any token after
#\as a character. - Viewer: case folding is not applied: after
#!fold-casethe viewer still compares names exactly, so(DEFINE x 1)is not coloured as a definition even when the program reads it so. - Viewer: SRFI 169 underscores in numbers (
1_000), SRFI 267 raw strings, SRFI 270 hexadecimal floats, SRFI 108 and 109 quasi-literals, SRFI 107 XML syntax, SRFI 119 and 110 indentation syntax, and Racket’s#pxand#rxliterals in a file that does not open with#langare not recognised.
Unknown
- Reference: which implementations accept
#trueand#false, the#u8spelling and datum labels is not tabulated; the table above gives the report that defines each form.
See also
- Data types – what each token reads as
- Macros – the pattern language and its colours
- Procedures and numbers – the numeric tower behind the number syntax