{Begin Chapter Litatoms} {Title Litatoms} {Text {index *PRIMARY* Litatoms} {index *PRIMARY* Atoms} {index *PRIMARY* Literal atoms} {index *PRIMARY* Symbols} A "litatom" (for "literal atom") is an object which conceptually consists of a print name, a value, a function definition, and a property list. In some Lisp dialects, litatoms are also known as "symbols." A litatom is read as any string of non-delimiting characters that cannot be interpreted as a number. The syntatic characters that delimit litatoms are called separator or break characters (see {PageRef Tag ReadTables}) and normally are space, end-of-line, line-feed, {lisp (} (left paren), {lisp )} (right paren), {lisp "} (double quote), {lisp [} (left bracket), and {lisp ]} (right bracket). However, any character may be included in a litatom by preceding it with the character {lisp %}.{index %} Here are some examples of litatoms: {lispcode A wxyz 23SKIDDOO %] 3.1415+17 Long% Litatom% With% Embedded% Spaces} {note para about how CLISP translates A+B into something else---warning about not using +-*/ in litatoms??? note about other special chars like quote??} {index *PRIMARY* LITATOM Fn} {FnDef {FnName LITATOM} {FnArgs X} {Text Returns {lisp T} if {arg X} is a litatom,{index Litatoms Term} {lisp NIL} otherwise. Note that a number is not a litatom. {lisp (LITATOM NIL)} ={lisp T}. }} {index *PRIMARY* ATOM Fn} {FnDef {FnName ATOM} {FnArgs X} {Text Returns {lisp T} if {arg X} is an atom{index Atoms Term} (i.e. a litatom or a number); {lisp NIL} otherwise. Warning: {lisp (ATOM {arg X})} is {lisp NIL} if {arg X} is an array, string, etc. In many dialects of Lisp, the function {fn ATOM} is defined equivalent to the Interlisp function {fn NLISTP}. {lisp (ATOM NIL)} = {lisp T}. }} Litatoms are printed by {fn PRINT} and {fn PRIN2} as a sequence of characters with {lisp %}'s inserted before all delimiting characters (so that the litatom will read back in properly). Litatoms are printed by {fn PRIN1} as a sequence of characters without these extra {lisp %}'s. For example, the litatom consisting of the five characters {lisp A}, {lisp B}, {lisp C}, {lisp (}, and {lisp D} will be printed as {lisp ABC%(D} by {fn PRINT} and {lisp ABC(D} by {fn PRIN1}. Litatoms can also be constructed by {fn PACK}, {fn PACK*}, {fn SUBATOM}, {fn MKATOM}, and {fn GENSYM} (which uses {fn MKATOM}). Litatoms are unique. In other words, if two litatoms print the same, they will {it always} be {fn EQ}. Note that this is {it not} true for strings, large integers, floating point numbers, and lists; they all can print the same without being {lisp EQ}. Thus if {fn PACK} or {fn MKATOM} is given a list of characters corresponding to a litatom that already exists, they return a pointer to that litatom, and do {it not} make a new litatom. Similarly, if the read program is given as input a sequence of characters for which a litatom already exists, it returns a pointer to that litatom. Note: Interlisp is different from other Lisp dialects which allow "uninterned" litatoms. Note: Litatoms are limited to 255 characters in Interlisp-D; 127 characters in Interlisp-10. {note -VAX ???} Attempting to create a larger litatom either via {fn PACK} or by typing one in (or reading from a file) will cause an error, {lisp ATOM TOO LONG}.{index ATOM TOO LONG Error} {Begin SubSec Using Litatoms as Variables} {Title Using Litatoms as Variables} {Text {note "binding" or "value"??} Litatoms are commonly used as variables. Each litatom has a "top level" variable binding, which can be an arbitrary Interlisp object. Litatoms may also be given special variable bindings within {fn PROG}s or function calls, which only exist for the duration of the function. When a litatom is evaluated, the "current" variable binding is returned. This is the most recent special variable binding, or the top level binding if the litatom has not been rebound. {fn SETQ} is used to change the current binding. For more information on variable bindings in Interlisp, see {PageRef Tag Stack}. Note: The compiler ({PageRef Tag Compiler}) treats variables somewhat differently than the interpreter, and the user has to be aware of these differences when writing functions that will be compiled. For example, variable references in compiled code are not checked for {lisp NOBIND}, so compiled code will not generate unbound atom errors. In general, it is better to debug interpreted code, before compiling it for speed. The compiler offers some facilities to increase the efficiency of variable use in compiled functions. Global variables ({PageRef Term GLOBALVARS}) can be defined so that the entire stack is not searched at each variable reference. Local variables ({PageRef Term LOCALVARS}) allow compiled functions to access variable bindings which are not on the stack, which reduces variable conflicts, and also makes variable lookup faster. By convention, a litatom whose top level binding is to the litatom {atom NOBIND}{index *PRIMARY* NOBIND Litatom} is considered to have no top level binding. If a litatom has no local variable bindings, and its top level value is {atom NOBIND}, attempting to evaluate it will cause an unbound atom error.{index UNBOUND ATOM Error} The two litatoms {atom T}{index T Litatom} and {atom NIL}{index NIL Litatom} always evaluate to themselves. Attempting to change the binding of {atom T} or {atom NIL} with the functions below will generate the error {lisp ATTEMPT TO SET T}{index ATTEMPT TO SET T Error} or {lisp ATTEMPT TO SET NIL}.{index ATTEMPT TO SET NIL Error} The following functions (except {fn BOUNDP}) will also generate the error {lisp ARG NOT LITATOM},{index ARG NOT LITATOM Error} if not given a litatom. {FnDef {FnName BOUNDP} {FnArgs VAR} {Text Returns {lisp T} if {arg VAR} has a special variable binding (even if bound to {lisp NOBIND}), or if {arg VAR} has a top level value other than {atom NOBIND}; otherwise {lisp NIL}. In other words, if {arg X} is a litatom, {lisp (EVAL {arg X})} will cause an {lisp UNBOUND ATOM} error if and only if {lisp (BOUNDP {arg X})} returns {lisp NIL}.{index UNBOUND ATOM Error} {note Jerico does this differently. Vax?? ---lmm} }} {FnDef {FnName SET} {FnArgs VAR VALUE} {Text Sets the "current" variable binding of {arg VAR} to {arg VALUE}, and returns {arg VALUE}. Note that {fn SET} is a normal lambda spread function, so both {arg VAR} and {arg VALUE} are evaluated before it is called. Thus, if the value of {lisp X} is {lisp B}, and the value of {lisp Y} is {lisp C}, then {lisp (SET {lisp X} {lisp Y})} would result in {lisp B} being set to {lisp C}, and {lisp C} being returned as the value of {fn SET}. }} {FnDef {FnName SETQ} {FnArgs VAR VALUE} {Type NOSPREAD NLAMBDA} {Text Nlambda version of {fn SET}; {arg VAR} is not evaluated, {arg VALUE} is. Thus if the value of {lisp X} is {lisp B} and the value of {lisp Y} is {lisp C}, {lisp (SETQ X Y)} would result in {lisp X} (not {lisp B}) being set to {lisp C}, and {lisp C} being returned. Note: Since {fn SETQ} is an nlambda, {it neither} argument is evaluated during the calling process. However, {fn SETQ} itself calls {fn EVAL} on its second argument. As a result, typing {lisp (SETQ VAR FORM)} and {lisp SETQ(VAR FORM)} to the Interlisp executive is equivalent: in both cases {lisp VAR} is not evaluated, and {lisp FORM} is. {note It appears that SETQ evaluates all of its arguments (except the first) to allow (SETQ X Y + 1) to error out to CLISP (when + is evaluated). Yuk! ---mjs} }} {FnDef {FnName SETQQ} {FnArgs VAR VALUE} {Type NLAMBDA} {Text Like {fn SETQ} except that neither argument is evaluated, e.g., {lisp (SETQQ X (A B C))} sets {lisp X} to {lisp (A B C)}. }} {MacDef {Name PSETQ} {Args VAR{sub 1} VALUE{sub 1} {ellipsis} VAR{sub N} VALUE{sub N}} {Text Does a multiple {fn SETQ} of {arg VAR{sub 1}} (unevaluated) to the value of {arg VALUE{sub 1}}, {arg VAR{sub 2}} to the value of {arg VALUE{sub 2}}, etc. All of the {arg VALUE{sub i}} terms are evaluated before any of the assignments. Therefore, {lisp (PSETQ A B B A)} can be used to swap the values of the variables {lisp A} and {lisp B}. }} {FnDef {FnName GETTOPVAL} {FnArgs VAR} {Text Returns the top level value of {arg VAR} (even if {lisp NOBIND}), regardless of any intervening local bindings. }} {FnDef {FnName SETTOPVAL} {FnArgs VAR VALUE} {Text Sets the top level value of {arg VAR} to {arg VALUE}, regardless of any intervening bindings, and returns {arg VALUE}. }} A major difference between various Interlisp implementations is the way that variable bindings are implemented. Interlisp-10 and Interlisp-Jerico use what is called "shallow" binding. Interlisp-D and Interlisp-VAX use what is called "deep" binding. In a deep binding system,{index deep binding} a variable is bound by saving on the stack the variable's new value. When a variable is accessed, its value is found by searching the stack for the most recent binding. If the variable is not found on the stack, the top level binding is retrieved from a "value cell"{index *PRIMARY* Value cell of a litatom} associated with the variable. In a "shallow" binding system,{index shallow binding} a variable is bound by saving on the stack the variable name and the variable's old value and putting the new value in the variable's value cell. When a variable is accessed, its value is always found in its value cell. {fn GETTOPVAL} and {fn SETTOPVAL} are less efficient in a shallow binding system, because they have to search the stack for rebindings; it is more economical to simply rebind variables. In a deep binding system, {fn GETTOPVAL} and {fn SETTOPVAL} are very efficient since they do not have to search the stack, but can simply access the value cell directly. {fn GETATOMVAL} and {fn SETATOMVAL} can be used to access a variable's value cell, in either a shallow or deep binding system. {FnDef {FnName GETATOMVAL} {FnArgs VAR} {Text Returns the value in the value cell of {arg VAR}. In a shallow binding system, this is the same as {lisp (EVAL {arg ATM})}, or simply {arg VAR}. In a deep binding system, this is the same as {lisp (GETTOPVAL {arg VAR})}. }} {FnDef {FnName SETATOMVAL} {FnArgs VAR VALUE} {Text Sets the value cell of {arg VAR} to {arg VALUE}. In a shallow binding system, this is the same as {fn SET}; in a deep binding system, this is the same as {fn SETTOPVAL}. }} }{End SubSec Using Litatoms as Variables} {Begin SubSec Function Definition Cells} {Title Function Definition Cells} {Text {index function definition cells} Each litatom has a function definition cell, which is accessed when a litatom is used as a function. The mechanism for accessing and setting the function definition cell of a litatom is described on {PageRef Tag FunctionDefinition}. {note why not described here? ---lmm} }{End SubSec Function Definition Cells} {Begin SubSec Property Lists} {Title Property Lists} {Text {index *PRIMARY* Properties of litatoms} Each litatom has an associated property list, which allows a set of named objects to be associated with the litatom. A property list associates a name, known as a "property name"{index Property names} or "property", with an abitrary object, the "property value"{index Property values} or simply "value". Sometimes the phrase "to store on the property {arg X}" is used, meaning to place the indicated information on a property list under the property name {arg X}. Property names are usually litatoms or numbers, although no checks are made. However, the standard property list functions all use {fn EQ} to search for property names, so they may not work with non-atomic property names. Note that the same object can be used as both a property name and a property value. Note: Many litatoms in the system already have property lists, with properties used by the compiler, the break package, DWIM, etc. Be careful not to clobber such system properties. The variable {var SYSPROPS}{index *PRIMARY* SYSPROPS Var} is a list of property names used by the system. {note SYSPROPS NOT COMPLETE!! ---lmm} The functions below are used to manipulate the propert lists of litatoms. Except when indicated, they generate the error {lisp ARG NOT LITATOM},{index ARG NOT LITATOM Error} if given an object that is not a litatom. {FnDef {FnName GETPROP} {FnArgs ATM PROP} {Text Returns the property value for {arg PROP} from the property list of {arg ATM}. Returns {lisp NIL} if {arg ATM} is not a litatom, or {arg PROP} is not found. Note that {fn GETPROP} also returns {lisp NIL} if there is an occurrence of {arg PROP} but the corresponding property value is {lisp NIL}; this can be a source of program errors. Note: {fn GETPROP} used to be called {lisp GETP}.{index GETP (old name of GETPROP)} }} {FnDef {FnName PUTPROP} {FnArgs ATM PROP VAL} {Text Puts the property {arg PROP} with value {arg VAL} on the property list of {arg ATM}. {arg VAL} replaces any previous value for the property {arg PROP} on this property list. Returns {arg VAL}. }} {FnDef {FnName ADDPROP} {FnArgs ATM PROP NEW FLG} {Text Adds the value {arg NEW} to the list which is the value of property {arg PROP} on the property list of {arg ATM}. If {arg FLG} is {lisp T}, {arg NEW} is {fn CONS}ed onto the front of the property value of {arg PROP}, otherwise it is {fn NCONC}ed on the end (using {fn NCONC1}). If {arg ATM} does not have a property {arg PROP}, or the value is not a list, then the effect is the same as {index PUTPROP FN}{lisp (PUTPROP {arg ATM} {arg PROP} (LIST {arg NEW}))}. {fn ADDPROP} returns the (new) property value. Example: {lispcode _ (PUTPROP 'POCKET 'CONTENTS NIL) NIL _ (ADDPROP 'POCKET 'CONTENTS 'COMB) (COMB) _ (ADDPROP 'POCKET 'CONTENTS 'WALLET) (COMB WALLET)} }} {FnDef {FnName REMPROP} {FnArgs ATM PROP} {Text Removes all occurrences of the property {arg PROP} (and its value) from the property list of {arg ATM}. Returns {arg PROP} if any were found, otherwise {lisp NIL}. }} {FnDef {FnName REMPROPLIST} {FnArgs ATM PROPS} {Text Removes all occurrences of all properties on the list {arg PROPS} (and their corresponding property values) from the property list of {arg ATM}. Returns {lisp NIL}. }} {FnDef {FnName CHANGEPROP} {FnArgs X PROP1 PROP2} {Text Changes the property name of property {arg PROP1} to {arg PROP2} on the property list of {arg X}, (but does not affect the value of the property). Returns {arg X}, unless {arg PROP1} is not found, in which case it returns {lisp NIL}. }} {FnDef {FnName PROPNAMES} {FnArgs ATM} {Text Returns a list of the property names on the property list of {arg ATM}. {note includes prop names with nil values??} }} {FnDef {FnName DEFLIST} {FnArgs L PROP} {Text Used to put values under the same property name{index property names} on the property lists of several litatoms. {arg L} is a list of two-element lists. The first element of each is a litatom, and the second element is the property value{index property values} for the property {arg PROP}. Returns {lisp NIL}. For example, {lispcode (DEFLIST '( (FOO MA) (BAR CA) (BAZ RI) ) 'STATE)} puts {lisp MA} on {lisp FOO}'s {lisp STATE} property, {lisp CA} on {lisp BAR}'s {lisp STATE} property, and {lisp RI} on {lisp BAZ}'s {lisp STATE} property. }} Property lists are conventionally implemented as lists of the form {lispcode ({arg NAME{sub 1}} {arg VALUE{sub 1}} {arg NAME{sub 2}} {arg VALUE{sub 2}} {ellipsis})} although the user can store anything as the property list of a litatom. However, the functions which manipulate property lists observe this convention by searching down the property lists two {fn CDR}s at a time. Most of these functions also generate an error, {lisp ARG NOT LITATOM},{index ARG NOT LITATOM Error} if given an argument which is not a litatom, so they cannot be used directly on lists. ({lisp LISTPUT}, {lisp LISTPUT1}, {lisp LISTGET}, and {lisp LISTGET1} are functions similar to {lisp PUTPROP} and {lisp GETPROP} that work directly on lists. See {PageRef Fn LISTPUT}.) The property lists of litatoms can be directly accessed with the following functions: {FnDef {FnName GETPROPLIST} {FnArgs ATM} {Text Returns the property list of {arg ATM}. }} {FnDef {FnName SETPROPLIST} {FnArgs ATM LST} {Text If {arg ATM} is a litatom, sets the property list of {arg ATM} to be {arg LST}, and returns {arg LST} as its value. }} {FnDef {FnName GETLIS} {FnArgs X PROPS} {Text Searches the property list of {arg X}, and returns the property list as of the first property on {arg PROPS} that it finds. For example, {lispcode _ (GETPROPLIST 'X) (PROP1 A PROP3 B A C) _ (GETLIS 'X '(PROP2 PROP3)) (PROP3 B A C)} Returns {lisp NIL} if no element on {arg PROPS} is found. {arg X} can also be a list itself, in which case it is searched as described above. If {arg X} is not a litatom or a list, returns {lisp NIL}. }} }{End SubSec Property Lists} {Begin SubSec Print Names} {Title Print Names} {Text {Tag PrintNames} {index *PRIMARY* Print names} Each litatom has a print name, a string of characters that uniquely identifies that litatom. The term "print name" has been extended, however, to refer to the characters that are output when any object is printed. In Interlisp, all objects have print names, although only litatoms and strings have their print name explicitly stored. This section describes a set of functions which can be used to access and manipulate the print names of any object, though they are primarily used with the print names of litatoms. {note max length of print names is implementation dependent. for Interlisp-Vax, is 2^16 characters} The print name of an object is those characters that are output when the object is printed using {fn PRIN1}, e.g., the print name of the litatom {lisp ABC%(D} consists of the five characters {lisp ABC(D}. The print name of the list {lisp (A B C)} consists of the seven characters {lisp (A B C)} (two of the characters are spaces). Sometimes we will have occasion to refer to a "{lisp PRIN2}-name."{index PRIN2-names} The {lisp PRIN2}-name of an object is those characters output when the object is printed using {lisp PRIN2}. Thus the {lisp PRIN2}-name of the litatom {lisp ABC%(D} is the {it six} characters {lisp ABC%(D}. Note that the {fn PRIN2}-name depends on what readtable is being used (see {PageRef Tag ReadTables}), since this determines where {lisp %}'s will be inserted. Many of the functions below allow either print names or {lisp PRIN2}-names to be used, as specified by {arg FLG} and {arg RDTBL} arguments. If {arg FLG} is {lisp NIL}, print names are used. Otherwise, {fn PRIN2}-names are used, computed with respect to the readtable {arg RDTBL} (or the current readtable, if {arg RDTBL} = {lisp NIL}). {note there is an inconsistancy: PRINT prints the PRIN2-name, and PRIN1 prints the print name. could be confusing.} Note: The print name of an integer depends on the setting of {index RADIX Fn}{fn RADIX} ({PageRef Fn RADIX}). The functions described in this section ({fn UNPACK}, {fn NCHARS}, etc.) define the print name of an integer as though the radix was 10, so that {lisp (PACK (UNPACK 'X9))} will always be {lisp X9} (and not {lisp X11}, if {fn RADIX} is set to 8). However, integers will still be {it printed} by {fn PRIN1} using the current radix. The user can force these functions to use print names in the current radix by changing the setting of the variable {var PRXFLG} ({PageRef Var PRXFLG}). {FnDef {FnName MKATOM} {FnArgs X} {Text Creates and returns an atom whose print name is the same as that of the string {arg X} or, if {arg X} isn't a string, the same as that of {lisp (MKSTRING {arg X})}. Examples: {lispcode (MKATOM '(A B C)) => %(A% B% C%)} {lispcode (MKATOM "1.5") => 1.5} Note that the last example returns a number, not a litatom. It is a deeply-ingrained feature of Interlisp that no litatom can have the print name of a number. }} {FnDef {FnName SUBATOM} {FnArgs X N M} {Text Equivalent to {lisp (MKATOM (SUBSTRING {arg X} {arg N} {arg M}))}, but does not make a string pointer (see {PageRef Fn SUBSTRING}). Returns an atom made from the {arg N}th through {arg M}th characters of the print name of {arg X}. If {arg N} or {arg M} are negative, they specify positions counting backwards from the end of the print name. Examples: {lispcode (SUBATOM "FOO1.5BAR" 4 6) => 1.5} {lispcode (SUBATOM '(A B C) 2 -2) => A% B% C} }} {FnDef {FnName PACK} {FnArgs X} {Text If {arg X} is a list of atoms, {fn PACK} returns a single atom whose print name is the concatenation of the print names of the atoms in {arg X}. If the concatenated print name is the same as that of a number, {fn PACK} will return that number. For example, {lispcode (PACK '(A BC DEF G)) => ABCDEFG} {lispcode (PACK '(1 3.4)) => 13.4} {lispcode (PACK '(1 E -2)) => .01} Although {arg X} is usually a list of atoms, it can be a list of arbitrary Interlisp objects. The value of {fn PACK} is still a single atom whose print name is the concatenation of the print names of all the elements of {arg X}, e.g., {lispcode (PACK '((A B) "CD")) => %(A% B%)CD} If {arg X} is not a list or {lisp NIL}, {fn PACK} generates an error, {lisp ILLEGAL ARG}.{index ILLEGAL ARG Error} }} {FnDef {FnName PACK*} {FnArgs {arg X{sub 1}} {arg X{sub 2}} {ellipsis} {arg X{sub N}}} {Type NOSPREAD} {Text Nospread version of {fn PACK} that takes an arbitrary number of arguments, instead of a list. Examples:, {lispcode (PACK* 'A 'BC 'DEF 'G) => ABCDEFG} {lispcode (PACK* 1 3.4) => 13.4} }} {FnDef {FnName UNPACK} {FnArgs X FLG RDTBL} {Text Returns the print name of {arg X} as a list of single-characters atoms, e.g., {lispcode (UNPACK 'ABC5D) => (A B C 5 D)} {lispcode (UNPACK "ABC(D") => (A B C %( D)} If {arg FLG}={lisp T}, the {index PRIN2-names}{fn PRIN2}-name of {arg X} is used (computed with respect to {arg RDTBL}), e.g., {lispcode (UNPACK "ABC(D" T) => (%" A B C %( D %")} {lispcode (UNPACK 'ABC%(D" T) => (A B C %% %( D)} Note: {lisp (UNPACK {arg X})} performs {arg N} {fn CONS}es, where {arg N} is the number of characters in the print name of {arg X}. }} {FnDef {FnName DUNPACK} {FnArgs X SCRATCHLIST FLG RDTBL} {Text A destructive version of {fn UNPACK} that does not perform any {fn CONS}es but instead reuses the list {arg SCRATCHLIST}. If the print name is too long to fit in {arg SCRATCHLIST}, {fn DUNPACK} will extend it. If {arg SCRATCHLIST} is not a list, {fn DUNPACK} returns {lisp (UNPACK {arg X} {arg FLG} {arg RDTBL})}. }} {index *PRIMARY* NCHARS Fn} {FnDef {FnName NCHARS} {FnArgs X FLG RDTBL} {Text Returns the number of characters in the print name of {arg X}. If {arg FLG}={lisp T}, the {index PRIN2-names}{fn PRIN2}-name is used. For example, {lispcode (NCHARS 'ABC) => 3} {lispcode (NCHARS "ABC" T) => 5} Note: {fn NCHARS} works most efficiently on litatoms and strings, but can be given any object. }} {FnDef {FnName NTHCHAR} {FnArgs X N FLG RDTBL} {Text Returns the {arg N}th character of the print name of {arg X} as an atom. {arg N} can be negative, in which case it counts from the end of the print name, e.g., -1 refers to the last character, -2 next to last, etc. If {arg N} is greater than the number of characters in the print name, or less than minus that number, or 0, {fn NTHCHAR} returns {lisp NIL}. Examples: {lispcode (NTHCHAR 'ABC 2) => B} {lispcode (NTHCHAR 15.6 2) => 5} {lispcode (NTHCHAR 'ABC%(D -3 T) => %%} {lispcode (NTHCHAR "ABC" 2) => B} {lispcode (NTHCHAR "ABC" 2 T) => A} }} Note: {fn NTHCHAR} and {fn NCHARS} work much faster on objects that actually have an internal representation of their print name, i.e., litatoms and strings, than they do on numbers and lists, as they do not have to simulate printing. {index *PRIMARY* Lower case characters} {FnDef {FnName L-CASE} {FnArgs X FLG} {Text Returns a lower case version of {arg X}. If {arg FLG} is {lisp T}, the first letter is capitalized. If {arg X} is a string, the value of {fn L-CASE} is also a string. If {arg X} is a list, {fn L-CASE} returns a new list in which {fn L-CASE} is computed for each corresponding element and non-{lisp NIL} tail of the original list. Examples: {lispcode (L-CASE 'FOO) => foo} {lispcode (L-CASE 'FOO T) => Foo} {lispcode (L-CASE "FILE NOT FOUND" T) => "File not found"} {lispcode (L-CASE '(JANUARY FEBRUARY (MARCH "APRIL")) T) => '(January February (March "April"))} }} {index *PRIMARY* Upper case characters} {FnDef {FnName U-CASE} {FnArgs X} {Text Similar to {fn L-CASE}, except returns the upper case version of {Arg X}. }} {FnDef {FnName U-CASEP} {FnArgs X} {Text Returns {lisp T} if {arg X} contains no lower case letters; {lisp NIL} otherwise. }} {FnDef {Name GENSYM} {Args PREFIX {anonarg} {anonarg} {anonarg} {anonarg}} {Text Returns a litatom of the form {lisp Xnnnn}, where {lisp X}={arg PREFIX} (or {lisp A} if {arg PREFIX} is {lisp NIL}) and {lisp nnnn} is an integer. Thus, the first one generated is {lisp A0001},{index A000n (gensym)} the second {lisp A0002}, etc. The integer suffix is always at least four characters long, but it can grow beyond that. For example, the next litatom produced after {lisp A9999} would be {lisp A10000}. {fn GENSYM} provides a way of generating litatoms for various uses within the system. {note see flames on new args to GENSYM in AR 214} }} {VarDef {Name GENNUM} {Text The value of {var GENNUM}, initially {lisp 0}, determines the next {fn GENSYM}, e.g., if {var GENNUM} is set to {lisp 23}, {lisp (GENSYM)}={lisp A0024}. }} The term "gensym" is used to indicate a litatom that was produced by the function {fn GENSYM}. Litatoms generated by {fn GENSYM} are the same as any other litatoms: they have property lists, and can be given function definitions. Note that the litatoms are not guaranteed to be new. For example, if the user has previously created {lisp A0012}, either by typing it in, or via {fn PACK} or {fn GENSYM} itself, then if {var GENNUM} is set to {lisp 11}, the next litatom returned by {fn GENSYM} will be the {lisp A0012} already in existence. {FnDef {FnName MAPATOMS} {FnArgs FN} {Text Applies {arg FN} (a function or lambda expression) to every litatom in the system. Returns {lisp NIL} For example, {lispcode (MAPATOMS (FUNCTION (LAMBDA(X) (if (GETD X) then (PRINT X)]} will print every litatom with a function definition. Note: In some implementations of Interlisp, unused litatoms may be garbage collected, which can effect the action of {fn MAPATOMS}. }} {note GC may change value in non-incremental GC system, which may throw away atoms ---lmm} {FnDef {FnName APROPOS} {FnArgs STRING ALLFLG QUIETFLG OUTPUT} {Text {fn APROPOS} scans all litatoms in the system for those which have {arg STRING} as a substring and prints them on the terminal along with a line for each relevant item defined for each selected atom. Relevant items are (1) function definitions, for which only the arglist is printed, (2) dynamic variable values, and (3) non-null property lists. {fn PRINTLEVEL} ({PageRef Fn PRINTLEVEL}) is set to {lisp (3 . 5)} when {fn APROPOS} is printing. If {arg ALLFLG} is {lisp NIL}, then atoms with no relevant items and "internal" atoms are omitted ("internal" currently means those litatoms whose print name begins with a {lisp \} or those litatoms produced by {fn GENSYM}). If {arg ALLFLG} is a function (i.e., {lisp (FNTYP {arg ALLFLG})} is non-{lisp NIL}), then it is used as a predicate on atoms selected by the substring match, with value {lisp NIL} meaning to omit the atom. If {arg ALLFLG} is any other non-{lisp NIL} value, then no atoms are omitted. If {arg QUIETFLG} is non-{lisp NIL}, then no printing at all is done, but instead a list of the selected atoms is returned. If {arg OUTPUT} is non-{lisp NIL}, the printing will be directed to {arg OUTPUT} (which should be a stream open for output) instead of to the terminal stream. }} }{End SubSec Print Names} {Begin SubSec Characters and Character Codes} {Title Characters and Character Codes} {Text {index *PRIMARY* NS characters} {index *PRIMARY* Character codes} {index *PRIMARY* Characters} Characters may be represented in two ways: as single-character atoms, or as integer character codes. In many situations, it is more efficient to use character codes, so Interlisp provides parallel functions for both representations. Interlisp-D uses the 16-bit NS character set, described in the document {it Character Code Standard} [Xerox System Integration Standards, XSIS 058404, April 1984]. Legal character codes range from 0 to 65535. The NS (Network Systems) character encoding encompasses a much wider set of available characters than the 8-bit character standards (such as ASCII), including characters comprising many foreign alphabets and special symbols. For instance, Interlisp-D supports the display and printing of the following: Le systÿÿñ°ÿme d'information Xerox 11xx est remarquablement polyglotte. Das Xerox 11xx Kommunikationssystem bietet merkwÿÿñåÿrdigeÿÿ multilingualeÿ ÿÿNutzmñÔglichkeitenÿ. Mÿÿ ï8 ""[w] ÿ ÿÿïN ÿ ÿÿïµ v with Rwvÿ: M ÿÿï8ÿ [v] These characters can be used in strings, litatom print names, symbolic files, or anywhere else 8-bit characters could be used. All of the standard string and print name functions ({fn RPLSTRING}, {fn GNC}, {fn NCHARS}, {fn STRPOS}, etc.) accept litatoms and strings containing NS characters. For example: {lispcode _(STRPOS "char" "this is an 8-bit character string") 18 _(STRPOS "char" "ÿÿcelui-ci ÿcomporteÿÿ des charactñ°reÿs NS") 23} In almost all cases, a program does not have to distinguish between NS characters or 8-bit characters. The exception to this rule is the handling of input/output operations (see {PageRef Term NS character I/O}). The function {fn CHARCODE} ({PageRef Fn CHARCODE}) provides a simple way to create individual NS characters codes. The VirtualKeyboards library package provides a set of virtual keyboards that allow keyboard or mouse entry of NS characters. {FnDef {FnName PACKC} {FnArgs X} {Text Similar to {fn PACK} except {arg X} is a list of character codes. For example, {lispcode (PACKC '(70 79 79)) => FOO} }} {FnDef {FnName CHCON} {FnArgs X FLG RDTBL} {Text Like {fn UNPACK}, except returns the print name of {arg X} as a list of character codes. If {arg FLG}={lisp T}, the {lisp PRIN2}-name{index PRIN2-names} is used. For example, {lispcode (CHCON 'FOO) => (70 79 79)} }} {FnDef {FnName DCHCON} {FnArgs X SCRATCHLIST FLG RDTBL} {Text Similar to {fn DUNPACK}. }} {FnDef {Name NTHCHARCODE} {Args X N FLG RDTBL} {Text Similar to {fn NTHCHAR}, except returns the character code of the {arg N}th character of the print name of {arg X}. If {arg N} is negative, it is interpreted as a count backwards from the end of {arg X}. If the absolute value of {arg N} is greater than the number of characters in {arg X}, or 0, then the value of {fn NTHCHARCODE} is {lisp NIL}. If {arg FLG} is {lisp T}, then the {fn PRIN2}-name of {arg X} is used, computed with respect to the readtable {arg RDTBL} }} {note move (RPLCHARCODE X N CHR) here??} {FnDef {FnName CHCON1} {FnArgs X} {Text Returns the character code of the first character of the print name of {arg X}; equal to {lisp (NTHCHARCODE {arg X} 1)}. }} {FnDef {FnName CHARACTER} {FnArgs N} {Text {arg N} is a character code. Returns the atom having the corresponding single character as its print name. {lispcode (CHARACTER 70) => F} }} {FnDef {FnName FCHARACTER} {FnArgs N} {Text Fast version of {fn CHARACTER} that compiles open. {note are there caviats? Is there any reason to ever use the other version, except for debugging purposes (tracing, advising)? no, use CHARACTER ---lmm flush??} {note in Interlisp-Vax, FCHARACTER compiles open and does not check if N is a valid character code} }} The following function makes it possible to gain the efficiency that comes from dealing with character codes without losing the symbolic advantages of character atoms: {FnDef {Name CHARCODE} {Args CHAR} {Type NLAMBDA} {Text Returns the character code specified by {arg CHAR} (unevaluated). If {arg CHAR} is a one-character atom or string, the corresponding character code is simply returned. Thus, {lisp (CHARCODE A)} is 65, {lisp (CHARCODE 0)} is 48. If {arg CHAR} is a multi-character litatom or string, it specifies a character code as described below. If {arg CHAR} is {lisp NIL}, {fn CHARCODE} simply returns {lisp NIL}. Finally, if {arg CHAR} is a list structure, the value is a copy of {arg CHAR} with all the leaves replaced by the corresponding character codes. For instance, {lisp (CHARCODE (A (B C))) => (65 (66 67))}. If a character is specified by a multi-character litatom or string, {fn CHARCODE} interprets it as follows: {Begin Labeledlist CHARCODE character specification} {Label {lisp CR}, {lisp SPACE}, etc.} {Text The variable {index *PRIMARY* CHARACTERNAMES Var}{var CHARACTERNAMES} contains an association list mapping special litatoms to character codes. Among the characters defined this way are {lisp CR} (13), {lisp LF} (10), {lisp SPACE} or {lisp SP} (32), {lisp ESCAPE} or {lisp ESC} (27), {lisp BELL} (7), {lisp BS} (8), {lisp TAB} (9), {lisp NULL} (0), and {lisp DEL} (127). The litatom {lisp EOL} maps into the appropriate {index End-of-line character}End-Of-Line character code in the different Interlisp implementations (31 in Interlisp-10, 13 in Interlisp-D, 10 in Interlisp-VAX). Examples: {lispcode (CHARCODE SPACE) => 32} {lispcode (CHARCODE CR) => 13} } {Label {lisp {arg CHARSET},{arg CHARNUM}}} {Label {lisp {arg CHARSET}-{arg CHARNUM}}} {Text If the character specification is a litatom or string of the form {lisp {arg CHARSET},{arg CHARNUM}} or {lisp {arg CHARSET}-{arg CHARNUM}}, the character code for the character number {arg CHARNUM} in the character set {arg CHARSET} is returned. {index *PRIMARY* Character sets} The 16-bit NS character encoding is divided into a large number of "character sets." Each 16-bit character can be decoded into a character set (an integer from 0 to 254 inclusive) and a character number (also an integer from 0 to 254 inclusive). {arg CHARSET} is either an {it octal} number, or a litatom in the association list {index *PRIMARY* CHARACTERSETNAMES Var}{var CHARACTERSETNAMES} (which defines the character sets for {lisp GREEK}, {lisp CYRILLIC}, etc.). {arg CHARNUM} is either an {it octal} number, a single-character litatom, or a litatom from the association list {var CHARACTERNAMES}. Note that if {arg CHARNUM} is a single-digit number, it is interpreted as the character "2", rather than as the octal number 2. Examples: {lispcode (CHARCODE 12,6) => 2566} {lispcode (CHARCODE 12,SPACE) => 2592} {lispcode (CHARCODE GREEK,A) => 9793} } {Label {lisp ^{arg CHARSPEC}} (control chars)} {Text If the character specification is a litatom or string of one of the forms above, preceeded by the character "^", this indicates a "control character," derived from the normal character code by clearing the seventh bit of the character code (normally set). Examples: {lispcode (CHARCODE ^A) => 1} {lispcode (CHARCODE ^GREEK,A) => 9729} } {Label {lisp #{arg CHARSPEC}} (meta chars)} {Text If the character specification is a litatom or string of one of the forms above, preceeded by the character "#", this indicates a "meta character," derived from the normal character code by setting the eighth bit of the character code (normally cleared). {lisp ^} and {lisp #} can both be set at once. Examples: {lispcode (CHARCODE #A) => 193} {lispcode (CHARCODE #^GREEK,A) => 9857} } {End Labeledlist CHARCODE character specification} A {fn CHARCODE} form can be used wherever a structure of character codes would be appropriate. For example: {lispcode (FMEMB (NTHCHARCODE X 1) (CHARCODE (CR LF SPACE ^A))) (EQ (READCCODE FOO) (CHARCODE GREEK,A))} There is a macro for {fn CHARCODE} which causes the character-code structure to be constructed at compile-time. Thus, the compiled code for these examples is exactly as efficient as the less readable: {lispcode (FMEMB (NTHCHARCODE X 1) (QUOTE (13 10 32 1))) (EQ (READCCODE FOO) 9793)} }} {MacDef {Name SELCHARQ} {Args E CLAUSE{sub 1} {ellipsis} CLAUSE{sub N} DEFAULT} {Text Similar to {fn SELECTQ} ({PageRef Fn SELECTQ}), except that the selection keys are determined by applying {fn CHARCODE} (instead of {fn QUOTE}) to the key-expressions. If the value of {arg E} is a character code or {lisp NIL} and it is {fn EQ} or {fn MEMB} to the result of applying {fn CHARCODE} to the first element of a clause, the remaining forms of that clause are evaluated. Otherwise, the default is evaluated. Thus {lispcode (SELCHARQ (BIN FOO) ((SPACE TAB) (FUM)) ((^D NIL) (BAR)) (a (BAZ)) (ZIP))} is exactly equivalent to {lispcode (SELECTQ (BIN FOO) ((32 9) (FUM)) ((4 NIL) (BAR)) (97 (BAZ)) (ZIP))} Furthermore, {lisp SELCHARQ} has a macro definition such that it always compiles as an equivalent {fn SELECTQ}. }} }{End SubSec Characters and Character Codes} }{End Chapter Litatoms} &&MODERN CLASSIC ?1(DEFAULTFONT 1 (GACHA 10) (GACHA 8) (TERMINAL 8))  Î $'š#{  mÂÚ€©+$TZKM—$r4'ZZ( X¡)zWV'p-wþ‚e‚(ß.«*)""ê'()Ò4!&Ù*SU.Ã2D.¤ñ "$&*¥/‘2ë'H-(G 2œCb¥)(-t(Š Ë='LvT"°.# 'b.0 -%%ì0sAj/#,N,.64„9<,• #`/r##*$&ë(&X"$=95("J#VK“g2™%g  55…\?¾ÿ|Ÿ.' "ëÓ1>0%3 ! !Õò!P(+±(8/\z)"y%l &3¤d¨#fl5&S$!++ö!Ö%)(/  ),:"*3m 6)Ê /P¤     p-‘öèzº