Skip to main content

Full text of "LISP 1.5"

See other formats




LISP 1.5 



AUGUST, 1969 


Report No. 1004 

George G. Robertson 

Vanderbilt University- 
Computer Center 
Nashville, Tennessee 






2.1 Symbolic Expressions. II - 2 

2.2 Elementary Functions. II - 2 

2.3 List Notation. II - 4 

2.4 Meta-Language Expressions. II - 4 

2.5 Syntax. II - 7 


3.1 The Universal Function. Ill - 1 

3.2 Variables, Constants, Functions, 

and Special Forms. Ill - 2 

3.3 Extentions. Ill - 4 

3.4 Arithmetic. HI - 5 

3.5 Program Feature. IU - 6 


4.1 Internal Structures. IV - 2 

4.2 Functions. IV - 8 


5.1 The LISP Program. V - 1 

5.2 Tape Operations... V - 1 

5.3 System Messages. V - 1 

5.4 Control Card Options. V - 6 




This publication is intended as a reference manual in the use of 
Vanderbilt SDS SIGMA 7 LISP 1.5, based on MIT 7090 LISP 1.5 (see LISP 
1.5 Programmer's Manual , MIT Press, January 1966). The manual is divided 
into five sections. The first three sections offer an introduction to 
the LISP language. The final two offer a description of the SIGMA 7 
implementation and user operating procedures. 

LISP is a mathematical language designed primarily for meaningful 
manipulation of list structures. When certain important features are 
added to the mathematical language, it can be extended to a programming 
language suitable for list processing. The mathematical language is 
complete without these extensions, but without them, it is not very useful 
as a programming language. With the extensions added, the language is 
referred to as the programming language LISP 1.5. 

Once the mathematical language has been extended to a programming 
language, the task becomes one of developing a programming system capable 
of translating the programming language into meaningful computer operations. 
With some languages, this task is best accomplished with a compiler. A 
compiler is a program which translates the source language into machine 
language. With LISP 1.5, however, this task is best accomplished with an 
interpretive system. An interpretive system is a programming system which 
executes a source language program by examining the source language and 
performing specified algorithms. These algorithms may be specified by the 

user in the LISP language, or they may be one of many primitive routines 
included in the system. A primitive is a machine language routine designed 
to perform one specific algorithm. These primitives along with the inter¬ 
preter make up the interpretive system. The task of translating the 
programming language LISP 1.5 is accomplished with such an interpretive 

Thus, the problem of implementing the mathematical language LISP on 
the SDS SIGMA 7 is reduced to a two step process. First, extend the 
mathematical language to a programming language. Second, develop an 
interpretive system capable of translating the programming language. These 
processes, as well as a mathematical description of the language, are 
discussed in this manual. 


LISP is a formal system and, as such, has the elements of 
any formal system. The elements of LISP include a set of symbols 
which are called symbolic expressions, abbreviated S-expressions. 

Also included is a functional notation over the set of symbols. 

These functions are referred to as Meta-language expressions, 
abbreviated M-expressions. A formal mapping of M-expressions into 
S-expressions is developed as a part of the system. Finally, a 
universal function, written as an M-exprossion, is defined. This 
function is used for interpreting the S-expression images of the 
M-expressions. This interpretation is actually the application of 
any function to its arguments. These elements form a complete 
mathematical system. 

As a mathematical system, LISP can be thought of as a 
mathematical language. A language is a set of sentences over 
an alphabet. The alphabet, which is a finite set of symbols, is 
the set of upper and lower case Latin letters, the arabic numerals, 
and a few special characters such as left and right parentheses, the 
comma, the blank, and the period. A sentence over an alphabet is 
any string of finite length composed of symbols from the alphabet 
which satisfies the rules of some grammar. The sentences in LISP 
are the atomic symbols which make up S-expressions. The mathematical 
system gives the language its meaning. Given the elements of the 
mathematical system, the mathematical language can be recognized and 


2.1 Symbolic Expressions 

The smallest whole element of the LISP language is the atomic 
symbol. An atomic symbol is a string of numerals and capital letters 
with the first character of the string being a letter. 

Examples : 





All S-expressions are composed of atomic symbols plus appropriate 
delimiters. An S-expression is either an atomic symbol or a left 
parenthesis, followed by an S-expression, followed by a period, 
followed by an S-expression, followed by a right parenthesis. An 
S-expression of the second type is sometimes referred to as a 
dotted pair. 



(A1 . A2) 

(A . (B . C)) 

((A . B) . C) 

((A . B) . (C . D)) 

2.2 Elementary Functions 

The elementary functions operate on S-expressions. To dif¬ 
ferentiate functions from S-expressions, the functions will be in 
small letters. Arguments to functions will be separated by a semi¬ 
colon. The five elementary functions are cons , head , tail, eq , and 
atom . 

The function cons is used to construct new S-expressions from 
smaller S-expressions. There are two arguments to cons and its value 
is an S-expression with the arguments to the function being the 

elements of the dotted pair. 

Examples : 

cons (A ; B) = (A . B) 
cons ((A . B) ; C) = ((A . B) . C) 
cons (A ; (B . C)) = (A . (B . C)) 
cons (cons (A ; B) ; C) = ((A . B) . C) 

The functions head and tail are selectors. The function 

head selects the first S-expression of the dotted pair which is 

the functional argument, while tail selects the second S-expres- 
sion of the dotted pair. Either function applied to an atomic symbol 
yields an undefined result. 


head ((A . B)) = A 

tail ((A . B)) = B 

head (((A . B) . C)) = (A . B) 

tail (((A . B) . C)) = C 

tail (head (((A . B) . C))) = B 

head (A) is undefined 

head (cons (A ; B)) = A 

tail (cons (A ; B)) = B 

cons (head ((A . B)) ; tail ((A . B))) = (A . B) 

The functions ec^ and atom are predicates, that is, they are 

functions whose value is either true or false. In LISP, the values 

true and false are represented by the atomic symbols T and F, 

respectively. The predicate ec[ tests for equality of atomic symbols. 

It is undefined for non-atomic arguments. The predicate atom is 

true if its argument is an atomic symbol and false it its argument 

is a dotted pair. , 

Examples : 

eq (A ; A) = T 
eq (A ; B) = F 

eq (A ; (B . C)) is undefined 
atom (ATOM) = T 
atom ((A . B)) = F 
atom (head ((A . B))) = T 

II - 4 

2.3 List Notation 

All non-atomic S-expressions used up to this point have been 
written as dotted pairs. Any non-atomic S-expression may be written 
in this form, but, for convenience, LISP allows an alternative form 
for this type of S-expression. The alternative form, called list 
notation, consists of a left parenthesis, followed by an arbitrary 
number of S-expressions, each separated from the following by either 
a blank or a comma, followed by a right parenthesis. The list 
(a^ a 2 ...a^) is equivalent to the list . (a 2 . (...(a n .NIL)...))), 
where NIL is the atomic symbol used to terminate lists. Dotted pairs 
and list notation may be used in the same S-expression. 

Examples ; 

(A B C) = (A . (B . (C . NIL))) 

((A B) C) = ((A . (B . NIL)) . (C . NIL)) 

(A) = (A . NIL) 

((A)) = ((A . NIL) . NIL) 

(A (B . C)) = (A . ((B . C) . NIL)) 

2.4 Meta-language Expressions 

The five elementary functions already discussed are examples 
of M-expressions. The M-expressions were distinguished from S-expres- 
sions by the use of lower case letters and the use of the semicolon 
as a seperator for arguments. Lower case letters are also used to 
represent variables in LISP. A variable is a symbol used to repre¬ 
sent an arbitrary S-expression. There are three other M-expressions 
which will be discussed before defining the mapping of M-expressions 
into S-expressions. These are the conditional expression, the lambda 
notation, and the label notation. 

In order to facilitate the definition of recursive functions, 

the conditional expression is included in the LISP language. A 

conditional expression is of the form (p, -* e, ; p~ e 0 ;...; p -*■ e ) 

s. L & £. nil 

where each p^ is an expression whose value is either true or false, 
and each e^ is any expression. The p^ are searched from left to 
right until the first true one is found. The value of the corre¬ 
sponding e^ becomes the value of the conditional expression. If 
none of the p^ are true, then the value of the entire expression 
is undefined. Each p^ or e^ can be either an S-expression, a function, 
a composition of functions, or another conditional function. 

Example : 

(eq (head (x) ; A) cons (B ; tail (x)) ; T ->■ x) 

In this example, x is a variable. If the head of x is A, then the 
value of the expression is the list x with A replaced by B. If the 
head of x is not A, then the value is x unchanged. 

The lambda notation is included in the language to allow the 
distinction between functions and forms. The lambda notation of 
Alonzo Church (See The Calculi of Lambda-Conversion by A. Church) 
is used. A form is an expression of more than one variable where 
the correspondence between variable and argument is not specified. 

If the correspondence is specified, then the expression is a function. 
The lambda notation allows a form to be converted to a function by 
specifying the correspondence. If e is a form in the variables 
x^^;...;x n , then the expression A((Xj;...jx^); e) represents the 
function of n variables obtained by substituting the n arguments in 
order for the variables Xjj...;x , respectively. 

II - 6 

Examples : 

MO ; y) ; y 2 + x) (3;4) = 4 2 + 3 = 19 

H(y X) ; y 2 + x) (3; 4) = 3 2 + 4 = 13 

In order to use a function recursively, the function name 
must be bound. The lambda notation is not sufficient for this, so 
the label notation is included in the language. If e is a expres¬ 
sion, and a is its name, we write label (a ; e) . 

Example : 

label (ff ; A((x) ; (atom (x) ->■ x ; T -»• ff (head (x))))) 

In this expression, x is a bound variable, and ff is a bound function 


The mapping of M-expressions into S-expressions can now be 
defined. If the function is represented by its name, it is translated 
by changing all of the letters to upper case, making it an atomic 
symbol. If the function uses the lambda notation, then the expres¬ 
sion X((x 1 ;...;x n ); e) is translated into (LAMBDA (XI ... XN) e*), 
where e* is the translation of e. If the function begins with label, 
then the translation of label (a ; e) is (LABEL a* e*). A variable, 
like a function name, is translated by using upper case letters. 

The translation of a constant X is (QUOTE X). This avoids ambiguity 
from the translation of x, which is X. The form fnfargjj...;arg n ) 
is translated into (fn* arg^*...arg n *). Finally, the conditional 
expression (p^ -+• e 1 ;...;p n e R ) is translated into (COND (pj* e^*) 

• ••(p n * e n *». 

Examples : 

M-expressions S-expressions 

x X 

head HEAD 

head (x) (HEAD X) 

II - 7 



(atom(x)->-x; T+ff(head(x))) 

label (ff; X ((x); (atom(x)-*x; 
T-*-f f (head (x) ) ) ) ) 



(FF (HEAD X)) 


((QUOTE T) (FF (HEAD X)))) 
((ATOM X) X) 

((QUOTE T) (FF (HEAD X)))))) 

2.5 Syntax 

The discussion of the formal system is now complete with the 
exception of a discussion of the universal function. Discussion of 
that function will be deferred to the section on the extension of 
the mathematical language to a programming language. The purpose 
of the universal function is to allow interpretation of the appli¬ 
cation of a function to its arguments. The interpretive nature of 
this function makes the programming language easily translatable. 

It is for that reason that discussion of it is found in the next 


For completeness, the syntax of the LISP language, described 
in Backus notation (see J. W. Backus, The Syntax and Semantics of 
the Proposed International Algebraic Language of the Zurich ACM- 
Gamm Conference. ICIP Paris, June 1959), is included. 

The Data Language 

<letter>::= 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 

<digit>::= 0|l|2|3|4|5|6|7|8|9 

<atomic-symbol>::= <LETTER>|<atomic-symbol><LETTER>|<atomic-symbol><digit> 

<S-expression>::= <atomic-symbol>| 

(<S- expression>.<S-expression>)| 

(<S-exp part>) 

<S-exp part>::= <empty>|<S-expression>|<S-exp part><S-expression> 

The Meta-Language 

<l$tter>::= 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 
<identifier>::= <letter>|<identifier><letter>|<identi£ier><digit> 
<form>::= <constant>| 


<function>(<argument list>)| 

<constant>: := <S-expression 
<variable>::= <identifier> 

<argument>:: = <form> 

<argument list>::= <empty>|<argument>|<qrgument list>;<argument> 
<conditional list>::= <empty> | <form>-*<form> | 

<form>-*-<form>; conditional list> 

<function>::= <identi£ier>| 

A(<var list>;<£orm>)| 

label (<identifier>;<£unction>) 

<var list>::= (<variable list>) 

<variable list>::= <empty>|<variable>|<variable list>;<variable> 


To make the mathematical language LISP useful in a programming 
environment, it must be extended to a programming language. First, 
in a programming system it is difficult to differentiate a data language 
and a meta-language. The solution to this problem is that the LISP formal 
system provides a universal function which can make that distinction, and 
which can interpret the meta-language expressed in the data language. Next, 
in a programming environment, there must be means of allowing the programmer 
to define his own functions and initialize his own variables to constants. 

Also, there should be provisions for logical operations on certain types 
of data and arithmetic operations on other types. To make the system useful, 
a large number of functions should be available to the programmer to accom¬ 
plish these types of tasks. Finally, there should be some method of 
controlled looping available to the programmer. With all of these extensions, 
the mathematical language becomes very useful in a programming environment, 
and the extended language can rightfully be called a programming language. 

3.1 The Universal Function 

An interpreter or universal function is one that can compute the value 
of any given function applied to its arguments when given a description of that 
function. The LISP universal function is evalquote (fn, args). All LISP 
functions have S-expressions as arguments, and therefore, the argument fn of 
evalquote must be an S-expression. In particular, fn is the S-expression image 
of some M-expression function. The universal function obeys the following 
identity. Let f be a function written as an M-expression, and let fn be its 

translation, an S-expression. Let f be a function of n arguments and let 
args=(argj...arg n ), a list of n S-expressions being used as arguments. Then 
evalquote (fn, args)=f(argp...;arg n ) if either side of the equation is 
defined at all. 

Example ; 

f: A((x;y) ; cons( head (x) ; y)) 

fn: (LAMBDA (X Y) (CONS (HEAD X) Y)) 

argp (A B) 

arg 2 : (C D) 

args: ((A B) (C D)) 

evalquote ((LAMBDA (X Y) (CONS (HEAD X) Y)j ; ((A B) (C D)))= 

X ((x;y) ; cons(head (x) ; y)) ((A B) ; (C D))= 

(A C D) 

During the execution of evalquote , an association list is maintained. 

This list has the current values of bound variables and function names. Two 
main functions are used by evalquote . They are eval and apply . The 
function apply handies a function and its arguments, while eval handles 
forms. Both auxiliary functions have the current association list as an argument. 
The maintenance of an association list in this manner allows dynamic binding 
of both variables and function names. 

3.2 Variables, Constants, Functions, and Special Forms 

A variable is a symbol used to represent an argument of a function. A 
variable becomes bound to a value in one of two ways. It may become bound 
by the lambda notation. The part of the interpreter that binds variables 
is called apply . When apply encounters a function beginning with LAMBDA, 
the association list is altered by adding the paired list of variables and 
arguments. During evaluation of the functions, when variables are 
encountered, they are evaluated by looking them up on the association list. 

If a variable has several bindings, the most recent is used. The part of 
the interpreter that finds the value of a variable is called eval . A variable 

remains bound within the scope of the lambda that binds it. 

The second way a variable may become bound is for the programmer to 
set the variable to a constant. A constant is simply a variable bound on 
the highest level. In other words, a constant is a variable which has the 
same value regardless of the current association list. This is accomplished 
by means of the property list, abbreviated p-list (see section 4.1 for 
detailed discussion of p-lists), associated with the variable symbol. Every 
atomic symbol has a p-list. If the p-list contains the indicator APVAL, then 
the next item on the p-list is the constant value of the variable. P-lists 
are searched by eval before the association list is searched, thus making it 
possible to set variables to constant values. This task is accomplished with 
the cset function. cset(X ; (ABC D)) makes the variable X always stand 
for (A B C D). 

Similarly, there are two ways to bind function names. One way is to 
use the label notation to alter the current association list by adding the 
function name bound to its function definition. A more desirable method 
involves the changing of the p-list of the atomic symbol representing the 
function name. The indicator EXPR on a p-list informs apply that the 
function is bound on the highest level of the S-expression which follows on 
the p-list. The function apply searches the p-list before searching the 
current association list, so that this method will override the label 
notation. The alteration of the p-list is accomplished by the function 
define . 

There is another class of functions in the LISP system. These are bound 
on their respective p-lists by the indicator SUBR followed by linkage to a 
machine language subroutine. All of the functions which are a part of the 
LISP system are of this type. 

A special form is a type of function with an indefinite number of 
arguments. The arguments of a special form are not evaluated before the 
special form receives them, unlike all other functional arguments. Special 
forms have indicators on their p-lists called FEXPR and FSUBR for LISP- 
defined forms and machine language forms, respectively. Special forms are 
included in the language to give it flexibility. 

3.3 Extensions 

There are several extensions to the language which are very useful 
in a programming environment. A full complement of input and output 
functions should be added, as well as functions which are designed for 
character manipulation. These functions are referred to as pseudo-functions 
because it is their side effects, not their values, which are important. For 
example, the print function has a side effect the physical printing of its 
S-expression argument on the line printer. The value of the print function 
is trivial and may be ignored. In addition to this type of pseudo-function, 
it would be useful to introduce functionals, that is, functions which have 
functions as arguments. Finally, it would be useful to include propositional 
connectives. These extensions extend the scope and usefulness of the 

The syntax of the meta-language does not allow functions as arguments. 

It expects an argument to be a form. To allow functionals, we must modify 
the syntatic definition of an argument to include functional arguments: 

<argument>::= form>|<function> 

Also, a rule for translating functional arguments must be set forth. If fn 
is a function used as an argument, then it is translated into (FUNCTION fn*). 

Now, functionals will be considered a part of the programming language. 

To allow logical connectives, three predicates are introduced. 

These are and , or , and not , The predicate not has only one argument, and 
its value is true if the argument has a value of false, false otherwise. 

The predicates and and or have an indefinite number of arguments, and 
are, therefore, special forms. If any of the arguments to and are false, 
then the value of and is false. Otherwise, its value is true. If any of 
the arguments to or~ are true, then the value of or is true. Otherwise, its 
value is false. With these predicates, any Boolean operations may be performed. 
3.4 Arithmetic 

Any useful programming language must have means of performing arithmetic 
and logical operations and making basic tests. For this reason, the 
programming language LISP 1.5 has provisions for handling fixed-point and 
floating-point numbers and logical words. In discussing arithmetic in LISP, 
two things must be considered; the form of numbers for reading and printing, 
and the arithmetic functions and predicates. 

Numbers are stored internally as a special type of atomic symbol. They 
may occur in S-expressions as though they were atomic symbols. Numbers are 
constants that evaluate to themselves. They do not need to be quoted. 

Numbers should not be used as variables or function names. 

A floating-point number must include a decimal point, but not as the 
first or last character. An optional plus or minus sign may precede the 
number. An optional exponent may be written directly after the number with 
the letter E, followed by an optional sign, followed by one or two digits of 
exponent. A fixed-point number _».s written as an integer with an optional sign. 

A logical word is written as a hexadecimal constant. It begins with 
the letter X, followed by the character ', followed by up to eight hex¬ 
adecimal digits, that is, the digits and the letters A, B, C, D, E, F, 
followed by the character ’. 

The arithmetic functions and predicates will be described in detail 
in section 4.2. These functions must be given numbers as arguments; 
otherwise an error condition will result. Types of numbers may be mixed 
in a list of numeric arguments. If all arguments are fixed-point numbers, 
then the value of the function will be fixed-point number. If at least 
one argument is a floating-point number, then the value of the function 
will be a floating-point number. These arithmetic functions may be used 
recursively, just as other functions available to the interpreter. 

3.5 Program Feature 

The addition of the program feature to LISP 1.5 allows the programmer 
to write an Algol-like program containing LISP statements to be executed. 
This allows the programmer to use controlled looping in his LISP program. 

The program form has the structure (PROG, list of program variables, 
sequence of statements and atomic symbols...). An atomic symbol in the 
list is the location marker for the statement beginning immediately after 
that symbol. The first list after the symbol PROG is a list of program 
variables. If there are none, then this should be written NIL or (). 

Program variables are treated much like bound variables, but they are not 
bound by LAMBDA. The value of each program variable is NIL until it has 
been set to something else by either a SET form or a SETQ form. These forms 
are used only to set program variables. 

Ill - 7 

Program statements, which are often executed for their effect 
rather than their value, are normally executed in sequence. That is, 
the statements are evaluated with the current association list, and then 
the value is ignored. The sequence of statements executed may be altered 
by the form GO. (GO A) causes a transfer to the statement with the 
location marker A. The form GO can be used only as a statement on the top 
level of a PROG or immediately inside a COND which is on the top level of 
a PROG. If a conditional statement on the top level of a PROG has none of 
its propositions true, then, unlike elsewhere, the program continues with 
the next statement. The normal end of a program is the form RETURN. The 
argument of RETURN is evaluated, and this is the value of the program. If 
a program runs out of statements, it returns with the value NIL. The program 
feature, like other LISP functions, can be used recursively. 

Example : 

rev (x) ::prog ( (y; z) ; 

A (nul 1 (x)-*return (y); 


B y:=cons(z;y); 


The predicate null is true if its argument is NIL. It is useful in 
determining when the end of a list is reached. The function rev will 
reverse a list on all levels so that 

rev((A ((B C) I)))) = ((D (C B)) A). 


'Oils section contains the specifications for an implementation of 
the programming language LISP 1.5 on the SD5 SIGMA 7 at Vanderbilt 
University. This implementation is based on the M. I. T. 7090 LISP 
system. The major difference between the two systems is the omission 
of the compiler and assembler from the SIGMA 7 system. In other words, 
this system is an interpretive-only system; all routines associated with 
the compiler, assembler, and loader arc not present in this implementation. 

Hie SDS SIGMA 7 is a binary computer with a 32-bit word length and 
65,536 words of storage, expandable to 131-072 words. There are 16 general 
registers, 7 of which can be used for indexing. One level of indirect 
addressing, with or without post-indexing, is allowed. All of memory is 
addressable and alterable by byte (8-bit), halfword (2-byte), word (4-byte), 
and doubleword (8-byte). The halfword addressability makes the elementary 
functions extremely simple if free storage is limited to 2*'* or 32,768 words, 
so that a pointer to a word in free storage may be contained in a halfword. 
When the SDS Batch Processing Monitor is in use, it resides in the lower 
19,000 words of memory. 

The programming system used to translate the programming language LISP 
1.5 is an interpretive system. The interpretive system is composed of three 
major components. First, there is a translator which translates the source 
language into internal list structures. This routine places the paired 
arguments, called doublets, for evalquote, onto a list called the input list, 
abbreviated I-list. A LISP program is simply a series of these doublets. 

Second, there is the interpreter or universal function evalquote. A 
control routine passes the pairs from the I-list to the interpreter for 
execution. The interpreter interprets the application of its first 
argument, which is an S-expression image of some M-expression, to its 
second argument, which is the S-expression argument to the function. The 
interpreter uses an association list, now abbreviated A-list, to keep track 
of which variables are bound and which functions names are bound. The 
interpreter, on its lowest level, links the source arguments to appropriate 
primitives or source language functions. The third component of the interpre¬ 
tive system is the set of primitives. 

In discussing the implementation of this programming system, three 
things must be included. There must be a complete description of the system's 
internal structures, the functions available to the user, and the running 
procedures for the system. This section gives these descriptions. 

4.1 Internal Structures 

Five major areas of discussion evolve from a discussion of the internal 
structures in the LISP system. First, we must specify the run-time storage 
layout. That is, we must specify exactly where the major components of the 
system will be when the system is in use. Second, we must consider the internal 
representation of list structures. Third, we should consider the make up of 
property lists, for both atomic symbols and for numeric constants. Fourth, 
we should consider each of the special structures necessary to make the system 
complete. Finally, we should consider the method of garbage collection and 
the structures that the garbage collection routine uses. The primary purpose 
of discussing these internal structures is to give the reader an idea of what 

the real make up of this programming system is, rather than simply present 
a functional description of the system. 

The run-time storage layout is best representated by the following 


Lists are structural forms built out of computer words as parts of 
trees. In representating list structure, a computer word will be divided 
as follows: 

Bit Purpose 

0 Reserved for garbage collection 

1-15 head(x) - contains a displacement from the beginning of 

the Free storage area 
16 0 - normal 

1 - indicates head of numeric p-list 
17-31 tail(x) - contains a displacement from the beginning of 

the Free storage area 

To represent a word, a rectangle is used. Bits 0 and 16 are ignored, if 
zero, and the word is represented by a rectangle divided into two sections. 
The presence of a name in a section indicates a pointer to that atomic 
symbol's property list. The pointer to NIL is represented by 

Every atomic symbol has a property list. When an atomic symbol is 

read, a p-list is created for it. A p-list is characterized by having a -1, 

or hexadecimal 7FFF, as the first element of the list. The rest of the 

list contains various indicators followed by pertinant properties of the 

symbol, and/or flags. A flag is not followed by a property, but rather 

indicates a property itself. The indicators and flags are: 

ATOM - flag - the -1 which characterizes p-lists 
TRACE - flag - indicates that this function should be traced 
EXf'R - indicator - followed by a pointer to an S-expression 
which represents some function 
FEXPR - indicator - followed by a pointer to an S-expression 
which represents a special form 
SUBR - indicator - followed by linkage to machine language 
subroutine, a function 

FSUBR - indicator - followed by linkage to machine language 
subroutine, a special form 

APVAL - indicator - followed by permanent value of the symbol 
PNAM - indicator - followed by a pointer to a list of full words 
containing the symbols print name 


Full word storage is reserved for storage of elements of the system 
which require a full word of significance. The primary use is for the 

storing of print names, numbers, and linkages of subroutines. 
Example : 

The print name for the atomic symbol EXAMPLE is: 

Numbers have a special p-list. The type of number 
indicated by TYP, where logical words have TYP equal to 
numbers have TYP equal to 1, and floating-point numbers 






represented is 
0 , fixed-point 
have a TYP of 2. 

One of the most important special structures is the object list. The 
object list is a list of all atomic symbols in existence. The read function 
uses this list to assure no duplications of p-lists. The structure is actually 
28 lists. The first 26 correspond to the letters of the alphabet, and any 
atomic symbol beginning with the i th letter will have its p-list on the i th 


list in the object list. The 27 list consists of all special symbols while 
the 28^ list consists of all numbers. 

Example : 

heads of lists 

Two other special lists have already been discussed. They are the 
association list and the input list. Both of these lists, along with the 
object list, are used during garbage collection to trace all active list 

There arc several other special structures that should be mentioned. 
Certain functions available to the user work with characters rather than 
pointers to lists. These characters are called character objects. The 
functions expecting character objects will consider the head of a list to be 
an EBCDIC character rather than a displacement address. There are also 
several buffers in the system. The character manipulation buffer, called 
60FF0, is 120 bytes long. All functions designed to do character 
manipulations use this buffer. There are three input buffers, each 80 bytes 
long. Input is actually done with the middle (2 nc *) buffer. The other two 

buffers are used for indication of errors by the errorl function. There 

is also a 120 byte output buffer. Finally, a large section of the run¬ 
time storage layout is reserved for a push-down stack. When arguments 
are passed to any subroutine, the push-down stack is used for passing 
arguments. Whenever a. recursive routine is entered, the push-down stack 
is used to save pertinent information. All of these special structures 
are necessary to make the system complete. 

When a word of Free or Full word storage is requested and none is 
available, the garbage collector is called. A user may explicitly call 
the garbage collector if he so desires. The user function is called 
reclaim . The garbage collector traces all active lists through the object 
list, the input list, and the current association list, setting bit 0 of 
every free storage word it encounters to 1. For full words, the garbage 
collector sets a corresponding bit in a bit table. When all lists have been 
exhausted, the garbage collector makes a linear pass over free storage, 
creating a new free storage list from words with bit 0 set to 0, and 
resetting bit 0 if it, is set to 1. Then the garbage collector does the 
same for full word storage using the bit table. The function reclaim has 
no arguments and its value is NIL. 

4.2 Functions and Constants in the LISP System 

This section contains all functions available in the LISP System 
as of August 1969. 

Each entry contains the name of the object, the property under 
which it is available (e.g., EXPR, FEXPR, SUBR, FS1JBR, or APVAL), 
whether it. is a pseudo-function, functional (function having functions 
as arguments), or predicate, and in some cases a definition of the 
function as an M-expression. In the case of APVAL's, the value is 

Elementary Functions 

car [x] : SUBR 

head [x] : SUBR 

cdr [x] : SUBR 

tail [x] : SUBR 

The elementary functions car and cdr always have some sort of value 
rather than giving an error diagnostic. A chain of cdr's applied to an 
atomic symbol will allow one to search its property list. Indiscriminate 
use of these functions past the atomic level will result in non-list 
structure and may appear as lengthy or even infinite garbage expressions 
if printed. 

The functions head and tail are identical to the functions car and 
cdr respectively. 
cons [x;y] : SUBR 

com; obtains a new word from the free storage list and places its 
two arguments in the head and tail of this word, respectively. It does not 
check to see if the arguments are valid list structure. The value of con s 

IV - 9 

is a pointer to the word that was just created. If the free storage 
list has been exhausted, cons calls the garbage collector to make 
a new free storage list and then performs the cons operation. 
atom [x] : SUBR predicate 

The first word on the property list of an atomic symbol contains 
-1 or 7FFFj£ in the head. The atom subroutine depends upon this, and 
on the fact that NIL is located at 0. 

ec^[x;y] : SUBR predicate 

eq is true if its two arguments are identical list structure. 
equal [x;y] : SUBR predicate 

equal is true if its arguments are the same S-expression, although 
they do not have to be identical list structures in the computer. It uses 
eq on the atomic level and is recursive. Floating point numbers in 
S-expressions are compared for numerical equality with a floating point 
tolerance of 3 x 10Fixed point numbers are compared for numerical 

list [x 1 ;...;x n ] : FSUBR 

The value of list is a list of its arguments. 
null [x] : SUBR predicate 

The value of null is true if its argument is NIL which is located at 
0 in the computer. 

SUBR pseudo-function 

SUBR pseudo-function 

SUBR pseudo-function 



The operator rpla c.a[x;y] replaces the head of x with y. Its value 
is x, but x is something different from what it was before. In terms of 
value, rplaca can be described by the equation. 

rplac a[x;y] = cons [y;cdr[x]]. But the effect is quite different: 
there is no cons involved and a new word is not created. 
rplacd [x;y] replaces the tail of x with y. 

These operators must be used with caution. They can permanently 
alter existing definitions and other basic memory. They can be used to 
create circular lists, which can cause infinite printing, and look 

infinite to functions that search, such as e qual and subst . 


The functions replhd and repltl are identical to the functions rplaca 
and rplacd respectively. 

Logical Connectives 

and[x 1 ;x 2 ...,x r ] : FSUBR predicate 

The arguments of and are evaluated in sequence, from left to right, 
until one is found that is false, or until the end of the list is reached. 
The value of and is false or true repectively. 
or[Xj;x 2 ...,x n ] : FSUBR predicate 

The arguments of or are evaluated in sequence from left to right, until 
one is found that is true, or until the end of the list is reached. The 
value of or is true or false respectively. 
not[x] : SUBR predicate 

The value of not is true if its argument is false, and false otherwise. 

IV - 11 

I nter pret er and Pr og_Feature 
evalquote ifn;args ] : S!JBR 

evalquoto [ fn; args ] = [get [ fn; FEXPR] get[fn; FSUBR]-* 

T-*apply[fn; args; NIL]] 

This definition shows that evalquote is capable of handling special 
forms as a sort of exception. Apply cannot handle special forms and will 
give an error if given one as its first argument. 
apply [fn;args;a] : SUBR 

In this description, spread can be regarded as a pseudo-function of 
one argument. This argument is a list, s pread puts the individual items 
of this list into the push-down stack. 

These M-expressions should not be taken too literally. In many cases, 
the actual program is a store and transfer where a recursion is suggested 
by these definitions. 

apply [fn;args;a]-[ 

atom[fn]-*[get[fn;EXPR]-*[expr; ^argsja]; 

f spread[args] 

get [fn;SUBR]-* ^ $ALIST:=a; j" j 
[ TSX subr 1 ^ J 

T-*apply[cdr[sassoc[fn;a;X[ [ ];error[A2] ] ] ];args;a]; 
eq[car[fn];LABEL]-*apply[caddr[fn];args;const cons[cadr[fn];caddr[fn]];a]]; 

T-*apply [eval[fn;a];args;a] ] 

1. The value of get is set aside. This is the meaning of the apparent free 
or undefined variable. 




null [ form ]-*-NIL; 
numberp [ f orm]-»-f orm; 

atom [ f orra ]-*■[ get [ f orm; APVAL ]^-car [ apval 1 ]; 

T-*cdr [sassoc [ form; a; X [ [ ]; error [ A8 ] ] ] ] ]; 
eq [ car [ f orm ]; QUOTE ]-»-cadr [ f orm]; 
eq[car[form] ;COND]-*-evcon[cdr[form] ;a]; 
eq[car[form] ;PROG]-*-prog[cdr[form] ;a]; 

atom[ car [form] ]-*[get [ car [ form]; EXPR]->-apply [ expr; ^evlis [ cdr [ form]; a]; a]; 



[TSX subr,^4 

^AC:=cdr[form]; | 

get[car[form] ;FSUBR]-*-jMQ:=$ALIST:=a; p 5 

|TSX fsubr, 1 4 J 


T-*eval[cons[cdr[sassoc[car[form] ;a;X[ [] ;error[A9] ] ] ]; 


T->-apply[ car [form]; evils [cdr [form] ;a] ;a] ] 
evcon (c; a] = [null [ c]-»-error [ A3 ]; 

eval[caar[c] ;a]-»-eval[cadar[c] ;a]; 

T-*evcon[cdr[c]; a] ] 

evlislmjaJ^maplisttn^Xt [j ] ;eval[car[j] ;a] ] ] 

The PROG Feature 

The PROG feature is an FSUBR coded into the system. It can best be 
explained in English, although it is possible to define it by using M-expressions. 

1. As soon as the PROG feature is entered, the list of program variables 
is used to make a new list in which each one is paired with NIL. This is then 
appended to the current a-list. Thus each program variable is set to NIL 
at the entrance to the program. 

1. The value of get is set aside. This is the meaning of the apparent free 
or undefined variable. 

IV - 13 

2. 'Che remainder of the program is searched for atomic symbols 
that are understood to bo location symbols. A go-list is formed in which 
each location symbol is paired with a pointer into the remainder of the 

3. When a set or a setq is encountered, the name of the variable is 
located on the a-list. The value of the variable (or edr of the pair) is 
actually replaced with the new value. 

If the variable is bound several times on the a-list, only the first 
or most recent occurrence is changed. J.f the current binding of the 
variable is at a higher level then the entrance to the prog , then the change 
will remain in effect throughout the scope of that binding, and the old 
f value will be lost. 

If the variable does not occur on the a-list, then an error diagnostic 
will occur. 

4. When a re turn is encountered at any point, its argument is 
evaluated and returned as the value of the most recent prog that has been 

5. The form £0 may be used only in two ways. 

a. (GO X) may occur on the top level of the prog , x must be a 
location symbol of this pro g and not another one on a higher or lower level. 

b. This form may also occur as one of the value parts of a 
conditional expression, if this conditional expression occurs on the top 
level of the prog . 

If a go is used incorrectly or refers to a nonexistent location, an 
error diagnostic will occur. 

IV - 14 


6. When the form cond occurs on the top level of a prog , it differs 
from other conds in the following ways. 

a. It is the only instance in which a go can occur inside a cond. 

b. If the cpnd runs out of clauses, an error diagnostic will no 
occur. Instead, the pro g will continue with the next statement. 

7. When a statement is executed, this has the following meaning, with 
the exception of the special foras cond , go, retu rn, setq and the pseudo- 
function set , all of which are peculiar to prog . 

The statement £ is executed by performing eval[s;a], where a is the 
current a-list, and then ignoring the value. 

8. If a prog runs out of statements, its value is NIL. 

Defining Functions and Functions Useful for Property Lists 
d efine [x] : SUBR pseudo-function 

The argument of define , x, is a list of pairs 

((u lV - Vn” 

where each u is a name and each v is a A-expression for a function. For 
each pair, define puts an EXPR on the property list for u pointing to v. 

The function of define puts things on at the front of the property list. 

The value of define is the list of u's. 
define[x] = deflist[x;EXPR] 

deflist[x;ind] : SUBR pseudo-function 

The function deflist is a more general defining function. Its first 
argument is a list of pairs as for define . Its second argument is the indicator 
that is to be used. After deflist has been executed with (u^v^) amoung its 
first argument, the property list of u i will begin: 





If deflist or define is used twice on the same object with the 
same indicator, the old value will be replaced by the new one. 
attrib [x;e] : SUBR pseudo-function 

The function attrib concatenates its two arguments by changing the 
last element of its first argument to point to the second argument. Thus 
it is commonly used to tack something onto the end of a property, list. The 
value of attrib is the second argument. 

For example 

attrib [FF; (EXPR (LAMBDA (X) (COND ((ATOM.X) X) (T (FF (CAR X))))))] 
would put EXPR followed by the LAMDBA expression for FF onto the end of 
the property list for FF. 

prop [x;y;u] : SUBR functional 

The function prop searches the list x for an item that is e^ to y. 

If such an element is found, the value of prop is the rest of the list 
beginning immediately after the element. Otherwise the value is u[], where 
u is a function of no arguments. 

prop[x;y;u] = [null[x] -*■ u[];eq[car[x];y]+cdr[x]; 

T -»-prop[cdr[x];y;u]] 

I£t[x;y] : SUBR 

get is somewhat like prop ; however its value is car of the rest of 
the list if the indicator is found, and NIL otherwise. 

get[x;y[ = [mill[x] -> NII,;eq[car[x] ;y] -> cadr[x]; 

T •> get[cdr[x];y]] 

cset [ob;val] : SUBR pseudo-function 

This pseudo-function is used to create a constant by putting 
the indicator APVAL and a value on the property list of an atomic 
symbol. The first argument should be an atomic symbol; the second 
argument is the value to be placed on that atomic symbol’s p-list. 

The value of cset is the value of cons[val,NIL]. 
csetq [ob;val] : FSUBR pseudo-function 

csetq is like cset except that it quotes its first argument 
instead of evaluating it. 

remprop [x;ind] : SUBR pseudo-function 

The pseudo-function re mprop searches the list, x, looking for all 
occurrences of the indicator ind. When such an indicator is found, its 
name and the succeeding property are removed from the list. The two 
"ends" of the list are tied together as indicated by the dashed line 


The value of remprop is NIL. 

When an indicator appears on a property list without a property following 
it, then it is called a flag. An example of a flag is the indicator TRACE 
which informs the interpreter that the function on whose property list it 
appears is to be traced. There are two pseudo-functions for creating and 
removing flags respectively. 

flag[£;ind] : SUBR . pseudo-function 

The pseudo-function flag puts the flag ind on the property list of 
every atomic symbol in the list Z. Note that Z cannot be an atomic symbol, 
and must be a list of atomic symbols. The flag is always placed immediately 
following the first word of the property list, and the rest of the property 
list then follows. The value of flag is NIL. No property list ever 
receives a duplicated flag. 

remflag [l;ind] : SUBR pseudo-function 

remflag removes all occurrences of the indicator ind from the property 
list of etch atomic symbol in the list Z. It does this by patching around 
the indicator with a rplacd in a manner similar to the way remprop works. 
Table Building and Table Reference Functions 
pair [x;y] : SUBR 

The function pair has as value the list of pairs of corresponding 
elements of the lists x and y. The arguments x and y must be lists of the 
same number of elements. They should not be atomic symbols. The value is 
a dotted pair list, i.e. ((a ^ (« 2 • B 2 ) 

pairfxjy] = [prog[u;v;m] 

u:= x; 
v:= y; 

A [null[u] -* [null[v] ■+ return[m];T -* error[F2]]]; 

[null[v] error[F3]]; 

m:= cons[cons[car[u];car[v]];m ]; 

u:= cdr[u]; 

v:= cdr[v]; 


IV - 18 

sassoc[x;y;u] : SUM functional 

The function sassoc searches y, which is a list of dotted pairs, 
for a pair whose first element that is x. If such a pair is found, the 
value of sassoc is this pair. Otherwise the function u of no arguments 
is taken as the value of sassoc . 

sassoc[x;y;u] = [null[y] u[];eq[caarfy];x] -*■ car[y]; 

T sassocfx;cdr[y];u]] 

subst [x;y;z] : SUBR 

The function suhst has as value the result of substituting x for all 
occurrences of the S-expression y in the S-cxpression z. 

subst.[x;y;z] = [equal[y;z] -> x; 

atom[z] -*• z; 

T -»• cons[subst[x;y;car[z]];subst[x;y;cdr[z]]]] 

sublis [x;y] : SUBR 

Here x is a list of pairs. 

C( u l • vp (u 2 



v )) 
n J J 

The value of sublis [x;y] is the result of substituting each v for 
the corresponding u in y. 

sublis[x;y] = [null[x] -»■ y; 

null[y] y; 

T ■+ search [x; 

Mf. j ]; equal [y; caar[ j] ] ]; 


*[[j]l[atom[y] -► y; 

T cons [sublis[x;car[y] ];sublis[x;cdr[y] ]]]]]] 

List Handling Functions 
append [x;y] : 


The function append combines its two arguments into one new list. 
The value of append is the resultant list. For example, 
append [(A B) (C) ] = (A B C) 
append[((A)) (C D)] = ((A) C D) 

append[x;y] = [null[x] y; T -*■ cons[car[x];append[cdr[x];y]]] 

Note that append copies the top level of the first list; append is like 
nconc except that nconc does not copy its first argument. 
cone t x 2 >X-n>». ■ >x^1 : FSUBR pseudo-function 

c°nc concatenates its arguments by stringing them all together on 
the top level. For example, 

cone [ (A (B • C) D); (F); (G H) ] = (A (B • C) D F G H). 
cone concatenates its arguments without copying them. Thus it 
changes existing list structure and is a pseudo-function. The value of 
cone is the resulting concatenated list. 
nconc [x;y] : SUBR pseudo-function 

The function nconc concatenates its arguments without copying the 
first one. The operation is identical to that of attrjb except that the 
value is the entire result, (i.e. the modified first argument, x). 

The program for nconc[x;y] has the program variable m and is as 

nconc[x;y] = prog[[m]; 

£null[x] -*■ return[y]]; 

A [null[cdr[m]] •+• go[B]]; 

B rplacd[m;y]; 

copy [x] : SUBR 

This function makes a copy of the list x. The value of copy 
is the location of the copied list. 

copy[x] = [null[x] ■+• NIL;atom[x] x;T -*■ cons[copy[car[x]]; 

reverse [-2] : SUBR 

This is a function to reverse the top level of a list. Thus 

reverse[(A B (C • D))] = ((C • D) B A)) 

reverse[£] = prog[[v]; 

A [null[u] -* return[v]]; 
to [A]] 

member [x;£] : SUBR predicate 

If the S-expression x is a member of the list £, then the value of 
member is *T*. Otherwise, the value is NIL. 

member[x;£.] = [null[£] -»■ F;equal[x;car[£]] ■** T; 

T member [x; cdr [-t]]] 

length [x] : SUBR 

The value of length is the number of items in the list x. The list 

( ) or NIL has length 0. 

IV - 21 

efface[x;£] : SUBR pseudo-function 

The function efface deletes the first appearance of the item x 

from the list £. 

efface[x;£] = [null[£] -*■ NIL; 

equal [x;car[£]] -*• cdr[£]; 

T -*■ rplacd[£;efface[x;cdr[£]]]] 

These four functionals apply a function, f, to x, then to cdr[x], 
then to cddr[x], etc. 

Functionals or Functions with Functions as Arguments 
maplist [x;f] : SUBR functional 

The function maplist is a mapping of the list x onto a new list f[x]. 
maplist[x;f] = [null[x] NIL;T cons [f [x] ;maplist[cdr[x] ;f]] ] 
mapcon [x;f] : SUBR pseudo-functional 

The function mapcon is like the function maplist except that the 
resultant list is a concatenated one instead of having been created by 
cons- ing. 

mapcon[x;f] = [null[x] NIL;T -*■ nconc[f [x] ;mapcon[cdr[x] ;f]] ] 
ma£[x;f] : SUBR functional 

The function ma£ is like the function maplist except that the value 
°f ma£ is NIL, and ma£ does not do a cons of the evaluated functions. 
map is used only when the action of doing f[x] is important. 

The program for map[x;f] has the program variable m and is the 


map[x;f] = prog[[m]; 
m: = x; 

LOOP [null [m] -*■ return[NIL] ]; 


m:= cdr[m]; 


search [x;p;f;u] : SUBR functional 

The function search looks through a list x for an element that has 
the property p, and if such an element is found the function f of that 
element is the value of search . If there is no such element, the function 
u of one argument x is taken as the value of search (in this case x is, 
of course, NIL). 

search[x;p;f;u] = [null[x] -*• u[x];p[x] -*■ f[x];T -*■ search[cdr[x];p;f;u]] 
Arithmetic Functions 

We shall now list all of the arithmetic functions in the System. They 
must be given numbers as arguments; otherwise an error condition will result 
The arguments may be any type of number. A function may be given some 
fixed-point arguments and some floating-poing arguments at the same time. 

If all of the arguments for a function are fixed-point numbers, then 
the value will be a fixed-point number. If at least one argument is a 
floating-point number, then the value of the function will be a floating¬ 
point number. 

plus [x^;...;x^j is a function of any number of arguments whose value 
is the algebraic sum of the arguments. 

difference [x;yj has for its value the algebraic difference of its 

minus[x] has for its value -x. 

IV - 23 

times [x.^;... ;x^] is a function of any number of arguments, whose 
value is the product (with correct sign) of its arguments. 

addl[x] has x+1 for its value. The value is fixed-point or floating¬ 
point, depending on the argument. 

subl [x] has x-1 for its value. The value is fixed-point or floating¬ 
point, depending on the argument. 

max i^;... ;x n ] chooses the largest of its arguments of its value. 

Note that max[3;2.0]= 3.0. 

min tx^...;x^] chooses the smallest of its arguments for its value. 

recip [x] computes 1/x. The reciprocal of any fixed point number is 
defined as zero. 

quotient [x;y] computes the quotient of its arguments. For fixed- 
point arguments, the value is the number theoretic quotient. A divide 
check or floating-point trap will result in a LISP error. 

remainder [x;y] computes the number theoretic remainder for fixed- 
point numbers, and the floating-point residue for floating-point arguments. 

divide [x;y] = cons[quotient[x;y]; cons [remainder[x;y];NIL]] 

expt [x;y] = x^. If both x and y are fixed-point numbers, this is 
computed by iterative multiplication. Otherwise the power is computed by 
using logarithms. The first argument cannot be negative. 

We shall now list all of the arithmetic predicates in the System. 

They may have fixed-point and floating-point arguments mixed freely. The 
value of a predicate is *T* or NIL. 

lessp [x;y] is true if x <y, and false otherwise. 

greaterp [x;y] is true if x > y. 

zerop [x] is true if x=0, or if |x| < 3 x 10 

onep [x] is true if j x-11 < 3 x 10 

minusp [x] is true if x is negative. 

numbergi [x] is true if x is a number (fixed-point or floating-point). 

fixp [x] is true only if x is a fixed-point number. If x is not a 
number at all, an error will result. 

floatp [x] is similar to fixp[x] but for floating-point numbers. 

equal [x;y] works on any arguments including S-expressions incorporating 
numbers inside them. Its value is true if the arguments are identical. 
Floating-point numbers must satisfy |x-y| < 3 x 10 . 

The logical functions operate on 32 bit words. The only acceptable 
arguments are fixed-point numbers. These may be read in as hexadecimal 
or decimal integers, or they may be the result of a previous computation. 

logor[x^;...;x n J performs a logical OR on its arguments. 

logand [x^;. ..;x r ] performs a logical AND on its arguments. 

logxortXjj...; x r ] performs an exclusive OR 

(0 v 0 = 0 , 1 v 0 = 0 v 1 = 1, 1 v. 1 = 0). 

leftshift [x;n] = x X 2 n . The first argument is shifted left by the 
number of bits specified by the second argument. If the second argument is 
negative, the first argument will be shifted right. , 

If the first argument is logical, a logical shift is done and the result 

is logical. If the first argument is fixed-point, an arithmetic shift is 
done and the result is fixed-point. If the first argument is floating¬ 
point, a floating shift is done and the result is floating-point, 
array [arg] • SUBR pseudo-function 

Provision is made in LISP 1.5 for allocating blocks or storage for data. 
The data may consist of numbers, atomic symbols or other S-expressions. 

The pseudo-function array reserves space for arrays, and turns the 
name of an array into a function that can be used to fill the array or locate 

any element of it. 

IV - 25 

Arrays may have up to three indices. Each element (uniquely specified 
by its co-ordinates) contains a pointer to an S-expression. 

array is a function of one argument which is a list of arrays to be 
declared. Each item is a list containing the name of an array, its 
dimensions, and the word LIST. (Non-list arrays are reserved for future 
developments of the LISP system.) 

For example, to make an array called alpha of size 7 x 10, and one 
called beta of size 3x4x5 one should execute: 

array[((ALPHA (7 10) LIST) (BETA (3 4 5) LIST))] 

After this has been executed, both arrays exist and their elements 
are all set to NIL. Indices range from 0 to n-1. 

alpha and beta are now functions that can be used to set or locate 

elements of these respective arrays. 

To set alpha . . to x, execute - 

To set alpha 3 4 to (A B C) execute - 
alpha[SET;(A B C);3;4] 

Inside a function or program X might be bound to (A B C), I bound to 3, 
and J bound to 4, in which case the setting can be done by evaluating - 

To locate an element of an array, use the array name as a function 
with the coordinates as axis. Thus any time after executing the previous 
example - 

alpha[3;4] = (ABC) 

IV - 26 

Arrays are stored as lists originating in the property list of 
the array name. Indexing is accomplished by a linear search for the 
n** 1 element of the array list. 

Input and Output 

rea< * [ ] : SUBR pseudo-function 

The execution of read causes one list to be read from the SI device. 
The list that is read is the value of read . 
print [x] : SUBR pseudo-function 

The execution of print causes the S-expression x to be printed on 
the LO device. The value of print is its argument. 
punch [x] : SUBR pseudo-function 

The execution of punch causes S-expression x to be punched in BCD 
card images on the PO device. The value of punch is its argument. 
prinl [x] : SUBR pseudo-function 

prinl prints an atomic symbol without terminating the print line. 

The argument of prinl must be an atomic symbol. 
terpri [ ] : SUBR pseudo-function 

terpri terminates the print line. 
mprint [x i] : SUBR pseudo-function 

The execution of mprint causes the S-expression x to be written 
in 80 character records on device F:i. The F: device must be assigned to 
a physical device by an !ASSIGN control card preceeding the I LISP control 
card. The value of mprint is the list printed. 

1 < i < 5 

inread [i] 



The execution of mread causes one S-expression to be read from 
the F:i device. The value of mread is the S-expression read. 

1 <_ i <_ 5 . 

rewind[i] : SUBR pseudo-function 

rewind [i] rewinds the F:i device. 

The value of rewind is NIL. 

1 <_ i <_ 5 

backspace [i] : SUBR pseudo-function 

The execution of backspace causes the F:i device to be backspaced 
one record. Caution in the use of this function is recommended, for if 
an S-expression to be read from an F: device is more than 80 characters, 
then it will occupy more than one record on the F: device, and a single 
backspace will not move the device all the way back to the beginning of 
the S-expression. The value of backspace is NIL, 

1 i i £ 5 . 

Packing and Unpacking Characters 

When a sequence of characters is to be made into either a print 
name or a numerical object, the characters must be put one by one into a 
buffer called BOFFO. BOFFO is. used to store the characters until they 
are to be combined. It is not available explicitly to the LISP programmer, 
but the character-packing functions are described in terms of theip effects 
on BOFFO. At any point, BOFFO contains a sequence of characters. Each 
operation on BOFFO either adds another character at the end of the sequence 
or clears BOFFO, i.e., sets BOFFO to the null sequence. The maximum length 
of the sequence is 120 characters; an attempt to add more characters will 

cause an error. 

The character-packing- functions arc: 
pack [c] : SUBR pseudo-function 

The argument of pack must be a character object, pack adds the 
character c at the end of the sequence of characters in BOFFO. The 
value of pack is NIL. 

clearbuff [ ] : SUBR pseudo-function 

clearbuff is a function of no arguments. It clears BOFFO and has 
value NIL. The contents of BUFFO are undefined until a clearbuff has been 

mknam [ ] : SUBR pseudo-function 

mknam is a function of no arguments. Its value is a list of full 
words containing the characters in BOFFO in packed BCD form. The last word 
is filled out with blanks if necessary. After mknam is performed, BOFFO ; 
is automatically cleared. Note that intern [mknam[ ]] yields the object 
whose print name is in BOFFO. 

numob [ ] : SUBR pseudo-function 

numob is a function of no arguments. Its value is the numerical object 
represented by the sequence of characters in BOFFO. (Positive decimal integers 
from 0 to 9 are converted so as to point to the corresponding character object.) 

unpack [x]: : SUBR pseudo-function 

This function has as argument a pointer to a full word, unpack considers 
the full word to be a set of 4 BCD characters, and has as value a list of 
these characters ignoring all characters including and following the first 


intern [pname] : SUBR pseud-function 

This function has as argument a pointer to a PNAME type structure 
such as 

Its value is the atomic symbol having this print name. If it does 
not already exist, then a new atomic symbol will be created. 

The Character-Classifying Predicates 

liter[c]: : SUBR predicate 

liter has as argument a character object. Its value is T if the 
character is a letter of the alphabet, and F otherwise. 
digit [c]: : SUBR predicate 

digit has as argument a character object. Its value is T if the 
character is a digit between 0 and 9, and F otherwise. 
opchar fc]: : SUBR predicate 

opchar has as argument a character object. Its value is T if the 
character is +, -,•■/, *, or =, and F otherwise. 
dash [c]: : SUBR predicate 

dash has as argument a character object. Its value is T if the character 
is an 11-punch minus, and F otherwise. 

The Character-Reading Functions 

The character-reading functions make it possible to read characters 
one by one from input. 

There is an object CURCHAR whose value is the character most recently 
read (as an object). There is also an object CHARCOUNT whose value is an 
integer object given the column just read on the card, i.e., the column 
number of the character given by CURCHAR. There are three functions which 
affect the value of CURCHAR: 

startread [ ]: : SUBR pseudo-function 

startread is a function of no arguments which causes a new card to be 
read. The value of startread is the first character on that card, or more 
precisely, the object corresponding to the first character on the card. If 
and end-of-file condition exists, the value of startread is $EOF$. The value 
of CURCHAR becomes the same as the output of startread , and the value of 
CHARCOUNT becomes 1. Both CURCHAR and CHARCOUNT are undefined until a 
startread is performed. A startread may be performed before the current 
card has been completely read. 

advance[ ]: : SUBR pseudo-function 

advance is a function of no arguments which causes the next character to 
be read. The value of advance is that character. After the 72 n< * character 
on the card has been read, the next advance will have value $EOR$. After 
reading $EOR$, the next advance will act like a startread , i.e., will read 
the first character of the next card unless an end-of-file condition exists. 
Hie new value of CURCHAR is the same as the output of advance ; executing 
advance also increases the value of CHARCOUNT by 1. However, CHARCOUNT is 

undefined when CURCHAR is either $EOR$ or $EOF$. 

endread[ ]: 



endread is a function of no arguments which causes the remainder of 
the card to be read and ignored, endread sets CURCHAR to $EOR$ and leaves 
CHARCOUNT undefined; the value of endread is always $EOR$. An advance 
following endread acts like a startread . If CURCHAR already has value 
$EOR$ and endread is performed, CURCHAR will remain the same and endread 
will, as usual, have value $EOR$. 

Diagnostic Function 

errorl [ ]: : SUBR pseudo-function 

error1 is a function of no arguments and has value NIL. It should be 
executed only while reading characters from a card (or tape]). Its effect 
is to mark the character just read, i.e., CURCHAR, so that when the end 
of the card is reached, either by successive advances or by an endread , 
the entire card is printed out along with a visual pointer to the defective 
character. For a line consisting of ABCDEFG followed by blanks, a pointer 
to C would look like this: 




If errorl is performed an even number of times on the same character, the 
A will not appear. If errorl is performed before the first startread or 
while CURCHAR has value $EOR$ or $EOF$, it will have no effect. Executing 
a startread before the current card has been completed will cause the 
errorl printout to be lost. The card is considered to have been completed 
when CURCHAR has been set to $EOR$. Successive endreads will cause the 
errorl printout to be reprinted. Any number of characters in a given 

line may be marked by errorl . 

Miscellaneous Functions 

trace [x] : SUBR pseudo-function 

The argument of trace is a list of functions. After trace has 
been executed, the arguments and values of these functions are printed 
each time the function is entered recursively. The value of trace is 
NIL. Special forms cannot be traced. 
untrace [x] : SUBR pseudo-function 

This removes the tracing from all functions in the list x. The value 
of untrace is NIL. 

obkeep [s] : SUBR pseudo-function 

The argument of obkeep is a list of atom names which the programmer 
wishes to keep. All other atomic symbols are removed from the system. The 
value of obkeep is NIL. 

reserved [ ] : SUBR pseudo-function 

The execution of reserved causes the printing of all atoms on the 
object list. The value of reserved is NIL. 
space [x] : SUBR pseudo-function 

space[*T*] causes all output to be double-spaced, space [NIL] restores 
the spacing to its original status. The value of space is NIL. 
eject [ ] : SUBR pseudo-function 

eject [ ] causes a skip to the top of the next page of output. Its 
value is NIL. 

verbos [x] : SUBR pseudo-function 

verbos [NIL] causes reclaim not to print its message whenever it is 
called, verbos[*T*] restores reclaim's message. Its value is NIL. 

count [n] 



count [n] turns the cons counter on and resets, the .counter. After 
n conses have been executed, a cons counter trap occurs, count [NIL] 
turns the counter on so as to continue counting from the state it was 
in when last turned off. The value of count is NIL. 
uncount [NIL] : SUBR pseudo-function 

uncount [NIL] turns off the cons counter. Its value is NIL. 
speak [NIL] : SUBR pseudo-function 

The value of speak [NIL] is the number of conses counted since the 
counter was last reset. 

error [x] : SUBR pseudo-function 

error causes an error diagnostic to be printed along with the 
S-expression x. The value of error is x. 
prog2 [x;y] : SUBR 

the value of prog2 is its second argument. It is used mainly to 
perform two pseudo-functions. 
prog2[x;y] = y 

cpl[x] : SUBR 

cpl copies its argument which must be a list of a very special type. 



The copied list is the value of cpl . 

IV - 34 

gensym [ ] : SUBR 

The function gensym has no arguments. Its value is a new, distinct, 
and freshly created atomic symbol with a print name of the form G001, 

G002, ..., G999. 

This function is useful for creating atomic symbol when one is 
needed; each one is guaranteed unique, gensym names are not permanent 
and will not be recognized if read back in. 

££lect[q;(q 1 e 1 );(q 2 e 2 );...;(q n e n );e] : FSUBR 

The q^'s in select are evaluated in sequence from left to right until 
one is found that 

<\ ± = q> 

and the value of select is the value of the corresponding e.. If no such ... 


q^ is found the value of select is that of e. 

tempus [ ] : SUBR pseudo-function 

Executing this will cause a time statement to appear in the output. 

The value is NIL. 

reclaim [ ] : SUBR pseudo-function 

Executing this will cause a garbage collection to occur. The value 
is NIL. 

pause [ ] : SUBR pseudo-function 

pause [ ] is a no operation function. Its value is NIL. 
dump [low;high;title] : SUBR pseudo-function 

The first two arguments must be absolute hexadecimal addresses. . 
dump causes memory to be dumped in hexadecimal from location low to 
location high . The value of dump is NIL. 

intern[x] : SUBR pseudo-function 

The argument of intern must be a PNAME type of structure, that is, 
a list of full words forming a print name. If this print name belongs 
to an already existing atomic symbol, this is found, otherwise a new 
one is created. The value of intern in either case is an atomic symbol 
having the specified print name. 
remob [x] : SUBR 

This removes the atom x from the object list. It causes the symbol 
and all its properties to be lost unless the symbol is referred t° by 
active list structure. When an atomic symbol has been removed, subsequent 
reading of its name from input will create a different atomic symbol. Its 
value is NIL. 

traceset[x] : EXPR pseudo-function 

traceset is a debugging aid. The argument x should be a list of 
functions names. Each of these functions must be an EXPR which has a PROG 
on the top level, traceset modifies the definition of the function so 
that every SETQ on the first level inside the PROG is traced. 

For example, suppose a PROG has the statement (SETQ A X). At run 
time, if this statement is executed while X has the value (U V), then in 
addition to setting the variable A, the function will print out. 

(A =) 

(U V) 

untraceset [x] is part of the traceset package. Its argument is a list of 
functions whose definitions are to be restored to their original condition. 

IV - 36 

printprop [x] : EXPR pseudo-function 

If x is an atomic symbol, all of its properties will be printed in 
the output. Nothing is changed by printprop . 
punchdef [x] : EXPR pseudo-function 

If x is a list of atomic symbols, each one having an EXPR or FEXPR 
will have its definition punched out. Nothing is changed. 





















(BCD blank) 

(character count during reading of characters) 

(current character during reading of characters) 










★•j 1 * 


5.1 The LISP Program 

A program for execution in LISP consists of a sequence of 
doublets. . The first list or atomic symbol of each doublet is in¬ 
terpreted as a function. Hie second is a list of arguments for the 
function. They are evaluated by evalquote , and the value is printed. 

The program should be terminated by the atomic symbol STOP. There is 
no particular card format for writing LISP. Card boundaries are 

ignored. ' , 

* s » ' ‘ 

If ! tfie liser? requires input data for his LISP <program, this d'ata 

. i ' ’ 

should begi^on the next cqjrd. immediately j^ftei^ the 9 ard witty the 

° ■ * * . • ■ 1 I j 

STOP atomic ^s^inbol. The end of data,should*be indicated by ( eit!hei“ a 

i : i ; . i 1 j | 1 ’ 

\ ! j \ ! , 

!EOp or a !I*IN carijl. ! 1 ’’ 

5.2 Tape Operations 


The functions rewind , mprint , mread, 'and backspace are designed 
to allow the user access to tape and other physical devices. Specifically, 
they use the user DCB's F:l, F:2, F:3, F:4, and F:5. If used, the F: 

devices must be assigned by IASSIGN control cards preceeding the !LISP 


control card. * 

5.3 System Messages ' 

Translation Phase 

When the translation phase is initiated, the following message appears 
as the heading. 

* LISP 1.5 





Following this message is the source listing. Errors encountered 
during the translation phase are discussed under Input/Output error 
messages. Normally, an error in the translation phase will cause the 
interpreter to be bypassed. In this case, the following message 
would be found. 

Interpreter Phase 

The interpreter phase is begun by: 


When the interpreter is entered, it prints: 

followed by the two arguments to evalquote . 

At completion of the interpretation of a doublet, evalquote prints: 
followed by the value. 

When the interpreter phase is. completed: 

Garbage Collector 

When the garbage collector is called, it prints the following; 

where m is the number of free words collected, and n is the number of 
full words collected. 

Error Diagnostics 

When an error occurs, a diagnostic giving the nature of the error is 
printed out. The diagnostic gives the type of error and in some cases 

additional information about the error. If the DB option was specified, 
then a backtrace is also printed. This is a list of functions that were 
entered recursively but not completed at the time of the error. 

In most cases, the program continues with the next doublet if in 
debug mode. If not in debug mode, control is returned to the monitor. 
Certain errors are fatal, and control is always passed to the monitor. 
Interpreter Errors: 


This occurs when an atomic symbol, given as the first argument 
to apply , does not have a definition either on its property list or on 
the a-list of apply . The atomic symbol immediately following the 
diagnostic is the undefined symbol. 


Eval expects the first object on a list to be evaluated to be an 
atomic symbol. This frequently occurs when a parenthesis miscount causes 
the wrong phase to be evaluated. The undefined symbol is printed. 


A function expecting a fixed number of arguments was passed the 
wrong number of arguments. 


The atomic symbol in question is not bound on the a-list for eval 
nor does it have an APVAL. The undefined symbol is printed. 


None of the propositions following COND are true. 


Go refers to a point not labelled. 


Either set or setq is attempted on a nonexistent program variable. 
The undefined symbol is printed. 

Character-Handling Errors: 


Miscellaneous Errors: 



Pair is used by the interpreter to bind variables to arguments. 

If a function is given the wrong number of arguments, this error may 


The push-down stack is the memory device that keeps track of the 
level of recursion. When recursion becomes very deep, this error may 
occur. Non-terminating recursion will cause this error. 

Garbage Collector Errors: 


This error occurs only when the system is so choked that it cannot 
be restored. Control goes to the monitor. 

Arithmetic Errors: 


First argument cannot be negative. 


Input - Output Errors: 



This error occurs when the read program encounters a character 
such as a ")" or out of context. This occurs frequently when there 
is a parenthesis miscount. 


The dot-notation was not used properly. 



5.4 Control Card Options 

The options listed below may be specified on the !LISP control 


DB - debug - After any error, a backtrace is given. Then execution 
is continued with the next doublet. 

NODB - no debug, default - After an error, the execution is terminated 
and control is returned to the monitor. 

LS - list source, default 

NOLS - no list source 

GO - Begin execution of the first doublet even if translation phase 
errors occur. 

NOGO - No execution phase. 

If neither GO nor NOGO is specified, then the execution phase 
will begin if no translation phase errors occur. 


An interpretive system capable of translating the prograpning 
language LISP 1.5 has been successfully implemented on the SDS SIGMA 7. 
There are no restrictions to the language in this implementation. The 
mathematical language LISP, with sufficient extensions to make it useful 
in a programming environment, is now accessible to SIGMA 7 users. The 
language's primary use has been in the field of artificial intelligence 
research. It has been used for symbolic calculations in calculus, 
mathematical logic, game playing, and other fields of artificial intelli¬ 
gence. It has also been useful in further understanding of information 
structures in general. It is hoped that the implementation of LISP on 
the SIGMA 7 might allow more people access to the language, so that its 
study and use might prove more profitable. 

In the future, the present implementation will be expanded to 
include a compiler, assembler, and loader. The compiler may be called 
by the user to translate any function from LISP into machine language. 

When this is done, the function should be much faster in execution speed, 
for the interpreter will link the source arguments to the compiled function 
rather than execute it interpretively. The assembler and loader will allow 
the LISP user to include assembly language subroutines which he himself has 
written. These additions should improve the speed of the LISP system as 
well as add to its flexibility. 


The functions 

that are marked by an asterisk are 


functions or 

functions that are 

different from the functions with ■ 

the : 

same name in 

M.I.T. 7090 LISP 1, 

.5. See Section 4.2 for details on