texlive[59244] Master/texmf-dist: bnumexpr (17may21)

commits+karl at tug.org commits+karl at tug.org
Mon May 17 22:44:02 CEST 2021


Revision: 59244
          http://tug.org/svn/texlive?view=revision&revision=59244
Author:   karl
Date:     2021-05-17 22:44:02 +0200 (Mon, 17 May 2021)
Log Message:
-----------
bnumexpr (17may21)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/bnumexpr/README.md
    trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexpr.pdf
    trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexpr.tex
    trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexprchanges.tex
    trunk/Master/texmf-dist/source/latex/bnumexpr/bnumexpr.dtx
    trunk/Master/texmf-dist/tex/latex/bnumexpr/bnumexpr.sty

Modified: trunk/Master/texmf-dist/doc/latex/bnumexpr/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/bnumexpr/README.md	2021-05-17 20:43:33 UTC (rev 59243)
+++ trunk/Master/texmf-dist/doc/latex/bnumexpr/README.md	2021-05-17 20:44:02 UTC (rev 59244)
@@ -1,5 +1,5 @@
 | Source:  bnumexpr.dtx
-| Version: v1.4a, 2021/05/13 (doc: 2021/05/13)
+| Version: v1.5, 2021/05/17 (doc: 2021/05/17)
 | Author:  Jean-Francois Burnol
 | Info:    Expressions with big integers
 | License: LPPL 1.3c
@@ -20,7 +20,8 @@
 - comma separated expressions,
 - the space character as well as the underscore may serve
   to separate groups of digits,
-- optional conversion of output to hexadecimal.
+- optional conversion of output to hexadecimal,
+- customizability and extendibility of the syntax.
 
 The expression parser is a scaled-down variant from the
 `\xintiiexpr...\relax`
@@ -55,22 +56,27 @@
   : change history.
 
 `bnumexpr.tex`
-  : can be used to generate the documentation:
+  : can be used to generate the documentation
 
-  :  - with latex+dvipdfmx: `"latex bnumexpr.tex"` (thrice) then
-      `"dvipdfmx bnumexpr.dvi"`.
+To generate the documentation:
 
-  :  - with pdflatex: `"pdflatex bnumexpr.tex"` (thrice).
+  - with latex+dvipdfmx: `"latex bnumexpr.tex"` (thrice) then
+    `"dvipdfmx bnumexpr.dvi"`.
 
-  : In both cases files `README.md` and `bnumexprchanges.tex` must
-    be located in the same repertory as `bnumexpr.tex` and `bnumexpr.dtx`.
+  - with pdflatex: `"pdflatex bnumexpr.tex"` (thrice).
 
-without `bnumexpr.tex`:
-  : `"pdflatex bnumexpr.dtx"` (thrice) extracts all files and
+In both cases files `README.md` and `bnumexprchanges.tex` must
+be located in the same repertory as `bnumexpr.tex` and `bnumexpr.dtx`.
+
+Without `bnumexpr.tex`:
+
+  - `"pdflatex bnumexpr.dtx"` (thrice) extracts all files and
     simultaneously generates the pdf documentation.
 
-Finishing the installation:
+Final steps:
 
+- move files to appropriate destination:
+
            bnumexpr.sty   --> TDS:tex/latex/bnumexpr/
 
            bnumexpr.dtx   --> TDS:source/latex/bnumexpr/
@@ -78,6 +84,8 @@
            bnumexpr.pdf   --> TDS:doc/latex/bnumexpr/
               README.me   --> TDS:doc/latex/bnumexpr/
 
+- discard auxiliary files generated during compilation.
+
 License
 =======
 
@@ -96,9 +104,8 @@
 
 The Author and Maintainer of this Work is Jean-Francois Burnol.
 
-This Work consists of the main source file `bnumexpr.dtx`
-and the derived files
+This Work consists of the main source file and its derived files
 
-    bnumexpr.sty, bnumexpr.pdf, bnumexpr.tex, bnumexprchanges.tex,
-    and README.md
+    bnumexpr.dtx, bnumexpr.sty, bnumexpr.pdf, bnumexpr.tex,
+    bnumexprchanges.tex, README.md
 

Modified: trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexpr.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexpr.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexpr.tex	2021-05-17 20:43:33 UTC (rev 59243)
+++ trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexpr.tex	2021-05-17 20:44:02 UTC (rev 59244)
@@ -21,9 +21,9 @@
 %% same distribution. (The sources need not necessarily be
 %% in the same archive or directory.)
 %% ---------------------------------------------------------------
-\def\bnedocdate {2021/05/13}% package bnumexpr documentation date
-\def\bnepackdate{2021/05/13}% package bnumexpr date
-\def\bneversion {1.4a}      % package bnumexpr version
+\def\bnedocdate {2021/05/17}% package bnumexpr documentation date
+\def\bnepackdate{2021/05/17}% package bnumexpr date
+\def\bneversion {1.5}      % package bnumexpr version
 %% ---------------------------------------------------------------
 %% The bnumexpr package: Expressions with big integers
 %% Copyright (C) 2014-2021 by Jean-Francois Burnol

Modified: trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexprchanges.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexprchanges.tex	2021-05-17 20:43:33 UTC (rev 59243)
+++ trunk/Master/texmf-dist/doc/latex/bnumexpr/bnumexprchanges.tex	2021-05-17 20:44:02 UTC (rev 59244)
@@ -24,12 +24,37 @@
 %% The bnumexpr package: Expressions with big integers
 %% Copyright (C) 2014-2021 by Jean-Francois Burnol
 %%
+\item[1.5 (2021/05/17)]
+  \begin{itemize}
+  \item \textbf{breaking change:} the power operators act now in a right
+    associative way; this has been announced at \xintexprname as a probable
+    future evolution, and is implemented in anticipation here now.
+  \item \textbf{fix two bugs} (imported from upstream \xintexprname) regarding
+    hexadecimal input: impossibility to use |"\foo| syntax (one had to do
+    |\expandafter"\foo| which is unexpected constraint; a very longstanding
+    \xintexprname bug) and issues with leading zeros (since \xintexprname |1.2m|).
+  \item renamed |\bnumexprsetup| into |\bnumsetup|; the former remains
+    available but is deprecated.
+  \item the customizability and extendibility is now total:
+    \begin{enumerate}
+      \item |\bnumprintone|, |\bnumprintonetohex|, |\bnumprintonesep|, |\bnumhextodec|,
+      \item |\bnumdefinfix| which allows to add extra infix operators,
+      \item |\bnumdefpostfix| which allows to add extra postfix operators.
+    \end{enumerate}
+  \item |\bnumsetup|, |\bnumdefinfix|, |\bnumdefpostfix| obey the
+    |\xintglobaldefstrue| and |\xintverbosetrue| settings.
+  \item documentation is extended, providing details regarding the precedence
+    model of the parser, as inherited from upstream \xintexprname; also an
+    example of usage of |\bnumsetup| is included on how to transform
+    |\bnumeval| into a calculator with fractions.
+  \end{itemize}
+
 \item[1.4a (2021/05/13)]
   \begin{itemize}
   \item fix undefined control sequences errors encountered by the parser in
     case of either extra or missing closing parenthesis (due to a problem
     in technology transfer at |1.4| from upstream \xintexprname).
-  \item fix |\BNE_Op_opp| must now be f-expandable (also caused as a
+  \item fix |\BNE_Op_opp| must now be \emph{f}-expandable (also caused as a
     collateral to the technology transfer).
   \item fix user documentation regarding the constraints applying to the user
     replacement macros for the core algebra, as they have changed at |1.4|.

Modified: trunk/Master/texmf-dist/source/latex/bnumexpr/bnumexpr.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/bnumexpr/bnumexpr.dtx	2021-05-17 20:43:33 UTC (rev 59243)
+++ trunk/Master/texmf-dist/source/latex/bnumexpr/bnumexpr.dtx	2021-05-17 20:44:02 UTC (rev 59244)
@@ -1,17 +1,17 @@
 % -*- coding: utf-8-unix; time-stamp-format: "%02d-%02m-%:y %02H:%02M:%02S %Z"; sentence-end-double-space: t; -*-
 %<*dtx>
-\def\bnedtxtimestamp  {Time-stamp: <13-05-2021 12:37:08 CEST>}
+\def\bnedtxtimestamp  {Time-stamp: <17-05-2021 14:16:23 CEST>}
 \iffalse
 %</dtx>
 %<*drv>
 %% ---------------------------------------------------------------
-\def\bnedocdate {2021/05/13}% package bnumexpr documentation date
-\def\bnepackdate{2021/05/13}% package bnumexpr date
-\def\bneversion {1.4a}      % package bnumexpr version
+\def\bnedocdate {2021/05/17}% package bnumexpr documentation date
+\def\bnepackdate{2021/05/17}% package bnumexpr date
+\def\bneversion {1.5}      % package bnumexpr version
 %</drv>
 %<*readme>--------------------------------------------------------
 | Source:  bnumexpr.dtx
-| Version: v1.4a, 2021/05/13 (doc: 2021/05/13)
+| Version: v1.5, 2021/05/17 (doc: 2021/05/17)
 | Author:  Jean-Francois Burnol
 | Info:    Expressions with big integers
 | License: LPPL 1.3c
@@ -32,7 +32,8 @@
 - comma separated expressions,
 - the space character as well as the underscore may serve
   to separate groups of digits,
-- optional conversion of output to hexadecimal.
+- optional conversion of output to hexadecimal,
+- customizability and extendibility of the syntax.
 
 The expression parser is a scaled-down variant from the
 `\xintiiexpr...\relax`
@@ -67,22 +68,27 @@
   : change history.
 
 `bnumexpr.tex`
-  : can be used to generate the documentation:
+  : can be used to generate the documentation
 
-  :  - with latex+dvipdfmx: `"latex bnumexpr.tex"` (thrice) then
-      `"dvipdfmx bnumexpr.dvi"`.
+To generate the documentation:
 
-  :  - with pdflatex: `"pdflatex bnumexpr.tex"` (thrice).
+  - with latex+dvipdfmx: `"latex bnumexpr.tex"` (thrice) then
+    `"dvipdfmx bnumexpr.dvi"`.
 
-  : In both cases files `README.md` and `bnumexprchanges.tex` must
-    be located in the same repertory as `bnumexpr.tex` and `bnumexpr.dtx`.
+  - with pdflatex: `"pdflatex bnumexpr.tex"` (thrice).
 
-without `bnumexpr.tex`:
-  : `"pdflatex bnumexpr.dtx"` (thrice) extracts all files and
+In both cases files `README.md` and `bnumexprchanges.tex` must
+be located in the same repertory as `bnumexpr.tex` and `bnumexpr.dtx`.
+
+Without `bnumexpr.tex`:
+
+  - `"pdflatex bnumexpr.dtx"` (thrice) extracts all files and
     simultaneously generates the pdf documentation.
 
-Finishing the installation:
+Final steps:
 
+- move files to appropriate destination:
+
            bnumexpr.sty   --> TDS:tex/latex/bnumexpr/
 
            bnumexpr.dtx   --> TDS:source/latex/bnumexpr/
@@ -90,6 +96,8 @@
            bnumexpr.pdf   --> TDS:doc/latex/bnumexpr/
               README.me   --> TDS:doc/latex/bnumexpr/
 
+- discard auxiliary files generated during compilation.
+
 License
 =======
 
@@ -108,11 +116,10 @@
 
 The Author and Maintainer of this Work is Jean-Francois Burnol.
 
-This Work consists of the main source file `bnumexpr.dtx`
-and the derived files
+This Work consists of the main source file and its derived files
 
-    bnumexpr.sty, bnumexpr.pdf, bnumexpr.tex, bnumexprchanges.tex,
-    and README.md
+    bnumexpr.dtx, bnumexpr.sty, bnumexpr.pdf, bnumexpr.tex,
+    bnumexprchanges.tex, README.md
 
 %</readme>--------------------------------------------------------
 %<*!readme>
@@ -122,12 +129,37 @@
 %%
 %</!readme>
 %<*changes>-------------------------------------------------------
+\item[1.5 (2021/05/17)]
+  \begin{itemize}
+  \item \textbf{breaking change:} the power operators act now in a right
+    associative way; this has been announced at \xintexprname as a probable
+    future evolution, and is implemented in anticipation here now.
+  \item \textbf{fix two bugs} (imported from upstream \xintexprname) regarding
+    hexadecimal input: impossibility to use |"\foo| syntax (one had to do
+    |\expandafter"\foo| which is unexpected constraint; a very longstanding
+    \xintexprname bug) and issues with leading zeros (since \xintexprname |1.2m|).
+  \item renamed |\bnumexprsetup| into |\bnumsetup|; the former remains
+    available but is deprecated.
+  \item the customizability and extendibility is now total:
+    \begin{enumerate}
+      \item |\bnumprintone|, |\bnumprintonetohex|, |\bnumprintonesep|, |\bnumhextodec|,
+      \item |\bnumdefinfix| which allows to add extra infix operators,
+      \item |\bnumdefpostfix| which allows to add extra postfix operators.
+    \end{enumerate}
+  \item |\bnumsetup|, |\bnumdefinfix|, |\bnumdefpostfix| obey the
+    |\xintglobaldefstrue| and |\xintverbosetrue| settings.
+  \item documentation is extended, providing details regarding the precedence
+    model of the parser, as inherited from upstream \xintexprname; also an
+    example of usage of |\bnumsetup| is included on how to transform
+    |\bnumeval| into a calculator with fractions.
+  \end{itemize}
+
 \item[1.4a (2021/05/13)]
   \begin{itemize}
   \item fix undefined control sequences errors encountered by the parser in
     case of either extra or missing closing parenthesis (due to a problem
     in technology transfer at |1.4| from upstream \xintexprname).
-  \item fix |\BNE_Op_opp| must now be f-expandable (also caused as a
+  \item fix |\BNE_Op_opp| must now be \emph{f}-expandable (also caused as a
     collateral to the technology transfer).
   \item fix user documentation regarding the constraints applying to the user
     replacement macros for the core algebra, as they have changed at |1.4|.
@@ -366,6 +398,16 @@
 pdfpagemode=UseOutlines}
 \usepackage{bookmark}
 
+% importé de xint 2021/05/14
+\newcommand\RaisedLabel[2][6]{%
+\vspace*{-#1\baselineskip}%
+\begingroup
+  \let\leavevmode\relax\phantomsection
+  \label{#2}%
+\endgroup
+\vspace*{#1\baselineskip}%
+}
+
 %---- \verb, and verbatim like `environments'. \MicroFont et \MacroFont
 \makeatletter
 \def\MicroFont {\ttfamily\cdbx at SetSoftWrapBox\color{smallverbcolor}}
@@ -397,43 +439,27 @@
 \def\makestarlowast {\let*\lowast\catcode`\*\active}%
 \catcode`* 12
 
-%------------obsolete------------
-%--- straight quotes, added (finally...) Nov 4, 2014
-% \begingroup\makeatletter
-%   \catcode`\'\active
-%   \catcode`\`\active
-% \@firstofone {\endgroup
-%   \def\makequotesstraight {% textcomp package has been loaded by newtxtt
-%      \let`\textasciigrave
-%      \let'\textquotesingle
-%      \catcode39\active
-%      \catcode96\active }%
-% }
-%------------
-
-% Tentative, mardi 09 septembre 2014 à 22:41:28
-
-% Modifié mardi 13 octobre 2015 à 15:24:00 pour utilisable en
-% argument, et en particulier dans un \footnote{}. Mais utilise
-% \scantokens et macro délimitée maintenant.
-
-%\def\jf at makeletter #1{\catcode`#111\relax }
-
 \def\verb #1%
 {%
   \relax\leavevmode\null
   \begingroup
    \MicroFont
-   \catcode`_ 11 \catcode`! 11 \catcode`: 11 
-   \catcode`< 11 \catcode`> 11
-  % \scantokens will have a result of inserting a space after cs's.
-  % hence the need to have the catcodes of things like _ right.
-  % I also need < for > for one occasion in code comments
-  % naturally won't work in footnotes though.
-  % this code is truly not satisfying, but enough for my needs here.
-   \def\@jfverb ##1#1{\let\do\@makeother \dospecials
+   \def\@makeletter##1{\catcode`##1=11\relax}%
+   % \scantokens will have a result of inserting a space after cs's.
+   % hence the need to have the catcodes of things like _ right.
+   % I also need < for > for code comments
+   % \dospecials at begin document
+   % \do\ \do\\\do\{\do\}\do\$\do\&\do\#\do\^\do\_\do\%\do\~\do\|
+   \odef\dospecials{\dospecials\do\:\do\<\do\>\do\-\do\+}%
+   % naturally won't work in footnotes though.
+   % this code is truly not satisfying, but enough for my needs here.
+   \catcode`\\ 11 \catcode`## 11
+   % I don't do \catcode`\% 11 to avoid surprises in code comments
+   % if my |...| has a linebreak
+   \def\@jfverb ##1#1{\let\do\@makeletter \dospecials
+   % lowering a bit the *
                       \makestarlowast
-  %\let\do\do at noligs  \verbatim at nolig@list % not needed here
+   %\let\do\do at noligs  \verbatim at nolig@list % not needed here
                       \@vobeyspaces\everyeof{\noexpand}%
                       \expandafter\@@jfverb\scantokens{##1}\relax}%
   \@jfverb
@@ -455,17 +481,49 @@
 
 \makeatother
 
+% Lundi 17 mai 2021 à 13:58:27
+% J'ajoute un export automatique des exemples qui servira de poor man test
+% suite
+\newwrite\tests
+\immediate\openout\tests=\jobname-out.txt
+
 % mardi 13 octobre 2015 à 15:32:51
 % le | n'est pas encore actif ici!
 \catcode`| \active
+% first one uses \bnumexpr deliberately with no \bnethe to test 1.4
     \def\bneshow #1%
-    {|\thebnumexpr#1\relax|$$\color{digitscolor}\bnumexpr#1\relax$$}
+    {|\thebnumexpr#1\relax|%
+     \edef\x{\bnumexpr#1\relax}%
+     \immediate\write\tests{\detokenize{\thebnumexpr#1\relax}^^J\x}%
+     $$\color{digitscolor}\x$$\ignorespaces}
+    \def\bneshowthe #1%
+    {|\bnethe\bnumexpr#1\relax|%
+     \edef\x{\bnethe\bnumexpr#1\relax}%
+     \immediate\write\tests{\detokenize{\bnethe\bnumexpr#1\relax}^^J\x}%
+     $$\color{digitscolor}\x$$\ignorespaces}
     \def\bneshoweval #1%
-    {|\bnumeval{#1}|$$\color{digitscolor}\bnumeval{#1}$$}
+    {|\bnumeval{#1}|%
+     \edef\x{\bnumeval{#1}}%
+     \immediate\write\tests{\detokenize{\bnumeval{#1}}^^J\x}%
+     $$\color{digitscolor}\x$$\ignorespaces}
     \def\bneshowevaltohex #1%
-    {|\evaltohex{#1}|$$\color{digitscolor}\evaltohex{#1}$$}
+    {|\evaltohex{#1}|%
+     \edef\x{\evaltohex{#1}}%
+     \immediate\write\tests{\detokenize{\evaltohex{#1}}^^J\x}%
+     $$\color{digitscolor}\x$$\ignorespaces}
 \catcode`| 12
 
+% toujours pénible de devoir se battre avec les espaces verticaux de TeX
+\AtBeginDocument{%
+% \message{ICI below: \the\belowdisplayskip^^J%
+%              belowshort: \the\belowdisplayshortskip^^J%
+%              above: \the\abovedisplayskip^^J%
+%              aboveshor: \the\abovedisplayshortskip^^J%
+% }%
+   \belowdisplayskip\belowdisplayshortskip
+   \abovedisplayskip\abovedisplayshortskip
+}
+
 \DeclareRobustCommand\csa [1]{{\char92\detokenize{#1}}}
 \newcommand\csh[1]{\texorpdfstring{\csa{#1}}{\textbackslash\detokenize{#1}}}
 
@@ -480,53 +538,30 @@
           {bnumexpr}%
     \xspace }%
 
+\def\bnumnameuserdoc
+   {\texorpdfstring
+          {\hyperref[titlepage]{{\color{PineGreen}\ttzfamily bnumexpr}}}
+          {bnumexpr}%
+    \xspace }%
+
 \def\xintkernelname
    {\href{http://www.ctan.org/pkg/xint}{xintkernel}\xspace }%
+\def\xintcorename
+   {\href{http://www.ctan.org/pkg/xint}{xintcore}\xspace }%
 \def\xintname
    {\href{http://www.ctan.org/pkg/xint}{xint}\xspace }%
-\def\xintcorename
-   {\href{http://www.ctan.org/pkg/xint}{xintcore}\xspace }%
+\def\xintfracname
+   {\href{http://www.ctan.org/pkg/xint}{xintfrac}\xspace }%
 \def\xintexprname
    {\href{http://www.ctan.org/pkg/xintexpr}{xintexpr}\xspace }%
 \def\xintbinhexname
    {\href{http://www.ctan.org/pkg/xint}{xintbinhex}\xspace }%
 
-
-% \centeredline: OUR OWN LITTLE MACRO FOR CENTERING LINES
-% =======================================================
-
-% 7 mars 2013
-% -----------
-%
-% This macro allows to conveniently center a line inside a paragraph and still
-% allow use therein of \verb or other macros changing catcodes.
-% A proposito, the \LaTeX \centerline uses \hsize and not \linewidth !
-% (which in my humble opinion is bad)
-
-% Actually my \centeredline works nicely in list environments.
-
-% \ignorespaces ajouté le 9 juin 2013.
-
-% Note: \centeredline creates a group
-
-\makeatletter
-\newcommand*\centeredline {%
-      \ifhmode \\\relax
-        \def\centeredline@{\hss\egroup\hskip\z at skip\ignorespaces }%
-      \else
-        \def\centeredline@{\hss\egroup }%
-      \fi
-      \afterassignment\@centeredline
-      \let\next=}
-\def\@centeredline
-    {\hbox to \linewidth \bgroup \hss \bgroup \aftergroup\centeredline@ }
-
-
 \frenchspacing
 \usepackage{bnumexpr}
-
+\usepackage{xintfrac}
 \usepackage{etoc}
-
+\usepackage{centeredline}
 \usepackage{framed}
 \makeatletter\let\check at percent\relax\makeatother
 \begin{document}
@@ -540,6 +575,8 @@
  The \bnumname package\par
 }
 
+\RaisedLabel{titlepage}
+
 {\centering
   \textsc{Jean-François Burnol}\par
   \footnotesize
@@ -563,12 +600,20 @@
 \item it computes powers (with either |**| or |^| as infix operator),
 \item it computes factorials (with |!| as postfix operator),
 \item it has an operator |//| for floored division and |/:| for the
-  associated modulo,
-\item the space character is ignored and can thus be used to separate in the
+  associated modulo (like {\catcode`\% 12 |%|} in Python which we can't use for obvious reasons),
+\item the space character is ignored%
+%
+\footnote{It is not completely ignored, |\count37<space>| will automatically
+  be prefixed by |\number| and the space token delimits the integer indexing
+  the count register. Also, devious inputs using nested braces around spaces
+  may create unexpected internal situations and even break the parser.}
+%
+and can thus be used to separate in the
   source blocks of digits for better readability of long numbers,
 \item also the underscore |_| may be used as visual digit
   separator,
-\item comma separated expressions are allowed.
+\item comma separated expressions are allowed,
+\item syntax is customizable and extendible.
 \end{itemize}
 There is also a more core-level |\bnumexpr...\relax| construct%
 \footnote{Since |1.4|, one can use |\bnumexpr...\relax| directly in
@@ -596,14 +641,12 @@
 Further, at |1.4| (|2021/05/12|) the |\expanded| primitive is
 required. It is available in all engines since \TeX Live 2019.
 
-By default the arithmetic operations are executed via the \xintcorename
-macros, but via option |custom| and usage of |\bnumexprsetup| it is
-possible to replace them by expandable macros of a custom origin.
-
 \section{Examples}
 
+With certain languages, Babel with PDF\LaTeX\ may make some characters active, for example the
+|!| with the French language. It must then be input as |\string!|.
 \noindent\bneshow {---1 208 637 867 * (2 187 917 891 - 3 109 197 072)}%
-\bneshoweval {(13_8089_1090-300_1890_2902)*(1083_1908_3901-109_8290_3890)}%
+\bneshowthe {(13_8089_1090-300_1890_2902)*(1083_1908_3901-109_8290_3890)}%
 \bneshoweval {(92_874_927_979**5-31_9792_7979**6)/30!}%
 \bneshoweval {30!/20!/21/22/23/24/25/(26*27*28*29)}%
 \bneshoweval {13^50//12^50, 13^50/:12^50}%
@@ -610,9 +653,154 @@
 \bneshoweval {13^50/12^50, 12^50}%
 \bneshoweval {(1^10+2^10+3^10+4^10+5^10+6^10+7^10+8^10+9^10)^3}%
 \bneshoweval {100!/36^100}%
-\bneshoweval {"10*"100*"1000*"A0000, 16^(1+2+3+4)*10}%
-\bneshowevaltohex{"7FFFFFFF+1, "400^3, "ABCDEF*"FEDCBA}%
+\bneshoweval {"0010*"0100*"1000*"A0000, 16^(1+2+3+4)*10}%
+\bneshowevaltohex{"7FFFFFFF+1, "0400^3, "ABCDEF*"0000FEDCBA, 1234}%
+\bneshoweval {"\evaltohex{12345678}FFFF, 000012345679*16**4-1}
 
+\section{The \texttt{custom} package option and \csh{bnumsetup}}
+
+Package \bnumname needs that some \emph{big integer engine} provides the macros doing
+the actual computations. By default, it loads package \xintcorename (a subset
+of \href{http://www.ctan.org/pkg/xint}{xint}) and uses \csa{bnumsetup} in
+the following way:
+\begin{verbatim}
+    \usepackage{xintcore}
+    \bnumsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul,
+               divround=\xintiiDivRound, div=\xintiiDivFloor,
+               mod=\xintiiMod, pow=\xintiiPow, fac=\xintiiFac,
+               opp=\xintiiOpp}
+\end{verbatim}
+
+If
+using \csa{bnumsetup}, it is not necessary to specify all keys,
+for example one can do |\bnumsetup{mul=\MySlowerMul}|, and only
+multiplication will be changed.
+
+Naturally it is up to the user to load the appropriate package for
+the alternative macros.
+
+The macros serving as custom user replacements%
+%
+\footnote{%
+  The replacement macros will by default receive arguments composed of
+  explicit digit tokens, with no leading zeros, with at most one leading minus
+  sign and no plus sign.
+
+  The format of these arguments will depend on what the other customized
+  macros do. For example if |opp=\foo| is used and the custom |\foo| inserts a
+  |+| when taking the opposite of a negative number, then the other custom
+  macros for arithmetic (and the |\foo| macro itself) must be able to handle
+  arguments starting optionally with such a |+|.%
+}
+must be \emph{f}-expandable,
+except for the computation of factorials, which only has to be
+\emph{x}-expandable.%
+%
+\footnote{Prior to |1.4|, only \emph{x}-expandability was required. It is easy however to use an |\expanded| based wrapper to convert  \emph{x}-expandable macros into  \emph{f}-expandable ones.}
+%
+
+Macro |\bnumsetup| can be used multiple times in the same document, thus
+allowing to switch math engines or to remap operators to some other arithmetic
+macros of the same math engine. Its effect obeys the local scope.%
+%
+\footnote{The effect is global if under |\xintglobaldefstrue| setting.}
+
+The hexadecimal input via the |"| prefix is converted internally to decimal
+notation using |\xintHexToDec| from package \xintbinhexname, and customization
+is possible via redefinition of |\bnumhextodec|, whose default is to be an
+alias to |\xintHexToDec|.
+
+The final conversion back to hexadecimal done by |\evaltohex| is handled by
+|\bnumprintonetohex| which defaults to |\xintDecToHex|.
+
+These two steps can thus be customized as will. But the loading of package
+\xintbinhexname can not be canceled.
+
+\section{\csh{bnumprintone}, \csh{bnumprintonetohex}, \csh{bnumprintonesep}}
+
+The computed values are printed one by one, separated by a comma and a space
+(this is customizable as |\bnumprintonesep|), and each value being handed over
+to |\bnumprintone|. By default this does nothing else than producing its
+argument as is, it can be redefined at will (perhaps using macros such as in
+\autoref{sec:printing} to handle the case of very long numbers).
+
+There is also |\bnumprintonetohex| which is used by |\evaltohex| (this is its
+sole difference from |\bnumeval|).  Its default definition makes it an alias
+to |\xintDecToHex| from package \xintbinhexname.
+
+\section{Example of customization: let the syntax handle fractions!}
+
+I will show how to transform |\bnumeval| into a calculator with fractions! We
+will use the \xintfracname macros, but coerce them into always producing
+fractions in lowest terms (except for powers). For optimization we use
+the |[0]| post-fix which speeds-up the input parsing by the \xintfracname
+macros. We remove it on output via a custom |\bnumprintone|.
+
+Note that the |/| operator is associated to |divround| key but of course here
+the used macro will simply do an exact division of fractions, not a rounded-to-%
+an integer division. This is the whole point of using a macro of our own
+choosing!
+\begin{verbatim}
+\usepackage{xintfrac}
+\newcommand\myIrrAdd[2]{\xintIrr{\xintAdd{#1}{#2}}[0]}
+\newcommand\myIrrSub[2]{\xintIrr{\xintSub{#1}{#2}}[0]}
+\newcommand\myIrrMul[2]{\xintIrr{\xintMul{#1}{#2}}[0]}
+\newcommand\myDiv[2]{\xintIrr{\xintDiv{#1}{#2}}[0]}
+\newcommand\myDivFloor[2]{\xintDivFloor{#1}{#2}[0]}
+\newcommand\myMod[2]{\xintIrr{\xintMod{#1}{#2}}[0]}
+\newcommand\myPow[2]{\xintPow{#1}{#2}}% will have trailing [0]
+\newcommand\myFac[1]{\xintFac{#1}}%     produces trailing [0]
+\bnumsetup{add=\myIrrAdd, sub=\myIrrSub, mul=\myIrrMul,
+           divround=\myDiv, div=\myDivFloor,
+           mod=\myMod, pow=\myPow, fac=\myFac}%
+% % if any operation happened, the result is already irreducible
+% % (except power of non-irreducible) so this is overhead:
+% \let\bnumprintone\xintIrr
+% % but it is safe way to get rid of the trailing [0]
+% % else we have to take care of case with no [0] because of no operations
+% % well let's do it:
+\makeatletter
+\def\myPrintOne#1{\@myPrintOne#1[0]\relax}
+\def\@myPrintOne#1[0]#2\relax{#1}
+\let\bnumprintone\myPrintOne
+\makeatother
+\end{verbatim}
+\begingroup
+\newcommand\myIrrAdd[2]{\xintIrr{\xintAdd{#1}{#2}}[0]}
+\newcommand\myIrrSub[2]{\xintIrr{\xintSub{#1}{#2}}[0]}
+\newcommand\myIrrMul[2]{\xintIrr{\xintMul{#1}{#2}}[0]}
+\newcommand\myDiv[2]{\xintIrr{\xintDiv{#1}{#2}}[0]}
+\newcommand\myDivFloor[2]{\xintDivFloor{#1}{#2}[0]}
+\newcommand\myMod[2]{\xintIrr{\xintMod{#1}{#2}}[0]}
+\newcommand\myPow[2]{\xintPow{#1}{#2}}% will have trailing [0]
+\newcommand\myFac[1]{\xintFac{#1}}%     produces trailing [0]
+\bnumsetup{add=\myIrrAdd, sub=\myIrrSub, mul=\myIrrMul, divround=\myDiv,
+  div=\myDivFloor, mod=\myMod, pow=\myPow, fac=\myFac}%
+\makeatletter
+\def\myPrintOne#1{\@myPrintOne#1[0]\relax}%
+\def\@myPrintOne#1[0]#2\relax{#1}%
+\let\bnumprintone\myPrintOne
+\makeatother
+\bneshoweval{1000000*(1/100+1/2^7-20/5^4)/(1/3-5/7+9/11)^2}
+\bneshoweval{(1-1/2)(1-1/3)(1-1/4)(1-1/5)(1-1/6)(1-1/7)}
+\bneshoweval{(1-1/3+1/9-1/27-1/81+1/243-1/729+1/2187)^5}
+\bneshoweval{(1+1/10)^10 /: (1-1/10)^10}
+\bneshoweval{2^-3^4}
+\endgroup
+
+This last example is computed differently than it would be with \xintexprname
+|1.4f| because \bnumname |1.5| already applies right associativity to powers,
+whereas \xintexprname |1.4f| still applies left associativity.
+
+Note also that the above changes break |\evaltohex| whose output routine uses
+by default |\xintDecToHex| which will choke on fractional input. However it is
+not difficult to write a macro applying separately to numerator and
+denominator.
+
+Computations with fractions quickly give birth to big results, see
+\autoref{sec:printing} on how to modify |\bnumprintone| to coerce \TeX\ into
+wrapping numbers too long for the available width.
+
 \section{Differences from \csh{numexpr}}
 \label{sec:differences}
 
@@ -692,12 +880,12 @@
 ...
 \fi
 \end{verbatim}
-the end of line will insert a terminating space token. Again, here
-|\bnumeval{...}| must produce an integer acceptable to \TeX, i.e. at most
-{\number"7FFFFFFF} in absolute value.
+the end of line will (under the normal \LaTeX\ configuration) insert a
+terminating space token. Again, here |\bnumeval{...}| must produce an integer
+acceptable to \TeX, i.e. at most {\number"7FFFFFFF} in absolute value.
 
 \section{Printing big numbers}
-
+\label{sec:printing}
 \LaTeX{} will not split long numbers at the end of lines. I personally
 often use helper macros (not in the package) of the following type:
 
@@ -714,96 +902,255 @@
 
 \noindent|\thebnumexpr 1000!\relax=|\phantom{0}{\color{digitscolor}\printnumber{\thebnumexpr 1000!\relax}}\par
 
-\section{Expression syntax}
+\section{Expression syntax and its customizability}
 
-It is the expected one with infix operators and parentheses, the
-recognized operators being |+|, |-|, |*|, |/| (rounded division),
-|^| (power), |**| (power), |//| (by default floored division),
-|/:| (the associated modulo) and |!| (factorial). One can input hexadecimal
-numbers as in \TeX\ syntax for number assignments, i.e. using a |"| prefix and
-only uppercase letters |ABCDEF|.
+The implemented syntax is the expected one with infix operators and
+parentheses, the recognized operators being |+|, |-|, |*|, |/| (rounded
+division), |^| (power), |**| (power), |//| (by default floored division), |/:|
+(the associated modulo) and |!| (factorial). One can input hexadecimal numbers
+as in \TeX\ syntax for number assignments, i.e. using a |"| prefix and only
+uppercase letters |ABCDEF|.
 
-The modulo |/:| is by default associated with the floored division |//|, but
-using |\bnumexprsetup{mod=...}| it can, like the other operators, be remapped
-to any macro of one's choice.
+Different computations may be separated by commas. The whole expression is
+handled token by token, any component (digit, operator, parentheses... even
+the ending |\relax|) may arise on the spot from macro expansions.  The
+underscore |_| can be used to separate digits in long numbers, for readability
+of the input.
 
-Different computations may be separated by commas. The whole
-expression is handled token by token, any component (digit, operator,
-parenthesis... even the ending |\relax|) may arise on the spot from
-macro expansions.
+The precedence rules are as expected and detailed in the next section.
+Operators on the same level of precedence (like |*|, |/|, |//|, |/:|) behave
+in a left-associative way, and these examples behave as e.g.\@ with Python
+analogous operators:\newline \bneshoweval{100//3*4, 100*4//3, 100/:3*4,
+  100*4/:3, 100//3/:5}
 
-The precedence rules are the expected ones. Tacit multiplication applies in
-front of parentheses, and after them, and it has an elevated precedence
-compared to multiplication explicitly induced by |*|.
+At |1.5| a change was made to the power operators which became
+right-associative. Again, this matches the behaviour e.g.\@ of Python:%
+%
+\footnote{It had been announced at \xintexprname \texttt{1.4} that probably in
+  future power operator would become right-associative, so we experiment it
+  here in \bnumname in advance.}%
+%
+\newline
+\bneshoweval{2^3^4, 2^(3^4)}
 
-There is currently no user interface to change precedence levels. The
-three operators |/|, |//|, |/:| are at the same level of precedence as the
-multiplication |*|. The factorial postfix |!| has highest precedence. The
-minus signs inherit the precedence level of the previously encountered infix
-operators.
+It is possible to customize completely the behaviour of the parser, in two ways:
+\begin{itemize}
+\item via |\bnumsetup| which has a simple interface to replace the macros
+  associated to the operators |+|, |-|, |*|, |/|, |//|, |/:|, |**| and |^| by
+  custom macros,
+\item or even more completely via |\bnumdefinfix| and |\bnumdefpostfix| which
+  allow to add new operators to the syntax! (or overwrite existing ones...)
+\end{itemize}
 
-In case of equal precedence the operations are left-associative,%
+\section{Precedences}
+
+The parser implements precedence rules based on concepts which are summarized
+below. I am providing them for users who will use the customizing macros.
+\begin{itemize}
+\item an infix operator has two associated precedence levels, say |L| and
+  |R|,
+\item the parser proceeds from left to right, pausing each time it has found a
+  new number and an operator following it,
+\item the parser compares the left-precedence |L| of the new found operator to
+  the right-precedence |R_last| of the last delayed operation (which already
+  has one argument and would like to know if it can use the new found one): if
+  |L| is at most equal to it, the delayed operation is now executed, else the
+  new-found operation is kept around to be executed first, once it will have
+  gathered its arguments, of which only one is known at this stage.
+\end{itemize}
+
+Although there is thus internally all the needed room for sophistication, the
+implemented table of precedences simply puts all of multiplication and
+division related operations at the same level, which means that left
+associativity will apply with these operators. I could see that Python behaves
+the same way for its analogous operators.
+
+Here is the default table of precedences as implemented by the package:
+\begin{center}
+\DeleteShortVerb{\|}%
+  \begin{tabular}{|c|c|c|}
+    \multicolumn3{c}{Table of precedences}\\\hline
+\MakeShortVerb{\|}%
+    operator& left &right\\\hline
+    |+|,|-|& 12&12\\
+    |*|,|/|,|//|,|/:|& 14&14\\
+    tacit |*|&16&14\\
+    |**|, |^|& 18&17\\
+    |!| &20&n/a\\\hline
+  \end{tabular}
+\end{center}
+Tacit multiplication applies in front of parentheses, and after them, also in
+front of count variables or registers. As shown in the table it has an
+elevated precedence compared to multiplication explicitly induced by |*|, so
+|100/4(9)| is computed as |100/36| and not as |25*9|:\newline
+\bneshoweval{100/4(9), (100/4)9, 1000 // (100/4) 9 (1+1) * 13}
+More generally |A/B(C)(D)(E)*F| will compute |(A/(B*C*D*E))*F|.%
 %
-\footnote{But it has been announced at \xintexprname \texttt{1.4} that
-  probably in future power operator will become right-associative, and if this
-  is done, this will be transferred to \bnumname also.}
-%
-hence:\newline \bneshoweval{2^3^4, (2^3)^4, 2^(3^4)}
+\footnote{The |B(C)(D)(E)| product will be computed as |B*(C*(D*E))| because
+  the right-precedence of tacit multiplication is |14| but its left-precedence
+  is |16|, creating right associativity.  As the underlying mathematical
+  operation is associative this is irrelevant to final result.}
 
-The underscore |_| can be used to separate digits in long numbers, for
-readability of the input.
+The unary |-|, as prefix, has a special behaviour: after an infix operator it
+will acquire a right-precedence which is the minimum of |12| (i.e.\@ the
+precedence of addition and subtraction) and of the right-precedence of the
+infix operator.  For example |2^-3^4| will be parsed as |2^(-(3^4))|, raising
+an error because the parser is by default integer only, but see the section
+about |\bnumsetup| which explains how to let |\bnumeval| computes fractions!
 
-\section{Options}
 
-The sole package option is |custom|: it tells \bnumname not to load
-package \xintcorename.
+\section{\csh{bnumdefinfix}}
 
-\section{\csh{bnumexprsetup}}
+It is possible to define infix binary operators of one's own choosing.%
+%
+\footnote{The effect of |\bnumdefinfix| is global if under |\xintglobaldefstrue| setting.}
+%
+The syntax is 
+\centeredline{|\bnumdefinfix|\marg{operator}\marg{\string\macro}\marg{L-prec}\marg{R-prec}}
+\begin{description}
+\item[\marg{operator}] The characters for the operator, they may be letters or
+  non-letters, and must not be active or among the special characters |\|,
+  \textcolor{smallverbcolor}{\{}, \textcolor{smallverbcolor}{\}}, |#| and
+  {\catcode`\% 12 |%|}.  Also,
+    spaces will be removed.%
+%
+\footnote{The |_| can be used, but not as first character of the operator, as
+  it would be mis-construed on usage as part of the previous number, and
+  ignored as such.}%
+%
+$^{,}$%
+%
+{\catcode`# 12 \footnote{It is actually possible to use |#| as an operator
+    name or a character in such a name but the definition with |\bnumdefinfix|
+    must then be done either with \expandafter|\string\string#| or
+    |####|...}}%
+$^{,}$%
+%
+\footnote{Active characters must be prefixed by |\string| both at the time of
+  the definition and at the time of use. It is probably better to use a toggle which
+  will turn off the activity, both at time of definition and at time of use.}%
+\item[\marg{\string\macro}] The expandable macro (expecting two mandatory
+  arguments) which is to assign to the infix operator. This macro must be
+  \emph{f}-expandable. Also it must (if the default package configuration is
+  not modified for the core operators) produce integers in the ``strict''
+  format which is expected by the \xintcorename macros for arithmetic: no
+  leading zeros, at most one minus sign, no plus sign, no spaces.
+\item[\marg{L-prec}] An integer, minimal |4|, maximal |22|, which governs
+  the left-\hskip0pt precedence of the infix operator.
+\item[\marg{R-prec}] An integer, minimal |4|, maximal |22|, which governs the
+  right-\hskip0pt precedence of the infix operator.
+\end{description}
+Generally, the two precedences are set to the same value.
 
-Package \bnumname needs that some big integer engine provides the macros doing
-the actual computations. By default, it loads package \xintcorename (a subset
-of \href{http://www.ctan.org/pkg/xint}{xint}) and uses \csa{bnumexprsetup} in
-the following way:
+Once a multi-character operator is defined, the first characters of its name
+can be used if no ambiguity.  In case of ambiguity, it is the earliest defined
+shortcut which prevails, except for the full name. So for example if |$abc|
+operator is defined, and |$ab| is defined next, then |$| and |$a| will still
+serve as shortcuts to the original |$abc|, but |$ab| will refer to the newly
+defined operator.
+
+Fully qualified names are never ambiguous, and a shortcut once defined will
+change meaning under only these two possibilities:
+\begin{itemize}
+\item it is re-defined as the full name of a new operator,
+\item the original operator to which the shortcut refers is defined again; then 
+  the shortcut is automatically updated to point to the new meaning.
+\end{itemize}
 \begin{verbatim}
-    \usepackage{xintcore}
-    \bnumexprsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul,
-                   divround=\xintiiDivRound, div=\xintiiDivFloor,
-                   mod=\xintiiMod, pow=\xintiiPow, fac=\xintiiFac,
-                   opp=\xintiiOpp}%
+\def\equals#1#2{\ifnum\pdfstrcmp{#1}{#2}=0 \expandafter1\else
+                                             \expandafter0\fi}
+% or:
+\def\equals#1#2{\expanded{\ifnum\pdfstrcmp{#1}{#2}=0 1\else0\fi}}
+\def\differ#1#2{\expanded{\ifnum\pdfstrcmp{#1}{#2}=0 0\else1\fi}}
+\bnumdefinfix{==}{\equals}{10}{10}
+\bnumdefinfix{!=}{\differ}{10}{10}
+\bnumdefinfix{times}{\xintiiMul}{14}{14}
+\bnumdefinfix{++}{\xintiiAdd}{19}{19}
 \end{verbatim}
+%\def\equals#1#2{\ifnum\pdfstrcmp{#1}{#2}=0 \expandafter1\else\expandafter0\fi}
+\def\equals#1#2{\expanded{\ifnum\pdfstrcmp{#1}{#2}=0 1\else0\fi}}
+\def\differ#1#2{\expanded{\ifnum\pdfstrcmp{#1}{#2}=0 0\else1\fi}}
+\bnumdefinfix{==}{\equals}{10}{10}
+\bnumdefinfix{!=}{\differ}{10}{10}
+\bnumdefinfix{times}{\xintiiMul}{14}{14}
+\bnumdefinfix{++}{\xintiiAdd}{19}{19}
+%
+\bneshoweval{2 + 3! = 5, 2 + (3!) == 8} Notice in the |2+3! = 5| example that
+the existence of |!=| prevails on applying the factorial, so this is test
+whether |2+3| and |5| differ; it is not a matter of precedence here, but of
+input parsing ignoring spaces. And |2+3! == 8| would create an error as after
+having found the |!=| operator and now expecting a digit (as there is no |!==|
+operator) the parser would find an unexpected |=| and report an error. Hence
+the usage of parentheses in the input.%
+%
+\footnote{As |!=| is indeed defined out-of-the-box in the \xintexprname
+  syntax, the |3! == 8| issue applies with |\xinteval| and perhaps I should
+  add it to the user documentation, as warning.}\newline
+\bneshoweval{2^5 == 4 times 8, 11 t 14}
+\bneshoweval{100 ++ -10 ^ 3, (100 - 10)^3, 2 ** 5 ++ 3, 2^(5+3)}
 
-If
-using \csa{bnumexprsetup}, it is not necessary to specify all keys,
-for example one can do |\bnumexprsetup{mul=\MyFasterMul}|, and only
-multiplication will be changed.
 
-Naturally it is up to the user to load the appropriate package for
-the alternative macros.
+\section{\csh{bnumdefpostfix}}
 
-The macros serving as custom user replacements must be \emph{f}-expandable.%
+It is possible to define postfix unary operators of one's own choosing.%
 %
-\footnote{Prior to |1.4|, only \emph{x}-expandability was required. The author
-  could relax again the constraint, if asked to do so. Or perhaps simply add
-  an option for it.}
+\footnote{The effect of |\bnumdefpostfix| is global if under |\xintglobaldefstrue| setting.}
 %
-(except for the computation of factorials, which only has to be
-\emph{x}-expandable).
+The syntax is 
+\centeredline{|\bnumdefpostfix|\marg{operator}\marg{\string\macro}\marg{L-prec}}
+\begin{description}
+\item[\marg{operator}] The characters for the operator name: same
+  conditions as for |\bnumdefinfix|. Postfix and infix operators share the
+  same name-space, regarding abbreviated names.
+\item[\marg{\string\macro}] The one argument expandable macro to assign to
+  the postfix operator. This macro only needs to be \emph{x}-expandable.
+\item[\marg{L-prec}] An integer, minimal |4|, maximal |22|, which governs the
+  left-\hskip0pt precedence of the infix operator.
+\end{description}
+Examples below which use the maximal precedence are typical of what is
+expected of a ``function'' (and I even used |.len()| notation with parentheses
+in one example, the parentheses are part of the postfix operator name).  And
+indeed such postfix operators are thus a way to implement functions in
+disguise, circumventing the fact that the \bnumname parser will never be
+extended to work with functional syntax (for this, see \xintexprname).  With
+the convention (followed in some examples) that such postfix operators start
+with a full stop, but never contain another one, we can chain simply by using
+concatenation (no need for parentheses), as there will be no
+ambiguity.
+\begin{verbatim}
+\usepackage{xint}% for \xintiiSum, \xintiiSqrt
+\def\myRev#1{\xintNum{\xintReverseOrder{#1}}}% reverse and trim leading zeros
+\bnumdefpostfix{$}{\myRev}{22}%     the $ will have top precedence
+\bnumdefpostfix{:}{\myRev}{4}%      the : will have lowest precedence
+\bnumdefpostfix{::}{\xintiiSqr}{4}% the :: is a completely different operator
+\bnumdefpostfix{.len()}{\xintLength}{22}% () for fun but a single . will be enough!
+\bnumdefpostfix{.sumdigits}{\xintiiSum}{22}% .s will abbreviate
+\bnumdefpostfix{.sqrt}{\xintiiSqrt}{22}%     .sq will be unambiguous (but confusing)
+\bnumdefpostfix{.rep}{\xintReplicate3}{22}%  .r will be unambiguous
+\end{verbatim}
+\def\myRev#1{\xintNum{\xintReverseOrder{#1}}}% reverse digits and trim leading zeros
+\bnumdefpostfix{$}{\myRev}{22}% $
+\bnumdefpostfix{:}{\myRev}{4}%
+\bnumdefpostfix{::}{\xintiiSqr}{4}%
+\bnumdefpostfix{.len()}{\xintLength}{22}%
+\bnumdefpostfix{.sumdigits}{\xintiiSum}{22}%
+\bnumdefpostfix{.sqrt}{\xintiiSqrt}{22}%
+\bnumdefpostfix{.rep}{\xintReplicate3}{22}%
+\bneshoweval{(2^31).len(), (2^31)., 2^31$, 2^31:, (2^31)$}
+\bneshoweval{(2^31).sqrt, 100000000.sq.sq}
+\bneshoweval{(2^31).sumdigits, 123456789.s, 123456789.s.s, 123456789.s.s.s}
+\bneshoweval{10^10+10000+2000+300+40+5:}
+\bneshoweval{1+2+3+4+5+6+7+8+9+10 :: +1 :: *2 :: :: :}
+\bneshoweval{123456789.r}\par\vspace*{-\baselineskip}% Toujours LaTeX avec ses
+                                % espaces verticaux TROP GRANDS DEPUIS 30 ANS
+\begin{verbatim}
+\bnumdefpostfix{.rep}{\xintReplicate5}{22}% .rep modified --> .r too
+\end{verbatim}
+\bnumdefpostfix{.rep}{\xintReplicate5}{22}%
+\bneshoweval{123456789.r}
 
-They will by default receive arguments composed of explicit digit tokens, with
-no leading zeros, with at most one leading minus sign and no plus sign.
+\clearpage
 
-The format of these arguments may depend on what the |opp=\foo| replacement
-macro does. If the custom |\foo| inserts a |+| when taking the opposite of a
-negative number, then the custom macros for arithmetic (and the |\foo| macro
-itself) must be able to handle arguments starting optionally with such a |+|.
-
-Macro |\bnumexprsetup| can be used multiple times in the same document, thus
-allowing to switch math engines or to remap operators to some other arithmetic
-macros of the same math engine. Its effect obeys the local scope.
-
-At |1.4| release there is no option to customize how the hexadecimal input and
-output is handled, it goes necessarily via the \xintbinhexname macros.
-
 \section{Readme}
 \begingroup
 \makeatletter\def\x{\baselineskip10pt
@@ -819,7 +1166,7 @@
                     \noindent\kern\parindent\input README.md
 \endgroup }\x
 
-%\clearpage
+\clearpage
 
 \section{Changes}
 %\small
@@ -841,61 +1188,53 @@
 %</dtx>
 %<*package>
 %
-% \section{Package \bnumnameimp implementation}
+% \section{\bnumname implementation}
 % \label{sec:bnumexprcode}
 % \etocdefaultlines
 % \localtableofcontents
-% \etocmarkbothnouc{Package \bnumnameimp implementation}
+% \etocmarkbothnouc{\bnumnameuserdoc \hyperref[sec:bnumexprcode]{implementation}}
 %
-% Comments are sparse.  Actually at |1.4|, there are simply no comments. I
-% transferred from \xintexprname its |\expanded| based infra-structure from
-% its own |1.4| release of January 2020.
+% I transferred mid-May 2021 from \xintexprname its |\expanded| based
+% infra-structure from its own |1.4| release of January 2020 and bumped
+% version to |1.4|. Also I added support for hexadecimal input and output, via
+% unconditional loading of \xintbinhexname.
 %
-% Error handling by the parser is kept to a minimum; if something goes wrong,
-% the offensive token gets discarded, and it is not even always the case that
-% some expandable error message is issued.
-%
-% A few comments at |1.4a|:
+% A few comments added here at |1.4a|:
 % \begin{itemize}
 % \item It looked a bit costly and probably would have been mostly useless to
 %   end users to integrate in \bnumname support for nested structures via
 %   square brackets [, ], which is in \xintexprname since its January 2020
-%   |1.4| release.  But some underlying related architecture remains here; we
-%   could make some micro-gains probably but diverging from upstream code
+%   |1.4| release.  But some of the related architecture remains here; we
+%   could make some gains probably but diverging from upstream code
 %   would make maintenance a nightmare.
+% \item Formerly, the |\csname...\endcsname| encapsulation technique had the
+%   after-effect to allow the macros supporting the infix operators to be only
+%   \emph{x}-expandable.  At |1.4|, I could have still allowed support macros
+%   being only \emph{x}-expandable, but, keeping in sync with upstream, I have
+%   used only a |\romannumeral| trigger and did not insert an |\expanded|, so
+%   now the support macros must be \emph{f}-expandable.  The |1.4a| release
+%   fixes the related user documentation of |\bnumsetup| which was not
+%   updated at |1.4|.  The support macro for the factorial however needs only
+%   be \emph{x}-expandable.
+% \item Also, I simply do not understand why the legacy (|1.2e|) user documentation
+%   said that the support macros were supposed to \emph{f}-expand their arguments, as
+%   they are used only with arguments being explicit digit tokens (and
+%   optional minus sign).
 % \item The |\bnumexpr\relax| syntax creating an empty ople is by itself now
 %   legal, and can be injected (comma separated) in an expression, keeping it
 %   invariant, however |\bnumeval{}| ends in a |File ended while scanning use
 %   of \BNE_print_c| error because |\BNEprint| makes the tacit requirement
 %   that the 1D ople to output has at least one item.
-% \item Formerly, the |\csname...\endcsname| encapsulation technique had the
-%   after-effect to allow the macros supporting the infix operators to be only
-%   x-expandable.  At |1.4|, I could have still allowed only x-expandable
-%   macros, but, keeping in sync with upstream, I have used only a
-%   |\romannumeral| trigger and did not insert an |\expanded|, so now the
-%   support macros must be f-expandable.  The |1.4a| release fixes the related
-%   user documentation of |\bnumexprsetup| which was not updated at |1.4|.
-%   The support macro for the factorial however needs only be x-expandable.
-% \item Also, I simply do not understand why the legacy user documentation
-%   said that the support macros were supposed to f-expand their arguments, as
-%   they are used only with arguments being explicit digit tokens (and
-%   optional minus sign).
-% \item I hesitated a bit about making the decimal to hexadecimal and
-%   hexadecimal to decimal support macros customizable, but dropped the
-%   idea. Loading \xintbinhexname unconditionally has also the advantage to
-%   not have to define some \xintkernelname provided helper macros; and it
-%   still does not load \xintcorename, so is keeping dependencies somewhat low
-%   and the |custom| option significant.
-% \item I had fleetingly consider a parser |\hexexpr| where input is
-%   hexadecimal with no |"| prefix, but implementing this basically means
-%   duplicating with new names a large chunk of the parser code to have parser
-%   specific |"getnext"| macros for example.  Not worth it.
 % \end{itemize}
 %
-% \subsection{Package identification and catcode setup}
+% At |1.5|, right-associativity is implemented for powers in anticipation of
+% upstream, and the customizability and extendibility of the package is made
+% total via added |\bnumdefinfix| and |\bnumdefpostfix|.
+%
+% \subsection{Package identification}\leavevmode
 %    \begin{macrocode}
 \NeedsTeXFormat{LaTeX2e}%
-\ProvidesPackage{bnumexpr}[2021/05/13 v1.4a Expressions with big integers (JFB)]%
+\ProvidesPackage{bnumexpr}[2021/05/17 v1.5 Expressions with big integers (JFB)]%
 %    \end{macrocode}
 % \subsection{Load unconditionally xintbinhex}
 % Newly done at |1.4|. Formerly, \bnumname had no dependency if loaded
@@ -908,39 +1247,56 @@
 %    \begin{macrocode}
 \RequirePackage{xintbinhex}[2021/05/10]%
 %    \end{macrocode}
-% \subsection{\csh{bnumexprsetup}}
+% \subsection{Package options}\leavevmode
 %    \begin{macrocode}
+\def\BNEtmpa {0}%
+\DeclareOption {custom}{\def\BNEtmpa {1}}%
+\ProcessOptions\relax
+%    \end{macrocode}
+% \subsection{\csh{bnumsetup} and conditional loading of \xintcorename}
+% The keys should have been |Add|, |Sub|, \dots, not |add|, |sub|, \dots, so
+% internally macros |\BNE_Op_Add| etc\dots\ macro names would be used, but well,
+% let's simply live with this.
+%
+% |\bnumsetup| replaces at |1.5| deprecated |\bnumexprsetup| which is kept as an alias.
+%    \begin{macrocode}
 {\catcode`! 3 \catcode`_ 11 %
-  \gdef\bnumexprsetup #1{\BNE_parsekeys #1,=!,}%
+  \gdef\bnumsetup #1{\BNE_parsekeys #1,=!,}%
   \gdef\BNE_parsekeys #1=#2#3,%
   {%
     \ifx!#2\expandafter\BNE_parsedone\fi
+  \XINT_global
     \expandafter
     \let\csname BNE_Op_\xint_zapspaces #1 \xint_gobble_i\endcsname%
-    =#2\BNE_parsekeys
+    =#2%
+  \ifxintverbose
+    \PackageInfo{bnumexpr}{assigned
+    \ifxintglobaldefs globally \fi
+     \string#2 to \xint_zapspaces #1 \xint_gobble_i\MessageBreak
+%    \end{macrocode}
+% Workaround the space inserted by |\on at line|.
+%    \begin{macrocode}
+     \expandafter\xint_firstofone}%
+  \fi
+  \BNE_parsekeys
   }%
   \gdef\BNE_parsedone #1\BNE_parsekeys {}%
 }%
-%    \end{macrocode}
-% \subsection{Package options}
-% The keys should have been |Add|, |Sub|, \dots, not |add|, |sub|, \dots, so
-% internally macros |\BNE_Op_Add| etc\dots\ macro names would be used, but well,
-% let's simply leave with this.
-%    \begin{macrocode}
-\def\BNEtmpa {0}%
-\DeclareOption {custom}{\def\BNEtmpa {1}}%
-\ProcessOptions\relax
-\edef\BNErestorecatcodes{\XINTrestorecatcodes}%
-\XINTsetcatcodes%
-\if0\BNEtmpa\expandafter\xint_secondoftwo\fi
-\xint_gobble_i{%
+\let\bnumexprsetup\bnumsetup
+\if0\BNEtmpa\expandafter\@secondoftwo\fi
+\@gobble{%
     \RequirePackage{xintcore}[2021/05/10]%
-    \bnumexprsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul,
+    \bnumsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul,
                    divround=\xintiiDivRound, div=\xintiiDivFloor,
                    mod=\xintiiMod, pow=\xintiiPow, fac=\xintiiFac,
                    opp=\xintiiOpp}%
 }%
 %    \end{macrocode}
+% \subsection{Activate usual \xintname catcodes for code source}\leavevmode
+%    \begin{macrocode}
+\edef\BNErestorecatcodes{\XINTrestorecatcodes}%
+\XINTsetcatcodes%
+%    \end{macrocode}
 % Strangely those three are not defined in xintkernel.sty, but only in xint.sty
 %    \begin{macrocode}
 \long\def\xint_firstofthree  #1#2#3{#1}%
@@ -947,8 +1303,26 @@
 \long\def\xint_secondofthree #1#2#3{#2}%
 \long\def\xint_thirdofthree  #1#2#3{#3}%
 %    \end{macrocode}
-% \subsection{\csh{bnumexpr}, \csh{thebnumexpr}, \csh{bnethe}, \csh{bnumeval}}
+% For the mechanism of |\bnumdefinfix| we need [1] precedence levels to be
+% available as |\chardef|'s. \xintkernelname already provides 0-10, 12, 14,
+% 16, 18, 20, 22.  Admittedly they could be created only dynamically, and then
+% I would not have to set a cap at 22, but well, that's already a large
+% supported range for a functionality nobody will use, as nobody probably uses
+% the package to start with.
+%
+% .. [1] left levels need to be represented by one token; right levels are
+% hard-coded into |checkp_<op>| macros and could have been there explicit
+% digit tokens but we will use the |\xint_c_...| |\char|-tokens.
 %    \begin{macrocode}
+\chardef\xint_c_xi   11
+\chardef\xint_c_xiii 13
+\chardef\xint_c_xv   15
+\chardef\xint_c_xvii 17
+\chardef\xint_c_xix  19
+\chardef\xint_c_xxi  21
+%    \end{macrocode}
+% \subsection{\csh{bnumexpr}, \csh{thebnumexpr}, \csh{bnethe}, \csh{bnumeval}}\leavevmode
+%    \begin{macrocode}
 \def\XINTfstop {\noexpand\XINTfstop}%
 \def\bnumexpr  {\romannumeral0\bnumexpro}%
 \def\bnumexpro {\expandafter\BNE_wrap\romannumeral0\bnebareeval }%
@@ -962,19 +1336,25 @@
 \def\bnebareeval{\BNE_start}%
 \def\bnethe#1{\expanded\expandafter\xint_gobble_i\romannumeral`&&@#1}%
 \protected\def\BNEprint.#1{{\BNE_print#1.}}%
-\def\BNE_print#1{#1\expandafter\BNE_print_a\string}%
+\def\BNE_print#1{\bnumprintone{#1}\expandafter\BNE_print_a\string}%
 \def\BNE_print_a#1{\unless\if#1.\expandafter\BNE_print_b\fi}%
 \def\BNE_print_b
    {\expandafter\BNE_print_c\expandafter{\expandafter\xint_gobble_i\string}}%
-\def\BNE_print_c#1{, #1\expandafter\BNE_print_a\string}%
+\def\BNE_print_c#1{\bnumprintonesep\bnumprintone{#1}\expandafter\BNE_print_a\string}%
 \protected\def\BNEprinthex.#1{{\BNE_printhex#1.}}%
-\def\BNE_printhex#1{\xintDecToHex{#1}\expandafter\BNE_printhex_a\string}%
+\def\BNE_printhex#1{\bnumprintonetohex{#1}\expandafter\BNE_printhex_a\string}%
 \def\BNE_printhex_a#1{\unless\if#1.\expandafter\BNE_printhex_b\fi}%
 \def\BNE_printhex_b
    {\expandafter\BNE_printhex_c\expandafter{\expandafter\xint_gobble_i\string}}%
-\def\BNE_printhex_c#1{, \xintDecToHex{#1}\expandafter\BNE_printhex_a\string}%
+\def\BNE_printhex_c#1{\bnumprintonesep\bnumprintonetohex{#1}\expandafter\BNE_printhex_a\string}%
+\let\bnumprintone\xint_firstofone
+\let\bnumprintonetohex\xintDecToHex
+\def\bnumprintonesep{, }%
 %    \end{macrocode}
 % \subsection{\csh{BNE_getnext}}
+% The upstream |\BNE_put_op_first| has a string of included |\expandafter|,
+% which was imported here at |1.4| and |1.4a| but they serve nothing in our
+% context. Removed this useless overhead at |1.5|.
 %    \begin{macrocode}
 \def\BNE_getnext #1%
 {%
@@ -981,7 +1361,7 @@
     \expandafter\BNE_put_op_first\romannumeral`&&@%
     \expandafter\BNE_getnext_a\romannumeral`&&@#1%
 }%
-\def\BNE_put_op_first #1#2#3{\expandafter#2\expandafter#3\expandafter{#1}}%
+\def\BNE_put_op_first #1#2#3{#2#3{#1}}%
 \def\BNE_getnext_a #1%
 {%
     \ifx\relax #1\xint_dothis\BNE_foundprematureend\fi
@@ -1021,8 +1401,7 @@
 % In the case of hitting a |(|, previous release inserted directly a
 % |\BNE_oparen|.  But the expansion architecture imported from upstream
 % |\xintiiexpr| has been refactored, and the |..._oparen| meaning and
-% usage evolved.  We stick with |{}\xint_c_ii^v (| from upstream,
-% which works (I am 15 months away from \xintexprname |1.4|).
+% usage evolved.  We stick with |{}\xint_c_ii^v (| from upstream.
 %    \begin{macrocode}
 \def\BNE_getnextfork #1{%
     \if#1+\xint_dothis \BNE_getnext_a \fi
@@ -1031,7 +1410,7 @@
     \xint_orthat {\BNE_scan_number #1}%
 }%
 %    \end{macrocode}
-% \subsection{Parsing an integer in decimal or hexadecimal notation}
+% \subsection{Parsing an integer in decimal or hexadecimal notation}\leavevmode
 %    \begin{macrocode}
 \def\BNE_scan_number #1%
 {%
@@ -1039,7 +1418,22 @@
     \ifnum \xint_c_ix<1\string#1 \xint_dothis \BNE_startint\fi
     \xint_orthat \BNE_notadigit #1%
 }%
-\def\BNE_notadigit#1{\BNE_getnext }%
+%    \end{macrocode}
+% If user employs |\bnumdefinfix| with |\string#|, and then tries |100##3|,
+% the first |#| will be interpreted as operator (assuming no
+% operator starting with |##| has actually been defined) and the error
+% "message" (which is not using |\message| or a |\write|)
+% will then be
+% \centeredline{|Digit? (got `##')|}
+% because the parser is actually looking for a digit but finds the second |#|,
+% and TeX displays it doubled. This is doubly
+% confusing, but well, let's not dwell on that.
+%    \begin{macrocode}
+\def\BNE_notadigit#1%
+{%
+    \expandafter\BNE_scan_number
+    \romannumeral`&&@\XINT_expandableerror{Digit? (got `#1'). Hit I<RET><digit>}%
+}%
 \def\BNE_startint #1%
 {%
     \if #10\expandafter\BNE_gobz_a\else\expandafter\BNE_scanint_a\fi #1%
@@ -1060,15 +1454,18 @@
 {%
     \expandafter\BNE_scanint_main\romannumeral`&&@#1%
 }%
+%    \end{macrocode}
+% Upstream (at |1.4f|) has |_getop| here, but let's jump directly to |BNE_getop_a|.
+%    \begin{macrocode}
 \def\BNE_scanint_hit_cs \ifnum#1\fi#2\BNE_scanint_again
 {%
-    \iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#2%
+    \iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#2%
 }%
 \def\BNE_scanint_next #1\BNE_scanint_again
 {%
     \if    _#1\xint_dothis\BNE_scanint_again\fi
     \xint_orthat
-    {\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#1}%
+    {\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#1}%
 }%
 \def\BNE_gobz_scanint_main #1%
 {%
@@ -1080,9 +1477,12 @@
 {%
     \expandafter\BNE_gobz_scanint_main\romannumeral`&&@#1%
 }%
+%    \end{macrocode}
+% Upstream (at |1.4f|) has |_getop| here, but let's jump directly to |BNE_getop_a|.
+%    \begin{macrocode}
 \def\BNE_gobz_scanint_hit_cs\ifnum#1\fi#2\BNE_scanint_again
 {%
-    0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#2%
+    0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#2%
 }%
 \def\BNE_gobz_scanint_next #1\BNE_scanint_again
 {%
@@ -1089,20 +1489,60 @@
     \if    _#1\xint_dothis\BNE_gobz_scanint_again\fi
     \if    0#1\xint_dothis\BNE_gobz_scanint_again\fi
     \xint_orthat
-    {0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#1}%
+    {0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#1}%
 }%
 \def\BNE_hex_in #1.%
 {%
-    \expanded{{{\xintHexToDec{#1}}}\expandafter}\romannumeral`&&@\BNE_getop
+    \expanded{{{\bnumhextodec{#1}}}\expandafter}\romannumeral`&&@\BNE_getop
 }%
-\def\BNE_scanhex #1% #1="
+\let\bnumhextodec\xintHexToDec
+%    \end{macrocode}
+% Upstream (until |1.4f|) had a long-standing bug in its hexadecimal input,
+% which was inherited here at |1.4|: the |\BNE_scanhex| triggered
+% |\BNE_scanhex_a| which then grabbed an unexpanded token and used it as is
+% in an |\ifcat|... this made syntax such as |"\foo| broken.  Fixed here at
+% |1.5|.
+%
+% And there was a further long-standing bug in upstream (from |1.2m| to
+% |1.4f|) about leading hexadecimal zeros not being trimmed. This was
+% inherited here at |1.4|. Fixed also at |1.5|.
+%    \begin{macrocode}
+\def\BNE_scanhex #1#2% #1="
 {%
-    \expandafter\BNE_hex_in\expanded\bgroup\BNE_scanhex_a
+    \expandafter\BNE_hex_in\expanded\bgroup
+    \expandafter\BNE_scanhexgobz_a\romannumeral`&&@#2%
 }%
+\def\BNE_scanhexgobz_a #1%
+{%
+    \ifcat #1\relax0.\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi
+    \BNE_scanhexgobz_aa #1%
+}%
+\def\BNE_scanhexgobz_aa #1%
+{%
+    \if\ifnum`#1>`0
+       \ifnum`#1>`9
+       \ifnum`#1>`@
+       \ifnum`#1>`F
+       0\else1\fi\else0\fi\else1\fi\else0\fi 1%
+       \xint_dothis\BNE_scanhex_b
+    \fi
+    \if 0#1\xint_dothis\BNE_scanhexgobz_bgob\fi
+    \if _#1\xint_dothis\BNE_scanhexgobz_bgob\fi
+    \if .#1\xint_dothis\BNE_scanhexgobz_toII\fi
+    \xint_orthat
+     {\XINT_expandableerror
+        {HexDigit was expected but saw `#1'. Using 0, hit <RET>}%
+      0.>;\iffalse{\fi}}%
+    #1%
+}%
+\def\BNE_scanhexgobz_bgob #1#2%
+{%
+    \expandafter\BNE_scanhexgobz_a\romannumeral`&&@#2%
+}%
 \def\BNE_scanhex_a #1%
 {%
-    \ifcat #1\relax\xint_dothis{.\iffalse{\fi}#1}\fi
-    \xint_orthat {\BNE_scanhex_aa #1}%
+    \ifcat #1\relax.\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi
+    \BNE_scanhex_aa #1%
 }%
 \def\BNE_scanhex_aa #1%
 {%
@@ -1114,7 +1554,7 @@
        \expandafter\BNE_scanhex_b
     \else
        \if _#1\xint_dothis{\expandafter\BNE_scanhex_bgob}\fi
-       \xint_orthat {\xint_afterfi {.\iffalse{\fi}}}%
+       \xint_orthat {.\iffalse{\fi\expandafter}}%
     \fi
     #1%
 }%
@@ -1128,6 +1568,14 @@
 }%
 %    \end{macrocode}
 % \subsection{\csh{BNE_getop}}
+% The upstream analog to |\BNE_getop_a| applies |\string| to |#1| in its
+% thirdofthree branch before handing over to analog of |\BNE_scanop_a|, but I
+% see no reason for doing it here (and I do have to check if upstream has
+% any valid reason to do it). Removed. First branch was a |\BNE_foundend|,
+% used only here, and expanding to |\xint_c_\relax|, let's move the
+% |#1| (which will be |\relax|) last and simply insert |\xint_c_|.
+%
+% The |_scanop| macros have been refactored at upstream and here |1.5|.
 %    \begin{macrocode}
 \def\BNE_getop #1%
 {%
@@ -1141,12 +1589,12 @@
     \ifnum\xint_c_ix<1\string#1 \xint_dothis\xint_secondofthree\fi
     \if    (#1\xint_dothis      \xint_secondofthree\fi %)
     \xint_orthat \xint_thirdofthree
-    {\BNE_foundend}%
-    {\BNE_precedence_*** *#1}%
-    {\expandafter\BNE_scanop_a \string#1}%
+    \xint_c_
+    {\BNE_prec_tacit *}%
+    \BNE_scanop_a
+    #1%
 }%
 \catcode`* 12
-\def\BNE_foundend {\xint_c_ \relax}%
 \def\BNE_scanop_a #1#2%
 {%
     \expandafter\BNE_scanop_b\expandafter#1\romannumeral`&&@#2%
@@ -1153,24 +1601,33 @@
 }%
 \def\BNE_scanop_b #1#2%
 {%
-    \ifcat#2\relax\xint_dothis{\BNE_foundop_a #1#2}\fi
-    \ifcsname BNE_itself_#1#2\endcsname
-    \xint_dothis
-        {\expandafter\BNE_scanop_c\csname BNE_itself_#1#2\endcsname}\fi
-    \xint_orthat {\BNE_foundop_a #1#2}%
+    \unless\ifcat#2\relax
+           \ifcsname BNE_itself_#1#2\endcsname
+           \BNE_scanop_c
+    \fi\fi
+    \BNE_foundop_a #1#2%
 }%
-\def\BNE_scanop_c #1#2%
+\def\BNE_scanop_c #1#2#3#4#5% #1#2=\fi\fi
 {%
-    \expandafter\BNE_scanop_d\expandafter#1\romannumeral`&&@#2%
+    #1#2%
+    \expandafter\BNE_scanop_d\csname BNE_itself_#4#5\expandafter\endcsname
+    \romannumeral`&&@%
 }%
 \def\BNE_scanop_d #1#2%
 {%
-  \ifcat#2\relax \xint_dothis{\BNE_foundop #1#2}\fi
-  \ifcsname BNE_itself_#1#2\endcsname
-  \xint_dothis
-        {\expandafter\BNE_scanop_c\csname BNE_itself_#1#2\endcsname }\fi
-  \xint_orthat {\csname BNE_precedence_#1\endcsname #1#2}%
+    \unless\ifcat#2\relax
+           \ifcsname BNE_itself_#1#2\endcsname
+           \BNE_scanop_c
+    \fi\fi
+    \BNE_foundop #1#2%
 }%
+%    \end{macrocode}
+% If a postfix say |?s| is defined and |?r| is encountered the |?| will have
+% been interpreted as a shortcut to |?s| and then the |r| will be found with
+% the parser (after having executed the already found postfix) now looking for
+% another operator so the error message will be |Operator? (got `r')| which is
+% doubly confusing... well, let's not dwell on that.
+%    \begin{macrocode}
 \def\BNE_foundop_a #1%
 {%
     \ifcsname BNE_precedence_#1\endcsname
@@ -1177,14 +1634,14 @@
         \csname BNE_precedence_#1\expandafter\endcsname
         \expandafter #1%
     \else
-        \xint_afterfi{\BNE_getop\romannumeral0%
-        \XINT_expandableerror
-        {"#1" is unknown as operator. (I)nsert one:} }%<<deliberate space
-    \fi
+        \expandafter\BNE_getop_a\romannumeral`&&@%
+        \xint_afterfi{\XINT_expandableerror
+        {Operator? (got `#1'). Hit I<RET><operator>}}%
+     \fi
 }%
 \def\BNE_foundop #1{\csname BNE_precedence_#1\endcsname #1}%
 %    \end{macrocode}
-% \subsection{Expansion spanning; opening and closing parentheses}
+% \subsection{Expansion spanning; opening and closing parentheses}\leavevmode
 %    \begin{macrocode}
 \def\BNE_tmpa #1#2#3#4#5%
 {%
@@ -1211,7 +1668,7 @@
     \def#5%
     {%
         \XINT_expandableerror
-        {An extra ) has been removed. Hit Return, fingers crossed.}%
+        {An extra ) has been removed. Hit <RET>, fingers crossed.}%
         \expandafter#2\romannumeral`&&@\expandafter\BNE_put_op_first
         \romannumeral`&&@\BNE_getop_legacy
     }%
@@ -1267,13 +1724,13 @@
     \csname BNE_op_-xii\endcsname
 \let\BNE_precedence_)\xint_c_i
 \def\BNE_missing_) 
-   {\XINT_expandableerror{Sorry to report a missing ) at the end of this journey.}%
+   {\XINT_expandableerror{Missing ). Hit <RET> to proceed}%
     \xint_c_ \BNE_done }%
 \catcode`) 12
 %    \end{macrocode}
 % \subsection{The comma as binary operator}
 % At |1.4|, it is simply a union operator for 1D oples. Inserting directly
-% here a |<space><comma>| separator (as in earlier releases) in accumulated
+% here a |<comma><space>| separator (as in earlier releases) in accumulated
 % result would avoid having to do it on output but to the cost of diverging
 % from \xintexprname upstream code, and to have to let the |\evaltohex| output
 % routine handle comma separated values rather than braced values.
@@ -1312,29 +1769,46 @@
 \expandafter\let\csname BNE_precedence_,\endcsname\xint_c_iii
 %    \end{macrocode}
 % \subsection{The minus as prefix operator of variable precedence level}
-% This |\BNE_Op_opp| causes trouble as at |1.4| it must be f-expandable,
+% This |\BNE_Op_opp| caused trouble at |1.4| as it must be \emph{f}-expandable,
 % whereas earlier it expanded inside |\csname...\endcsname| context, so I
-% could define it as {\catcode`\#12 |\if-#1\else\if0#10\else-#1\fi\fi|} where
-% {\catcode`\#12 |#1|} was the
+% could define it as \centeredline{|\if-#1\else\if0#10\else-#1\fi\fi|} where
+% |#1| was the
 % first token of unbraced argument but this meant at |1.4| an added
 % |\xint_firstofone| here. Well let's return to sanity at |1.4a| and not add
 % the |\xint_firstofone| and simply default |\BNE_Op_opp| to |\xintiiOpp|,
 % which it should have been all along! And on this occasion let's trim user
-% documentation of irrelevant complications.
+% documentation of complications.
+%
+% The package used to need to define unary minus operator with precedences 12,
+% 14, and 18.  It also defined it at level 16 but this was unneedeed actually,
+% no operator possibly generating usage of an |op_-xvi|.
+%
+% At |1.5| the right precedence of powers was lowered to 17, so we now need
+% here only 12, 14, and 17.
+%
+% Due to |\bnumdefinfix| it is needed to support also, perhaps, the other
+% levels 13, 15, 16, 18, ....  This will be done only if necessary and is the
+% reason why the macros |\BNE_defminus_a| and |\BNE_defminus_b| are given
+% permanent names. In fact it is now |\BNE_defbin_b| which will decide to invoke
+% or not the |\BNE_defminus_a|, and we activate it here only for the base
+% precedence 12.
+%
+% The |\XINT_global| are inexistent in upstream at |1.4f| as it does not
+% incorporate yet some analog to |\bnumdefinfix/\bnumdefpostfix|.
 %    \begin{macrocode}
-\def\BNE_tmpb #1#2#3#4#5%
+\def\BNE_defminus_b #1#2#3#4#5%
 {%
-    \def #1% \BNE_op_-<level>
+    \XINT_global\def #1% \BNE_op_-<level>
     {%
       \expandafter #2\romannumeral`&&@\expandafter#3%
       \romannumeral`&&@\BNE_getnext
     }%
-    \def #2##1##2##3% \BNE_exec_-<level>
+    \XINT_global\def #2##1##2##3% \BNE_exec_-<level>
     {%
       \expandafter ##1\expandafter ##2\expandafter
        {\expandafter{\romannumeral`&&@\BNE_Op_opp##3}}%
     }%
-    \def #3##1% \BNE_check-_-<level>
+    \XINT_global\def #3##1% \BNE_check-_-<level>
     {%
       \xint_UDsignfork
         ##1{\expandafter #4\romannumeral`&&@#1}%
@@ -1341,7 +1815,7 @@
           -{#4##1}%
       \krof
     }%
-    \def #4##1##2% \BNE_checkp_-<level>
+    \XINT_global\def #4##1##2% \BNE_checkp_-<level>
     {%
       \ifnum ##1>#5%
         \expandafter #4%
@@ -1351,9 +1825,9 @@
       \fi
     }%
 }%
-\def\BNE_tmpa #1%
+\def\BNE_defminus_a #1%
 {%
-\expandafter\BNE_tmpb
+    \expandafter\BNE_defminus_b
     \csname BNE_op_-#1\expandafter\endcsname
     \csname BNE_exec_-#1\expandafter\endcsname
     \csname BNE_check-_-#1\expandafter\endcsname
@@ -1360,33 +1834,53 @@
     \csname BNE_checkp_-#1\expandafter\endcsname
     \csname xint_c_#1\endcsname
 }%
-\BNE_tmpa {xii}%
-\BNE_tmpa {xiv}%
-\BNE_tmpa {xvi}%
-\BNE_tmpa {xviii}%
+\BNE_defminus_a {xii}%
 %    \end{macrocode}
 % \subsection{The infix operators.}
 % I could have at the |1.4| refactoring injected usage of |\expanded| here,
-% but kept in sync with upstream \xintexprname code.
+% but kept in sync with upstream \xintexprname code. Any \emph{x}-expandable
+% macro can easily be converted into an \emph{f}-expandable one using
+% |\expanded|, so this is no serious limitation.
 %
 % Macro names are somewhat bad and there is much risk of confusion in future
 % maintenance of |\BNE_Op_| prefix (used for |\BNE_Op_add| etc...; besides
 % this should have been |\BNE_Op_Add|) and |\BNE_op_| prefix (used for
-% {\catcode`+ 11 |\BNE_op_+|} etc...).
+% |\BNE_op_+| etc...).
+%
+% At |1.5| decision is made to anticipate the announced upstream change to let
+% the power operators be right associative, matching Python behaviour. This
+% change is simply implemented by hardcoding in |\BNE_checkp_<op>| the right
+% precedence which so far, for such operators, had been identical with the
+% left precedence (upstream has examples of direct coding without
+% formalization). In fact the right precedence existed already as argument to
+% |\BNE_defbin_b| as the precedence to assign to unary minus following |<op>|.
+%
+% Note1: although it is easy to change the left precedence at user level, the
+% right precedence is now more inaccessible. But on the other hand \bnumname
+% provides |\bnumdefinfix| so all is customizable at user level.
+%
+% Note2: Tacit multiplication is not really a separate operator, it is
+% the |*| with an elevated left precedence, which costs nothing to create and
+% this precedence is stored in chardef token |\BNE_prec_tacit|.
+%
+% Compared to upstream, we use here numbers as arguments to |\BNE_defbin_b|,
+% and convert to roman numerals internally, also the operator macro is passed
+% as a control sequence not as its name (and |#6| and |#7| are permuted in
+% |\BNE_defbin_c|).
 %    \begin{macrocode}
 \def\BNE_defbin_c #1#2#3#4#5#6#7%
 {%
-  \def #1##1% \BNE_op_<op>
+  \XINT_global\def #1##1% \BNE_op_<op>
   {%
     \expanded{\unexpanded{#2{##1}}\expandafter}%
     \romannumeral`&&@\expandafter#3\romannumeral`&&@\BNE_getnext
   }%
-  \def #2##1##2##3##4% \BNE_exec_<op>
+  \XINT_global\def #2##1##2##3##4% \BNE_exec_<op>
   {%
     \expandafter##2\expandafter##3\expandafter
-      {\expandafter{\romannumeral`&&@#6##1##4}}%
+      {\expandafter{\romannumeral`&&@#7##1##4}}%
   }%
-  \def #3##1% \BNE_check-_<op>
+  \XINT_global\def #3##1% \BNE_check-_<op>
   {%
     \xint_UDsignfork
       ##1{\expandafter#4\romannumeral`&&@#5}%
@@ -1393,9 +1887,9 @@
         -{#4##1}%
     \krof
   }%
-  \def #4##1##2% \BNE_checkp_<op>
+  \XINT_global\def #4##1##2% \BNE_checkp_<op>
   {%
-    \ifnum ##1>#7%
+    \ifnum ##1>#6%
       \expandafter#4%
       \romannumeral`&&@\csname BNE_op_##2\expandafter\endcsname
     \else 
@@ -1405,51 +1899,138 @@
 }%
 \def\BNE_defbin_b #1#2#3#4%
 {%
-  \expandafter\BNE_defbin_c
-  \csname BNE_op_#1\expandafter\endcsname
-  \csname BNE_exec_#1\expandafter\endcsname
-  \csname BNE_check-_#1\expandafter\endcsname
-  \csname BNE_checkp_#1\expandafter\endcsname
-  \csname BNE_op_-#3\expandafter\endcsname
-  \csname #4\expandafter\endcsname
-  \csname BNE_precedence_#1\endcsname
-  \expandafter
-  \let\csname BNE_precedence_#1\expandafter\endcsname
-      \csname xint_c_#2\endcsname
+    \expandafter\BNE_defbin_c
+    \csname BNE_op_#1\expandafter\endcsname
+    \csname BNE_exec_#1\expandafter\endcsname
+    \csname BNE_check-_#1\expandafter\endcsname
+    \csname BNE_checkp_#1\expandafter\endcsname
+    \csname BNE_op_-\romannumeral\ifnum#3>12 #3\else 12\fi
+            \expandafter\endcsname
+    \csname xint_c_\romannumeral#3\endcsname #4%
+  \XINT_global
+    \expandafter
+    \let\csname BNE_precedence_#1\expandafter\endcsname
+        \csname xint_c_\romannumeral#2\endcsname
+    \unless
+    \ifcsname BNE_exec_-\romannumeral\ifnum#3>12 #3\else 12\fi\endcsname
+%    \end{macrocode}
+% This will execute only for |#3>12| as |\BNE_exec_-xii| exists.
+%    \begin{macrocode}
+     \expandafter\BNE_defminus_a\expandafter{\romannumeral#3}%
+    \fi
 }%
-\BNE_defbin_b {//} {xiv}{xiv}{BNE_Op_div}%
-\BNE_defbin_b {/:} {xiv}{xiv}{BNE_Op_mod}%
-\BNE_defbin_b  +   {xii}{xii}{BNE_Op_add}%
-\BNE_defbin_b  -   {xii}{xii}{BNE_Op_sub}%
-\BNE_defbin_b  *   {xiv}{xiv}{BNE_Op_mul}%
-\BNE_defbin_b  /   {xiv}{xiv}{BNE_Op_divround}%
-\BNE_defbin_b  ^   {xviii}{xviii}{BNE_Op_pow}%
-\expandafter\def\csname BNE_itself_**\endcsname {^}%
+\BNE_defbin_b  +   {12} {12}  \BNE_Op_add
+\BNE_defbin_b  -   {12} {12}  \BNE_Op_sub
+\BNE_defbin_b  *   {14} {14}  \BNE_Op_mul
+\BNE_defbin_b  /   {14} {14}  \BNE_Op_divround
+\BNE_defbin_b {//} {14} {14}  \BNE_Op_div
+\BNE_defbin_b {/:} {14} {14}  \BNE_Op_mod
+\BNE_defbin_b  ^   {18} {17}  \BNE_Op_pow
+%    \end{macrocode}
+% At upstream, we can use shortcut
+% \centeredline{|\expandafter\def\csname BNE_itself_**\endcsname {^}|}
+% but it means then that any redefinition of |^| propagates to |**|, besides it
+% creates a special case which would need consideration by
+% |\BNE_dotheitselves|, or special restrictions to add to user documentation.
+% Better to simply handle |**| as a full operator.
+%    \begin{macrocode}
+\BNE_defbin_b {**} {18} {17}  \BNE_Op_pow
+\expandafter\def\csname BNE_itself_**\endcsname {**}%
 \expandafter\def\csname BNE_itself_//\endcsname {//}%
 \expandafter\def\csname BNE_itself_/:\endcsname {/:}%
-\expandafter\let\csname BNE_precedence_***\endcsname \xint_c_xvi
+\let\BNE_prec_tacit\xint_c_xvi
 %    \end{macrocode}
-% \subsection{! as postfix factorial operator}
-% This one uses |\expanded|.
+% \subsection{\csh{bnumdefinfix}: extending the syntax}\leavevmode
+% |#1| gives the operator characters, |#2| the associated macro, |#3| its
+% left-precedence and |#4| its right precedence (as integers).
+%
+% The "itself" definitions are done in such a way that unambiguous abbreviations
+% work; but in case of ambiguity the first defined operator is used.
+%
+% However, if for example operator |$a| was defined after |$ab|, then although
+% |$| will use |$ab| which was defined first, |$a| will use as expected the
+% second defined operator.
+%
+% The mismatch |\BNE_defminus_a| vs |\BNE_defbin_b| is inherited from
+% upstream, I keep it to simplify maintenance.
 %    \begin{macrocode}
-\catcode`! 11
-\let\BNE_precedence_! \xint_c_xx
-\def\BNE_op_! #1%
+\def\bnumdefinfix #1#2#3#4%
 {%
-    \expandafter\BNE_put_op_first
-    \expanded{{{\BNE_Op_fac#1}}\expandafter}\romannumeral`&&@\BNE_getop
+    \edef\BNE_tmpa{#1}%
+    \edef\BNE_tmpa{\xint_zapspaces_o\BNE_tmpa}%
+    \edef\BNE_tmpL{\the\numexpr#3\relax}%
+    \edef\BNE_tmpL{\ifnum\BNE_tmpL<4 4\else\ifnum\BNE_tmpL<23 \BNE_tmpL\else 22\fi\fi}%
+    \edef\BNE_tmpR{\the\numexpr#4\relax}%
+    \edef\BNE_tmpR{\ifnum\BNE_tmpR<4 4\else\ifnum\BNE_tmpR<23 \BNE_tmpR\else 22\fi\fi}%
+    \BNE_defbin_b \BNE_tmpa\BNE_tmpL\BNE_tmpR #2%
+    \expandafter\BNE_dotheitselves\BNE_tmpa\relax
+  \ifxintverbose
+    \PackageInfo{bnumexpr}{infix operator \BNE_tmpa\space
+    \ifxintglobaldefs globally \fi
+        does
+        \unexpanded{#2}\MessageBreak with precedences \BNE_tmpL, \BNE_tmpR;}%
+  \fi
 }%
+\def\BNE_dotheitselves#1#2%
+{%
+    \if#2\relax\expandafter\xint_gobble_ii
+    \else
+  \XINT_global
+      \expandafter\edef\csname BNE_itself_#1#2\endcsname{#1#2}%
+      \unless\ifcsname BNE_precedence_#1\endcsname
+  \XINT_global
+        \expandafter\edef\csname BNE_precedence_#1\endcsname
+                         {\csname BNE_precedence_\BNE_tmpa\endcsname}%
+  \XINT_global
+        \expandafter\odef\csname BNE_op_#1\endcsname
+                         {\csname BNE_op_\BNE_tmpa\endcsname}%
+      \fi
+    \fi
+    \BNE_dotheitselves{#1#2}%
+}%
 %    \end{macrocode}
-% \subsection{Cleanup}
+% \subsection{\csh{bnumdefpostfix}}
+% Support macros for postfix operators only need to be \emph{x}-expandable.
 %    \begin{macrocode}
-\let\BNEtmpa\relax \let\BNE_tmpa\relax \let\BNE_tmpb\relax \let\BNE_tmpc\relax
+\def\bnumdefpostfix #1#2#3%
+{%
+    \edef\BNE_tmpa{#1}%
+    \edef\BNE_tmpa{\xint_zapspaces_o\BNE_tmpa}%
+    \edef\BNE_tmpL{\the\numexpr#3\relax}%
+    \edef\BNE_tmpL{\ifnum\BNE_tmpL<4 4\else\ifnum\BNE_tmpL<23 \BNE_tmpL\else 22\fi\fi}%
+  \XINT_global
+    \expandafter\let\csname BNE_precedence_\BNE_tmpa\expandafter\endcsname
+                    \csname xint_c_\romannumeral\BNE_tmpL\endcsname
+  \XINT_global
+    \expandafter\def\csname BNE_op_\BNE_tmpa\endcsname ##1%
+    {%
+        \expandafter\BNE_put_op_first
+        \expanded{{{#2##1}}\expandafter}\romannumeral`&&@\BNE_getop
+    }%
+    \expandafter\BNE_dotheitselves\BNE_tmpa\relax
+  \ifxintverbose
+    \PackageInfo{bnumexpr}{postfix operator \BNE_tmpa\space
+    \ifxintglobaldefs globally \fi
+        does \unexpanded{#2}\MessageBreak
+        with precedence \BNE_tmpL;}%
+  \fi
+}%
+%    \end{macrocode}
+% \subsection{! as postfix factorial operator}\leavevmode
+%    \begin{macrocode}
+\bnumdefpostfix{!}{\BNE_Op_fac}{20}%
+%    \end{macrocode}
+% \subsection{Cleanup}\leavevmode
+%    \begin{macrocode}
+\let\BNEtmpa\relax
+\let\BNE_tmpa\relax \let\BNE_tmpb\relax \let\BNE_tmpc\relax
+\let\BNE_tmpR\relax \let\BNE_tmpL\relax
 \BNErestorecatcodes%
 %    \end{macrocode}
 % \MakePercentComment
 %</package>
 %<*dtx>
-\DeleteShortVerb{\|}%
-\CheckSum {947}%
+\CheckSum {1205}%
 \makeatletter\check at checksum\makeatother%
 \Finale%
 %% End of file xint.dtx

Modified: trunk/Master/texmf-dist/tex/latex/bnumexpr/bnumexpr.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/bnumexpr/bnumexpr.sty	2021-05-17 20:43:33 UTC (rev 59243)
+++ trunk/Master/texmf-dist/tex/latex/bnumexpr/bnumexpr.sty	2021-05-17 20:44:02 UTC (rev 59244)
@@ -25,35 +25,50 @@
 %% Copyright (C) 2014-2021 by Jean-Francois Burnol
 %%
 \NeedsTeXFormat{LaTeX2e}%
-\ProvidesPackage{bnumexpr}[2021/05/13 v1.4a Expressions with big integers (JFB)]%
+\ProvidesPackage{bnumexpr}[2021/05/17 v1.5 Expressions with big integers (JFB)]%
 \RequirePackage{xintbinhex}[2021/05/10]%
+\def\BNEtmpa {0}%
+\DeclareOption {custom}{\def\BNEtmpa {1}}%
+\ProcessOptions\relax
 {\catcode`! 3 \catcode`_ 11 %
-  \gdef\bnumexprsetup #1{\BNE_parsekeys #1,=!,}%
+  \gdef\bnumsetup #1{\BNE_parsekeys #1,=!,}%
   \gdef\BNE_parsekeys #1=#2#3,%
   {%
     \ifx!#2\expandafter\BNE_parsedone\fi
+  \XINT_global
     \expandafter
     \let\csname BNE_Op_\xint_zapspaces #1 \xint_gobble_i\endcsname%
-    =#2\BNE_parsekeys
+    =#2%
+  \ifxintverbose
+    \PackageInfo{bnumexpr}{assigned
+    \ifxintglobaldefs globally \fi
+     \string#2 to \xint_zapspaces #1 \xint_gobble_i\MessageBreak
+     \expandafter\xint_firstofone}%
+  \fi
+  \BNE_parsekeys
   }%
   \gdef\BNE_parsedone #1\BNE_parsekeys {}%
 }%
-\def\BNEtmpa {0}%
-\DeclareOption {custom}{\def\BNEtmpa {1}}%
-\ProcessOptions\relax
-\edef\BNErestorecatcodes{\XINTrestorecatcodes}%
-\XINTsetcatcodes%
-\if0\BNEtmpa\expandafter\xint_secondoftwo\fi
-\xint_gobble_i{%
+\let\bnumexprsetup\bnumsetup
+\if0\BNEtmpa\expandafter\@secondoftwo\fi
+\@gobble{%
     \RequirePackage{xintcore}[2021/05/10]%
-    \bnumexprsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul,
+    \bnumsetup{add=\xintiiAdd, sub=\xintiiSub, mul=\xintiiMul,
                    divround=\xintiiDivRound, div=\xintiiDivFloor,
                    mod=\xintiiMod, pow=\xintiiPow, fac=\xintiiFac,
                    opp=\xintiiOpp}%
 }%
+\edef\BNErestorecatcodes{\XINTrestorecatcodes}%
+\XINTsetcatcodes%
 \long\def\xint_firstofthree  #1#2#3{#1}%
 \long\def\xint_secondofthree #1#2#3{#2}%
 \long\def\xint_thirdofthree  #1#2#3{#3}%
+\chardef\xint_c_xi   11
+\chardef\xint_c_xiii 13
+\chardef\xint_c_xv   15
+\chardef\xint_c_xvii 17
+\chardef\xint_c_xix  19
+\chardef\xint_c_xxi  21
 \def\XINTfstop {\noexpand\XINTfstop}%
 \def\bnumexpr  {\romannumeral0\bnumexpro}%
 \def\bnumexpro {\expandafter\BNE_wrap\romannumeral0\bnebareeval }%
@@ -67,23 +82,26 @@
 \def\bnebareeval{\BNE_start}%
 \def\bnethe#1{\expanded\expandafter\xint_gobble_i\romannumeral`&&@#1}%
 \protected\def\BNEprint.#1{{\BNE_print#1.}}%
-\def\BNE_print#1{#1\expandafter\BNE_print_a\string}%
+\def\BNE_print#1{\bnumprintone{#1}\expandafter\BNE_print_a\string}%
 \def\BNE_print_a#1{\unless\if#1.\expandafter\BNE_print_b\fi}%
 \def\BNE_print_b
    {\expandafter\BNE_print_c\expandafter{\expandafter\xint_gobble_i\string}}%
-\def\BNE_print_c#1{, #1\expandafter\BNE_print_a\string}%
+\def\BNE_print_c#1{\bnumprintonesep\bnumprintone{#1}\expandafter\BNE_print_a\string}%
 \protected\def\BNEprinthex.#1{{\BNE_printhex#1.}}%
-\def\BNE_printhex#1{\xintDecToHex{#1}\expandafter\BNE_printhex_a\string}%
+\def\BNE_printhex#1{\bnumprintonetohex{#1}\expandafter\BNE_printhex_a\string}%
 \def\BNE_printhex_a#1{\unless\if#1.\expandafter\BNE_printhex_b\fi}%
 \def\BNE_printhex_b
    {\expandafter\BNE_printhex_c\expandafter{\expandafter\xint_gobble_i\string}}%
-\def\BNE_printhex_c#1{, \xintDecToHex{#1}\expandafter\BNE_printhex_a\string}%
+\def\BNE_printhex_c#1{\bnumprintonesep\bnumprintonetohex{#1}\expandafter\BNE_printhex_a\string}%
+\let\bnumprintone\xint_firstofone
+\let\bnumprintonetohex\xintDecToHex
+\def\bnumprintonesep{, }%
 \def\BNE_getnext #1%
 {%
     \expandafter\BNE_put_op_first\romannumeral`&&@%
     \expandafter\BNE_getnext_a\romannumeral`&&@#1%
 }%
-\def\BNE_put_op_first #1#2#3{\expandafter#2\expandafter#3\expandafter{#1}}%
+\def\BNE_put_op_first #1#2#3{#2#3{#1}}%
 \def\BNE_getnext_a #1%
 {%
     \ifx\relax #1\xint_dothis\BNE_foundprematureend\fi
@@ -131,7 +149,11 @@
     \ifnum \xint_c_ix<1\string#1 \xint_dothis \BNE_startint\fi
     \xint_orthat \BNE_notadigit #1%
 }%
-\def\BNE_notadigit#1{\BNE_getnext }%
+\def\BNE_notadigit#1%
+{%
+    \expandafter\BNE_scan_number
+    \romannumeral`&&@\XINT_expandableerror{Digit? (got `#1'). Hit I<RET><digit>}%
+}%
 \def\BNE_startint #1%
 {%
     \if #10\expandafter\BNE_gobz_a\else\expandafter\BNE_scanint_a\fi #1%
@@ -154,13 +176,13 @@
 }%
 \def\BNE_scanint_hit_cs \ifnum#1\fi#2\BNE_scanint_again
 {%
-    \iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#2%
+    \iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#2%
 }%
 \def\BNE_scanint_next #1\BNE_scanint_again
 {%
     \if    _#1\xint_dothis\BNE_scanint_again\fi
     \xint_orthat
-    {\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#1}%
+    {\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#1}%
 }%
 \def\BNE_gobz_scanint_main #1%
 {%
@@ -174,7 +196,7 @@
 }%
 \def\BNE_gobz_scanint_hit_cs\ifnum#1\fi#2\BNE_scanint_again
 {%
-    0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#2%
+    0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#2%
 }%
 \def\BNE_gobz_scanint_next #1\BNE_scanint_again
 {%
@@ -181,20 +203,49 @@
     \if    _#1\xint_dothis\BNE_gobz_scanint_again\fi
     \if    0#1\xint_dothis\BNE_gobz_scanint_again\fi
     \xint_orthat
-    {0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop#1}%
+    {0\iffalse{{{\fi}}\expandafter}\romannumeral`&&@\BNE_getop_a#1}%
 }%
 \def\BNE_hex_in #1.%
 {%
-    \expanded{{{\xintHexToDec{#1}}}\expandafter}\romannumeral`&&@\BNE_getop
+    \expanded{{{\bnumhextodec{#1}}}\expandafter}\romannumeral`&&@\BNE_getop
 }%
-\def\BNE_scanhex #1% #1="
+\let\bnumhextodec\xintHexToDec
+\def\BNE_scanhex #1#2% #1="
 {%
-    \expandafter\BNE_hex_in\expanded\bgroup\BNE_scanhex_a
+    \expandafter\BNE_hex_in\expanded\bgroup
+    \expandafter\BNE_scanhexgobz_a\romannumeral`&&@#2%
 }%
+\def\BNE_scanhexgobz_a #1%
+{%
+    \ifcat #1\relax0.\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi
+    \BNE_scanhexgobz_aa #1%
+}%
+\def\BNE_scanhexgobz_aa #1%
+{%
+    \if\ifnum`#1>`0
+       \ifnum`#1>`9
+       \ifnum`#1>`@
+       \ifnum`#1>`F
+       0\else1\fi\else0\fi\else1\fi\else0\fi 1%
+       \xint_dothis\BNE_scanhex_b
+    \fi
+    \if 0#1\xint_dothis\BNE_scanhexgobz_bgob\fi
+    \if _#1\xint_dothis\BNE_scanhexgobz_bgob\fi
+    \if .#1\xint_dothis\BNE_scanhexgobz_toII\fi
+    \xint_orthat
+     {\XINT_expandableerror
+        {HexDigit was expected but saw `#1'. Using 0, hit <RET>}%
+      0.>;\iffalse{\fi}}%
+    #1%
+}%
+\def\BNE_scanhexgobz_bgob #1#2%
+{%
+    \expandafter\BNE_scanhexgobz_a\romannumeral`&&@#2%
+}%
 \def\BNE_scanhex_a #1%
 {%
-    \ifcat #1\relax\xint_dothis{.\iffalse{\fi}#1}\fi
-    \xint_orthat {\BNE_scanhex_aa #1}%
+    \ifcat #1\relax.\iffalse{\fi\expandafter}\expandafter\xint_gobble_i\fi
+    \BNE_scanhex_aa #1%
 }%
 \def\BNE_scanhex_aa #1%
 {%
@@ -206,7 +257,7 @@
        \expandafter\BNE_scanhex_b
     \else
        \if _#1\xint_dothis{\expandafter\BNE_scanhex_bgob}\fi
-       \xint_orthat {\xint_afterfi {.\iffalse{\fi}}}%
+       \xint_orthat {.\iffalse{\fi\expandafter}}%
     \fi
     #1%
 }%
@@ -230,12 +281,12 @@
     \ifnum\xint_c_ix<1\string#1 \xint_dothis\xint_secondofthree\fi
     \if    (#1\xint_dothis      \xint_secondofthree\fi %)
     \xint_orthat \xint_thirdofthree
-    {\BNE_foundend}%
-    {\BNE_precedence_*** *#1}%
-    {\expandafter\BNE_scanop_a \string#1}%
+    \xint_c_
+    {\BNE_prec_tacit *}%
+    \BNE_scanop_a
+    #1%
 }%
 \catcode`* 12
-\def\BNE_foundend {\xint_c_ \relax}%
 \def\BNE_scanop_a #1#2%
 {%
     \expandafter\BNE_scanop_b\expandafter#1\romannumeral`&&@#2%
@@ -242,23 +293,25 @@
 }%
 \def\BNE_scanop_b #1#2%
 {%
-    \ifcat#2\relax\xint_dothis{\BNE_foundop_a #1#2}\fi
-    \ifcsname BNE_itself_#1#2\endcsname
-    \xint_dothis
-        {\expandafter\BNE_scanop_c\csname BNE_itself_#1#2\endcsname}\fi
-    \xint_orthat {\BNE_foundop_a #1#2}%
+    \unless\ifcat#2\relax
+           \ifcsname BNE_itself_#1#2\endcsname
+           \BNE_scanop_c
+    \fi\fi
+    \BNE_foundop_a #1#2%
 }%
-\def\BNE_scanop_c #1#2%
+\def\BNE_scanop_c #1#2#3#4#5% #1#2=\fi\fi
 {%
-    \expandafter\BNE_scanop_d\expandafter#1\romannumeral`&&@#2%
+    #1#2%
+    \expandafter\BNE_scanop_d\csname BNE_itself_#4#5\expandafter\endcsname
+    \romannumeral`&&@%
 }%
 \def\BNE_scanop_d #1#2%
 {%
-  \ifcat#2\relax \xint_dothis{\BNE_foundop #1#2}\fi
-  \ifcsname BNE_itself_#1#2\endcsname
-  \xint_dothis
-        {\expandafter\BNE_scanop_c\csname BNE_itself_#1#2\endcsname }\fi
-  \xint_orthat {\csname BNE_precedence_#1\endcsname #1#2}%
+    \unless\ifcat#2\relax
+           \ifcsname BNE_itself_#1#2\endcsname
+           \BNE_scanop_c
+    \fi\fi
+    \BNE_foundop #1#2%
 }%
 \def\BNE_foundop_a #1%
 {%
@@ -266,10 +319,10 @@
         \csname BNE_precedence_#1\expandafter\endcsname
         \expandafter #1%
     \else
-        \xint_afterfi{\BNE_getop\romannumeral0%
-        \XINT_expandableerror
-        {"#1" is unknown as operator. (I)nsert one:} }%<<deliberate space
-    \fi
+        \expandafter\BNE_getop_a\romannumeral`&&@%
+        \xint_afterfi{\XINT_expandableerror
+        {Operator? (got `#1'). Hit I<RET><operator>}}%
+     \fi
 }%
 \def\BNE_foundop #1{\csname BNE_precedence_#1\endcsname #1}%
 \def\BNE_tmpa #1#2#3#4#5%
@@ -297,7 +350,7 @@
     \def#5%
     {%
         \XINT_expandableerror
-        {An extra ) has been removed. Hit Return, fingers crossed.}%
+        {An extra ) has been removed. Hit <RET>, fingers crossed.}%
         \expandafter#2\romannumeral`&&@\expandafter\BNE_put_op_first
         \romannumeral`&&@\BNE_getop_legacy
     }%
@@ -353,7 +406,7 @@
     \csname BNE_op_-xii\endcsname
 \let\BNE_precedence_)\xint_c_i
 \def\BNE_missing_)
-   {\XINT_expandableerror{Sorry to report a missing ) at the end of this journey.}%
+   {\XINT_expandableerror{Missing ). Hit <RET> to proceed}%
     \xint_c_ \BNE_done }%
 \catcode`) 12
 \def\BNE_tmpa #1#2#3#4#5%
@@ -388,19 +441,19 @@
     \csname BNE_checkp_,\expandafter\endcsname
     \csname BNE_op_-xii\endcsname
 \expandafter\let\csname BNE_precedence_,\endcsname\xint_c_iii
-\def\BNE_tmpb #1#2#3#4#5%
+\def\BNE_defminus_b #1#2#3#4#5%
 {%
-    \def #1% \BNE_op_-<level>
+    \XINT_global\def #1% \BNE_op_-<level>
     {%
       \expandafter #2\romannumeral`&&@\expandafter#3%
       \romannumeral`&&@\BNE_getnext
     }%
-    \def #2##1##2##3% \BNE_exec_-<level>
+    \XINT_global\def #2##1##2##3% \BNE_exec_-<level>
     {%
       \expandafter ##1\expandafter ##2\expandafter
        {\expandafter{\romannumeral`&&@\BNE_Op_opp##3}}%
     }%
-    \def #3##1% \BNE_check-_-<level>
+    \XINT_global\def #3##1% \BNE_check-_-<level>
     {%
       \xint_UDsignfork
         ##1{\expandafter #4\romannumeral`&&@#1}%
@@ -407,7 +460,7 @@
           -{#4##1}%
       \krof
     }%
-    \def #4##1##2% \BNE_checkp_-<level>
+    \XINT_global\def #4##1##2% \BNE_checkp_-<level>
     {%
       \ifnum ##1>#5%
         \expandafter #4%
@@ -417,9 +470,9 @@
       \fi
     }%
 }%
-\def\BNE_tmpa #1%
+\def\BNE_defminus_a #1%
 {%
-\expandafter\BNE_tmpb
+    \expandafter\BNE_defminus_b
     \csname BNE_op_-#1\expandafter\endcsname
     \csname BNE_exec_-#1\expandafter\endcsname
     \csname BNE_check-_-#1\expandafter\endcsname
@@ -426,23 +479,20 @@
     \csname BNE_checkp_-#1\expandafter\endcsname
     \csname xint_c_#1\endcsname
 }%
-\BNE_tmpa {xii}%
-\BNE_tmpa {xiv}%
-\BNE_tmpa {xvi}%
-\BNE_tmpa {xviii}%
+\BNE_defminus_a {xii}%
 \def\BNE_defbin_c #1#2#3#4#5#6#7%
 {%
-  \def #1##1% \BNE_op_<op>
+  \XINT_global\def #1##1% \BNE_op_<op>
   {%
     \expanded{\unexpanded{#2{##1}}\expandafter}%
     \romannumeral`&&@\expandafter#3\romannumeral`&&@\BNE_getnext
   }%
-  \def #2##1##2##3##4% \BNE_exec_<op>
+  \XINT_global\def #2##1##2##3##4% \BNE_exec_<op>
   {%
     \expandafter##2\expandafter##3\expandafter
-      {\expandafter{\romannumeral`&&@#6##1##4}}%
+      {\expandafter{\romannumeral`&&@#7##1##4}}%
   }%
-  \def #3##1% \BNE_check-_<op>
+  \XINT_global\def #3##1% \BNE_check-_<op>
   {%
     \xint_UDsignfork
       ##1{\expandafter#4\romannumeral`&&@#5}%
@@ -449,9 +499,9 @@
         -{#4##1}%
     \krof
   }%
-  \def #4##1##2% \BNE_checkp_<op>
+  \XINT_global\def #4##1##2% \BNE_checkp_<op>
   {%
-    \ifnum ##1>#7%
+    \ifnum ##1>#6%
       \expandafter#4%
       \romannumeral`&&@\csname BNE_op_##2\expandafter\endcsname
     \else
@@ -461,37 +511,96 @@
 }%
 \def\BNE_defbin_b #1#2#3#4%
 {%
-  \expandafter\BNE_defbin_c
-  \csname BNE_op_#1\expandafter\endcsname
-  \csname BNE_exec_#1\expandafter\endcsname
-  \csname BNE_check-_#1\expandafter\endcsname
-  \csname BNE_checkp_#1\expandafter\endcsname
-  \csname BNE_op_-#3\expandafter\endcsname
-  \csname #4\expandafter\endcsname
-  \csname BNE_precedence_#1\endcsname
-  \expandafter
-  \let\csname BNE_precedence_#1\expandafter\endcsname
-      \csname xint_c_#2\endcsname
+    \expandafter\BNE_defbin_c
+    \csname BNE_op_#1\expandafter\endcsname
+    \csname BNE_exec_#1\expandafter\endcsname
+    \csname BNE_check-_#1\expandafter\endcsname
+    \csname BNE_checkp_#1\expandafter\endcsname
+    \csname BNE_op_-\romannumeral\ifnum#3>12 #3\else 12\fi
+            \expandafter\endcsname
+    \csname xint_c_\romannumeral#3\endcsname #4%
+  \XINT_global
+    \expandafter
+    \let\csname BNE_precedence_#1\expandafter\endcsname
+        \csname xint_c_\romannumeral#2\endcsname
+    \unless
+    \ifcsname BNE_exec_-\romannumeral\ifnum#3>12 #3\else 12\fi\endcsname
+     \expandafter\BNE_defminus_a\expandafter{\romannumeral#3}%
+    \fi
 }%
-\BNE_defbin_b {//} {xiv}{xiv}{BNE_Op_div}%
-\BNE_defbin_b {/:} {xiv}{xiv}{BNE_Op_mod}%
-\BNE_defbin_b  +   {xii}{xii}{BNE_Op_add}%
-\BNE_defbin_b  -   {xii}{xii}{BNE_Op_sub}%
-\BNE_defbin_b  *   {xiv}{xiv}{BNE_Op_mul}%
-\BNE_defbin_b  /   {xiv}{xiv}{BNE_Op_divround}%
-\BNE_defbin_b  ^   {xviii}{xviii}{BNE_Op_pow}%
-\expandafter\def\csname BNE_itself_**\endcsname {^}%
+\BNE_defbin_b  +   {12} {12}  \BNE_Op_add
+\BNE_defbin_b  -   {12} {12}  \BNE_Op_sub
+\BNE_defbin_b  *   {14} {14}  \BNE_Op_mul
+\BNE_defbin_b  /   {14} {14}  \BNE_Op_divround
+\BNE_defbin_b {//} {14} {14}  \BNE_Op_div
+\BNE_defbin_b {/:} {14} {14}  \BNE_Op_mod
+\BNE_defbin_b  ^   {18} {17}  \BNE_Op_pow
+\BNE_defbin_b {**} {18} {17}  \BNE_Op_pow
+\expandafter\def\csname BNE_itself_**\endcsname {**}%
 \expandafter\def\csname BNE_itself_//\endcsname {//}%
 \expandafter\def\csname BNE_itself_/:\endcsname {/:}%
-\expandafter\let\csname BNE_precedence_***\endcsname \xint_c_xvi
-\catcode`! 11
-\let\BNE_precedence_! \xint_c_xx
-\def\BNE_op_! #1%
+\let\BNE_prec_tacit\xint_c_xvi
+\def\bnumdefinfix #1#2#3#4%
 {%
-    \expandafter\BNE_put_op_first
-    \expanded{{{\BNE_Op_fac#1}}\expandafter}\romannumeral`&&@\BNE_getop
+    \edef\BNE_tmpa{#1}%
+    \edef\BNE_tmpa{\xint_zapspaces_o\BNE_tmpa}%
+    \edef\BNE_tmpL{\the\numexpr#3\relax}%
+    \edef\BNE_tmpL{\ifnum\BNE_tmpL<4 4\else\ifnum\BNE_tmpL<23 \BNE_tmpL\else 22\fi\fi}%
+    \edef\BNE_tmpR{\the\numexpr#4\relax}%
+    \edef\BNE_tmpR{\ifnum\BNE_tmpR<4 4\else\ifnum\BNE_tmpR<23 \BNE_tmpR\else 22\fi\fi}%
+    \BNE_defbin_b \BNE_tmpa\BNE_tmpL\BNE_tmpR #2%
+    \expandafter\BNE_dotheitselves\BNE_tmpa\relax
+  \ifxintverbose
+    \PackageInfo{bnumexpr}{infix operator \BNE_tmpa\space
+    \ifxintglobaldefs globally \fi
+        does
+        \unexpanded{#2}\MessageBreak with precedences \BNE_tmpL, \BNE_tmpR;}%
+  \fi
 }%
-\let\BNEtmpa\relax \let\BNE_tmpa\relax \let\BNE_tmpb\relax \let\BNE_tmpc\relax
+\def\BNE_dotheitselves#1#2%
+{%
+    \if#2\relax\expandafter\xint_gobble_ii
+    \else
+  \XINT_global
+      \expandafter\edef\csname BNE_itself_#1#2\endcsname{#1#2}%
+      \unless\ifcsname BNE_precedence_#1\endcsname
+  \XINT_global
+        \expandafter\edef\csname BNE_precedence_#1\endcsname
+                         {\csname BNE_precedence_\BNE_tmpa\endcsname}%
+  \XINT_global
+        \expandafter\odef\csname BNE_op_#1\endcsname
+                         {\csname BNE_op_\BNE_tmpa\endcsname}%
+      \fi
+    \fi
+    \BNE_dotheitselves{#1#2}%
+}%
+\def\bnumdefpostfix #1#2#3%
+{%
+    \edef\BNE_tmpa{#1}%
+    \edef\BNE_tmpa{\xint_zapspaces_o\BNE_tmpa}%
+    \edef\BNE_tmpL{\the\numexpr#3\relax}%
+    \edef\BNE_tmpL{\ifnum\BNE_tmpL<4 4\else\ifnum\BNE_tmpL<23 \BNE_tmpL\else 22\fi\fi}%
+  \XINT_global
+    \expandafter\let\csname BNE_precedence_\BNE_tmpa\expandafter\endcsname
+                    \csname xint_c_\romannumeral\BNE_tmpL\endcsname
+  \XINT_global
+    \expandafter\def\csname BNE_op_\BNE_tmpa\endcsname ##1%
+    {%
+        \expandafter\BNE_put_op_first
+        \expanded{{{#2##1}}\expandafter}\romannumeral`&&@\BNE_getop
+    }%
+    \expandafter\BNE_dotheitselves\BNE_tmpa\relax
+  \ifxintverbose
+    \PackageInfo{bnumexpr}{postfix operator \BNE_tmpa\space
+    \ifxintglobaldefs globally \fi
+        does \unexpanded{#2}\MessageBreak
+        with precedence \BNE_tmpL;}%
+  \fi
+}%
+\bnumdefpostfix{!}{\BNE_Op_fac}{20}%
+\let\BNEtmpa\relax
+\let\BNE_tmpa\relax \let\BNE_tmpb\relax \let\BNE_tmpc\relax
+\let\BNE_tmpR\relax \let\BNE_tmpL\relax
 \BNErestorecatcodes%
 \endinput
 %%



More information about the tex-live-commits mailing list.