The Revised Maclisp ManualThe PitmanualPage A-22
Published by HyperMeta Inc.
 
Prev | Index | Next
[Blue Marble]
Climate Change
What was wrong with the electric car?


Debugging


DESCRIBEFunction(DESCRIBE object [file])

Describes the nature of the given object. If a file is specified, the output is directed to that file. The symbol * is returned.

(setq foo (open '(test file) 'out))
=> #FILE-OUT-|DSK:JDOE;TEST FILE|-70726

(setq four 4)
=> 4

(describe four)
4 is a FIXNUM

=> *

(describe 'four)
The value of FOUR is 4
  4 is a FIXNUM

=> *

(describe foo)
#FILE-OUT-|DSK:JDOE;TEST FILE|-70726 is a FILE

=> *

(describe four foo)
=> *

(close foo)
=> T

Web-Only Note:

No entry for this function was included in the hardcopy edition. For completeness, this entry was added for the webbed edition.

The *RSET Family


*RSETValueT

*RSET is a debugging switch. If *RSET is not NIL, the interpreter keeps extra information (see EVALFRAME) and makes extra checks to aid in debugging. If NIL, many error checks are skipped, allowing faster execution at the risk of allowing certain errors to go undetected.


*RSETFunction(*RSET val)

Sets the *RSET flag to NIL if val is NIL, to T if val is not NIL, and returns the value it set it to. See description of the variable *RSET.

Definition:

(DEFUN *RSET (VAL) (SETQ *RSET (NOT (NOT VAL))))

*RSET-TRAPValue+INTERNAL-*RSET-BREAK

The value of *RSET-TRAP, if not NIL, is the handler function for the condition which is signalled when an error returns control to top level, just before the bindings are restored.

UUO Links


NOUUOValueNIL

The value of the variable controls the creation of UUO links by the UUO handler. If not NIL, then links will not get snapped; if NIL, the links will be snapped, providing faster speed. See also PURE and *PURE. Note: having this value be T, and perhaps doing (SSTATUS UUOLINKS) will be needed in an environment where TRACE-type functions will be used.


NOUUOFunction(NOUUO val)

Sets the variable NOUUO to val.

Definition:

(DEFUN NOUUO (VAL) (SETQ NOUUO (NOT (NOT VAL))))

Looking Back Up the Stack


BAKLISTFunction(BAKLIST [pdlptr])

[PDP-10 Only] Returns a list of interesting state information about the stack. Very heuristic and not very fast to do because it involves a MAPATOMS and consing, but requires very little info on the stack in order to do its thing.

Since *RSET dynamically controls whether debugging info is saved on the stack, this may not work as well if *RSET has been bound to NIL during the creation of all or part of the current state.

This is primarily useful as an interactive debugging tools. More complete debugging info is available from the ERRFRAME and EVALFRAME functions.

(* (+ 'a 3) 4)
;A NON-NUMERIC VALUE

;BKPT WRONG-TYPE-ARG
(baklist)
=> ((+INTERNAL-WNA-BREAK _) (+ _) (* _))

BAKTRACEFunction(BAKTRACE [pdlptr])

Displays the stack of pending function calls. An optional argument of a pdlptr (a fixnum; see EVALFRAME) or NIL (meaning show whole stack) may be provided. A printed form of BAKLIST.

Stack Frame Information Facilities


EVALFRAMEFunction(EVALFRAME q)

The argument to evalframe is a pdl ptr, as with ERRFRAME, or NIL to get the most recent stack frame. The pdl is searched for an evaluation of a function call, using the same rules about starting point and direction as ERRFRAME uses. EVALFRAME always skips over any calls to itself that it finds in the pdl.

It returns a list (sym pdlptr form envptr), where sym is one of EVAL or APPLY; pdlptr is a pdl pointer to the evaluation in the stack, suitable for use as an argument to EVALFRAME or ERRFRAME or BAKTRACE; form is the form being evaluated (if sym was EVAL) or the name of the function (if sym was APPLY) being applied; and envptr is a fixnum pointer to the stack environment (sometimes loosely called an `a-list pointer' in memory of the days when variable bindings lived on an actual a-list) which can be used with EVAL or APPLY to evaluate something in the binding context which corresponds to the stack frame represented by this return list.

EVALFRAME returns NIL if no evaluation can be found. One way this can happen is if *RSET is bound to NIL and not enough debugging information has been kept, but it may happen in other ways as well.

Non-Local Return


FRETRYFunction(FRETRY pdlptr form)

[PDP-10 Only] FRETRY “unwinds” the stack to the point indicated by the first argument, which should be a pdl pointer such as would be in the list returned by EVALFRAME, and it then evaluates the form extracted from its second argument, which should be a list such as would be returned by EVALFRAME. It was intended primarily to be used to “re-try” something that appears to be losing, but which has been corrected (say, in an error break loop).

;; A simple use to retry a form on the stack after error 
;; correction.
(SETQ EF (EVALFRAME ...)) ; Get some evalframe in EF
(FRETRY (CADR EF) EF)	  ; Retry that evaluation

;; A more complex usage for debugging
(SETQ PP (GET-PDL-PTR <some-state>))
 ; Return upward to a certain stack frame, then stop and
 ; look around at what's in that environment...
(FRETRY PP `(EVAL ,PP (BREAK STOP-AND-LOOK)))

FRETURNFunction(FRETURN pdlptr val)

Returns control to the evaluation context designated by its first argument, which must be a fixnum pdl pointer and forces it to return val. This “non-local-return” function can be used to do fancy recovery from errors. (See also TRACE)

The EVALHOOK variable


EVALHOOKValueNIL

Whenever the function eval is entered, whether from within the system or by explicit invocation by the user, then if the value of the variable EVALHOOK is not NIL, and *RSET is not NIL, and (SSTATUS EVALHOOK T) has been done, then eval does not evaluate its argument. Instead it assumes that the value of the variable EVALHOOK is a function of one argument. It fetches this function, lambda-binds evalhook to NIL, and calls the function with the argument to eval. This function then has the responsibility for evaluating the form and returning a result. This result becomes the result of the original call to EVAL. It is evident that such a function can do other things besides evaluate the form; e.g. it can print trace information. The reason that EVALHOOK is bound back to NIL before calling the hook function is because the hook function may be interpreted, and we want to avoid infinite recursion. there is a problem, though: how can the hook function evaluate its argument once it has printed stuff out? If it just calls eval back again, then the variable EVALHOOK will be NIL, and the hook function will not get called for the recursive calls on EVAL. If it SETQ's EVALHOOK to the hook function and then calls EVAL, the hook function will get called back with the same thing. For this reason there is an EVALHOOK function.

The EVALHOOK function


EVALHOOKFunction(EVALHOOK form hookfn [env])

Calls EVAL with its first argument, after binding the variable EVALHOOK to its second argument and bypassing the hook function check in EVAL. The third argument, env, is optional and allows the user to specify a pointer to an environment that the evaluation should occur in (see EVALFRAME).

On Multics, this function takes only the two required arguments; the optional env argument is not permitted.

;; This DEMO doesn't work as shown. It should be fixed 
;;  sometime. But for now, if you just try the things it says
;;  you'll get the idea (sigh)...
(DEFUN HOOK FEXPR (X) ;Called as (HOOK <form>)
       (LET ((*RSET T) ; Enable debugging mode
             (EVALHOOK 'HOOK-FUNCTION)) ; Enable our hook
            (PROG2 (SSTATUS EVALHOOK T); Do the magic SSTATUS
                   (EVAL (CAR X))	; Evaluate form
                   (SSTATUS EVALHOOK NIL)))) ; Ugh! Can't bind!

(DEFUN HOOK-FUNCTION (F)
   (FORMAT T "~&Form:  ~S" F) ; Display form to be EVAL'd
   (LET ((V ;V gets value of form, recursively eval'd with hook
          (EVALHOOK F 'HOOK-FUNCTION)))
     (FORMAT T "~&Returned: ~S" V) ; Display value returned
     V))  ; Don't forget to return the value

; Thus we could do 
(HOOK  (CONS (CAR '(A . B)) 'C))
Form:  (CONS (CAR (QUOTE (A . B))) (QUOTE C))
Form:  (CAR (QUOTE (A . B))
Form:  (QUOTE (A . B))
Returned: (A . B)
Form:  (QUOTE C)
Returned: C
Returned: ((A . B) . C)
=> ((A . B) . C)

;Naturally, one can dream up infinitely hairy things to do
;with this, such as interactive tracing and breaking,
;indented output, etc.

EVALHOOKStatus Option(STATUS EVALHOOK)

The release notes for this operation say: “... (STATUS EVALHOOK) exists but does not return anything meaningful at all.” See (SSTATUS EVALHOOK ..) which is more useful.


EVALHOOKSStatus Option(SSTATUS EVALHOOK flag)

Used to enable EVALHOOK operation. The variable *RSET must not be NIL and the variable EVALHOOK must contain a function which will handle the EVALHOOK'ing for this to have much effect (see the EVALHOOK function).

The PDP-10 MarBreak Facility (ITS-Only)


MARStatus Option(STATUS MAR)

Returns NIL if (SSTATUS MAR ...) has not been done, else returns a list which is the state of the mar. The car of that list is the bits that have been set for the mar and the cadr is the location it is trapping on. Note that the bits will have 4 OR'd into them. This is because user mode trapping is forced. Hence, if (SSTATUS MAR 2 ...) was done, then (6 ..) is returned by this status option.

Using the MAR from DDT will not confuse Lisp, and Lisp tries not to confuse DDT. If Lisp is not using the MAR, then it doesn't even take the MAR interrupt from ITS, and so DDT can trap it.

Note: MAR interrupts may not work always correctly. Sometimes you can get infinite recursions because the MAR handler runs too soon and when it is done, the interrupt happens again without getting past the point that tripped it. Beware.


MAR-BREAKValueNIL

The variable MAR-BREAK, if not NIL, is a handler function which is called when the MAR break interrupt is received. The function gets one argument which presently is always NIL.

The MAR facility is a PDP-10 hardware feature which allows Lisp to detect when a given memory location is referenced and gives an interrupt.


MARSStatus Option(SSTATUS MAR i loc)

Sets up a MAR breakpoint on a location, loc, with modes given by i, a fixnum, according to the following table:

0 Turn off the mar feature. 
1 Break on instruction fetch. 
2 Break on write. 
3 Break on all references. 

On the KL-10, these additional values are reputed to work:

#o10 Break on data read. 
#o11 Break on read and fetch. 
#o12 Break on read and write, but not fetch. 
#o13 Break on fetch and write, but not read. 

The 4 bit (Exec vs. User mode) is ignored (User is forced). The loc is any s-expression; that cell is the one monitored.

;; Create a cell to watch
(SETQ FOO (LIST 'A 'B))
;; Set up the MAR to go off when that cell is 
;; RPLACA'd or RPLACD'd.
(SSTATUS MAR 2 FOO)

When the MAR-BREAK interrupt is signalled, an implicit (SSTATUS MAR 0 NIL) has been performed. It is up to the MAR-BREAK function to re-enable the mar if desired. This is similar to the operation of the alarmclock function. The intention is to help prevent infinite loops.

See also documentation on the MAR-BREAK variable which holds the handler for the MAR interrupt.

;; Define a handler for the MAR interrupt
(DEFUN MAR-TRACER (X)
  (FORMAT T "~&;The variable ~S now has the value ~S~%"
          MAR-VARIABLE (SYMEVAL MAR-VARIABLE))
  (SSTATUS MAR 2. (MUNKAM (VALUE-CELL-LOCATION MAR-VARIABLE))))
=> MAR-TRACER
;; Tell lisp what function to use for MAR interrupt handling
(SETQ MAR-BREAK 'MAR-TRACER)
=> MAR-TRACER
;; Define a way of MAR-tracing a function
(DEFMACRO MAR-TRACE (VAR)
  `(PROGN (SETQ MAR-VARIABLE ',VAR)
          (IF (NOT (BOUNDP ',VAR))
              (SETQ ,VAR NIL))
          (SSTATUS MAR 2.
                   (MUNKAM (VALUE-CELL-LOCATION ',VAR)))
          ',VAR))
=> MAR-TRACE
;; Define a way of un-MAR-tracing a function
(DEFMACRO MAR-UNTRACE ()
  '(PROGN (SETQ MAR-VARIABLE NIL)
          (SSTATUS MAR 0. NIL)
          T))
=> MAR-UNTRACE
;; Now trace a variable
(MAR-TRACE QUUX)
=> QUUX
(SETQ QUUX 5)
;The variable QUUX now has the value 5
=> 5
(DO ((QUUX 0 (+ QUUX 1))) ((= QUUX 2)) (HACK QUUX))
;The variable QUUX now has the value 0
;The variable QUUX now has the value 1
;The variable QUUX now has the value 2
;The variable QUUX now has the value 5
=> NIL
(MAR-UNTRACE QUUX)
=> T

Deciphering Random Objects


SUBRFunction(SUBR machinelocation)

[PDP-10 Only] Returns the lisp symbol the address of whose subr/lsubr/fsubr property is such that the machine-address given as an arg is probably part of that definition, or "?" if it is not sure.

Tracing Facilities


TRACESpecial Form(TRACE q1 q2 ...)

The TRACE facility is one of Lisp's oldest debugging tools. Args are not evaluated.

There are many options to TRACE, the simplest of which is (TRACE f), where f is a symbol naming a function to trace. This redefines f so that it types out when it is entered and exited.

If an argument field contains a list rather than a symbol, the car of the list specifies the function, f to be traced, and the remaining elements of the list specify how that tracing should be done. The following options are relevant:

BREAK pred Causes a break just prior to entry of 
 f iff pred evaluates true. 
COND pred Typeout occurs iff pred evaluates true. 
WHEREIN fn Traces f only in fn
ARGPDL sym Upon entry to f, TRACE does a 
 (PUSH (LIST depth fn args) sym) 
 and upon exit TRACE does a 
 (POP sym)
ENTRY (exp1 exp2 ...) Upon entry, does a 
 (PRINT (EVAL expn)) 
 for each exp
EXIT (exp1 exp2 ...) Like ENTRY, but upon exit. 
ARG exp1 exp2 ... Type out only function's arguments. 
VALUE exp1 exp2 ... Type out only function's return value. 
BOTH exp1 exp2 ... Type out both args and return value (default case). 
NIL exp1 exp2 ... Type out neither args nor return values. 

Note that an arbitrary number of forms may follow ARG, VALUE, BOTH, or NIL. The results of evaluating these forms will always be printed out by the traced function upon entry and exit, regardless of whether args or return values are being traced.

The Lisp Machine function BREAK-IN can be simulated by

(TRACE (fn1 WHEREIN fn2))

Tracing can be undone using UNTRACE.


UNTRACESpecial Form(UNTRACE sym1 sym2 ...)

Undoes a TRACE for the given symbols, which are not evaluated. If no symbols are given, all traces are undone.

This function is intended primarily for interactive use and does not become defined in Lisp until after a TRACE has been done.


UUOLINKSStatus Option(STATUS UUOLINKS)

Returns information about the number of available slots for linking between compiled functions. If no links, NIL is returned. Otherwise, the result is a list whose car is some information about purification and whose cadr is a count of free cells (probably only useful if you are out of address space).

Web-Only Note:

The orginal sources show a question mark after the information about the car of the result. I guess that meant I wasn't very sure.


UUOLINKSSStatus Option(SSTATUS UUOLINKS)

Causes all links between compiled functions to be "unsnapped." This should be done whenever (NOUUO T) is done to insure that the interpreter always gets a chance to save debugging information on every function call.

Argument Information


ARGSFunction(ARGS f [data])

If no data is supplied, returns information about the number of arguments expected by f. If f wants n arguments, ARGS returns (NIL . n). If f can take from m to n arguments, ARGS returns (m . n). If f is an FSUBR or a LEXPR, EXPR, or FEXPR, the results are meaningless; usually they will be NIL but that's not guaranteed. In the (m . n) case, an n of #o776 should be taken to mean infinity.

If data is supplied, ARGS sets the args information for f instead of reading it and returns f. Setting args info only works for compiled functions and should not be done for predefined system functions.

Examples:

(args 'time)	=> (NIL . 0)		; no args
(args 'car)	=> (NIL . 1)		; one arg
(args 'list)	=> NIL			; 0 or more args
(args '*array)	=> (2 . 7)		; 2 to 7 args
(args 'mapcar)	=> (2 . #o776)		; 2 or more args

EVALValueNIL

[PDP-10 Only] The symbol EVAL, if not NIL, should be a handler to be called when the car of an expression seen by EVAL is non-atomic and its car is not one of LAMBDA, LABEL, or FUNARG. The function receives the entire form to be EVAL'd and the value it returns is returned as the result of the EVAL.

There is no analogous feature for use at compile time. As such, this feature is strongly discouraged for production systems.

(SETQ EVAL '(LAMBDA (X) (*BREAK T `(WHAT ABOUT ,X ?))))
=> (LAMBDA (X) (*BREAK T `(WHAT ABOUT ,X ?)))
(+ 5 1) ;Normal
=> 6
((LAMBDA (X) X) 3) ;Normal
=> 3
(+ ((ODD FORM) HUH?) 5)
;BKPT (WHAT ABOUT ((ODD FORM) HUH?) ?)
(RETURN 2)
=> 7

PUNTStatus Option(STATUS PUNT)

[PDP-10 Only] If the value of this switch is T, the default, then if a symbol has no functional properties, the evaluator will not bother to look in the value cell of the variable for a functional definition. This switch is only for backward compatibility with a time ages ago when function definitions could also go in the value cell. Semantically and efficiency-wise, such behavior was found to be a bad idea so it was removed. Setting it back to NIL causes the evaluator to do the check in the value cell as a last resort. The term punt is local MIT jargon, meaning to “purposefully ignore or avoid doing something, usually something involving work”; in this case, the thing which may be punted is the value cell lookup. Multics Maclisp behaves as if (STATUS PUNT) were NIL.


PUNTSStatus Option(SSTATUS PUNT x)

[PDP-10 Only] Sets the value of PUNT switch to T or NIL, as given by x.


[Blue Marble]
Climate Change
Are we doing enough?

The Revised Maclisp Manual (Sunday Morning Edition)
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.
Prev | Index | Next