LISP REFERENCE MANUAL
by Eric Norman and Rick LeFaivre


This is a reference manual for LISP as implemented for the Univac 1100 series of computers at the Madison Academic Computing Center.

This manual gives details on the facilities and usage of 1100 LISP. Familiarity with LISP is assumed. Either via usage of LISP on a different machine or that gained from the LISP Primer, which is also available from MACC.


TABLE OF CONTENTS
1.0 INTRODUCTION  . . . . . . . . . . . . . . . . . . 1-1

2.0 THE UNIVERSE OF DISCOURSE . . . . . . . . . . . . 2-1 
    2.1 ATOMIC OBJECTS  . . . . . . . . . . . . . . . 2-1 
        2.1.1 Numbers . . . . . . . . . . . . . . . . 2-1 
        2.1.2 Atomic Symbols  . . . . . . . . . . . . 2-2 
        2.1.3 Strings . . . . . . . . . . . . . . . . 2-2 
        2.1.4 Truth Values  . . . . . . . . . . . . . 2-2 
        2.1.5 Functions . . . . . . . . . . . . . . . 2-3 
    2.2 COMPOSITE OBJECTS . . . . . . . . . . . . . . 2-3 
        2.2.1 Lists . . . . . . . . . . . . . . . . . 2-3 

3.0 BASIC FUNCTIONS . . . . . . . . . . . . . . . . . 3-1 
    3.1 EVALUATION  . . . . . . . . . . . . . . . . . 3-1 
    3.2 BASIC FUNCTIONS . . . . . . . . . . . . . . . 3-2 
        3.2.1 Symbol Manipulating Functions . . . . . 3-2 
        3.2.2 Arithmetic Functions  . . . . . . . . . 3-8 
    3.3 SPECIAL-FORMS . . . . . . . . . . . . . . . . 3-10

4.0 IMPLEMENTATION  . . . . . . . . . . . . . . . . . 4-1
    4.1 MEMORY ORGANIZATION . . . . . . . . . . . . . 4-1 
    4.2 EVALUATION  . . . . . . . . . . . . . . . . . 4-3 

5.0 USING THE 1100 LISP SYSTEM  . . . . . . . . . . . 5-1 
    5.1 THE LISP SUPERVISOR . . . . . . . . . . . . . 5-1 
    5.2 OUTPUT CONVENTIONS  . . . . . . . . . . . . . 5-2 
        5.2.1 The Backtrace . . . . . . . . . . . . . 5-3 
    5.3 CONTROL STATEMENTS  . . . . . . . . . . . . . 5-4 
    5.4 CONTROL FUNCTIONS . . . . . . . . . . . . . . 5-6 
    5.5 DIAGNOSTICS . . . . . . . . . . . . . . . . . 5-9
    5.6 STOPPING A RUNAWAY LISP SYSTEM  . . . . . . . 5-12
    5.7 THE LISP LIBRARY  . . . . . . . . . . . . . . 5-12

6.0 INPUT-OUTPUT  . . . . . . . . . . . . . . . . . . 6-1
    6.1 INPUT . . . . . . . . . . . . . . . . . . . . 6-1 
    6.2 OUTPUT  . . . . . . . . . . . . . . . . . . . 6-3 
    6.3 NON-LISP PARSING  . . . . . . . . . . . . . . 6-5 
    6.4 DUMP-LOAD . . . . . . . . . . . . . . . . . . 6-7 

7.0 DEBUGGING LISP PROGRAMS . . . . . . . . . . . . . 7-1 
    7.1 $TRACE  . . . . . . . . . . . . . . . . . . . 7-1 
    7.2 $BREAK  . . . . . . . . . . . . . . . . . . . 7-3 
    7.3 $TRACEV . . . . . . . . . . . . . . . . . . . 7-4 
    7.4 $UNBUG  . . . . . . . . . . . . . . . . . . . 7-5 
    7.5 $BRKPT  . . . . . . . . . . . . . . . . . . . 7-5 
    7.6 Miscellaneous . . . . . . . . . . . . . . . . 7-5 

8.0 THE LISP EDITOR . . . . . . . . . . . . . . . . . 8-1 

9.0 THE LISP PRETTYPRINTER  . . . . . . . . . . . . . 9-1 

10.0 THE LISP COMPILER  . . . . . . . . . . . . . . . 10-1
     10.1 USING THE COMPILER  . . . . . . . . . . . . 10-1
     10.2 FREE VARIABLES  . . . . . . . . . . . . . . 10-2
     10.3 SPECIAL-FORMS . . . . . . . . . . . . . . . 10-3
     10.4 MACROS  . . . . . . . . . . . . . . . . . . 10-4
     10.5 Miscellaneous . . . . . . . . . . . . . . . 10-4
          10.5.1 Usage of GROW  . . . . . . . . . . . 10-4
          10.5.2 MANIFEST . . . . . . . . . . . . . . 10-4
          10.5.3 EXCISE . . . . . . . . . . . . . . . 10-4
          10.5.4 Listing  . . . . . . . . . . . . . . 10-5
          10.5.5 Functions for the Compiler . . . . . 10-5

11.0 PROPERTY LISTS . . . . . . . . . . . . . . . . . 11-1

12.0 FUNCTIONS  . . . . . . . . . . . . . . . . . . . 12-1

APPENDIX A (Index)  . . . . . . . . . . . . . . . . . A-1



Chapter 1
INTRODUCTION

This reference manual is designed for users of the 1100 LISP system implemented at the Madison Academic Computing Center.

The intent is to mainly give details of the facilities and usage of 1100 LISP instead of to teach LISP in general. Therefore familiarity with LISP is assumed. This familiarity could be because the user has used LISP on other machines or because he has read the LISP Primer, and practiced LISP, and now wants a more thorough understanding.

This manual is complete in the sense that nothing else (like the LISP Primer) need be read; however, the basics are presented very quickly and the only narrative occurs when either details are being explained that were lacking in the LISP Primer or when differences between 1100 LISP and LISP on other machines are being emphasized.

In some cases, information is given about how the LISP system is actually implemented within the computer when this information is considered helpful in understanding how to use LISP.

But in most cases, LISP is described as the high-level language that it is. That is, LISP is described in terms of what LISP does instead of in terms of what it causes some machine to do.

The 1100 LISP system exists primarily as an interpreter which reads user supplied LISP expressions, evaluates them, and prints their values. In order to make it easier to debug programs, to modify them and save them, and to make them more efficient, there is a LISP library which contains a tracing package, a LISP text-editor, a routine to print out LISP functions, and a compiler. These are all described later in this manual. There is also a complete list describing all the functions that are supplied by the LISP system itself.


Chapter 2
THE UNIVERSE OF DISCOURSE

This chapter explains what objects are available in LISP and how they are to be written.

In general, extra spaces in LISP are optional and can be used to lay out LISP programs in a neat and readable format.


2.1 ATOMIC OBJECTS

Atomic objects are those objects in LISP that are usually not thought of as containing subparts. The general rule for delimiting all atomic objects is that each must be delimited on both sides by either a line boundary or a LISP punctuation mark, which on the 1100 are space, comma, period, left and right parentheses, left and right square brackets, left and right broken brackets, apostrophe, double quotes, and question mark; e.g.


     blank  ,  .  (  )  [  ]  <  >  `  "  ?

The following rules apply to the use of punctuation marks:

(1) Atomic objects may not cross line or card boundaries.

(2) At least one space or comma is required between consecutive atomic objects.

(3) Spaces and commas are equivalent. (A,B,,C) is equivalent to (A B C).

(4) Any number of spaces or commas surrounding some other punctuation mark is equivalent to that punctuation mark alone.

(5) A question mark on a line or card causes the rest of that image to be ignored. This may be used to include commentary information.


2.1.1 Numbers

Integers are written as any sequence of decimal digits optionally preceded by a sign and optionally followed by the letter "E" and a decimal scale factor.

Examples: 0, +3, 10, -256, 1E6 (same as 1000000), and -0.

The largest integer allowed in 1100 LISP is 2**35-1.

Integers may be written in octal by writing a sequence of octal digits with optional sign and followed by the letter "Q" and an optional octal scale factor. A minus sign indicates one's complement and scaling is performed by doing a circular left shift. Examples: 0Q, 74Q, 77Q3 (same as 77000Q), and -77Q2 (same as 777777770077Q).

Real numbers must contain a decimal point, which may not be the first character; they may optionally be preceded by a sign and may optionally be followed by the letter "E" and a decimal exponent. Examples: 0.0, 3.14159, -4.3E10, and -2.06E-22.


2.1.2 Atomic Symbols

Atomic symbols in LISP are usually written as any sequence of letters and digits that starts with a letter.

In 1100 LISP any sequence of characters that does not contain a LISP punctuation mark and cannot be interpreted as a number will be interpreted as an atomic symbol.

Examples: A, ABC, ANATOMICSYMBOL, P1, 1P, +, 10EE, A-B, and NIL.

LISP punctuation marks may be included in atomic symbols by preceding them with an exclamation mark (!). The exclamation mark means to interpret the character following it as a regular character and not to attribute any special significance to it.

Examples: HOW!?, A!!B, A!B (same as AB), !!, and !23 (this is an atomic symbol, not a number).

These would be printed out as HOW?, A!B, AB, !, and 23.


2.1.3 Strings

Strings in 1100 LISP are written as any sequences of characters surrounded on both sides by double quotes ("). To include a double quote in a string, two consecutive double quotes are written.

Examples: "ABC", "THISISASTRING", and "THISISADOUBLEQUOTE("")".

Strings are not atomic symbols; they may not be used as names of functions or variables, and nor do they have property lists.

The usefulness of strings is in printing out textual material; i.e. (PRINT "WHAT DO YOU WANT?") is a lot easier to write than (PRINT `WHAT!DO!YOU!WANT!?).


2.1.4 Truth Values

Falsehood in LISP is represented by the atomic symbol NIL and truth is represented by anything else.

The atomic symbol T is constantly bound to itself and is customarily used to represent truth. The atomic symbols F and NIL are both bound to NIL so either may be used to represent falsehood in an expression.


2.1.5 Functions

Functions are data objects in 1100 LISP and can be manipulated just as easily as other data; i.e. they can be assigned to variables, supplied as arguments to other functions, or returned as results of functions.

There is a difference between a function and the name of a function. For instance, PLUS is an atomic symbol, not a function, but it happens to be the name of a function, namely that function which computes the sum of its arguments. There is no way that functions themselves can be written, the best we can do is to write the name of a function or some other expression that evaluates to the desired function. But it will be seen that this causes no problems.


2.2 COMPOSITE OBJECTS

There is only one type of composite object in LISP, known affectionately as a "consed pair".

In other LISP systems, they are sometimes called S-expressions. It is essentially an ordered pair consisting of two other LISP objects. It is written as a left parenthesis, followed by a LISP object, followed by a dot, followed by another LISP object, and finally a right parenthesis; e.g. (thing1 . thing2).

The left and right parts of a consed pair can be any LISP objects whatsoever, including other consed pairs.

Although it is not necessary to surround the dot with spaces, it is usually a good idea in order to avoid confusion with real numbers.

Examples: (A . B), (A . 1), (2 . 78) (not a real number), ((A . B) . (C . D)), and (A . (B . (C . NIL))).


2.2.1 Lists

A special subset of all the composite objects is singled out because of their usefulness and called lists.

A list is any composite object of the form

(X1 . (X2 . (X3.... (Xn . NIL)... )))

where there may be any number of Xi's and each may be any LISP object.

Such a list may be written far more conveniently as (X1 X2 X3... Xn).

The list notation is used almost universally when writing in LISP. In general, we write a list by writing a left parenthesis, then the elements of the list separated by spaces (or commas, if you prefer), and ending with a right parenthesis.

In 1100 LISP square or broken brackets may be used in place of parentheses. As a bonus, a special convention allows one to do some automatic parenthesis balancing. The rule is this: Any closing bracket, ), ], or >, will generate the correct closing brackets to close all opening brackets, (, [, or <, to the left back thru the one corresponding to the closing bracket that was written.

E.g. writing a ] will force closure of all lists starting with ( or < back to the left until an unclosed [ is found to close.

Examples of legitimate lists:

(A, B, C), [ D E F ], (A123 . 456BCD), (ONEELEMENTLIST), (A B (A SUBLIST) C D), (), and <A (B (C [D E] F [G ) H>.

The last is the same as the list (A (B (C (D E) F (G)) H)).

The empty list may be written (); it is equivalent to the atomic symbol NIL and the two can be used interchangably.


Chapter 3
BASIC FUNCTIONS

This chapter details some of the more or less primitive functions of LISP that are provided by the 1100 LISP system.

The fundamental notion in LISP is that of applying a function to arguments. This is written like so: (FN ARG1 ARG2... ).

This means that the function symbolized by FN is to be applied to the arguments symbolized by the ARG.

Exactly what we mean by "symbolize" will be explained below. In all cases except one, writing a list as a LISP expression means that a function is to be applied to some arguments. The only exception is when the first element of the list is a special atomic symbol (e.g. QUOTE, COND, PROG, etc.) that indicates that some special method of evaluation is to take place.

These special cases are called special-forms in 1100 LISP.

Some of the more basic of them will be listed below along with the primitive functions.


3.1 EVALUATION

By "evaluation" in 1100 LISP we mean the process of reducing a LISP expression to its value.

The rules for evaluating a LISP expression are as follows:

Numbers, strings, and functions have themselves as values.

Atomic symbols for which constant bindings have been established (via CSETQ, DEFINE, etc.) evaluate to their constant value.

Atomic symbols without constant bindings must be LAMBDA-variables or PROG-variables and evaluate to their most recent binding.

Lists whose first element is an atomic symbol indicating a special-form are evaluated according to the special rules for that special-form.

All other lists mean that a function is to be applied to some arguments; each element of the list is evaluated in turn, and the value of the first element (which must be a function) is applied to the values of the rest of the elements of the list as agruments; the result of this application is the value of the expression.

When we say that a function is "symbolized" by an atomic symbol or that an atomic symbol "names" a function, what we mean is that that atomic symbol evaluates to that function. In by far the majority of the cases, this "naming" arises because the atomic symbol has the function as a constant value. This constant value has either been established by CSETQ or is provided by the 1100 LISP system.

To those of you who learned LISP on a different machine, be aware that the constant binding in 1100 LISP takes the place of all the indicators APVAL, EXPR, SUBR, etc. that are used on other systems.

In 1100 LISP, an atomic symbol can have only one value, and that value does not depend on whether you write the atomic symbol as a function or an argument.

E.g. when you write the atomic symbol PLUS in a LISP expression, you always mean that function which computes the sum of its arguments.

If you wish, you might now want to read chapter 4, which gives details on how LISP is implemented on the 1100. This may give you a better understanding of what is going on.


3.2 BASIC FUNCTIONS

Most of the basic functions of 1100 LISP are listed below.

Specialized functions for input-output, property lists, etc. will be described in separate chapters. An alphabetical index to the descriptions of all functions appears in the back of this manual. In general, when lower case letters are used to represent arguments to a function, they represent the value of whatever LISP expression is written in their place.

A few more notes about the terminology used in this manual are in order.

There is a difference between the name of a function and that function itself. When refering to a function, lower case letters will be used. When capital letters are used, reference is always being made to an atomic symbol.

In many cases, to emphasize the difference, an statement of the form "the function named ATSYMB" will be used instead of just atsymb.

The word iff means if and only if.

The word pseudo-function means those functions in LISP that are applied because of the side-effects that they produce; their result is incidental.

When we speak of the result when describing a function, especially when describing a pseudo-function, we mean the value of the expression that applies that function to its arguments, i.e. what is normally meant by the value of a function.


3.2.1 Symbol Manipulating Functions

(CAR x)
x must be a composite object. This expression retrieves the left part of that composite object.

If x is a list, (CAR x) will be its first element.


(CDR x)
x must be a composite object. This expression retrieves the right part of that object. If x is a list, (CDR x) will be the "rest" of the list, i.e. the list that remains after the first element is removed.


(C...R x)
where C...R is any sequence of A's and D's up to a maximum of 35 is the composition of the appropriate CAR's and CDR's associated from the right. E.g. (CADDR x) is the same as (CAR (CDR (CDR x))).

Zero A's and D's is valid; (CR x) is equivalent to x.


(CONS x y)
results in the composite object (x . y). If y is a list, (CONS x y) results in a new list with x inserted as its first element.


(ATOM x)
is true iff x is atomic, i.e. a number, atomic symbol, function, or string.


(EQ x y)
is true if x and y are the same atomic symbol. It is false if either x or y is an atomic symbol and the other is anything else.

It is undefined if neither x nor y is an atomic symbol.


(EQUAL x y)
is true iff x and y are the same LISP object, i.e. would appear identical if printed. Equal must be used to compare numbers, strings, or lists.

The only exception to the "same if printed" rule is that equal may be used to compare numbers of different types, e.g. (EQUAL 1 1.0) = (EQUAL 1 1Q) = (EQUAL 1.0 1Q) = T.

Any number that is within 0.000003 of a real number is considered equal to it.


(RPLACA x y)
x must be a composite object. It is altered so that its left part is now y. The result is the new, altered x.


(RPLACD x y)
x must be a composite object. It is altered so that its right part is now y. The result is x.y.

WARNING! Rplaca and rplacd permanently alter list structure and their use can have disasterous consequences. These pseudo-functions should never be used unless you know precisely what you are doing.


(NULL x)
is true iff x is the atomic symbol NIL (the empty list)


(NOT x)
is true iff x is false. Due to the way truth and falsehood are represented in LISP, (NOT x) = (NULL x) = (EQ x NIL).


(LIST x 1x 2... xn)
forms the list (x 1x 2... xn).

(LIST) = NIL.


(MEMBER x s)
is true iff x is one of the elements of the list s. The "truth" that is returned is the rest of the list s starting with x if it is found. The following LISP definition is equivalent. Note that the function named EQUAL is used, not EQ.

(CSETQ MEMBER(LAMBDA (X L)
  (COND 
    ((NULL L) NIL)
    ((EQUAL (CAR L) X) L)
    (T (MEMBER X (CDR L))))))


(APPEND s1 s2)
is the list consisting of the elements of s1 followed by the elements of s2.

(CSETQ APPEND(LAMBDA (L1 L2)
  (COND
    ((NULL L1) L2)
    (T (CONS (CAR L1) (APPEND (CDR L1) L2)))))) 


(NCONC s1 s2)
will alter s1 to end up pointing to s2. The value is the same as (APPEND s1 s2) but the effect is quite different. It is quite easy to create a circular list with nconc, e.g. (NCONC xx).

(CSETQ NCONC(LAMBDA (L1 L2) 
  (COND
    ((NULL L1) L2)
    (T (RPLACD L1 (NCONC (CDR L1) L2)))))) 


(LENGTH s)
is the length of the list s. (LENGTH NIL) = 0.


(REVERSE s)
is a list with the elements of s written in reverse order. (REVERSE '(A (B C) D)) = (D (B C) A); (REVERSE NIL) = NIL.


(NTH s n)
n must be an integer. nth gives the nth final segment of s counting from the left if n is positive and from the right if n is negative. Final segments of a list are those lists that come from the series s, (CDR s), (CDDR s), (CDDDR s), etc., (NTH '(A B C) 1) = (A B C), (NTH '(A B C) 2) = (B C), (NTH '(A B C) -1) = (C). If n is 0 or too big for the list, the result is NIL.


(ASSOC x s n)
is the nth element of s whose car is equal to x.

n is an optional argument and if omitted, one is assumed.

(CSETQ ASSOC(LAMBDA (X L N) 
  (COND
    ((NULL L) NIL)
    ((EQUAL (CAAR L) X)
      (COND
        ((EQUAL N 1) (CAR L)) 
        (T (ASSOC X (CDR L) (SUB1 N)))))
    (T (ASSOC X (CDR L) N))))) 


(SUBST x y z)
gives a copy of the object z with every subpart that is equal to y changed to x.

I.e. substitute x for y in z. The definition given below in LISP is not the most "obvious" one, It goes through a little extra work in order to avoid making a complete copy of any subpart that is not changed.

(CSETQ SUBST(LAMBDA(X Y Z) 
  (COND
    ((EQUAL Y Z) X)
    ((ATOM Z) Z) 
    (T (CONSIFNEW(SUBST X Y (CAR Z))(SUBST X Y (CDR Z)) Z))))) 

(CSETQ CONSIFNEW(LAMBDA(NCAR NCDR OLD) 
  (COND
    ((AND (EQ (CAR OLD) NCAR) (EQ (CDR OLD) NCDR)) OLD)
    (T(CONS NCAR NCDR)))))


(GENSYM h)
gives a brand new atomic symbol guaranteed to be unique, i.e. will not be eq to any other atomic symbol.

If this atomic symbol is printed, it will appear as hn, where h is how the object h would be printed and n is some random integer. h is an optional argument and if omitted, the atomic symbol G is assumed.


(OBLIST fn)
fn must be a pseudo-function of one argument and will be applied to every atomic symbol currently in the LISP system with the exception of those generated by gensym.

fn is optional and if omitted, all the atomic symbols in the system will be printed.

The result is NIL.


(AMB x1 x2... xn)
will be one of the xi's selected at random.

This random argument picker is LISP's version of a random number generator.


(IFTYPE x n)
true iff x is an object of type n. n must be an integer between 0 and 8.

See chapter 4 for further explanation.

The types are as follows:

     0 = composite object (consed pair).

     1 = integer.  
 
     2 = octal integer.
 
     3 = real number.  
 
     4 = system defined function.  
 
     5 = compiled function.
 
     6 = function created by LAMBDA. an
 
     7 = atomic symbol.
 
     8 = string.


(ERASE s)
s must be a list of atomic symbols and each one of them will have its constant binding removed and its property-list emptied.

The result is NIL.


(MAPC s fn)
the pseudo-function of one argument fn is applied to each element of the list s.

The value is NIL.

(CSETQ MAPC(LAMBDA(L FN)
  (PROG() 
    LOOP
    (COND( (NULL L) (RETURN NIL)))
    (FN (CAR L)) 
    (SETQ L (CDR L)) 
    (GO LOOP)))) 
(MAP s fn)
The pseudo-function of one argument fn is applied to each final-segment of s.

The definition in LISP is similar to that for mapc with (FN (CAR L)) changed to (FN L).


(INTO s fn)
or
(MAPCAR s fn)
is the list resulting from the application of the one argument function fn to each element of the list s.

(CSETQ MAPCAR
  (CSETQ INTO(LAMBDA(L FN)
    (COND
      ((NULL L) NIL)
      (T (CONS (FN (CAR L)) (INTO (CDR L) FN))))))


(ONTO s fn)
or
(MAPLIST s fn)
is the list resulting from the application of fn to each final-segment of the list s. Definition in LISP is similar to that of into with (FN (CAR L)) changed to (FN L).


(INDEX s end fn)
fn must be a function of two arguments. If s is the list (x1 x2... xn), the value of the above expression is the same as (fn 'x1 (fn 'x2... (fn 'xn end))).

Example: (INDEX x y CONS) is equivalent to (APPEND x y) and (INDEX s PLUS) evaluates to the sum of the elements of s.

(CSETQ INDEX(LAMBDA(L END FN)
  (COND
    ((NULL L) END)
    (T (FN (CAR L) (INDEX (CDR L) END FN)))))) 


(ONDEX s end fn)
value similar to index except that fn is applied to each final-segment of s and the rest of the "ondexed" list.


3.2.2 Arithmetic Functions

The arguments to all the functions below must be numbers. Unless stated otherwise, any mixture of real numbers and integers is allowed. If any of the arguments to an arithmetic function is a real number, all other arguments will be converted to real and the result will be of type real.

If all the arguments are integers, the result will be an integer.

(PLUS x1 x2... xn)
evaluates to x1 + x2 + ...+ xn.

Any number of arguments is allowed.

(PLUS x) = x, (PLUS) = 0.


(DIFFERENCE x y)
evaluates to x - y.


(TIMES x1 x2 ... xn)
evaluates to x1 * x2 * ... * xn.

Any number of arguments is allowed.

(TIMES x) = x, (TIMES) = 1.


(QUOTIENT x y)
gives the number-theoretic quotient of x divided by y if both are integers, otherwise the real quotient.

(QUOTIENT 5 2) = 2, (QUOTIENT 5 2.0) = 2.5.


(REMAINDER x y)
gives the number-theoretic remainder when x is divided by y if both are integers, otherwise gives the floating-point residue.


(ADD1 x)
gives x + 1.


(SUB1 x)
gives x - 1.


(MINUS x)
gives the one's complement of x.


(ENTIER x)
gives the largest integer that is less than or equal to x if x is real, otherwise x.

(ENTIER 10.5) = 10, (ENTIER -10.5) = -11.


(LOGOR x1 x2 ... xn)
gives the logical sum of x1 thru xn regarded as 36 bit words.

(LOGOR) = 0Q.


(LOGAND x1 x2 ... xn)
gives the logical product of x1 thru xn regarded as 36 bit words.

(LOGAND) = -0Q.


(LOGXOR x1 x2 ... xn)
gives the logical exclusive-or of x1 thru xn regarded as 36 bit words.

(LOGXOR) = 0Q.


(LEFTSHIFT x n)
treats x as a 36 bit word and shifts it left by n bits with zero-bits entering from the right. If n is negative, x is circularly shifted to the right by n bits.


(ZEROP x)
is true iff x is zero.


(NUMBERP x)
is true iff x is an integer or a real number.


(FIXP x)
is false if x is a real number, true otherwise.


(FLOATP x)
is true iff x is a real number.


(MINUSP x)
is true iff x is a negative number.


(GREATERP x y)
is true if x is greater than y and false if x is less than or equal to y. Real numbers are compared with a tolerance of 0.000003, so (GREATERP 1.0000001 1) is false.


(LESSP x y)
is true if x is less than y and false if x is greater than or equal to y.

See remarks about floating-point tolerances above.

Of the three expressions (EQUAL x y), (GREATERP x y), and (LESSP x y), exactly one will be true and the other two false.


3.3 SPECIAL-FORMS

The special-forms in 1100 LISP are listed below.

Each special-form has its own method of evaluating its "arguments" so in this case, when a lower case letter is used, it represents the actual expression that is written in its place instead of the value of that expression.

(QUOTE x)
evaluates to the object x. I.e. it is x, not what x evaluates to. Any time that the input routine sees an apostrophe, it will read the next LISP object and put it in a QUOTE special-form.

E.g. `A may be written instead of (QUOTE A), `(A B C) may be written instead of (QUOTE (A B C)), and so forth.


(DO e1 e2...)
Each ei is evaluated in sequence from left to right. The value of each ei is discarded except the last which becomes the value of the entire expression.

DO is used to perform pseudo-functions.

DO is the 1100 LISP equivalent of PROG2 or PROGN on other machines.

(COND (p1 e11 e12...)
      (p2 e21 e22...)
      (pn en1 en2...))
Each pi is evaluated from left to right until one is found that is true (not NIL), then the corresponding eij's are evaluated from left to right and the value of each discarded except the last, which becomes the value of the entire conditional expression.

If there are no ei's following the first true pi, then the value of the conditional expression is the value of that pi.

If none of the pi's are true, the value of the conditional expression is NIL.


(AND e1 e2...)
The ei's are evaluated from left to right until one is found that is false, in which case the value of the entire expression is NIL and no more ei's are evaluated.

If no ei's are false, the the value of the expression is the value of the last ei.


(OR e1 e2...)
The ei's are evaluated from left to right until one is found that is true, in which case the value of the entire expression is the value of that true ei and no more ei's are evaluated.

If none of the ei's are true, the value of the expression is NIL.


(CSETQ v e)
v must be an atomic symbol. The expression e is evaluated and its value is established as the constant value of the atomic symbol v.

This value will be the value of the atomic symbol v whenever it is used as an expression until it is explicitly changed via another csetq.


(CSET v e)
will establish the value of the expression e as the constant value of the atomic symbol that you get by evaluating v.

I.e. (CSETQ V e) is equivalent to (CSET (QUOTE V) e).

CSET (and SET below) are almost never used since CSETQ and SETQ are virtually always the ones you want.


(LAMBDA (v1 v2... vn) e1 e2... en)
Each vi must be an atomic symbol that does not and never will have a constant value. The above evaluates to that function of v1, v2,... vn that is computed by (DO e1 e2... en).

That is, the special-form LAMBDA evaluates to a function. Whenever that function is applied to some arguments, it computes its result by evaluating the ei's from left to right in an environment where each vi will evaluate to its corresponding argument. The value of each ei is discarded except the last, which becomes the result of the function. The bindings of the vi's to the arguments only last during the evaluation of the i's; after the result is computed, they are restored to their former (if any) values.

Note: the special-form LAMBDA only creates a function, it does not apply it to any arguments nor does it give it a name. The customary method of naming a function in 1100 LISP is to assign it to a variable; e.g. (CSETQ FN (LAMBDA (V1 V2... )...)).

LAMBDA may be used to create functions that take an indefinite number of arguments. This is done by writing a dot in front of the last vi.

E.g. (LAMBDA (V1 V2 . VR)...).

In this case the first two arguments to which this function is applied will be bound to V1 and V2; VR will be bound to a list of the rest of the arguments (NIL if none).

If it is possible that the function can be applied to zero arguments, then one writes (LAMBDA VL...) and VL will be bound to a list of all the arguments whenever the function is applied.

Writing LAMDA instead of LAMBDA will create a function whose free variables have the values that they had at the time the function was created (i.e. right now) instead of the values that they will have when the function is applied to arguments (see chapter 12 for further explanation).


(STACK s)
s must evaluate to a list. (STACK s) may be written in place of a sequence of arguments to a function. It is equivalent to writing each member of s as a quoted argument to that function. STACK seems to act like the inverse of the function named LIST since (LIST (STACK s)) = s and (STACK (LIST e1... en)) is the same as writing e1... en.

For example, (APPEND x y) is the same as (LIST (STACK x)(STACK y)) and (PLUS (STACK s)) evaluates to the sum of the elements of s.

If you are used to LISP on a different machine, or if you plan to write LISP programs on the 1100 that will eventually be used on a different machine, be advised that I know of no other LISP system extant that has anything corresponding to STACK.

(PROG (v1 v2... vn) s1 s2... sn)
Each vi is either an atomic symbol or is of the form (v e) where v is an atomic symbol and e is some LISP expression.

The special-form PROG is evaluated by first initializing each vi as a local variable. Each vi that is an atomic symbol is bound to NIL and each v in a (v e) is given the initial value that is the value of the expression e. These local variables are just like LAMBDA-variables and only last until the PROG is completed. And also like LAMBDA-variables, they cannot have constant bindings.

The si's that are lists are then evaluated from left to right and their values discarded until either a transfer of control is encountered (see GO below), an exit is made from the PROG (see RETURN below), or the si's are exhausted, in which case the value of the entire PROG-expression is NIL.

The si's that are atomic symbols are labels for use with GO.

Since the value of each si will be discarded, each must be a pseudo-function that somehow affects things in order for it to make sense.


(GO lab)
lab must be an atomic symbol that also appears as a label in the PROG in which this GO is written. Evaluation of a GO-expression will cause control to be transferred to this label and evaluation of the si's will proceed from there.

Note that lab is the actual label desired, not an expression that evaluates to that label.


(RETURN e)
When a return is encountered in a PROG, the expression e is evaluated and the PROG is immediately terminated with its value being the value of e.


(SETQ v e)
v should be either a PROG- or a LAMBDA variable that has a current binding. Its binding will be changed to the value of the expression e.

If there is no current binding for the variable v, one will be created for it at the most recent level of supervision, i.e. as if v were a local variable to the most recent call of the LISP supervisor (function named LISP, see chapter 5).


(SET v e)
will assign the value of the expression e to the value of v. (cf CSET above).


(ATTEMPT e (n1 e1) (n2 e2)... (np ep))
e is any LISP expression. Each ni must be an integer and each ei is a LISP expression.

An attempt will be made to evaluate the expression e. If a value results, the value of the entire ATTEMPT-expression is that value and none of the ei's are evaluated.

However, if at some time during the evaluation of e, an expression of the form (ERROR n) is evaluated, n will be evaluated and must be an integer; then the system returns to the most recent ATTEMPT-expression that has this n as one of the ni's and the value of the corresponding ei becomes the value of that ATTEMPT-expression. This ei is not evaluated with the "traps" of the ATTEMPT-expression in effect; however, it can itself be another ATTEMPT-expression.


(ERROR n flg)
n must evaluate to a number and will cause a return to the most recent ATTEMPT-expression that has n as a "trap" number (see above).

flg controls the backtrace during this return. If flg is omitted or is NIL, no backtrace is produced. If it is an integer, that many of the most recent expressions being evaluated will be printed. And if it is T, a full backtrace will be printed back to the point where the ATTEMPT is found. (See discussion of the backtrace below in chapter 5.)

The convention that has been established is that negative trap numbers are used by the system and the user has all the positive ones.

You may still use ATTEMPT-expressions with negative trap numbers to handle system errors yourself, though. You can also cause your own system errors with (ERROR-n).

The ones assigned to the system are:

 0 = return to LISP supervisor after an error. 

-1 = RETURN to last PROG because of a return. 
 
-2 = return to last PROG because of a GO. 
 
-3 = return to LISP supervisor after an @@X C interrrupt.

-4 = return to supervisor because a trap number was not found.

-5 = return to read routine after :OOPS.

-6 = return to supervisor after control statement processed.

-7 = initiate backtrace because of a :PEEK.



Chapter 4
ON IMPLEMENTATION

This chapter discusses some of the "magic" that goes on inside the 1100 when LISP is running. It is presented here mainly to satisfy curiosity.

However, a small understanding of what is going on behind the scenes is often useful in understanding exactly what LISP is doing.

There will be some places here where simplifications are made in order to promote a clearer understanding. Although things may be done in a manner slightly different from what is presented here, this is essentially what is happening.


4.1 MEMORY ORGANIZATION

In essence, everything in LISP is represented by a pointer.

For instance, a number like 3 would be represented by a pointer to (the address of) a word that contains the number 3. These pointers are what are passed as arguments to functions, stored as values of variables, or returned as results of applying functions.

There are times when, given a pointer, it is necessary to determine what kind of information (integer, list, function, etc.) is being pointed at. This can be determined by noticing which part of memory is being pointed to.

The main building block of LISP, the consed-pair, is represented by a pointer to a word containing two other pointers, the left half of the word points to car of the consed-pair and the right half points to cdr.

A list like (A 2 BRUTE) would be represented in memory like so:

     _____________     _____________     _____________
    |______|______|-->|______|______|-->|______|______|--> NIL
       |                 |                 |
       v                 v                 v
                       _____________
       A              |___________02|     BRUTE
Where A, NIL, and BRUTE have been written instead of the actual memory representations of those atomic symbols.

The arrows indicate that the fields from which they originate contain the addresses of the words to which they point.

Atomic symbols have the following representation in memory:

                           ____________
     to constant value <--|_____|______|--> to property list
          to hash link <--|_____|______|--> to print name
Note that each atomic symbol takes two words of memory.

The pointer to the constant value is only there if the atomic symbol has such a value, otherwise it is zero. Property lists are explained in chapter 11.

The print name is a string containing the characters in the atomic symbol. (Strings are represented as words where the left half contains three characters of the string and the right half points to the rest of the string, if any.)

The hash link is used by the input routine to speed up searching.

Whenever an atomic symbol is read in by LISP, a search is made to see iff this atomic symbol has been read before. If it has been, no new atomic symbol is created. Instead the pointer to the old atomic symbol is used.

This is necessary because when you use an atomic symbol to name a function the constant value field points to the function and any expression that uses that function must have access to that same atomic symbol so that the function can be's retrieved.

This also explains why both EQ and EQUAL exist. EQ simply compares the two pointers that it receives as arguments and does not have to look at the print names of the atomic symbols.

When LISP starts, an available space list is created. This is a list of all the available words in memory. When a function like cons is applied, it removes a word from this available space list and places pointers to its two arguments in their appropriate fields and returns a pointer to this word as its result.

Similarly, if the function plus is applied, the arguments are summed and the sum placed in a new word taken from available space. The result will be a pointer to this new word.

Notice that the pseudo-functions named RPLACA and RPLACD do not create new words. They simply take the word that is being pointed at by their first argument and place the pointer that is their second argument in the appropriate half.

Eventually available space will be exhausted. When this happens a process known as garbage collection takes place. The garbage collector looks through memory and finds all words that are "active". For instance, by starting with the pointer to the expression being evaluated and following all pointers as far as possible, all the words that might possibly be needed in the evaluation are discovered. Once all the active words are discovered, everything else(the garbage) is strung together in a new available space list and evaluation then proceeds.


4.2 EVALUATION

A function in 1100 LISP is represented by a pointer to the code that is to be executed in order to compute the result of that function. For instance, the function that computes the sum of its arguments is represented by a pointer to the code within the LISP interpreter that adds the numbers that have been placed on the push-down stack and stores their sum in a new word in memory.

This pointer (i.e. the address of this code) is what is initially stored in the constant value field of the atomic symbol PLUS.

The push-down stack is a last-in first-out stack that is used during evaluation to transmit arguments to functions, to keep local variables, and to save return addresses for recursive calls.

In general, the method of applying a function to its arguments in 1100 LISP is to move the arguments onto the push-down stack and then jump to the code for the function. The code for the function must do the proper things with the arguments on the push-down stack in order to compute the result of the function and then unwind the stack as it returns.

The representation of functions as pointers to executable code requires a bit of prestidigitation in order to handle functions created by LAMBDA.

Essentially what happens is that when a function is created (not applied) by the special-form LAMBDA, a tiny section of executable code is put in memory. Then, whenever this function is applied, this code will be jumped to after the arguments are placed on the push-down stack and it will in turn jump back into the LISP interpreter where the arguments are retrieved from their push-down stack and associated with their corresponding LAMBDA-variables and then the body of the LAMBDA-expression is retrieved and evaluated in this environment.

The mechanism for establishing the correspondence between LAMBDA- and PROG-variables and their values is called an association list.

An association list looks like this:

( (v1 . a1) (v2 . a2)... )

Each vi is a LAMBDA- or PROG-variable and each ai is the value to which it is bound.

When a LAMBDA-defined function is applied, the arguments from the push-down stack become the ai's and the variables retrieved from the LAMBDA-expression become the vi's. Each of these (v.a) pairs is added to the front of the association list.

After all the variables are bound, the body of the LAMBDA-expression is retrieved and handed off to the expression evaluator.

After the result is computed, the association list is restored to its original state and we are done applying the function.

The expression evaluator is really the heart of the LISP interpreter. It is a function named EVAL which when given a LISP expression as its argument will compute the value of that expression in the current environment.

It is described below as a LISP function along with some of the important auxiliary functions.

Many of these functions do not really exist in the LISP system; the descriptive names that are used merely reflect what is happening in machine code.

Of special note are the "functions" that start with "M-", these are not even functions in the pure sense since they do some cheating with the push-down stack that functions aren't really supposed to do.

The descriptive name was just chosen to give you an idea of what sort of magic goes on in machine language.

<CSETQ EVAL(LAMBDA[EXP]
  (COND
    [(ATOM EXP) 
      (COND
        [(NOT (IFTYPE EXP 7)) EXP]
        [(IFCONSTANT EXP) (CONSTANTVALUEOF EXP)] 
        [T (CDR (ASSOC EXP ALIST))])]
    [(IFSPECIALFORM (CAR EXP)) (M-DOSPECIALFORM (CDR EXP))]
    [T (PROG [FN] 
      <SETQ FN(EVAL (CAR EXP))>
      EVALLOOP
      <SETQ EXP (CDR EXP)>
      <COND [ (NULL EXP) (RETURN (APPLY FN))]>
      <M-MOVEONTOSTACK (EVAL (CAR EXP))>
      <GO EVALLOOP>)]))>
 
<CSETQ APPLY(LAMBDA[FN]
  (COND
    [(OR ( IFTYPE FN 4) (IFTYPE FN 5)) <M-JUMPTO FN>]
    [(NOT (IFTYPE FN 6)) <DIAGNOSTIC FN "IS NOT A FUNCTION">] 
    [T (PROG [V VL (OLDALIST ALIST)]
         <SETQ VL (VARSFROMLINKNODE FN)>
         BINDLOOP
         <COND[ (NULL VL) <GO BODY>]>
         <CSETQ ALIST (CONS (CONS (CAR VL) (M-GETONEFROMSTACK)) ALIST)>
         <SETQ VL (CDR VL)>
         <GO BINDLOOP>
         BODY
         <SETQ V (EVALSEQ (BODYFROMLINKNODE FN) NIL )>
         <CSETQ ALIST OLDALIST>
         (RETURN V))]))>

<CSETQ EVALSEQ(LAMBDA[EXPRS V]
  (COND
    [ (NULL EXPRS) V ] 
    [ T (EVALSEQ (CDR EXPRS) (EVAL (CAR EXPRS)))]))>

<CSETQ DOLAMBDA(LAMBDA[REXP]
  (MAKELINKNODE (CAR REXP) (CDR REXP)))>

<CSETQ DOQUOTE(LAMBDA[REXP]
  (CAR REXP))>

<CSETQ DOCOND(LAMBDA[PAIRS]
  (COND
    [ (NULL PAIRS) NIL ]
    [ (EVAL (CAAR PAIRS)) (EVALSEQ (CDAR PAIRS) (EVAL (CAAR PAIRS)))]
    [ T (DOCOND (CDR PAIRS))]))>
  
<CSETQ DOOR(LAMBDA[EXPRS]
  (COND
    [ (NULL EXPRS) NIL ]
    [ (EVAL (CAR EXPRS))] 
    [ T (DOOR (CDR EXPRS))]))>

<CSETQ DOPROG(LAMBDA[REXP] 
  (PROG [ (VL (CAR REXP)) PV IV (STATS REXP) PROGVAL TARGET]
    INIT
    <COND[ (NULL VL) <GO BODY>]
      [ (ATOM (CAR VL)) <SETQ PV (CAR VL)> <SETQ IV NIL>] 
      [ T <SETQ PV (CAAR VL)> <SETQ IV (EVAL (CADAR VL)>]>
    <CSETQ ALIST (CONS (CONS PV IV) ALIST)>
    <SETQ VL (CDR VL)>
    <GO INIT>
    BODY
    <SETQ STATS (CDR STATS)>
    <COND[ (NULL STATS) (RETURN NIL)] 
      [(ATOM (CAR STATS)) <GO BODY>]>
    <ATTEMPT <EVAL (CAR STATS)>
      [-1 (RETURN PROGVAL)]
      [-2 <SETQ STATS (CDR REXP)> <GO HUNT>]>
    <GO BODY>
    HUNT
    <COND[ (NULL STATS) <DIAGNOSTIC "GO" TARGET "ILLEGAL">]
      [(EQ (CAR STATS) TARGET ) <GO BODY>]>
    <SETQ STATS (CDR STATS)>
    <GO HUNT>))>

<CSETQ DOSETQ(LAMBDA[REXP] 
  (CDR (RPLACD (ASSOC (CAR REXP) ALIST ) (EVAL (CADR REXP)))))>

<CSETQ DORETURN(LAMBDA[REXP]
  <SETQ PROGVAL (EVAL (CAR REXP))>
  <ERROR -1>)>
 
<CSETQ DOGO(LAMBDA[REXP]
  <SETQ TARGET (CAR REXP)>
  <ERROR -2>)>

<CSETQ DOSTACK(LAMBDA[REXP]
  <STACKEMUP (EVAL (CAR REXP))>)>
 
<CSETQ STACKEMUP(LAMBDA[ARGS]
  <COND
    [ (NULL ARGS) <M-GOTO EVALLOOP>]
    [ T <M-MOVEONTOSTACK (CAR ARGS)>& #60STACKEMUP (CDR ARGS)>]>)>

The function m-dospecialform above in eval essentially gets replaced by one of the functions doquote, docond, doprog, etc.

What really happens is that the complement of a pointer to docond, doquote, etc. is placed in the constant value field of the atomic symbols COND, QUOTE, etc. It is this negative pointer that is noticed by ifspecialform in eval and the routine to handle the special-form is immediately jumped to.

The function apply doesn't exactly work as described; it actually just jumps to the code for the function whether it is type 4, 5, or 6.

The function makelinknode forms a two word piece of code (type 6 node) in memory that if jumped to, will jump right back to that part of apply that is written as a PROG.

The above description does omit some of the little details about error checking and push-down stack housekeeping and some of the other frills that are available in 1100 LISP, but is is essentially a fairly accurate description of what really goes on inside the interpreter.


Chapter 5
ON USING THE 1100 LISP SYSTEM

The 1100 LISP system is an interpreter that essentially reads a LISP expression, computes its value, and prints that value. It then returns to read the next expression and so forth.

One gains access to the 1100 LISP system by merely typing in @LISP. No file or element names need be supplied since 1100 LISP isa completely self-contained system.

Once LISP signs on, you are in the read-evaluate-print loop.

Normally the first thing you would do is to @ADD the elements that contain the definitions of the functions that you are working on, or, there being none, you would define the functions that you want to try out.

Once functions have been defined, tried out on a few test cases and corrected (see text-editor below), they can be filed away for later use (see pretty-printer below). If efficiency is a concern, they can be compiled and turned into machine code.


5.1 THE LISP SUPERVISOR

The LISP supervisor, which performs the read-evaluate-print loop, is available as a pseudo-function called LISP.

A description in LISP would go as follows:

(CSETQ LISP(LAMBDA IG 
  (PROG (EXPR VALUE INPUTGETTER)
    (COND( (NULL IG) (SETQ INPUTGETTER DEFAULTINPUTGETTER))
         ( T (SETQ INPUTGETTER (CAR IG)))) 
    LOOP
    (CLEARBUFF) 
    (SETQ EXPR (INPUTGETTER))
    (ATTEMPT (SETQ VALUE (EVAL EXPR)) 
      (0 (GO LOOP)) 
      (-3 (GO LOOP))
      (-4 (GO LOOP))
      (-6 (GO LOOP)))
    (PRIN1 "VALUE:  ")
    (PRINT VALUE)
    (GO LOOP))))

(CSETQ DEFAULTINPUTGETTER(LAMBDA() 
  (PRINT "EVAL:") 
  (READ))
As a special note to those of you who have been used to LISP on other machines. Notice that there is no EVALQUOTE in 1100 LISP. You always write LISP expressions, even on the "top level".

This has been found to eliminate a tremendous amount of confusion for people using LISP. The only reason that EVALQUOTE was invented on other systems was that people didn't like writing (QUOTE arg) all the time when talking to the supervisor. In 1100 LISP this problem is solved by giving you a much easier way of quoting arguments, i.e. `arg.s

However, if you really insist on using the function and list of arguments method of supplying input, or if you already have a card deck using this form and wish to use it on the 1100, then the optional variable to the function named LISP (IG above) allows you to supply your own input routine for the LISP supervisor that reads and transmogrifies the input in any manner that you wish.

E.g. you can do the following:

(CSETQ AWFUL(LAMBDA()
  (PRINT "FN AND ARGS:")
  (PROG (FN ARGS)
    (SETQ FN (READ)) 
    (SETQ ARGS (READ))
    (SETQ ARGS (INTO ARGS (LAMBDA(A) (LIST `QUOTE A)))) 
    (RETURN (CONS FN ARGS)))))

(LISP AWFUL)
Note that the LISP supervisor is a PROG. It is possible to leave it by merely having it evaluate an expression of the form (RETURN v) and v will become the result returned to whoever called the supervisor. You will find later that when in HELP mode, you may wish to go off and do some computing before resuming the evaluation. In such cases, merely typing in (LISP) will create a new level of supervision and when you are done you can return from this level with a value to resume.

Note also that the LISP system clears out the input buffer before it starts reading and always starts on a new line. This allows you to finish typing an expression with a ">" or "]" or ")))))" or whatever in order to force closure of all unmatched left-parentheses. As long as the expression being evaluated doesn't try to do any reading itself, these extra unclosed right-parentheses will be discarded and will never hurt anybody. If you are going to do some of your own input, then make sure the input buffer is clear before you start.


5.2 OUTPUT CONVENTIONS

The 1100 LISP system has certain output conventions that you will need to know about. The first is that there is a limit to the width and depth of objects that will be printed.

If you see "&"'s and "--"'s in your output and don't know why they are there, look up the function called PLIMIT under input-output in chapter 6.

The second convention is how the 1100 LISP systems prints functions.

Normally, a function with a name will be printed as [fn], where fn is the atomic symbol to which the function has been constantly bound. This use of square brackets in output does not mean a list. The LISP print routine always uses parentheses to delimit lists; when it uses square brackets, it is trying to tell you that you asked it to print a function.

It will search through all the atomic symbols attempting to find an atomic symbol that names this function, and will insert it in the square brackets if it finds one.

If it can't find one it will print something of the form [n:aaaaaaQ], where n is an integer and aaaaaaQ is an octal number. (If you're curious, n is the type of the function, see IFTYPE, and aaaaaaQ is its address in memory.)

Usually, the only time a function will be printed is right after you define one via csetq and in this case the function will have a name (since you just finished giving it one). You should expect the value of any function-defining expression like (CSETQ fn (LAMBDA...)) to be printed out as [fn].

However, if you use csetq to rename an already existing function, e.g. (CSETQ HEAD CAR), then the value could be printed as [HEAD] or as [CAR] depending on which atomic symbol was found first.

Related to this convention is the fact that a pointer to address zero will be printed as simply "@". This pointer usually arises because you applied a system-defined LISP function to an argument that is illegal, like trying to append something that is not a list to another list.

In general, seeing "@"'s in your output means that you are doing something illegal.

The last convention regards how the LISP system prints an object that is "almost" a list.

An object of the form

     (x1 . (x2 . (x3 . ....(xn . xp))))
where xp is an atom other than NIL only fails to be a list because that last atom is not NIL. This will be printed out as

     (x1 x2 x3 ... xn.xp)
and in fact can even be input that way.

In general, the LISP system always tries to print something using the list notation; it only resorts to the dot notation when it absolutely has to.


5.2.1 The Backtrace

The backtrace is printed by the LISP system after most errors.

It is a listing of the expressions in the process of being evaluated when the error occurred. If a full backtrace is requested (see below) it also includes the association lists that were used to evaluate those expressions.

Each line of the backtrace begins with the sequence "...".

Which entries are association lists and which are expressions should be obvious. Association lists always contain the character sequence [] which marks the levels of supervision.

Note that if a variable is bound to a list on the association list, it will appear as a list where the variable is the first element. For example, if N is bound to 5 and L is bound to the list (A B C), then part of the backtrace might look like:

     ...((N . 5) (L A B C)... )
The normal depth and length limits used during the backtrace are 3 and 10. These may be changed if desired by the pseudo-function named BACKTR (see below).


5.3 CONTROL STATEMENTS

The following 1100 LISP control statements are used to control the state of affairs while running LISP.

Each 1100 LISP control statement must start with a colon in column one.

Most cause you to return to the LISP supervisor for another expression to evaluate after they have performed their function; however, a few are "transparent" and may be typed in any time that input is being read.

After they perform their function, you may continue typing in input just as if the transparent control statement had never been typed.

:LISP
causes the 1100 LISP system to immediately return to the supervisor and request the next expression to evaluate.


:BACK x
also causes a return to the supervisor but on the way back, a backtrace is printed.

If x is blank, the type and length of the backtrace is determined by the mode (batch or timesharing) of the run (see below under function named BACKTR).

If x is "T", then a full backtrace will be printed including both expressions being evaluated and association lists.

If x is an integer from 1 through 9, then that many of the most recent expressions being evaluated will be printed, but no association lists.


:PEEK x
causes a backtrace to be printed just like :BACK but is transparent. After the backtrace is printed, you can continue typing in input.


:OOPS
causes the LISP system to start reading the LISP object being read again. If you notice a mistake in a line that has already been typed in, this is used to start the object all over again. Obviously, if you notice the mistake in the current line before the carriage return is typed, then you can use the cancel character to restart the line.


:LIST
is a transparent control statement that instructs the read routine to list lines as they are read. This is normally not used since the 1100 LISP system automatically starts out in :LIST mode if it is a batch run and in :UNLIST mode if timesharing.


:UNLIST
is a transparent control statement that instructs the LISP read routine not to list lines as they are read.


:DATA
may be inserted in front of lines that are to be read by the pseudo-function named READ. In batch mode, this will prevent the LISP system from attempting to evaluate these data as expressions should evaluation terminate before all these data are read.

All data lines will be skipped until a :LISP or :END statement is read.


:LOAD
is used in front of lines that are kept in a symbolic element and loaded into LISP via @ADD. :LOAD will put LISP in the :UNLIST mode and will furthermore suppress printing of the EVAL: and VALUE: messages.

:LOAD mode remains in effect until an :END control statement is read, at which time the listing mode is restored to whatever it was before the :LOAD statement was read.


:END
turns off :LOAD or :DATA mode.


:TIME
causes the following message to be printed out

EVALUATION: n1, GARBAGE: n2(n3), MEMORY:n4

where n1 is the number of milliseconds that have been spent during this execution of LISP, n2 is the number of these milliseconds that have been spent collecting garbage, n3 is the number of garbage collections that have been performed, and n4 is the number of words of memory that have been used so far.


:STOP
will leave the 1100 LISP system just as if an EXEC-8 control statement were typed ("@" in column one).


:EXEC @image off
will send @image off to EXEC-8 via a CSF$ request. The "@" must appear in column 7 of this control statement.

This statement is seldom used anymore since the new EXEC-8 system allows you to write @@image and accomplish the same thing.


5.4 CONTROL FUNCTIONS

The functions listed below are similar in purpose to the LISP control statements above, the only difference is that they may be called from within a LISP program. Although they usually won't be used in this dynamic fashion, there are a few cases where this is useful.

(EVAL exp)
will enter the LISP evaluator to evaluate the expression exp in the current environment, i.e. with the current association list.

This is primarily used when you write your own special-forms (via DEFSPEC); the "arguments" to these special-forms are unevaluated LISP expressions and must often be evaluated under control of the special-form.


(ALIST)
will return as its result the current association list (see chapter 4).


(DEFINE s)
s must be a list of the form ( (a1 e1) (a2 e2)...) where each ai is an atomic symbol and each ei is some LISP expression (the ei's will usually be LAMBDA-expressions).

The effect is equivalent to the sequence of statements (CSETQ a1 e1), (CSETQ a2 e2), etc.

The result is the list (a1 a2...).


(DEFSPEC a lexp)
defines the atomic symbol a as representing a special-form. These user-defined special-forms are like functions except that the "arguments" that they receive are the unevaluated LISP expression written after them.

lexp will usually be a LAMBDA-expression that describes the special-form.

If lexp is an atomic symbol that represents an already existing special-form, then a becomes another such atomic symbol.

E.g. (DEFSPEC IF COND)

Special-forms and macros are not LISP objects in the usual sense; they cannot be supplied as arguments to other functions nor can they be returned as results of functions. However, once an atomic symbol is chosen to represent a special-form or macro, you can no longer use that atomic symbol as a variable.

Note that defspec (and defmac below) are very rarely used.

Be sure you understand the caveats concerning them below when using the compiler (chapter 10).


(DEFMAC a lexp)
will establish a as representing a macro using the function lexp.

A macro is just like a user-defined special-form in that it receives unevaluated LISP expressions as "arguments" but its result is evaluated after the function lexp computes it (via eval).

I.e. a macro essentially computes an expression that will evaluate to the desired value instead of computing the value itself.

(LISP)
will cause a new level of supervision to be entered.

The read-eval-print loop will be performed until this level of supervision is exited by doing a (RETURN exp). The value of exp will become the value of the call to LISP.

The definition above in section 5.1 is a description of the LISP supervisor. This is useful in HELP: mode (see below) when you need to go off and do some computing before you can supply the value for help.


(BACKTR flg dl)
will change the default system backtrace mode to flg.

flg may be the atomic symbol T (full backtrace), an integer n (n most recent expressions), or NIL (no backtrace).

dl is optional and if present, must be a consed pair of two integers e.g. (3.7) and will become the print limits used while printing backtraces.

The value of the above will always be the old backtrace flag; the value of the expression (BACKTR) will be the current backtrace flag.


(GROW n)
will expand the 1100 LISP system by n core blocks (one core block = 512 words).

The largest that the 1100 LISP system can get is 131K, which is a grow of about 186 core blocks. Only the very largest of LISP programs should ever need anything close to this much core.

The value of the above expression is an octal number that is the highest core address assigned to the LISP system. The value of the expression (GROW) is the highest address assigned and no growing is done.

Note that because of addressing restrictions in compiled code (see chapter 10), no more than 58 core blocks may be added to the system before any functions are loaded via (LOADfile).


(TIME)
results in the number of milliseconds that have been spent so far in this LISP run.


(GCTIME)
results in the number of milliseconds that have been spent collecting garbage.


(MEMORY)
results in the number of words of memory that have been obtained so far during this LISP run. Note that many of these words have been returned to the LISP system by the garbage collector so that this number in no way reflects the current size of the LISP system.


(DATE)
results in the current date in the form (mo da yr-1900). I.e. on the day that the swallows leave Capistrano this year (1975), the value of (DATE) would be the list (10 23 75).


(DTIME)
results in the current time of day in milliseconds past midnight.


(BREAK a fn)
a must be an atomic symbol that is constantly bound to a function. This establishes fn as a function that will be applied whenever an expression of the form (a...) is evaluated. fn will receive as its arguments the atomic symbol a, the function which it names, and the original arguments to which a was being applied. The result of applying fn to all these arguments will be the value of the original expression. The result is NIL.

The main reason for this pseudo-function is for the debug package (see chapter 7).


(UNBREAK a)
removes the break condition, if any, from the function named a.


5.5 DIAGNOSTICS

The following diagnostics will appear when evaluation cannot proceed.

In most cases, an immediate return to the supervisor is effected and a backtrace is printed according to the backtrace flag (see BACKTR above).

There are a few cases however, where evaluation can proceed if just one value is supplied. In such cases, the 1100 LISP system enters what is known as HELP: mode. It prints out the diagnostic followed by the message HELP:. You may then supply any LISP expression and the value of this expression will be used to continue evaluation. If you do not wish to continue, you can return to the supervisor by typing in :LISP or :BACK.

The :PEEK control statement is useful in HELP: mode to examine the backtrace first. Note that HELP: mode only happens in timesharing mode, in batch mode the LISP system just returns to the supervisor.

UNBOUND x HELP:
x is a variable that you have attempted to evaluate and it has no value, i.e. it is neither a constant nor a current LAMBDA- or PROG-variable, or it might be a LAMBDA-variable in a function to which you supplied too few arguments.

HELP: mode will be entered to request a value and this value will be used to resume evaluation. Note that this value will not become a permanent value for this variable unless you explicitly make it so by SETQ or CSETQ.


CANNOT TAKE CAR OR CDR OF x
x is an atom that you have attempted to take car or cdr of.


WARNING, x CANNOT BE BOUND BECAUSE OF MISSING ARGUMENT
x is a LAMBDA-variable in a function that you have applied to too few arguments. This is only a warning; the function will still be applied as usual. However, if the variable x is ever evaluated, the UNBOUND x diagnostic message will occur.


WARNING, x IS AN ILLEGAL VARIABLE
x is a LAMBDA- or PROG-variable that you shouldn't use since it has been given a constant binding. This is only a warning; evaluation will proceed but the constant value of x will always be used when it is evaluated.


x IS NOT A FUNCTION HELP:
x is either the value of the expression that was written as the first expression in a function application, e.g. value of X in the expression (X ARG1 ARG2), or is the argument to a function that requires another function as one of its arguments (MAP, MAPC, INTO, etc.). x is either a number, string, atomic symbol, or a consed-pair and cannot be used as a function.

HELP: mode is entered and the value resulting (which had better be a function or you will just see this diagnostic again) is used as a function in place of x.

One way to get this diagnostic is if you are used to other LISP systems where one writes things like

(MAPs (QUOTE (LAMBDA... ))).


In the 1100 LISP system, this is written (MAPs (LAMBDA...)) or (MAPs (FUNCTION (LAMBDA...))).


STACK OVERFLOW
The internal push-down stack used during the evaluation of expressions has exceeded its bounds. This is almost always caused by "infinite recursion". No backtrace is provided. If this happens during a garbage collection, it is fatal and the LISP run terminates in error.


MEMORY IS EXHAUSTED
The garbage collector could find no garbage.


GO x ILLEGAL
x is a label that appears in a (GO x) pseudo-function. This label could not be found in the most recent PROG.


ERROR n NOT FOUND
n is an error number in an (ERROR n) expression and could not be found in an ATTEMPT-expression. An (ERROR 4) is performed instead.


CARDS SKIPPED IN DATA MODE
You have attempted to evaluate lines supplied as data and protected by a :DATA control statement. Lines will be skipped until a :LISP or :END control statement is read.


CONTROL CARD MISPELED
a line starting with a colon in column one contains no recognizable LISP control statement.


ERROR IN EXECUTION OF COMPILED CODE
You have executed code that was produced by the compiler attempting to generate code for a poorly defined function.

For example, the code produced for a (GO x), where x is not a valid label can cause this.


EXEC REJECTED: xxxxxxxxxxxx
The image that you sent to EXEC-8 via an :EXEC control statement was not acceptable. xxxxxxxxxxxx is the bit pattern that indicates EXEC-8's objections.


ER ERROR nn: xxxxxx
ILLEGAL INSTRUCTION: xxxxxx
GUARD MODE: xxxxxx
I/O ERROR nn: xxxxxx
SYMB ERROR nn: xxxxxx

A contingency interrrupt has occurred of the indicated type.

nn is the contingency code and xxxxxx is the address of the instruction causing the error. These are usually caused by giving a system-defined function an illegal arguments (like a number when it expects a list).


5.6 STOPPING A RUNAWAY LISP SYSTEM

There are times when you do something that either hangs the LISP system up in a loop or starts it spewing forth more output that you really want to see. If it is printing, you can stop it via the break key on your terminal and then return to the supervisor by typing in @@XOC.

If the system seems to be hung in a loop, just typing in @@XC will suffice.

After it returns to the supervisor, the EVAL: that it usually prints out usually gets lost, so you might want to type in :LISP to verify that you are where you think you are.

The contingency caused by the @@XC returns to the supervisor by doing an (ERROR 3) so you can catch the break-key interrupts with an ATTEMPT-expression if you wish.


5.7 The LISP LIBRARY

There are a few LISP support routines that reside in the LISP library. These routines (editor, compiler, etc.) will be discussed in chapters below.

The LISP library is called LISP*LIB and resides on mass-storage. In general, each routine is kept on the library in two forms, the symbolic element is the routine as it is written in LISP and the absolute element is a dump (via DUMP) of the compiled routine.

To get the symbolic element, you merely type in

     @ADD LISP*LIB.elementname 
The appropriate elementname for each routine will be given in the chapters below.

To get one of the compiled routines you type in

     @@USE LISP,LISP*LIB.
     (LOAD `(LISP.elementname)) 
Once you have done the @@USE, you needn't do it again if you load another compiled routine from the library.

Although the compiled routines are more efficient than the symbolic ones, the difference is not that significant so don't feel that you have to use the compiled routines.

Except for the major entry points (functions named EDIT, COMPILE, etc.) all other function names and variables used by these routines begin with the characters "xx-" where xx is a prefix appropriate to the routine being used.

As long as any atomic symbols that you use do not have hyphens in them, then there will be no name collisions between library routines and yours.

The symbolic routines may be listed if you wish. They do show examples of LISP programs and what prettyprinted output looks like.

You can also, of course, load in a symbolic version and then change it with the editor to do whatever you would like it to do and then prettyprint it into your own file.


Chapter 6
ON INPUT-OUTPUT

This chapter details the input-output pseudo-functions available in 1100 LISP. These have grown slowly over the years and each was inserted in an ad-hoc manner in order to satisfy a pressing need. As a result, there is virtually no coherence to the input-output system of 1100 LISP and there are still some capabilities that one would like to have (like writing into elements) but are currently not available.

We would like to completely redo the input-output system of 1100 LISP and make it one unified package, but this is a low priority project. Therefore this chapter describes the current input-output system, messy as it is.


6.1 INPUT

In general the input routines of 1100 LISP only read from the standard input stream. If it is necessary to include a file or element, it must be inserted into this stream via @ADD.

Each input pseudo-function will gobble up characters from the input stream until it has constructed an appropriate object. The result will be this object and the input routines will be set to begin with the next character in the input stream if called again. All the input routines are oblivious to line boundaries; they essentially pretend that all the input lines are strung out in one long image with at least one blank appearing between any two consecutive lines.

The pseudo-functions associated with input are:

(READ)
results in the next LISP object appearing in the input stream. I.e. a number, atomic symbol, list, etc.

There is no such thing as a syntax error; if the input does not conform to the rules for LISP syntax, the LISP system will make some sense (usually nonsense) out of it.

Of special note is that if the first character in the input stream is a closing bracket (")", "]", or ">") or a period, the result of read will be the atomic symbol that has that character as its print-name.

This function will skip over any initial blanks or commas that it sees. It also does the automatic parenthesis balancing described above.

Furthermore, be warned that the read routine is where the translation from `object to (QUOTE object) takes place. If you have data that contains apostrophes that you are going to read yourself, this translation will still happen. (See below under readmacros.)


(READCH)
results in an atomic symbol whose print name is the same as the next character in the input stream, whether it be a letter, digit, or LISP punctuation mark. Due to the way EXEC-8 handles input lines, the number of blanks that may appear between successive lines is unpredictable. If a LISP control statement appears in the input stream, it is still recognized and processed; the colon and following characters on that line are not read by readch.


(TOKEN)
will result in either an atom (in which case the result is the same as (READ)), or a non-blank punctuation mark (in which case the result is the same as if (READCH) were used).


(REQUEST x)
is equivalent to (DO (PRINT x) (EVAL (READ))).


(CLEARBUFF)
The input buffer is cleared out so that input will continue from the next input line. If the input routine is already at the beginning of a line, then nothing happens. The result is NIL.


(SETCOL n)
n must be an integer between 0 and 128; the input routine will be set so that it begins reading characters from column n of the current line. (SETCOL 0) is equivalent to (CLEARBUFF). The result is NIL.


(BACKSP)
will back up the input routine one character if possible. If a character was backed over, the result is T. If the input routine was at the beginning of a line, the result is NIL and nothing happens.


6.2 OUTPUT

The output routines of the 1100 LISP system take LISP objects and edit their appropriate character representations into an internal line buffer and then print this buffer when it is full.

Be sure that you understand about the output conventions of 1100 LISP detailed in 5.2.

The following pseudo-functions are used for output in the 1100 LISP system:

(PRINT x)
the object x is edited into its external character representation beginning at the next column of the internal buffer and then the buffer is sent to the standard printer (your terminal or line printer). If the buffer overflows during editing, then more than one line will be printed.

The result is x.


(PRIN1 x col)
The object x is edited into its external character representation beginning in column col of the internal buffer. The buffer is not printed unless it overflows during editing, and if it does overflow, editing continues in column col of the next buffer. col is optional and if omitted, editing begins in the next column and will continue in column 1 after buffer overflow.

The result is x.


(PRIN2 x col)
is just like PRIN1 except that x is edited into a format that can be read by the LISP input routine. In particular, prin2 places double quotes (") around strings and inserts exclamation marks in front of punctuation marks that appear in atomic symbols. However, prin2 does not allow you to print functions or other unprintable objects and read them back in.


(TERPRI fl)
If there is anything in the internal buffer, it is printed in the file whose name is fl. fl must be an atomic symbol whose print name is the same as an internal file name that has been assigned to this run. I.e. fl is either a @USE name or a filename without qualifier; you cannot have an "*" in fl nor may it end with a period. If fl is omitted, output goes to the standard output device.

Once a fl has been specified, this file is used for all further output (like via print) until either another terpri is done or a return is made to the LISP supervisor, in which case the default output device becomes the standard one.

Note that the internal buffer will contain something, and terpri will therefore have an effect, only when prin1 or prin2 have been used. The result is NIL.

All the files used as alternate outputs will be closed automatically if LISP terminates normally. If LISP terminates in error, you must close them yourself by @BRKPT filename (no period).

To close a file while still in LISP, you type in @@BRKPT filename (still no period).


(SPACE n)
Will set the spacing on the next line so that n lines will be skipped before it is printed. The skip stops at the top of the next page if it is encountered before n lines are skipped.

(SPACE 0) unconditionally skips to the top of the next page. (SPACE 0)causes the next line to be overprinted. The result is NIL.


(CURRCOL)
yields the next column of the internal line buffer that is due to receive a character.


(PLENGTH x)
is the number of characters which would be used if the object x were edited using prin1 but no editing is actually done.


(PLENGTH2 x)
is the number of characters that would be used if the object x were edited using prin2 but no editing is actually done.


(PLIMIT dl)
dl must be a consed pair of two integers, (d . l).

d becomes the depth at which non-atomic objects will be printed as "&" and l becomes the length of a list after which the rest of the elements are printed as "--".

The reason for these limits is twofold. First, if a circular or self-containing object is printed, it will not generate an infinite amount of output.

The second reason is that if all the detail of a large and deeply nested object were printed, it would be almost impossible to see any of the overall structure.

By only printing down to certain levels, enough detail is eliminated that the overall structure is more apparent.

The initial limits are set at (10 . 50) for everything except backtracing. The value returned by plimit is the old limits so that they can be restored if necessary.

(PLIMIT) will merely retrieve the current limits.


6.3 NON-LISP PARSING

Whenever you are doing your own input-output of objects that do not easily conform to the LISP syntax, it usually becomes necessary to read characters one at a time and build your own atomic symbols or whatever when you need to. The following functions are used for manipulating strings, atomic symbols, and the like in an input-output related manner.

(STRING a)
a must be an atomic symbol. The value will be a string which will be the print-name of a. For example,(EQUAL (STRING `A) "A") is true.


(ATSYMB s)
s must be a string. The value will be the atomic symbol whose print-name is s, i.e. the atomic symbol will be unique. E.g. (EQ (ATSYMB "A") `A) is true.


(COMPRESS cl)
cl must be a list of atomic symbols or strings. The value is the object that would be created by the input pseudo-function named TOKEN if it were to scan a line consisting of the first characters of the elements of cl.

Normally, cl is a list of one character atomic symbols and they are compressed into a single atomic symbol.

Note that compression stops as soon as a LISP punctuation mark other than an apostrophe is found. (COMPRESS `(A BB "CDE" !> F G H I)) = ABC.


(EXPLODE x)
gives a list with each element being a one character atomic symbol that corresponds to a character that would be edited by (PRIN1 x). E.g. (EXPLODE "ABC") = (EXPLODE `ABC) = (A B C).


(EXPLODE2 x)
gives a list with each element being a one character atomic symbol that corresponds to a character that would be edited by (PRIN2 x).

Note that for atomic symbols, strings, and numbers, compress and explode2 are inverses of each other.


(DELIM c f)
This is a pseudo-function that allows you to specify which characters are to be treated as punctuation marks.

c must be a string representing the character in question and f is either T (set delimiter) or NIL (clear delimiter).

For example, doing a (DELIM "+" T) will cause AB+CD to be read as three atomic symbols (AB, +, and CD) instead of just one.

The value returned is the old delimiter flag so that it can be restored if desired. (DELIM "c") merely retrieves the current delimiter flag for the character c.


(READMAC c fn)
The readmacro feature of 1100 LISP allows you to take control of the input routine when certain characters are seen.

c is a string representing the character in question and fn is either a function of no arguments (set readmacro) or NIL (clear readmacro).

The value is the old readmacro or NIL depending on whether the character had an associated readmacro or not.

If a readmacro is set for a character, each time that character is the first character seen by read (not by token or readch) the function of no arguments is applied. The result of applying that function will be taken as the object read.

The readmacro may itself perform reads, tokens, or readchs in order to obtain the desired object.

To give you a feel for the use of readmacros, the following are supplied by the system (the actual code is more efficient than this, but the effect is identical).

     (READMAC "`" (LAMBDA() (LIST `QUOTE (READ))))

     (READMAC "?" (LAMBDA() (CLEARBUFF) (READ))) 

     (READMAC "," (LAMBDA() (READ)))

Thus to change the system comment character to a semicolon you can do

     (READMAC ";" (READMAC "?" F))

     (DELIM ";" (DELIM "?" F))
Note that !, ", and blank, though not associated with readmacros in the strict sense since they are also recognized by token, are flagged as readmacros and may be changed if desired.


6.4 DUMP LOAD

There are presently two methods of saving functions or other objects on mass storage for later use. The first is to use the prettyprinter (see chapter 9), which has the advantage of printing out function definitions in a readable format so that they can be listed or changed by @EDIT if desired.

However, compiled code or other circular objects may not be saved using the prettyprinter. A more general method is to use the pseudo-function named DUMP, which will let you save any kind of object whatsoever.

The call is:

(DUMP x fl)
fl must be either an atomic symbol that represents an internal file name of a file assigned to this run (dumping will begin in sector zero) or must be a consed pair of two atomic symbols (f . e).

f must be an internal filename as above and e is an element name within this program file (x will be dumped as an element of type absolute in element e).

What gets dumped is not only the object x, but everything that can be reached by following pointers that start at the object x.

This means, for instance, that if x is an atomic symbol, its constant value will also be dumped if it has one, as will any entries on its property list. Thus (DUMP 'FN 'DUMPFILE) will save the function you have named FN if there is one since that is the constant value of FN; furthermore; if this function uses any other functions, they will be dumped also since they can be reached from pointers starting at FN.

There is absolutely no restriction on what can be dumped. No matter how complex, circular, or self-containing the object x is, when it is loaded back in it will have the same structure, including all circularities.

If fl is omitted on the call to dump, then dumping continues beyond where it left off on the last dump.

To load a dumped object back in, you do:

(LOAD fl)
where fl specifies either a file or an element as in dump.

(LOAD) will cause loading to continue from where the last load left off.

The object loaded will be copied back into core with the same structure that it had when it was dumped.

If a dumped atomic symbol had a constant value, it will be re-established with the loaded constant value taking precedence if it already had one. Any entries on a dumped property list will be added to the property list if not already there and will replace old entries if the indicators are already there.

The primary purpose of dump and load is to save and restore compiled code that has been generated from function definitions. Due to addressing restrictions on the 1100, you cannot load any compiled code after you have expanded memory past 65K (58 blocks).

Be warned that dumped LISP objects takes up a suprisingly large amount of mass storage space due to the record keeping that is necessary to preserve the structure of the object when it is loaded. You will find that a dumped function definition takes up about 2 to 3 times as much mass storage as the prettyprinted definition.


Chapter 7
DEBUGGING LISP PROGRAMS

Along with the backtrace described above, the 1100 LISP system provides a powerful set of functions for monitoring the execution of a program.

The debug package is written in LISP and resides in the LISP library. It is loaded by typing in:

     @ADD LISP*LIB.DEBUG   or   @@USE LISP,LISP*LIB.FTE
                                (LOAD `(LISP.DEBUG))
The major pseudo-functions in the debug package are those called $TRACE, $BREAK, $TRACEV and $UNBUG.

The auxiliary pseudo-function called $BRKPT is also available for use if desired. Each of these pseudo-functions is described below.


7.1 $TRACE

The pseudo-function named $TRACE allows you to conditionally trace the entry to and exit from functions. It is designed to be simple enough for use in most normal situations while still providing a capability for complex conditional monitoring of function execution. This flexibility is attained by providing default values for its various arguments.

The complete form of the calling sequence is:

($TRACE fns e1 s1 e2 s2)
where fns is an atomic symbol that names a function, special-form, or macro, or fns is a list of such atomic symbols.

e1 and e2 are LISP expressions and s1 and s2 are lists of expressions.

Each time one of the functions indicated by fns is entered, e1 is evaluated. If its value is NIL, function application then proceeds as usual. Otherwise each of the expressions in s1 is evaluated and each value printed before applying the function.

If s1 is the atomic symbol T, the LAMBDA-variables in the function are printed along with their corresponding arguments.

After the function has computed its result, e2 is evaluated and if non-NIL each expression in s2 is evaluated and printed.

In any case the function is exited as usual.

e1, e2 and the expressions in s1 and s2 may reference the arguments passed to the function via the variable $ARGS and the expressions ($1) ,, ($2), etc. where $ARGS gives the entire list of arguments and ($n) gives the nth argument. In most cases, uncompiled functions are being traced and the arguments can also be referenced by their corresponding LAMBDA-variables.

Thus you may reference the two arguments of a function created by (LAMBDA (L V)... ) by ($1) and ($2), or (CAR $ARGS) and (CADR $ARGS), or by L and V and the expressions listed in s2 may reference the result of the function via the variable $VAL. This gives the capability of onditionally tracing the exit from a function depending on its result.

Since in most cases you don't need the full power of the complete trace routine, any of the arguments may be omitted and their omission will cause various default interpretations. Of course, if an argument is present, the arguments preceding it must also be present.

The default interpretations are:

     e1     T       (trace unconditionally)
     s1     T       (print arguments)
     e2     e1      (trace result if entry traced)
     s2     `($VAL) (print result of function)


The following examples show some of the possibilities:

($TRACE `(f1 f2...))
causes each of the functions f1, f2, etc. to be traced unconditionally, with the arguments printed upon entry and the value upon exit.


($TRACE `FUNC `(NULL ( $1 )))
causes the function named FUNC to be traced only when its first argument is NIL.


($TRACE `FUNCT `([$1] [LENGTH($2)]))
causes the function named FUNC to be unconditionally traced, with its first argument and the length of its second argument printed on entry and its result printed on exit.


($TRACE `FUNC T T F)
causes the function named FUNC to be traced on entry but not on exit.


($TRACE TRFNS T NIL T `(TREE))
causes each of the functions in the list bound to TRFNS to be traced, with no expressions printed on entry and the value of the atomic symbol TREE printed on exit.

The following example shows what a part of a session with LISP would look like if tracing were used.

@ADD LISP*LIB.DEBUG

VALUE: DEBUG PACKAGE LOADED

EVAL: (CSETQ LENGTH(LAMBDA(L)
        (COND
          ( (NULL L) 0) 
          ( T (PLUS 1 (LENGTH (CDR L> 

VALUE:  [LENGTH]

EVAL:  ($TRACE `LENGTH)

VALUE:  T

EVAL:  (LENGTH `(A B))

>ENTERING LENGTH [0]
 L: (A B)
    >ENTERING LENGTH [1]
     L: (B)
        >ENTERING LENGTH [2]
         L: NIL
        <LEAVING  LENGTH [2]
         $VAL: 0  
    <LEAVING  LENGTH [1]
     $VAL: 1
<LEAVING  LENGTH [0]
 $VAL: 2

VALUE: 2
The level numbers ([0], [1], etc.) are printed to make it easier to identify corresponding enter-exit pairs.


7.2 $BREAK

The pseudo-function named $BREAK allows you to conditionally interrupt the execution of a function as it is entered or exited. It is similar to the debugging function named $TRACE except that instead of printing the values of a given set of expressions, a read-eval-print loop is entered to give you an opportunity to interrogate the status of your program. A function may be either traced or broken, but not both.

The complete form of a call on $BREAK looks like:

($BREAK fns e1 e2)
where fns is as described above under $TRACE and e1 and e2 are LISP expressions.

Each time one of the functions indicated by fns is entered, e1 will be evaluated. If its value is NIL, application proceeds as usual. Otherwise a read-eval-print loop is entered; you may type in expressions which will be evaluated and their values printed. This loop will continue until you type in T and application of the function then proceeds.

When the function has computed its result, another read-eval-print loop is entered if e2 evaluates to non-NIL. Again, you stay in the loop until you type in T.

The arguments and result of the function being broken may be referenced in the same manner as in $TRACE above.

If e1 or e2 are omitted, the default values are:

     e1     T     (break unconditionally)
     e2     e     (break exit if entry broken)


For example, doing:

($BREAK `FUNC `($2) F)
causes the function named FUNC to enter a read-eval-print loop only when it is entered with its second argument being non-NIL.


7.3 $TRACEV

The debugging function named $TRACEV allows you to monitor the values assigned to specified atomic symbols via the functions or special-forms named SET, SETQ, CSET, and CSETQ.

There are two calling sequences:

($TRACEV ats) or ($TRACEV ats e)
where ats is either an atomic symbol or a list of atomic symbols and e is any LISP expression.

If e is not present, a message of the form "*CSETQ var:value" is printed each time that the binding of one of the atomic symbols indicated by ats has its binding changed via a "SET" type of operation.

If e is present, then the message is printed only if the value of e is non-NIL, and in addition, a read-eval-print loop is entered to allow you to examine the state of affairs. This happens just before the value of the variable is changed and as usual, a T gets you out of the loop.

The new value that is about to be assigned may be referenced by the variable $VAL.

For example, the following will cause a read-eval-print loop to happen each time one of the indicated atomic symbols is set to NIL.

($TRACEV `(A1 A2 A3) `(NULL $VAL))


7.4 $UNBUG

Doing an:

($UNBUG ats)
where ats is either an atomic symbol or a list of atomic symbols will remove all tracing, breaking, or value tracing from the atomic symbols listed in, or the function named in, ats.

Functions must be unbugged before they can be edited or pretty-printed (see below).

The expression ($UNBUG) will cleanse everything in the world.


7.5 $BRKPT

The functions named $BREAK and $TRACEV both use this function to enter a read-eval-print loop. You may also use it to establish breakpoints at interesting locations.

($BRKPT x)
will cause x to be printed and a read-eval-print loop to be entered.


7.6 Miscellaneous

There are very few restrictions on what can and what cannot be traced or broken.

Functions can be traced whether they are defined by the user, supplied by the system, or have been compiled.

However if you do wish, for some obscure reason, to trace a system-defined function, be advised that the debug package was written in LISP and may also use this system-defined function and you might get in an infinite loop trying to trace this function. This problem only occurs in the version of the debugging package that you get when you @ADD the element LISP*LIB.DEBUG, when you load the compiled version with (LOAD `(LISP.DEBUG)) this will not occur due to use of the function called MANIFEST (see below, chapter 10).

The following information may prove useful to provide even more control over the debugging package.

The normal print-depth and print-length limits used during debugging are 3 and 5 and are kept as a consed pair bound to DB-LIMIT.

These limits may be changed if desired, e.g.

(CSETQ DB-LIMIT `(2 . 7))
Both the tracing and breaking functions maintain level counters to keep track of depth of nested function calls.

If debugging terminates abnormally, these may be erroneous. All you need to do is to set them back to 0, e.g.

(CSETQ DB-TLEV (CSETQ DB-BLEV 0))
It is possible to change part of the message printed when a function is entered or exited. For example, to cut down on terminal output, you can do a (CSETQ DB-ETEXT "+") and the message will be changed from ">ENTERING func[n]" to +func[n].

The variable to change for the exit message is DB-LTEXT.

It is good practice to turn off all debugging (via ($UNBUG)) before dumping any functions, since you might otherwise have problems when you load what you dumped. All functions that are loaded will automatically be unbugged; this is of no serious consequence but it may surprise you occasionally. Problems will arise, however, if you are doing any value-tracing ($TRACEV) when you do a load. It is therefore stongly recommended that you turn off all value-tracing before loading anything.


Chapter 8
ON THE LISP EDITOR

The LISP editor allows you to change and repair LISP objects; its primary purpose is to fix faulty function definitions.

It is loaded by typing in:

     @ADD LISP*LIB.EDIT   or   @@USE LISP,LISP*LIB.
                               (LOAD `(LISP.EDIT))
The main special-form (because it automatically "quotes" its argument) of the LISP editor is called EDIT. To edit a LISP object, you type in (EDIT atsym) where atsym is an atomic symbol to which the object to be edited is constantly bound. E.g. to fix a function, you type in (EDIT func) where func is the atomic symbol that names the function.

Note that you don't type in (EDIT `func).

The editor works by focusing on a certain subpart of the object to be edited. This subpart may be changed or the focus can be changed via the various editing commands.

When you start the editor it is focused on the entire object and is ready to accept editing commands.

You can put as many editing commands on one line as you wish; they will be performed from left to right.

The usual mode is to do the necessary commands to focus on the subobject to be changed, then do the command to effect the change, and end with a final P to see what you did.

The editing commands are:


P
The command P causes the current object to be printed. The form used is (-- x1 x2 x3 x4 x5 --).

This means that you are focused on a segment of a list that begins with x1. The -- after x5 means that there are more elements to the right of x5; if there are fewer than 5 elements left in the list, the -- and extra xi's will not be there.

The -- before x1 means that there are some elements to the left of x1 in the list (this arises when you use the M command).

Any non-atomic object at a depth greater that 2 will be printed as &.

For example, if we enter (EDIT FUNC) the editor could respond with

(LAMBDA ( NV ) (COND ( & NIL ) ( T &)))
Typing a positive integer causes the editor to descend one level. If our current focus is (-- x1 x2 ...), typing a 1 sets x1 as the focus, 2 makes x2 the current focus, and so forth.

The object descended to is not printed, so you must also include a P command if you want to see it.


-n
A negative integer causes the editor to ascend that many levels back out of the object into which you have descended.

E.g. doing a -1 gets us back to where we were before the last positive integer was typed.

An absurdly large negative integer like -9999 will get us back to the entire object.


M -n
The M (move) command moves us horizontally in the current object.

If the current focus is (-- xi xj ...), doing any Mn changes it to (-- xi+n xj+n...).

I.e. positive n means move right and negative means move left.

The reason for the move command is that editing changes happen starting with the first xi printed in the focus (not the beginning of the list).

You need to move to the right to make changes in the middle of a list.

It is not necessary to move back to the left end of a list before ascending out of it.


D
The D (delete) command deletes the current focus and automatically ascends one level (i.e. does a -1).

For example, if we are focused on ( A ( B C ) D ) doing 2 D P gives us ( A D ). Warning! So would 2 M 1 D P; the horizontal position in an object has no effect on the D command.


R exp
To replace the current object, type an R (replace) followed by an expression that evaluates to the new object. This means that the new object will usually have to be quoted.

The object that is replaced is the rest of the list after the elements that have been moved over by a M+n. Study the following examples carefully.

If we start with ( A ( B C ) D ), doing 2 R `X -1 P gives ( A X D ), 2 M 1 R `X -1 P gives ( A ( B . X ) D ), 2 M 1 R NIL -1 P gives ( A ( B ) D ), and 2 M 1 R `(X) -1 P gives ( A ( B X ) D ).


C exp1 exp2
To change all occurrances of something in an object, type a C followed by an expression that evaluates to the object to be changed and then an expression that evaluates to the object to change it to.

For example, starting with ( A ( A ( B A ) ) B ), 2 C `A `X -1 P gives ( A ( X ( B X ) ) B ) and 2 M 1 C `A `X -1 P would give ( A ( A ( B X ) ) B ).


I exp
To insert an object, type I followed by an expression that evaluates to the object to be inserted. This object will be inserted to the left of the first element of the list printed in the current focus and becomes the new first element printed.

E.g. if we are looking at (-- x1 x2... ), doing an I `X gives (-- X x1 x2... ).

From ( A ( B C ) D ), 2 I `X -1 P gives ( A ( X B C ) D ) while 2 M 1 I `X -1 P gives ( A ( B X C ) D ).


G n
The G (group) command is used to insert parentheses.

The first n elements in the current focus will be grouped into a list and become the first element. E.g. from (A B C D), doing a M 1 G 2 M -1 P gives ( A ( B C ) D ).


U
The U (ungroup) command takes the first element of the current focus, which must be a list, and appends it to the focus.

( A ( B C ) D ) becomes ( A B C D ) after M 1 U M -1 P


S name
The S (save) command must be followed by an atomic symbol. This atomic symbol becomes a name for the current focus just as if we had done a (SETQ name focus).

This is used to rearrange lists.

For example, starting with ( A ( B C ) D ), doing 2 S AT D I AT gives ( ( B C ) A D ).


E exp
The E (evaluate) command simply evaluates the expression exp. It is used when you need to go back into LISP and compute something before continuing with editing.


STORE
The STORE command is the signal that you are done.

The edited object will be placed as the constant binding for the atomic symbol edited.


RESTORE
RESTORE restores the object back to its original state before editing started. It is used mainly when you make a mistake and can't recover (like deleting too much).

Note that if you just want to browse around in an object, RESTORE STORE is a nice way to leave with the assurance that nothing has been changed.

The LISP editor's only diagnostic is a question mark which it prints whenever you do something that doesn't make sense, like M 5 when there are only 4 elements to move over.

The current focus is unchanged after this diagnostic. If an illegal command appears in the middle of a sequence of commands on one line, all the rest are ignored.

The print-depth and print-length limits used by the editor are constantly bound to the symbol ED-LIMIT and may be changed if desired. E.g.

(CSETQ ED-LIMIT `( 4 . 7 ))
The initial value is (3 . 5).


Finally, there is another function which may be of use in special applications of the editor. The function named EDIT1 takes any LISP object as its argument, enters the editor to solicit commands, and returns the edited object when STORE is typed.

If, for instance, you have an object tucked away on a property-list that you want to edit, you might do something like

(PUT `AT `IND ( EDIT1 ( GET 'AT 'IND )))



Chapter 9
ON THE LISP PRETTYPRINTER

The LISP prettyprint package allows you to print out function definitions and property list entries in a readable format, or to dump them into a file where they can be stored for later use.

The prettyprint package is loaded by typing:

     @ADD LISP*LIB.PRETTYP   or   @@USE LISP,LISP*LIB. 
                                  (LOAD `(LISP.PRETTYP))
The major pseudo-function of the prettyprint package is called PRETTYP and will print out constant bindings (function definitions) or property list entries.

The call is:

(PRETTYP s)
Where s is a list of designators, each of which has one of the following forms:


a (atomic symbol)
Prettyprint the object which this atomic symbol represents. a may represent anything whatsoever, including functions, special-forms, or macros, as long as it is not circular (i.e. contains itself as a subobject). Note that recursively defined functions are not circular; they contain their own names, but not themselves and can therefore be prettyprinted.


( i a1 a2 ... an )
For each of the atomic symbols a1 ... an, prettyprint the property list entry for the indicator i.


"c"
Prettyprint the readmacro (see chapter 6) and delimiter flag for the character c.

In each case, the print starts with the proper (CSETQ a, (DEFSPEC a, (DEFMAC a, (PUT `a `i, or (READMAC "c" so that the thing being prettyprinted will be re-established if reloaded.

To write the output in a file instead of on your terminal you must assign a file and supply its name as a second argument like so:

     @@ASG,T DUMPFILE  
     (PRETTYP stuff `DUMPFILE)
The above will cause the designated objects to be prettyprinted into DUMPFILE surrounded by a :LOAD/:END pair. stuff will be quoted and placed at the end as an indication of what was dumped. Thus if stuff was the list ( F1 F2 (IND F3 F4 )),then DUMPFILE would look like:

:LOAD
(CSETQ F1 ...


(CSETQ F2 ...


(PUT `F3 `IND ...


(PUT `F4 `IND ...


:END
 
`(F1 F2 (IND F3 F4))
After the file has been closed (see below) this information could be reloaded by typing in @ADD DUMPFILE. in this or a later LISP session.

The "value" of this @ADD will be ( F1 F2 ( F3 F4 )) to indicate that the restoration has been done.

Alternately, a third argument may be given to prettyp that will be placed in the file after the :END. For example:

(PRETTYP stuff `DUMPFILE "FUNCTIONS LOADED")
After using the prettyprinter to dump to a file, that file remains open and more information may be dumped into it later. The file will be closed automatically when LISP terminates, unless it terminates in error.

The safe thing to do is to always close the file yourself when you are done with it by typing in (no period after filename):

     @@BRKPT filename
Such files are in SDF format and can be listed with @DATA or @EDIT.

Note that you can currently only prettyprint to a data file. If you want it kept in an element, you must copy it in later by perhaps a @COPY,I.

For examples of prettyprinted output and how to use the prettyprinter, you can list one of the following elements: LISP*LIB.EDIT, LISP*LIB.COMPILER, LISP*LIB.PRETTYP, or LISP*LIB.DEBUG.

Lines printed will not extend past column 72. To change this parameter (like when prettyprinting on the line printer), CSETQ the atomic symbol PP-WIDTH to the maximum column desired.

When prettyprinting functions that have been placed on property lists, a search is made to see if any atomic symbol is constantly bound to that function, and if found, just (PUT `a `ifuncname) is dumped, otherwise the actual LAMBDA-expression is dumped.

If you attempt to print an object that can't be printed (e.g. a function that has been compiled), a search is made for another atomic symbol that is constantly bound to the same object. If one is found, its name is printed, e.g. (CSETQ SUMPLUS).

Otherwise "**UNDEF**" will be printed as its value. To notify you of such mistakes, the result returned by the function named PRETTYP is a list of every designator for which prettyprinting could not be effected.


Chapter 10
The LISP Compiler

The 1100 LISP system normally acts as an interpreter that reads expressions and evaluates them. However, when one is developing a large system and has functions that have already been tested and debugged, he sometimes would like to compile them so that they run more efficiently.

For this purpose the 1100 LISP compiler is used. The compiler will use the definition of the function to generate machine code. This code will be placed in core and thereafter be used whenever the function is applied, just as if it were a hand-coded, system-defined function.

It must be emphasized that the compiler is designed to be used on correct, bug-free functions only. The compiler gives almost no diagnostics and the code generated from a badly defined function will error out in exotic and wonderful ways.

It should also be mentioned that there is no necessity to use the compiler after a function is working thinking that efficiency is going to improve by a few orders of magnitude. Compiled code is faster than interpreted code by a factor that ranges between about 5 and 30. This is not because the code generated is slow, it is instead because the 1100 LISP interpreter is so fast.


10.1 Using the COMPILER

The compiler is loaded by typing:

     @ADD LISP*LIB.COMPILER   or   @@USE LISP,LISP*LIB.
                                   (LOAD `(LISP.COMPILER))
The major entry to the compiler is the pseudo-function named COMPILE.


To compile a group of functions type:

(COMPILE s)
Where s is a list of designators, each of which has one of the following forms:

fnn
compile the function, special-form, or macro indicated by the atomic symbol fnn.


(i a1 a2 ... an )
For each of the atomic symbols a1 ... an, compile the function on its property list under the indicator i.

For example, (COMPILE `( F1 F2 ( IND F3 ))) will generate machine code for the functions named F1 and F2 and the function on the property list of F3 under the indicator IND. All this code will be placed in core and will be used instead of the old functions defined as LAMBDA-expressions.


10.2 FREE VARIABLES

Normally, that is all one needs to do in order to use the compiler. However, there is one situation where the compiler needs some extra information: when free variables are used. Free variables are those variables that are used in a function and have neither a constant binding nor are they a LAMBDA- or PROG-variable in that function (which means that they must be a variable in some other function).

The compiler does not know whether these variables are constants that have yet to be defined, or are fluid variables that must be handled by the association-list mechanism. By convention, the compiler assumes that such free variables are constants unless told otherwise via the declaration:

(FLUID `( v1 v2 ... vn ))
Any variable that is used free in a function to be compiled, or which appears as a LAMBDA- or PROG-variable in a function to be compiled but is referenced as a free variable in some other lower-level function, must be declared fluid before compilation. After compiling all functions that either bind or reference a free variable, they may be declared unfluid by


(UNFLUID `( v1 ... vn ))
This allows subsequent functions in which the variables appear as ordinary local variables to be compiled in an optimal manner.

As an aid to discovering free occurrences of variables, the result returned by the compiler is a list of all atomic symbols that the compiler assumed were constants. This does not include those atomic symbols that had constant bindings at compile time since the compiler knows that they are constants.

If any of these are in fact supposed to be fluid variables, you must declare them fluid, restore the function definition as a LAMBDA-expression, and re-compile.


10.2.1 When free variables aren't really free

There are some cases where variables which appear free in a LAMBDA-expression needn't be declared fluid since the compiler is smart enough to reference them directly.

The necessary conditions are: (1) The LAMBDA-expression is written directly as the function in an expression, e.g. (( LAMBDA ...) ...), or as an argument to one of the system functions named MAPC, MAP, PROP, or OBLIST, and (2) the referenced variable is bound in the function being compiled (in a higher level LAMBDA or PROG).

Thus when compiling

(LAMBDA ( X L ) ... (MAPC L ( LAMBDA ( Y ) ... X... )))
X needn't be declared fluid even though it appears free in the second LAMBDA-expression.


10.2.2 Linking between compiled and interpreted functions

There is another somewhat more subtle situation where variables must be declared fluid, involving calls from a compiled function to the LISP interpreter. Ordinary variables are assigned a location on the push-down stack (see chapter 4) and addressed directly in compiled code. The interpreter, however, accesses variables by looking them up on the association list. Thus any variables which are passed unevaluated to the interpreter must appear on the association list and must therefore be declared fluid.

There are three ways by which a compiled function can cause the interpreter to be entered.

The first is when a function is applied which simply hasn't been compiled yet. This is really no problem since you must do the same thing regarding free variables whether that function is compiled or not. The second two cases are fortunately extremely rare. The second involves explicit calls to the evaluator. For example, if V is a variable, ( EVAL ( LIST `FNN `V)) will cause V to be evaluated by the interpreter if it isn't constant, so it must be declared fluid. The last way to enter the interpreter is to use the function named SET (SETQ is handled automatically by the compiler). For example, if V is a variable and L gets bound to the list ( V... ), the expression ( SET (CAR L)...) will cause V to be passed to the interpreter to be found on the association list.


10.3 SPECIAL FORMS

Special-forms that you have defined yourself (via DEFSPEC) may be compiled just as normal functions. Care must be taken, however, if the special-form (which it usually will) contains any calls to the evaluator. Other functions pass unevaluated expressions to these special-forms, which may eventually evaluate these expressions. In such a case any variables used in the unevaluated expression must be declared fluid when the function using the special-form is compiled.


10.4 MACROS

The compiler handles macros by expanding them at compile-time and then compiling the resultant expression. The macro itself needn't be compiled, although if often used it might be.

After compiling all functions that use a particular macro, it can be discarded; it will not be needed at run-time.

Note that this only works for "nice" macros; it does not work for macros which expand as a function of the run-time environment, or which have any run-time side-effects. Such macros should be written as special-forms if you insist on doing such things.


10.5 MISCELLANEOUS



10.5.1 Usage of GROW

It is recommended (although not necessary) that functions to be compiled be loaded or defined before expanding memory (GROW n) beyond 65K (58 blocks). This allows compiled code to access addresses directly instead of thru index registers.

After loading all the functions to be compiled, core may be expanded beyond this limit if desired either before or after compilation.

It is imperative, however, that compiled code that has been dumped (via DUMP) be subsequently loaded before expanding memory beyond 65K.


10.5.2 MANIFEST

1 The expression (MANIFEST x) is equivalent to x when interpreted. However, using this expression in a function to be compiled tells the compiler that the value of x can be computed at compile-time, so the compiler will evaluate it then instead of generating the code necessary to evaluate it at run-time.

It is used when you write unnecessarily complex LISP expressions in order to "parameterize" your program. Once the parameters have been chosen, the expressions in which they appear may only have to be evaluated once at compile-time.


10.5.3 EXCISE

1 The normal use of the compiler is to compile some functions and then save them (using DUMP). However, there are a number of flags and things left hanging around by the compiler which will be dumped also, and hence will be with you forever after. To get around this, type in (EXCISE) when you are all through compiling to remove the compiler and all of its associated flags from core.


10.5.4 Listing

The compiler works by generating a pseudo-machine code before generating the actual 1100 code. In certain cases it is helpful (more often just interesting) to look at this code and see just what the compiler thinks of your function (especially useful for debugging the compiler!).

To have this code printed out on your terminal or line printer, enter a second argument to the compiler thus:

(COMPILE clist T) 
The intermediate code for each function will be listed as it is compiled.

This code is for the most part self-explanatory. If it's not, then you probably shouldn't be printing it out anyway.


10.5.5 Special functions for the compiler

There are a few system functions that the compiler and other system routines need in order to get at function definitions, emit compiled code, and the like. These will be briefly described below. You should never need these functions unless you are really doing some system-type programming.

In any case, you shouldn't be using them unless you know exactly what you are doing.

(*CAR x)
is the same as (CAR x) except that it may be applied to atoms without the system objecting.

(*CDR x)
is the counterpart of (*CAR x).


(*EXAM x n)
yields an octal integer which is the contents of the nth word following the object x. n is optional and if omitted, 0 is assumed.


(*DEPOSIT v x n)
deposits the octal integer v in the nth word following the object x in memory. If n is omitted, 0 is assumed. The result is v.


(*DEF fn)
yields the LAMBDA-expression that is used to create the function fn, which must be an object of type 6 (see iftype above). If fn is anything else, the result is NIL.


(*SPEC sf)
Same as *DEF except that sf must be a special-form created by defspec.


(*MACRO m)
Same as *DEF except m must be a macro defined by defmac.


(*CHAIN x)
yields an octal number reflecting the car's and cdr's needed for the functions named CR, CAR, CAAR, CADAR, etc. If x is not a car-cdr chain, the result is NIL.


(*BEGIN)
prepares for the emission of a new section of compiled code.

The result is the address where the code following the last *begin was emitted.


(*ORG x)
sets things up so that compiled code will be emitted starting at x.


(*EMIT i a)
emits one instruction of compiled code. i is an octal integer that is the instruction and a is a pointer that will be added to this instruction.


(*EPT n)
yields the nth entry point to the LISP system.

These entry points are the places where compiled code needs to jump to unwind the stack, look up variables on the association list, etc.


Chapter 11
PROPERTY LISTS

Associated with each atomic symbol in LISP is a thing called a property list.

A property list is a list of consed-pairs (called attribute-value pairs) or atomic symbols (called flags).

The attribute-value pairs are used to store a value under that attribute of the atomic symbol in question. Flags are used to indicate a particular condition by their presence or absence.

An attribute or a flag is represented by some atomic symbol that you choose; it will usually have some mnemonic name.

Note that only atomic symbols can have property lists; they cannot be attached to numbers, lists, or strings.

The following functions are used to manipulate property lists.

(PUT a i v)
will put the object v on the property list of the atomic symbol a under the attribute i. The result is the object v.

If there is already an entry for i on the property list of a, v replaces the old one, if not, a new one is created.


(GET a i)
will yield the value associated with the attribute i on the property list of the atomic symbol a. If there is no such value, the result is NIL.


(REMPROP a i)
will remove the attribute i and its associated value from the property list of the atomic symbol a. The result is a.


(PROP a i fn)
If an entry for i exists on the property list of the atomic symbol a, the result will be the entry, i.e. i consed with its associated value. If there is no entry for i, the result is the function fn of no arguments applied to no arguments.


(FLAG a flg)
will put the flag flg on the property list of the atomic symbol a. The result will be a.


(IFFLAG a flg)
will be true iff the flag flg appears on the property list of the atomic symbol a. Note that (GET a flg) and (IFFLAG a flg) are not necessarily the same.


(UNFLAG a flg)
removes the flag flg from the property list of the atomic symbol a. The result is a.

For an illustration of how property lists and flags can be used, you can study the LISP compiler in LISP*LIB.COMPILER.

Note especially how functions to do the special processing for special-forms and other interesting functions are just hung out on the property lists of the appropriate atomic symbols and their mere presence activates the special processing.


Chapter 12
FUNCTIONS

One of the powerful features of LISP is its ability to handle functions just as other data. In 1100 LISP, this ability is even more powerful because not only can they be supplied as arguments to other functions, but they can be computed as results of other functions.

What can be done with this power has, frankly, not been explored much yet because it is an area where people just haven't trained themselves to think as easily and naturally as in other areas (like algebra, calculus, or Fortran).

The major problem as far as LISP is concerned in this area is that of free variables.

Free variables are variables that are used in some LAMBDA-expression but are not LAMBDA-variables in that LAMBDA-expression, nor are they constants.

The value that such variables will have is that value which they have currently in time; but in virtually all cases, the value that you want such variables to have is the value that they had when you wrote them.

Consider the following. Suppose we define the function named INTO so:

(CSETQ INTO (LAMBDA (X FN)
  (COND
    ( (NULL X) NIL)
    ( T (CONS (FN (CAR X)) (INTO (CDR X) FN)))))) 
and having defined that, suppose we attempt to use it to define another function that will take a list of numbers and increase each one by a given amount like so:

(CSETQ ADDTO (LAMBDA (L X)
  (INTO L (LAMBDA (I) (PLUS I X)))))
One would hope that the result of (ADDTO `( 1 2 3 ) 4) would be the list (5 6 7). Unfortunately, if it is written exactly as above the result will be gibberish. The reason is that the variable X in the expression (PLUS I X) will, by the time it gets around to being evaluated, have the same value as the variable X used in the definition of into, which is the list being "intoed".

In the above case this problem could be solved by merely renaming the variable X to some other (carefully chosen) atomic symbol. In many LISP systems this is in fact, the only possible solution.

This is not a satisfactory solution for two reasons.

First, it is possible to construct cases (although it isn't clear that any useful cases can be constructed) where it just isn't possible to rename variables in such a manner to avoid collisions like the above (you do it by making a variable collide with itself).

The second reason is that any solution of this nature is doomed to failure anyway.

Just ponder the following function:

(CSETQ COMPOSE (LAMBDA (F1 F2)
  (LAMBDA (X) (F1 (F2 X)))))
The result of applying this function to two other functions is the composition of those two functions. ((COMPOSE CAR CDR) `(A B C)) = B (CADR `(A B C)) = B.

As written, this will not work since by the time you get around to applying the composition, which is the function created by (LAMBDA (X) ... ) above, the bindings for F1 and F2 have long since disappeared.

If you are tempted to dismiss examples such as this as being useless, I can assure you that the reason that you think they are useless is that you have never used them before. And the reason for that is that you have never had a programming language that allowed you to do such things before.

On the other hand, maybe you have done things like this before without realizing it.

Remember how you think of a matrix as a function that you can apply to a vector and transform it into another vector? And remember how you multiply two matrices to compute the composition of the functions they represent?

Anyway, the solution to the above problems is that whenever a function is created, information must also be created that tells the bindings of all the free variables in that function. The solution is quite easy to effect (in 1100 LISP, that is).

All that has to be done is that when a function is created, part of that function is the environment (association list, see chapter 4) in which it was created. This association list is retrieved just before the function is applied to any arguments and the LAMBDA-variables for that function are bound starting with this association list.

In 1100 LISP there are two methods of accomplishing this.

(FUNCTION fn)
will compute a function that is just like the function fn except it will effectively be applied using the current environment.

In general, whenever you use LAMBDA to create a function that has free variables, you should write (FUNCTION (LAMBDA... )) instead.

To users of other LISP systems, notice that the function named FUNCTION only solves the free variable problem, it in no way serves as a mechanism for "quoting" functions, which is unnecessary in 1100 LISP.

(LAMDA ( v1 v2 ... vn ) e1 e2... en )
(Note spelling.) is just like (LAMBDA ...) except that the current environment is also captured and will be used to evaluate any free variables in the ei's. The fact that LAMDA is not the normal mode in LISP is a flaw and has been perpetrated throughout all the LISP systems because of the spectre called compatability.


Appendix A

The following is an alphabetical list of all the atomic symbols that are used to name system-defined functions, special-forms, or library support functions. These should not be used as variables in LISP programs. You may use them as names for functions as long as you realize that you are going to destroy the normal function of that name.

ADD1  . . . . . . . . . . . . . . . . . . . . . . 3-9  
ALIST . . . . . . . . . . . . . . . . . . . . . . 5-6
AMB . . . . . . . . . . . . . . . . . . . . . . . 3-6
AND . . . . . . . . . . . . . . . . . . . . . . . 3-11
APPEND  . . . . . . . . . . . . . . . . . . . . . 3-4
ASSOC . . . . . . . . . . . . . . . . . . . . . . 3-5
ATOM  . . . . . . . . . . . . . . . . . . . . . . 3-3
ATSYMB  . . . . . . . . . . . . . . . . . . . . . 6-5
ATTEMPT . . . . . . . . . . . . . . . . . . . . . 3-14
BACKSP  . . . . . . . . . . . . . . . . . . . . . 6-2
BACKTR  . . . . . . . . . . . . . . . . . . . . . 5-8
BREAK . . . . . . . . . . . . . . . . . . . . . . 5-8
CAR . . . . . . . . . . . . . . . . . . . . . . . 3-2
CDR . . . . . . . . . . . . . . . . . . . . . . . 3-3
C...R . . . . . . . . . . . . . . . . . . . . . . 3-3
CLEARBUFF . . . . . . . . . . . . . . . . . . . . 6-2
COMPILE . . . . . . . . . . . . . . . . . . . . . 10-1 
COMPRESS  . . . . . . . . . . . . . . . . . . . . 6-5
COND  . . . . . . . . . . . . . . . . . . . . . . 3-11
CONS  . . . . . . . . . . . . . . . . . . . . . . 3-3
CSET  . . . . . . . . . . . . . . . . . . . . . . 3-11
CSETQ . . . . . . . . . . . . . . . . . . . . . . 3-11
CURRCOL . . . . . . . . . . . . . . . . . . . . . 6-4
DATE  . . . . . . . . . . . . . . . . . . . . . . 5-8
DEFINE  . . . . . . . . . . . . . . . . . . . . . 5-7
DEFMAC  . . . . . . . . . . . . . . . . . . . . . 5-7
DEFSPEC . . . . . . . . . . . . . . . . . . . . . 5-7
DELIM . . . . . . . . . . . . . . . . . . . . . . 6-6
DIFFERENCE  . . . . . . . . . . . . . . . . . . . 3-8
DO  . . . . . . . . . . . . . . . . . . . . . . . 3-1
DTIME . . . . . . . . . . . . . . . . . . . . . . 5-8
DUMP  . . . . . . . . . . . . . . . . . . . . . . 6-7
EDIT  . . . . . . . . . . . . . . . . . . . . . . 8-1
EDIT1 . . . . . . . . . . . . . . . . . . . . . . 8-4
ENTIER  . . . . . . . . . . . . . . . . . . . . . 3-9
EQ  . . . . . . . . . . . . . . . . . . . . . . . 3-3
EQUAL . . . . . . . . . . . . . . . . . . . . . . 3-3
ERASE . . . . . . . . . . . . . . . . . . . . . . 3-7
ERROR . . . . . . . . . . . . . . . . . . . . . . 3-14
EVAL  . . . . . . . . . . . . . . . . . . . . . . 5-6
EXCISE  . . . . . . . . . . . . . . . . . . . . . 10-4
EXPLODE . . . . . . . . . . . . . . . . . . . . . 6-5
EXPLODE2  . . . . . . . . . . . . . . . . . . . . 6-6
F . . . . . . . . . . . . . . . . . . . . . . . . 2-2
FIXP  . . . . . . . . . . . . . . . . . . . . . . 3-10
FLAG  . . . . . . . . . . . . . . . . . . . . . . 11-1
FLOATP  . . . . . . . . . . . . . . . . . . . . . 3-10
FLUID . . . . . . . . . . . . . . . . . . . . . . 10-2
FUNCTION  . . . . . . . . . . . . . . . . . . . . 12-2
GCTIME  . . . . . . . . . . . . . . . . . . . . . 5-8
GENSYM  . . . . . . . . . . . . . . . . . . . . . 3-6
GET . . . . . . . . . . . . . . . . . . . . . . . 11-13
GO  . . . . . . . . . . . . . . . . . . . . . . . 3-13
GREATERP  . . . . . . . . . . . . . . . . . . . . 3-10
GROW  . . . . . . . . . . . . . . . . . . . . . . 5-8
IFFLAG  . . . . . . . . . . . . . . . . . . . . . 11-13
IFTYPE  . . . . . . . . . . . . . . . . . . . . . 3-6
INDEX . . . . . . . . . . . . . . . . . . . . . . 3-8
INTO  . . . . . . . . . . . . . . . . . . . . . . 3-7
LAMBDA  . . . . . . . . . . . . . . . . . . . . . 3-12
LAMDA . . . . . . . . . . . . . . . . . . . . . . 12-3
LEFTSHIFT . . . . . . . . . . . . . . . . . . . . 3-9
LENGTH  . . . . . . . . . . . . . . . . . . . . . 3-5
LESSP . . . . . . . . . . . . . . . . . . . . . . 3-10
LISP  . . . . . . . . . . . . . . . . . . . . . . 5-7
LIST  . . . . . . . . . . . . . . . . . . . . . . 3-4
LOAD  . . . . . . . . . . . . . . . . . . . . . . 6-7
LOGAND  . . . . . . . . . . . . . . . . . . . . . 3-9
LOGOR . . . . . . . . . . . . . . . . . . . . . . 3-9
LOGXOR  . . . . . . . . . . . . . . . . . . . . . 3-9
MANIFEST  . . . . . . . . . . . . . . . . . . . . 10-4 
MAP . . . . . . . . . . . . . . . . . . . . . . . 3-7
MAPC  . . . . . . . . . . . . . . . . . . . . . . 3-7
MAPCAR  . . . . . . . . . . . . . . . . . . . . . 3-7
MAPLIST . . . . . . . . . . . . . . . . . . . . . 3-7
MEMBER  . . . . . . . . . . . . . . . . . . . . . 3-4
MEMORY  . . . . . . . . . . . . . . . . . . . . . 5-8
MINUS . . . . . . . . . . . . . . . . . . . . . . 3-9
MINUSP  . . . . . . . . . . . . . . . . . . . . . 3-10 
NCONC . . . . . . . . . . . . . . . . . . . . . . 3-5
NIL . . . . . . . . . . . . . . . . . . . . . . . 2-2
NOT . . . . . . . . . . . . . . . . . . . . . . . 3-4
NTH . . . . . . . . . . . . . . . . . . . . . . . 3-5
NULL  . . . . . . . . . . . . . . . . . . . . . . 3-4
NUMBERP . . . . . . . . . . . . . . . . . . . . . 3-10 
OBLIST  . . . . . . . . . . . . . . . . . . . . . 3-6
ONDEX . . . . . . . . . . . . . . . . . . . . . . 3-8
ONTO  . . . . . . . . . . . . . . . . . . . . . . 3-7
OR  . . . . . . . . . . . . . . . . . . . . . . . 3-11
PLENGTH . . . . . . . . . . . . . . . . . . . . . 6-4
PLENGTH2  . . . . . . . . . . . . . . . . . . . . 6-4
PLIMIT  . . . . . . . . . . . . . . . . . . . . . 6-4
PLUS  . . . . . . . . . . . . . . . . . . . . . . 3-8
PRETTYP . . . . . . . . . . . . . . . . . . . . . 9-1
PRIN1 . . . . . . . . . . . . . . . . . . . . . . 6-3
PRIN2 . . . . . . . . . . . . . . . . . . . . . . 6-3
PRINT . . . . . . . . . . . . . . . . . . . . . . 6-3
PROG  . . . . . . . . . . . . . . . . . . . . . . 3-13
PROP  . . . . . . . . . . . . . . . . . . . . . . 11-1
PUT . . . . . . . . . . . . . . . . . . . . . . . 11-1
QUOTE . . . . . . . . . . . . . . . . . . . . . . 3-10 
QUOTIENT  . . . . . . . . . . . . . . . . . . . . 3-8
READ  . . . . . . . . . . . . . . . . . . . . . . 6-1
READCH  . . . . . . . . . . . . . . . . . . . . . 6-2
READMAC . . . . . . . . . . . . . . . . . . . . . 6-6
REMAINDER . . . . . . . . . . . . . . . . . . . . 3-9
REMPROP . . . . . . . . . . . . . . . . . . . . . 11-1 
REQUEST . . . . . . . . . . . . . . . . . . . . . 6-2
RETURN  . . . . . . . . . . . . . . . . . . . . . 3-13 
REVERSE . . . . . . . . . . . . . . . . . . . . . 3-5
RPLACA  . . . . . . . . . . . . . . . . . . . . . 3-3
RPLACD  . . . . . . . . . . . . . . . . . . . . . 3-4
SET . . . . . . . . . . . . . . . . . . . . . . . 3-14 
SETCOL  . . . . . . . . . . . . . . . . . . . . . 6-2
SETQ  . . . . . . . . . . . . . . . . . . . . . . 3-14 
SPACE . . . . . . . . . . . . . . . . . . . . . . 6-4
STACK . . . . . . . . . . . . . . . . . . . . . . 3-12 
STRING  . . . . . . . . . . . . . . . . . . . . . 6-5
SUB1  . . . . . . . . . . . . . . . . . . . . . . 3-9
SUBST . . . . . . . . . . . . . . . . . . . . . . 3-5
T . . . . . . . . . . . . . . . . . . . . . . . . 2-2
TERPRI  . . . . . . . . . . . . . . . . . . . . . 6-3
TIME  . . . . . . . . . . . . . . . . . . . . . . 5-8
TIMES . . . . . . . . . . . . . . . . . . . . . . 3-8
TOKEN . . . . . . . . . . . . . . . . . . . . . . 6-2
UNBREAK . . . . . . . . . . . . . . . . . . . . . 5-8
UNFLAG  . . . . . . . . . . . . . . . . . . . . . 11-2 
ZEROP . . . . . . . . . . . . . . . . . . . . . . 3-9
*BEGIN  . . . . . . . . . . . . . . . . . . . . . 10-6 
*CAR  . . . . . . . . . . . . . . . . . . . . . . 10-5 
*CDR  . . . . . . . . . . . . . . . . . . . . . . 10-5 
*CHAIN  . . . . . . . . . . . . . . . . . . . . . 10-6 
*DEF  . . . . . . . . . . . . . . . . . . . . . . 10-5 
*DEPOSIT  . . . . . . . . . . . . . . . . . . . . 10-5 
*EMIT . . . . . . . . . . . . . . . . . . . . . . 10-6 
*EPT  . . . . . . . . . . . . . . . . . . . . . . 10-6 
*EXAM . . . . . . . . . . . . . . . . . . . . . . 10-5 
*MACRO  . . . . . . . . . . . . . . . . . . . . . 10-6 
*ORG  . . . . . . . . . . . . . . . . . . . . . . 10-6 
*SPEC . . . . . . . . . . . . . . . . . . . . . . 10-6 
$BREAK  . . . . . . . . . . . . . . . . . . . . . 7-3
$BRKPT  . . . . . . . . . . . . . . . . . . . . . 7-5
$TRACE  . . . . . . . . . . . . . . . . . . . . . 7-1
$TRACEV . . . . . . . . . . . . . . . . . . . . . 7-4
$UNBUG  . . . . . . . . . . . . . . . . . . . . . 7-5