SHARE LISP differs somewhat from the LISP 1.5 system described in
the LISP 1.5 Programmer's Manual, but only in (generally)
inessential details. It is hoped that the changes will be widely
hailed as improvements.
Verbos and the Garbage CollectorThe garbage collector now prints its message in a single-spaced
format; thus, the amount of paper generated by a program with
many cons'es is somewhat less than formerly. Furthermore, the
garbage collector printout may be suspended by executing
"VERBOS(NIL)"; and the printout may be reinstated by executing
"VERBOS(*T*)".
Flap TrapEvery now and then a state of affairs known as floating-point
trap occurs - this results when a floating-point arithmetic
instruction generates a number whose exponent is too large in
magnitude for the eight-bit field reserved for it. When this
trap occurs and the offending exponent is negative, the obvious
thing to do is to call the result zero. The old system, however,
simply printed out a "FLAP TRAP" error message and went on to the
next pair of S-expressions to be evaluated. The new system
stores a floating-point zero in the accumulator when an underflow
occurs. (There has, as yet, been no request to have "infinity"
stored in the accumulator when an overflow occurs.)
TimeThe new system prints the time upon entering and leavingevalquote. In fact, two times are printed, but in a neat,
concise, impersonal manner which, it is felt, is more suitable to
the "age of automation" than the quote from Lewis Carroll. The
times are printed in minutes and milliseconds; the first time is
the age of the packet - by definition, this is zero whenevalquote is first entered - and the second time is the age of
the system being used. Thus, when evalquote is left, the time
printout tells how much time was spent in the execution of the
packet and how much time has been spent in execution of SET or
SETSET packets since the birth of the system plus the time spent
in the packet being finished. This time printout, to be
meaningful, requires the computer to have a millisecond clock in
cell 5 (RPQ F 89349, with millisecond feature).
It is also possible to determine how much time is required to
execute a given function "TIME1( )" initializes two time cells
to zero and prints out, in the same format that is used for theevalquote time printout, two times, and these are both zero.
"TIME()" prints (again in the evalquote time printout format) the
time since the last execution of "TIME()" and the time since the
last execution of "TIME1()". The use of the time and time1functions has no effect on the times recorded by evalquote.
Lap and SymtabHeretofore, lap has not only returned the symbol table as its
value but has printed it out as well. This phenomenon is
familiar to those who have much at all to do with lap or thecompiler. The lap in the new system always prints the function
name and the octal location in which the first word of the
assembled function is stored. (If the assembled function is not
a SUBR or FSUBR, then only the octal origin of the assembled code
is printed.) The printout is left-Justified on the output page
and has the form "<function name> (ORIGIN xxxxxQ)".
The value of lap is still the symbol table, but the printing of
the symbol table may be suspended by executing "SYMTAB(NIL)", and
the printing may be restored by executing "SYMTAB(*T*)".
Non-Printing CompilerThe problem of the verbosity of the compiler is only slightly
abated by the symtab function. The remainder of the trouble may
be cured by executing "LISTING(NIL)". This turns off the
printout of the lap code generated by the compiler. And, of
course, the printout may be reinstated by executing
"LISTING(*T*)". Thus, for a perfectly quiet compilation (except
for the origin printout by lap), one need only execute
"SYMTAB(NIL)" and "LISTING(NIL)" before compiling.
Tracecount (Alarm-Clock Trace)The trace feature of LISP is quite useful, but, with very little
encouragement, it can be made to generate wastebaskets full of
useless output. Often a programmer will find that his output
(without tracing) consists of many lines of garbage collector
printout, an error message, and a few cryptic remarks concerning
the condition of the push-down list at the time the error
occurred. In such a situation, one wishes he could begin tracing
only a short time before the occurrence of the error. The
tracecount function permits exactly this. "TRACECOUNT(x)" causes
the tracing (of those functions designated to be traced by the
trace function call) to begin after x number of function
entrances. Furthermore, when the tracecount mechanism has been
activated, by execution of "TRACECOUNT(x)", some of the blank
space in the garbage collector printout will be used to output
the number of function entrances which have taken place up to the
time of the garbage collection; each time the arguments or value
of a traced function are printed the number of function entrances
will be printed; and if an error occurs, the number of function
entrances accomplished before the error will be printed.
The tracecount feature (or alarm-clock trace, as it is called by
Marvin Minsky of M. I. T.) enables a programmer to run a job
(preceding the program by "TRACE -COUNT(O)"), estimate the number
of function entrances that occur before the program generates an
error condition or a wrong answer, and then run the job again,
tracing only the pertinent portion of the execution.
Space and EjectA small amount of additional control over the form of the data
printed by LISP has been provided in the space and ejectfunctions.
"SPACE(*T*)" causes all output to be double-spaced. "SPACE(NIL)"
restores the spacing to its original status, in particular, the
output of the print routine reverts to single-spacing, and the
"END OF EVALQUOTE OPERATOR" printout again ejects the page before
printing.
"EJECT()" causes a blank line with a carriage control character
of 1 to be printed on the output tape. The result is a skip to
the top of the next page of output.
UntimeThis routine is not available to the programmer, but its mention
here may prevent some anxiety. In the event that the program
time estimate is exceeded during system I/O, using the old
system, one finds himself in the position of having part of one
system and part of another stored in core or on the SYSTMP. This
situation would be intolerable if the programmer were trying to
save some definitions so that he could use them later. To avoid
this unpleasantness, the system I/O routines have been modified
so that the clock is, in essence, turned off during system I/O
and three seconds is automatically added to the elapsed time at
the conclusion of the read or write operation (in a machine with
a millisecond core clock this is the case - machines with 1/60
second core clocks add 50 seconds, but this is easily changed).
A clock trap that would normally have occurred during the
execution of the read or write will be executed before the I/O
operation takes place.
TapeA few programmers with very large programs have long bemoaned the
inability of LISP to communicate between different systems. The
functions tape, rewind, mprmt, mread, andbackspace have been designed to alleviate this difficulty. "TAPE(s)",
where s is a list, allows the user to specify up to ten scratch tapes;
if more than ten are specified, only the first ten are used. The value
of tape is its argument. The initial tape settings are, from one
to ten, A4, A5, A6, A7, A8, B2, B3, B4, B5, B6. The tapes must
be specified by the octal number that occurs in the address
portion of a machine-language instruction to rewind that tape;
that is, a four-digit octal number is required - the first
(high-order) digit is a 1 if channel A is desired, 2 if channel B
is desired; the second digit must be a 2; the third and fourth
are the octal representation of the unit number. Thus, to
specify that scratch tapes one, two, and three are to be tapes
A4, Bl, and A5, respectively, execute "TAPE ((1204Q 2201Q
1205Q))". Only the low-order fifteen bits of the numbers in the
tape list are used by the tape routines, so it is possible to use
decimal integers or floating-point numbers in the tape list
without generating errors.
Rewind"REWIND(x)" rewinds scratch tape x, as specified in the most
recently executed tape function. For example, if the last tape
function executed was "TAPE ((1204Q 2201Q))", then "REWIND(2)"
will cause tape B1 to be rewound. The value of rewind is NIL.
Mprint"MPRINT(x s)" prints the S-expression s on scratch tape x. The
format of the output is identical to the normal LISP output,
except that sequence numbers are printed in the rightmost eight
columns of the output line and the output line is only 80
characters long (the scratch tape output is generated by the
punch routine), and is suitable for punching or being read bymread. The value of mprint is the list printed.
Mread"MREAD(x)" reads one S-expression from scratch tape x. The value
of mread is the S-expression read.
Backspace"BACKSPACE(x)" causes scratch tape x to be backspaced one record.
Caution in the use of this function is recommended, for if an
S-expression to be read from tape contains more than 72
characters, then it will occupy more than one record on the tape,
and single backspace will not move the tape all the way back to
the beginning of the S-expression. The value of backspace is
NIL.
EvalquoteEvalquote is available to the programmer as a LISP function -
thus, one may now write "(EVALQUOTE APPEND ((A)(B C D)))", rather
than "(EVAL (QUOTE (APPEND (A)(B C D))) NIL)", should one desire
to do so.
BacktraceThis function was copied (not quite literally) from M. I. T.'s
LISP system on the time-shared 7094. Backtrace is a function of
no arguments in which the manner of specifying the no arguments
constitutes, in effect, an argument. The first call ofbacktrace, with any argument, or with none, suspends backtrace
printouts when errors occur. Thereafter, the value of "BACKTRACE
NIL" is the backtrace for the most recent error; and "BACKTRACE
x", for x not NIL, restores the backtrace printout to the error
routine. Backtrace should always be evaluated by evalquote.
Read-In ErrorsA common cause of free-storage or circular list printouts is an
error (in parenthesis count, usually) during the initial read-in
of a packet. The new system causes the accumulator to be cleared
if an error occurs during the initial read-in, so that the
contents of the accumulator are printed as "NIL".
ObkeepAnyone desperate for a few more words of free storage may make up
a list, s, of all atom names he wants to retain in his personal
LISP systems, then execute (in a SET packet) "OBKEEP(s)". All
atoms except those which are members of s will be eliminated from
the object list.
Reserved"RESERVED NIL" prints the names of the atoms on the object list
in alphabetical order, along with the indicators (not
alphabetized, and flags may be missed) on their property lists.
This function should help to solve some of the problems that
arise involving mysterious behavior of compiled functions that
worked fine when interpreted.
Gensym and SymnamGensym now omits leading zeroes from the numeric portions of the
print-names of the symbols it generates, thus, what once looked
like "G00001" now prints as "G1". Furthermore, it is possible to
specify a heading word of from zero to six characters for thegensym symbols by executing symnam. "SYMNAM(NIL)" causes
LISP-generated symbols to have purely numeric print-names (but
they are not numbers). The numeric portions of the print-names
are truncated from the left so as not to overlap the heading
characters. Thus, "SYMNAM(AAAAA)" causes gensym to produce
distinct atoms with the following (not necessarily distinct)
print-names. AAAAA1, AAAAA2, .... AAAAA9, AAAAAO, AAAAA1, ....
The argument of symnam must have the indicator PNAME on its
property list. "SYMNAM(12)" will cause undefined results.
IfFor the convenience of those who find it difficult to get along
with the "COND" form of the conditional statement, the following
"IF" forms are provided in the new system. "IF (a THEN b ELSE
c)" and "IF (a b c)" are equivalent to "COND ((a b) (T c))". "IF
(a THEN b)" and "IF (a b)" are equivalent to "COND ((a b))".
For"FOR (index
)",
for n less than 17, sets index
to the value of i and skips out of the following loop as soon as
the value of u is not NIL: evaluate u, evaluate
evaluate
, evaluate s, go to the beginning of the loop. If i,
s, and u are numbers, then the for statement is similar to the
ALGOL "for index = i step s until u do begin
end". The value of thefor statement is the value of
the last time it
was evaluated. The final value of index is available outside thefor function because cset is used to set the index.
SublisSublis has been re-hand-compiled so that it behaves as if it were
defined as follows.
sublis[p;e] =
label[suba;
[[e];[
atom[e]
label [subb;
[[x];[
null[x]
e;
eq[caar[x];e]
cdar[x];
T
subb[cdr[x]]
]]][p];
T
[[u;v];[
and[equal[car[e];u];equal[cdr[e];v]]
e;
T
cons[u,v]
]][suba[car[e]];suba[cdr[e]]]
]]][e].
The differences between the new sublis and the old one, as far as
the programmer is concerned, are that the new model is faster and
the result shares as much storage as possible with e.
Characteristics of the SystemThe set-up deck supplied with the SHARE LISP system produces a
system tape with the following properties:
Size (in words) -
Binary Program Space 14000 octal
Push-Down List 5000 octal
Full-Word Space 4220 octal
Free Storage 22400 octal
System Tape (SYSTAP) B7
System Temporary Tape (SYSTMP) B6
System Input Tape (SYSPIT) A2
System Output Tape (SYSPOT) A3
System Punch Tape (SYSPPT) A3
The console switches may be used to obtain special results:
SW1 on for LISP input from on-line card reader
SW2 has no effect
SW3 on for LISP output on on-line printer
SW4 has no effect
SW5 on to suppress SYSPOT output
SW6 on to return to overlord after accumulator printout
resulting from error *F 5*. SW6 off for error printout.