bugGNU roff - Bugs: bug #57944, doc/groff.texi: expand .de...

 
 

bug #57944: doc/groff.texi: expand .de documentation

Submitter:  Dave <barx>
Submitted:  Tue 03 Mar 2020 10:53:18 AM UTC
   
 
Category:  Core Severity:  3 - Normal
Item Group:  Documentation Status:  Fixed
Privacy:  Public Assigned to:  gbranden
Open/Closed:  Closed Planned Release:  1.23.0
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Mon 23 Aug 2021 04:23:38 AM UTC, comment #7: 


commit 7252c3dbf76b9da06df048fd41a1207e501a3a82
Author: G. Branden Robinson <g.branden.robinson@gmail.com>
Date:   Sat Aug 21 22:39:36 2021 +1000

    [docs]: Elaborate macro definition discussion.

    Fixes <https://savannah.gnu.org/bugs/?57944>.  Thanks to Dave Kemper for
    the report.

    * Clarify ordering of macro definition effectuation and end macro call.
    * Update example to model it on a device of Tadziu Hoffman's.
    * Fix misstatement which implied that escaping in nested macro
      definitions was multiplicative rather than exponential.
    * Coalesce material on macro creation and aliasing behavior.
    * Restore \$1 and \$2 parameter expansions to \$*, \$@, \$^ example; now
      I need them again for pleasant page layout in PDF.
    * Update stale macro names in example and discussion.
    * Make another nesting example less colorless.


G. Branden Robinson <gbranden>
Group administrator
Sun 22 Aug 2021 10:07:02 PM UTC, comment #6: 


comment #5:

> Looks fantastic, and addresses both of the points raised in comment #0 of this bug, so I think we can close it out now.


Thanks--but after I push! :D

G. Branden Robinson <gbranden>
Group administrator
Sun 22 Aug 2021 12:29:43 PM UTC, comment #5: 

Looks fantastic, and addresses both of the points raised in comment #0 of this bug, so I think we can close it out now.

Dave <barx>
Group Member
Sun 22 Aug 2021 01:27:49 AM UTC, comment #4: 

comment #3:

> A sound approach.  And I find just about everything you write to be clear and carefully worded to be precise.  Maybe it doesn't seem that way because I only seize upon the rare exceptions.


Thank you!
 

> Anyway, this is definitely one of those troff oddities that can be exploited in useful ways but is fairly unconventional even to seasoned coders.


I'm trying to get to a point where I can draw a line under my current batch of commits and push them.  Here's a preview of what I have in mind for this ticket.


commit d57b67df99698047208e83a0c97f52af25d4fabd
Author: G. Branden Robinson <g.branden.robinson@gmail.com>
Date:   Sat Aug 21 22:39:36 2021 +1000

    [docs]: Elaborate macro definition discussion.

    Fixes <https://savannah.gnu.org/bugs/?57944>.  Thanks to Dave Kemper for
    the report.

    * Clarify ordering of macro definition effectuation and end macro call.
    * Update example to model it on a device of Tadziu Hoffman's.
    * Fix misstatement which implied that escaping in nested macro
      definitions was multiplicative rather than exponential.
    * Coalesce material on macro creation and aliasing behavior.
    * Restore \$1 and \$2 parameter expansions to \$*, \$@, \$^ example; now
      I need them again for pleasant page layout in PDF.
    * Update stale macro names in example and discussion.
    * Make another nesting example less colorless.

diff --git a/doc/groff.texi b/doc/groff.texi
index 55ac9ef1..b2ede97a 100644
--- a/doc/groff.texi
+++ b/doc/groff.texi
@@ -12039,27 +12039,25 @@ restarting the next iteration.
 A @dfn{macro} is a stored collection of text and control lines that can
 be used multiple times.  Use macros to define common operations.
 @xref{Strings}, for a (limited) alternative syntax to call macros.
-While requests exist for the purpose of creating macros, simply
-interpolating an undefined macro will cause it to be defined as empty.
-@xref{Identifiers}.
+While requests exist for the purpose of creating macros, simply calling
+an undefined macro, or interpolating it as a string, will cause it to be
+defined as empty.  @xref{Identifiers}.

 @Defreq {de, name [@Var{end}]}
 Define a macro @var{name}, replacing the definition of any existing
 request, macro, string, or diversion called @var{name}.  GNU
-@code{troff} stores subsequent lines to an internal buffer in ``copy
-mode'' (see below).  If the optional second argument is not specified,
-the macro definition ends with the control line @samp{..} (two dots).
-Alternatively, @var{end} names a macro which, upon being subsequently
-called, ends the definition of @var{name}.
-
-Spaces or tabs are permitted after the first dot in the line containing
-the ending token (either @samp{.} or macro @samp{@var{end}}).  Don't
-insert a tab character immediately after the @samp{..}, or it will fail
-to be recognized as ending the macro definition.@footnote{While it is
-possible to define and call a macro @samp{.}, you can't use it as the
-end-of-macro macro: during a macro definition, @samp{..} is never
-handled as calling @samp{.}, even if you say @samp{.de @var{name} .}
-explicitly.}
+@code{troff} enters ``copy mode'', storing subsequent input lines in an
+internal buffer.  If the optional second argument is not specified, the
+macro definition ends with the control line @samp{..} (two dots).
+Alternatively, @var{end} identifies a macro whose call syntax ends the
+definition of @var{name}; @var{end} is then called normally.  Spaces or
+tabs are permitted after the control character in the line containing
+this ending token (either @samp{.} or @samp{@var{end}}), but a tab
+immediately after the token prevents its recognition as the end of a
+macro definition.@footnote{While it is possible to define and call a
+macro @samp{.}, you can't use it as an end macro: during a macro
+definition, @samp{..} is never handled as calling @samp{.}, even if
+@samp{.de @var{name} .} explicitly precedes it.}
 @c
 @c @Example
 @c .de .
@@ -12090,27 +12088,42 @@ isn't interpreted as such until the outer macro is later interpolated.
 We can use an end macro instead.  Each level of nesting should use a
 unique end macro.

+An end macro need not be defined until it is called.  This fact enables
+a nested macro definition to begin inside one macro and end inside
+another.  Consider the following example.@footnote{The structure of this
+example is adapted from, and structurally isomorphic to, part of a
+solution by Tadziu Hoffman to the problem of reflowing text multiple
+times to find an optimal configuration for it.
+@uref{https://lists.gnu.org/archive/html/groff/2008-12/msg00006.html}}
+
 @Example
-.de en \" a do-nothing macro
+.de m1
+.  de m2 m3
+you
+..
+.de m3
+Hello,
+Joe.
 ..
-.de mo
-.  de mi en
-Hello, Joe.
-What do you know?
-.  en
+.de m4
+do
 ..
-.mo
-.mi
+.m1
+know?
+.  m3
+What
+.m4
+.m2
     @result{} Hello, Joe.  What do you know?
 @endExample

 @noindent
 A nested macro definition @emph{can} be terminated with @samp{..},
 and nested macros @emph{can} reuse end macros, but these control lines
-must be escaped twice for each level of nesting.  The necessity of this
-escaping and the utility of nested macro definitions will become clearer
-when we employ macro parameters and consider the behavior of copy mode
-in detail.
+must be escaped multiple times for each level of nesting.  The necessity
+of this escaping and the utility of nested macro definitions will become
+clearer when we employ macro parameters and consider the behavior of
+copy mode in detail.
 @endDefreq

 @Defreq {de1, name [@Var{end}]}
@@ -12165,11 +12178,6 @@ token is inserted at the beginning, and a ``compatibility restore''
 token at the end, with compatibility mode switched on during execution.
 @endDefreq

-Macro identifiers share their name space with requests, strings, and
-diversions; @ref{Identifiers}.  @xref{als,,the description of the
-@code{als} request}, for possible pitfalls if redefining a macro that
-has been aliased.
-
 @DefreqList {am, name [@Var{end}]}
 @DefreqItemx {am1, name [@Var{end}]}
 @DefreqItemx {ami, name [@Var{end}]}
@@ -12209,11 +12217,14 @@ spots (@pxref{Debugging}).
 create an alias of, remove, and rename a macro, respectively.

 @cindex object creation
-The @code{am}, @code{as}, @code{da}, @code{de}, @code{di}, and @code{ds}
-requests (together with their variants) only create a new object if the
-name of the macro, diversion, or string is currently undefined or if it
-is defined as a request; normally, they modify the value of an existing
-object.
+Macro identifiers share their name space with requests, strings, and
+diversions; @ref{Identifiers}.  The @code{am}, @code{as}, @code{da},
+@code{de}, @code{di}, and @code{ds} requests (together with their
+variants) only create a new object if the name of the macro, diversion,
+or string is currently undefined or if it is defined as a request;
+normally, they modify the value of an existing object.  @xref{als,,the
+description of the @code{als} request}, for pitfalls when redefining a
+macro that is aliased.

 @Defreq {return, [@Var{anything}]}
 Exit a macro, immediately returning to the caller.  If called with an
@@ -12280,8 +12291,8 @@ parameter interpolations would be similar to command-line
 parameters---fixed for the entire duration of a @code{roff} program's
 run.  The advantage of interpolating @code{\$} escape sequences even in
 copy mode is that they can change from one interpolation to the next,
-like parameters to a function call.  The additional escape character is
-the price of this power.}
+like function parameters.  The additional escape character is the price
+of this power.}

 @DefescList {\\$*, , , }
 @DefescItemx {\\$@@, , , }
@@ -12297,11 +12308,15 @@ they were arguments to the @code{ds} request.

 @Example
 .de foo
-.  tm $*='\\$*'
-.  tm $@@='\\$@@'
-.  tm $^='\\$^'
+. tm $1='\\$1'
+. tm $2='\\$2'
+. tm $*='\\$*'
+. tm $@@='\\$@@'
+. tm $^='\\$^'
 ..
 .foo " This is a "test"
+    @error{} $1=' This is a '
+    @error{} $2='test"'
     @error{} $*=' This is a  test"'
     @error{} $@@='" This is a " "test""'
     @error{} $^='" This is a "test"'
@@ -12330,8 +12345,6 @@ Applying string interpolation to a macro does not change this name.
 ..
 .als bar foo
 .
-@endExample
-@Example
 .de aaa
 .  foo
 ..
@@ -12345,8 +12358,6 @@ Applying string interpolation to a macro does not change this name.
 \\*[bar]\\
 ..
 .
-@endExample
-@Example
 .aaa
     @error{} foo
 .bbb
@@ -12433,14 +12444,14 @@ bar
 \\..
 .
 ..
-.foo
-.bar
+.m1
+.m2
     @result{} foo bar
 @endExample

 @noindent
 The first backslash is consumed while the macro is read, and the second
-is interpreted while executing macro @code{foo}.
+is interpreted while executing macro @code{m1}.
 @endDefesc

 @code{roff} documents should not use the @code{\\} or @code{\.}
@@ -12466,9 +12477,9 @@ practice.
 \\..
 .  M2 of
 ..
-This is getting
+This understeer is getting
 .M1 out
-    @result{} This is getting out of hand.
+    @result{} This understeer is getting out of hand.
 @endExample

 Each escape character is interpreted twice---once in copy mode, when the


G. Branden Robinson <gbranden>
Group administrator
Fri 20 Aug 2021 02:22:07 PM UTC, comment #3: 

comment #2:

> This quick experiment did not turn out as I expected.


Huh, nor I.  I guess I hadn't absorbed the implications as thoroughly as I'd have hoped.

> I try not to write new documentation with existing
> documentation open before me,


A sound approach.  And I find just about everything you write to be clear and carefully worded to be precise.  Maybe it doesn't seem that way because I only seize upon the rare exceptions.

Anyway, this is definitely one of those troff oddities that can be exploited in useful ways but is fairly unconventional even to seasoned coders.

Dave <barx>
Group Member
Fri 20 Aug 2021 11:49:07 AM UTC, comment #2: 


comment #1:

> original submission:
> > CSTR #54 made this clear: it included the sentence (using "yy"
> > in place of "end") "Input lines are copied in copy mode until
> > the definition is terminated by a line beginning with .yy,
> > whereupon the macro yy is called."
>
> Commit 07edefd1 adds to the info manual: "Alternatively, 'end' names a macro which, upon being subsequently called, ends the definition of 'name'."
>
> This addresses this part of the bug.  To me, the CSTR #54 wording is a little clearer; it made the order of events immediately clear to me, while I had to read the new sentence a couple times before fully understanding it.  But the new sentence ultimately does say the same thing as the CSTR #54 one, so this may be merely a limitation of my brain.


No, I think you're right, and I in fact had not absorbed that fact.  This quick experiment did not turn out as I expected.


.de bar
.  if d foo .tm foo is defined
..
.de foo bar
.  nop
.bar
foo is defined


I try not to write new documentation with existing documentation open before me, to avoid the risk of plagiarism, and also because thinking things through carefully myself helps me to learn the topic better.

On the other hand, it also reveals deficiencies in my knowledge.

I'll kick this back up to normal because I think I have made the manual erroneous in this respect.  I'll have to recast.

Thanks for the quick spotting, Dave.

G. Branden Robinson <gbranden>
Group administrator
Fri 20 Aug 2021 11:22:19 AM UTC, comment #1: 

original submission:

> CSTR #54 made this clear: it included the sentence (using "yy"
> in place of "end") "Input lines are copied in copy mode until
> the definition is terminated by a line beginning with .yy,
> whereupon the macro yy is called."


Commit 07edefd1 adds to the info manual: "Alternatively, 'end' names a macro which, upon being subsequently called, ends the definition of 'name'."

This addresses this part of the bug.  To me, the CSTR #54 wording is a little clearer; it made the order of events immediately clear to me, while I had to read the new sentence a couple times before fully understanding it.  But the new sentence ultimately does say the same thing as the CSTR #54 one, so this may be merely a limitation of my brain.

Dave <barx>
Group Member
Tue 03 Mar 2020 10:53:18 AM UTC, original submission:  

An amazingly useful Tadziu-penned roff trick in the list archives (http://lists.gnu.org/archive/html/groff/2008-12/msg00006.html) has an implementation that exposes at least one, and maybe two, deficiencies in groff's .de documentation.

(1) .de's second parameter

The documentation doesn't fully describe what happens when the second parameter is used in .de (or other requests of its ilk).

There is one example in the entire info document that uses such a second parameter:


\# a dummy macro to avoid a warning
.de end
..
[snipped]
.  de bar end
.    nop \f[B]Hallo \\\\$1!\f[]
.  end


This example defines an empty, dummy macro .end.  The comment above this dummy macro says its only purpose is to suppress a warning.

Nowhere does the document address whether the .end macro can contain other instructions at all; and, if it can, what this implies:  Does .end immediately end the "bar" definition, and then .end is executed?  Or is the content of .end essentially appended to .bar?  Phrased differently, does .end end .bar at the moment .end begins, or at the moment .end ends?

CSTR #54 made this clear: it included the sentence (using "yy" in place of "end") "Input lines are copied in copy mode until the definition is terminated by a line beginning with .yy, whereupon the macro yy is called."  This should be added to the groff documentation.

(2) macros writing macros

The other interesting thing Tadziu's code does is define a macro (BB) to define a macro (XX).  For this it uses a syntax that would be illegal in most modern programming languages because it breaks conventional nesting.  In pseudocode, what it does is:

begin macro BB
begin macro XX
end macro BB
end macro XX

The reason it works (I assume) is that the content of macro BB is read in copy-in mode, so that "begin macro XX" isn't actually parsed until macro BB is invoked.

Arguably, since groff's info manual already documents copy-in mode, nothing further need be added to explain this.  But it's such a nonintuitive and useful way to (ab)use the language, I wonder if the manual should include an explanation or example that highlights it.

Dave <barx>
Group Member

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by gbranden (Posted a comment)
  • -email is unavailable- added by barx (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    Follow 7 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2021-08-23 gbranden StatusIn Progress Fixed
        Open/ClosedOpen Closed
        Planned ReleaseNone 1.23.0
    2021-08-20 gbranden Severity1 - Wish 3 - Normal
        StatusNone In Progress
        Assigned toNone gbranden
    2021-08-20 barx Severity3 - Normal 1 - Wish

    Back to the top

    Powered by Savane 3.13-f8d8.
    Corresponding source code