A PROPOSED CHARACTER STANDARD FOR LISP (including NIL and LISPM) [Revision 3] INTRODUCTION For the purposes of this standard, "character" is considered to be a conceptual data type (like "a-list") and not necessarily an actual one distinct from all others. Hence there is no predicate CHARACTERP in this proposal, and no requirement that the range of the TYPEP function contain the symbol CHARACTER. All that is required is that certain functions be defined to return "characters" and that certain kinds of syntax are converted by READ into "characters"; and moreover that certain functions defined below behave as specified when given "characters" (and they may do anything they like when given "non-characters"). In this way a LISP implementation may represent characters as, for example, fixnums or symbols and still conform to this standard by implementing the additional functions and READ syntax described below. To this end we merely propose that in any given LISP implementation there be some set of objects which serve as characters. This standard is permissive in the same sense used by the ANSI FORTRAN standard: it is only required that the implementation behave as defined here under the circumstances given. Extensions of any sort are permitted, provided that certain extensions, if made at all, should be made as described here for the sake of compatibility. The idea is thus that this proposed standard may be only a subset of the character capabilities provided in any particular implementation, but should be a subset common to all implementations. Hence a program which confines itself to the subset should be compatible to the extent covered by the standard; and a program which uses an extension described here should work in all implementations supporting that extension. This proposal is primarily for NIL, but effort has been made to allow the LISP Machine to support it. The names of the functions described here are meant to be representative and not definitive. GENERALITIES Every character object has three attributes: FONT, BITS, and CODE. The FONT and BITS attributes are non-negative fixnums. The CODE is a character object whose FONT and BITS attributes are zero; thus two characters which have the same CODE differ only in their FONT or BITS attributes. There is a bijective mapping between character codes and some range of non-negative fixnums. This mapping is explicitly undefined in this proposal. The system constant *:MAX-CHAR-CODE contains a fixnum which is greater than any element of the fixnum range of the mapping. [It is not clear whether to require that the range of the mapping be compact -- it may be convenient to permit "holes" in the range from 0 to (- *:MAX-CHAR-CODE 1).] The mapping is effected from characters to fixnums by the function CHAR-CODE; this function ignores the BITS and FONT attributes of the argument. The function CODE-CHAR maps a fixnum to the corresponding character code, or produces NIL if the fixnum does not map to a valid character code. The functions CHAR-BITS and CHAR-FONT take characters and produce fixnums. The function CHARACTER (CODE &OPTIONAL (BITS 0) (FONT 0)) takes a character and two optional fixnums and constructs a character. Notice that (CHARACTER X) returns the CODE of the character x as a character. An error results if the BITS or FONT value is not permissible in a character. Characters are divided into two sets: "graphic" or "printing" characters, and "non-graphic" or "control" characters. Graphic characters always occupy a single character position when printed (whatever that means). The predicate GRAPHICP is true of graphic characters, and false of nongraphic characters. Some characters can be elements of the STRING data type, and others may not. The predicate STRINGCHARP is true of characters that can be in strings, and false of characters that cannot be in strings. Some characters may be thought of as being "upper-case", "lower-case", or "digits". The predicates UPPERCASEP, LOWERCASEP, and DIGITP test for these qualities. The function CHAR-UPCASE, given a character, returns a character with the same FONT and BITS attributes, but possibly a new CODE (the code can differ only if LOWERCASEP was true of the character -- but it may fail to differ anyway if there is no corresponding upper-case character in the font); similarly for CHAR-DOWNCASE (can differ only if UPPERCASEP). The non-NIL value DIGITP returns for a digit is a fixnum which is the "weight" of the digit (which may be negative?!). The function DIGIT-CHAR (N &OPTIONAL (FONT 0)), given a fixnum and optionally a font number, produces the character in that font (default 0) which encodes that fixnum weight, or NIL if that cannot be done. There is a total ordering on characters (a collating sequence). This ordering can be tested via the predicates CHAR<, CHAR=, and CHAR>. The only requirement on this ordering is that upper-case characters, lower-case characters, and digits (as three distinct groups) have the "expected" ordering (within each group), provided that they have the same FONT and BITS attributes. The ordering is not defined here between two characters whose FONT or BITS attributes differ. CHAR-EQUAL, CHAR-LESSP, and CHAR-GREATERP are similar except that they extract the codes from the character operands, thus ignoring the FONT and BITS attributes, and also apply CHAR-UPCASE, thus ignoring case differences. THE STANDARD CHARACTER SET The character set for all implementations of NIL will based on the 95 ASCII printing characters (octal 40-176), plus TAB (11), NEWLINE (possibly 15, then 12), FORM (14), and RUBOUT (177). This makes 100 characters total. It ought to be possible to express most reasonable NIL programs in this restricted character set. Every effort should be made to express programs using only these characters:
! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ The standard character set only provides for BITS and FONT attributes to take on the value zero. The syntax "#/x", where "x" is a character in the read data stream, is read as the character object whose code is that for "x". This character object has FONT and BITS attributes of zero. The syntax "#=/x", where "x" is a character in the read data stream, is read as if it were "#/x" and then the function CHAR-CODE applied; thus it is read as a fixnum. This is the same fixnum as that which the function TYI returns when it reads the character "x". The syntax "#=nnn", where nnn has the syntax of a fixnum, is an implementation-dependent syntax which reads in as the character resulting from applying CODE-CHAR to the fixnum nnn. The syntax "#\name", where "name" is the name of a non-graphic character, including TAB, LF, FORM, CR, SPACE, and RUBOUT, is read as the corresponding character object; for example, "#\TAB" will read as the character . DEFINED EXTENSIONS No NIL implementation is required to implement more than the standard character set. However, if an implementation provides any extensions, then they should be done in the way described here. More precisely, any extension which provides a capability described below should if possible be done in the manner described below; and any provided capability not described below should not preclude future implementation of capabilities described below. Whether or not extended character features are implemented, there is a predicate STANDARD-CHARP, which is true of the 100 standard characters and false of non-standard characters. (1) Additional character codes. Additional graphic codes may be defined by particular NIL implementations. It is strongly suggested that the following graphics be used for the next 33 characters defined: center-dot down-arrow alpha beta logical-and logical-not epsilon pi lambda gamma delta up-arrow plus-minus circle-plus infinity partial-sign left-horseshoe right-horseshoe up-horseshoe down-horseshoe for-all there-exists circle-x left/right-arrow left-arrow right-arrow not-equal diamond less-or-equal greater-equal equivalence logical-or integral-sign If implementation circumstances do not permit the use of these graphics, then the next-best thing is for that implementation to define a correspondence from its graphics to these. Additional non-graphic codes may also be assigned by particular NIL implementations. Their names and purposes will be implementation- dependent. Suggested names include: If such non-graphic codes are introduced, the "#\" syntax should be extended appropriately for input purposes (e.g. #\BREAK). (2) Additional fonts. Implementations may provide for font codes which are positive fixnums. The system constant *:MAX-CHAR-FONT contains a fixnum which is one larger than the largest permissible font number; thus fonts 0 through (- *:MAX-CHAR-FONT 1) are permissible. The predicates STRINGCHARP, GRAPHICP, UPPERCASEP, LOWERCASEP, and DIGITP may depend on the FONT attribute; that is, two characters with the same CODE but different FONT attributes may give different results. (3) Control bits. Implementations may provide for non-zero BITS attributes. These are fixnums which encode weighted binary values (i.e. bits). The bits have conventional names and weights as follows: CONTROL 1 META 2 [ GREEK 4 ;do we want to assign additional PARA 8 ; names for the future?? HYPER 16 SUPER 64 SUB 128 ] So that one can avoid depending on these weights, there are system constant names for them: *:CONTROL-CHAR-BIT, *:META-CHAR-BIT, etc. There are also predicates CONTROL-CHARP, META-CHARP, etc. which are true of characters with that bit set and false of characters with that bit clear. [Should we avoid defining the precise weights?] The system constant *:MAX-CHAR-BITS is one larger than the sum of all possible bit weightings. The predicates STRINGCHARP and GRAPHICP may depend on the BITS attribute; that is, two characters with the same CODE but different BITS attributes may give different results. (4) Printing characters with non-zero FONT or BITS. PRIN1 should print a character in such a way that READ can read it. If possible, the "#/x" or "#\" notation should be used. But if no other way works, this one will: #,(CHARACTER x (+ bit1 bit2 ...) n) where "x" is the printed representation of the CODE, the BITS are represented as the sum of the individual bit values, and "n" is the font number. It's a bit verbose, but will work. PRINC should, if possible, print the character "nicely", whatever that may mean; but that probably means using the right font, anyway. (5) Non-standard character objects Primarily for the benefit of the LISP Machine, we suppose that it may be desirable to intermix odd objects derived from unusual input devices in the main character input stream (for example, mouse information). There is a semi-predicate FUNNY-CHARP which is false of "ordinary" character objects, and non-false (it may return type information) of "funny" characters. The only requirements on ordinary and funny characters are: (1) the result of TYI is never a funny character (TYI filters out and discards such characters, and there is some other function which can read all characters, funny or not); (2) non-funny characters are required to behave properly under the defined character functions such as CHAR-CODE, CHAR-BITS, CHAR-FONT, etc.; (3) funny characters need not be meaningful to the defined character functions. (Note that it is not required that input from unusual devices such as mice be expressed as funny characters; it is only required that if they produce input not in the form of a standard character then TYI must filter them out, and FUNNY-CHARP must be true of them.) SOME REMARKS ON THE PROPOSAL The intent of this proposal is to be able to routinely insulate programs from the particular character set encodings internal to any particular implementation. In particular, it should be possible to write programs which deal reasonably with characters and which can run on the VAX (an ASCII machine), the S1 (an extended ASCII machine), the LISP Machine (a different extended ASCII machine), and the 370 (an EBCDIC machine) without having to require all implementations to use the same internal encoding (which might impact efficiency elsewhere, e.g. in dealing with I/O with some operating system). The mapping between characters and fixnums is provided to make it easier to do dispatching and array indexing on characters. If one is careful one can make code independent of the precise encoding. For example, one can write: (CASEQ (CHAR-CODE CH) ((#/+) (PLUS A B)) ((#/-) (DIFFERENCE A B)) ((#/*) (TIMES A B)) ((#//) (QUOTIENT A B)) (T (ERROR "Barf!" CH))) Similarly, if one is careful to initialize arrays not by knowing the encoding (e.g. its ordering), but by associating character objects with the initial contents, one can avoiding depending on the internal encoding: (DO I 0 (+ I 1) (= I *:MAX-CHAR-CODE) (ASET THE-ARRAY I 'DEFAULT-HANDLER)) (DO X '(#/+ PLUS-HANDLER #/- DIFFERENCE-HANDLER #/* TIMES-HANDLER #// QUOTIENT-HANDLER) (CDDR X) (NULL X) (ASET THE-ARRAY (CHAR-CODE (CAR X)) (CADR X))) In particular, this works well when the program is moved to another implementation which happens to provide extra character codes not anticipated when the program was written. Note that while it is not required to implement non-zero fonts, neither is it forbidden for extended "simple characters" to have a non-zero font number. We require that when one of the standard 100 characters is typed (to TYI or after "#/"), it means that character code in FONT zero with zero BITS. However, if an epsilon or beta is typed on a Knight keyboard, the implementation might well read it as a font 1 (Greek?) character. Similarly, it might (for example) wish to supply a non-zero GREEK bit, whether or not the GREEK shift key was held down. NIL, unlike the LISP machine, will not have sixteen-bit strings, or for that matter strings with characters of any defined field width. It is guaranteed that: (a) strings can hold the 100 standard characters, and (b) an S-exp type array can certainly hold any character whatsoever. There is no requirement that characters per se and characters within strings have the same internal representation. In any given implementation, it may or may not be desirable to have extraction from a string "unpack" the character, and to have insertion into a string "pack" the character. SUMMARY OF PROPOSED FUNCTIONS AND SYSTEM CONSTANTS (1) Predicates STRINGCHARP GRAPHICP UPPERCASEP LOWERCASEP DIGITP STANDARD-CHARP FUNNY-CHARP CONTROL-CHARP META-CHARP [GREEK-CHARP etc.] (2) Other functions CHARACTER CHAR-BITS CHAR-FONT CHAR-CODE CODE-CHAR CHAR-UPCASE CHAR-DOWNCASE DIGIT-CHAR CHAR< CHAR> CHAR= CHAR-LESSP CHAR-GREATERP CHAR-EQUAL (3) System constants *:MAX-CHAR-CODE *:MAX-CHAR-FONT *:MAX-CHAR-BITS *:CONTROL-CHAR-BIT *:META-CHAR-BIT [*:GREEK-CHAR-BIT etc.] PROPOSED IMPLEMENTATION FOR VAX/NIL Characters can have 27 bits of data in them. It is not critical how these are allocated to the three attributes; let as assign eight bits apiece. We describe four possible schemes. In two schemes only the CODE part of a character can fit into a string. The two schemes differ primarily at the TYI interface. The third scheme allows strings to contain (some) CONTROL and META characters. In one scheme, TYI simply reads all ASCII characters as simple character codes. Any character read from the keyboard fits in a string. Only the 95 ASCII printing characters are graphic; the rest are non-graphic characters. In the second scheme, the 100 standard characters are read as FONT=0, BITS=0. ASCII codes 0-10, 13, 16-37 (octal) are read as FONT=0, BITS=1, and a CODE which is 100+. This scheme may be more conducive to the writing of a portable editor (?). In the third scheme, string characters are a packed encoding. The highest bit is the META bit. The other seven are an ASCII value which is unpacked into a code and a CONTROL bit in the same way TYI does in the second scheme. In this way one has the 100 standard characters plus some "CONTROL-alphabetics", and an independent META bit. One advantage of this scheme is that it doesn't require many graphics with which to print a full 8-bit character code. One disadvantage is that it is not clear how to notate strings with meta-characters in them. PROPOSED IMPLEMENTATION FOR NIL/S-1 The options for the S-1 are pretty much the same as for the VAX, except that nine bits are available for string characters. Probably this will be allocated as a META bit, a CONTROL bit, and a Stanford (MIT?) ASCII code. The graphics , , , and will probably be displaced by , , , and . will probably actually be the graphic . Thus this character set will be much like that used within ITS TECO. Perhaps we should say that if an implementation provides (a) non-zero BITS encoded into STRING characters, and (b) the graphics , , , and , then it should implement the standard SAIL escape convention. PROPOSED IMPLEMENTATION FOR THE LISP MACHINE The LISP Machine can go on representing characters as fixnums if desired. One problem is that currently such fixnums are used in two different and inconsistent ways. One is as "%%CH-" characters, which have eight bits of character code and eight of font number. The other is as "%%KBD-" characters, which have eight bits of character code and three of control bits (CONTROL, META, and MOUSE). I propose to reorganize the fields into a single unified character type. Let characters have 23 bits. The low eight bits are a character code. The next eight are font number. The high seven are control bits. This proposal maintains compatibility with the current use (?) of ART-16 arrays. Moreover, if code is actually using %%KBD-CONTROL and friends properly (ha ha), then moving the control bits shouldn't hurt any (ha ha ha). I propose to include MOUSE characters in this scheme by using the above-defined FUNNY-CHARP convention. There should be some functions for extracting parts of a mouse character. POSSIBLE FUNCTION DEFINITIONS FOR NIL/VAX Assume that the function *:CHARACTER-TO-FIXNUM changes a character to a fixnum with the same bits (it just alters the type code), and *:FIXNUM-TO-CHARACTER inverts this process. Some of these functions can of course perhaps be implemented much more cleverly by hand-coding in machine language. Some can even be coded more efficiently by bumming the LISP code. These are meant to be illustrative. (1) Predicates (DEFUN STRINGCHARP (CH) (AND (ZEROP (CHAR-BITS CH)) (ZEROP (CHAR-FONT CH)))) (DEFUN GRAPHICP (CH) (PLUSP (AREF *:GRAPHICP-BIT-ARRAY (CHAR-FONT CH) (CHAR-CODE CH)))) (DEFUN UPPERCASEP (CH) (PLUSP (AREF *:UPPERCASEP-BIT-ARRAY (CHAR-FONT CH) (CHAR-CODE CH)))) (DEFUN LOWERCASEP (CH) (PLUSP (AREF *:LOWERCASEP-BIT-ARRAY (CHAR-FONT CH) (CHAR-CODE CH)))) ;;; [Shouldn't this take an optional RADIX argument, a fixnum between 0 ;;; and 26, which can default to 10? It seems very strange for ;;; (DIGITP #/Q) to return true. - JAR] (DEFUN DIGITP (CH) (LET ((N (CHAR-CODE CH))) (COND ((AND (NOT (< N #=/0)) (NOT (> N #=/9))) (- N #=/0)) ((AND (NOT (< N #=/A)) (NOT (> N #=/Z))) ;? (+ (- N #=/A) 10.)) ((AND (NOT (< N #=/a)) (NOT (> N #=/z))) ;?? (+ (- N #=/a) 10.))))) (DEFUN STANDARD-CHARP (CH) (PLUSP (AREF *:STANDARD-CHARP-BIT-ARRAY (CHAR-FONT CH) (CHAR-CODE CH)))) (DEFUN FUNNY-CHARP (CH) (CHECK-ARG CH CHARACTERP "a character") NIL) (DEFUN CONTROL-CHARP (CH) (NOT (ZEROP (LOGAND (CHAR-BITS CH) *:CONTROL-CHAR-BIT)))) (DEFUN META-CHARP (CH) (NOT (ZEROP (LOGAND (CHAR-BITS CH) *:META-CHAR-BIT)))) (2) Other functions (DEFUN CHARACTER (CH &OPTIONAL (BITS 0) (FONT 0)) (CHECK-ARG CH CHARACTERP "a character") (CHECK-ARG BITS (AND (FIXNUMP BITS) (< -1 BITS *:MAX-CHAR-BITS)) "valid character bits" CHAR-BITS) (CHECK-ARG FONT (AND (FIXNUMP FONT) (< -1 BITS *:MAX-CHAR-FONT)) "a valid character font number" CHAR-FONT) (*:FIXNUM-TO-CHARACTER (+ (CHAR-CODE CH) (LSH BITS *:CHAR-BITS-LSH-OFFSET) (LSH FONT *:CHAR-FONT-LSH-OFFSET)))) (DEFUN CHAR-BITS (CH) (CHECK-ARG CH CHARACTERP "a character") (\ (LSH (*:CHARACTER-TO-FIXNUM CH) (- *:CHAR-BITS-LSH-OFFSET)) *:MAX-CHAR-BITS)) (DEFUN CHAR-FONT (CH) (CHECK-ARG CH CHARACTERP "a character") (\ (LSH (*:CHARACTER-TO-FIXNUM CH) (- *:CHAR-FONT-LSH-OFFSET)) *:MAX-CHAR-FONT)) (DEFUN CHAR-CODE (CH) (CHECK-ARG CH CHARACTERP "a character") (\ (*:CHARACTER-TO-FIXNUM CH) *:MAX-CHAR-CODE)) (DEFUN CODE-CHAR (N) (AND (< -1 N *:MAX-CHAR-CODE) (*:FIXNUM-TO-CHARACTER N)))) ;;; The following code assumes a bijective mapping within each font between ;;; upper case characters and lower case characters, and that the mapping ;;; can be implemented by adding a constant offset to the character code. (DEFUN CHAR-UPCASE (CH) (CHECK-ARG CH CHARACTERP "a character") (COND ((LOWERCASEP CH) (CHARACTER (CODE-CHAR (- (CHAR-CODE CH) (AREF *:CASE-OFFSET-ARRAY (CHAR-FONT CH)))) (CHAR-BITS CH) (CHAR-FONT CH))) (T CH))) (DEFUN CHAR-DOWNCASE (CH) (CHECK-ARG CH CHARACTERP "a character") (COND ((UPPERCASEP CH) (CHARACTER (CODE-CHAR (+ (CHAR-CODE CH) (AREF *:CASE-OFFSET-ARRAY (CHAR-FONT CH)))) (CHAR-BITS CH) (CHAR-FONT CH))) (T CH))) (DEFUN DIGIT-CHAR (N) (COND ((< N 0) '()) ((< N 10.) (CODE-CHAR (+ N #=/0))) ((< N 36.) (CODE-CHAR (+ N -10. #=/A))) (T '()))) (DEFUN CHAR< (CH1 CH2) (CHECK-ARG CH1 CHARACTERP "a character") (CHECK-ARG CH2 CHARACTERP "a character") (< (*:CHARACTER-TO-FIXNUM CH1) (*:CHARACTER-TO-FIXNUM CH2))) (DEFUN CHAR> (CH1 CH2) (CHECK-ARG CH1 CHARACTERP "a character") (CHECK-ARG CH2 CHARACTERP "a character") (> (*:CHARACTER-TO-FIXNUM CH1) (*:CHARACTER-TO-FIXNUM CH2))) (DEFUN CHAR= (CH1 CH2) (CHECK-ARG CH1 CHARACTERP "a character") (CHECK-ARG CH2 CHARACTERP "a character") (= (*:CHARACTER-TO-FIXNUM CH1) (*:CHARACTER-TO-FIXNUM CH2))) (DEFUN CHAR-LESSP (CH1 CH2) (CHECK-ARG CH1 CHARACTERP "a character") (CHECK-ARG CH2 CHARACTERP "a character") (< (CHAR-UPCASE (CHAR-CODE CH1)) (CHAR-UPCASE (CHAR-CODE CH2)))) (DEFUN CHAR-GREATERP (CH1 CH2) (CHECK-ARG CH1 CHARACTERP "a character") (CHECK-ARG CH2 CHARACTERP "a character") (> (CHAR-UPCASE (CHAR-CODE CH1)) (CHAR-UPCASE (CHAR-CODE CH2)))) (DEFUN CHAR-EQUAL (CH1 CH2) (CHECK-ARG CH1 CHARACTERP "a character") (CHECK-ARG CH2 CHARACTERP "a character") (= (CHAR-UPCASE (CHAR-CODE CH1)) (CHAR-UPCASE (CHAR-CODE CH2)))) (3) System constants (CONSTANT TAB #Q11) (CONSTANT LF #Q12) (CONSTANT FORM #Q14) (CONSTANT CR #Q15) (CONSTANT SPACE #Q40) (CONSTANT RUBOUT #Q177) (CONSTANT *:MAX-CHAR-CODE #Q400) (CONSTANT *:MAX-CHAR-BITS #Q400) (CONSTANT *:MAX-CHAR-FONT #Q400) (CONSTANT *:CONTROL-CHAR-BIT #Q1) (CONSTANT *:META-CHAR-BIT #Q2) POSSIBLE FUNCTION DEFINITIONS FOR THE LISP MACHINE In constrast to the definitions given above for the VAX, the definitions given here are bummed pretty hard. I have not avoided building numbers into the code; I assume this is okay, as long as the numbers are contained only in this code. Functions which are already defined in the LISP Machine are not given here, though their definitions may need fixing up some. (1) Predicates (DEFUN STRINGCHARP (CH) (ZEROP (LOGAND CH -400))) (DEFUN GRAPHICP (CH) (ZEROP (LOGAND CH 200))) ;? (DEFUN UPPERCASEP (CH) (SETQ CH (LOGAND CH 377)) (AND (>= CH 101) (<= CH 132))) (DEFUN LOWERCASEP (CH) (SETQ CH (LOGAND CH 377)) (AND (>= CH 141) (<= CH 172))) (DEFUN DIGITP (CH) (SETQ CH (LOGAND CH 377)) (AND (>= CH 60) (<= CH 71) (- CH 60))) (DEFUN CONTROL-CHARP (CH) (NOT (ZEROP (LOGAND CH 100000)))) (DEFUN METAP-CHARP (CH) (NOT (ZEROP (LOGAND CH 200000)))) (2) Other functions (DEFUN CHARACTER (CH &OPTIONAL (BITS 0) (FONT 0)) (DPB BITS 1707 (DPB FONT 1010 (LOGAND CH 377)))) (DEFUN CHAR-BITS (CH) (LDB CH 1707)) (DEFUN CHAR-FONT (CH) (LDB CH 1010)) (DEFUN CHAR-CODE (CH) (LOGAND CH 377)) (DEFUN CODE-CHAR (N) (AND (ZEROP (LOGAND CH -400)) N)) (DEFUN DIGIT-CHAR (N) (COND ((OR (< N 0) (> N 9)) '()) (T (+ N 60)))) (DEFUN CHAR< (CH1 CH2) (< CH1 CH2)) (DEFUN CHAR> (CH1 CH2) (> CH1 CH2)) (DEFUN CHAR= (CH1 CH2) (= CH1 CH2)) (3) System constants (CONSTANT TAB #Q11) (CONSTANT LF #Q12) (CONSTANT FORM #Q14) (CONSTANT CR #Q15) (CONSTANT SPACE #Q40) (CONSTANT RUBOUT #Q177) (CONSTANT SI:MAX-CHAR-CODE 400) (CONSTANT SI:MAX-CHAR-BITS 200) (CONSTANT SI:MAX-CHAR-FONT 400) (CONSTANT SI:CONTROL-CHAR-BIT 1) (CONSTANT SI:META-CHAR-BIT 2) (CONSTANT SI:MOUSE-CHAR-BIT 4) ;;; The following are for compatibility with the current way things are done (CONSTANT %%CH-CHAR 0010) (CONSTANT %%CH-FONT 1010) (CONSTANT %%KBD-CHAR 0010) (CONSTANT %%KBD-CONTROL 1701) (CONSTANT %%KBD-META 2001) (CONSTANT %%KBD-CONTROL-META 1702) (CONSTANT %%KBD-MOUSE 2101) (CONSTANT %%KBD-MOUSE-BUTTON 0010) ;Unfortunately not really compatible given ; above proposal for encoding multiple buttons (CONSTANT %%KBD-MOUSE-N-CLICKS 1010)