(FILECREATED "30-MAY-79 00:25:14" <LISPUSERS>CIRCLPRINT.;3 19722 changes to: CIRCLPRINTCOMS previous date: " 5-JUL-78 19:49:27" <LISPUSERS>CIRCLPRINT.;2) (PRETTYCOMPRINT CIRCLPRINTCOMS) (RPAQQ CIRCLPRINTCOMS [(FNS CIRCLMAKER CIRCLMAKER1 CIRCLPRINT CIRCLMARK RLPRIN1 RLRESTORE CSEARCH PLACEPRINT C2PRINT ROOMLEFT RLPRIN2 CPRINT CLPRINT CIRCLNC) (VARS CIRCLMARKER) (BLOCKS (CIRCLBLOCK CIRCLMAKER CIRCLMAKER1 CIRCLPRINT CIRCLMARK RLPRIN1 RLRESTORE CSEARCH PLACEPRINT C2PRINT ROOMLEFT RLPRIN2 CPRINT CLPRINT CIRCLNC (ENTRIES CIRCLPRINT CIRCLMARK RLPRIN1 RLPRIN2 RLRESTORE CIRCLMAKER CIRCLMAKER1) (SPECVARS RLKNT LABELIST REFLIST) (LOCALFREEVARS PLACELIST LL) (NOLINKFNS . T) (GLOBALVARS #UNDOSAVES RESETVARSLST]) (DEFINEQ (CIRCLMAKER [LAMBDA (L) (* lmm: 19 MAY 75 232) (PROG (LABELIST REFLIST) (CIRCLMAKER1 L) (* An error is generated if REFLIST is non-NIL, because this means that some nodes are referenced in L without being labeled (i.e. defined) and indicates that the user may have omitted some code. See the comments in CIRCLMAKER1 for additional information.) (COND (REFLIST (ERROR (QUOTE "LABEL NOT FOUND FOR REFERENCE"))) (T (RETURN L]) (CIRCLMAKER1 [LAMBDA (L) (* This function makes use of two free variables, REFLIST and LABELIST, which are alist-like structures that provide information about nodes that have been defined (labeled) and where they have been referenced. LABELIST is a list of lists. Each list in labelist is of the form (n . L), where n is the number that is being used to label the node L. REFLIST is also a list of lists. Each list in REFLIST is of the form (n (L1 L2 ...) (L1' L2' ...)), where n is the number of the node that is being referred to, and L1, L2,... are those nodes for which car is a reference to {n}, and L1', L2',... are those nodes for which cdr is a reference to {n}.) (PROG (CARL CDRL CARLN CDRLN NODECODE) [COND ((LISTP L) (SETQ CARL (CAR L)) (SETQ CDRL (CDR L] (COND [(AND CARL (ATOM CARL)) (COND [[AND (NEQ CARL (QUOTE {})) (EQ (NTHCHAR CARL 1) (QUOTE {)) (EQ (NTHCHAR CARL -1) (QUOTE })) (FIXP (SETQ CARLN (MKATOM (SUBSTRING CARL 2 -2] (* This part of the conditional checks to see whether CARL is a reference to a node, i.e. an atom of the form {n}, where n is a number. If so, then we check to see whether the node has yet been labeled (this is the assoc on labelist), whether it has been previously referred to, but not labelled (this is the assoc on reflist), or else assume that it has neither been referred to nor labelled previously. In the first case, we replace (/rplaca) CARL with a pointer to the node that is labelled n (as explained above, this would be cdr of nodecode). In the second case, we add a pointer to L to (cadr nodecode) which is that part of REFLIST which contains pointers to those nodes for which car is the atom {n}. In the final case, we add a new sublist to REFLIST, to record that a reference has been made to a node numbered n. It should be noted that, throughout this program, all such manipulations are undoable, so that the user can (for example) control-D and undo circlmaker to regain his original expression.) (COND ((SETQ NODECODE (ASSOC CARLN LABELIST)) (/RPLACA L (CDR NODECODE))) ((SETQ NODECODE (ASSOC CARLN REFLIST)) (/NCONC1 (CADR NODECODE) L)) (T (SETQ REFLIST (/NCONC1 REFLIST (LIST CARLN (LIST L) NIL] ([AND (NEQ CARL (QUOTE *)) (NEQ CARL (QUOTE **)) (EQ (NTHCHAR CARL 1) (QUOTE *)) (EQ (NTHCHAR CARL -1) (QUOTE *)) (FIXP (SETQ CARLN (MKATOM (SUBSTRING CARL 2 -2] (* This part of the conditional checks to see whether CARL is a label for a node, i.e. an atom of the form *n*, where n is a number. If so, then we check to see whether a node has already been labelled by the same number, in which case an error is generated (*n* is ambiguous, multiply used label). Otherwise, we check to see that cdr of l is a list, in which case we physically (but undoably) remove the label from L , add a new sublist to LABELIST, and check to see whether there is a sublist on REFLIST that indicates that references to L have already been made. If so, then we make the appropriate changes to car and cdr of the nodes wwich referenced L, and undoably remove the sublist (NODECODE) from REFLIST, because the only purpose of this sublist was to preserve a record of those nodes which referenced L, before the label for L was found and the actual pointers from those nodes to L could be established-- now that the pointers have been established, we can decrement REFLIST-- if all nodes that are referenced are in fact labeled somewhere in the structure, then REFLIST should eventually in this way be decremented to NIL-- otherwise the monitoring function CIRCLMAKER will generate an error, if it was the top level function that called CIRCLMAKER1. Finally, we call circlmaker1 recursively on L, and return the resultant value of L. If the original cdr of l were not a list, then we would generate the CARL "IS MISPLACED LABEL" error-- this is intended to handle expressions like (*1* . {1}), which are anomalous because the label does not really point to a node, and there is a likelihood that the user has inadvertently omitted some code.) (COND ((ASSOC CARLN LABELIST) (ERROR CARL (QUOTE "IS AMBIGUOUS, MULTIPLY USED LABEL"))) ((LISTP (CDR L)) (/RPLACA L (CADR L)) (/RPLACD L (CDDR L)) (SETQ LABELIST (/NCONC1 LABELIST (CONS CARLN L))) [COND ((SETQ NODECODE (ASSOC CARLN REFLIST)) (SETQ REFLIST (/DREMOVE NODECODE REFLIST)) [MAPC (CADR NODECODE) (FUNCTION (LAMBDA (X) (/RPLACA X L] (MAPC (CADDR NODECODE) (FUNCTION (LAMBDA (X) (/RPLACD X L] (CIRCLMAKER1 L) (RETURN L)) (T (ERROR CARL (QUOTE "IS MISPLACED LABEL"] ((LISTP CARL) (CIRCLMAKER1 CARL))) (COND [(AND CDRL (ATOM CDRL)) (COND [[AND (NEQ CDRL (QUOTE {})) (EQ (NTHCHAR CDRL 1) (QUOTE {)) (EQ (NTHCHAR CDRL -1) (QUOTE })) (FIXP (SETQ CDRLN (MKATOM (SUBSTRING CDRL 2 -2] (* This branch of the conditional checks to see whether CDRL is a reference to a node, i.e. an atom of the form {n} where n is a number. If so, then the steps followed are analogous to those described above for the case in which CARL is a reference to a node. A similar check is made below to see whether CDRL is a label for a node. An error is generated in this case, because such a label has no meaning (the label does not point to a node), and there is a likelihood that the user has inadvertently omitted some code. The error message reads "*n* IS MISPLACED LABEL".) (COND ((SETQ NODECODE (ASSOC CDRLN LABELIST)) (/RPLACD L (CDR NODECODE))) ((SETQ NODECODE (ASSOC CDRLN REFLIST)) (/NCONC1 (CADDR NODECODE) L)) (T (SETQ REFLIST (/NCONC1 REFLIST (LIST CDRLN NIL (LIST L] ([AND (EQ (NTHCHAR CDRL 1) (QUOTE *)) (NEQ CDRL (QUOTE *)) (NEQ CDRL (QUOTE **)) (EQ (NTHCHAR CDRL -1) (QUOTE *)) (FIXP (MKATOM (SUBSTRING CDRL 2 -2] (ERROR CDRL (QUOTE "IS MISPLACED LABEL"] ((LISTP CDRL) (CIRCLMAKER1 CDRL))) (RETURN L]) (CIRCLPRINT [LAMBDA (L PRINTFLG RLKNT) (* lmm: 24-JAN-76 1 22) [RESETLST (RESETSAVE (RADIX 10)) (RESETVARS (#UNDOSAVES) (PROG NIL (CIRCLMARK L RLKNT) (COND (PRINTFLG (RLPRIN1 L)) (T (RLPRIN2 L))) (RLRESTORE L] L]) (CIRCLMARK [LAMBDA (L RLKNT) (* lmm: 19 MAY 75 233) (PROG NIL (COND ((NULL RLKNT) (SETQ RLKNT 0))) (RETURN (CSEARCH L]) (RLPRIN1 [LAMBDA (L) (PROG (PLACELIST LL) (SETQ PLACELIST NIL) (SETQ LL (LINELENGTH)) (CLPRINT L (QUOTE CAR)) (TERPRI]) (RLRESTORE [LAMBDA (L) (* lmm: 19 MAY 75 234) (PROG NIL (COND ((AND (LISTP L) (EQ (CAAR L) CIRCLMARKER)) (RPLACA L (CADAR L)) (RLRESTORE (CAR L)) (RLRESTORE (CDR L]) (CSEARCH [LAMBDA (L) (* lmm: 19 MAY 75 234) (PROG (NXPOINT) (COND ((LISTP L) (SETQ NXPOINT (CAR L)) [COND [(LISTP NXPOINT) (COND ((EQ (CAR NXPOINT) CIRCLMARKER) [COND ((NULL (CDDR NXPOINT)) (NCONC1 NXPOINT (SETQ RLKNT (ADD1 RLKNT] (RETURN NIL)) (T (/RPLACA L (LIST CIRCLMARKER NXPOINT)) (CSEARCH NXPOINT] (T (/RPLACA L (LIST CIRCLMARKER NXPOINT] (RETURN (CSEARCH (CDR L]) (PLACEPRINT [LAMBDA (P) (COND (P (COND ((IGREATERP (CDAR P) -1) (SPACES (IDIFFERENCE (CDAR P) (POSITION))) (PRIN1 (CAAR P)) (RPLACD (CAR P) -1))) (PLACEPRINT (CDR P]) (C2PRINT [LAMBDA (L CAMEFROM) (* lmm: 19 MAY 75 234) (PROG NIL (TERPRI) (PLACEPRINT PLACELIST) (TERPRI) (TERPRI) (RETURN (CPRINT L CAMEFROM]) (ROOMLEFT [LAMBDA NIL (IDIFFERENCE LL (POSITION]) (RLPRIN2 [LAMBDA (L) (RESETLST (PROG (PLACELIST LL) (* Rather than checking NCHARS of every atom before printing it just to make sure that lines don't go over the boundary (causing LISP to put in TERPRI's where we don't want them) LINELENGTH is just changed to be something huge and we are conservative about how much we think will fit on a line... If a structure has atoms with more than 8 characters, and appears on the end of a line, it might overflow, though) (SETQ LL (IDIFFERENCE (LINELENGTH) 8)) (RESETSAVE (LINELENGTH (IPLUS LL 80))) (CPRINT L (QUOTE CAR)) (TERPRI) (PLACEPRINT PLACELIST) (TERPRI]) (CPRINT [LAMBDA (L CAMEFROM) (* This function does most of the work involved in circlprinting in the double line format. IN this format, a node is labeled by the appearance of its number on the line below where the node begins. If the node is car of the node we came from (i.e. if CAMEFRON = 'CAR) then the node begins with a left parens, and the node's number should begin immediately below that left parens. If the node is cdr of the node we came from (i.e. if CAMEFROM = 'CDR) then the node is a tail of a list, and the number identifying it should appear on the line below the beginning of that tail. Thus, when labeeling a node we have to save the position where the node begins. Also, we have to alternate printing nodes and printing their labels below them. The function that prints labels below nodes is PLACEPRINT. CPRINT saves the information necessary to print labels in the correct position by adding sublists to an alist called PLACELIST. When CPRINT adds a sublist to PLACELIST, this sublist is of the form (N . P), where N is the number of the ndoe being labeled, and P is the position where printing of the label should begin. When PLACEPRINT prints a line of labels, it merely cdr's thru PLACELIST checking to see if there are any sublists of the form (N . P), where P is greater than -1.0 For each such sublist, N is printed and then the sublist is physically altered to be of the form (N . -1). Thus PLACELIST can also be used as a list of all labels that have been printed (or will be printed, when PLACEPRINT is called next), and CPRINT can merely do an assoc on placelist to see if a given node has been previously labeled.) (PROG (LN N CARL CARLN CDRL CDRLN LABELEDCDRL? LABELEDCARL? EXSPACES ROOM) (COND ((ILESSP (SETQ ROOM (ROOMLEFT)) 3) (C2PRINT L CAMEFROM)) ((OR (NLISTP L) (NLISTP (CAR L)) (NEQ (CAAR L) CIRCLMARKER)) (ERROR (QUOTE "UNCIRCLMARKED LIST STRUCTURE"))) ((AND (SETQ LN (CDDAR L)) (SETQ N (CAR LN)) (FASSOC N PLACELIST)) (* L has already been printed; print a back reference) [COND ((ILESSP ROOM (IPLUS 2 (CIRCLNC N))) (RETURN (C2PRINT L CAMEFROM] (PRIN1 (QUOTE {)) (PRIN1 N) (PRIN1 (QUOTE }))) ([AND LN (ILESSP ROOM (IPLUS 3 (SETQ EXSPACES (CIRCLNC N] (C2PRINT L CAMEFROM)) (T [COND (LN (SETQ PLACELIST (NCONC1 PLACELIST (CONS (CAR LN) (POSITION] (* If LN is not NIL, the structure needs to be labeled) [COND ((EQ CAMEFROM (QUOTE CAR)) (PRIN1 (QUOTE %(] [COND (LN (COND ((OR (NEQ EXSPACES 1) (NEQ CAMEFROM (QUOTE CAR))) (* Make sure there is enough space to clearly label L) (SPACES EXSPACES] [COND ((NLISTP (SETQ CARL (CADAR L))) (PRIN2 CARL)) ((EQ L CARL) (COND ((ILESSP (ROOMLEFT) (IPLUS 2 EXSPACES)) (TERPRI) (PLACEPRINT PLACELIST) (TERPRI) (TERPRI))) (PRIN1 (QUOTE {)) (PRIN1 (CAR LN)) (PRIN1 (QUOTE }))) (T (CPRINT CARL (QUOTE CAR] (COND ((NULL (CDR L)) (PRIN1 (QUOTE %)))) ((NLISTP (CDR L)) (PRIN1 (QUOTE " .")) (SPACES 1) (PRIN2 (CDR L)) (PRIN1 (QUOTE %)))) ((AND (SETQ CDRLN (CDDADR L)) (FASSOC (CAR CDRLN) PLACELIST)) (* If (CDR L) has been labeled, then print a reference.) (COND ([ILESSP (ROOMLEFT) (IPLUS 6 (CIRCLNC (CAR CDRLN] (TERPRI) (PLACEPRINT PLACELIST) (TERPRI) (TERPRI))) (PRIN1 (QUOTE " .")) (SPACES 1) (PRIN1 (QUOTE {)) (PRIN1 (CAR CDRLN)) (PRIN1 (QUOTE })) (PRIN1 (QUOTE %)))) (T (SPACES 1) (CPRINT (CDR L) (QUOTE CDR]) (CLPRINT [LAMBDA (L CAMEFROM) (* This function does most of the work involved in cirlcprinting in the single line format. The problems encountered with the double line format (see CPRINT) do not occur here. In particular the alist PLACELIST is used by CLPRINT only to store the numbers of the reentrant nodes that have already been labeled, not the positions where they were labeled. CLPRINT prints a description of each node (i.e. a label, a reference, or car and cdr) as it encounters it.) (PROG (LN N LABELIT CARL CDRL CDRLN LISTPCDRL? LABELEDCDRL? EXSPACES) (COND ((ILESSP (ROOMLEFT) 2) (TERPRI))) (COND ((LISTP L) (COND ((NOT (EQ (CAAR L) CIRCLMARKER)) (ERROR (QUOTE "UNCIRCLMARKED LIST STRUCTURE"))) ((AND (SETQ LN (CDDAR L)) (SETQ N (CAR LN)) (SETQ EXSPACES (CIRCLNC N)) (FMEMB N PLACELIST)) (* If L is a reentrant node and has already been labeled then we simply print a reference to L. CIRCLNC computes the number of digits in N which is 2 less than the number of characters needed to label or reference L, and makes it the value of EXSPACES. If N is greater than or equal to 10000, then an error is generated. Otherwise, the FMEMB on placelist checks to see if L has already been labeled, in which case we print a reference to L, in the code below this comment.) (COND ((ILESSP (ROOMLEFT) (IPLUS 2 EXSPACES)) (TERPRI))) (PRIN1 (QUOTE {)) (PRIN1 N) (PRIN1 (QUOTE }))) (T (COND (LN (* Checks to see if L has to be labeled.) (COND ((ILESSP (ROOMLEFT) (IPLUS 3 EXSPACES)) (TERPRI))) (SETQ LABELIT T))) [COND (LABELIT (* If L is to be labeled, then add N to placelist.) (SETQ PLACELIST (NCONC PLACELIST LN] [COND ((EQ CAMEFROM (QUOTE CAR)) (PRIN1 (QUOTE %(] (COND (LABELIT (* If L is to be labeled, then print a label.) (PRIN1 (QUOTE *)) (PRIN1 (CAR LN)) (PRIN1 (QUOTE *)) (SPACES 1))) (COND [(LISTP (SETQ CARL (CADAR L))) (* If CARL is a list then if L = CARL then print a reference to CARL automatically, else CPRINT CARL.) (COND ((EQ L CARL) (COND ((ILESSP (ROOMLEFT) (IPLUS 2 EXSPACES)) (TERPRI))) (PRIN1 (QUOTE {)) (PRIN1 (CAR LN)) (PRIN1 (QUOTE }))) (T (CLPRINT CARL (QUOTE CAR] (T (PRIN2 CARL))) (COND ((LISTP (SETQ CDRL (CDR L))) (* Check whether CDRL needs to be labeled.) (COND ((AND (SETQ CDRLN (CDDADR L)) (FMEMB (CAR CDRLN) PLACELIST)) (SETQ LABELEDCDRL? T)) (T (SETQ LABELEDCDRL? NIL))) (SETQ LISTPCDRL? T)) (T (SETQ LISTPCDRL? NIL))) (COND (CDRL (* make sure there will be a space between carl and cdrl.) (SPACES 1))) (COND [LISTPCDRL? (* If CDRL has been labeled and is reentrant, then print a reference. Else if CDRL is a list the CLPRINT CDRL, else just prin1 it.) (COND (LABELEDCDRL? (SETQ N (CAR CDRLN)) (COND ((ILESSP (ROOMLEFT) (IPLUS 5 (CIRCLNC N))) (TERPRI))) (PRIN1 (QUOTE %.)) (SPACES 1) (PRIN1 (QUOTE {)) (PRIN1 (CAR CDRLN)) (PRIN1 (QUOTE })) (PRIN1 (QUOTE %)))) (T (CLPRINT CDRL (QUOTE CDR] ((NULL CDRL) (PRIN1 (QUOTE %)))) (T (PRIN1 (QUOTE %.)) (SPACES 1) (PRIN2 CDRL) (PRIN1 (QUOTE %)]) (CIRCLNC [LAMBDA (N) (COND ((ILESSP N 10) 1) ((ILESSP N 100) 2) ((ILESSP N 1000) 3) ((ILESSP N 10000) 4) (T (ERROR (QUOTE "REENTRANT NODE HAS BEEN NUMBERD OVER 10000"]) ) (RPAQQ CIRCLMARKER "BEENHERE") [DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY (BLOCK: CIRCLBLOCK CIRCLMAKER CIRCLMAKER1 CIRCLPRINT CIRCLMARK RLPRIN1 RLRESTORE CSEARCH PLACEPRINT C2PRINT ROOMLEFT RLPRIN2 CPRINT CLPRINT CIRCLNC (ENTRIES CIRCLPRINT CIRCLMARK RLPRIN1 RLPRIN2 RLRESTORE CIRCLMAKER CIRCLMAKER1) (SPECVARS RLKNT LABELIST REFLIST) (LOCALFREEVARS PLACELIST LL) (NOLINKFNS . T) (GLOBALVARS #UNDOSAVES RESETVARSLST)) ] (DECLARE: DONTCOPY (FILEMAP (NIL (798 19253 (CIRCLMAKER 808 . 1331) (CIRCLMAKER1 1335 . 8241) (CIRCLPRINT 8245 . 8552) ( CIRCLMARK 8554 . 8739) (RLPRIN1 8743 . 8914) (RLRESTORE 8916 . 9169) (CSEARCH 9171 . 9675) (PLACEPRINT 9679 . 9909) (C2PRINT 9911 . 10133) (ROOMLEFT 10137 . 10194) (RLPRIN2 10198 . 10942) (CPRINT 10946 . 15100) (CLPRINT 15104 . 19037) (CIRCLNC 19041 . 19251))))) STOP P