This file is the documentation for the Lisp Trace package.  It is
admittedly out of date, but nonetheless better than nothing.  Improve
it!

  08/01/72 

The Lisp Trace package consists of three main functions,
Trace, untrace, and remtrace, all of which are fexprs.

A call to Trace has the following form:
	(Trace <Trace specs>)
a "Trace spec" in turn is either an atom (the name
of the function to be Traced) or a list of this form:
	(<function name> <options>)
where the options are as follows:

Break <pred>    causes a break after printing the entry
		Trace (if any) but before applying the
		Traced function to its arguments, if
		and only if <pred> evaluates to non-nil. 

Cond <pred>     causes Trace information to be printed
		for function entry and/or exit if and
		only if <pred> evaluates to non-nil.

Entrycond <pred> causes Trace information to be printed for
		function entry if and only if <pred> evaluates to
		non-nil. If both cond and entrycond are used, the
		<pred> specified for cond is evaluated first; and
		both <pred>'s must evaluate to non-nil for
		entry Trace information to be printed. If the
		<pred> for cond evaluates to nil, then the <pred> for
		entrycond will not be evaluated.

Exitcond <pred>	causes Trace information to be printed for
		function exit if and only if <pred> evaluates to
		non-nil. If both cond and exitcond are used, both must
		evaluate to non-nil for exit Trace information to be
		printed. Note that the <pred> for cond is
		not re-evaluated on exit; rather, its value on entry
		is saved. If this value is nil, then the <pred>
		for exitcond will not be evaluated.

Wherein <fn>    causes the function to be Traced only
		when called from the specified function.
		One can give several Trace specs to Trace,
		all specifying the same function but with
		different wherein options, so that the
		function is Traced in different ways when
		called from different functions. Note that
		if the function specified by the wherein
		option is already being Traced itself, the
		wherein option probably will not work as
		desired, probably. (Then again, it might.)  
		Note that <fn> must be an interpreted function,
		since the wherein Trace involves altering
		the calling function as well as the called.

Argpdl <pdl>    specifies an atom <pdl> whose value Trace
		initially sets to nil. When the function is
		Traced, a list of the current recursion
		level for the function, the function's
		name, and a list of the arguments is consed
		onto the <pdl> when the function is entered,
		and cdr'ed back off when the function is
		exited. (Actually, this consing/cdring is done by
		means of lambda-binding, so that if an error or
		other interrupt occurs the <pdl> will be reset by
		unbinding.) The <pdl> can be inspected from a
		breakpoint, for example, and used to
		determine the very recent history of the
		function. This option can be used with or
		without printed Trace output. Each function
		can be given its own pdl, or one pdl may
		serve several functions. 

Entry <list>    specifies a list of arbitrary s-expressions
		whose values are to be printed along with
		the usual entry Trace. The list of
		resultant values, when printed, is preceded
		by a \\ to separate them from the other
		information.

Exit <list>     similar to entry, but specifies expressions
		whose values are printed with the exit Trace.
		Again, the list of values printed
		is preceded by \\.

Arg     	specify that the function's arguments,
value		resultant value, both, or neither are to
both		be Traced. If not specified, the default
nil		is both. Any "options" following one of
		these four are assumed to be arbitrary
		s-expressions whose values are to be printed
		on both entry and exit to the function.
		However, if arg is specified, the values are
		printed only on entry, and if value, only on
		exit. Note that since arg, value, both, nil,
		swallow all following expressions for this
		purpose, whichever one is used should be the
		last option specified. Any such values
		printed will be preceded by a // and will
		follow any values specified by entry or exit
		options.


If the variable arglist is used in any of the expressions
given for the cond, break, entry, exit, or after-the-arg-
value-both-or-nil options, when those expressions are
evaluated the value of arglist will effectively be a list
of the arguments given to the Traced function. Thus
	(Trace (foo break (null (car arglist))))
would cause a break in foo iff the first argument to
foo is nil. Similarly, the variable fnvalue will effectively
be the resulting value of the Traced function; since the value
of the function is of course available only on exit
from the function, this should only be used with the exit and
exitcond options. Also, the variable recurlev, on both entry and
exit, will effectively have as its value a number indicating the
current recursion level (as would be printed by Trace). This
allows conditional breaks and Traces based on the depth
of recursion. The recursion level is incremented by means of
lambda-binding; thus if an error or other interrupt occurs,
the recursion level will be reset by unbinding.
(Note that the word "effectively" is used in describing the
values of the above "variables" since these variables are
not actually used; Trace actually performs a sublis on the
expressions for the options mentioned above, substituting
certain non-interned atoms for any and all appearances of
the special "variables" mentioned above. Therefore, do
not try to use these variables for anything but obtaining
their values when using them in expressions for the above
options.)

In addition to using the variable arglist, expressions
for Trace options may refer to the actual names of
the function's arguments if the function is interpreted rather
than compiled. Furthermore, such argument variables may
be examined from breakpoints.

 
Trace uses the Prin1 current at the time of printing the trace
for its printouts.  Thus, in order to have your Trace output
passed through Grind, you might perform (setq prin1 'Sprint);
for debugging Macsyma internals, (Fasload Funpr Fasl Dsk Libmax)
(setq prin1 'Funprint).  You can also use the Grind option
(Trace (foo Grind)), but of course this uses the system grind.

Examples of calls to Trace:

[1] to Trace function foo, printing both arguments on entry
and result on exit:
	(Trace foo)  or  (Trace (foo))  or  (Trace (foo both)).

[2] to Trace function foo only when called from function bar,
and then only if (cdr x) is nil:
	(Trace (foo wherein bar cond (null (cdr x))))
     or (Trace (foo cond (null (cdr x)) wherein bar)).
As this example shows, the order of the options makes no
difference, except for arg, value, both, or nil, which must
be last.

[3] to Trace function quux, printing the resultant value
on exiting but no arguments on entry, printing the value
of (car x) on entry, of foo1, foo2, and (foo3 bar) on exit,
and of zxcvbnm and (qwerty shrdlu) on both entry and exit:
	(Trace (quux entry ((car x)) exit (foo1 foo2 (foo3 bar))
		value zxcvbnm (qwerty shrdlu))).

[4] to Trace function foo only when called by functions bar
and baz, printing args on entry and result on exit, printing
the value of (quux barf barph) on exit from foo when called
by baz only, and conditionally breaking when called by bar if
a equals b:
	(Trace (foo wherein bar break (equal a b))
		(foo wherein baz exit ((quux barf barph)))).

[5] to Trace functions phoo and fu, never printing anything
for either, but saving all arguments for both on a common pdl
called foopdl, and breaking inside phoo if x is nil:
	(Trace (phoo argpdl foopdl break (null x) cond nil nil)
		(fu argpdl foopdl cond nil nil)).
The "cond nil" prevents anything at all from being printed.
The second nil in each <Trace spec> specifies that no args
or value are to be printed; although the cond nil would
prevent the printout anyway, specifying this too prevents
Trace from even setting up the mechanisms to do this (which
it would, against the possibility that someday nil might not
evaluate to nil.)

[6] to Trace function foobar, printing args on entry and
result on exit, plus the value of moby-expr on exit, and
pretty-printing the output:
	(Trace (foobar grind exit (moby-expr))).

[7] to Trace function ghoti, one of whose arguments is
fish, printing all arguments only if fish
is non-nil, and printing on exit only if the result is not
a number:
	(Trace (ghoti entrycond fish
		      exitcond (not (numberp fnvalue)))).

[8] to Trace function ssehc, printing Trace output only if
draob is non-atomic, and even then on entry only if pohsib is
a negative number, breaking when the recursion level is either
3 or greater than 7:
	(Trace (ssehc cond draob
		      entrycond (and (numberp pohsib) (minusp pohsib))
		      break (and neeuq (or (equal recurlev 3)
					   (lessp 7 recurlev))))).


Trace returns as its value a list of names of all functions
set to Trace; for any functions Traced with the wherein
option, say (Trace (foo wherein bar)), instead of returning
just the name it returns a 3-list (foo wherein bar).
If Trace finds a <Trace spec> it doesn't like, instead of the
function's name it returns a list whose car is ? and whose
cdr indicates what Trace didn't like. (This should be slightly
more helpful than the oold Trace, which simply returned nil.)
A list of possible error indications:

(? wherein foo)     Trace couldn't find an expr, fexpr, or
		    macro property for the function specified by the
		    wherein option; or the function specified was not
		    atomic.

(? Argpdl foo)      the item following the argpdl option was
		    not a non-nil pname-type atom.

(? Foo not function) indicates that the function specified
		    to be Traced was non-atomic, or had no functional
		    property. (Valid functional properties are expr,
		    fexpr, subr, fsubr, lsubr, and macro.)

(? Foo)		    foo is not a valid option.

Thus a call to Trace such as
	(Trace (foo wherein (nil)) (bar argpdl nil))
would return, without setting up any Traces,
	((? wherein (nil)) (? argpdl nil)).

If you attempt to specify to Trace a function already
being Traced, Trace calls untrace before setting up the new
Trace. If an error occurs, causing (? <random>) to be
returned, the function for which the error occurred may or
may not have been untraced. Beware!

it is possible to call Trace with no arguments. (Trace)
returns as its value a list of all functions currently
being Traced.




Untrace is used to undo the effects of Trace and restore
functions to their normal (?) untraced state. The argument
to untrace for a given function should be essentially what
Trace returned for it; i.e. If Trace returned foo, use
(untrace foo); if Trace returned (foo wherein bar) use
(untrace (foo wherein bar)). Untrace will take multiple
untrace specifications, e.g. (Untrace foo quux (bar 
wherein baz) fuphoo). Calling untrace with no arguments
will untrace all functions currently being Traced.



Remtrace, oddly enough, expunges the entire Trace package.
It takes no arguments.



