groff
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GNU eqn clarifications and reforms (was: EQN - special words)


From: G. Branden Robinson
Subject: Re: GNU eqn clarifications and reforms (was: EQN - special words)
Date: Thu, 1 Jun 2023 08:20:15 -0500

Hi Damian,

At 2023-06-01T14:08:34+1000, Damian McGuckin wrote:
> On Wed, 31 May 2023, G. Branden Robinson wrote:
> > At 2023-06-01T12:06:47+1000, Damian McGuckin wrote:
> > > I am worried my new EQN documentation is not going to be relevant
> > > to heirloom (Plan9's?) TROFF/EQN and NEATROFF/NEATEQN. I can just
> > > put in a warning.
> > 
> > I don't know much about other eqn implementations, but I've never
> > heard/read that any of them innovated in any way beyond the feature
> > set of Version 7 Unix eqn.  (I haven't specifically researched this
> > issue, but I do read everything I can get my hands on about *roff
> > and I would expect to have blundered into _something_ over the past
> > 5-6 years...)
> 
> OK, so I can go back to calling a '~' and '^' a full space and a half
> space and assuming that they have widths of 2/7th of an em and 1/6 of
> an em as per the old documentation.

You might want to advise readers that those amounts are approximate.
Demanding eqn users might sweat distances to the hundredth of an em.

> > Further, GNU eqn is almost completely backward compatible with V7
> > eqn with respect to input.  There are two exceptions I know of, now
> > both clearly documented in the eqn(1) page in groff Git HEAD.
> > 
> > 1.  An input token of "..." puts an ellipsis on the text baseline in GNU
> >    eqn, but on the math axis in V7 eqn.
> 
> That's what I thought but in 1.22.4
> 
>       '...'   produces 3 separated dots
>       cdots   produces 3 an ellipsis
>       cdot    produces 1 dot
> 
> all at the same height as a minus sign, i.e. above the text baseline.

Yes, that's true of 1.22.4.  I had forgotten about a change I made; GNU
eqn's documentation ran ahead of its implementation by about 15 years in
this respect.  While composing this mail, we've had an exchange on this.

https://lists.gnu.org/archive/html/groff/2023-06/msg00002.html

> Note that cdots is defined in 'lex.cpp' as
> 
>       \(md \(md \(md
> 
> and I notice that the troff symbol \(md (middot) is defined absolutely
> nowhere, even if the groff \[md] or multiplication do is in
> groff_char.

I have to differ with you here.  The special character `md` is defined
lots of places.  First, in the canonical place for device-independent
troffs, in font description files.[1]

font/devX100-12/S:md    4,5     0       0327
font/devX100/S:md       4,5     0       0327
font/devX75-12/S:md     3,4     0       0327
font/devX75/S:md        3,3     0       0327
font/devcp1047/R.proto:md       24      0       0263
font/devdvi/S:md        "
font/devdvi/SC:md       "
font/devlatin1/R.proto:md       "
font/devlbp/HB:md       2027    0       0x3b7    8,32    # dotmath
font/devlbp/HBI:md      2027    0       0x3b7    8,32    # dotmath
font/devlbp/HI:md       1893    0       0x3b7    8,32    # dotmath
font/devlbp/HNB:md      499     0       0x3b7    8,32    # dotmath
font/devlbp/HNBI:md     499     0       0x3b7    8,32    # dotmath
font/devlbp/HNI:md      466     0       0x3b7    8,32    # dotmath
font/devlbp/HNR:md      466     0       0x3b7    8,32    # dotmath
font/devlbp/HR:md       1893    0       0x3b7    8,32    # dotmath
font/devlbp/TB:md       1633    0       0x3b7    8,32    # dotmath
font/devlbp/TBI:md      1633    0       0x3b7    8,32    # dotmath
font/devlbp/TI:md       1723    0       0x3b7    8,32    # dotmath
font/devlbp/TR:md       1723    0       0x3b7    8,32    # dotmath
font/devlj4/S:md        8781,10407      0       69066   -- MSL  302 ( 8M 202)
font/devps/S:md 250,310 3       215     dotmath

The formatter/libgroff also has special support for it as part of the
"groff glyph list", the fixed set of special character identifiers that
we support to get parity across devices and to consistently transform to
and from Unicode code points.  (This is, I think, why you don't see
"devutf8" above.)

src/libs/libgroff/glyphuni.cpp:  { "md", "22C5" },
src/libs/libgroff/uniglyph.cpp:  { "22C5", "md" },

There is also some special support for this character in gxditview.

src/devices/xditview/ChangeLog: * DviChar.c: Replacing `md' glyph name with 
`pc' in latin-1 map to
src/devices/xditview/ChangeLog: make it distinct from the `md' glyph in the 
symbol font.
src/devices/xditview/ChangeLog: * DviChar.c: Add entries for lB, rB, oq, lC, 
rC, md.
src/libs/libxutil/DviChar.c:{   "md",

...and in eqn for production of MathML...

src/preproc/eqn/text.cpp:  {"md", "·"},  // ISOnum

...and finally some fallbacks for terminal devices.

tmac/tty-char.tmac:.if c\[md] .tty-char \[pc] \[md]
tmac/tty-char.tmac:.if c\[pc] .tty-char \[md] \[pc]
tmac/tty-char.tmac:.tty-char \[md] .
tmac/tty.tmac:.    if c\[md] \
tmac/tty.tmac:.      tr \[bu]\[md]

> > 2.  "delim on" turns (back) on any previously specified equation
> >    delimiters in GNU eqn, but in V7 eqn sets up 'o' and 'n' as
> >    delimiters of the left and right ends of an "inline" equation.
> 
> In 1.22.4, 'delim on' fails.

Are you running eqn with '-C'?

$ cat EXPERIMENTS/eqn-delim-on.roff
.nf
.EQ
delim $$
.EN
$a + b = c$
.EQ
delim off
.EN
$c + d = e$
.EQ
delim on
.EN
$f + g = h$
$ groff --version | head -n 1
GNU groff version 1.22.4
$ groff -Tascii -e EXPERIMENTS/eqn-delim-on.roff | cat -s
a+b=c
$c + d = e$
f+g=h

$ groff -C -Tascii -e EXPERIMENTS/eqn-delim-on.roff | cat -s
a+b=c
$c + d = e$
$f + g = h$

In groff 1.23.0, "delim on" will be honored even in compatibility mode;
this is documented with a rationale in the NEWS file.[2]

> > "times" is an eqn macro.  It's defined like this:
> > 
> >    define "times" ! type "binary" \[mu] !
> > 
> > ...except this definition doesn't actually take place in an eqnrc
> > file or anything like that, but initialized directly into a C++ data
> > structure.
> 
> Scary programming.

Not _too_ scary.  Just a struct of two pointers to constant characters
(strings).  In my opinion it's way scarier to parse the input to get the
strings you want to add to that struct, since that input can be
arbitrary, hostile, and evocative of C++ undefined behavior.  ;-)

Anyway, since the camel's nose of the STL is already in groff, and I've
got my C++ books out of storage, my resolve to start replacing some of
groff's hand-rolled data structures and "algorithms"[3] with standard
library containers is growing.  A lot of lex.cpp might be replaced with
std:map<> and .find().

But initializing containers in C++98 is _really gross_.  (Lippman points
out that there are 5 ways to do it.  All are ugly.)  C++11 got this much
more right.

> > Someday I want to experiment with moving all of these built-in macro
> > definitions into the eqnrc file, with interesting consequences for
> > anyone who runs eqn with the '-R' flag.
> 
> Sounds like great rationalization.

It would also make the language more flexible.  Perhaps more than some
people might desire, though.  Worth arguing about after 1.23.0.

> Ignore what I said about divide. Your idea of putting the definition
> in the user's our initialization file sounds like the way to go when
> needed.

Or in the document!

Regards,
Branden

[1] One could argue that the "charset" section of a "DESC" file might be
    a more canonical location for Kernighan troff ca. 1981.  But James
    Clark (and perhaps others before him in proprietary troffs) appears
    to have decided that fonts could vary so much in repertoire that
    there was no point maintaining a "default" charset in the device
    description file.

[2] https://git.savannah.gnu.org/cgit/groff.git/tree/NEWS?h=1.23.0.rc4#n118

[3] I have some unease with the application of the term "algorithm" to
    things as simple as a `for` loop that traverses an array in order,
    performs an identity comparison on each item, and returns the index
    when a match is found.  While this is indeed an algorithm in the
    strict sense, I've encountered too many programmers who throw this
    word around at every opportunity (usually to describe their own
    work).  I have visions of fitting engineers with shock collars; if
    they talk up their "algorithm" but can't tell you its time
    complexity in O-notation off the top of their head, they get a jolt.

    To un-digress, the point of migrating some bits of groff code to the
    STL would be for the reason the STL is there in the first place[4]:
    to delegate that which is not the focus of your project elsewhere,
    reducing the size of your code base.  And, potentially, enjoying
    optimizations to the internals of a map or hash type developed by
    Boost lunatics who will happily smash 499 Ferraris into the
    retaining wall before, covered in soot, happily delivering a 500th
    that is 2.5% faster.

[4] I mean apart from Bjarni Stroustrup's maniacal objective of keeping
    any programmer from ever discovering the virtues of the Ada
    language, which had generics in a cleaner and nicer form 15 years
    before C++ standardized.

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]