The Revised Maclisp ManualThe PitmanualPage A-20
Published by HyperMeta Inc.
Prev | Index | Next
[Blue Marble]
Climate Change
Is it really safe to play “wait and see?”


SETSYNTAXFunction(SETSYNTAX character data1 data2)

Sets the syntax bits and/or macro property of the given character.

Web-Only Note:

The rest of this entry for SETSYNTAX was something I puzzled out while trying to put together the Sunday Morning Edition. I hope it's at least approximately right. -KMP, 13 Jun 2007

In general, if the data2 is a FIXNUM, SETSYNTAX will treat it as a "translation character" (see the CHTRAN option to STATUS and SSTATUS). If the data2 is a function name (symbol or LAMBDA expression), SETSYNTAX will assign a "readmacro" which is that function.

If data1 is the symbol MACRO and data2 is a function, arranges for function to be called when the character is found by READ. The result of the call is the result is used by READ directly. For example:

=> READ2
=> T
'$3 4
=> (3 4)
=> T
=> (FOO FOO)

If data1 is the symbol SPLICING and data2 is a function, arranges for function to be called when the character is found by READ. In this case, the result of the call is "spliced" into the containing list. (It's an error if there is no containing list.) Here's an example:

(setsyntax #/@ 'splicing 'read2)
=> T
'($3 4 @3 4)
=> ((3 4) 3 4)
;;; Don't return a list longer than one at toplevel!
@3 4

Note that the semicolon readmacro is implemented as a splicing macro that simply returns the empty list (see +INTERNAL-/;-MACRO).

(defun skip1 () (read) nil) ;read but discard a form
=> SKIP1
=> T
'(foo &(a b c) bar)
=> (FOO BAR)

If data1 is the symbol SINGLE and data2 is a character to translate to, then when READ sees the character, it will substitute a symbol whose name is the single character having the code given by data2.

(setsyntax #/@ 'single #/@)
=> T
=> (FOO /@ BAR)
=> T
=> (FOO A BAR)

With some care, individual syntax bits can be assigned. See (STATUS SYNTAX) for details on the bits.

(SETSYNTAX #/& #o40000 #/&)
=> T
=> (ABC)

See also: (STATUS SYNTAX), (STATUS CHTRAN character)

To see a list of pre-defined readmacros, see the Reader Macro Index.

/ (Slash)Reader Macro

Typing the character slash makes the next character not have its normal reader syntax and behave as alphabetic instead. For example, to keep the semicolon character from being a comment character and to type the symbol whose name is the three characters "A;B" you can type "A/;B". To type a slash, you must quote it with a slash. Hence, the division operator, whose name is the single character "/" must be typed as "//". Slashing a character which already has alphabetic syntax has no effect. The syntaxes /F/O/O and FOO denote the same three-letter symbol FOO. Except on Multics, lowercase characters will be uppercased by READ. Typing slashes before lowercase characters will inhibit this effect. The syntax Foo denotes the symbol FOO, but the syntax F/o/o denotes the symbol |Foo| (see below).

| (Vertical Bar)Reader Macro

Typing lots of slashes may get to be tedious. For example, the symbol named "..." can be typed as "/././." but it can also be typed as "|...|". Placing vertical bars around a section of text is the same as typing slash before each of the characters with the following exception: Slash can still be inserted before characters inside of vertical bars. Before any character except "/" or "|" it is ignored, but before those characters, it makes their normal syntax not apply.

This process of attaching slashes or vertical bars is called slashification. Lisp's internal representation of symbols' pnames does not include any information about slashification; it only includes the characters which really make up the symbol's name. The Lisp output function PRINC will print objects without slashification, but that output will not be suitable for being re-read by READ. the PRIN1 (and PRINT) functions will output objects with any slashification necessary for them to be later re-read by READ. Because symbols have more than one input syntax, PRIN1 will try to select what it feels is the most aesthetic presentation style to type the symbol back at you. Here are some examples of ways a programmer might input some symbols and how PRINC and PRIN1 would display those symbols.

Using vbars Using slashes Result of PRINC Result of PRIN1 
|//| // / // 
|abc| /a/b/c abc |abc| 
|a| /a a /a 
|abc /|| /a/b/c/ /| abc | |abc /|| 
|.| /. . |.| 
|FOO-x| foo-/x FOO-x FOO-/x 
|(X Y)| /(X/ Y/) (X Y) |(X Y)| 
|//A| //a /A //A 
|//a| ///a /a |//a| 

' (Quote)Reader MacroQUOTE

Typing 'form is equivalent to typing (QUOTE form).

#' (Sharp Quote)Reader MacroFUNCTION

Typing #'form is equivalent to typing (FUNCTION form). The shorthand form is preferred.


; (Semicolon)Reader MacroComment

Typing semicolon begins a comment field which extends to the end of the line (marked by a carriage return). Semicolon commenting is implemented as a splicing readmacro, so is suppressed immediately after a slash or anywhere between matched vertical bars or doublequotes. For example, the expression

(+ 1 ;adjusts for a fencepost error
   x y)

is the same as (+ 1 x y).


_ (Underscore)Reader MacroFixnum Left Shift

If "_" occurs inside a fixnum, it means left shift the number to the left by the amount specified to the right. e.g., 3_18. is the same as #o3000000. This syntax always yields a fixnum.

Web-Only Note:

Yes, those are 6 octal zeros because 3 shifted by 18 (decimal) bits is #2r11000000000000000000, or #o3000000 since the 18 binary zeros contract to 6 octal zeros.

Note also that, in the hardcopy version of this manual, the underscore character appeared in headings as a left-pointing arrow. This is because in early character coding systems, the code for that character sometimes displayed as an underscore and sometimes as a left arrow.

It may not be obvious why this is a Reader Macro. The behavior isn't implemented by a function but by the syntax bits. The following example may help. (Note that the base used is octal, so decoding the bits should be easy. Note also that the 20(octal) bit says this is a shifter, and the 40(octal) bit distinguishes this case from Uparrow (^).)

=> 62 ; 40(octal) + 20(octal) + 2
=> T
=> 140
=> 140

^ (Uparrow)Reader MacroInteger Exponentiation

If "^" occurs inside a fixnum, as in n^m, it means add m zeros to the end of n. Note that both n and m are read in the current radix. e.g., #o3^10 is the same as #o300000000.

Web-Only Note:

Yes, those are 8 octal zeros because 3 x 10^10 in base 8 is #o300000000. Note also that uparrow and caret were largely synonymous in the context of Maclisp. The hardcopy manual is inconsistent as to which notation is used where; for simplicity, caret is used uniformly in this webbed edition.

It may not be obvious why this is a Reader Macro. The behavior isn't implemented by a function but by the syntax bits. The following example may help. (Note that the base used is octal, so decoding the bits should be easy. Note also that the 20(octal) bits says this is a shifter, and the lack of a 40(octal) bit distinguishes this case from Underscore (_).)

=> 22 ; 20(octal) + 2
=> T
=> 300000
=> 300000

#| (Sharp Vertical Bar)Reader MacroComment

An expression of the form "#|...|#" is a comment. Also, these comments nest correctly. So "#|...#|...|#...|#" terminates after the second "|#" rather than the first. Thus the expression

(TIMES 3.14159 #|This is an approximation to pi|# 2)

is parsed by READ the same as (TIMES 3.14159 2)

Usage of this syntax for comments is rare. Most users still prefer that comments be clearly marked on each line by a semicolon. Its introduction into the language was intended primarily to allow functions to be commented out without changing their indentation.

" (Doublequote)Reader MacroString Quote

There are two meanings for expressions bounded by doublequotes in Lisp. Both are intended to provide approximations to a string functionality. For more info on this, see documentation on the String concept.

` (Backquote)Reader MacroBackquote

Backquote is a readmacro which is seen most commonly in DEFMACRO forms, though it has other applications as well.

Typing backquote before a form, as in `form, is equivalent to typing (QUOTE form) except that

In a backquote expression, any subform of form which is:

preceded by a comma (,will be evaluated. 
preceded by a comma atsign (,@will be evaluated and spliced in using APPEND
preceded by a comma dot (,.will be evaluated and spliced in using NCONC

For example, consider the following equivalencies

`(A B C) means '(A B C) 
`((A B) ,X) means (LIST '(A B) X) 
`(A (B ,C) ,D E) means (LIST* 'A (LIST 'B C) D '(E)) 
`(A ,@B) means (CONS 'A B) 
`(A ,@B C) means (CONS 'A (APPEND B '(C))) 
`(A ,.B C) means (CONS 'A (NCONC B '(C))) 
`(,.A ,@B ,C D E) means (NCONC A (APPEND B (CONS C '(D E)))) 

Sample Usage:

;; Init some variables
(setq x '(a b c) y '(d e f) z '(g h i))
(G H I)

;; Try some backquote expressions
`(x ,x ,@x (y ,@z) w)
(X (A B C) A B C (Y G H I) W)

`(setq abc (append ,@x))

Use of RPLACA, RPLACD, NCONC, NREVERSE, or other destructive operations on the result of evaluating a backquote expression is not advised. Backquote makes no claim to how much sharing there will be between the backquote form and the structures produced by that form. It will try to maximize sharing, but it is a violation of its abstraction to assume that certain resulting structure will or will not be shared.

Now let's consider some code where we might want to use backquote...

(defmacro foo (fn x) (list 'funcall fn "foo x))
(defmacro bar (fn x) (list 'funcall fn "bar x))
(defmacro baz (fn x) (list 'funcall fn "baz x))

can be more easily written as

(defmacro foo (fn x) `(funcall ,fn 'foo ,x))
(defmacro bar (fn x) `(funcall ,fn 'bar ,x))
(defmacro baz (fn x) `(funcall ,fn 'baz ,x))

However, since backquote expressions can nest, they may also be written as

(defmacro def-funcalled (name . bvl)
  (let ((var (gensym)))
    `(defmacro ,name (,var ,@bvl) `(funcall ,,var ',',name ,,@bvl))))
(def-funcalled foo x)
(def-funcalled bar x)
(def-funcalled baz x)

The particular style to be used is largely a matter of taste. What backquote offers is an opportunity to show the general shape of the expression which will result. Prior to the existence of backquote, one would have written DEF-FUNCALLED as:

(defmacro def-funcalled (name . bvl)
  (let ((var (gensym)))
    (list 'defmacro
          (cons var bvl)
          (list* 'list
                 (list 'quote (list 'quote name))

which didn't give one a good feel for what the shape of the result might be. In some cases, using nested backquotes will make the program more clear; in some cases it will make it less clear. There are programmers who fear sophisticated constructs like backquote because they feel they just clutter their programs; and there are programmers who blindly resist an occasional call to LIST or CONS when backquote would express the result just fine. The best programmer, however, will maintain a clear knowledge of what tools are available at any given time and pick those which most clearly express his intent to others who might read his program.

Web-Only Note:

I've tried to retain the indentation style of the original MACLISP manual. It's worth noting that most of this manual uses the old-style indentation, with what is considered excess indentation by modern styles. For example, indenting a DEFUN body to align with the name of the function being defined, rather than indenting only two spaces. These examples above use the new style indentation. The reason is probably that this manual took years to produce, and backquote was among the latter-day features, so the examples of using this feature reflect a change in cultural style that had recently occurred (between the start of this manual's production, around 1979, and the end of its production, around 1981).

, (Comma)Reader Macro

The character sequences "," and ",." and ",@" are used internally to the backquote readmacro.

#/ (Sharp Slash)Reader MacroCharacter code

This character sequence, followed immediately by any ASCII character, is parsed by READ as that character's ASCII code. For example, #/A reads as the fixnum 101 octal (65 decimal).

#\ (Sharp Backslash)Reader MacroControl Character code

This character sequence, followed immediately by a symbol which names that character, is parsed by READ as the ASCII code for the character whose name is that symbol. For example, #\ALT reads as 33 octal (27 decimal). To find the preferred name for a character, call (FORMAT NIL "~@C" char).

#^ (Sharp Uparrow)Reader MacroControl-character code

Since control characters are sometimes hard to type in for use with "#/", this allows the user to type their ASCII codes symbolically. Followed by a character, char, this reads as Control-char's ASCII value. For example, #^G (sharpsign uparrow G) reads as the fixnum 7. Many characters have symbolic names as well; when such a name exists, the "#\" syntax is generally preferred.

Web-Only Note:

As noted previously, the hardcopy manual used uparrow and caret as synonyms, and was inconsistent in its notation. For simplicity, caret is used here in the webbed edition.

#RReader MacroArbitrary Input Radix

The expression #nRnumber causes number to be read in radix n instead of the default input radix (given by IBASE). The n is always read in base 10 (decimal). For example, #5r12 is read as 7. Whitespace is permitted between the #r and the number which follows it. Note that for input bases greater than ten, a sign is required for numbers which contain other than the digits 0 through 9. (See also (STATUS +).)

#OReader MacroOctal Input Radix

The expression #Onumber causes number to be read in octal (radix 8) instead of the default input radix (given by IBASE). For example, #o11 is read as 9.

#XReader MacroHex Input Radix

The expression #Xnumber causes number to be read in hex (radix 16) instead of the default input radix (given by IBASE). For example, #x+A is read as 10. Note that in hex, as with any input base greater than ten, a sign is required for numbers which contain other than the digits 0 through 9. (See also (STATUS +).)

#+ (Sharp Plus)Reader MacroReadtime Conditional

If the first form after a #+ is a symbol sym, then if (STATUS FEATURE sym) is true, then the second form following will be seen by READ; otherwise it will be invisible to READ. For example:

(defun f (x) (g #+debug x))

will READ as

(defun f (x) (g x))

if (STATUS FEATURE DEBUG) is true, and

(defun f (x) (g))


It is possible to combine conditions using lists that begin with AND, OR and NOT. For example:


will be read iff


is true.

Note: There are frequently better ways to conditionalize code without resorting to readmacros. Think twice before cluttering your code in this way.

#- (Sharp Minus)Reader MacroReadtime Conditionalize

Like "#+" but the second form is read if the feature description given by the first form is not true. These are sometimes seen together to implement code portability between differing dialects in the Maclisp family (Maclisp, NIL, Lisp, Lisp Machine Lisp, Franz Lisp). For example,

(defun f (x) (g #+lispm (copylist x) #-lispm (append x nil)))

or just:

(defun copylist (x) (append x nil))
which would define copylist everywhere but on the Lisp Machine.

#MReader MacroIf For Maclisp

This is shorthand for "#+MACLISP".

#NReader MacroIf For NIL

This is shorthand for "#+NIL".

Web-Only Note:

NIL (the New Implementation of Lisp) was a dialect of Lisp being developed at MIT for use on the VAX.

#QReader MacroIf For LispM

This is shorthand for "#+LISPM".

Web-Only Note:

The kinds of Lisp Machines this referred to were the MIT, LMI, TI, and Symbolics Lisp Machines. Interlisp D machines were not counted as Lisp Machines for this purpose.

#. (Sharp Dot)Reader MacroReadtime Evaluation

Typing #.expression will cause READ to return the result of evaluating expression, rather than expression itself. For example,

(SETQ CHAR (+ CHAR #.(- #/a #/A)))

is the same as writing

(SETQ CHAR (+ CHAR #o40))

since the subtraction happens at readtime rather than runtime.

Sharp dot may also be useful inside quoted data in some limited cases. For example,

(SETQ X '(A #.*A* B #.*B*))

will read using the values of *A* and *B* in the indicated places.

This requires that the variables be bound at readtime rather than at runtime. Contrast this with backquote, which allows you to effectively de-quote regions using values available at run-time:

(setq x 3)

(let ((x (1+ x))) '(x= #.x))
(X= 3)

(let ((x (1+ x))) '(x= ,x))
(X= 4)

#, (Sharp Comma)Reader MacroLoad Time Evaluation

For interpreted code, this is the same as "#." but for compiled code, the evaluation of the expression is delayed until the compiled code is loaded into its target environment rather than happening at readtime in the compiler as would happen with "#."

#% (Sharp Percent)Reader MacroReadtime Macro Expansion

In rare cases, macro libraries may need this feature, which allows readtime macro expansion of the form which follows. Typing

'#%(LET ((X 3)) (SETF (CAR Y) X))

is equivalent to typing

'((LAMBDA (X) (SETF (CAR Y) X)) 3)

Note, however, that MACROEXPAND expands only macrocalls at the toplevel of the given list. to expand the SETF, you would have to write

'#%(LET ((X 3)) #%(SETF (CAR Y) X))

Input Syntax

The argument conventions for these syntax controlling STATUS and SSTATUS options are quite obscure. In this subsection, the argument ch means a character. If ch is atomic, it will not be evaluated and may be either a fixnum representing the character's ASCII value or a single character symbol. If the ch argument is non-atomic, it will be evaluated and must evaluate to a fixnum character representation. It is recommended as a point of style that the option of using a symbol be avoided as it is somewhat visually confusing.


Returns the 18 syntax bits for the character ch as a fixnum. See the beginning of this subsection for a description of ch's argument conventions.


Sets ch's syntax bits to a given fixnum, i. The argument position for i is always evaluated and the result of that evaluation is returned from this operation. See the beginning of this subsection for a description of ch's argument conventions.

Syntax bits are interpreted according to the following table:

bit meaning 
Alphabetic; i.e., #/A to #/Z 
Lowercase and extended alphabetic; i.e., #/a to #/z and #/!, #/%, etc. 
Decimal digit; i.e., #/0 through #/9 
10 Sign Character; i.e., #/+ or #/- 
20 Fixnum Shift Character; i.e., #/^ or #/_ 
40 Second choice denoter for 10, 20, 1000, and 4000 
100 PRINT should slashify if not first char 
200 Decimal point for numbers; i.e., #/. 
400 PRINT should slashify when in first position 
1000 The rubout character, or the tty force feed char 
2000 The syntax quote character for READ; i.e., #// 
4000 A macro or splicing macro character; e.g., #/' 
10000 Close paren; i.e., #/) 
20000 "Consing dot"; i.e., #/. 
40000 Open Paren; i.e., #/( 
100000 Space or Tab 
200000 Single character object (no such character by default) 
400000 Worthless characters, and any with 200 or 1000-400000 on. 


Gets the character translation table entry for the character ch. This is the ASCII code of a character substituted for ch when it appears in a pname being read in. See the beginning of this subsection for a description of ch's argument conventions.

CHTRANSStatus Option(SSTATUS CHTRAN ch newch)

Sets ch's character translation to newch. The newch argument position is always evaluated and must yield a fixnum representation of a character. See the beginning of this subsection for a description of ch's argument conventions. Returns the value of newch.


Returns NIL if ch is not a macro character. If ch is a macro character, returns a list of the macro character function and the type, which is NIL for normal macros and SPLICING for splicing macros. See the beginning of this subsection for a description of ch's argument conventions.

MACROSStatus Option(SSTATUS MACRO ch fn [flag])

If fn evaluates to something other that NIL, makes ch a readmacro character with associated function fn. If fn evaluates to NIL, removes any former designation of ch as a readmacro and makes it be an ordinary extended alphabetic character.

The flag argument position may optionally be filled with the symbol SPLICING, which will not be evaluated, but which indicates that the readmacro is to be a splicing macro rather than an ordinary macro. If flag is omitted or NIL, the macro is a normal (non-splicing) readmacro.

The readmacro function given by fn should be a function of no arguments. It can expect the standard input stream to be set up correctly for reading characters. A normal readmacro function returns the object which replaces the readmacro character and any characters it has read. For example, the singlequote readmacro is described by:


Splicing readmacros return a list of values to be spliced back into the input stream. NIL means no values were read. A singleton list means that one value (the first and only element in that list) was read. A need to write splicing macros that return lists more than one long is rare, but Maclisp will support it. Here's an example of how the semicolon readmacro's effect could be described in Maclisp:

(DEFUN +INTERNAL-/;-MACRO () (READLINE) NIL) ;discard rest of line

See the beginning of this subsection for a description of ch's argument conventions.

Note: In fact, the implementation is such that the flag argument will declare the given fn to be a splicing macro if the first character of the flag is the character "S", however, users are encouraged not to rely on this implementational detail.

+Status Option(STATUS +)

Gets the value of the + switch (T or NIL). This switch is normally for NIL. If it is T, atoms more than one character long beginning with a + or a - are interpreted as numbers by the reader even if they contain letters.

+SStatus Option(SSTATUS + val)

Sets the + switch to T or NIL depending on val, which is evaluated. The new value of the + switch is returned. This allows the use of input bases greater than ten without making it too easy for the new 'digits' to collide with the letters making up variable names.

Sample Usage:

(PROGN (SETQ A 1. +A 2.) ;Confusing variable names!
       (SETQ IBASE 16. BASE 16.) ;Enable Base-16 I/O
       (DEFUN F (A) (+ A 3)) ;Define a test function
(F A) ; Our variable A has value 1)
(F +A) ; Our variable +A has a value 2
(SSTATUS + T) ;Enable + input syntax
(F A) ; 'A' still denotes our variable A
(F +A) ; But '+A' now denotes the number 10 (base 16)
(F /+A) ; /+A still means the symbol +A, however.


Returns the value of the ttyread switch, which is kept in the readtable. At present this is not used for anything in the Multics implementation. In the PDP-10 implementation it controls whether tty "force feed" characters are used. If NIL, then only force feed characters cause the tty pre-scan function to return with its buffered list of characters.


Sets the ttyread switch to T or NIL depending on val, which is evaluated. The new value of the switch is returned.

Sharpsign Macro Support


Sets up so that the sharpsign readmacro will dispatch to fn when followed by char. ind should be one of MACRO, SPLICING, PEEK, PEEK-MACRO, or PEEK-SPLICING. The optional fourth argument, rt. allows the user to associate the dispatching with some other readtable than the default, which is READTABLE.

The function should expect a single argument which is NIL if no digits came between the "#" and the dispatch character or the number seen if digits did intervene. The macro should read from the default stream.

An indicator of MACRO means the readmacro always returns exactly one form. If the indicator is SPLICING, the readmacro may at least sometimes return other than one form; SPLICING macros, therefore, return a list of their results.

PEEK-MACRO and PEEK-SPLICING are like MACRO and SPLICING except that when the function is run, the dispatch character is still on the input stream. Normally, the dispatch character would not still be present on that stream. PEEK is another name for PEEK-MACRO.

DEFSHARPSpecial Form(DEFSHARP char [ind] bvl . body)


(DEFUN /#-MACRO-char bvl . body)
(SETSYNTAX-SHARP-MACRO char 'ind '/#-MACRO-char)

Sample Usage:

;; Define odd macro
(defsharp /~ (arg) arg ;ignored
  (reverse read)))

#~(3 2 +)

'(* x #~(c b a +))
(* X (+ A B C))

;;Define an odd comment macro
(defsharp /! splicing (arg) arg ;ignored
  (read) nil) ;read next form on stream but ignore it

(plus 2 #!(pi) 3.14159)

'#~((A B) #!FOO C #!(3 #~(4 5 6)) D #!#~(X Y) #~#!(AA BB) (CC DD))
((DD CC) D C (A B))


An alist used by the # readmacro for its dispatching info. To update this info, use SETSYNTAX-SHARP-MACRO or DEFSHARP.


This variable is used by +INTERNAL-/#-MACRO for dispatch character "/". It contains an alist of symbolic names for characters and their appropriate numeric codes. For example, to get #\NULL to return 0 (as would be done on systems with ASCII character input) the alist would have the form ((NULL . 0) ... )

Backquote Support


This variable can be set to the symbol READ or the symbol EVAL. It determines when a backquoted expression is turned into normal lispy functions. If set to READ, then READ will return (CONS A B) when it sees `(,A . ,B). If set to EVAL, it will return lists which contain calls to macros which will later expand into calls to CONS, LIST, APPEND, etc. Setting this variable to EVAL works better with pretty printed code and worse with normally printed code. Setting it to READ works better with normally printed code and worse with pretty printed code. Sophisticated users may notice other differences of effect as well, especially when the eventual target of the backquoted structure is not Maclisp EVAL.

[Blue Marble]
Climate Change
Is nuclear the new green?

The Revised Maclisp Manual (Sunday Morning Edition)
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.
Prev | Index | Next