4.2BSD/usr/lisp/ch13.n

." $Header: /na/franz/doc/RCS/ch13.n,v 1.1 83/01/31 07:08:37 jkf Exp $
.Lc The\ CMU\ User\ Toplevel\ and\ the\ File\ Package 13
.ch 2 Introduction
This documentation was written by Don Cohen, and the functions described below
were imported from PDP-10 CMULisp.
.sp 1v
\fINon CMU users note:\fP this is not the default top level for your Lisp
system.  In order to start up this top level, you should type
\fI(load\ 'cmuenv)\fP.

.sh 2 User\ Command\ Input\ Top\ Level 13

The top-level is the function that reads what you type, evaluates it
and prints the result.  The \fInewlisp\fP top-level was inspired by the
CMULisp top-level (which was inspired by interlisp) but is much
simpler.  The top-level is a function (of zero arguments) that can be
called by your program.  If you prefer another top-level, just redefine
the top-level function and type "(reset)" to start running it.  The
current top-level simply calls the functions tlread, tleval and tlprint
to read, evaluate and print.  These are supposed to be replaceable by
the user.  The only one that would make sense to replace is tlprint,
which currently uses a function that refuses to go below a certain
level and prints "...]" when it finds itself printing a circular list.
One might want to prettyprint the results instead.  The current
top-level numbers the lines that you type to it, and remembers the last
n "events" (where n can be set but is defaulted to 25).  One can refer
to these events in the following "top-level commands":
.Eb
\fITOPLEVEL COMMAND SUMMARY\fP

??	prints events - both the input and the result.  If you just type
	"??" you will see all of the recorded events.  "?? 3" will show
	only event 3, and "?? 3 6" will show events 3 through 6.

redo	pretends that you typed the same thing that was typed before.  If
	you type "redo 3" event number 3 is redone.  "redo -3" redoes the
	thing 3 events ago.  "redo" is the same as "redo -1".

ed	calls the editor and then does whatever the editor returns.  Thus
	if you want to do event 5 again except for some small change, you
	can type "ed 5", make the change and leave the editor.  "ed -3"
	and "ed" are analogous to redo.
.Ee
Finally, you can get the value of event 7 with the function (valueof 7).
The other interesting feature of the top-level is that it makes outermost
parentheses superfluous for the most part.  This works the same way as in
CMULisp, so you can use the help for an explanation.  If you're not sure
and don't want to risk it you can always just include the parentheses.

.Lf top-level
.Se
.i top-level
is the  LISP top level function.   As well
as  being the  top level  function with  which  the user
interacts, it can be  called recursively by the  user or
any function.  Thus, the  top level can be  invoked from
inside the editor, break package, or a user  function to
make its commands available to the user.
.No
The  CMU
.Fr
top-level   uses  
.i lineread
rather  than  
.i read.
The difference will not usually be noticeable.  The principal thing to be
careful  about is that input  to the function or  system being called
cannot appear  on the same line as the  top-level call.  For example,
typing \fI(editf foo)fP on one  line will edit 
.i foo  
and evaluate P, not edit
.i foo 
and execute the  p command in the editor.  
.i top-level
specially recognizes the following commands:

.Lf valueof "'g_eventspec"
.Re
the value(s) of the event(s) specified by g_eventspec.  If a single
event is specified, its value will be returned.  If more than one event
is specified, or an event has more than one subevent (as for
.i redo,
etc), a list of vlaues will be returned. 

.sh 2 The\ File\ Package

Users typically define functions in lisp and then want to save them for
the next session.  If you do \fI(changes)\fP, a list of the functions that are
newly defined or changed will be printed.  When you type \fI(dskouts)\fP, the
functions associated with files will be saved in the new versions of
those files.  In order to associate functions with files you can either
add them to the \fIfilefns\fP list of an existing file or create a new file to
hold them.  This is done with the 
.i file
function.  If you type \fI(file new)\fP
the system will create a variable called 
.i newfns.  
You may add the names of the functions to go into that file to 
.i newfns.  
After you do \fI(changes)\fP,
the functions which are in no other file are stored in the value of the
atom
.i changes.  
To put these all in the new file, \fI(setq newfns (append newfns changes))\fP.
Now if you do \fI(changes)\fP, all of the changed functions
should be associated with files.  In order to save the changes on the
files, do \fI(dskouts)\fP.  All of the changed files (such as NEW) will be 
written.  To recover the new functions the next time you run 
.Fr , 
do \fI(dskin new)\fP.
.Eb
Script started on Sat Mar 14 11:50:32 1981
$ newlisp
Welcome to newlisp...
1.(defun square (x) (* x x))		; define a new function
square
2.(changes)				; See, this function is associated
					; with no file.
<no-file>      (square)nil
3.(file 'new)				; So let's declare file NEW.
new
4.newfns				; It doesn't have anything on it yet.
nil
5.(setq newfns '(square))		; Add the function associated
(square)				; with no file to file NEW.
6.(changes)				; CHANGES magically notices this fact.

new            (square)nil
7.(dskouts)				; We write the file.
creating new
(new)
8.(dskin new)				; We read it in!
(new)
14.Bye
$ 
script done on Sat Mar 14 11:51:48 1981

.Ee

.Lf changes "s_flag"
.Re
Changes computes a list containing an entry for each file which
defines atoms that have been marked changed.  The entry contains the
file name and the changed atoms defined therein.  There is also a 
special entry for changes to atoms which are not defined in any known
file.  The global variable 
.i filelst
contains the list of "known" files.  If no flag is passed this result 
is printed in human readable form and the value returned is t if there
were any changes and nil if not.  Otherwise nothing is printed and the
computer list is returned.  The global variable
.i changes
contains the atoms which are marked changed but not yet associated
with any file.  The
.i changes
function attempts to associate these names with files, and any that are not
found are considered to belong to no file.  The
.i changes
property is the means by which changed functions are associated with
files.  When a file is read in or written out its
.i changes
property is removed.
.Lf dc "s_word s_id [ g_descriptor1  ... ] <text> <esc>"
.Re
.i dc
defines comments.  It is exceptional in that its behavior is very
context dependent.  When 
.i dc
is executed from 
.i dskin
it simply records the
fact that the comment exists.  It is expected that in interactive mode
comments will be found via 
.i getdef
- this allows large
comments which do not take up space in your core image.  When 
.i dc
is executed from the terminal it expects you to type a comment.  
.i dskout
will write out the comments that you define and also copy the comments on the
old version of the file, so that the new version will keep the old comments
even though they were never actually brought into core.
The optional id is a mechanism for distinguishing among several
comments associated with the same word.  It defaults to nil.  However
if you define two comments with the same id, the second is considered
to be a replacement for the first.  
The behavior of
.i dc
is determined by the value of the global variable
.i def-comment.
.i def-comment
contains the name of a function that is run.
Its arguments are the word, id and attribute list.  
.i def-comment
is initially 
.i dc-define.
Other functions rebind it to 
.i dc-help,
.i dc-userhelp,
and the value of 
.i dskin-comment.
The comment property of an atom is a list of entries, each representing
one comment.  Atomic entries are assumed to be identifiers of comments on
a file but not in core.  In-core comments are represented by a list of the
id, the attribute list and the comment text.  The comment text is an
uninterned atom.  Comments may be deleted or reordered by editing the
comment property.

.Lf dskin "l_filenames"
.Se
READ-EVAL-PRINTs the contents of  the given files.  This
is the function to use to read files created by 
.i dskout.
.i dskin
also declares the files that it reads (if a 
.i file-fns
list is defined and the file is otherwise declarable by 
.i file
), so that changes to it can be recorded.

.Lf dskout "s_file1 ..."
.Se
For each file specified,
.i dskout
assumes  the  list named
filenameFNS (i.e.,  the file name,  excluding extension,
concatenated  with  
.i fns
)  contains  a  list  of function
names, etc., to be loaded
Any previous version of the file will be renamed  to have extension
".back".
.Lf dskouts "s_file1 ..."
.Se
applies
.i dskout
to and  prints the name  of each
s_filei   (with   no   additional    arguments,   assuming
filenameFNS to be a list to be loaded) for  which s_file\fIi\fP
is either not in \fIfilelst\fP  (meaning it is a new  file not
previously declared by \fIfile\fP  or given as an  argument to
\fIdskin\fP, \fIdskouts\fP, or \fIdskouts\fP) or is in \fIfilelst\fP and has some
recorded changes to definitions of atoms in filenameFNS,
as recorded by \fImark!changed\fP and noted by changes.
If \fIfile\fPi  is not  specified, \fIfilelst\fP  will be
used.  This  is the  most common  way of  using dskouts.
Typing  \fI(dskouts)\fP  will  save  every  file  reported  by
\fI(changes)\fP to have changed definitions.

.Lf dv  "s_atom g_value"
.Eq
\fI(setq atom 'value)\fP.
.i dv
calls  
.i mark!changed.
.Lf file "'s_file"
.Se
declares its argument to be a file to be used for reporting and saving
changes to functions by adding the file name to a list of files, 
.i filelst.
.i file
is called for each file argument of 
.i dskin,
.i dskout,
and 
.i dskouts.
.Lf file-fns "'s_file"
.Re
the name of the fileFNS list for its file argument s_file.
.Lf getdef "'s_file ['s_i1 ...]"
.Se
selectively executes definitions for atoms s_i1 ... from the
specified file.  Any of the words to be defined which end with "@"
will be treated as patterns in which the @ matchs any suffix
(just like the editor).  
.i getdef
is driven by
.i getdeftable
(and thus may be programmed).  It looks for lines in the file that start
with a word in the table.  The first character must be a "(" or "["
followed by the word, followed by a space, return or something else that will
not be considered as part of the identifier by 
.i read,
e.g., "(" is unacceptable.  When one is found the next word is read.  If
it matches one of the identifiers in the call to 
.i getdef 
then the table entry is executed.  The table entry is a function of the
expression starting in this line.  Output from
.i dskout
is in acceptable format for 
.i getdef.
.i getdef
.Re
a list of the words which match the ones it looked for, for which it found
(but, depending on the table, perhaps did not execute) in the file.
.No
.i getdeftable
is the table that drives 
.i getdef.
It is in the form of an association list.  Each element is a dotted pair
consisting of the name of a function for which
.i getdef
searches and a function of one argument to be executed when it is found.
.Lf mark!changed "'s_f"
.Se
records the fact that the definition of s_f has been changed.  It is
automatically called by 
.i def,
.i defun,
.i de,
.i df,
.i defprop,
.i dm,
.i dv,
and the editor when a definition is altered.