|The Revised Maclisp Manual||Page A-20|
|SETSYNTAX||Function||(SETSYNTAX character data1 data2)|
Sets the syntax bits and/or macro property of the given character.
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:
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:
Note that the semicolon readmacro is implemented as a splicing macro that simply returns the empty list (see +INTERNAL-/;-MACRO).
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.
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 /|| |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 Macro||QUOTE|
Typing 'form is equivalent to typing (QUOTE form).
|#' (Sharp Quote)||Reader Macro||FUNCTION|
Typing #'form is equivalent to typing (FUNCTION form). The shorthand form is preferred.
|; (Semicolon)||Reader Macro||Comment|
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).
See also: SETSYNTAX, +INTERNAL-/;-MACRO
|_ (Underscore)||Reader Macro||Fixnum 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.
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 (^).)
|^ (Uparrow)||Reader Macro||Integer Exponentiation|
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 (_).)
|#| (Sharp Vertical Bar)||Reader Macro||Comment|
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)
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 Macro||String 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 Macro||Backquote|
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))))
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...
can be more easily written as
However, since backquote expressions can nest, they may also be written as
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:
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.
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|
|#/ (Sharp Slash)||Reader Macro||Character code|
|#\ (Sharp Backslash)||Reader Macro||Control Character code|
|#^ (Sharp Uparrow)||Reader Macro||Control-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.
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.
|#R||Reader Macro||Arbitrary 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 +).)
|#O||Reader Macro||Octal 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.
|#X||Reader Macro||Hex 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 Macro||Readtime Conditional|
(defun f (x) (g #+debug x))
will READ as
(defun f (x) (g x))
(defun f (x) (g))
will be read iff
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 Macro||Readtime 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,
|#M||Reader Macro||If For Maclisp|
|#N||Reader Macro||If For NIL|
This is shorthand for "#+NIL".
NIL (the New Implementation of Lisp) was a dialect of Lisp being developed at MIT for use on the VAX.
|#Q||Reader Macro||If For LispM|
This is shorthand for "#+LISPM".
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 Macro||Readtime Evaluation|
Typing #.expression will cause READ to return the result of evaluating expression, rather than expression itself. For example,
is the same as writing
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:
|#, (Sharp Comma)||Reader Macro||Load 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 Macro||Readtime Macro Expansion|
In rare cases, macro libraries may need this feature, which allows readtime macro expansion of the form which follows. Typing
is equivalent to typing
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.
|SYNTAX||Status Option||(STATUS SYNTAX ch)|
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.
|SYNTAX||SStatus Option||(SSTATUS SYNTAX ch i)|
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 1 Alphabetic; i.e., #/A to #/Z 2 Lowercase and extended alphabetic; i.e., #/a to #/z and #/!, #/%, etc. 4 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.
|CHTRAN||Status Option||(STATUS CHTRAN ch)|
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.
|CHTRAN||SStatus 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.
|MACRO||Status Option||(STATUS MACRO ch)|
|MACRO||SStatus 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:
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 +)|
|+||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.
(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 'DONE) DONE (F A) ; Our variable A has value 1) +4 (F +A) ; Our variable +A has a value 2 +5 (SSTATUS + T) ;Enable + input syntax T (F A) ; 'A' still denotes our variable A +4 (F +A) ; But '+A' now denotes the number 10 (base 16) +D (F /+A) ; /+A still means the symbol +A, however. +5
|TTYREAD||Status Option||(STATUS TTYREAD)|
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.
|TTYREAD||SStatus Option||(SSTATUS TTYREAD val)|
Sharpsign Macro Support
|SETSYNTAX-SHARP-MACRO||Function||(SETSYNTAX-SHARP-MACRO char ind fn [rt])|
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.
|DEFSHARP||Special Form||(DEFSHARP char [ind] bvl . body)|
(DEFUN /#-MACRO-char bvl . body) (SETSYNTAX-SHARP-MACRO char 'ind '/#-MACRO-char)
;; Define odd macro (defsharp /~ (arg) arg ;ignored (reverse read))) /#-MACRO-~ #~(3 2 +) 5 '(* 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 /#-MACRO-! (plus 2 #!(pi) 3.14159) 5.14159 '#~((A B) #!FOO C #!(3 #~(4 5 6)) D #!#~(X Y) #~#!(AA BB) (CC DD)) ((DD CC) D C (A B))
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) ... )
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.
|The Revised Maclisp Manual (Sunday Morning Edition)|
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.