{Begin SubSec CIRCLPRINT} {Title CIRCLPRINT} {Text {note CIRCLPRINT was written by P. C. Jackson.} {it Note: CIRCLPRINT is a LispUsers package contained on the file {lisp CIRCLPRINT.DCOM}. } {fn HPRINT} ({PageRef Fn HPRINT}) is designed primarily for dumping circular or reentrant list structures (as well as other data structures for which {fn READ} is not an inverse of {fn PRINT}) so that they can be read back in by Interlisp. The CIRCLPRINT package is designed for printing circular or reentrant structures so that the user can look at them and understand them. A reentrant list structure is one that contains more than one occurrence of the same ({fn EQ}) structure. For example, {fn TCONC} ({PageRef Fn TCONC}) makes uses of reentrant list structure so that it does not have to search for the end of the list each time it is called. Thus, if {lisp X} is a list of 3 elements, {lisp (A B C)}, being constructed by {fn TCONC}, the reentrant list structure used by {fn TCONC} for this purpose is: {lispcode ----- |.|.|-----------------| ----- | | | V V ----- ----- ----- |A|.|---->|B|.|---->|C|/| ----- ----- -----} This structure would be printed by {fn PRINT} as {lisp ((A B C) C)}. Note that {fn PRINT} would produce the same output for the non-reentrant structure: {lispcode ----- ----- |.|.|---->|C|/| ----- ----- | V ----- ----- ----- |A|.|---->|B|.|---->|C|/| ----- ----- -----} In other words, {fn PRINT} does not indicate the fact that portions of the structure in the first figure are identical. Similarly, if {fn PRINT} is applied to a circular list structure (a special type of reentrant structure) it will never terminate. For example, if {fn PRINT} is called on the structure: {lispcode . ----- |--->|.|/| | ----- | | |-----|} it will print an endless sequence of left parentheses, and if applied to: {lispcode . ----- |--->|A|.|----| | ----- | | | |-------------|} will print a left parenthesis followed by an endless sequence of {lisp A}'s. The function {index CIRCLPRINT FN}{fn CIRCLPRINT} described below produces output that will exactly describe the structure of any circular or reentrant list structure. This output may be in either single or double-line formats. Below are a few examples of the expressions that {index CIRCLPRINT FN}{fn CIRCLPRINT} would produce to describe the structures discussed above. First Figure, single line: {lispcode ((A B *1* C) {bracket 1})} First Figure, double-line: {lispcode ((A B C) {bracket 1}) 1} Third Figure, single-line: {lispcode (*1* {bracket 1})} Third Figure, double-line: {lispcode ({bracket 1}) 1} Forth Figure, single-line: {lispcode (*1* A . {bracket 1})} Forth Figure, double-line: {lispcode (A . {bracket 1}) 1} The more complex structure: {lispcode . ----- |-------->|.|.|--------------------------| | ----- | | | | | V V | ----- ----- ----- ----- | |--->|.|.|---->|.|.|---->|A|.|---->|B|.| | | ----- ----- ----- ----- | | | |^ | | |-----| ||-------------------| | | |--------------------|} is printed as follows: Single-line: {lispcode (*2* (*1* {bracket 1} *3* {bracket 2} A *4* B . {bracket 3}) . {bracket 4})} Double-line: {lispcode (({bracket 1} {bracket 2} A B . {bracket 3}) . {bracket 4}) 21 3 4} In both formats, the reentrant nodes in the list structure are labeled by numbers. (A reentrant node is one that has two or more pointers coming into it.) In the single-line format, the label is printed between asterisks at the beginning of the node (list or tail) that it identifies. In the double-line format, the label is printed below the beginning of the node it identifies. An occurrence of a reentrant node that has already been identified is indicated by printing its label in brackets. {FnDef {FnName CIRCLPRINT} {FnArgs LIST PRINTFLG RLKNT} {Text Prints an expression describing {arg LIST}. If {arg PRINTFLG}={lisp NIL}, double-line format is used, otherwise single-line format. {fn CIRCLPRINT} first calls {fn CIRCLMARK}, and then calls either {fn RLPRIN1} (if {arg PRINTFLG}={lisp T}) or {fn RLPRIN2} (if {arg PRINTFLG}={lisp NIL}). Finally, {fn RLRESTORE} is called to restore {arg LIST} to its unmarked state. Returns {arg LIST}. }} {FnDef {FnName CIRCLMARK} {FnArgs LIST RLKNT} {Text Marks each reentrant node in {arg LIST} with a unique number, starting at {arg RLKNT}+1 (or 1, if {arg RLKNT} is {lisp NIL}). Value is (new) {arg RLKNT}. Marking {arg LIST} physically alters it. However, the marking is performed undoably. In addition, {arg LIST} can always be restored by specifically calling {fn RLRESTORE}. }} {FnDef {FnName RLPRIN1} {FnArgs LIST} {Text Prints an expression describing {arg LIST} in the single-line format. Does not restore {arg LIST} to its un{fn CIRCLMARK}ed state. {arg LIST} must previously have been {fn CIRCLMARK}ed or an error is generated. }} {FnDef {FnName RLPRIN2} {FnArgs LIST} {Text Same as {fn RLPRIN1}, except that the expression describing {arg LIST} is printed in the double-line format. }} {FnDef {FnName RLRESTORE} {FnArgs LIST} {Text Physically restores list to its original, unmarked state. }} Note that the user can mark and print several structures which together share common substructures, e.g., several property lists, by making several calls to {fn CIRCLMARK}, followed by calls to {fn RLPRIN1} or {fn RLPRIN2}, and finally to {fn RLRESTORE}.{note how??} {FnDef {FnName CIRCLMAKER} {FnArgs LIST} {Text {arg LIST} may contain labels and references following the convention used by {fn CIRCLPRINT} for printing reentrant structures in single line format, e.g., {lisp (*1* . {bracket 1})}. {fn CIRCLMAKER} performs the necessary {fn RPLACA}'s and {fn RPLACD}'s to make {arg LIST} correspond to the indicated structure. Value is (altered) {arg LIST}. }} {FnDef {FnName CIRCLMAKER1} {FnArgs LIST} {Text Does the work for {fn CIRCLMAKER}. Uses free variables {var LABELST}{index LABELST Var} and {var REFLST}.{index REFLST Var} {var LABELST} is a list of dotted pairs of labels and corresponding nodes. {var REFLST} is a list of nodes containing references to labels not yet seen. {fn CIRCLMAKER} operates by initializing {var LABELST} and {var REFLST} to {lisp NIL}, and then calling {fn CIRCLMAKER1}. It generates an error if {var REFLST} is not NIL when {fn CIRCLMAKER1} returns. The user can call {fn CIRCLMAKER1} directly to "connect up" several structures that share common substructures, e.g., several property lists. }} }{End SubSec CIRCLPRINT}