CONTENTS

1.0	Toke overview
1.1	Installation and running
1.2	Basics
2.0	Tokenization
2.1	Changing the token grammar
2.2	Changing the lexical scanner
2.3	Morphology
2.4	Displaying information
3.0	Change rules
3.1	Syntax of change rules
3.1.1	Syntax of conditions
3.1.2	Predicates
3.1.3	Relations
3.1.4	Subscripts
3.1.5	Ranges
3.1.6	Conditional subscripts
3.2	Actions
3.2.1	Changes and the `follow' string
3.2.2	Changes and tokenization
3.2.3	The rule application protocol
3.2.4	Each component of a condition is tested separately
3.2.5	Insertion and deletion of tokens can change the loop index
3.3	Using Toke non-interactively
4.0	Tips, Tricks and Caveats



1.0	Toke Overview

Toke is a program that tokenizes a document and lets you examine parts
of it to see its typographical and morphological structure. In
addition, Toke allows you to apply `change rules' to all or part of
the document.

This is version 1.0a.


1.1	Installation  and Running

Installation instructions are supplied in the accompanying README file.

The following two paragraphs do not apply to the Macintosh version.

You can specify a document name on the command line, in which case the
document will be read in and tokenized at startup. You can also
specify a file containing change rules, in the form `-r
rulesfile'. And you can do both or neither.

Additionally, it's possible to run Toke as a non-interactive
application by using the option `-i'. See 3.3 for further details on
how this mode operates.

1.2	Basics

Toke presents a window consisting of three frames, each with its own
scrollbar. (However I usually refer to these frames as `windows').

The top window contains change rules, the middle window contains a
document, and the bottom window displays informative messages from the
program, or information about a selected range of tokens.

The bottom two windows are `read-only', which is to say that changes
to their contents occur only under the program's control. 

The entire (three-part) window can be resized interactively, but its
separate frames cannot.

Above all these windows is a menubar-cum-pallette. This contains a
File menu, which offers operations on the document, as well as
quitting; a Rules menu, which offers counterparts pertaining to the
change rules; a Search menu, which allows you to find either literal
or regular expressions in the text; and a Help menu, which however is
not currently extremely helpful.

Most of the menu items have keyboard equivalents, which all involve
the Control key. (They are shown on the menus, Emacs-style, as C-o
etc. Note that C-o means `control + lower-case o', whereas  C-O means
`control + shift + o'.) There is one control-key sequence which does
not correspond to any menu item: C-a selects all the text in the
document and causes action to occur as if you had manually selected
it.

To the right of the menu headings is a series of checkboxes which
control options in Toke's operations. Initially all these options are
turned off, so you need to set either `Info' or `Apply' for anything
much to happen. Some options are disabled when they logically cannot
be in effect. The settings that they _would_ have if not disabled are,
however, remembered and shown.

In addition to this GUI-style display, there is a
regular Unix-style console. This can be used to give Tcl/Tk commands
directly to Toke. If you wish, you may close it.


2.0	Tokenization

Tokenization is performed in accordance with a context-free grammar
that is specified, as a `bison' grammar file, in `docparse.y'. That
grammar controls the building of tokens out of more primitive units
called `bundles', which are themselves specified in a `flex' grammar
file called `docparse.l'. 

Changes to either of these files require re-compilation and re-linking
of the project, but are otherwise relatively easy to make. The next
two sections explain how.


2.1	Changing the token grammar

The token grammar is in the file `docparse.y'. This file consists of
several sections which are marked off by lines beginning with a
percent sign `%'. The basic structure is as follows:

		comments
	%{
		C declarations
	%}
		Declarations of terminal nodes, e.g.
		%token ALPHA
	%%
		Bison grammar statements
	%%
		Further C statements or end of file

You can change the grammar by changing the grammar rules between the
lines beginning with `%%'. Each rule is in the following format

	LHS:	RHS

ie, a statement that a symbol on the left-hand side (which is followed
by a colon) expands to the sequence of symbols on the right-hand side
(which are separated from each other by white space). Alternative
expansions use the vertical bar or `pipe' character:

	LHS:	RHS-1
	     |	RHS-2
	     |	RHS-3
		etc.

Each symbol in the RHS of a rule is itself either (1) the LHS of some
other rule, if it is a non-terminal symbol, or (2) a terminal
symbol. By convention, terminal symbols are in upper case and
non-terminal symbols are in lower case.

Since terminal symbols are not defined in this file, bison has
to be told about them. That is why each such symbol must be declared
in a %token declaration in the right place, as indicated above (see
2.2 for how terminal symbols are actually defined).

Associated with each grammar production is an `action', namely one or
more C statements enclosed in braces. A header file defines several macros
to simplify the process of supplying action statements. Essentially,
all productions that have two elements on their RHS can simply include
the action

	{ Make2(type, class) }

while all productions that have three elements on their RHS can
include the action

	{ Make3(type, class) }

and so on. Macros are provided for up to five RHS elements.

Productions where the RHS consists of a single element (i.e. unary
branching) do not require a specific action. In this case, the LHS
mother is simply equated with the RHS daughter. However, if you want
to record an explicit unary branch, you can insert the following
macro:

	{ Make1(type, class) }

Once you have modified the grammar file, you can compile a new version
of Toke using the new grammar by typing:

	make -r

This will produce a file called `toke.out' _in the source file
directory_, which you can then move to wherever you like.

However, if your grammar invokes new terminal symbols, you must also
arrange for the lexical scanner to recognize these. This is the topic
of the next section.


2.2	Changing the lexical scanner

The lexical scanner which feeds the tokenizer is defined in file
`docparse.l'. This is a `flex' input file which associates regular
expressions with specific types of tokens, and which builds `bundles'
at the lowest level. The format is not unlike that of a bison grammar
file (2.1):

		comments
	%{
		C declarations
	%}

	%%
		scanner productions
	%%

The scanner productions define how particular sequences of characters
are associated with abstract token types. Each production is of the
form

	regular-expression	action

except that the regular expression must appear flush with the left
margin. The actions are again arbitrary C statements, but for the
purposes of Toke a macro called Make is provided that covers all the
usual cases. Thus the format of a production is (modulo the line
positioning)

	regular-expression	Make(type, class, abstract-identifier)

where the `abstract-identifier' is declared in a %token statement in
`docparse.y'.  

(The one production that should not be casually changed is the one
concerning line-feeds and other line separators, since this is also
responsible for setting some internal variables related to line
starts.)

Once you have modified the scanner file, the procedure for updating
Toke is as outlined at the end of the previous section.


2.3	Morphology

Toke uses the University of Pennsylvania morphological database
package to retrieve morphological information about tokens. In
addition it uses a reversed database created from the Penn database to
construct surface forms from morphological descriptions. The
morphological analysis and generating functions, however, look to the
rest of the program like `black boxes', so that a different database
could be used in future.


2.4	Displaying information

One thing that Toke can do is display various forms of information
about tokens in the document. To enable this display, you must set the
checkbox `Info'. Then, when a token or range of tokens is selected (by
dragging, double- or triple-clicking, or typing control-a to select
all tokens) information about those tokens is displayed in the bottom
window. The bottom window is fairly small so you may need to scroll to
see the information you're interested in.

By default, there is presented for each token an SGML-style string
telling the token's consecutive ID number, its type, its `follow', its
starting and ending offsets, and its actual text.

Two checkboxes control the display of additional information. If you
select Morphology, you additionally see a representation of the
morphological analyses returned by consulting the Penn morphological
database. (Typically there is more than one.)

If you select Bundles, you also get information about sub-token
typographical structure.

If rules are being applied, then the information presented in the
bottom window represents the state of affairs _after_ all rules have
applied.


3.0	Change Rules

Change rules are condition-action statements that specify changes to
be made to the document based on morphological and typographical
attributes of tokens within it.

Change rules are typed or loaded into the topmost frame -- hereinafter
the "rules window". They are read in automatically if specified on the
command line preceded by `-r '. They are also read in response to the
Open and Revert commands on the Rules menu (keyboard shortcuts
control-shift-o and control-shift-r respectively).

Before being applied to the document, change rules are compiled into a
more efficient internal representation. This compilation occurs when
change rules are first read in, and additionally whenever a selection
is made in the document window when the rules window is
"dirty". ("Dirtiness" is implemented in crude fashion: any keystroke
or mouse click in the rules window renders it dirty.)

If any rules are syntactically ill-formed, they are highlighted (in
yellow!). Such rules are not compiled, but their erroneous status does
not affect other rules. You may correct the errors or proceed.

Finally, rules are applied only if Apply has been checked. Toke begins
with this option unset. Normally, the display is not updated until all
rules have been applied to the entire selected range of
tokens. However, if you check Incremental you will see the text change
progressively as each rule is applied to each token. (This option
greatly slows things down.)



3.1	Syntax of change rules

Each change rule occupies a single (physical) line of text. If the
first non-space character is `%' (the percent sign) the rule is
treated as a comment and otherwise ignored. 

Rules consist of a condition and, optionally, an action. The condition
is enclosed within angle brackets. For example, the following rule

	 delete

deletes any token that is one of the inflectional forms of the verb
`to be'. The following rule

	

triggers on instances of "Henry" but otherwise does nothing. (This
mechanism may be useful for extending the notation beyond change rules
proper.)


3.1.1	Syntax of conditions

Conditions test for the (in)equality of some attribute with a single
value or a list of values. Single values are mentioned directly:

	

Lists of values consist of symbols enclosed in parentheses and
separated by white space. The following rule

	 delete

deletes tokens consisting of any inflectional form of any of the
listed verbs.

Values, whether mentioned individually or in lists, can consist of any
sequence of letters, digits and the underscore character (i.e. they
are more or less ALGOL-style `identifiers'). If they contain any other
characters, they must be quoted within single or double quotes. Hence:

	

A special value is symbolized by an asterisk character `*'. This
matches any value at all, and stores the match in an internal
array. The first match is stored as #0, the second as #1, etc. There
can be at most ten such matches, i.e. #0 to #9. (The use for this
mechanism is discussed below, under Actions (3.2).)

Conditions can be conjoined, by being separated by a comma. Conjunctions
are evaluated from left to right. Evaluation ceases with the first
sub-condition to fail. The following

	

identifies tokens which are unambiguously nouns (or at least they're
not also verbs). A more thorough attempt would be:

	


3.1.2	Predicates

The following predicates are currently available to test against:

	literal		the actual text of the token
	lexeme		the base form of the token as recovered from
			the morphological analyser
	category	the syntactic part-of-speech of the token
	inflection	the string representing inflections as
			reported by the morphological analyser
	type		the typographical `type' of the token as
			established by the tokenizer; types are:
				w	"word"
				p	"punctuation"
				a	"ambiguous"
	class		the typographical `class' of the token as
			established by the tokenizer; some classes are:
				lower-alpha
				upper-alpha
				init-cap-alpha
				numeric
				question-mark
				hyphens
	follow		the following white-space characters that are
			attached to the token


3.1.3	Relations

The following operators can be used to relate predicates with
individual values or lists of values:

	==		the LHS is identical to the RHS
	!=		the LHS is not identical to the RHS
	=~		the LHS contains the RHS
	!~		the LHS does not contain the RHS

	[Note: `==' and '!=' are implemented with strcmp(3),
	while `=~' and `!~' are implemented with strstr(3).]

When the RHS is a list, the sense of the operators works as follows:
the positive ones, `==' and `=~', succeed if a match is made against
_any_ element of the list, whereas the negative ones, `!=' and `!~',
succeed only if _no_ element of the list matches. For example,

	

succeeds if the base of the current token is any of the mentioned pet
animals, while

	

succeeds if the base of the current token is _not_ any such pet.

	[Note: In other words, the negator is given scope over the
	whole expression:  is treated as if
	!, which is itself illegal, however.]

When the RHS is the wildcard value `*', the match succeeds regardless
of which operator is used. Thus  and  mean
exactly the same thing, though the former notation is intuitively more
appealing.


3.1.4	Subscripts

An unadorned predicate name, such as `lexeme', is understood as
applying to the _current_ token. Alternatively, a predicate can apply
to some other token which is calculated relative to the current
token. This is achieved by supplying a _subscript_, which is enclosed
in square brackets.

The most straightforward subscript is a positive or negative integer
which specifies an offset relative to the current token. Positive
integers specify offsets after the current token, negative integers
offsets before the current token. The current token has offset
zero. Therefore:

	lexeme[0]	is the same as `lexeme'
	lexeme[1]	refers to the next token
	lexeme[+1]	ditto
	lexeme[-1]	refers to the previous token

It is safe to specify very large offsets: they will be constrained so
as never to refer to anything before the first or after the last
token. For example,

	category[-10000]

is a reasonable way to query the category of the first token, in a
document that contains fewer than 10,000 tokens. (There is no way to
specify _absolute_ token positions.)


3.1.5	Ranges

A subscript need not identify just a single offset. By separating a
pair of offsets with a colon `:', it is possible to specify a
range. So:

	type[-5:-1]	refers to the type of any of the five tokens
			preceding the current token
	type[-1:+1]	refers to the type of an adjacent token, as
			well as the current token
	type[-10000:10000]
			might be a reasonable way to refer to the
			type of any token in the document

Ranges are processed in ascending numerical order, until either a
match is found or the range is exhausted. For instance, given the
following scrap of text, with the underlined token being current,

	man is born free but _everywhere_ he is in chains

the following condition will succeed on `man', and cease further
scanning:

	

(This is because `man' is listed as a verb as well as a noun.)


3.1.6	Conditional subscripts

It is possible to specify an offset from the current token not only
numerically but conditionally. The token so identified (if any) is the
nearest token to the current token for which the condition
succeeds. Specifically, scanning proceeds outwards from the first
token after the current token (for positive offsets) or the first
token before the current token (for negative offsets), until a match
is found or the entire remainder of the document is scanned.

Conditional subscripts have exactly the same syntax and semantics as
top-level conditions, in full generality. For example,

	lexeme[-]

retrieves the lexeme attribute of the nearest verb to the left, while

	literal[]	or equivalently
	literal[+]

retrieves the literal form of the nearest following (unambiguous)
punctuation character, and

	lexeme[-]

retrieves the base form of the nearest token to the left which is
itself immediately followed by a verb (if the current token is a verb,
this will be the preceding token).

Note one important difference between conditional and numerical
subscripts: numerical scubscripts always identify some token, even if
it is the first or the last in the document; conditional subscripts may
fail to identify any token (in which case the larger test they are a
part of fails).


3.2	Actions

Actions consist of the insertion, deletion, or replacement of tokens,
signalled by the keywords `insert', `delete', and `change'
respectively. The next argument is an optional token identifier, which
has the syntax and semantics of subscript selectors (though without the
enclosing square brackets). In its absence, the action is applied to
the current token. So

	delete		means delete the current token
	delete 0	means the same
	delete -1	means delete the previous token
	delete -
			means delete the nearest preceding preposition

(The token identifier must identify a single token: it cannot be a
range.)

For `insert', the token identifier identifies the token _before_ which
the insertion is made.

The `change' and `insert' actions take a further argument which
specifies the material to be inserted, or by which the identified
token should be replaced (`change' is simply `delete' plus
`insert'). This material can be specified in two ways: as a literal
string, or as the result of a function call.

Literal strings are simply mentioned, quoted if necessary. The
following changes tokens which are determiners to the string `DET':

	 change DET		or equivalently,
	 change 0 DET		  "    "    "
	 change "DET"		  "    "    "
	 change 0 "DET"

Function calls are enclosed in curly braces. The first identifier
names the function and subsequent identifiers, separated by white
space, name the arguments.

Currently only one function call is supported: `gen' takes three
arguments -- a base form, a category, and a string specifying
inflectional information -- and returns, if it can, an appropriate
surface form. The following action changes the current token to the
form `making':

	change {gen make V PROG}

If gen cannot retrieve an appropriate surface form, it returns the
string `???', which serves as a conspicuous reminder that the action
did not go as you presumably expected.

A literal argument to an action, or any of the arguments to a
function, can also be specified in the form `#n', i.e. the hash sign
plus a digit. Such a specification is replaced by the n'th string that
was remembered by a previous occurrence of `*', or by the empty string
if there wasn't an n'th remembered string.

For example, the following rule is intended to put all verbs into
their infinitive form

	 change {gen #1 V INF}

while the following is intended to change instances of `die' to 
`cark' in the appropriate inflectional guise:

	 change {gen cark V #1}

And the following replaces every token which has a morphological entry
with its base form:

	 change #1

(See 3.2.4 for why these probably won't work quite as you expect.)

Actions, like conditions, can be conjoined. Conjoined actions are
executed sequentially from left to right.


3.2.1	Changes and the `follow' string

The text is tokenized in such a way that white space following a token
is generally included as part of that token, as the value of a special
`follow' attribute. The question arises what to do with this when
applying changes to the token.

On a `change', there is no change to the follow.

On an `insert', a space is added after the inserted token, and becomes
the value of its follow.

On a `delete', the follow is also deleted, _unless_ it consists of one
or more linefeeds.


3.2.2	Changes and tokenization

Changed and newly inserted tokens are entered as `fake' tokens, of
type `?' and class `unknown'. [They should, of course, be retokenized
properly.]


3.2.3	Rule Application Protocol

The application of change rules to the selected text within a document
proceeds according to a well-defined rule application protocol, which 
goes as follows:

	(1)	The range of selected tokens is identified, and
extended to include any partially selected tokens (this includes
tokens whose `follow' lies within the selection).

	(2)	The entire set of rules is applied to each token in
the range, in ascending numerical order, but subject to (7).

	(3)	For each token, the rules are applied in sequential
order, starting with the textually earliest rule.

	(4)	For each rule, the condition is first tested, and if
it succeeds, the action is executed.

	(5)	Each component of the condition is tested separately,
and with no effect from previous components except that any component
which fails will cause the whole condition to fail.

	(6)	Each component of the action is executed in
turn. Whatever changes each component prescribes -- including changes
to the text and insertion and deletion of tokens -- are made
immediately.

	(7)	Action components which specify the insertion or
deletion of tokens return an integer (0, 1, or -1) which specifies the
amount by which the current token is renumbered. The number is
non-zero if and only if an insertion or deletion was made _at or
before_ the current token. This number is propagated back up through
all steps of the protocol up to step (2).

The important parts of this to bear in mind are steps (5) and
(7). Some examples will make the process clearer.


3.2.4	Each component of a condition is tested separately

Take the following rule:

   change {gen operate V #1}

The rule evidently intends to replace (arguably sexist) occurrences of
`man' as a verb with the inflectionally appropriate form of
`operate'. But whether it will work or not depends entirely on the
order in which the morphological analyser returns the various analyses
of `man'. 

Imagine that the current token is literally `man'. Then the
morphological analyser might return the following records, in the
given order:

	(1)	man	V	INF
	(2)	man	N	3sg

The sub-condition  succeeds on the first analysis, so the
next sub-condition is tested. The sub-condition  succeeds
on the first analysis, so the next sub-condition is tested. The
sub-condition  succeeds on the first analysis, and as a
side effect sets #1 to be `INF'. Then the action calls for the
generation of `operate V INF', which returns `operate', which gets
substituted for `man'. So far so good.

Now imagine instead that the morphological analyser returns the noun
and verb senses in the opposite order, as

	(1)	man	N	3sg
	(2)	man	V	INF

The  sub-condition succeeds on the first analysis; the
 sub-conditions fails on the first analysis but succeeds
on the second; the  succeeds _on the first analysis_
and thus sets #1 to be `3 sg'. The action will then call for the
generation of `man V 3sg'; this will probably fail and return `???',
but even if it didn't fail it would return `operates' rather than
`operate'. This is not what was intended.

The order in which the morphological analyser returns competing
analyses is for all intents and purposes arbitrary (it is not
consistent). But even if the order were fixed and publicly known, this
would not help much, as the semantics of conditions as currently
implemented specifies that conditions succeed on the _first_
successful match. In our present instance it would therefore help if
verb senses were consistently returned before noun senses, but
precisely this order would fail for some other conceivable rule.


3.2.5	Insertion and deletion of tokens can change the loop index

When a token is deleted, all following tokens are renumbered
immediately to be one less than they were. Similarly, when a token is
inserted, all following tokens are renumbered immediately to be one
greater than they were.

At the same time, these insertions and deletions occur under the
control of the loop (step (2) in 3.2.3) which sequentially processes
a range of numerically-identified tokens. If nothing special were done
to prevent it, the interaction of insertions and deletions with the
controlling loop index would have two undesirable consequences:

(a)	after a deletion of the current token or any token before it,
	the next token would not get processed at all (e.g. deleting
	token #5 causes the erstwhile token #6 to become token #5; but
	the loop would still move on to process what is now token #6,
	and the former #6 would escape processing altogether);

(b)	after an insertion before the current token or any token
	before it, the current token would have its index increased
	by 1, and would therefore get processed again on the next
	round; it is quite possible that this would lead to an
	infinite loop where the current token constantly resatisfies
	the conditions for inserting something before it.

To avoid these problems, change rules and every relevant component of
them return the amount by which the current token has been renumbered,
and this number is used to adjust the loop index. This renumbering is
also applied to the components of a single action, so that actions
consisting of several changes work as expected. For instance, the
following changes `delightful' to `very nice':

	 insert very, change nice

Without renumbering, this rule would insert `very' and then change
_it_ to `nice', resulting in `nice delightful'. But in fact the
meaning of the (implied) token identifier 0, namely some N, changes to
N+1 between the insertion and the change.

The rule is that each successful single deletion at or before the
current token changes the meaning of `current token number' by
subtracting one from it, and each successful single insertion before
the current token changes the meaning of `current token number' by
adding one to it. Since a single action can perform multiple
insertions and deletions, the overall loop index controlling
application of the change rules might get changed by an arbitrary
amount between change rules. It will never, however, become less than
zero or greater than the current number of tokens in the document.

Note that this behaviour, while helpful, does not solve all problems
posed to the numbering of tokens by the possibility of insertions and
deletions. In particular, deletions and insertions _after_ the current
token are not taken account of, and can cause the change rules to be
applied to a greater or smaller range than was originally selected.


3.3	Using Toke non-interactively

If you supply the option `-i' on the command line, Toke will operate
in a non-interactive mode. Amongst other things, this means that it
does not require an X server, so it can be used from a dumb terminal.

In non-interactive mode, Toke assumes that the purpose of the exercise
is to apply a set of change rules to a document to produce a new
document. The new document is piped to the standard output, so you
will probably want to redirect it.

If either a rules file or a document file is not specified on the
command line, Toke reads the standard input for these. It reads a
rules file (if necessary) first, and then a document file. If the
standard input is coming from your terminal, you can just type in
rules (followed by Control-D), and then a text (also followed by
Control-D). If either a rules or a document file has been specified
on the command line, the other will be taken from the standard input.

It makes no sense (though it is allowed) to ask Toke to read both its
rules and its document from _redirected_ standard input. What will
happen is that the piped stream will be used up as the rules file, and
the document will appear to be empty, and no output will be
produced. Caveat user.

Here's an example of using Toke in non-interactive mode to test a rule
whose intended effect is to strip punctuation from a document:

	% toke -i
	 change ""
	^D
	"What do you want now?" asked Mary. "I'm so tired."
	^D
	What do you want now asked Mary I'm so tired


4.0	Tips, Tricks and Caveats

*** Sick of menu selections?

	Most of the menu items have control-key equivalents. Most
items on the File and Search menus can be accessed by typing control +
first character of item. Most items on the Rules menu can be accessed
by typing control + shift + first character of item.

*** Change rules not getting applied?

	Make sure Apply has been checked. Toke starts with this option
turned _off_.

*** Want to process the whole document?

	Type Control-a to select the whole text.

*** Results of change rules unexpected?

	Try checking Incremental. By seeing the changes as they
happen, it may become clearer where something is going wrong.

*** Change rules working too slowly?

	Try unchecking Info. Building the display of information in
the bottom window is quite expensive.

*** Delete key not working in rules window?

	It does, but it deletes _forward_. Use the backspace key to
delete backward.

*** Morphological generator function returning `???'?

	Trivially this of course means that it couldn't generate a
surface form with the arguments you gave it. The real reason could be:

	- you're passing it inflectional specifications for the wrong
part of speech (see 3.2.4).

	- inflectional over-/under-differentiation. The verb
`be' has more specific inflectional markers than other verbs,
e.g. a special 1st-person singular present form. Trying to generate
forms of another verb with such a specification won't work. Similarly
the modal verbs lack non-finite forms. In general, generation of
surface forms works only when an _exact_ match to the supplied
inflectional string is found.

	- the entry you want isn't listed. In compiling a reverse
database to support generation of surface forms, approximately 500
items had to be omitted because they overflowed the internal buffer
used by the Penn program that creates a database from a text
file. Mostly these were forms of great length and low frequency
(e.g. `Afro-Americaner', `Afro-Americanest'), but they also included
_all forms of the verb `be'_ and all contractions such as `can't',
etc.

*** Linefeeds not getting deleted or changed?

	They won't be. As a special (and temporary) measure, tokens
consisting of line-feeds cannot be changed or deleted. In fact nothing
can be done that alters the line structure of the document.

*** Woops, I shouldn't have done that!

	You can revert the document (or the rules). Of course this
loses all the changes you've made since the last disk load, so perhaps
you should save your document (or rules) every so often when things
do go right.

*** Stop, I want to get off!

	You can't. There's no interrupt mechanism at present. If you
really don't like what's happening and you can't wait for it to
finish, select the Console window and type Control-C. This will abort
the program. [Yes, this will get fixed.]


[jcj 21-Apr-97]

Comments to jcj@mail.usyd.edu.au