579 lines
30 KiB
HTML
579 lines
30 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">
|
|
<!Converted with LaTeX2HTML 0.6.5 (Tue Nov 15 1994) by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds >
|
|
<HEAD>
|
|
<TITLE>27.3. Dynamic Control of the Arrangement of Output</TITLE>
|
|
</HEAD>
|
|
<BODY>
|
|
<meta name="description" value=" Dynamic Control of the Arrangement of Output">
|
|
<meta name="keywords" value="clm">
|
|
<meta name="resource-type" value="document">
|
|
<meta name="distribution" value="global">
|
|
<P>
|
|
<b>Common Lisp the Language, 2nd Edition</b>
|
|
<BR> <HR><A NAME=tex2html4764 HREF="node257.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html4762 HREF="node253.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html4756 HREF="node255.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html4766 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html4767 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
|
|
<B> Next:</B> <A NAME=tex2html4765 HREF="node257.html"> Format Directive Interface</A>
|
|
<B>Up:</B> <A NAME=tex2html4763 HREF="node253.html"> Pretty Printing</A>
|
|
<B> Previous:</B> <A NAME=tex2html4757 HREF="node255.html"> Pretty Printing Control </A>
|
|
<HR> <P>
|
|
<H1><A NAME=SECTION003130000000000000000>27.3. Dynamic Control of the Arrangement of Output</A></H1>
|
|
<P>
|
|
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
|
|
The following functions and macros support precise control of what should
|
|
be done when a piece of output is too large to fit in the space available.
|
|
Three concepts underlie the way these operations work: <i>logical blocks</i>,
|
|
<i>conditional newlines</i>, and <i>sections</i>. Before proceeding further, it is
|
|
important to define these terms.
|
|
<P>
|
|
The first line of figure <A HREF="node256.html#PRETTYPRINTSECTIONSFIGURE">27-1</A> shows a
|
|
schematic piece of output. The characters in the output are represented by
|
|
hyphens. The positions of conditional newlines are indicated by
|
|
digits. The beginnings and ends of logical blocks are indicated in the
|
|
figure by ``<tt><</tt>'' and ``<tt>></tt>'' respectively.
|
|
<P>
|
|
The output as a whole is a logical block and the outermost section. This
|
|
section is indicated by the <tt>0</tt>'s on the second line of
|
|
figure <A HREF="node256.html#PRETTYPRINTSECTIONSFIGURE">27-1</A>. Logical blocks nested within
|
|
the output are specified by the macro
|
|
<tt>pprint-logical-block</tt>. Conditional newline positions are specified by calls
|
|
on <tt>pprint-newline</tt>. Each conditional newline defines two sections (one
|
|
before it and one after it) and is associated with a third (the section
|
|
immediately containing it).
|
|
<P>
|
|
The section after a conditional newline consists of all the output up to,
|
|
but not including, (a) the next conditional newline immediately contained
|
|
in the same logical block; or if (a) is not applicable, (b) the next
|
|
newline that is at a lesser level of nesting in logical blocks; or if (b)
|
|
is not applicable, (c) the end of the output.
|
|
<P>
|
|
The section before a conditional newline consists of all the output back
|
|
to, but not including, (a) the previous conditional newline that is
|
|
immediately contained in the same logical block; or if (a) is not
|
|
applicable, (b) the beginning of the immediately containing logical block.
|
|
The last four lines in figure <A HREF="node256.html#PRETTYPRINTSECTIONSFIGURE">27-1</A> indicate
|
|
the sections before and after the four conditional newlines.
|
|
<P>
|
|
The section immediately containing a conditional newline is the shortest
|
|
section that contains the conditional newline in question. In
|
|
figure <A HREF="node256.html#PRETTYPRINTSECTIONSFIGURE">27-1</A>, the first conditional newline is
|
|
immediately contained in the section marked with <tt>0</tt>'s, the second and third
|
|
conditional newlines are immediately contained in the section before the
|
|
fourth conditional newline, and the fourth conditional newline is
|
|
immediately contained in the section after the first conditional newline.
|
|
<P>
|
|
<pre><A NAME=PRETTYPRINTSECTIONSFIGURE> </A>
|
|
----------------------------------------------------------------
|
|
Figure 27-1: Example of Logical Blocks, Conditional Newlines, and Sections
|
|
|
|
<-1---<--<--2---3->--4-->->
|
|
000000000000000000000000000
|
|
11 111111111111111111111111
|
|
22 222
|
|
333 3333
|
|
44444444444444 44444
|
|
|
|
----------------------------------------------------------------
|
|
</pre>
|
|
<P>
|
|
Whenever possible, the pretty printer displays the entire contents of a
|
|
section on a single line. However, if the section is too long to fit in
|
|
the space available, line breaks are inserted at conditional newline
|
|
positions within the section.
|
|
<P>
|
|
<BR><b>[Function]</b><BR>
|
|
<tt>pprint-newline <i>kind</i> &optional <i>stream</i></tt><P>The <i>stream</i> (which defaults to <tt>*standard-output*</tt>) follows the
|
|
standard conventions for stream arguments to printing functions (that is,
|
|
<tt>nil</tt> stands for <tt>*standard-output*</tt> and <tt>t</tt> stands for
|
|
<tt>*terminal-io*</tt>). The <i>kind</i> argument specifies the style of
|
|
conditional newline. It must be one of <tt>:linear</tt>, <tt>:fill</tt>,
|
|
<tt>:miser</tt>, or <tt>:mandatory</tt>. An error is signaled if any other value is
|
|
supplied. If <i>stream</i> is a pretty printing stream created by
|
|
<tt>pprint-logical-block</tt>, a line break is inserted in the output when the
|
|
appropriate condition below is satisfied. Otherwise, <tt>pprint-newline</tt>
|
|
has no effect. The value <tt>nil</tt> is always returned.
|
|
<P>
|
|
If <i>kind</i> is <tt>:linear</tt>, it specifies a `linear-style' conditional newline.
|
|
A line break is inserted if and only if the immediately containing section
|
|
cannot be printed on one line. The effect of this is that line breaks are
|
|
either inserted at every linear-style conditional newline in a logical
|
|
block or at none of them.
|
|
<P>
|
|
If <i>kind</i> is <tt>:miser</tt>, it specifies a `miser-style' conditional newline.
|
|
A line break is inserted if and only if the immediately containing section
|
|
cannot be printed on one line and miser style is in effect in the
|
|
immediately containing logical block. The effect of this is that
|
|
miser-style conditional newlines act like linear-style conditional
|
|
newlines, but only when miser style is in effect. Miser style is in effect
|
|
for a logical block if and only if the starting position of the logical
|
|
block is less than or equal to <tt>*print-miser-width*</tt> from the right margin.
|
|
<P>
|
|
If <i>kind</i> is <tt>:fill</tt>, it specifies a `fill-style' conditional
|
|
newline. A line break is inserted if and only if either (a) the following
|
|
section cannot be printed on the end of the current line, (b) the preceding
|
|
section was not printed on a single line, or (c) the immediately containing
|
|
section cannot be printed on one line and miser style is in effect in the
|
|
immediately containing logical block. If a logical block is broken up into
|
|
a number of subsections by fill-style conditional newlines, the basic
|
|
effect is that the logical block is printed with as many subsections as
|
|
possible on each line. However, if miser style is in effect, fill-style
|
|
conditional newlines act like linear-style conditional newlines.
|
|
<P>
|
|
If <i>kind</i> is <tt>:mandatory</tt>, it specifies a `mandatory-style' conditional
|
|
newline. A line break is always inserted. This implies that none of the
|
|
containing sections can be printed on a single line and will therefore
|
|
trigger the insertion of line breaks at linear-style conditional newlines
|
|
in these sections.
|
|
<P>
|
|
When a line break is inserted by any type of conditional newline, any
|
|
blanks that immediately precede the conditional newline are omitted from
|
|
the output and indentation is introduced at the beginning of the next line.
|
|
By default, the indentation causes the following line to begin in the same
|
|
horizontal position as the first character in the immediately containing
|
|
logical block. (The indentation can be changed via <tt>pprint-indent</tt>.)
|
|
<P>
|
|
There are a variety of ways <i>un</i>conditional newlines can be introduced into
|
|
the output (for example, via <tt>terpri</tt> or by printing a string containing a newline
|
|
character). As with mandatory conditional newlines, this prevents any of
|
|
the containing sections from being printed on one line. In general, when
|
|
an unconditional newline is encountered, it is printed out without
|
|
suppression of the preceding blanks and without any indentation following
|
|
it. However, if a per-line prefix has been specified (see
|
|
<tt>pprint-logical-block</tt>), that prefix will always be printed no matter how a
|
|
newline originates.
|
|
<P>
|
|
<BR><b>[Macro]</b><BR>
|
|
<pre>
|
|
pprint-logical-block (<i>stream-symbol</i> <i>list</i>
|
|
<b>[[</b> { :prefix | :per-line-prefix} <i>p</i> | :suffix <i>s</i> <b>]]</b>)
|
|
{<i>form</i>}*
|
|
</pre>
|
|
<P>This macro causes printing to be grouped into a logical block. It returns
|
|
<tt>nil</tt>.
|
|
<P>
|
|
The <i>stream-symbol</i> must be a symbol. If it is <tt>nil</tt>, it is treated the same
|
|
as if it were <tt>*standard-output*</tt>. If it is <tt>t</tt>, it is treated the same as if
|
|
it were <tt>*terminal-io*</tt>. The run-time value of <i>stream-symbol</i> must
|
|
be a stream (or <tt>nil</tt> standing for <tt>*standard-output*</tt>
|
|
or <tt>t</tt> standing for <tt>*terminal-io*</tt>).
|
|
The logical block is printed into this destination stream.
|
|
<P>
|
|
The body (which consists of the <i>form</i>s)
|
|
can contain any arbitrary Lisp forms. Within the body,
|
|
<i>stream-symbol</i> (or <tt>*standard-output*</tt> if <i>stream-symbol</i> is
|
|
<tt>nil</tt>, or <tt>*terminal-io*</tt> if <i>stream-symbol</i> is <tt>t</tt>) is bound
|
|
to a ``pretty printing'' stream that supports decisions about the arrangement
|
|
of output and then forwards the output to the destination stream. All the
|
|
standard printing functions (for example, <tt>write</tt>, <tt>princ</tt>, <tt>terpri</tt>) can
|
|
be used to send output to the pretty printing stream created by
|
|
<tt>pprint-logical-block</tt>. All and only the output sent to this pretty
|
|
printing stream is treated as being in the logical block.
|
|
<P>
|
|
<tt>pprint-logical-block</tt> and the pretty printing stream it creates have dynamic
|
|
extent. It is undefined what happens if output is attempted outside of
|
|
this extent to the pretty printing stream created. It is unspecified what
|
|
happens if, within this extent, any output is sent directly to the
|
|
underlying destination stream (by calling <tt>write-char</tt>, for example).
|
|
<P>
|
|
The <tt>:suffix</tt>, <tt>:prefix</tt>, and <tt>:per-line-prefix</tt> arguments must all
|
|
be expressions that (at run time) evaluate to strings. The <tt>:suffix</tt> argument <i>s</i>
|
|
(which defaults to the null string) specifies a suffix that is printed just
|
|
after the logical block. The <tt>:prefix</tt> and <tt>:per-line-prefix</tt> arguments
|
|
are mutually exclusive. If neither <tt>:prefix</tt> nor <tt>:per-line-prefix</tt> is
|
|
specified, a <tt>:prefix</tt> of the null string is assumed.
|
|
The <tt>:prefix</tt> argument
|
|
specifies a prefix <i>p</i> that is printed before the beginning of the logical block.
|
|
The <tt>:per-line-prefix</tt> specifies a prefix <i>p</i> that is printed before the block
|
|
and at the beginning of each subsequent line in the block.
|
|
An error is signaled if <tt>:prefix</tt> and <tt>:per-line-prefix</tt> are both used
|
|
or if a <tt>:suffix</tt>, <tt>:prefix</tt>, or <tt>:pre-line-prefix</tt> argument does not
|
|
evaluate to a string.
|
|
<P>
|
|
The <i>list</i> is interpreted as being a list that the body is responsible
|
|
for printing. (See <tt>pprint-exit-if-list-exhausted</tt> and
|
|
<tt>pprint-pop</tt>.) If <i>list</i> does not (at run time) evaluate to a list,
|
|
it is printed using <tt>write</tt>. (This makes it easier to write printing
|
|
functions that are robust in the face of malformed arguments.) If
|
|
<tt>*print-circle*</tt> (and possibly also <tt>*print-shared*</tt>)
|
|
is not <tt>nil</tt> and <i>list</i> is a circular (or shared) reference
|
|
to a cons, then an appropriate ``<tt>#<i>n</i>#</tt>'' marker is printed.
|
|
(This makes it easy to write printing functions that provide full support
|
|
for circularity and sharing abbreviation.) If <tt>*print-level*</tt> is not
|
|
<tt>nil</tt> and the logical block is at a dynamic nesting depth of greater
|
|
than <tt>*print-level*</tt> in logical blocks, ``<tt>#</tt>'' is printed. (This
|
|
makes it easy to write printing functions that provide full support for depth
|
|
abbreviation.)
|
|
<P>
|
|
If any of the three preceding conditions occurs, the indicated output is
|
|
printed on <i>stream-symbol</i> and the <i>body</i> is skipped along with the
|
|
printing of the prefix and suffix. (If the
|
|
body is not responsible for printing a list, then the first two tests
|
|
above can be turned off by supplying <tt>nil</tt> for the <i>list</i> argument.)
|
|
<P>
|
|
In addition to the <i>list</i> argument of <tt>pprint-logical-block</tt>, the
|
|
arguments of the standard printing functions such as <tt>write</tt>,
|
|
<tt>print</tt>, <tt>pprint</tt>, <tt>print1</tt>, and <tt>pprint</tt>, as well as the
|
|
arguments of the standard <tt>format</tt> directives such as <tt>~A</tt>,
|
|
<tt>~S</tt>, (and <tt>~W</tt>) are all checked (when necessary) for
|
|
circularity and sharing. However, such checking is not applied to the
|
|
arguments of the functions <tt>write-line</tt>, <tt>write-string</tt>, and
|
|
<tt>write-char</tt> or to the literal text output by <tt>format</tt>. A
|
|
consequence of this is that you must use one of the latter functions if you
|
|
want to print some literal text in the output that is not supposed to be
|
|
checked for circularity or sharing. (See the examples below.)
|
|
<P>
|
|
<hr>
|
|
<b>Implementation note:</b> Detection of circularity and sharing is supported by the pretty printer by
|
|
in essence performing the requested output twice. On the first pass,
|
|
circularities and sharing are detected and the actual outputting of
|
|
characters is suppressed. On the second pass, the appropriate
|
|
``<tt>#<i>n</i>=</tt>'' and ``<tt>#<i>n</i>#</tt>'' markers are inserted and
|
|
characters are output.
|
|
<P>
|
|
A consequence of this two-pass approach to the detection of circularity and
|
|
sharing is that the body of a <tt>pprint-logical-block</tt> must not
|
|
perform any side-effects on the surrounding environment. This includes not
|
|
modifying any variables that are bound outside of its scope. Obeying this
|
|
restriction is facilitated by using <tt>pprint-pop</tt>, instead of an ordinary
|
|
<tt>pop</tt> when traversing a list being printed by the body of a
|
|
<tt>pprint-logical-block</tt>.)
|
|
<hr>
|
|
<P>
|
|
<BR><b>[Macro]</b><BR>
|
|
<tt>pprint-exit-if-list-exhausted</tt><P><tt>pprint-exit-if-list-exhausted</tt> tests whether or not the <i>list</i>
|
|
argument of <tt>pprint-logical-block</tt> has been exhausted (see
|
|
<tt>pprint-pop</tt>). If this list has been reduced to <tt>nil</tt>,
|
|
<tt>pprint-exit-if-list-exhausted</tt> terminates the execution of the
|
|
immediately containing <tt>pprint-logical-block</tt> except for the printing of
|
|
the suffix. Otherwise <tt>pprint-exit-if-list-exhausted</tt> returns <tt>nil</tt>.
|
|
An error message is issued if <tt>pprint-exit-if-list-exhausted</tt> is used
|
|
anywhere other than syntactically nested within a call on
|
|
<tt>pprint-logical-block</tt>. It is undefined what happens if <tt>pprint-pop</tt>
|
|
is executed outside of the dynamic extent of this
|
|
<tt>pprint-logical-block</tt>.
|
|
<P>
|
|
<BR><b>[Macro]</b><BR>
|
|
<tt>pprint-pop</tt><P><tt>pprint-pop</tt> pops elements one at a time off the <i>list</i> argument of
|
|
<tt>pprint-logical-block</tt>, taking care to obey <tt>*print-length*</tt>,
|
|
<tt>*print-circle*</tt>, and <tt>*print-shared*</tt>. An error message is issued if it is
|
|
used anywhere other than syntactically nested within a call on
|
|
<tt>pprint-logical-block</tt>. It is undefined what happens if <tt>pprint-pop</tt> is executed
|
|
outside of the dynamic extent of this call on <tt>pprint-logical-block</tt>.
|
|
<P>
|
|
Each time <tt>pprint-pop</tt> is called, it pops the next value off the <i>list</i> argument of <tt>pprint-logical-block</tt> and returns it. However,
|
|
before doing this, it performs three tests. If the remaining list is not a
|
|
list (neither a cons nor <tt>nil</tt>), ``<tt>. </tt>'' is printed
|
|
followed by the remaining list. (This makes it easier to write printing
|
|
functions that are robust in the face of malformed arguments.) If
|
|
<tt>*print-length*</tt> is <tt>nil</tt> and <tt>pprint-pop</tt> has already been called
|
|
<tt>*print-length*</tt> times within the immediately containing logical block,
|
|
``<tt>...</tt>'' is printed. (This makes it easy to write printing functions
|
|
that properly handle <tt>*print-length*</tt>.) If <tt>*print-circle*</tt> (and possibly also
|
|
<tt>*print-shared*</tt>) is not <tt>nil</tt>, and the remaining list is a circular
|
|
(or shared) reference, then ``<tt>. </tt>'' is printed followed by an appropriate
|
|
``<tt>#<i>n</i>#</tt>'' marker. (This catches instances of cdr circularity and sharing
|
|
in lists.)
|
|
<P>
|
|
If any of the three preceding conditions occurs, the indicated output is
|
|
printed on the pretty printing stream created by the immediately containing
|
|
<tt>pprint-logical-block</tt>
|
|
and the execution of the immediately containing
|
|
<tt>pprint-logical-block</tt>
|
|
is terminated except for the printing of the suffix.
|
|
<P>
|
|
If <tt>pprint-logical-block</tt> is given a <i>list</i> argument of
|
|
<tt>nil</tt>-because it is not processing a list-<tt>pprint-pop</tt> can still
|
|
be used to obtain support for <tt>*print-length*</tt> (see the example function
|
|
<tt>pprint-vector</tt> below). In this situation, the first and third tests
|
|
above are disabled and <tt>pprint-pop</tt> always returns <tt>nil</tt>.
|
|
<P>
|
|
<BR><b>[Function]</b><BR>
|
|
<tt>pprint-indent <i>relative-to</i> <i>n</i> &optional <i>stream</i></tt><P><tt>pprint-indent</tt> specifies the indentation to use in a logical block.
|
|
<i>Stream</i> (which defaults to <tt>*standard-output*</tt>) follows the
|
|
standard conventions for stream arguments to printing functions. The argument <i>n</i> specifies the indentation in ems. If <i>relative-to</i> is <tt>:block</tt>, the
|
|
indentation is set to the horizontal position of the first character in the
|
|
block plus <i>n</i> ems. If <i>relative-to</i> is <tt>:current</tt>, the
|
|
indentation is set to the current output position plus <i>n</i> ems.
|
|
<P>
|
|
The argument <i>n</i> can be negative; however, the total indentation cannot be moved
|
|
left of the beginning of the line or left of the end of the rightmost per-line
|
|
prefix. Changes in indentation caused by <tt>pprint-indent</tt> do not take
|
|
effect until after the next line break. In addition, in miser mode all
|
|
calls on <tt>pprint-indent</tt> are ignored, forcing the lines corresponding to the
|
|
logical block to line up under the first character in the block.
|
|
<P>
|
|
An error is signaled if a value other than <tt>:block</tt> or <tt>:current</tt> is
|
|
supplied for <i>relative-to</i>. If <i>stream</i> is a pretty printing
|
|
stream created by <tt>pprint-logical-block</tt>, <tt>pprint-indent</tt> sets the
|
|
indentation in the innermost dynamically enclosing logical block.
|
|
Otherwise, <tt>pprint-indent</tt> has no effect. The value <tt>nil</tt> is always
|
|
returned.
|
|
<P>
|
|
<BR><b>[Function]</b><BR>
|
|
<tt>pprint-tab <i>kind</i> <i>colnum</i> <i>colinc</i> &optional <i>stream</i></tt><P><tt>pprint-tab</tt> specifies tabbing as performed by the standard <tt>format</tt>
|
|
directive <tt>~T</tt>. <i>Stream</i> (which defaults to
|
|
<tt>*standard-output*</tt>) follows the standard conventions for stream
|
|
arguments to printing functions. The arguments <i>colnum</i> and <i>colinc</i> correspond to the two parameters to <tt>~T</tt> and are in
|
|
terms of ems. The <i>kind</i> argument specifies the style of tabbing. It
|
|
must be one of <tt>:line</tt> (tab as by <tt>~T</tt>) <tt>:section</tt> (tab as
|
|
by <tt>~T</tt>, but measuring horizontal positions relative to the
|
|
start of the dynamically enclosing section), <tt>:line-relative</tt> (tab as by
|
|
<tt>~@T</tt>), or <tt>:section-relative</tt> (tab as by
|
|
<tt>~@T</tt>, but measuring horizontal positions relative to
|
|
the start of the dynamically enclosing section). An error is signaled if
|
|
any other value is supplied for <i>kind</i>. If <i>stream</i> is a pretty
|
|
printing stream created by <tt>pprint-logical-block</tt>, tabbing is performed.
|
|
Otherwise, <tt>pprint-tab</tt> has no effect. The value <tt>nil</tt> is always
|
|
returned.
|
|
<P>
|
|
<BR><b>[Function]</b><BR>
|
|
<tt>pprint-fill <i>stream</i> <i>list</i> &optional <i>colon?</i> <i>atsign?</i> <BR></tt><tt>pprint-linear <i>stream</i> <i>list</i> &optional <i>colon?</i> <i>atsign?</i> <BR></tt><tt>pprint-tabular <i>stream</i> <i>list</i> &optional <i>colon?</i> <i>atsign?</i> <i>tabsize</i></tt><P>These three functions specify particular ways of pretty printing lists.
|
|
<i>Stream</i> follows the standard conventions for stream arguments to
|
|
printing functions. Each function prints parentheses around the output if
|
|
and only if <i>colon?</i> (default <tt>t</tt>) is not <tt>nil</tt>. Each function
|
|
ignores its <i>atsign?</i> argument and returns <tt>nil</tt>. (These two
|
|
arguments are included in this way so that these functions can be used via
|
|
<tt>~/.../</tt> and as <tt>set-pprint-dispatch</tt> functions as well as
|
|
directly.) Each function handles abbreviation and the detection of
|
|
circularity and sharing correctly and uses <tt>write</tt> to print <i>list</i>
|
|
when given a non-list argument.
|
|
<P>
|
|
The function <tt>pprint-linear</tt> prints a list either all on one line or with
|
|
each element on a separate line. The function <tt>pprint-fill</tt> prints a list
|
|
with as many elements as possible on each line. The function
|
|
<tt>pprint-tabular</tt> is the same as <tt>pprint-fill</tt> except that it prints the
|
|
elements so that they line up in columns. This function takes an
|
|
additional argument <tt>tabsize</tt> (default 16) that specifies the column
|
|
spacing in ems.
|
|
<P>
|
|
As an example of the interaction of logical blocks, conditional newlines,
|
|
and indentation, consider the function <tt>pprint-defun</tt> below. This
|
|
function pretty prints a list whose <i>car</i> is <tt>defun</tt> in the standard way assuming
|
|
that the length of the list is exactly 4.
|
|
<P><pre>
|
|
;;; Pretty printer function for DEFUN forms.
|
|
|
|
(defun pprint-defun (list)
|
|
(pprint-logical-block (nil list :prefix "(" :suffix ")")
|
|
(write (first list))
|
|
(write-char #\space)
|
|
(pprint-newline :miser)
|
|
(pprint-indent :current 0)
|
|
(write (second list))
|
|
(write-char #\space)
|
|
(pprint-newline :fill)
|
|
(write (third list))
|
|
(pprint-indent :block 1)
|
|
(write-char #\space)
|
|
(pprint-newline :linear)
|
|
(write (fourth list))))
|
|
</pre><P>
|
|
<P>
|
|
Suppose that one evaluates the following:
|
|
<P><pre>
|
|
(pprint-defun '(defun prod (x y) (* x y)))
|
|
</pre><P>
|
|
<P>
|
|
If the line width available is greater than or equal to 26, all of the
|
|
output appears on one line. If the width is reduced to 25,
|
|
a line break is inserted at the linear-style conditional newline before
|
|
<tt>(* X Y)</tt>, producing the output shown below. The
|
|
<tt>(pprint-indent :block 1)</tt> causes <tt>(* X Y)</tt> to be printed at a relative
|
|
indentation of 1 in the logical block.
|
|
<P><pre>
|
|
(DEFUN PROD (X Y)
|
|
(* X Y))
|
|
</pre><P>
|
|
<P>
|
|
If the width is 15, a line break is also inserted at the
|
|
fill-style conditional newline before the argument list. The argument list lines
|
|
up under the function name because of the call on
|
|
<tt>(pprint-indent :current 0)</tt> before the printing of the function name.
|
|
<P><pre>
|
|
(DEFUN PROD
|
|
(X Y)
|
|
(* X Y))
|
|
</pre><P>
|
|
<P>
|
|
If <tt>*print-miser-width*</tt> were greater than or equal to 14,
|
|
the output would have been entirely in miser mode.
|
|
All indentation changes are
|
|
ignored in miser mode and line breaks are inserted at miser-style
|
|
conditional newlines. The result would have been as follows:
|
|
<P><pre>
|
|
(DEFUN
|
|
PROD
|
|
(X Y)
|
|
(* X Y))
|
|
</pre><P>
|
|
<P>
|
|
As an example of the use of a per-line prefix, consider that evaluating the expression
|
|
<P><pre>
|
|
(pprint-logical-block (nil nil :per-line-prefix ";;; ")
|
|
(pprint-defun '(defun prod (x y) (* x y))))
|
|
</pre><P>
|
|
produces the output
|
|
<P><pre>
|
|
;;; (DEFUN PROD
|
|
;;; (X Y)
|
|
;;; (* X Y))
|
|
</pre><P>
|
|
with a line width of 20 and <tt>nil</tt> as the value
|
|
of the printer control variable <tt>*print-miser-width*</tt>.
|
|
<P>
|
|
(If <tt>*print-miser-width*</tt> were not <tt>nil</tt> the output
|
|
<P><pre>
|
|
;;; (DEFUN
|
|
;;; PROD
|
|
;;; (X Y)
|
|
;;; (* X Y))
|
|
</pre><P>
|
|
might appear instead.)
|
|
<P>
|
|
As a more complex (and realistic) example, consider the function
|
|
<tt>pprint-let</tt> below. This specifies how to pretty print a <tt>let</tt> in the
|
|
standard style. It is more complex than <tt>pprint-defun</tt> because it has
|
|
to deal with nested structure. Also, unlike <tt>pprint-defun</tt>, it contains
|
|
complete code to print readably any possible list that begins with the
|
|
symbol <tt>let</tt>. The outermost <tt>pprint-logical-block</tt> handles the
|
|
printing of the input list as a whole and specifies that parentheses should
|
|
be printed in the output. The second <tt>pprint-logical-block</tt> handles the
|
|
list of binding pairs. Each pair in the list is itself printed by the
|
|
innermost <tt>pprint-logical-block</tt>. (A <tt>loop</tt> is used instead of
|
|
merely decomposing the pair into two elements so that readable output will
|
|
be produced no matter whether the list corresponding to the pair has one
|
|
element, two elements, or (being malformed) has more than two elements.) A
|
|
space and a fill-style conditional newline are placed after each pair
|
|
except the last. The loop at the end of the topmost
|
|
<tt>pprint-logical-block</tt> prints out the forms in the body of the <tt>let</tt>
|
|
separated by spaces and linear-style conditional newlines.
|
|
<P><pre>
|
|
;;; Pretty printer function for LET forms,
|
|
;;; carefully coded to handle malformed binding pairs.
|
|
|
|
(defun pprint-let (list)
|
|
(pprint-logical-block (nil list :prefix "(" :suffix ")")
|
|
(write (pprint-pop))
|
|
(pprint-exit-if-list-exhausted)
|
|
(write-char #\space)
|
|
(pprint-logical-block
|
|
(nil (pprint-pop) :prefix "(" :suffix ")")
|
|
(pprint-exit-if-list-exhausted)
|
|
(loop (pprint-logical-block
|
|
(nil (pprint-pop) :prefix "(" :suffix ")")
|
|
(pprint-exit-if-list-exhausted)
|
|
(loop (write (pprint-pop))
|
|
(pprint-exit-if-list-exhausted)
|
|
(write-char #\space)
|
|
(pprint-newline :linear)))
|
|
(pprint-exit-if-list-exhausted)
|
|
(write-char #\space)
|
|
(pprint-newline :fill)))
|
|
(pprint-indent :block 1)
|
|
(loop (pprint-exit-if-list-exhausted)
|
|
(write-char #\space)
|
|
(pprint-newline :linear)
|
|
(write (pprint-pop)))))
|
|
</pre><P>
|
|
<P>
|
|
Suppose that the following is evaluated with <tt>*print-level*</tt> having the value <tt>4</tt> and
|
|
<tt>*print-circle*</tt> having the value <tt>t</tt>.
|
|
<P><pre>
|
|
(pprint-let '#1=(let (x (*print-length* (f (g 3)))
|
|
(z . 2) (k (car y)))
|
|
(setq x (sqrt z)) #1#))
|
|
</pre><P>
|
|
<P>
|
|
If the line length is greater than or equal to 77, the output produced
|
|
appears on one line. However, if the line length is 76, line breaks are
|
|
inserted at the linear-style conditional newlines separating the forms in
|
|
the body and the output below is produced. Note that the degenerate
|
|
binding pair <tt>X</tt> is printed readably even though it fails to be a list; a
|
|
depth abbreviation marker is printed in place of <tt>(G 3)</tt>; the binding pair
|
|
<tt>(Z . 2)</tt> is printed readably even though it is not a proper list; and
|
|
appropriate circularity markers are printed.
|
|
<P><pre>
|
|
#1=(LET (X (*PRINT-LENGTH* (F #)) (Z . 2) (K (CAR Y)))
|
|
(SETQ X (SQRT Z))
|
|
#1#)
|
|
</pre><P>
|
|
<P>
|
|
If the line length is reduced to 35, a line break is inserted at one of the
|
|
fill-style conditional newlines separating the binding pairs.
|
|
<P><pre>
|
|
#1=(LET (X (*PRINT-PRETTY* (F #))
|
|
(Z . 2) (K (CAR Y)))
|
|
(SETQ X (SQRT Z))
|
|
#1#)
|
|
</pre><P>
|
|
<P>
|
|
Suppose that the line length is further reduced to 22 and <tt>*print-length*</tt> is
|
|
set to 3. In this situation, line breaks are inserted after both the first
|
|
and second binding pairs. In addition, the second binding pair is itself
|
|
broken across two lines. Clause (b) of the description of fill-style
|
|
conditional newlines prevents the binding pair <tt>(Z . 2)</tt> from being printed
|
|
at the end of the third line. Note that the length abbreviation hides the
|
|
circularity from view and therefore the printing of circularity markers
|
|
disappears.
|
|
<P><pre>
|
|
(LET (X
|
|
(*PRINT-LENGTH*
|
|
(F #))
|
|
(Z . 2) ...)
|
|
(SETQ X (SQRT Z))
|
|
...)
|
|
</pre><P>
|
|
<P>
|
|
The function <tt>pprint-tabular</tt> could be defined as follows:
|
|
<P><pre>
|
|
(defun pprint-tabular (s list &optional (c? t) a? (size 16))
|
|
(declare (ignore a?))
|
|
(pprint-logical-block
|
|
(s list :prefix (if c? "(" "") :suffix (if c? ")" ""))
|
|
(pprint-exit-if-list-exhausted)
|
|
(loop (write (pprint-pop) :stream s)
|
|
(pprint-exit-if-list-exhausted)
|
|
(write-char #\space s)
|
|
(pprint-tab :section-relative 0 size s)
|
|
(pprint-newline :fill s))))
|
|
</pre><P>
|
|
<P>
|
|
Evaluating the following with a line length of 25 produces the output shown.
|
|
<P><pre>
|
|
(princ "Roads ")
|
|
(pprint-tabular nil '(elm main maple center) nil nil 8)
|
|
<BR>Roads ELM MAIN
|
|
MAPLE CENTER
|
|
</pre><P>
|
|
<P>
|
|
The function below prints a vector using <tt>#(...)</tt> notation.
|
|
<P><pre>
|
|
(defun pprint-vector (v)
|
|
(pprint-logical-block (nil nil :prefix "#(" :suffix ")")
|
|
(let ((end (length v)) (i 0))
|
|
(when (plusp end)
|
|
(loop (pprint-pop)
|
|
(write (aref v i))
|
|
(if (= (incf i) end) (return nil))
|
|
(write-char #\space)
|
|
(pprint-newline :fill))))))
|
|
</pre><P>
|
|
<P>
|
|
Evaluating the following with a line length of 15 produces the output shown.
|
|
<P><pre>
|
|
(pprint-vector '#(12 34 567 8 9012 34 567 89 0 1 23))
|
|
|
|
#(12 34 567 8
|
|
9012 34 567
|
|
89 0 1 23)
|
|
</pre><P>
|
|
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
|
|
<P>
|
|
<BR> <HR><A NAME=tex2html4764 HREF="node257.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html4762 HREF="node253.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html4756 HREF="node255.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html4766 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html4767 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
|
|
<B> Next:</B> <A NAME=tex2html4765 HREF="node257.html"> Format Directive Interface</A>
|
|
<B>Up:</B> <A NAME=tex2html4763 HREF="node253.html"> Pretty Printing</A>
|
|
<B> Previous:</B> <A NAME=tex2html4757 HREF="node255.html"> Pretty Printing Control </A>
|
|
<HR> <P>
|
|
<HR>
|
|
<P><ADDRESS>
|
|
AI.Repository@cs.cmu.edu
|
|
</ADDRESS>
|
|
</BODY>
|