Trailing-Edge
-
PDP-10 Archives
-
decus_20tap1_198111
-
decus/20-0004/09lisp.doc
There are no other files named 09lisp.doc in the archive.
SECTION 9
1
THE INTERLISP EDITOR
The INTERLISP editor allows rapid, convenient modification of list
structures. Most often it is used to edit function definitions, (often
while the function itself is running) via the function editf, e.g.,
EDITF(FOO). However, the editor can also be used to edit the value of a
variable, via editv, to edit a property list, via editp, or to edit an
arbitrary expression, via edite. It is an important feature which
allows good on-line interaction in the INTERLISP system.
This chapter begins with a lengthy introduction intended for the new
user. The reference portion begins on page 9.11.
9.1 Introduction
Let us introduce some of the basic editor commands, and give a flavor
for the editor's language structure by guiding the reader through a
hypothetical editing session. Suppose we are editing the following
incorrect definition of append:
[LAMBDA (X)
Y
(COND
((NUL X)
Z)
(T (CONS (CAR)
(APPEND (CDR X Y]
We call the editor via the function editf:
_EDITF(APPEND)
EDIT
*
The editor responds by typing EDIT followed by *, which is the editor's
prompt character, i.e., it signifies that the editor is ready to accept
------------------------------------------------------------------------
1
The editor was written by and is the responsibility of W. Teitelman.
9.1
2
commands.
At any given moment, the editor's attention is centered on some
substructure of the expression being edited. This substructure is
called the current expression, and it is what the user sees when he
gives the editor the command P, for print. Initially, the current
expression is the top level one, i.e., the entire expression being
edited. Thus:
*P
(LAMBDA (X) Y (COND & &))
*
Note that the editor prints the current expression as though printlevel
were set to 2, i.e., sublists of sublists are printed as &. The command
? will print the current expression as though printlevel were 1000.
*?
(LAMBDA (X) Y (COND ((NUL X) Z) (T (CONS (CAR) (APPEND (CDR X Y))))))
*
and the command PP will prettyprint the current expression.
A positive integer is interpreted by the editor as a command to descend
into the correspondingly numbered element of the current expression.
Thus:
*2
*P
(X)
*
A negative integer has a similar effect, but counting begins from the
end of the current expression and proceeds backward, i.e., -1 refers to
the last element in the current expression, -2 the next to the last,
etc. For either positive integer or negative integer, if there is no
3
such element, an error occurs, the editor types the faulty command
------------------------------------------------------------------------
2
In other words, all lines beginning with * were typed by the user,
the rest by the editor.
3
'Editor errors' are not of the flavor described in Section 16, i.e.,
they never cause breaks or even go through the error machinery but
are direct calls to error! indicating that a command is in some way
faulty. What happens next depends on the context in which the
command was being executed. For example, there are conditional
commands which branch on errors. In most situations, though, an
error will cause the editor to type the faulty command followed by a
? and wait for more input. Note that typing control-E while a
command is being executed aborts the command exactly as though it
had caused an error.
9.2
followed by a ?, and then another *. The current expression is never
changed when a command causes an error. Thus:
*P
(X)
*2
2 ?
*1
*P
X
*
A phrase of the form "the current expression is changed" or 'the current
expression becomes' refers to a shift in the editor's attention, not to
a modification of the structure being edited.
When the user changes the current expression by descending into it, the
old current expression is not lost. Instead, the editor actually
operates by maintaining a chain of expressions leading to the current
one. The current expression is simply the last link in the chain.
Descending adds the indicated subexpression onto the end of the chain,
thereby making it be the current expression. The command 0 is used to
ascend the chain; it removes the last link of the chain, thereby making
the previous link be the current expression. Thus:
*P
X
*0 P
(X)
*0 -1 P
(COND (& Z) (T &))
*
Note the use of several commands on a single line in the previous
output. The editor operates in a line buffered mode, the same as
evalqt. Thus no command is actually seen by the editor, or executed,
until the line is terminated, either by a carriage return, or a matching
right parenthesis. The user can thus use control-A and control-Q for
line-editing edit commands, the same as he does for inputs to evalqt.
In our editing session, we will make the following corrections to
append: delete Y from where it appears, add Y to the end of the argument
4
list, change NUL to NULL, change Z to Y, add Z after CAR, and insert a
right parenthesis following CDR X.
------------------------------------------------------------------------
4
These two operations could be though of as one operation, i.e., MOVE
Y from its current position to a new position, and in fact there is
a MOVE command in the editor. However, for the purposes of this
introduction, we will confine ourselves to the simpler edit
commands.
9.3
First we will delete Y. By now we have forgotten where we are in the
function definition, but we want to be at the "top" so we use the
command ^, which ascends through the entire chain of expressions to the
top level expression, which then becomes the current expression, i.e., ^
removes all links except the first one.
*^ P
(LAMBDA (X) Y (COND & &))
*
Note that if we are already at the top, ^ has no effect, i.e., it is a
NOP. However, 0 would generate an error. In other words, ^ means "go to
the top," while 0 means "ascend one link."
The basic structure modification commands in the editor are:
(n) n > 1 deletes the corresponding
element from the current expression.
(n e1 ... em) n,m > 1 replaces the nth element in the current
expression with e1 ... em.
(-n e1 ... em) n,m > 1 inserts e1 ... em before the nth element
in the current expression.
Thus:
*P
(LAMBDA (X) Y (COND & &))
*(3)
*(2 (X Y))
*P
(LAMBDA (X Y) (COND & &))
*
All structure modification done by the editor is destructive, i.e., the
editor uses rplaca and rplacd to physically change the structure it was
given.
Note that all three of the above commands perform their operation with
respect to the nth element from the front of the current expression; the
sign of n is used to specify whether the operation is replacement or
insertion. Thus, there is no way to specify deletion or replacement of
the nth element from the end of the current expression, or insertion
before the nth element from the end without counting out that element's
position from the front of the list. Similarly, because we cannot
specify insertion after a particular element, we cannot attach something
at the end of the current expression using the above commands. Instead,
we use the command N (for nconc). Thus we could have performed the
above changes instead by:
9.4
*P
(LAMBDA (X) Y (COND & &))
*(3)
*2 (N Y)
*P
(X Y)
*^ P
*(LAMBDA (X Y) (COND & &))
*
Now we are ready to change NUL to NULL. Rather than specify the
sequence of descent commands necessary to reach NUL, and then replace it
with NULL, e.g., 3 2 1 (1 NULL), we will use F, the find command, to
find NUL:
*P
(LAMBDA (X Y) (COND & &))
*F NUL
*P
(NUL X)
*(1 NULL)
*0 P
((NULL X) Z)
*
Note that F is special in that it corresponds to two inputs. In other
words, F says to the editor, "treat your next command as an expression
to be searched for." The search is carried out in printout order in the
current expression. If the target expression is not found there, F
automatically ascends and searches those portions of the higher
expressions that would appear after (in a printout) the current
expression. If the search is successful, the new current expression
5
will be the structure where the expression was found, and the chain
will be the same as one resulting from the appropriate sequence of
ascent and descent commands. If the search is not successful, an error
6
occurs, and neither the current expression nor the chain is changed:
------------------------------------------------------------------------
5
If the search is for an atom, e.g., F NUL, the current expression
will be the structure containing the atom.
6
F is never a NOP, i.e., if successful, the current expression after
the search will never be the same as the current expression before
the search. Thus F expr repeated without intervening commands that
change the edit chain can be used to find successive instances of
expr.
9.5
*P
((NULL X) Z)
*F COND P
COND ?
*P
*((NULL X) Z)
*
Here the search failed to find a cond following the current expression,
although of course a cond does appear earlier in the structure. This
last example illustrates another facet of the error recovery mechanism:
to avoid further confusion when an error occurs, all commands on the
line beyond the one which caused the error (and all commands that may
7
have been typed ahead while the editor was computing) are forgotten.
We could also have used the R command (for replace) to change NUL to
NULL. A command of the form (R e1 e2) will replace all occurrences of
e1 in the current expression by e2. There must be at least one such
occurrence or the R command will generate an error. Let us use the R
command to change all Z's (even though there is only one) in append to
Y:
*^ (R Z Y)
*F Z
Z ?
*PP
[LAMBDA (X Y)
(COND
((NULL X)
Y)
(T (CONS (CAR)
(APPEND (CDR X Y]
*
The next task is to change (CAR) to (CAR X). We could do this by
(R (CAR) (CAR X)), or by:
*F CAR
*(N X)
*P
(CAR X)
*
The expression we now want to change is the next expression after the
current expression, i.e., we are currently looking at (CAR X) in (CONS
(CAR X) (APPEND (CDR X Y))). We could get to the append expression by
------------------------------------------------------------------------
7
i.e., the input buffer is cleared (and saved) (see clearbuf,
Section 14). It can be restored, and the type-ahead recovered via
the command $BUFS (alt-mode BUFS), described in Section 22.
9.6
typing 0 and then 3 or -1, or we can use the command NX, which does both
operations:
*P
(CAR X)
*NX P
(APPEND (CDR X Y))
*
Finally, to change (APPEND (CDR X Y)) to (APPEND (CDR X) Y), we could
perform (2 (CDR X) Y), or (2 (CDR X)) and (N Y), or 2 and (3), deleting
the Y, and then 0 (N Y). However, if Y were a complex expression, we
would not want to have to retype it. Instead, we could use a command
which effectively inserts and/or removes left and right parentheses.
There are six of these commands: BI,BO,LI,LO,RI, and RO, for both in,
both out, left in, left out, right in, and right out. Of course, we
will always have the same number of left parentheses as right
parentheses, because the parentheses are just a notational guide to
8
structure that is provided by our print program. Thus, left in, left
out, right in, and right out actually do not insert or remove just one
parenthesis, but this is very suggestive of what actually happens.
In this case, we would like a right parenthesis to appear following X in
(CDR X Y). Therefore, we use the command (RI 2 2), which means insert a
right parentheses after the second element in the second element (of the
current expression):
*P
(APPEND (CDR X Y))
*(RI 2 2)
*P
(APPEND (CDR X) Y)
*
We have now finished our editing, and can exit from the editor, to test
append, or we could test it while still inside of the editor, by using
the E command:
*E APPEND((A B) (C D E))
(A B C D E)
*
The E command causes the next input to be given to evalqt. If there is
another input following it, as in the above example, the first will be
applied (apply) to the second. Otherwise, the input is evaluated
(eval).
We prettyprint append, and leave the editor.
------------------------------------------------------------------------
8
Herein lies one of the principal advantages of a LISP oriented
editor over a text editor: unbalanced parentheses errors are not
possible.
9.7
*PP
[LAMBDA (X Y)
(COND
((NULL X)
Y)
(T (CONS (CAR X)
(APPEND (CDR X) Y]
*OK
APPEND
_
9.2 Commands for the New User
As mentioned earlier, the INTERLISP manual is intended primarily as a
reference manual, and the remainder of this chapter is organized and
presented accordingly. While the commands introduced in the previous
scenario constitute a complete set, i.e., the user could perform any and
all editing operations using just those commands, there are many
situations in which knowing the right command(s) can save the user
considerable effort. We include here as part of the introduction a list
of those commands which are not only frequently applicable but also easy
to use. They are not presented in any particular order, and are all
discussed in detail in the reference portion of the chapter.
UNDO undoes the last modification to the structure
being edited, e.g., if the user deletes the
wrong element, UNDO will restore it. The
availability of UNDO should give the user
confidence to experiment with any and all
editing commands, no matter how complex, because
he can always reverse the effect of the command.
BK like NX, except makes the expression immediately
before the current expression become current.
BF backwards find. Like F, except searches
backwards, i.e., in inverse print order.
\ Restores the current expression to the
expression before the last "big jump", e.g., a
find command, an ^, or another \. For example,
if the user types F COND, and then F CAR, \
would take him back to the COND. Another \
would take him back to the CAR.
\P like \ except it restores the edit chain to its
state as of the last print, either by P, ?, or
PP. If the edit chain has not been changed
since the last print, \P restores it to its
state as of the printing before that one, i.e.,
two chains are always saved.
9.8
Thus if the user types P followed by 3 2 1 P, \P will take him back to
the first P, i.e., would be equivalent to 0 0 0. Another \P would then
take him back to the second P. Thus the user can use \P to flip back
and forth between two current expressions.
&,-- The search expression given to the F or BF
command need not be a literal S-expression.
Instead, it can be a pattern. The symbol & can
be used anywhere within this pattern to match
with any single element of a list, and -- can be
used to match with any segment of a list. Thus,
in the incorrect definition of append used
earlier, F (NUL &) could have been used to find
(NUL X), and F (CDR --) or F (CDR & &), but not
F (CDR &), to find (CDR X Y).
Note that & and -- can be nested arbitrarily deeply in the pattern. For
example, if there are many places where the variable X is set, F SETQ
may not find the desired expression, nor may F (SETQ X &). It may be
necessary to use F (SETQ X (LIST --)). However, the usual technique in
such a case is to pick out a unique atom which occurs prior to the
desired expression, and perform two F commands. This "homing in"
process seems to be more convenient than ultra-precise specification of
the pattern.
$ (alt-mode) $ is equivalent to -- at the character level,
e.g., VER$ will match with VERYLONGATOM, as will
$ATOM, $LONG$, (but not $LONG) and $V$N$M$. $
can be nested inside of a pattern, e.g.,
F (SETQ VER$ (CONS --)).
If the search is successful, the editor will
print = followed by the atom which matched with
the $-atom, e.g.,
*F (SETQ VER$ &)
=VERYLONGATOM
*
Frequently the user will want to replace the entire current expression,
or insert something before it. In order to do this using a command of
the form (n e1 ... em) or (-n e1 ... em), the user must be above the
current expression. In other words, he would have to perform a 0
followed by a command with the appropriate number. However, if he has
reached the current expression via an F command, he may not know what
that number is. In this case, the user would like a command whose
effect would be to modify the edit chain so that the current expression
became the first element in a new, higher current expression. Then he
could perform the desired operation via (1 e1 ... em) or (-1 e1 ... em).
UP is provided for this purpose.
9.9
UP after UP operates, the old current expression is
the first element of the new current expression.
Note that if the current expression happens to
be the first element in the next higher
expression, then UP is exactly the same as 0.
Otherwise, UP modifies the edit chain so that
9
the new current expression is a tail of the
next higher expression:
*F APPEND P
(APPEND (CDR X) Y)
*UP P
... (APPEND & Y))
*0 P
(CONS (CAR X) (APPEND & Y))
*
The ... is used by the editor to indicate that
the current expression is a tail of the next
higher expression as opposed to being an element
(i.e., a member) of the next higher expression.
Note: if the current expression is already a
tail, UP has no effect.
(B e1 ... em) inserts e1 ... em before the current expression,
i.e., does an UP and then a -1.
(A e1 ... em) inserts e1 ... em after the current expression,
i.e., does an UP and then either a (-
2 e1 ... em) or an (N e1 ... em), if the current
expression is the last one in the next higher
expression.
(: e1 ... em) replaces current expression by e1 ... em, i.e.,
does an UP and then a (1 e1 ... em).
DELETE deletes current expression; equivalent to (:).
Earlier, we introduced the RI command in the append example. The rest
of the commands in this family: BI, BO, LI, LO, and RO, perform similar
functions and are useful in certain situations. In addition, the
commands MBD and XTR can be used to combine the effects of several
commands of the BI-BO family. MBD is used to embed the current
expression in a larger expression. For example, if the current
expression is (PRINT bigexpression), and the user wants to replace it by
(COND (FLG (PRINT bigexpression))), he could accomplish this by (LI 1),
(-1 FLG), (LI 1), and (-1 COND), or by a single MBD command, page 9.35.
------------------------------------------------------------------------
9
Throughout this chapter "tail" means "proper tail" (see Section 5).
9.10
XTR is used to extract an expression from the current expression. For
example, extracting the PRINT expression from the above COND could be
accomplished by (1), (LO 1), (1), and (LO 1) or by a single XTR command.
The new user is encouraged to include XTR and MBD in his repertoire as
soon as he is familiar with the more basic commands.
This ends the introductory material.
9.3 Attention Changing Commands
Commands to the editor fall into three classes: commands that change the
current expression (i.e., change the edit chain) thereby "shifting the
editor's attention," commands that modify the structure being edited,
and miscellaneous commands, e.g., exiting from the editor, printing,
evaluating expressions, etc.
Within the context of commands that shift the editor's attention, we can
distinguish among (1) those commands whose operation depends only on the
structure of the edit chain, e.g., 0, UP, NX; (2) those which depend on
the contents of the structure, i.e., commands that search; and (3) those
commands which simply restore the edit chain to some previous state,
e.g., \, \P. (1) and (2) can also be thought of as local, small steps
versus open ended, big jumps. Commands of type (1) are discussed on
page 9.11-16, type (2) on page 9.16-25, and type (3) on page
9.25-26.
9.3.1 Local Attention-Changing Commands
UP (1) If a P command would cause the editor to
type ... before typing the current expression,
ie.., the current expression is a tail of the
next higher expression, UP has no effect;
otherwise
(2) UP modifies the edit chain so that the old
current expression (i.e., the one at the time UP
was called) is the first element in the new
10
current expression.
------------------------------------------------------------------------
10
If the current expression is the first element in the next higher
expression UP simply does a 0. Otherwise UP adds the corresponding
tail to the edit chain.
9.11
Examples: The current expression in each case is (COND ((NULL X) (RETURN
Y))).
1. *1 P
COND
*UP P
(COND (& &))
2. *-1 P
((NULL X) (RETURN Y))
*UP P
... ((NULL X) (RETURN Y))
*UP P
... ((NULL X) (RETURN Y)))
3. *F NULL P
(NULL X)
*UP P
((NULL X) (RETURN Y))
*UP P
... ((NULL X) (RETURN Y)))
The execution of UP is straightforward, except in those cases where the
current expression appears more than once in the next higher expression.
For example, if the current expression is (A NIL B NIL C NIL) and the
user performs 4 followed by UP, the current expression should then
be ... NIL C NIL). UP can determine which tail is the correct one
because the commands that descend save the last tail on an internal
editor variable, lastail. Thus after the 4 command is executed, lastail
is (NIL C NIL). When UP is called, it first determines if the current
expression is a tail of the next higher expression. If it is, UP is
finished. Otherwise, UP computes
memb[current-expression;next-higher-expression] to obtain a tail
11
beginning with the current expression. If there are no other instances
of the current expression in the next higher expression, this tail is
the correct one. Otherwise UP uses lastail to select the correct
------------------------------------------------------------------------
11
The current expression should always be either a tail or an element
of the next higher expression. If it is neither, for example the
user has directly (and incorrectly) manipulated the edit chain, UP
generates an error.
9.12
12
tail.
n (n > 1) adds the nth element of the current expression
to the front of the edit chain, thereby making
it be the new current expression. Sets lastail
for use by UP. Generates an error if the
current expression is not a list that contains
at least n elements.
-n (n > 1) adds the nth element from the end of the current
expression to the front of the edit chain,
thereby making it be the new current expression.
Sets lastail for use by UP. Generates an error
if the current expression is not a list that
contains at least n elements.
0 Sets edit chain to cdr of edit chain, thereby
making the next higher expression be the new
current expression. Generates an error if there
is no higher expression, i.e., cdr of edit chain
is NIL.
Note that 0 usually corresponds to going back to the next higher left
parenthesis, but not always. For example, if the current expression is
(A B C D E F B), and the user performs:
*3 UP P
... C D E F G)
*3 UP P
... E F G)
*0 P
... C D E F G)
If the intention is to go back to the next higher left parenthesis,
13
regardless of any intervening tails, the command !0 can be used.
------------------------------------------------------------------------
12
Occasionally the user can get the edit chain into a state where
lastail cannot resolve the ambiguity, for example if there were two
non-atomic structures in the same expression that were eq, and the
user descended more than one level into one of them and then tried
to come back out using UP. In this case, UP prints LOCATION
UNCERTAIN and generates an error. Of course, we could have solved
this problem completely in our implementation by saving at each
descent both elements and tails. However, this would be a costly
solution to a situation that arises infrequently, and when it does,
has no detrimental effects. The lastail solution is cheap and
resolves 99% of the ambiguities.
13
!0 is pronounced bang-zero.
9.13
!0 does repeated 0's until it reaches a point where
the current expression is not a tail of the next
higher expression, i.e., always goes back to the
next higher left parenthesis.
^ sets edit chain to last of edit chain, thereby
making the top level expression be the current
expression. Never generates an error.
14
NX effectively does an UP followed by a 2,
thereby making the current expression be the
next expression. Generates an error if the
current expression is the last one in a list.
(However, !NX described below will handle this
case.)
BK makes the current expression be the previous
expression in the next higher expression.
Generates an error if the current expression is
the first expression in a list.
For example, if the current expression is (COND ((NULL X) (RETURN Y))):
*F RETURN P
(RETURN Y)
*BK P
(NULL X)
(NX n) n > 1 equivalent to n NX commands, except if an error
occurs, the edit chain is not changed.
(BK n) n > 1 equivalent to n BK commands, except if an error
occurs, the edit chain is not changed.
Note: (NX -n) is equivalent to (BK n), and vice versa.
!NX makes current expression be the next expression
at a higher level, i.e., goes through any number
of right parentheses to get to the next
expression.
------------------------------------------------------------------------
14
Both NX and BK operate by performing a !0 followed by an appropriate
number, i.e., there won't be an extra tail above the new current
expression, as there would be if NX operated by performing an UP
followed by a 2.
9.14
For example:
*PP
(PROG ((L L)
(UF L))
LP (COND
((NULL (SETQ L (CDR L)))
(ERROR!))
([NULL (CDR (FMEMB (CAR L)
(CADR L]
(GO LP)))
(EDITCOM (QUOTE NX))
(SETQ UNFIND UF)
(RETURN L))
*F CDR P
(CDR L)
*NX
NX ?
*!NX P
(ERROR!)
*!NX P
((NULL &) (GO LP))
*!NX P
(EDITCOM (QUOTE NX))
*
!NX operates by doing 0's until it reaches a stage where the current
expression is not the last expression in the next higher expression, and
then does a NX. Thus !NX always goes through at least one unmatched
right parenthesis, and the new current expression is always on a
different level, i.e., !NX and NX always produce different results. For
example using the previous current expression:
*F CAR P
(CAR L)
*!NX P
(GO LP)
*\P P
(CAR L)
*NX P
(CADR L)
*
(NTH n) n ~= 0 equivalent to n followed by UP, i.e., causes the
list starting with the nth element of the
current expression (or nth from the end if
15
n < 0) to become the current expression.
Causes an error if current expression does not
have at least n elements.
------------------------------------------------------------------------
15
(NTH 1) is a NOP, as is (NTH -n) where n is the length of the
current expression.
9.15
A generalized form of NTH using location specifications is described on
page 9.24.
9.3.2 Commands That Search
All of the editor commands that search use the same pattern matching
16
routine. We will therefore begin our discussion of searching by
describing the pattern match mechanism. A pattern pat matches with x
if:
1. pat is eq to x.
2. pat is &.
3. pat is a number and eqp to x.
4. pat is a string and strequal[pat;x] is true.
5. If car[pat] is the atom *ANY*, cdr[pat] is a list of
patterns and pat matches x if and only if one of the
patterns on cdr[pat] matches x.
6a. If pat is a literal atom or string containing one or more
17
alt-modes, each $ can match an indefinite number
(including 0) of contiguous characters in a literal atom
or string, e.g., VER$ matches both VERYLONGATOM and
"VERYLONGSTRING" as do $LONG$ (but not $LONG), and
$V$L$T$.
6b. If pat is a literal atom or string ending in two alt-
modes, pat matches with the first atom or string that is
"close" to pat, in the sense used by the spelling
corrector (Section 17). E.g. CONSS$$ matches with CONS,
CNONC$$ with NCONC or NCONC1.
The pattern matching routine always types a message of the
form =x to inform the user of the object matched by a
18
pattern of type 6a or 6b, e.g. =VERYLONGATOM.
7. If car[pat] is the atom --, pat matches x if
a. cdr[pat]=NIL, i.e., pat=(--), e.g.
(A --) matches (A) (A B C) and (A . B)
------------------------------------------------------------------------
16
This routine is available to the user directly, and is described on
page 9.68.
17
except that the atom $ (alt-mode) matches only with itself.
18
unless editquietflg=T.
9.16
In other words, -- can match any tail of a list.
b. cdr[pat] matches with some tail of x,
e.g., (A -- (&)) will match with (A B C (D)),
but not (A B C D), or (A B C (D) E). However,
note that (A -- (&) --) will match with
(A B C (D) E).
In other words, -- can match any interior segment of
a list.
8. If car[pat] is the atom ==, pat matches x if and only if
19
cdr[pat] is eq to x.
9. Otherwise if x is a list, pat matches x if car[pat]
matches car[x], and cdr[pat] matches cdr[x].
When the editor is searching, the pattern matching routine is called to
match with elements in the structure, unless the pattern begins with
..., in which case cdr of the pattern is matched against proper tails in
the structure. Thus if the current expression is (A B C (B C)),
*F (B --)
*P (B C)
*0 F (... B --)
*P
... B C (B C))
Matching is also attempted with atomic tails (except for NIL). Thus
*P
(A (B . C))
*F C
*P
... . C)
Although the current expression is the atom C after the final command,
it is printed as ... . C) to alert the user to the fact that C is a
tail, not an element. Note that the pattern C will match with either
instance of C in (A C (B . C)), whereas (... . C) will match only the
second C. The pattern NIL will only match with NIL as an element, i.e.,
it will not match in (A B), even though cddr of (A B) is NIL. However,
(... . NIL) (or equivalently (...)) may be used to specify a NIL tail,
e.g., (... . NIL) will match with cdr of the third subexpression of
((A . B) (C . D) (E)).
Search Algorithm
Searching begins with the current expression and proceeds in print
------------------------------------------------------------------------
19
Pattern 8 is for use by programs that call the editor as a
subroutine, since any non-atomic expression in a command typed in by
the user obviously cannot be eq to already existing structure.
9.17
order. Searching usually means find the next instance of this pattern,
and consequently a match is not attempted that would leave the edit
20
chain unchanged. At each step, the pattern is matched against the next
element in the expression currently being searched, unless the pattern
begins with ... in which case it is matched against the next tail of the
expression.
If the match is not successful, the search operation is recursive first
in the car direction and then in the cdr direction, i.e., if the element
under examination is a list, the search descends into that list before
21
attempting to match with other elements (or tails) at the same level.
However, at no point is the total recursive depth of the search (sum of
number of cars and cdrs descended into) allowed to exceed the value of
the variable maxlevel. At that point, the search of that element or
tail is abandoned, exactly as though the element or tail had been
completely searched without finding a match, and the search continues
with the element or tail for which the recursive depth is below
maxlevel. This feature is designed to enable the user to search
circular list structures (by setting maxlevel small), as well as
protecting him from accidentally encountering a circular list structure
22
in the course of normal editing. maxlevel is initially set to 300.
If a successful match is not found in the current expression, the search
23
automatically ascends to the next higher expression, and continues
searching there on the next expression after the expression it just
finished searching. If there is none, it ascends again, etc. This
process continues until the entire edit chain has been searched, at
which point the search fails, and an error is generated. If the search
fails (or, what is equivalent, is aborted by control-E), the edit chain
is not changed (nor are any conses performed).
If the search is successful, i.e., an expression is found that the
pattern matches, the edit chain is set to the value it would have had
had the user reached that expression via a sequence of integer commands.
------------------------------------------------------------------------
20
However, there is a version of the find command which can succeed
and leave the current expression unchanged (see page 9.19).
21
There is also a version of the find command (see page 9.20) which
only attempts matches at the top level of the current expression,
i.e., does not descend into elements, or ascend to higher
expressions.
22
maxlevel can also be set to NIL, which is equivalent to infinity.
23
See footnote on page 9.18.
9.18
If the expression that matched was a list, it will be the final link in
the edit chain, i.e., the new current expression. If the expression
that matched is not a list, e.g., is an atom, the current expression
24
will be the tail beginning with that atom, i.e., that atom will be the
first element in the new current expression. In other words, the search
25
effectively does an UP.
Search Commands
All of the commands below set lastail for use by UP, set unfind for use
by \ (page 9.25), and do not change the edit chain or perform any
conses if they are unsuccessful or aborted.
F pattern i.e., two commands: the F informs the editor
that the next command is to be interpreted as a
pattern. This is the most common and useful
form of the find command. If successful, the
edit chain always changes, i.e., F pattern means
find the next instance of pattern.
If memb[pattern;current-expression] is true, F
does not proceed with a full recursive search.
If the value of the memb is NIL, F invokes the
search algorithm described earlier.
Thus if the current expression is (PROG NIL LP (COND (-- (GO LP1))) ...
LP1 ...), F LP1 will find the prog label, not the LP1 inside of the GO
expression, even though the latter appears first (in print order) in the
current expression. Note that 1 (making the atom PROG be the current
expression), followed by F LP1 would find the first LP1.
(F pattern N) same as F pattern, i.e., finds the next instance
of pattern, except the memb check of F pattern
is not performed.
(F pattern T) Similar to F pattern, except may succeed without
changing edit chain, and does not perform the
memb check.
Thus if the current expression is (COND ..), F COND will look for the
next COND, but (F COND T) will "stay here".
------------------------------------------------------------------------
24
Unless the atom is a tail, e.g., B in (A . B). In this case, the
current expression will be B, but will print as ... . B).
25
Unless upfindflg=NIL (initially set to T). For discussion, see page
9.33-33.
9.19
(F pattern n) n > 1 Finds the nth place that pattern matches.
Equivalent to (F pattern T) followed by
(F pattern N) repeated n-1 times. Each time
pattern successfully matches, n is decremented
by 1, and the search continues, until n reaches
0. Note that the pattern does not have to match
with n identical expressions; it just has to
match n times. Thus if the current expression
is (FOO1 FOO2 FOO3), (F FOO$ 3) will find FOO3.
If the pattern does not match successfully n
times, an error is generated and the edit chain
is unchanged (even if the pattern matched n-1
times).
(F pattern) or only matches with elements at the
(F pattern NIL) top level of the current expression, i.e., the
search will not descend into the current
expression, nor will it go outside of the
current expression. May succeed without
changing edit chain.
For example, if the current expression is
(PROG NIL (SETQ X (COND & &)) (COND &) ...), F COND will find the COND
inside the SETQ, whereas (F (COND --)) will find the top level COND,
i.e., the second one.
(FS pattern1 ... patternn)
equivalent to F pattern1 followed by F
pattern2 ... followed by F patternn, so that if
F patternm fails, edit chain is left at place
patternm-1 matched.
(F= expression x) equivalent to (F (== . expression) x), i.e.,
searches for a structure eq to expression, see
page 9.17.
(ORF pattern1 ... patternn)
equivalent to
(F (*ANY* pattern1 ... patternn) N), i.e.,
searches for an expression that is matched by
either pattern1, pattern2, ... or patternn. See
page 9.16.
BF pattern backwards find. Searches in reverse print
order, beginning with expression immediately
before the current expression (unless the
current expression is the top level expression,
in which case BF searches the entire expression,
in reverse order).
BF uses the same pattern match routine as F, and
maxlevel and upfindflg have the same effect, but
the searching begins at the end of each list,
9.20
and descends into each element before attempting
to match that element. If unsuccessful, the
search continues with the next previous element,
etc., until the front of the list is reached, at
which point BF ascends and backs up, etc.
For example, if the current expression is
(PROG NIL (SETQ X (SETQ Y (LIST Z))) (COND ((SETQ W --) --)) --), F LIST
followed by BF SETQ will leave the current expression as (SETQ Y (LIST
Z)), as will F COND followed by BF SETQ.
(BF pattern T) search always includes current expression, i.e.,
starts at the end of current expression and
works backward, then ascends and backs up, etc.
Thus in the previous example, where F COND followed by BF SETQ found
(SETQ Y (LIST Z)), F COND followed by (BF SETQ T) would find the
(SETQ W --) expression.
(BF pattern) same as BF pattern.
(BF pattern NIL)
Location Specification
Many of the more sophisticated commands described later in this chapter
use a more general method of specifying position called a location
specification. A location specification is a list of edit commands that
are executed in the normal fashion with two exceptions. First, all
commands not recognized by the editor are interpreted as though they had
26
been preceded by F. For example, the location specification (COND 2 3)
27
specifies the 3rd element in the first clause of the next COND.
Secondly, if an error occurs while evaluating one of the commands in the
location specification, and the edit chain had been changed, i.e., was
not the same as it was at the beginning of that execution of the
location specification, the location operation will continue. In other
words, the location operation keeps going unless it reaches a state
where it detects that it is "looping", at which point it gives up.
Thus, if (COND 2 3) is being located, and the first clause of the next
COND contained only two elements, the execution of the command 3 would
cause an error. The search would then continue by looking for the next
COND. However, if a point were reached where there were no further
CONDs, then the first command, COND, would cause the error; the edit
------------------------------------------------------------------------
26
Normally such commands would cause errors.
27
Note that the user could always write F COND followed by 2 and 3 for
(COND 2 3) if he were not sure whether or not COND was the name of
an atomic command.
9.21
chain would not have been changed, and so the entire location operation
would fail, and cause an error.
The IF command in conjunction with the ## function provide a way of
using arbitrary predicates applied to elements in the current
expression. IF and ## will be described in detail later in the chapter,
along with examples illustrating their use in location specifications.
Throughout this chapter, the meta-symbol @ is used to denote a location
specification. Thus @ is a list of commands interpreted as described
above. @ can also be atomic, in which case it is interpreted as
list[@].
(LC . @) provides a way of explicitly invoking the
location operation, e.g., (LC COND 2 3) will
perform the the search described above.
(LCL . @) Same as LC except the search is confined to the
current expression, i.e., the edit chain is
rebound during the search so that it looks as
though the editor were called on just the
current expression. For example, to find a COND
containing a RETURN, one might use the location
specification (COND (LCL RETURN) \) where the \
would reverse the effects of the LCL command,
and make the final current expression be the
COND.
(2ND . @) Same as (LC . @) followed by another (LC . @)
except that if the first succeeds and second
fails, no change is made to the edit chain.
(3RD . @) Similar to 2ND.
(_ pattern) ascends the edit chain looking for a link which
matches pattern. In other words, it keeps doing
0's until it gets to a specified point. If
pattern is atomic, it is matched with the first
element of each link, otherwise with the entire
28
link.
------------------------------------------------------------------------
28
If pattern is of the form (IF expression), expression is evaluated
at each link, and if its value is NIL, or the evaluation causes an
error, the ascent continues.
9.22
For example:
*PP
[PROG NIL
(COND
[(NULL (SETQ L (CDR L)))
(COND
(FLG (RETURN L]
([NULL (CDR (FMEMB (CAR L)
(CADR L]]
*F CADR
*(_ COND)
*P
(COND (& &) (& &))
*
Note that this command differs from BF in that it does not search inside
of each link, it simply ascends. Thus in the above example, F CADR
followed by BF COND would find (COND (FLG (RETURN L))), not the higher
COND.
If no match is found, an error is generated, and
the edit chain is unchanged.
(BELOW com x) ascends the edit chain looking for a link
29
specified by com, and stops x links below
30
that, i.e. BELOW keeps doing 0's until it
gets to a specified point, and then backs off x
0's.
(BELOW com) same as (BELOW com 1).
For example, (BELOW COND) will cause the cond clause containing the
current expression to become the new current expression. Thus if the
current expression is as shown above, F CADR followed by (BELOW COND)
will make the new expression be
([NULL (CDR (FMEMB (CAR L) (CADR L] (GO LP)), and is therefore
equivalent to 0 0 0 0.
The BELOW command is useful for locating a substructure by specifying
something it contains. For example, suppose the user is editing a list
of lists, and wants to find a sublist that contains a FOO (at any
depth). He simply executes F FOO (BELOW \).
------------------------------------------------------------------------
29
x is evaluated, e.g., (BELOW com (IPLUS X Y)).
30
Only links that are elements are counted, not tails.
9.23
(NEX x) same as (BELOW x) followed by NX.
For example, if the user is deep inside of a SELECTQ clause, he can
advance to the next clause with (NEX SELECTQ).
NEX same as (NEX _).
The atomic form of NEX is useful if the user will be performing repeated
executions of (NEX x). By simply MARKing (see page 9.25) the chain
corresponding to x, he can use NEX to step through the sublists.
(NTH x) generalized NTH command. Effectively performs
(LCL . x), followed by (BELOW \), followed by
UP.
In other words, NTH locates x, using a search restricted to the current
expression, and then backs up to the current level, where the new
current expression is the tail whose first element contains, however
deeply, the expression that was the terminus of the location operation.
For example:
*P
(PROG (& &) LP (COND & &) (EDITCOM &) (SETQ UNFIND UF) (RETURN L))
*(NTH UF)
*P
... (SETQ UNFIND UF) (RETURN L))
*
If the search is unsuccessful, NTH generates an
error and the edit chain is not changed.
Note that (NTH n) is just a special case of (NTH x), and in fact, no
special check is made for x a number; both commands are executed
identically.
31
(pattern .. @) e.g., (COND .. RETURN). Finds a cond that
contains a return, at any depth. Equivalent to
(but more efficient than) (F pattern N),
(LCL . @) followed by (_ pattern).
For example, if the current expression is
(PROG NIL [COND ((NULL L) (COND (FLG (RETURN L] --), then
(COND .. RETURN) will make (COND (FLG (RETURN L))) be the current
expression. Note that it is the innermost COND that is found, because
this is the first COND encountered when ascending from the RETURN. In
other words, (pattern .. @) is not always equivalent to (F pattern N),
followed by (LCL . @) followed by \.
------------------------------------------------------------------------
31
An infix command, ".." is not a meta-symbol, it is the name of the
command. @ is cddr of the command.
9.24
Note that @ is a location specification, not just a pattern. Thus
(RETURN .. COND 2 3) can be used to find the RETURN which contains a
COND whose first clause contains (at least) three elements. Note also
that since @ permits any edit command, the user can write commands of
the form (COND .. (RETURN .. COND)), which will locate the first COND
that contains a RETURN that contains a COND.
9.3.3 Commands That Save and Restore the Edit Chain
Several facilities are available for saving the current edit chain and
later retrieving it: MARK, which marks the current chain for future
32
reference, _, which returns to the last mark without destroying it,
and __, which returns to the last mark and also erases it.
MARK adds the current edit chain to the front of the
list marklst.
_ makes the new edit chain be (CAR MARKLST).
Generates an error if marklst is NIL, i.e., no
MARKs have been performed, or all have been
erased.
__ similar to _ but also erases the MARK, i.e.,
performs (SETQ MARKLST (CDR MARKLST)).
Note that if the user has two chains marked, and wishes to return to the
first chain, he must perform __, which removes the second mark, and then
_. However, the second mark is then no longer accessible. If the user
wants to be able to return to either of two (or more) chains, he can use
the following generalized MARK:
(MARK atom) sets atom to the current edit chain,
(\ atom) makes the current edit chain become the value of
atom.
If the user did not prepare in advance for returning to a particular
edit chain, he may still be able to return to that chain with a single
command by using \ or \P.
\ makes the edit chain be the value of unfind.
Generates an error if unfind=NIL.
------------------------------------------------------------------------
32
An atomic command; do not confuse _ with the list command
(_ pattern).
9.25
unfind is set to the current edit chain by each command that makes a
"big jump", i.e., a command that usually performs more than a single
ascent or descent, namely ^, _, __, !NX, all commands that involve a
33
search, e.g., F, LC, .., BELOW, et al and \ and \P themselves.
For example, if the user types F COND, and then F CAR, \ would take him
back to the COND. Another \ would take him back to the CAR, etc.
\P restores the edit chain to its state as of the
last print operation, i.e., P, ?, or PP. If the
edit chain has not changed since the last
printing, \P restores it to its state as of the
printing before that one, i.e., two chains are
always saved.
For example, if the user types P followed by 3 2 1 P, \P will return to
34
the first P, i.e., would be equivalent to 0 0 0. Another \P would then
take him back to the second P, i.e., the user could use \P to flip back
and forth between the two edit chains.
(S var . @) Sets var (using setq) to the current expression
after performing (LC . @). Edit chain is not
changed.
Thus (S FOO) will set foo to the current expression, (S FOO -1 1) will
set foo to the first element in the last element of the current
expression.
This ends the section on "Attention Changing Commands."
------------------------------------------------------------------------
33
Except that unfind is not reset when the current edit chain is the
top level expression, since this could always be returned to via the
^ command.
34
Note that if the user had typed P followed by F COND, he could use
either \ or \P to return to the P, i.e., the action of \ and \P are
independent.
9.26
9.4 Commands That Modify Structure
The basic structure modification commands in the editor are:
(n) n > 1 deletes the corresponding element from the
current expression.
(n e1 ... em) n,m > 1 replaces the nth element in the current
expression with e1 ... em.
(-n e1 ... em) n,m > 1 inserts e1 ... em before the nth element
in the current expression.
(N e1 ... em) m > 1 attaches e1 ... em at the end of the
current expression.
As mentioned earlier:
all structure modification done by the editor is destructive, i.e., the
editor uses rplaca and rplacd to physically change the structure it was
given.
However, all structure modification is undoable, see UNDO page 9.59.
All of the above commands generate errors if the current expression is
not a list, or in the case of the first three commands, if the list
contains fewer than n elements. In addition, the command (1), i.e.,
delete the first element, will cause an error if there is only one
element, since deleting the first element must be done by replacing it
with the second element, and then deleting the second element. Or, to
look at it another way, deleting the first element when there is only
one element would require changing a list to an atom (i.e., to NIL)
35
which cannot be done.
If the value of changesarray is a hash array, the editor will mark all
structures that are changed by doing puthash[structure;fn;changesarray],
where fn is the name of the function. The algorithm used for marking is
as follows:
(1) If the expression is inside of another expression already marked as
being changed, do nothing.
------------------------------------------------------------------------
35
However, the command DELETE will work even if there is only one
element in the current expression, since it will ascend to a point
where it can do the deletion.
9.27
(2) If the change is an insertion of or replacement with a list, mark
the list as changed.
(3) If the change is an insertion of or replacement with an atom, or a
deletion, mark the parent as changed.
changesarray is primarily for use by prettyprint (Section 14). When the
value of changechar is not NIL, prettyprint, when printing to a file or
display terminal, prints changechar in the right margin while printing
an expression marked as having been changed. changechar is initially |.
9.4.1 Implementation of Structure Modification Commands
Note: Since all commands that insert, replace, delete or attach
structure use the same low level editor functions, the remarks made here
are valid for all structure changing commands.
For all replacement, insertion, and attaching at the end of a list,
36
unless the command was typed in directly to the editor, copies of the
corresponding structure are used, because of the possibility that the
exact same command, (i.e., same list structure) might be used again.
Thus if a program constructs the command (1 (A B C)) e.g., via
(LIST 1 FOO), and gives this command to the editor, the (A B C) used for
37
the replacement will not be eq to foo.
The rest of this section is included for applications wherein the editor
is used to modify a data structure, and pointers into that data
structure are stored elsewhere. In these cases, the actual mechanics of
structure modification must be known in order to predict the effect that
various commands may have on these outside pointers. For example, if
the value of foo is cdr of the current expression, what will the
commands (2), (3), (2 X Y Z), (-2 X Y Z), etc. do to foo?
Deletion of the first element in the current expression is performed by
replacing it with the second element and deleting the second element by
patching around it. Deletion of any other element is done by patching
around it, i.e., the previous tail is altered. Thus if foo is eq to the
------------------------------------------------------------------------
36
Some editor commands take as arguments a list of edit commands,
e.g., (LP F FOO (1 (CAR FOO))). In this case, the command (1 (CAR
FOO)) is not considered to have been "typed in" even though the LP
command itself may have been typed in. Similarly, commands
originating from macros, or commands given to the editor as
arguments to editf, editv, et al, e.g., EDITF(FOO F COND (N --)) are
not considered typed in.
37
The user can circumvent this by using the I command, which computes
the structure to be used. In the above example, the form of the
command would be (I 1 FOO), which would replace the first element
with the value of foo itself. See page 9.47.
9.28
current expression which is (A B C D), and fie is cdr of foo, after
executing the command (1), foo will be (B C D) (which is equal but not
eq to fie). However, under the same initial conditions, after executing
(2) fie will be unchanged, i.e., fie will still be (B C D) even though
38
the current expression and foo are now (A C D).
Both replacement and insertion are accomplished by smashing both car and
cdr of the corresponding tail. Thus, if foo were eq to the current
expression, (A B C D), after (1 X Y Z), foo would be (X Y Z B C D).
Similarly, if foo were eq to the current expression, (A B C D), then
after (-1 X Y Z), foo would be (X Y Z A B C D).
The N command is accomplished by smashing the last cdr of the current
expression a la nconc. Thus if foo were eq to any tail of the current
expression, after executing an N command, the corresponding expressions
would also appear at the end of foo.
In summary, the only situation in which an edit operation will not
change an external pointer occurs when the external pointer is to a
proper tail of the data structure, i.e., to cdr of some node in the
structure, and the operation is deletion. If all external pointers are
to elements of the structure, i.e., to car of some node, or if only
insertions, replacements, or attachments are performed, the edit
operation will always have the same effect on an external pointer as it
does on the current expression.
9.4.2 The A, B, and : Commands
In the (n), (n e1 ... em), and (-n e1 ... em) commands, the sign of the
integer is used to indicate the operation. As a result, there is no
direct way to express insertion after a particular element, (hence the
necessity for a separate N command). Similarly, the user cannot specify
deletion or replacement of the nth element from the end of a list
without first converting n to the corresponding positive integer.
Accordingly, we have:
(B e1 ... em) inserts e1 ... em before the current expression.
Equivalent to UP followed by (-1 e1 ... em).
For example, to insert FOO before the last element in the current
expression, perform -1 and then (B FOO).
------------------------------------------------------------------------
38
A general solution of the problem just isn't possible, as it would
require being able to make two lists eq to each other that were
originally different. Thus if fie is cdr of the current expression,
and fum is cddr of the current expression, performing (2) would have
to make fie be eq to fum if all subsequent operations were to update
both fie and fum correctly. Think about it.
9.29
(A e1 ... em) inserts e1 ... em after the current expression.
Equivalent to UP followed by (-2 e1 ... em) or
(N e1 ... em) whichever is appropriate.
(: e1 ... em) replaces the current expression by e1 ... em.
Equivalent to UP followed by (1 e1 ... em).
DELETE or (:) deletes the current expression.
DELETE first tries to delete the current expression by performing an UP
and then a (1). This works in most cases. However, if after performing
UP, the new current expression contains only one element, the command
(1) will not work. Therefore, DELETE starts over and performs a BK,
followed by UP, followed by (2). For example, if the current expression
is (COND ((MEMB X Y)) (T Y)), and the user performs -1, and then DELETE,
the BK-UP-(2) method is used, and the new current expression will be ...
((MEMB X Y)))
However, if the next higher expression contains only one element, BK
will not work. So in this case, DELETE performs UP, followed by (:
NIL), i.e., it replaces the higher expression by NIL. For example, if
the current expression is (COND ((MEMB X Y)) (T Y)) and the user
performs F MEMB and then DELETE, the new current expression will be ...
NIL (T Y)) and the original expression would now be (COND NIL (T Y)).
The rationale behind this is that deleting (MEMB X Y) from ((MEMB X Y))
changes a list of one element to a list of no elements, i.e., () or NIL.
If the current expression is a tail, then B, A, :, and DELETE all work
exactly the same as though the current expression were the first element
in that tail. Thus if the current expression were
... (PRINT Y) (PRINT Z)), (B (PRINT X)) would insert (PRINT X) before
(PRINT Y), leaving the current expression
... (PRINT X) (PRINT Y) (PRINT Z)).
The following forms of the A, B, and : commands incorporate a location
specification:
39 40
(INSERT e1 ... em BEFORE . @) Similar to (LC .@) followed by (B
e1 ... em).
------------------------------------------------------------------------
39
i.e., @ is cdr[member[BEFORE;command]]
40
except that if @ causes an error, the location process does not
continue as described on page 9.21. For example if @=(COND 3) and
the next COND does not have a 3rd element, the search stops and the
INSERT fails. Note that the user can always write (LC COND 3) if he
intends the search to continue.
9.30
*P
(PROG (& & X) **COMMENT** (SELECTQ ATM & NIL) (OR & &) (PRIN1 & T)
(PRIN1 & T) (SETQ X &
*(INSERT LABEL BEFORE PRIN1)
*P
(PROG (& & X) **COMMENT** (SELECTQ ATM & NIL) (OR & &) LABEL
(PRIN1 & T) (
41
*
Current edit chain is not changed, but unfind is
set to the edit chain after the B was performed,
i.e.,\ will make the edit chain be that chain
where the insertion was performed.
(INSERT e1 ... em AFTER . @)
Similar to INSERT BEFORE except uses A instead
of B.
(INSERT e1 ... em FOR . @)
similar to INSERT BEFORE except uses : for B.
42
(REPLACE @ WITH e1 ... em)
43
Here @ is the segment of the command between
REPLACE and WITH. Same as
(INSERT e1 ... em FOR . @).
Example: (REPLACE COND -1 WITH (T (RETURN L)))
(CHANGE @ TO e1 ... em) Same as REPLACE WITH.
44
(DELETE . @) does a (LC . @) followed by DELETE. Current
------------------------------------------------------------------------
41
Sudden termination of output followed by a blank line return
indicates printing was aborted by control-E.
42
BY can be used for WITH.
43
See footnote on page 9.30.
44
See footnote on page 9.30.
9.31
45
edit chain is not changed, but unfind is set
to the edit chain after the DELETE was
performed.
Example: (DELETE -1), (DELETE COND 3)
Note: if @ is NIL (i.e., empty), the corresponding operation is
performed here (on the current edit chain).
For example, (REPLACE WITH (CAR X)) is equivalent to (: (CAR X)). For
added readability, HERE is also permitted, e.g.,
(INSERT (PRINT X) BEFORE HERE) will insert (PRINT X). before the
current expression (but not change the edit chain).
Note: @ does not have to specify a location within the current
expression, i.e., it is perfectly legal to ascend to INSERT, REPLACE, or
DELETE
For example, (INSERT (RETURN) AFTER ^ PROG -1) will go to the top, find
the first PROG, and insert a (RETURN) at its end, and not change the
current edit chain.
The A, B, and : commands, commands, (and consequently INSERT, REPLACE,
and CHANGE), all make special checks in e1 thru em for expressions of
the form (## . coms). In this case, the expression used for inserting
or replacing is a copy of the current expression after executing coms, a
46
list of edit commands. For example, (INSERT (## F COND -1 -1) AFTER
47
3) will make a copy of the last form in the last clause of the next
cond, and insert it after the third element of the current expression.
------------------------------------------------------------------------
45
Unless the current expression is no longer a part of the expression
being edited, e.g., if the current expression is ... C) and the user
performs (DELETE 1), the tail, (C), will have been cut off.
Similarly, if the current expression is (CDR Y) and the user
performs (REPLACE WITH (CAR X)).
46
The execution of coms does not change the current edit chain.
47
Not (INSERT F COND -1 (## -1) AFTER 3), which inserts four elements
after the third element, namely F, COND, -1, and a copy of the last
element in the current expression.
9.32
9.4.3 Form Oriented Editing and the Role of UP
48
The UP that is performed before A, B, and : commands makes these
operations form-oriented. For example, if the user types F SETQ, and
then DELETE, or simply (DELETE SETQ), he will delete the entire SETQ
expression, whereas (DELETE X) if X is a variable, deletes just the
variable X. In both cases, the operation is performed on the
corresponding form, and in both cases is probably what the user
intended. Similarly, if the user types (INSERT (RETURN Y) BEFORE SETQ),
49
he means before the SETQ expression, not before the atom SETQ. A
consequent of this procedure is that a pattern of the form (SETQ Y --)
can be viewed as simply an elaboration and further refinement of the
pattern SETQ. Thus (INSERT (RETURN Y) BEFORE SETQ) and
50
(INSERT (RETURN Y) BEFORE (SETQ Y --)) perform the same operation and,
in fact, this is one of the motivations behind making the current
expression after F SETQ, and F (SETQ Y --) be the same.
Occasionally, however, a user may have a data structure in which no
special significance or meaning is attached to the position of an atom
in a list, as INTERLISP attaches to atoms that appear as car of a list,
versus those appearing elsewhere in a list. In general, the user may
not even know whether a particular atom is at the head of a list or not.
Thus, when he writes (INSERT expression BEFORE FOO), he means before the
atom FOO, whether or not it is car of a list. By setting the variable
51
upfindflg to NIL, the user can suppress the implicit UP that follows
searches for atoms, and thus achieve the desired effect. With
upfindflg=NIL, following F FOO, for example, the current expression will
be the atom FOO. In this case, the A, B, and : operations will operate
with respect to the atom FOO. If the user intends the operation to
refer to the list which FOO heads, he simply uses instead the pattern
(FOO --).
------------------------------------------------------------------------
48
and therefore in INSERT, CHANGE, REPLACE, and DELETE commands after
the location portion of the operation has been performed.
49
There is some ambiguity in (INSERT expr AFTER functionname), as the
user might mean make expr be the function's first argument.
Similarly, the user cannot write (REPLACE SETQ WITH SETQQ) meaning
change the name of the function. The user must in these cases write
(INSERT expr AFTER functioname 1), and (REPLACE SETQ 1 WITH SETQQ).
50
assuming the next SETQ is of the form (SETQ Y --).
51
Initially, and usually, set to T.
9.33
9.4.4 Extract and Embed
Extraction involves replacing the current expression with one of its
subexpressions (from any depth).
(XTR . @) replaces the original current expression with
the expression that is current after performing
52
(LCL . @).
For example, if the current expression is (COND ((NULL X) (PRINT Y))),
(XTR PRINT), or (XTR 2 2) will replace the cond by the print.
If the current expression after (LCL . @) is a
tail of a higher expression, its first element
is used.
For example, if the current expression is (COND ((NULL X) Y) (T Z)),
then (XTR Y) will replace the cond with Y, even though the current
expression after performing (LCL Y) is ... Y).
If the extracted expression is a list, then
after XTR has finished, the current expression
will be that list.
Thus, in the first example, the current expression after the XTR would
be (PRINT Y).
If the extracted expression is not a list, the
new current expression will be a tail whose
first element is that non-list.
Thus, in the second example, the current expression after the XTR would
be ... Y followed by whatever followed the COND.
If the current expression initially is a tail, extraction works exactly
the same as though the current expression were the first element in that
tail. Thus if the current expression is
... (COND ((NULL X) (PRINT Y))) (RETURN Z)), then (XTR PRINT) will
replace the cond by the print, leaving (PRINT Y) as the current
expression.
The extract command can also incorporate a location specification:
------------------------------------------------------------------------
52
See footnote on page 9.30.
9.34
53 54
(EXTRACT @1 FROM . @2) Performs (LC . @2) and then (XTR . @1).
Current edit chain is not changed, but unfind is
set to the edit chain after the XTR was
performed.
Example: If the current expression is (PRINT (COND ((NULL X) Y) (T Z)))
then following (EXTRACT Y FROM COND), the current expression will be
(PRINT Y). (EXTRACT 2 -1 FROM COND), (EXTRACT Y FROM 2),
(EXTRACT 2 -1 FROM 2) will all produce the same result.
While extracting replaces the current expression by a subexpression,
embedding replaces the current expression with one containing it as a
subexpression.
55
(MBD e1 ... em) MBD substitutes the current expression for all
instances of the atom * in e1 ... em, and
replaces the current expression with the result
of that substitution.
Examples: If the current expression is (PRINT Y),
(MBD (COND ((NULL X) *) ((NULL (CAR Y)) * (GO LP)))) would replace
(PRINT Y) with
(COND ((NULL X) (PRINT Y)) ((NULL (CAR Y)) (PRINT Y) (GO LP))).
If the current expression is (RETURN X), (MBD (PRINT Y) (AND FLG *))
would replace it with the two expressions (PRINT Y) and
(AND FLG (RETURN X)) i.e., if the (RETURN X) appeared in the cond clause
(T (RETURN X)), after the MBD, the clause would be
(T (PRINT Y) (AND FLG (RETURN X))).
If * does not appear in e1 ... em, the MBD is
interpreted as (MBD (e1 ... em *)).
Examples: If the current expression is (PRINT Y), then (MBD SETQ X) will
replace it with (SETQ X (PRINT Y)). If the current expression is
(PRINT Y), (MBD RETURN) will replace it with (RETURN (PRINT Y)).
MBD leaves the edit chain so that the larger expression is the new
current expression.
If the current expression initially is a tail, embedding works exactly
the same as though the current expression were the first element in that
tail. Thus if the current expression were ... (PRINT Y) (PRINT Z)),
(MBD SETQ X) would replace (PRINT Y) with (SETQ X (PRINT Y)).
------------------------------------------------------------------------
53
@1 is the segment between EXTRACT and FROM.
54
See footnote on page 9.30.
55
as with subst, a fresh copy is used for each substitution.
9.35
The embed command can also incorporate a location specification:
56 57
(EMBED @ IN . x) does (LC . @) and then (MBD . x). Edit
chain is not changed, but unfind is set to the
edit chain after the MBD was performed.
Example: (EMBED PRINT IN SETQ X), (EMBED 3 2 IN RETURN),
(EMBED COND 3 1 IN (OR * (NULL X))).
WITH can be used for IN, and SURROUND can be used for EMBED, e.g.,
(SURROUND NUMBERP WITH (AND * (MINUSP X))).
9.4.5 The MOVE Command
The MOVE command allows the user to specify (1) the expression to be
moved, (2) the place it is to be moved to, and (3) the operation to be
performed there, e.g., insert it before, insert it after, replace, etc.
58
(MOVE @1 TO com . @2) where com is BEFORE, AFTER, or the name of a
list command, e.g., :, N, etc. performs
59
(LC . @1), and obtains the current expression
there (or its first element, if it is a tail),
which we will call expr; MOVE then goes back to
the original edit chain, performs (LC . @2)
60
followed by (com expr), then goes back to @1
and deletes expr. Edit chain is not changed.
Unfind is set to edit chain after (com expr) was
performed.
For example, if the current expression is (A B C D), (MOVE 2 TO AFTER 4)
will make the new current expression be (A C D B). Note that 4 was
executed as of the original edit chain, and that the second element had
------------------------------------------------------------------------
56
@ is the segment between EMBED and IN.
57
See footnote on page 9.30.
58
@1 is the segment between MOVE and TO.
59
see footnote on page 9.30.
60
Setting an internal flag so expr is not copied.
9.36
61
not yet been removed.
As the following examples taken from actual editing will show, the MOVE
command is an extremely versatile and powerful feature of the editor.
*?
(PROG ((L L)) (EDLOC (CDDR C)) (RETURN (CAR L)))
*(MOVE 3 TO : CAR)
*?
(PROG ((L L)) (RETURN (EDLOC (CDDR C))))
*
*P
... (SELECTQ OBJPR & &) (RETURN &) LP2 (COND & &))
*(MOVE 2 TO N 1)
*P
... (SELECTQ OBJPR & & &) LP2 (COND & &))
*
*P
(OR (EQ X LASTAIL) (NOT &) (AND & & &))
*(MOVE 4 TO AFTER (BELOW COND))
*P
(OR (EQ X LASTAIL) (NOT &))
*\ P
... (& &) (AND & & &) (T & &))
*
*P
((NULL X) **COMMENT** (COND & &))
*(-3 (GO NXT]
*(MOVE 4 TO N (_ PROG))
*P
((NULL X) **COMMENT** (GO NXT))
*\ P
(PROG (&) **COMMENT** (COND & & &) (COND & & &) (COND & &))
*(INSERT NXT BEFORE -1)
*P
(PROG (&) **COMMENT** (COND & & &) (COND & & &) NXT (COND & &))
Note that in the last example, the user could have added the prog label
NXT and moved the cond in one operation by performing
(MOVE 4 TO N (_ PROG) (N NXT)). Similarly, in the next example, in the
course of specifying @2, the location where the expression was to be
moved to, the user also performs a structure modification, via (N (T)),
thus creating the structure that will receive the expression being
moved.
------------------------------------------------------------------------
61
If @2 specifies a location inside of the expression to be moved, a
message is printed and an error is generated, e.g.,
(MOVE 2 TO AFTER X), where X is contained inside of the second
element.
9.37
*P
((CDR &) **COMMENT** (SETQ CL &) (EDITSMASH CL & &))
*MOVE 4 TO N 0 (N (T)) -1]
*P
((CDR &) **COMMENT** (SETQ CL &))
*\ P
*(T (EDITSMASH CL & &))
*
If @2 is NIL, or (HERE), the current position specifies where the
operation is to take place. In this case, unfind is set to where the
expression that was moved was originally located, i.e., @1. For example:
*P
(TENEX)
*(MOVE ^ F APPLY TO N HERE)
*P
(TENEX (APPLY & &))
*
*P
(PROG (& & & ATM IND VAL) (OR & &) **COMMENT** (OR & &)
(PRIN1 & T) (
PRIN1 & T) (SETQ IND
62
*(MOVE * TO BEFORE HERE)
*P
(PROG (& & & ATM IND VAL) (OR & &) (OR & &) (PRIN1 &
*P
(T (PRIN1 C-EXP T))
*(MOVE ^ BF PRIN1 TO N HERE)
*P
(T (PRIN1 C-EXP T) (PRIN1 & T))
*
Finally, if @1 is NIL, the MOVE command allows the user to specify where
the current expression is to be moved to. In this case, the edit chain
is changed, and is the chain where the current expression was moved to;
unfind is set to where it was.
*P
(SELECTQ OBJPR (&) (PROGN & &))
*(MOVE TO BEFORE LOOP)
*P
... (SELECTQ OBJPR & &) LOOP (FRPLACA DFPRP &) (FRPLACD DFPRP
&) (SELECTQ
*
------------------------------------------------------------------------
62
Sudden termination of output followed by a blank line indicates
printing was aborted by control-E.
9.38
9.4.6 Commands That "Move Parentheses"
The commands presented in this section permit modification of the list
structure itself, as opposed to modifying components thereof. Their
effect can be described as inserting or removing a single left or right
parenthesis, or pair of left and right parentheses. Of course, there
will always be the same number of left parentheses as right parentheses
in any list structure, since the parentheses are just a notational guide
to the structure provided by print. Thus, no command can insert or
remove just one parenthesis, but this is suggestive of what actually
happens.
In all six commands, n and m are used to specify an element of a list,
usually of the current expression. In practice, n and m are usually
positive or negative integers with the obvious interpretation. However,
all six commands use the generalized NTH command, page 9.24, to find
their element(s), so that nth element means the first element of the
tail found by performing (NTH n). In other words, if the current
expression is (LIST (CAR X) (SETQ Y (CONS W Z))), then (BI 2 CONS),
(BI X -1), and (BI X Z) all specify the exact same operation.
All six commands generate an error if the element is not found, i.e.,
the NTH fails. All are undoable.
(BI n m) both in, inserts a left parentheses before the
nth element and after the mth element in the
current expression. Generates an error if the
mth element is not contained in the nth tail,
i.e., the mth element must be "to the right" of
the nth element.
Example: If the current expression is (A B (C D E) F G), then (BI 2 4)
will modify it to be (A (B (C D E) F) G).
(BI n) same as (BI n n).
Example: If the current expression is (A B (C D E) F G), then (BI -2)
will modify it to be (A B (C D E) (F) G).
(BO n) both out. Removes both parentheses from the nth
element. Generates an error if nth element is
not a list.
Example: If the current expression is (A B (C D E) F G), then (BO D)
will modify it to be (A B C D E F G).
(LI n) left in, inserts a left parenthesis before the
nth element (and a matching right parenthesis at
the end of the current expression), i.e.
equivalent to (BI n -1).
Example: if the current expression is (A B (C D E) F G), then (LI 2)
will modify it to be (A (B (C D E) F G)).
9.39
(LO n) left out, removes a left parenthesis from the
nth element. All elements following the nth
element are deleted. Generates an error if nth
element is not a list.
Example: If the current expression is (A B (C D E) F G), then (LO 3)
will modify it to be (A B C D E).
(RI n m) right in, inserts a right parenthesis after the
mth element of the nth element. The rest of the
nth element is brought up to the level of the
current expression.
Example: If the current expression is (A (B C D E) F G), (RI 2 2) will
modify it to be (A (B C) D E F G). Another way of thinking about RI is
to read it as "move the right parenthesis at the end of the nth element
in to after its mth element."
(RO n) right out, removes the right parenthesis from
the nth element, moving it to the end of the
current expression. All elements following the
nth element are moved inside of the nth element.
Generates an error if nth element is not a list.
Example: If the current expression is (A B (C D E) F G), (RO 3) will
modify it to be (A B (C D E F G)). Another way of thinking about RO is
to read it as "move the right parenthesis at the end of the nth element
out to the end of the current expression."
9.4.7 TO and THRU
EXTRACT, EMBED, DELETE, REPLACE, and MOVE can be made to operate on
several contiguous elements, i.e., a segment of a list, by using in
their respective location specifications the TO or THRU command.
(@1 THRU @2) does a (LC . @1), followed by an UP, and then a
(BI 1 @2), thereby grouping the segment into a
single element, and finally does a 1, making the
final current expression be that element.
For example, if the current expression is (A (B (C D) (E) (F G H) I) J
K), following (C THRU G), the current expression will be
((C D) (E) (F G H)).
(@1 TO @2) Same as THRU except last element not included,
i.e., after the BI, an (RI 1 -2) is performed.
If both @1 and @2 are numbers, and @2 is greater than @1, then @2 counts
from the beginning of the current expression, the same as @1. In other
words, if the current expression is (A B C D E F G), (3 THRU 5) means
(C THRU E) not (C THRU G). In this case, the corresponding BI command
is (BI 1 @2-@1+1).
9.40
THRU and TO are not very useful commands by themselves; they are
intended to be used in conjunction with EXTRACT, EMBED, DELETE, REPLACE,
and MOVE. After THRU and TO have operated, they set an internal editor
flag informing the above commands that the element they are operating on
is actually a segment, and that the extra pair of parentheses should be
removed when the operation is complete. Thus:
*P
(PROG (& & ATM IND VAL WORD) (PRIN1 & T) (PRIN1 & T) (SETQ IND &) (SETQ
VAL &) **COMMENT** (SETQQ
*(MOVE (3 THRU 4) TO BEFORE 7)
*P
(PROG (& & ATM IND VAL WORD) (SETQ IND &) (SETQ VAL &) (PRIN1 & T)
(PRIN1 & T) **COMMENT**
*
*P
(* FAIL RETURN FROM EDITOR. USER SHOULD NOTE THE VALUES OF SOURCEXPR AND
CURRENTFORM. CURRENTFORM IS THE LAST FORM IN SOURCEXPR WHICH WILL HAVE
BEEN TRANSLATED, AND IT CAUSED THE ERROR.)
*(DELETE (USER THRU CURR$))
=CURRENTFORM.
*P
(* FAIL RETURN FROM EDITOR. CURRENTFORM IS
*
*P
... LP (SELECTO & & & & NIL) (SETQ Y &) OUT (SETQ FLG &) (RETURN Y))
*(MOVE (1 TO OUT) TO N HERE]
*P
... OUT (SETQ FLG &) (RETURN Y) LP (SELECTQ & & & & NIL) (SETQ Y &))
*
*PP
[PROG (RF TEMP1 TEMP2)
(COND
((NOT (MEMB REMARG LISTING))
(SETQ TEMP1 (ASSOC REMARG NAMEDREMARKS)) **COMMENT**
(SETQ TEMP2 (CADR TEMP1))
(GO SKIP))
(T **COMMENT**
(SETQ TEMP1 REMARG)))
(NCONC1 LISTING REMARG)
(COND
((NOT (SETQ TEMP2 (SASSOC
*(EXTRACT (SETQ THRU CADR) FROM COND)
*P
(PROG (RF TEMP1 TEMP2) (SETQ TEMP1 &) **COMMENT** (SETQ TEMP2 &)
(NCONC1 LISTING REMARG) (COND & &
*
9.41
63
TO and THRU can also be used directly with XTR. Thus in the previous
example, if the current expression had been the COND, e.g., the user had
first performed F COND, he could have used (XTR (SETQ THRU CADR)) to
perform the extraction.
(@1 TO), (@1 THRU) both same as (@1 THRU -1), i.e., from @1
through the end of the list.
Examples:
*P
(VALUE (RPLACA DEPRP &) (RPLACD &) (RPLACA VARSWORD &) (RETURN))
*(MOVE (2 TO) TO N (_ PROG))
*(N (GO VAR))
*P
(VALUE (GO VAR))
*P
(T **COMMENT** (COND &) **COMMENT** (EDITSMASH CL & &) (COND &))
*(-3 (GO REPLACE))
*(MOVE (COND TO) TO N ^ PROG (N REPLACE))
*P
(T **COMMENT** (GO REPLACE))
*\ P
(PROG (&) **COMMENT** (COND & & &) (COND & & &) DELETE (COND & &)
REPLACE (COND &) **COMMENT** (EDITSMASH CL & &) (COND &))
*
------------------------------------------------------------------------
63
Because XTR involves a location specification while A, B, :, and MBD
do not.
9.42
*PP
[LAMBDA (CLAUSALA X)
(PROG (A D)
(SETQ A CLAUSALA)
LP (COND
((NULL A)
(RETURN)))
(SERCH X A)
(RUMARK (CDR A))
(NOTICECL (CAR A))
(SETQ A (CDR A))
(GO LP]
*(EXTRACT (SERCH THRU NOT$) FROM PROG)
=NOTICECL
*P
(LAMBDA (CLAUSALA X) (SERCH X A) (RUMARK &) (NOTICECL &))
*(EMBED (SERCH TO) IN (MAP CLAUSALA (FUNCTION (LAMBDA (A) *]
*PP
[LAMBDA (CLAUSALA X)
(MAP CLAUSALA (FUNCTION (LAMBDA (A)
(SERCH X A)
(RUMARK (CDR A))
(NOTICECL (CAR A]
*
9.4.8 The R Command
(R x y) replaces all instances of x by y in the current
expression, e.g., (R CAADR CADAR). Generates an
error if there is not at least one instance.
The R command operates in conjunction with the search mechanism of the
editor. The search proceeds as described on page 9.17-19, and x can
employ any of the patterns on page 9.16-17. Each time x matches an
element of the structure, the element is replaced by (a copy of) y; each
time x matches a tail of the structure, the tail is replaced by (a copy
of) y.
For example, if the current expression is (A (B C) (B . C)),
(R C D) will change it to (A (B D) (B . D)),
(R (... . C) D) to (A (B C) (B . D)),
(R C (D E)) to (A (B (D E)) (B D E)), and
(R (... . NIL) D) to (A (B C . D) (B . C) . D).
If x is an atom or string containing alt-modes, alt-modes appearing in y
stand for the characters matched by the corresponding alt-mode in x. For
example, (R FOO$ FIE$) means for all atoms or strings that begin with
9.43
64
FOO, replace the characters "FOO" by "FIE". Applied to the list
(FOO FOO2 XFOO1), (R FOO$ FIE$) would produce (FIE FIE2 XFOO1), and
(R $FOO$ $FIE$) would produce (FIE FIE2 XFIE1). Similarly, (R $D$ $A$)
65
will change (LIST (CADR X) (CADDR Y)) to (LIST (CAAR X) (CAADR)).
The user will be informed of all such alt-mode replacements by a message
of the form x->y, e.g., CADR->CAAR.
Note that the $ feature can be used to delete or add characters, as well
as replace them. For example, (R $1 $) will delete the terminating 1's
from all literal atoms and strings. Similarly, if an alt-mode in x does
not have a mate in y, the characters matched by the $ are effectively
66
deleted. For example, (R $/$ $) will change AND/OR to AND. y can also
be a list containing alt-modes, e.g., (R $1 (CAR $)) will change FOO1 to
(CAR FOO), FIE1 to (CAR FIE).
If x does not contain alt-modes, $ appearing in y refers to the entire
expression matched by x, e.g., (R LONGATOM '$) changes LONGATOM to
'LONGATOM, (R (SETQ X &) (PRINT $)) changes every (SETQ X &) to
67
(PRINT (SETQ X &)).
Since (R $x$ $y$) is a frequently used operation for replacing
characters, the following command is provided:
(RC x y) equivalent to (R $x$ $y$)
------------------------------------------------------------------------
64
If x matches a string, it will be replaced by a string. Note that it
does not matter whether x or y themselves are strings, i.e.
(R $D$ $A$), (R "$D$" $A$), (R $D$ "$A$"), and (R "$D$" "$A$") are
equivalent. Note also that x will never match with a number, i.e.,
(R $1 $2) will not change 11 to 12.
65
Note that CADDR was not changed to CAAAR, i.e., (R $D$ $A$) does not
mean replace every D with A, but replace the first D in every atom
or string by A. If the user wanted to replace every D by A, he could
perform (LP (R $D$ $A$)).
66
However, there is no similar operation for changing AND/OR to OR,
since the first $ in y always corresponds to the first $ in x, the
second $ in y to the second in x, etc.
67
If x is a pattern containing an alt-mode pattern somewhere within
it, the characters matched by the alt-modes are not available, and
for the purposes of replacement, the effect is the same as though x
did not contain any alt-modes. For example, if the user types
(R (CAR F$) (PRINT $)), the second $ will refer to the entire
expression matched by (CAR F$).
9.44
R and RC change all instances of x to y. The commands R1 and RC1 are
available for changing just one, (i.e., the first) instance of x to y.
(R1 x y) find the first instance of x and replace it by
y.
(RC1 x y) (R1 $x$ $y$).
In addition, while R and RC only operate within the current expression,
R1 and RC1 will continue searching, a la the F command, until they find
an instance of x, even if the search carries them beyond the current
expression.
(SW n m) switches the nth and mth elements of the current
expression.
For example, if the current expression is
(LIST (CONS (CAR X) (CAR Y)) (CONS (CDR X) (CDR Y))),
(SW 2 3) will modify it to be
(LIST (CONS (CDR X) (CDR Y)) (CONS (CAR X) (CAR Y))). The relative
order of n and m is not important, i.e., (SW 3 2) and (SW 2 3) are
equivalent.
SW uses the generalized NTH command to find the
nth and mth elements, a la the BI-BO commands.
Thus in the previous example, (SW CAR CDR) would produce the same
result.
9.5 Commands That Print
PP prettyprints the current expression.
P prints the current expression as though
printlevel were set to 2.
(P m) prints mth element of current expression as
though printlevel were set to 2.
(P 0) same as P
(P m n) prints mth element of current expression as
though printlevel were set to n.
(P 0 n) prints current expression as though printlevel
were set to n.
? same as (P 0 100)
9.45
Both (P m) and (P m n) use the generalized NTH command to obtain the
corresponding element, so that m does not have to be a number, e.g.,
(P COND 3) will work. PP causes all comments to be printed as
**COMMENT** (see Section 14). P and ? print as **COMMENT** only those
68
comments that are (top level) elements of the current expression.
PP* prettyprints current expression, including
comments.
PP* is equivalent to PP except that it first resets **comment**flg to
NIL (see Section 14). In fact, it is defined as (RESETVAR **COMMENT**FLG
NIL PP), see page 9.58.
PPV prettyprints current expression as a variable,
i.e., no special treatment for LAMBDA, COND,
SETQ, etc., or for CLISP.
PPT prettyprints current expression, printing CLISP
translations, if any.
?= prints the argument names and corresponding
values for current expression. Analagous to ?=
break command (Section 15).
For example, if the current expression is (STRPOS "AO???" X N (QUOTE
?) T), ?= prints
X = "AO???"
Y = X
START = N
SKIP = (QUOTE ?)
ANCHOR = T
TAIL =
All printing functions print to the terminal, regardless of the primary
output file. All use the readtable T. No printing function ever
changes the edit chain. All record the current edit chain for use by
\P, page 9.26. All can be aborted with control-E.
------------------------------------------------------------------------
68
Lower expressions are not really seen by the editor; the printing
command simply sets printlevel and calls print.
9.46
9.6 Commands That Evaluate
69
E only when typed in, causes the editor to call
70
lispx giving it the next input as argument.
Example: *E BREAK(FIE FUM)
(FIE FUM)
*E (FOO)
(FIE BROKEN)
:
(E x) evaluates x, i.e., performs eval[x], and prints
the result on the terminal.
(E x T) same as (E x) but does not print.
The (E x) and (E x T) commands are mainly intended for use by macros and
subroutine calls to the editor; the user would probably type in a form
for evaluation using the more convenient format of the (atomic) E
command.
(I c x1 ... xn) same as (C y1 ... yn) where y1=eval[xi].
Example: (I 3 (GETD (QUOTE FOO))) will replace the 3rd element of the
71
current expression with the definition of foo. (I N FOO (CAR FIE))
will attach the value of foo and car of the value of fie to the end of
the current expression. (I F= FOO T) will search for an expression eq
to the value of foo.
If c is not an atom, c is evaluated also.
------------------------------------------------------------------------
69
e.g, (INSERT D BEFORE E) will treat E as a pattern, and search for
E.
70
lispx is used by evalqt and break for processing terminal inputs. If
nothing else is typed on the same line, lispx evaluates its
argument. Otherwise, lispx applies it to the next input. In both
cases, lispx prints the result. See above example, and Sections 2
and 22.
71
The I command sets an internal flag to indicate to the structure
modification commands not to copy expression(s) when inserting,
replacing, or attaching.
9.47
Example: (I (COND ((NULL FLG) (QUOTE -1)) (T 1)) FOO), if flg is NIL,
inserts the value of foo before the first element of the current
expression, otherwise replaces the first element by the value of foo.
##[com1;com2; ... ;comn]is an NLAMBDA, NOSPREAD function (not a
command). Its value is what the current
expression would be after executing the edit
commands com1 ... comn starting from the present
edit chain. Generates an error if any of com1
thru comn cause errors. The current edit chain
72
is never changed.
Example: (I R (QUOTE X) (## (CONS .. Z))) replaces all X's in the
current expression by the first cons containing a Z.
The I command is not very convenient for computing an entire edit
command for execution, since it computes the command name and its
arguments separately. Also, the I command cannot be used to compute an
atomic command. The following two commands provide more general ways of
computing commands.
(COMS x1 ... xn) Each xi is evaluated and its value is executed
as a command.
For example, (COMS (COND (X (LIST 1 X)))) will replace the first element
of the current expression with the value of x if non-NIL, otherwise do
73
nothing.
(COMSQ com1 ... comn) executes com1 ... comn.
COMSQ is mainly useful in conjunction with the COMS command. For
example, suppose the user wishes to compute an entire list of commands
for evaluation, as opposed to computing each command one at a time as
does the COMS command. He would then write (COMS (CONS (QUOTE COMSQ)
x)) where x computed the list of commands, e.g.,
(COMS (CONS (QUOTE COMSQ) (GETP FOO (QUOTE COMMANDS)))).
------------------------------------------------------------------------
72
Recall that A, B, :, INSERT, REPLACE, and CHANGE make special checks
for ## forms in the expressions used for inserting or replacing, and
use a copy of ## form instead (see page 9.32). Thus, (INSERT
(## 3 2) AFTER 1) is equivalent to
(I INSERT (COPY (## 3 2)) (QUOTE AFTER) 1).
73
because NIL as a command is a NOP, see page 9.53.
9.48
9.7 Commands That Test
(IF x) generates an error unless the value of eval[x]
is true, i.e., if eval[x] causes an error or
eval[x]=NIL, IF will cause an error.
For some editor commands, the occurrence of an error has a well defined
meaning, i.e., they use errors to branch on, as cond uses NIL and non-
NIL. For example, an error condition in a location specification may
simply mean "not this one, try the next." Thus the location
specification
(IPLUS (E (OR (NUMBERP (## 3)) (ERROR!)) T)) specifies the first IPLUS
whose second argument is a number. The IF command, by equating NIL to
error, provides a more natural way of accomplishing the same result.
Thus, an equivalent location specification is (IPLUS (IF (NUMBERP (##
3)))).
The IF command can also be used to select between two alternate lists of
commands for execution.
(IF x coms1 coms2) If eval[x] is true, execute coms1; if eval[x]
causes an error or is equal to NIL, execute
74
coms2.
For example, the command (IF (READP T) NIL (P)) will print the current
expression provided the input buffer is empty.
(IF x coms1) if eval[x] is true, execute coms1; otherwise
generate an error.
(LP . coms) repeatedly executes coms, a list of commands,
until an error occurs.
For example, (LP F PRINT (N T)) will attach a T at the end of every
print expression. (LP F PRINT (IF (## 3) NIL ((N T)))) will attach a T
at the end of each print expression which does not already have a second
75
argument.
When an error occurs, LP prints n OCCURRENCES.
------------------------------------------------------------------------
74
Thus IF is equivalent to (COMS (CONS (QUOTE COMSQ) (COND
((CAR (NLSETQ (EVAL X))) COMS1)
(T COMS2)))).
75
i.e., the form (## 3) will cause an error if the edit command 3
causes an error, thereby selecting ((N T)) as the list of commands
to be executed. The IF could also be written as
(IF (CDDR (##)) NIL ((N T))).
9.49
where n is the number of times coms was
successfully executed. The edit chain is left
as of the last complete successful execution of
coms.
(LPQ . coms) same as LP but does not print the message
n OCCURRENCES.
In order to prevent non-terminating loops, both LP and LPQ terminate
76
when the number of iterations reaches maxloop, initially set to 30.
Since the edit chain is left as of the last successful completion of the
loop, the user can simply continue the LP command with REDO (Section
22).
(SHOW . x) x is a list of patterns. SHOW does a LPQ
printing all instances of the indicated
expression(s), e.g. (SHOW FOO (SETQ FIE &)) will
print all FOO's and all (SETQ FIE &)'s.
Generates an error if there aren't any instances
of the expression(s).
(EXAM . x) like SHOW except calls the editor recursively
(via the TTY: command described on page 9.53)
on each instance of the indicated espression(s)
so that the user can examine and/or change them.
(ORR coms1 ... comsn) ORR begins by executing coms1, a list of
commands. If no error occurs, ORR is finished.
Otherwise, ORR restores the edit chain to its
original value, and continues by executing
coms2, etc. If none of the command lists
execute without errors, i.e., the ORR "drops off
the end", ORR generates an error. Otherwise,
the edit chain is left as of the completion of
the first command list which executes without an
77
error.
For example, (ORR (NX) (!NX) NIL) will perform a NX, if possible,
------------------------------------------------------------------------
76
maxloop can also be set to NIL, which is equivalent to infinity.
77
NIL as a command list is perfectly legal, and will always execute
successfully. Thus, making the last "argument" to ORR be NIL will
insure that the ORR never causes an error. Any other atom is treated
as (atom), i.e., the above example could be written as (OR NX !NX
NIL).
9.50
otherwise a !NX, if possible, otherwise do nothing. Similarly,
DELETE could be written as (ORR (UP (1)) (BK UP (2)) (UP (: NIL))).
9.8 Macros
Many of the more sophisticated branching commands in the editor, such as
ORR, IF, etc., are most often used in conjunction with edit macros. The
macro feature permits the user to define new commands and thereby expand
78
the editor's repertoire. Macros are defined by using the M command.
(M c . coms) For c an atom, M defines c as an atomic
79
command. Executing c is then the same as
executing the list of commands coms.
For example, (M BP BK UP P) will define BP as an atomic command which
does three things, a BK, and UP, and a P. Macros can use commands
defined by macros as well as built in commands in their definitions.
For example, suppose Z is defined by (M Z -1 (IF (READP T) NIL (P))),
i.e., Z does a -1, and then if nothing has been typed, a P. Now we can
define ZZ by (M ZZ -1 Z), and ZZZ by (M ZZZ -1 -1 Z) or (M ZZZ -1 ZZ).
Macros can also define list commands, i.e., commands that take
arguments.
(M (c) (arg1 ... argn) . coms)
c an atom. M defines c as a list command.
Executing (c e1 ... en) is then performed by
substituting e1 for arg1, ... en for argn
throughout coms, and then executing coms.
For example, we could define a more general BP by
(M (BP) (N) (BK N) UP P). Thus, (BP 3) would perform (BK 3), followed
by an UP, followed by a P.
A list command can be defined via a macro so as to take a fixed or
indefinite number of "arguments", as with spread vs. nospread functions.
The form given above specified a macro with a fixed number of arguments,
as indicated by its argument list. If the "argument list" is atomic,
80
the command takes an indefinite number of arguments.
------------------------------------------------------------------------
78
However built in commands always take precedence over macros, i.e.,
the editor's repertoire can be expanded, but not redefined.
79
If a macro is redefined, its new definition replaces its old.
80
Note parallelism to EXPR's and EXPR*'s.
9.51
(M (c) arg . coms) c, arg both atoms, defines c as a list command.
Executing (c e1 ... en) is performed by
substituting (e1 ... en), i.e., cdr of the
command, for arg throughout coms, and then
executing coms.
For example, the command 2ND, page 9.22, can be defined as a macro by
(M (2ND) X (ORR ((LC . X) (LC . X)))).
Note that for all editor commands, "built in" commands as well as
commands defined by macros, atomic definitions and list definitions are
completely independent. In other words, the existence of an atomic
definition for c in no way affects the treatment of c when it appears as
car of a list command, and the existence of a list definition for c in
no way affects the treatment of c when it appears as an atom. In
particular, c can be used as the name of either an atomic command, or a
list command, or both. In the latter case, two entirely different
definitions can be used.
Note also that once c is defined as an atomic command via a macro
definition, it will not be searched for when used in a location
specification, unless it is preceded by an F. Thus (INSERT -- BEFORE
BP) would not search for BP, but instead perform a BK, and UP, and a P,
and then do the insertion. The corresponding also holds true for list
commands.
Occasionally, the user will want to employ the S command in a macro to
save some temporary result. For example, the SW command could be
defined as:
(M (SW) (N M) (NTH N) (S FOO 1) MARK 0 (NTH M) (S FIE 1)
81
(I 1 FOO) __ (I 1 FIE))
Since this version of SW sets foo and fie, using SW may have undesirable
side effects, especially when the editor was called from deep in a
computation, we would have to be careful to make up unique names for
dummy variables used in edit macros, which is bothersome. Furthermore,
it would be impossible to define a command that called itself
recursively while setting free variables. The BIND command solves both
problems.
(BIND . coms) binds three dummy variables #1, #2, #3,
(initialized to NIL), and then executes the edit
commands coms. Note that these bindings are
only in effect while the commands are being
------------------------------------------------------------------------
81
A more elegant definition would be:
(M (SW) (N M) (NTH N) MARK 0 (NTH M) (S FIE 1) (I 1 (## _ 1)) __ (I
1 FIE)),
but this would still use one free variable.
9.52
executed, and that BIND can be used recursively;
it will rebind #1, #2, and #3 each time it is
82
invoked.
Thus we could now write SW safely as:
(M (SW (N M) (BIND (NTH N) (S #1 1) MARK 0 (NTH M) (S #2 1)
(I 1 #1) __ (I 1 #2)))).
User macros are stored on a list usermacros. The prettydef command
USERMACROS (Section 14), is available for dumping all or selected user
macros.
9.9 Miscellaneous Commands
NIL unless preceded by F or BF, is always a NOP.
Thus extra right parentheses or square brackets
at the ends of commands are ignored.
TTY: calls the editor recursively. The user can then
type in commands, and have them executed. The
TTY: command is completed when the user exits
from the lower editor. (see OK and STOP below).
The TTY: command is extremely useful. It enables the user to set up a
complex operation, and perform interactive attention-changing commands
part way through it. For example the command (MOVE 3 TO AFTER COND 3 P
TTY:) allows the user to interact, in effect, within the MOVE command.
Thus he can verify for himself that the correct location has been found,
or complete the specification "by hand." In effect, TTY: says "I'll tell
you what you should do when you get there."
The TTY: command operates by printing TTY: and then calling the editor.
The initial edit chain in the lower editor is the one that existed in
the higher editor at the time the TTY: command was entered. Until the
user exits from the lower editor, any attention changing commands he
83
executes only affect the lower editor's edit chain. When the TTY:
command finishes, the lower editor's edit chain becomes the edit chain
of the higher editor.
OK exits from the editor
------------------------------------------------------------------------
82
BIND is implemented by (PROG (#1 #2 #3) (EDITCOMS (CDR COM))) where
com corresponds to the BIND command, and editcoms is an internal
editor function which executes a list of commands.
83
Of course, if the user performs any structure modification commands
while under a TTY: command, these will modify the structure in both
editors, since it is the same structure.
9.53
STOP exits from the editor with an error. Mainly for
use in conjunction with TTY: commands that the
user wants to abort.
Since all of the commands in the editor are errorset protected, the user
84
must exit from the editor via a command. STOP provides a way of
distinguishing between a successful and unsuccessful (from the user's
standpoint) editing session. For example, if the user is executing
(MOVE 3 TO AFTER COND TTY:), and he exits from the lower editor with an
OK, the MOVE command will then complete its operation. If the user
wants to abort the MOVE command, he must make the TTY: command generate
an error. He does this by exiting from the lower editor with a STOP
command. In this case, the higher editor's edit chain will not be
changed by the TTY: command.
SAVE exits from the editor and saves the "state of
the edit" on the property list of the function
or variable being edited under the property
EDIT-SAVE. If the editor is called again on the
same structure, the editing is effectively
"continued," i.e., the edit chain, mark list,
value of unfind and undolst are restored.
For example:
*P
(NULL X)
*F COND P
(COND (& &) (T &))
*SAVE
FOO
.
.
.
_EDITF(FOO)
EDIT
*P
(COND (& &) (T &))
*\ P
(NULL X)
*
SAVE is necessary only if the user is editing many different
expressions; an exit from the editor via OK always saves the state of
------------------------------------------------------------------------
84
Or by typing a control-D. STOP is preferred even if the user is
editing at the evalqt level, as it will perform the necessary
"wrapup" to insure that the changes made while editing will be
undoable (see Section 22).
9.54
85
the edit of that call to the editor. Whenever the editor is entered,
it checks to see if it is editing the same expression as the last one
edited. In this case, it restores the mark list, the undolst, and sets
unfind to be the edit chain as of the previous exit from the editor.
For example:
_EDITF(FOO)
EDIT
*P
(LAMBDA (X) (PROG & & LP & & & &))
.
.
.
*P
(COND & &)
*OK
FOO
.
. any number of lispx inputs
. except for calls to the editor
_EDITF(FOO)
EDIT
*P
(LAMBDA (X) (PROG & & LP & & & &))
*\ P
(COND & &)
*
Furthermore, as a result of the history feature (section 22), if the
editor is called on the same expression within a certain number of lispx
86
inputs, the state of the edit of that expression is restored,
regardless of how many other expressions may have been edited in the
meantime.
------------------------------------------------------------------------
85
on the property list of the atom EDIT, under the property name
LASTVALUE. OK also remprops EDIT-SAVE from the property list of the
function or variable being edited.
86
Namely, the size of the history list, initially 30, but it can be
increased by the user.
9.55
For example:
_EDITF(FOO)
EDIT
*
.
.
.
*P
(COND (& &) (& &) (&) (T &))
*OK
FOO
_ . less than 30 lispx inputs, including
editing
.
.
_EDITF(FOO)
EDIT
*\ P
(COND (& &) (& &) (&) (T &))
*
Thus the user can always continue editing, including undoing changes
from a previous editing session, if
(1) No other expressions have been edited since that
87
session; or
(2) That session was "sufficiently" recent; or
(3) It was ended with a SAVE command.
RAISE is an edit macro defined as UP followed by
(I 1 (U-CASE (## 1))), i.e., it raises to upper-
case the current expression, or if a tail, the
first element of the current expression.
LOWER Similar to RAISE, except uses l-case.
CAP First does a RAISE, and then lowers all but the
first character, i.e., the first character is
left capitalized.
Note: RAISE, LOWER, and CAP are all NOPs if the corresponding atom or
string is already in that state.
------------------------------------------------------------------------
87
Since saving takes place at exit time, intervening calls that were
aborted via control-D or exited via STOP will not affect the
editor's memory of this last session.
9.56
(RAISE x) equivalent to (I R (L-CASE x) x), i.e., changes
every lower-case x to upper-case in the current
expression.
(LOWER x) similar to RAISE, except performs (I R x (L-
CASE x)).
Note in both (RAISE x) and (LOWER x), x is typed in in upper case.
REPACK Permits the "editing" of an atom or string.
For example:
*P
... "THIS IS A LOGN STRING")
REPACK
*EDIT
P
(T H I S % I S % A % L O G N % S T R I N G)
*(SW G N)
*OK
88
"THIS IS A LONG STRING"
*
REPACK operates by calling the editor recursively on unpack of the
current expression, or if it is a list, on unpack of its first element.
If the lower editor is exited successfully, i.e., via OK as opposed to
STOP, the list of atoms is made into a single atom or string, which
replaces the atom or string being 'repacked.' The new atom or string is
always printed.
(REPACK @) does (LC . @) followed by REPACK, e.g.
(REPACK THIS$).
(; . x) x is the text of a comment. ; ascends the edit
chain looking for a "safe" place to insert the
comment, e.g., in a cond clause, after a prog
statement, etc., and inserts (* . x) after that
point, if possible, otherwise before. For
example, if the current expression is
(FACT (SUB1 N)) in
[COND
((ZEROP N) 1)
(T (ITIMES N (FACT (SUB1 N]
(; CALL FACT RECURSIVELY) would insert
------------------------------------------------------------------------
88
Note that this could also have been accomplished by (R $GN$ $NG$) or
simply (RC GN NG).
9.57
(* CALL FACT RECURSIVELY) before the itimes
89
expression.
; does not change the edit chain, but unfind is
set to where the comment was actually inserted.
JOINC is used to join two neighboring COND's together,
e.g. (COND clause1 clause2) followed by
(COND clause3 clause4) becomes
(COND clause1 clause2 clause3 clause4). JOINC
does an (F COND T) first so that you don't have
to be at the first COND.
(SPLITC x) splits one COND into two. x specifies the last
clause in the first COND, e.g. (SPLITC 3) splits
(COND clause1 clause2 clause3 clause4) into
(COND clause1 clause2) (COND clause3 clause4).
Uses generalized NTH command, so that x does not
have to be a number, e.g.,the user can say
(SPLITC RETURN), meaning split after the clause
containing RETURN. SPLITC also does an
(F COND T) first.
CL Clispifies current expression. See Section 23.
DW Dwimifies current expression. See Section 17
and 23.
(RESETVAR var form . coms)
executes coms while var is reset to the value of
form, and then restores var, i.e. effectively
calls the function resetvar (Section 5).
GET* If the current expression is a comment "map"
(see Section 14), reads in the full text of the
comment and replaces the current expression by
it.
------------------------------------------------------------------------
89
If inserted after the itimes, the comment would then be
(incorrectly) returned as the value of the cond. However, if the
cond was itself a prog statement, and hence its value was not being
used, the comment could be (and would be) inserted after the itimes
expression.
9.58
9.10 UNDO
Each command that causes structure modification automatically adds an
entry to the front of undolst that contains the information required to
restore all pointers that were changed by that command.
UNDO undoes the last, i.e., most recent, structure
modification command that has not yet been
90
undone, and prints the name of that command,
e.g., MBD UNDONE. The edit chain is then
exactly what it was before the "undone" command
91
had been performed. If there are no commands
to undo, UNDO types NOTHING SAVED.
!UNDO undoes all modifications performed during this
editing session, i.e. this call to the editor.
As each command is undone, its name is printed a
la UNDO. If there is nothing to be undone,
!UNDO prints NOTHING SAVED.
Whenever the user continues an editing session as described on page
9.54-56, the undo information of the previous session is protected by
inserting a special blip, called an undo-block, on the front of undolst.
This undo-block will terminate the operation of a !UNDO, thereby
confining its effect to the current session, and will similarly prevent
an UNDO command from operating on commands executed in the previous
session.
Thus, if the user enters the editor continuing a session, and
immediately executes an UNDO or !UNDO, the editor will type BLOCKED
------------------------------------------------------------------------
90
Since UNDO and !UNDO cause structure modification, they also add an
entry to undolst. However, UNDO and !UNDO entries are skipped by
UNDO, e.g., if the user performs an INSERT, and then an MBD, the
first UNDO will undo the MBD, and the second will undo the INSERT.
However, the user can also specify precisely which commands he wants
undone by identifying the corresponding entry on the history list as
described in Section 22. In this case, he can undo an UNDO command,
e.g., by typing UNDO UNDO, or undo a !UNDO command, or undo a
command other than that most recently performed.
91
Undoing an event containing an I, E, or S command will also undo the
side effects of the evaluation(s), e.g., undoing (I 3 (/NCONC FOO
FIE)) will not only restore the 3rd element but also restore FOO.
Similarly, undoing an S command will undo the set. See discussion of
UNDO in Section 22. (Note that if the I command was typed directly
to the editor, /NCONC would automatically be substituted for NCONC
as described in Section 22.)
9.59
instead of NOTHING SAVED. Similarly, if the user executes several
commands and then undoes them all, another UNDO or !UNDO will also cause
BLOCKED to be typed.
UNBLOCK removes an undo-block. If executed at a non-
blocked state, i.e., if UNDO or !UNDO could
operate, types NOT BLOCKED.
TEST adds an undo-block at the front of undolst.
Note that TEST together with !UNDO provide a "tentative" mode for
editing, i.e., the user can perform a number of changes, and then undo
all of them with a single !UNDO command.
9.11 Editdefault
Whenever a command is not recognized, i.e., is not "built in" or defined
as a macro, the editor calls an internal function, editdefault, to
92
determine what action to take. If a location specification is being
executed, an internal flag informs editdefault to treat the command as
though it had been preceded by an F.
If the command is a list, an attempt is made to perform spelling
93
correction on car of the command using editcomsl, a list of all list
------------------------------------------------------------------------
92
Since editdefault is part of the edit block, the user cannot advise
or redefine it as a means of augmenting or extending the editor.
However, the user can accomplish this via edituserfn. If the value
of the variable edituserfn is T, editdefault calls the function
edituserfn giving it the command as an argument. If edituserfn
returns a non-NIL value, its value is interpreted as a single
command and executed. Otherwise, the error correction procedure
described below is performed.
93
unless dwimflg=NIL. See Section 17 for discussion of spelling
correction.
9.60
94 95
edit commands. If spelling correction is successful, the correct
command name is rplacaed into the command, and the editor continues by
executing the command. In other words, if the user types
(LP F PRINT (MBBD AND (NULL FLG))), only one spelling correction will be
necessary to change MBBD to MBD. If spelling correction is not
successful, an error is generated.
If the command is atomic, the procedure followed is a little more
elaborate.
1) If the command is one of the list commands, i.e., a member of
editcomsl, and there is additional input on the same terminal line,
96
treat the entire line as a single list command. Thus, the user may
omit parentheses for any list command typed in at the top level
(provided the command is not also an atomic command, e.g. NX, BK).
For example,
*P
(COND (& &) (T &))
*XTR 3 2]
*MOVE TO AFTER LP
*
If the command is on the list editcomsl but no additional input is
on the terminal line, an error is generated, e.g.
*P
(COND (& &) (T &))
*MOVE
MOVE ?
*
If the command is on editcomsl, and not typed in directly, e.g., it
appears as one of the commands in a LP command, the procedure is
similar, with the rest of the command stream at that level being
treated as "the terminal line", e.g.
------------------------------------------------------------------------
94
When a macro is defined via the M command, the command name is added
to editcomsa or editcomsl, depending on whether it is an atomic or
list command. The prettydef command USERMACROS (Section 14), is
aware of this, and provides for restoring editcomsa and editcomsl.
95
Throughout this discussion, if the command was not typed in
directly, the user will be asked to approve the spelling correction.
See Section 17.
96
The line is read using readline (Section 14). Thus the line can be
terminated by a square bracket, or by a carriage return not preceded
by a space.
9.61
97
(LP F (COND (T &)) XTR 2 2).
2) If the command was typed in and the first character in the command
is an 8, treat the 8 as a mistyped left parenthesis, and and the
rest of the line as the arguments to the command, e.g.,
*P
(COND (& &) (T &))
*8-2 (Y (RETURN Z)))
=(-2
*P
(COND (Y &) (& &) (T &))
3) If the command was typed in, is the name of a function, and is
followed by NIL or a list car of which is not an edit command,
assume the user forgot to type E and means to apply the function to
its arguments, type =E and the function name, and perform the
indicated computation, e.g.
*BREAK(FOO)
=E BREAK
(FOO)
*
4) If the last character in the command is P, and the first n-1
characters comprise a number, assume that the user intended two
commands, e.g.,
*P
(COND (& &) (T &))
*0P
=0 P
(SETQ X (COND & &))
98
5) Attempt spelling correction using editcomsa, and if successful,
execute the corrected command.
6) Otherwise, if there is additional input on the same line, or command
stream, spelling correct using editcomsl as a spelling list, e.g.,
------------------------------------------------------------------------
97
Note that if the command is being executed in location context,
editdefault does not get this far, e.g., (MOVE TO AFTER COND XTR 3)
will search for XTR, not execute it. However,
(MOVE TO AFTER COND (XTR 3)) will work.
98
See footnote on page 9.62.
9.62
*MBBD SETQ X
=MBD
*
7) Otherwise, generate an error.
9.12 Editor Functions
edite[expr;coms;atm] edits an expression. Its value is the last
element of editl[list[expr];coms;atm].
Generates an error if expr is not a list.
99
editl[l;coms;atm;mess] editl is the editor. Its first argument is
the edit chain, and its value is an edit chain,
namely the value of l at the time editl is
100
exited.
coms is an optional list of commands. For
interactive editing, coms is NIL. In this case,
editl types EDIT and then waits for input from
101
terminal. All input is done with editrdtbl as
a readtable. Exit occurs only via an OK, STOP,
or SAVE command.
If coms is not NIL, no message is typed, and
each member of coms is treated as a command and
executed. If an error occurs in the execution
of one of the commands, no error message is
printed, the rest of the commands are ignored,
and editl exits with an error, i.e., the effect
is the same as though a STOP command had been
executed. If all commands execute successfully,
editl returns the current value of l.
atm is optional. On calls from editf, it is the
name of the function being edited; on calls from
------------------------------------------------------------------------
99
edit-ell, not edit-one.
100
l is a specvar, and so can be examined or set by edit commands. For
example, ^ is equivalent to (E (SETQ L (LAST L)) T). However, the
user should only manipulate or examine l directly as a last resort,
and then with caution.
101
If mess is not NIL, editl types it instead of EDIT. For example, the
TTY: command is essentially (SETQ L (EDITL L NIL NIL (QUOTE TTY:))).
9.63
editv, the name of the variable, and calls from
editp, the atom whose property list is being
edited. The property list of atm is used by the
SAVE command for saving the state of the edit.
Thus SAVE will not save anything if atm=NIL,
i.e., when editing arbitrary expressions via
edite or editl directly.
102
editl0[l;coms;mess;editlflg] like editl except does not rebind or
initialize the editor's various state variables,
such as lastail, unfind, undolst, marklst, etc.
editf[x] nlambda, nospread function for editing a
function. car[x] is the name of the
function,cdr[x] an optional list of commands.
For the rest of the discussion, fn is car[x],
and coms is cdr[x].
The value of editf is fn.
(1) In the most common case, fn is an expr, and editf simply performs
putd[fn;edite[getd[fn];coms;fn]]. However, if fn is an expr by
virtue of its being broken or advised, and
(1a) the original definition is also an expr, then the
broken/advised definition is given to edite to be edited (since
any changes there will also affect the original definition
because all changes are destructive). However, a warning
message is printed to alert the user that he must first
position himself correctly before he can begin typing commands
such as (-3 --), (N --), etc.
(1b) the original definition is not an expr, and there is no EXPR
property, and the file package "knows" which file fn is
contained in, then the expr definition of fn is loaded onto its
property list as described in (3) below, and proceeds to (1c),
otherwise a warning message is printed, and the edit proceeds,
e.g., the user may have called the editor to examine the advice
on a subr.
(1c) the original definition is not an expr, and there is an EXPR
property, then the function is unbroken/unadvised (latter only
with user's approval, since the user may really want to edit
the advice) and proceed as in (2).
(2) If fn is not an expr, but has an EXPR property, editf prints PROP,
and performs edite[getp[fn;EXPR];coms;fn]. If edite returns (i.e.,
------------------------------------------------------------------------
102
editlflg=T is for internal use by the editor.
9.64
if the editing is not terminated by a STOP), and some changes were
made, editf performs unsavedef[fn], prints UNSAVED, and then does
putd[fn;value-of-edite].
(3) if fn is neither an expr nor has an EXPR property, and the file
package (see section 14) "knows" which file fn is contained in, the
expr definition of fn is automatically loaded (using loadfns) onto
103
its property list, and proceed to (2) above. In addition, if fn
is a member of a block (see section 18), the user will be asked
whether he wishes the rest of the functions in the block to be
104
loaded at the same time.
(4) If fn is neither an expr nor has an EXPR property, but it does have
a definition, editf generates an fn NOT EDITABLE error.
(5) If fn is neither defined, nor has an EXPR property, but its top
level value is a list, editf assumes the user meant to call editv,
prints =EDITV, calls editv and returns. Similarly, if fn has a non-
NIL property list, editf prints =EDITP, calls editp and returns.
(6) If fn is neither a function, nor has an EXPR property, nor a top
level value that is a list, nor a non-NIL property list, editf
105
attempts spelling correction using the spelling list userwords,
and if successful, goes back to (1).
Otherwise, editf generates an fn NOT EDITABLE error.
------------------------------------------------------------------------
103
Because of the existence of the file map (see section 14), this
operation is extremely fast, essentially requiring only the time to
perform the READ to obtain the actual definition.
104
The editor's behaviour in case (3) is controlled by the value of
editloadfnsflg, which is a dotted pair of two flags, the first of
which (i.e., car of editloadfnsflg) controls the loading of the
function, and the second the loading of the block. A value of NIL
for either flag means "load but ask first," a value of T means
"don't ask, just do it" and anything else means "don't ask, don't do
it." The initial value of editloadfnsflg is (T), meaning load the
function without asking, ask about loading the block.
105
Unless dwimflg=NIL. Spelling correction is performed using the
function misspelled?. If fn=NIL, misspelled? returns the last "word"
referenced, e.g., by defineq, editf, prettyprint etc. Thus if the
user defines foo and then types editf[], the editor will assume he
meant foo, type =FOO, and then type EDIT. See Section 17.
9.65
If editf ultimately succeeds in finding a function to edit, i.e., does
not exit by calling editv or editp, editf calls the function addspell
106
after editing has been completed. Addspell "notices" fn, i.e., sets
lastword to fn, and adds fn to the appropriate spelling lists. If any
changes were made, editf also calls the file package to mark the
107
function as being changed, as described in section 14.
editv[editvx] nlambda, nospread function, similar to editf,
for editing values. car[editvx] specifies the
value, cdr[editvx] is an optional list of
commands.
If car[editvx] is a list, it is evaluated and its value given to edite,
e.g., EDITV((CDR (ASSOC (QUOTE FOO) DICTIONARY)))). In this case, the
value of editv is T.
However, for most applications, car[editvx] is a variable name, i.e.,
atomic, as in EDITV(FOO). If the value of this variable is NOBIND,
editv checks to see if it is the name of a function, and if so, assumes
the user meant to call editf, prints =EDITF, calls editf and returns.
Otherwise, editv attempts spelling correction using the list
108
userwords. Then editv will call edite on the value of car[editvx] (or
the corrected spelling thereof). Thus, if the value of foo is NIL, and
the user performs (EDITV FOO), no spelling correction will occur, since
foo is the name of a variable in the user's system, i.e., it has a
value. However, edite will generate an error, since foo's value is not
a list, and hence not editable. If the user performs (EDITV FOOO),
where the value of fooo is NOBIND, and foo is on the user's spelling
list, the spelling corrector will correct FOOO to FOO. Then edite will
be called on the value of foo. Note that this may still result in an
error if the value of foo is not a list.
When (if) edite returns, editv sets the variable to the value returned,
and calls addspell. If any changes were made, editv also calls the file
package to mark the variable as being changed.
The value of editv is the name of the variable whose value was edited.
------------------------------------------------------------------------
106
Unless dwimflg=NIL. addspell is described in Section 17.
107
Even though the call to newfile? does not occur until after the
editing is completed, nevertheless the function is effectively
marked as changed as soon as the first change is performed, so that
even if the edit is aborted via control-D, newfile? will still be
called.
108
Unless dwimflg=NIL. Misspelled? is also called if car[editvx] is
NIL, so that EDITV() will edit lastword.
9.66
editp[x] nlambda, nospread function, similar to editf for
editing property lists. If the property list of
car[x] is NIL, editp attempts spelling
correction using userwords. Then editp calls
edite on the property list of car[x], (or the
corrected spelling thereof). When (if) edite
returns, editp rplacd's car[x] with the value
returned, and calls addspell.
The value of editp is the atom whose property
list was edited.
editfns[x] nlambda, nospread function, used to perform the
same editing operations on several functions.
car[x] is evaluated to obtain a list of
109
functions. cdr[x] is a list of edit commands.
editfns maps down the list of functions, prints
the name of each function, and calls the editor
110
(via editf) on that function.
For example, EDITFNS(FOOFNS (R FIE FUM)) will change every FIE to FUM in
each of the functions on foofns.
The call to the editor is errorset protected, so
that if the editing of one function causes an
error, editfns will proceed to the next
111
function.
Thus in the above example, if one of the functions did not contain a
FIE, the R command would cause an error, but editing would continue with
the next function.
The value of editfns is NIL.
------------------------------------------------------------------------
109
If car[x] is atomic, and its value is not a list, and it is the name
of a file, filefnslst[car[x]] will be used as the list of functions
to be edited.
110
i.e., the definition of editfns might be:
[MAPC (EVAL (CAR X)) (FUNCTION (LAMBDA (Y)
(APPLY (QUOTE EDITF)
(CONS (PRINT Y T) (CDR X]
111
In particular, if an error occurred while editing a function via its
EXPR property, the function would not be unsaved. In other words, in
the above example, only those functions which contained a FIE, i.e.,
only those actually changed, would be unsaved.
9.67
edit4e[pat;x;changeflg] is the pattern match routine. Its value is T if
pat-matches x. See page 9.16-17 for definition
112
of "match".
Note: before each search operation in the editor begins, the entire
pattern is scanned for atoms or strings containing alt-modes. These are
replaced by patterns of the form (CONS (QUOTE $) (UNPACK atom/string))
for 6a, and
(CONS (QUOTE $$) (CONS (NCHARS atom/string) (UNPACK atom/string))), for
113
6b. Thus from the standpoint of edit4e, pattern type 6a is indicated
by car[pat] being the atom $ ($ is alt-mode) and pattern type 6b by
car[pat] being the atom $$ (double alt-mode).
Therefore, if the user wishes to call edit4e directly, he must first
convert any patterns which contain atoms or strings ending in alt-modes
to the form recognized by edit4e. This is done with the function
editfpat.
editfpat[pat;flg] makes a copy of pat with all patterns of type 6
114
converted to the form expected by edit4e.
editfindp[x;pat;flg] allows a program to use the edit find command as
a pure predicate from outside the editor. x is
an expression, pat a pattern. The value of
editfindp is T if the command F pat would
succeed, NIL otherwise. editfindp calls
editfpat to convert pat to the form expected by
edit4e, unless flg=T. Thus, if the program is
applying editfindp to several different
expressions using the same pattern, it will be
more efficient to call editfpat once, and then
call editfindp with the converted pattern and
flg=T.
------------------------------------------------------------------------
112
changeflg is for internal use by the editor.
113
In latter case, atom/string corresponds to the atom or string up to
but not including the final two-alt-modes. In both cases, dunpack is
used wherever possible.
114
flg=T is used for internal use by the editor.
9.68
115
esubst[x;y;z;errorflg;charflg] equivalent to performing (R y x)
with z as the current expression, i.e., the
order of arguments is the same as for subst.
Note that y and/or x can employ alt-modes. The
value of esubst is the modified z. Generates an
116
error if y not found in z. If errorflg=T,
also prints an error message of the form y ?.
esubst is always undoable.
changename[fn;from;to] replaces all occurrences of from by to in the
definition of fn. If fn is an expr, changename
performs nlsetq[esubst[to;from;getd[fn]]]. If
fn is compiled, changename searches the
literals of fn (and all of its compiler
generated subfunctions), replacing each
117
occurrence of from with to.
The value of changename is fn if at least one
instance of from was found, otherwise NIL.
changename is used by break and advise for changing calls to fn1 to
calls to fn1-IN-fn2.
editracefn[com] is available to help the user debug complex edit
macros, or subroutine calls to the editor. If
editracefn is set to T, the function editracefn
is called whenever a command that was not typed
in by the user is about to be executed, giving
it that command as its argument. However, the
TRACE and BREAK options described below are
probably sufficient for most applications.
If editracefn is set to TRACE, the name of the
command and the current expression are printed.
If editracefn=BREAK, the same information is
printed, and the editor goes into a break. The
user can then examine the state of the editor.
editracefn is initially NIL.
------------------------------------------------------------------------
115
unless charflg=T, in which case it is equivalent to (RC y x). See
page 9.44.
116
of the type that never causes a break.
117
Will succeed even if from is called from fn via a linked call. In
this case, the call will also be relinked to call to instead.
9.69