diff options
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3fp-parse.dtx')
-rw-r--r-- | macros/latex/contrib/l3kernel/l3fp-parse.dtx | 2899 |
1 files changed, 0 insertions, 2899 deletions
diff --git a/macros/latex/contrib/l3kernel/l3fp-parse.dtx b/macros/latex/contrib/l3kernel/l3fp-parse.dtx deleted file mode 100644 index 53b85a7cc8..0000000000 --- a/macros/latex/contrib/l3kernel/l3fp-parse.dtx +++ /dev/null @@ -1,2899 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3fp-parse.dtx -% -% Copyright (C) 2011-2024 The LaTeX Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -%</driver> -% \fi -% -% \title{^^A -% The \pkg{l3fp-parse} module\\ -% Floating point expression parsing^^A -% } -% \author{^^A -% The \LaTeX{} Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% \date{Released 2024-03-14} -% -% \maketitle -% -% \begin{documentation} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3fp-parse} implementation} -% -% \begin{macrocode} -%<*package> -% \end{macrocode} -% -% \begin{macrocode} -%<@@=fp> -% \end{macrocode} -% -% \subsection{Work plan} -% -% The task at hand is non-trivial, and some previous failed attempts -% show that the code leads to unreadable logs, so we had better get it -% (almost) right the first time. Let us first describe our goal, then -% discuss the design precisely before writing any code. -% -% In this file at least, a \meta{floating point object} is a floating -% point number or tuple. This can be extended to anything that starts -% with \cs{s_@@} or \cs{s_@@_\meta{type}} and ends with |;| with some -% internal structure that depends on the \meta{type}. -% -% \begin{macro}[EXP]{\@@_parse:n} -% \begin{syntax} -% \cs{@@_parse:n} \Arg{fp expr} -% \end{syntax} -% Evaluates the \meta{fp expr} and leaves the result -% in the input stream as a floating point object. This -% function forms the basis of almost all public \pkg{l3fp} functions. -% During evaluation, each token is fully \texttt{f}-expanded. -% -% \cs{@@_parse_o:n} does the same but expands once after its result. -% \begin{texnote} -% Registers (integers, toks, etc.) are automatically unpacked, -% without requiring a function such as \cs{int_use:N}. Invalid -% tokens remaining after \texttt{f}-expansion lead to -% unrecoverable low-level \TeX{} errors. -% \end{texnote} -% \end{macro} -% -% \begin{variable} -% { -% \c_@@_prec_func_int, -% \c_@@_prec_hatii_int, -% \c_@@_prec_hat_int, -% \c_@@_prec_not_int, -% \c_@@_prec_juxt_int, -% \c_@@_prec_times_int, -% \c_@@_prec_plus_int, -% \c_@@_prec_comp_int, -% \c_@@_prec_and_int, -% \c_@@_prec_or_int, -% \c_@@_prec_quest_int, -% \c_@@_prec_colon_int, -% \c_@@_prec_comma_int, -% \c_@@_prec_tuple_int, -% \c_@@_prec_end_int, -% } -% Floating point expressions are composed of numbers, given in various -% forms, infix operators, such as |+|, |**|, or~|,| (which joins two -% numbers into a list), and prefix operators, such as the unary~|-|, -% functions, or opening parentheses. Here is a list of precedences -% which control the order of evaluation (some distinctions are -% irrelevant for the order of evaluation, but serve as signals), from -% the tightest binding to the loosest binding. -% \begin{itemize} -% \item[16] Function calls. -% \item[13/14] Binary |**| and~|^| (right to left). -% \item[12] Unary |+|, |-|, |!| (right to left). -% \item[11] Juxtaposition (implicit~|*|) with no parenthesis. -% \item[10] Binary |*| and~|/|. -% \item[9] Binary |+| and~|-|. -% \item[7] Comparisons. -% \item[6] Logical \texttt{and}, denoted by~|&&|. -% \item[5] Logical \texttt{or}, denoted by~\verb*+||+. -% \item[4] Ternary operator |?:|, piece~|?|. -% \item[3] Ternary operator |?:|, piece~|:|. -% \item[2] Commas. -% \item[1] Place where a comma is allowed and generates a tuple. -% \item[0] Start and end of the expression. -% \end{itemize} -% \begin{macrocode} -\int_const:Nn \c_@@_prec_func_int { 16 } -\int_const:Nn \c_@@_prec_hatii_int { 14 } -\int_const:Nn \c_@@_prec_hat_int { 13 } -\int_const:Nn \c_@@_prec_not_int { 12 } -\int_const:Nn \c_@@_prec_juxt_int { 11 } -\int_const:Nn \c_@@_prec_times_int { 10 } -\int_const:Nn \c_@@_prec_plus_int { 9 } -\int_const:Nn \c_@@_prec_comp_int { 7 } -\int_const:Nn \c_@@_prec_and_int { 6 } -\int_const:Nn \c_@@_prec_or_int { 5 } -\int_const:Nn \c_@@_prec_quest_int { 4 } -\int_const:Nn \c_@@_prec_colon_int { 3 } -\int_const:Nn \c_@@_prec_comma_int { 2 } -\int_const:Nn \c_@@_prec_tuple_int { 1 } -\int_const:Nn \c_@@_prec_end_int { 0 } -% \end{macrocode} -% \end{variable} -% -% \subsubsection{Storing results} -% -% The main question in parsing expressions expandably is to decide where -% to put the intermediate results computed for various subexpressions. -% -% One option is to store the values at the start of the expression, and -% carry them together as the first argument of each macro. However, we -% want to \texttt{f}-expand tokens one by one in the expression (as -% \cs{int_eval:n} does), and with this approach, expanding the next -% unread token forces us to jump with \cs{exp_after:wN} over every value -% computed earlier in the expression. With this approach, the run-time -% grows at least quadratically in the length of the expression, if -% not as its cube (inserting the \cs{exp_after:wN} is tricky and slow). -% -% A second option is to place those values at the end of the expression. -% Then expanding the next unread token is straightforward, but this -% still hits a performance issue: for long expressions we would be -% reaching all the way to the end of the expression at every step of the -% calculation. The run-time is again quadratic. -% -% A variation of the above attempts to place the intermediate results -% which appear when computing a parenthesized expression near the -% closing parenthesis. This still lets us expand tokens as we go, and -% avoids performance problems as long as there are enough parentheses. -% However, it would be better to avoid requiring the closing -% parenthesis to be present as soon as the corresponding opening -% parenthesis is read: the closing parenthesis may still be hidden in a -% macro yet to be expanded. -% -% Hence, we need to go for some fine expansion control: the result is -% stored \emph{before} the start! -% -% Let us illustrate this idea in a simple model: adding positive -% integers which may be resulting from the expansion of macros, or may -% be values of registers. Assume that one number, say, $12345$, has -% already been found, and that we want to parse the next number. The -% current status of the code may look as follows. -% \begin{syntax} -% \cs{exp_after:wN} |\add:ww| \cs{int_value:w} 12345 \cs{exp_after:wN} ; -% \cs{exp:w} |\operand:w| \meta{stuff} -% \end{syntax} -% One step of expansion expands \cs{exp_after:wN}, which triggers the -% primitive \cs{int_value:w}, which reads the five digits we have -% already found, |12345|. This integer is unfinished, causing the -% second \cs{exp_after:wN} to expand, and to trigger the construction -% \cs{exp:w}, which expands |\operand:w|, defined to read -% what follows and make a number out of it, then leave \cs{exp_end:}, the -% number, and a semicolon in the input stream. Once |\operand:w| is -% done expanding, we obtain essentially -% \begin{syntax} -% \cs{exp_after:wN} |\add:ww| \cs{int_value:w} 12345 ; -% \cs{exp:w} \cs{exp_end:} 333444 ; -% \end{syntax} -% where in fact \cs{exp_after:wN} has already been expanded, -% \cs{int_value:w} has already seen |12345|, and -% \cs{exp:w} is still looking for a number. It finds -% \cs{exp_end:}, hence expands to nothing. Now, \cs{int_value:w} sees -% the \texttt{;}, which cannot be part of a number. The expansion -% stops, and we are left with -% \begin{syntax} -% |\add:ww| 12345 ; 333444 ; -% \end{syntax} -% which can safely perform the addition by grabbing two arguments -% delimited by~|;|. -% -% If we were to continue parsing the expression, then the following -% number should also be cleaned up before the next use of a binary -% operation such as |\add:ww|. Just like \cs{int_value:w} |12345| -% \cs{exp_after:wN}~|;| expanded what follows once, we need |\add:ww| -% to do the calculation, and in the process to expand the following -% once. This is also true in our real application: all the functions of -% the form \cs[no-index]{@@_\ldots_o:ww} expand what follows once. This comes at the -% cost of leaving tokens in the input stack, and we need to be -% careful not to waste this memory. All of our discussion above is nice -% but simplistic, as operations should not simply be performed in the -% order they appear. -% -% \subsubsection{Precedence and infix operators} -% -% The various operators we will encounter have different precedences, -% which influence the order of calculations: $1+2\times 3 = 1+(2\times -% 3)$ because $\times$~has a higher precedence than~$+$. The true -% analog of our macro |\operand:w| must thus take care of that. When -% looking for an operand, it needs to perform calculations until -% reaching an operator which has lower precedence than the one which -% called |\operand:w|. This means that |\operand:w| must know what the -% previous binary operator is, or rather, its precedence: we thus rename -% it |\operand:Nw|. Let us describe as an example how we plan to do -% the calculation |41-2^3*4+5|. More precisely we describe how to -% perform the first operation in this expression. Here, we abuse -% notations: the first argument of |\operand:Nw| should be an integer -% constant (\cs{c_@@_prec_plus_int}, \ldots{}) equal to the precedence -% of the given operator, not directly the operator itself. -% \begin{itemize} -% \item Clean up~|41| and find~|-|. We call |\operand:Nw|~|-| to find -% the second operand. -% \item Clean up~|2| and find~|^|. -% \item Compare the precedences of |-| and~|^|. Since the latter is -% higher, we need to compute the exponentiation. For this, find the -% second operand with a nested call to |\operand:Nw|~|^|. -% \item Clean up~|3| and find~|*|. -% \item Compare the precedences of |^| and~|*|. Since the former is -% higher, |\operand:Nw|~|^| has found the second operand of the -% exponentiation, which is computed: $2^{3} = 8$. -% \item We now have |41-8*4+5|, and |\operand:Nw|~|-| is still -% looking for a second operand for the subtraction. Is it~$8$? -% \item Compare the precedences of |-| and~|*|. Since the latter is -% higher, we are not done with~$8$. Call |\operand:Nw|~|*| to find -% the second operand of the multiplication. -% \item Clean up~|4|, and find~|+|. -% \item Compare the precedences of |*| and~|+|. Since the former is -% higher, |\operand:Nw|~|*| has found the second operand of the -% multiplication, which is computed: $8*4 = 32$. -% \item We now have |41-32+5|, and |\operand:Nw|~|-| is still looking -% for a second operand for the subtraction. Is it~$32$? -% \item Compare the precedences of |-| and~|+|. Since they are equal, -% |\operand:Nw|~|-| has found the second operand for the -% subtraction, which is computed: $41-32=9$. -% \item We now have |9+5|. -% \end{itemize} -% The procedure above stops short of performing all computations, but -% adding a surrounding call to |\operand:Nw| with a very low precedence -% ensures that all computations are performed before |\operand:Nw| -% is done. Adding a trailing marker with the same very low precedence -% prevents the surrounding |\operand:Nw| from going beyond the marker. -% -% The pattern above to find an operand for a given operator, is to find -% one number and the next operator, then compare precedences to know if -% the next computation should be done. If it should, then perform it -% after finding its second operand, and look at the next operator, then -% compare precedences to know if the next computation should be done. -% This continues until we find that the next computation should not be -% done. Then, we stop. -% -% We are now ready to get a bit more technical and describe which of the -% \pkg{l3fp-parse} functions correspond to each step above. -% -% First, \cs{@@_parse_operand:Nw} is the |\operand:Nw| function above, -% with small modifications due to expansion issues discussed later. We -% denote by \meta{precedence} the argument of \cs{@@_parse_operand:Nw}, -% that is, the precedence of the binary operator whose operand we are -% trying to find. The basic action is to read numbers from the input -% stream. This is done by \cs{@@_parse_one:Nw}. A first approximation -% of this function is that it reads one \meta{number}, performing no -% computation, and finds the following binary \meta{operator}. Then it -% expands to -% \begin{quote} -% \meta{number}\\ -% | \__fp_parse_infix_|\meta{operator}|:N| \meta{precedence} -% \end{quote} -% expanding the \texttt{infix} auxiliary before leaving the above in the -% input stream. -% -% We now explain the \texttt{infix} auxiliaries. We need some -% flexibility in how we treat the case of equal precedences: most often, -% the first operation encountered should be performed, such as |1-2-3| -% being computed as |(1-2)-3|, but |2^3^4| should be evaluated as -% |2^(3^4)| instead. For this reason, and to support the equivalence -% between |**| and~|^| more easily, each binary operator is converted to -% a control sequence |\__fp_parse_infix_|\meta{operator}|:N| when it is -% encountered for the first time. Instead of passing both precedences -% to a test function to do the comparison steps above, we pass the -% \meta{precedence} (of the earlier operator) to the \texttt{infix} -% auxiliary for the following \meta{operator}, to know whether to -% perform the computation of the \meta{operator}. If it should not be -% performed, the \texttt{infix} auxiliary expands to -% \begin{syntax} -% |@| \cs{use_none:n} |\__fp_parse_infix_|\meta{operator}|:N| -% \end{syntax} -% and otherwise it calls \cs{@@_parse_operand:Nw} with the precedence of -% the \meta{operator} to find its second operand \meta{number_2} and the -% next \meta{operator_2}, and expands to -% \begin{syntax} -% |@| \cs{@@_parse_apply_binary:NwNwN} -% ~~~~\meta{operator} \meta{number_2} -% |@| |\__fp_parse_infix_|\meta{operator_2}|:N| -% \end{syntax} -% The \texttt{infix} function is responsible for comparing precedences, -% but cannot directly call the computation functions, because the first -% operand \meta{number} is before the \texttt{infix} function in the -% input stream. This is why we stop the expansion here and give control -% to another function to close the loop. -% -% A definition of \cs{@@_parse_operand:Nw} \meta{precedence} with some -% of the expansion control removed is -% \begin{syntax} -% \cs{exp_after:wN} \cs{@@_parse_continue:NwN} -% \cs{exp_after:wN} \meta{precedence} -% \cs{exp:w} \cs{exp_end_continue_f:w} -% ~~\cs{@@_parse_one:Nw} \meta{precedence} -% \end{syntax} -% This expands \cs{@@_parse_one:Nw} \meta{precedence} completely, which -% finds a number, wraps the next \meta{operator} into an \texttt{infix} -% function, feeds this function the \meta{precedence}, and expands it, -% yielding either -% \begin{syntax} -% \cs{@@_parse_continue:NwN} \meta{precedence} -% \meta{number} |@| -% \cs{use_none:n} |\__fp_parse_infix_|\meta{operator}|:N| -% \end{syntax} -% or -% \begin{syntax} -% \cs{@@_parse_continue:NwN} \meta{precedence} -% \meta{number} |@| -% \cs{@@_parse_apply_binary:NwNwN} -% ~~\meta{operator} \meta{number_2} -% |@| |\__fp_parse_infix_|\meta{operator_2}|:N| -% \end{syntax} -% The definition of \cs{@@_parse_continue:NwN} is then very simple: -% \begin{syntax} -% |\cs_new:Npn \__fp_parse_continue:NwN #1#2@#3 { #3 #1 #2 @ }| -% \end{syntax} -% In the first case, |#3|~is \cs{use_none:n}, yielding -% \begin{syntax} -% \cs{use_none:n} \meta{precedence} \meta{number} |@| -% |\__fp_parse_infix_|\meta{operator}|:N| -% \end{syntax} -% then \meta{number} |@| |\__fp_parse_infix_|\meta{operator}|:N|. In -% the second case, |#3|~is \cs{@@_parse_apply_binary:NwNwN}, whose role -% is to compute \meta{number} \meta{operator} \meta{number_2} and to -% prepare for the next comparison of precedences: first we get -% \begin{syntax} -% \cs{@@_parse_apply_binary:NwNwN} -% ~~\meta{precedence} \meta{number} |@| -% ~~\meta{operator} \meta{number_2} -% |@| |\__fp_parse_infix_|\meta{operator_2}|:N| -% \end{syntax} -% then -% \begin{syntax} -% \cs{exp_after:wN} \cs{@@_parse_continue:NwN} -% \cs{exp_after:wN} \meta{precedence} -% \cs{exp:w} \cs{exp_end_continue_f:w} -% |\__fp_|\meta{operator}|_o:ww| \meta{number} \meta{number_2} -% \cs{exp:w} \cs{exp_end_continue_f:w} -% |\__fp_parse_infix_|\meta{operator_2}|:N| \meta{precedence} -% \end{syntax} -% where |\__fp_|\meta{operator}|_o:ww| computes \meta{number} -% \meta{operator} \meta{number_2} and expands after the result, thus -% triggers the comparison of the precedence of the \meta{operator_2} and -% the \meta{precedence}, continuing the loop. -% -% We have introduced the most important functions here, and the next few -% paragraphs we describe various subtleties. -% -% \subsubsection{Prefix operators, parentheses, and functions} -% -% Prefix operators (unary |-|, |+|,~|!|) and parentheses are taken care -% of by the same mechanism, and functions (\texttt{sin}, \texttt{exp}, -% etc.) as well. Finding the argument of the unary~|-|, for instance, -% is very similar to grabbing the second operand of a binary infix -% operator, with a subtle precedence explained below. Once that operand -% is found, the operator can be applied to it (for the unary~|-|, this -% simply flips the sign). A left parenthesis is just a prefix operator -% with a very low precedence equal to that of the closing parenthesis -% (which is treated as an infix operator, since it normally appears just -% after numbers), so that all computations are performed until the -% closing parenthesis. The prefix operator associated to the left -% parenthesis does not alter its argument, but it removes the closing -% parenthesis (with some checks). -% -% Prefix operators are the reason why we only summarily described the -% function \cs{@@_parse_one:Nw} earlier. This function is responsible -% for reading in the input stream the first possible \meta{number} and -% the next infix \meta{operator}. If what follows \cs{@@_parse_one:Nw} -% \meta{precedence} is a prefix operator, then we must find the operand -% of this prefix operator through a nested call to -% \cs{@@_parse_operand:Nw} with the appropriate precedence, then apply -% the operator to the operand found to yield the result of -% \cs{@@_parse_one:Nw}. So far, all is simple. -% -% The unary operators |+|, |-|,~|!| complicate things a little bit: -% |-3**2| should be $-(3^2)=-9$, and not $(-3)^2=9$. This would easily -% be done by giving~|-| a lower precedence, equal to that of the infix -% |+| and~|-|. Unfortunately, this fails in cases such as |3**-2*4|, -% yielding $3^{-2\times 4}$ instead of the correct $3^{-2}\times 4$. A -% second attempt would be to call \cs{@@_parse_operand:Nw} with the -% \meta{precedence} of the previous operator, but |0>-2+3| is then -% parsed as |0>-(2+3)|: the addition is performed because it binds more -% tightly than the comparision which precedes~|-|. The correct approach -% is for a unary~|-| to perform operations whose precedence is greater -% than both that of the previous operation, and that of the unary~|-| -% itself. The unary~|-| is given a precedence higher than -% multiplication and division. This does not lead to any surprising -% result, since $-(x/y) = (-x)/y$ and similarly for multiplication, and -% it reduces the number of nested calls to \cs{@@_parse_operand:Nw}. -% -% Functions are implemented as prefix operators with very high -% precedence, so that their argument is the first number that can -% possibly be built. -% -% Note that contrarily to the \texttt{infix} functions discussed -% earlier, the \texttt{prefix} functions do perform tests on the -% previous \meta{precedence} to decide whether to find an argument or -% not, since we know that we need a number, and must never stop there. -% -% \subsubsection{Numbers and reading tokens one by one} -% -% So far, we have glossed over one important point: what is a -% \enquote{number}? A number is typically given in the form -% \meta{significand}|e|\meta{exponent}, where the \meta{significand} is -% any non-empty string composed of decimal digits and at most one -% decimal separator (a period), the exponent -% \enquote{\texttt{e}\meta{exponent}} is optional and is composed of an -% exponent mark~|e| followed by a possibly empty string of signs -% |+| or~|-| and a non-empty string of decimal digits. The -% \meta{significand} can also be an integer, dimension, skip, or muskip -% variable, in which case dimensions are converted from points (or mu -% units) to floating points, and the \meta{exponent} can also be an -% integer variable. Numbers can also be given as floating point -% variables, or as named constants such as |nan|, |inf| or~|pi|. We may -% add more types in the future. -% -% When \cs{@@_parse_one:Nw} is looking for a \enquote{number}, here is -% what happens. -% \begin{itemize} -% \item If the next token is a control sequence with the meaning of -% \cs{scan_stop:}, it can be: \cs{s_@@}, in which case our job is -% done, as what follows is an internal floating point number, or -% \cs{s_@@_expr_mark}, in which case the expression has come to an early -% end, as we are still looking for a number here, or something else, -% in which case we consider the control sequence to be a bad -% variable resulting from \texttt{c}-expansion. -% \item If the next token is a control sequence with a different -% meaning, we assume that it is a register, unpack it with -% \cs{tex_the:D}, and use its value (in \texttt{pt} for dimensions -% and skips, \texttt{mu} for muskips) as the \meta{significand} of a -% number: we look for an exponent. -% \item If the next token is a digit, we remove any leading zeros, -% then read a significand larger than~$1$ if the next character is a -% digit, read a significand smaller than~$1$ if the next character -% is a period, or we have found a significand equal to~$0$ -% otherwise, and look for an exponent. -% \item If the next token is a letter, we collect more letters until -% the first non-letter: the resulting word may denote a function -% such as |asin|, a constant such as |pi| or be unknown. In the -% first case, we call \cs{@@_parse_operand:Nw} to find the argument -% of the function, then apply the function, before declaring that we -% are done. Otherwise, we are done, either with the value of the -% constant, or with the value |nan| for unknown words. -% \item If the next token is anything else, we check whether it is a -% known prefix operator, in which case \cs{@@_parse_operand:Nw} -% finds its operand. If it is not known, then either a number is -% missing (if the token is a known infix operator) or the token is -% simply invalid in floating point expressions. -% \end{itemize} -% Once a number is found, \cs{@@_parse_one:Nw} also finds an infix -% operator. This goes as follows. -% \begin{itemize} -% \item If the next token is a control sequence, it could be the -% special marker \cs{s_@@_expr_mark}, and -% otherwise it is a case of juxtaposing numbers, such as -% |2\c_zero_int|, with an implied multiplication. -% \item If the next token is a letter, it is also a case of -% juxtaposition, as letters cannot be proper infix operators. -% \item Otherwise (including in the case of digits), if the token is a -% known infix operator, the appropriate -% |\__fp_infix_|\meta{operator}|:N| function is built, and if it -% does not exist, we complain. In particular, the juxtaposition -% |\c_zero_int 2| is disallowed. -% \end{itemize} -% -% In the above, we need to test whether a character token~|#1| is a -% digit: -% \begin{verbatim} -% \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f: -% is a digit -% \else: -% not a digit -% \fi: -% \end{verbatim} -% To exclude |0|, replace |9| by |10|. The use of -% \cs{token_to_str:N} ensures that a digit with any catcode is detected. -% To test if a character token is a letter, we need to work with its -% character code, testing if |`#1| lies in $[65,90]$ (uppercase letters) -% or $[97,112]$ (lowercase letters) -% \begin{verbatim} -% \if_int_compare:w \__fp_int_eval:w -% ( `#1 \if_int_compare:w `#1 > `Z - 32 \fi: ) / 26 = 3 \exp_stop_f: -% is a letter -% \else: -% not a letter -% \fi: -% \end{verbatim} -% At all steps, we try to accept all category codes: when |#1|~is kept -% to be used later, it is almost always converted to category code other -% through \cs{token_to_str:N}. More precisely, catcodes $\{3, 6, 7, 8, -% 11, 12\}$ should work without trouble, but not $\{1, 2, 4, 10, 13\}$, -% and of course $\{0, 5, 9\}$ cannot become tokens. -% -% Floating point expressions should behave as much as possible like -% \eTeX{}-based integer expressions and dimension expressions. In -% particular, \texttt{f}-expansion should be performed as the expression -% is read, token by token, forcing the expansion of protected macros, -% and ignoring spaces. One advantage of expanding at every step is that -% restricted expandable functions can then be used in floating point -% expressions just as they can be in other kinds of expressions. -% Problematically, spaces stop \texttt{f}-expansion: for instance, the -% macro~|\X| below would not be expanded if we simply performed -% \texttt{f}-expansion. -% \begin{verbatim} -% \DeclareDocumentCommand {\test} {m} { \fp_eval:n {#1} } -% \ExplSyntaxOff -% \test { 1 + \X } -% \end{verbatim} -% Of course, spaces typically do not appear in a code setting, but may very -% easily come in document-level input, from which some expressions may -% come. To avoid this problem, at every step, we do essentially what -% \cs{use:f} would do: take an argument, put it back in the input -% stream, then \texttt{f}-expand it. This is not a complete solution, -% since a macro's expansion could contain leading spaces which would stop -% the \texttt{f}-expansion before further macro calls are performed. -% However, in practice it should be enough: in particular, floating -% point numbers are correctly expanded to the underlying \cs{s_@@} -% \ldots{} structure. The \texttt{f}-expansion is performed by -% \cs{@@_parse_expand:w}. -% -% ^^A begin[todo] -% -% \subsection{Main auxiliary functions} -% -% \begin{macro}[rEXP]{\@@_parse_operand:Nw} -% \begin{syntax} -% \cs{exp:w} \cs{@@_parse_operand:Nw} \meta{precedence} \cs{@@_parse_expand:w} -% \end{syntax} -% Reads the \enquote{\ttfamily\ldots{}}, performing every computation -% with a precedence higher than \meta{precedence}, then expands to -% \begin{syntax} -% \meta{result} |@| |\__fp_parse_infix_|\meta{operation}|:N| \ldots{} -% \end{syntax} -% where the \meta{operation} is the first operation with a lower -% precedence, possibly \texttt{end}, and the -% \enquote{\ttfamily\ldots{}} start just after the \meta{operation}. -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_infix_+:N} -% \begin{syntax} -% \cs{@@_parse_infix_+:N} \meta{precedence} \ldots{} -% \end{syntax} -% If |+|~has a precedence higher than the \meta{precedence}, cleans up -% a second \meta{operand} and finds the \meta{operation_2} which -% follows, and expands to -% \begin{syntax} -% |@| \cs{@@_parse_apply_binary:NwNwN} |+| \meta{operand} |@| \cs{@@_parse_infix_\meta{operation_2}:N} \ldots{} -% \end{syntax} -% Otherwise expands to -% \begin{syntax} -% |@| \cs{use_none:n} \cs{@@_parse_infix_+:N} \ldots{} -% \end{syntax} -% A similar function exists for each infix operator. -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_one:Nw} -% \begin{syntax} -% \cs{@@_parse_one:Nw} \meta{precedence} \ldots{} -% \end{syntax} -% Cleans up one or two operands depending on how the precedence of the -% next operation compares to the \meta{precedence}. If the following -% \meta{operation} has a precedence higher than \meta{precedence}, -% expands to -% \begin{syntax} -% \meta{operand_1} |@| \cs{@@_parse_apply_binary:NwNwN} \meta{operation} \meta{operand_2} |@| |\__fp_parse_infix_|\meta{operation_2}|:N| \ldots{} -% \end{syntax} -% and otherwise expands to -% \begin{syntax} -% \meta{operand} |@| \cs{use_none:n} |\__fp_parse_infix_|\meta{operation}|:N| \ldots{} -% \end{syntax} -% \end{macro} -% -% ^^A end[todo] -% -% \subsection{Helpers} -% -% \begin{macro}[rEXP]{\@@_parse_expand:w} -% \begin{syntax} -% \cs{exp:w} \cs{@@_parse_expand:w} \meta{tokens} -% \end{syntax} -% This function must always come within a \cs{exp:w} expansion. -% The \meta{tokens} should be the part of the expression that we have -% not yet read. This requires in particular closing all conditionals -% properly before expanding. -% \begin{macrocode} -\cs_new:Npn \@@_parse_expand:w #1 { \exp_end_continue_f:w #1 } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_return_semicolon:w} -% This very odd function swaps its position with the following -% \cs{fi:} and removes \cs{@@_parse_expand:w} normally responsible for -% expansion. That turns out to be useful. -% \begin{macrocode} -\cs_new:Npn \@@_parse_return_semicolon:w - #1 \fi: \@@_parse_expand:w { \fi: ; #1 } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP] -% { -% \@@_parse_digits_vii:N , -% \@@_parse_digits_vi:N , -% \@@_parse_digits_v:N , -% \@@_parse_digits_iv:N , -% \@@_parse_digits_iii:N , -% \@@_parse_digits_ii:N , -% \@@_parse_digits_i:N , -% \@@_parse_digits_:N -% } -% These functions must be called within an \cs{int_value:w} or -% \cs{@@_int_eval:w} construction. The first token which follows must -% be \texttt{f}-expanded prior to calling those functions. The -% functions read tokens one by one, and output digits into the input -% stream, until meeting a non-digit, or up to a number of digits equal -% to their index. The full expansion is -% \begin{syntax} -% \meta{digits} |;| \meta{filling 0} |;| \meta{length} -% \end{syntax} -% where \meta{filling 0} is a string of zeros such that \meta{digits} -% \meta{filling 0} has the length given by the index of the function, -% and \meta{length} is the number of zeros in the \meta{filling 0} -% string. Each function puts a digit into the input stream and calls -% the next function, until we find a non-digit. We are careful to -% pass the tested tokens through \cs{token_to_str:N} to normalize -% their category code. -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1 #2 #3 - { - \cs_new:cpn { @@_parse_digits_ #1 :N } ##1 - { - \if_int_compare:w 9 < 1 \token_to_str:N ##1 \exp_stop_f: - \token_to_str:N ##1 \exp_after:wN #2 \exp:w - \else: - \@@_parse_return_semicolon:w #3 ##1 - \fi: - \@@_parse_expand:w - } - } -\@@_tmp:w {vii} \@@_parse_digits_vi:N { 0000000 ; 7 } -\@@_tmp:w {vi} \@@_parse_digits_v:N { 000000 ; 6 } -\@@_tmp:w {v} \@@_parse_digits_iv:N { 00000 ; 5 } -\@@_tmp:w {iv} \@@_parse_digits_iii:N { 0000 ; 4 } -\@@_tmp:w {iii} \@@_parse_digits_ii:N { 000 ; 3 } -\@@_tmp:w {ii} \@@_parse_digits_i:N { 00 ; 2 } -\@@_tmp:w {i} \@@_parse_digits_:N { 0 ; 1 } -\cs_new:Npn \@@_parse_digits_:N { ; ; 0 } -% \end{macrocode} -% \end{macro} -% -% \subsection{Parsing one number} -% -% \begin{macro}[EXP]{\@@_parse_one:Nw} -% This function finds one number, and packs the symbol which follows -% in an \cs[no-index]{@@_parse_infix_\ldots{}} csname. -% |#1|~is the previous \meta{precedence}, -% and |#2|~the first token of the operand. We distinguish four cases: -% |#2|~is equal to \cs{scan_stop:} in meaning, |#2|~is a different -% control sequence, |#2|~is a digit, and |#2|~is something else (this -% last case is split further later). Despite the earlier -% \texttt{f}-expansion, |#2|~may still be expandable if it was -% protected by \cs{exp_not:N}, as may happen with the \LaTeXe{} command -% \tn{protect}. Using a well placed \cs{reverse_if:N}, this case is -% sent to \cs{@@_parse_one_fp:NN} which deals with it robustly. -% \begin{macrocode} -\cs_new:Npn \@@_parse_one:Nw #1 #2 - { - \if_catcode:w \scan_stop: \exp_not:N #2 - \exp_after:wN \if_meaning:w \exp_not:N #2 #2 \else: - \exp_after:wN \reverse_if:N - \fi: - \if_meaning:w \scan_stop: #2 - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_one_fp:NN - \else: - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_one_register:NN - \fi: - \else: - \if_int_compare:w 9 < 1 \token_to_str:N #2 \exp_stop_f: - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_one_digit:NN - \else: - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_one_other:NN - \fi: - \fi: - #1 #2 - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP] -% { -% \@@_parse_one_fp:NN, -% \@@_exp_after_expr_mark_f:nw, -% \@@_exp_after_?_f:nw -% } -% This function receives a \meta{precedence} and a control sequence -% equal to \cs{scan_stop:} in meaning. There are three cases. -% \begin{itemize} -% \item \cs{s_@@} starts a floating point number, and we call -% \cs{@@_exp_after_f:nw}, which |f|-expands after the floating -% point. -% \item \cs{s_@@_expr_mark} is a premature end, we call -% \cs{@@_exp_after_expr_mark_f:nw}, which triggers an |fp-early-end| -% error. -% \item For a control sequence not containing \cs[no-index]{s_@@}, we call -% \cs{@@_exp_after_?_f:nw}, causing a |bad-variable| error. -% \end{itemize} -% This scheme is extensible: additional types can be added by starting -% the variables with a scan mark of the form \cs[no-index]{s_@@_\meta{type}} and -% defining |\__fp_exp_after_|\meta{type}|_f:nw|. In all cases, we -% make sure that the second argument of \cs{@@_parse_infix:NN} is -% correctly expanded. -% A special case only enabled in \LaTeXe{} is that if \tn{protect} is -% encountered then the error message mentions the control sequence -% which follows it rather than \tn{protect} itself. The test for -% \LaTeXe{} uses \tn{@unexpandable@protect} rather than \tn{protect} -% because \tn{protect} is often \cs{scan_stop:} hence \enquote{does -% not exist}. -% \begin{macrocode} -\cs_new:Npn \@@_parse_one_fp:NN #1 - { - \@@_exp_after_any_f:nw - { - \exp_after:wN \@@_parse_infix:NN - \exp_after:wN #1 \exp:w \@@_parse_expand:w - } - } -\cs_new:Npn \@@_exp_after_expr_mark_f:nw #1 - { - \int_case:nnF { \exp_after:wN \use_i:nnn \use_none:nnn #1 } - { - \c_@@_prec_comma_int { } - \c_@@_prec_tuple_int { } - \c_@@_prec_end_int - { - \exp_after:wN \c_@@_empty_tuple_fp - \exp:w \exp_end_continue_f:w - } - } - { - \msg_expandable_error:nn { fp } { early-end } - \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w - } - #1 - } -\cs_new:cpn { @@_exp_after_?_f:nw } #1#2 - { - \msg_expandable_error:nnn { kernel } { bad-variable } - {#2} - \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w #1 - } -\cs_set_protected:Npn \@@_tmp:w #1 - { - \cs_if_exist:NT #1 - { - \cs_gset:cpn { @@_exp_after_?_f:nw } ##1##2 - { - \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w ##1 - \str_if_eq:nnTF {##2} { \protect } - { - \cs_if_eq:NNTF ##2 #1 { \use_i:nn } { \use:n } - { - \msg_expandable_error:nnn { fp } - { robust-cmd } - } - } - { - \msg_expandable_error:nnn { kernel } - { bad-variable } {##2} - } - } - } - } -\exp_args:Nc \@@_tmp:w { @unexpandable@protect } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP] -% { -% \@@_parse_one_register:NN, -% \@@_parse_one_register_aux:Nw, -% \@@_parse_one_register_auxii:wwwNw, -% \@@_parse_one_register_int:www, -% \@@_parse_one_register_mu:www, -% \@@_parse_one_register_dim:ww, -% } -% This is called whenever~|#2| is a control sequence other than -% \cs{scan_stop:} in meaning. We special-case \tn{wd}, \tn{ht}, \tn{dp} -% (see later) and otherwise assume that it is a register, but -% carefully unpack it with \cs{tex_the:D} within braces. First, we -% find the exponent following~|#2|. Then we unpack~|#2| with -% \cs{tex_the:D}, and the \texttt{auxii} auxiliary distinguishes -% integer registers from dimensions/skips from muskips, according to -% the presence of a period and/or of |pt|. For integers, simply -% convert \meta{value}|e|\meta{exponent} to a floating point number -% with \cs{@@_parse:n} (this is somewhat wasteful). For other -% registers, the decimal rounding provided by \TeX{} does not -% accurately represent the binary value that it manipulates, so we -% extract this binary value as a number of scaled points with -% \cs{int_value:w} \cs{dim_to_decimal_in_sp:n} |{| \meta{decimal value} |pt| |}|, and -% use an auxiliary of \cs{dim_to_fp:n}, which performs the -% multiplication by $2^{-16}$, correctly rounded. -% \begin{macrocode} -\cs_new:Npn \@@_parse_one_register:NN #1#2 - { - \exp_after:wN \@@_parse_infix_after_operand:NwN - \exp_after:wN #1 - \exp:w \exp_end_continue_f:w - \@@_parse_one_register_special:N #2 - \exp_after:wN \@@_parse_one_register_aux:Nw - \exp_after:wN #2 - \int_value:w - \exp_after:wN \@@_parse_exponent:N - \exp:w \@@_parse_expand:w - } -\cs_new:Npe \@@_parse_one_register_aux:Nw #1 - { - \exp_not:n - { - \exp_after:wN \use:nn - \exp_after:wN \@@_parse_one_register_auxii:wwwNw - } - \exp_not:N \exp_after:wN { \exp_not:N \tex_the:D #1 } - ; \exp_not:N \@@_parse_one_register_dim:ww - \tl_to_str:n { pt } ; \exp_not:N \@@_parse_one_register_mu:www - . \tl_to_str:n { pt } ; \exp_not:N \@@_parse_one_register_int:www - \s_@@_stop - } -\exp_args:Nno \use:nn - { \cs_new:Npn \@@_parse_one_register_auxii:wwwNw #1 . #2 } - { \tl_to_str:n { pt } #3 ; #4#5 \s_@@_stop } - { #4 #1.#2; } -\exp_args:Nno \use:nn - { \cs_new:Npn \@@_parse_one_register_mu:www #1 } - { \tl_to_str:n { mu } ; #2 ; } - { \@@_parse_one_register_dim:ww #1 ; } -\cs_new:Npn \@@_parse_one_register_int:www #1; #2.; #3; - { \@@_parse:n { #1 e #3 } } -\cs_new:Npn \@@_parse_one_register_dim:ww #1; #2; - { - \exp_after:wN \@@_from_dim_test:ww - \int_value:w #2 \exp_after:wN , - \int_value:w \dim_to_decimal_in_sp:n { #1 pt } ; - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro} -% { -% \@@_parse_one_register_special:N, -% \@@_parse_one_register_math:NNw, -% \@@_parse_one_register_wd:w, -% \@@_parse_one_register_wd:Nw -% } -% The \tn{wd}, \tn{dp}, \tn{ht} primitives expect an integer argument. -% We abuse the exponent parser to find the integer argument: simply -% include the exponent marker~|e|. Once that \enquote{exponent} is -% found, use \cs{tex_the:D} to find the box dimension and then copy -% what we did for dimensions. -% \begin{macrocode} -\cs_new:Npn \@@_parse_one_register_special:N #1 - { - \if_meaning:w \box_wd:N #1 \@@_parse_one_register_wd:w \fi: - \if_meaning:w \box_ht:N #1 \@@_parse_one_register_wd:w \fi: - \if_meaning:w \box_dp:N #1 \@@_parse_one_register_wd:w \fi: - \if_meaning:w \infty #1 - \@@_parse_one_register_math:NNw \infty #1 - \fi: - \if_meaning:w \pi #1 - \@@_parse_one_register_math:NNw \pi #1 - \fi: - } -\cs_new:Npn \@@_parse_one_register_math:NNw - #1#2#3#4 \@@_parse_expand:w - { - #3 - \str_if_eq:nnTF {#1} {#2} - { - \msg_expandable_error:nnn - { fp } { infty-pi } {#1} - \c_nan_fp - } - { #4 \@@_parse_expand:w } - } -\cs_new:Npn \@@_parse_one_register_wd:w - #1#2 \exp_after:wN #3#4 \@@_parse_expand:w - { - #1 - \exp_after:wN \@@_parse_one_register_wd:Nw - #4 \@@_parse_expand:w e - } -\cs_new:Npn \@@_parse_one_register_wd:Nw #1#2 ; - { - \exp_after:wN \@@_from_dim_test:ww - \exp_after:wN 0 \exp_after:wN , - \int_value:w \dim_to_decimal_in_sp:n { #1 #2 } ; - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_one_digit:NN} -% A digit marks the beginning of an explicit floating point number. -% Once the number is found, we catch the case of overflow and -% underflow with \cs{@@_sanitize:wN}, then -% \cs{@@_parse_infix_after_operand:NwN} expands \cs{@@_parse_infix:NN} -% after the number we find, to wrap the following infix operator as -% required. Finding the number itself begins by removing leading -% zeros: further steps are described later. -% \begin{macrocode} -\cs_new:Npn \@@_parse_one_digit:NN #1 - { - \exp_after:wN \@@_parse_infix_after_operand:NwN - \exp_after:wN #1 - \exp:w \exp_end_continue_f:w - \exp_after:wN \@@_sanitize:wN - \int_value:w \@@_int_eval:w 0 \@@_parse_trim_zeros:N - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_one_other:NN} -% For this function, |#2|~is a character token which is not a digit. -% If it is an \textsc{ascii} letter, \cs{@@_parse_letters:N} beyond this one and give -% the result to \cs{@@_parse_word:Nw}. Otherwise, the character is -% assumed to be a prefix operator, and we build -% |\__fp_parse_prefix_|\meta{operator}|:Nw|. -% \begin{macrocode} -\cs_new:Npn \@@_parse_one_other:NN #1 #2 - { - \if_int_compare:w - \@@_int_eval:w - ( `#2 \if_int_compare:w `#2 > `Z - 32 \fi: ) / 26 - = 3 \exp_stop_f: - \exp_after:wN \@@_parse_word:Nw - \exp_after:wN #1 - \exp_after:wN #2 - \exp:w \exp_after:wN \@@_parse_letters:N - \exp:w - \else: - \exp_after:wN \@@_parse_prefix:NNN - \exp_after:wN #1 - \exp_after:wN #2 - \cs:w - @@_parse_prefix_ \token_to_str:N #2 :Nw - \exp_after:wN - \cs_end: - \exp:w - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_word:Nw} -% \begin{macro}[rEXP]{\@@_parse_letters:N} -% Finding letters is a simple recursion. Once \cs{@@_parse_letters:N} -% has done its job, we try to build a control sequence from the -% word~|#2|. If it is a known word, then the corresponding action is -% taken, and otherwise, we complain about an unknown word, yield -% \cs{c_nan_fp}, and look for the following infix operator. Note that -% the unknown word could be a mistyped function as well as a mistyped -% constant, so there is no way to tell whether to look for arguments; -% we do not. -% The standard requires \enquote{inf} and \enquote{infinity} and -% \enquote{nan} to be recognized regardless of case, but we probably -% don't want to allow every \pkg{l3fp} word to have an arbitrary -% mixture of lower and upper case, so we test and use a -% differently-named control sequence. -% \begin{macrocode} -\cs_new:Npn \@@_parse_word:Nw #1#2; - { - \cs_if_exist_use:cF { @@_parse_word_#2:N } - { - \cs_if_exist_use:cF - { @@_parse_caseless_ \str_casefold:n {#2} :N } - { - \msg_expandable_error:nnn - { fp } { unknown-fp-word } {#2} - \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w - \@@_parse_infix:NN - } - } - #1 - } -\cs_new:Npn \@@_parse_letters:N #1 - { - \exp_end_continue_f:w - \if_int_compare:w - \if_catcode:w \scan_stop: \exp_not:N #1 - 0 - \else: - \@@_int_eval:w - ( `#1 \if_int_compare:w `#1 > `Z - 32 \fi: ) / 26 - \fi: - = 3 \exp_stop_f: - \exp_after:wN #1 - \exp:w \exp_after:wN \@@_parse_letters:N - \exp:w - \else: - \@@_parse_return_semicolon:w #1 - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP] -% {\@@_parse_prefix:NNN, \@@_parse_prefix_unknown:NNN} -% For this function, |#1|~is the previous \meta{precedence}, |#2|~is -% the operator just seen, and |#3|~is a control sequence which -% implements the operator if it is a known operator. If this control -% sequence is \cs{scan_stop:}, then the operator is in fact unknown. -% Either the expression is missing a number there (if the operator is -% valid as an infix operator), and we put \texttt{nan}, wrapping the -% infix operator in a csname as appropriate, or the character is -% simply invalid in floating point expressions, and we continue -% looking for a number, starting again from \cs{@@_parse_one:Nw}. -% \begin{macrocode} -\cs_new:Npn \@@_parse_prefix:NNN #1#2#3 - { - \if_meaning:w \scan_stop: #3 - \exp_after:wN \@@_parse_prefix_unknown:NNN - \exp_after:wN #2 - \fi: - #3 #1 - } -\cs_new:Npn \@@_parse_prefix_unknown:NNN #1#2#3 - { - \cs_if_exist:cTF { @@_parse_infix_ \token_to_str:N #1 :N } - { - \msg_expandable_error:nnn - { fp } { missing-number } {#1} - \exp_after:wN \c_nan_fp \exp:w \exp_end_continue_f:w - \@@_parse_infix:NN #3 #1 - } - { - \msg_expandable_error:nnn - { fp } { unknown-symbol } {#1} - \@@_parse_one:Nw #3 - } - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Numbers: trimming leading zeros} -% -% Numbers are parsed as follows: first we trim leading zeros, then -% if the next character is a digit, start reading a significand $\geq 1$ -% with the set of functions |\__fp_parse_large|\ldots{}; if it is a -% period, the significand is~$<1$; and otherwise it is zero. In the -% second case, trim additional zeros after the period, counting them for -% an exponent shift $\meta{exp_1}<0$, then read the significand with the -% set of functions |\__fp_parse_small|\ldots{} Once the significand is -% read, read the exponent if |e|~is present. -% -% \begin{macro}[rEXP]{\@@_parse_trim_zeros:N, \@@_parse_trim_end:w} -% This function expects an already expanded token. It removes any -% leading zero, then distinguishes three cases: if the first non-zero -% token is a digit, then call \cs{@@_parse_large:N} (the significand -% is $\geq 1$); if it is |.|, then continue trimming zeros with -% \cs{@@_parse_strim_zeros:N}; otherwise, our number is exactly zero, -% and we call \cs{@@_parse_zero:} to take care of that case. -% \begin{macrocode} -\cs_new:Npn \@@_parse_trim_zeros:N #1 - { - \if:w 0 \exp_not:N #1 - \exp_after:wN \@@_parse_trim_zeros:N - \exp:w - \else: - \if:w . \exp_not:N #1 - \exp_after:wN \@@_parse_strim_zeros:N - \exp:w - \else: - \@@_parse_trim_end:w #1 - \fi: - \fi: - \@@_parse_expand:w - } -\cs_new:Npn \@@_parse_trim_end:w #1 \fi: \fi: \@@_parse_expand:w - { - \fi: - \fi: - \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f: - \exp_after:wN \@@_parse_large:N - \else: - \exp_after:wN \@@_parse_zero: - \fi: - #1 - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP] -% {\@@_parse_strim_zeros:N, \@@_parse_strim_end:w} -% If we have removed all digits until a period (or if the body started -% with a period), then enter the \enquote{\texttt{small_trim}} loop -% which outputs $-1$ for each removed~$0$. Those $-1$ are added to an -% integer expression waiting for the exponent. If the first non-zero -% token is a digit, call \cs{@@_parse_small:N} (our significand is -% smaller than~$1$), and otherwise, the number is an exact zero. The -% name \texttt{strim} stands for \enquote{small trim}. -% \begin{macrocode} -\cs_new:Npn \@@_parse_strim_zeros:N #1 - { - \if:w 0 \exp_not:N #1 - - 1 - \exp_after:wN \@@_parse_strim_zeros:N \exp:w - \else: - \@@_parse_strim_end:w #1 - \fi: - \@@_parse_expand:w - } -\cs_new:Npn \@@_parse_strim_end:w #1 \fi: \@@_parse_expand:w - { - \fi: - \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f: - \exp_after:wN \@@_parse_small:N - \else: - \exp_after:wN \@@_parse_zero: - \fi: - #1 - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_zero:} -% After reading a significand of~$0$, find any exponent, then put a -% sign of~|1| for \cs{@@_sanitize:wN}, which removes everything -% and leaves an exact zero. -% \begin{macrocode} -\cs_new:Npn \@@_parse_zero: - { - \exp_after:wN ; \exp_after:wN 1 - \int_value:w \@@_parse_exponent:N - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Number: small significand} -% -% \begin{macro}[rEXP]{\@@_parse_small:N} -% This function is called after we have passed the decimal separator -% and removed all leading zeros from the significand. It is followed -% by a non-zero digit (with any catcode). The goal is to read up to -% $16$ digits. But we can't do that all at once, because -% \cs{int_value:w} (which allows us to collect digits and continue -% expanding) can only go up to $9$ digits. Hence we grab digits in -% two steps of $8$ digits. Since |#1| is a digit, read seven more -% digits using \cs{@@_parse_digits_vii:N}. The \texttt{small_leading} -% auxiliary leaves those digits in the \cs{int_value:w}, and -% grabs some more, or stops if there are no more digits. Then the -% \texttt{pack_leading} auxiliary puts the various parts in the -% appropriate order for the processing further up. -% \begin{macrocode} -\cs_new:Npn \@@_parse_small:N #1 - { - \exp_after:wN \@@_parse_pack_leading:NNNNNww - \int_value:w \@@_int_eval:w 1 \token_to_str:N #1 - \exp_after:wN \@@_parse_small_leading:wwNN - \int_value:w 1 - \exp_after:wN \@@_parse_digits_vii:N - \exp:w \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_small_leading:wwNN} -% \begin{syntax} -% \cs{@@_parse_small_leading:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} -% \end{syntax} -% We leave \meta{digits} \meta{zeros} in the input stream: the -% functions used to grab digits are such that this constitutes digits -% $1$ through~$8$ of the significand. Then prepare to pack $8$~more -% digits, with an exponent shift of zero (this shift is used in -% the case of a large significand). If |#4|~is a digit, leave it -% behind for the packing function, and read $6$~more digits to reach a -% total of $15$~digits: further digits are involved in the rounding. -% Otherwise put $8$~zeros in to complete the significand, then look -% for an exponent. -% \begin{macrocode} -\cs_new:Npn \@@_parse_small_leading:wwNN 1 #1 ; #2; #3 #4 - { - #1 #2 - \exp_after:wN \@@_parse_pack_trailing:NNNNNNww - \exp_after:wN 0 - \int_value:w \@@_int_eval:w 1 - \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f: - \token_to_str:N #4 - \exp_after:wN \@@_parse_small_trailing:wwNN - \int_value:w 1 - \exp_after:wN \@@_parse_digits_vi:N - \exp:w - \else: - 0000 0000 \@@_parse_exponent:Nw #4 - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_small_trailing:wwNN} -% \begin{syntax} -% \cs{@@_parse_small_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token} -% \end{syntax} -% Leave digits $10$ to~$15$ (arguments |#1| and |#2|) in the input -% stream. If the \meta{next~token} is a digit, it is the $16$th -% digit, we keep it, then the \texttt{small_round} auxiliary considers -% this digit and all further digits to perform the rounding: the -% function expands to nothing, to |+0| or to |+1|. -% Otherwise, there is no $16$-th digit, so we put a~$0$, and look for -% an exponent. -% \begin{macrocode} -\cs_new:Npn \@@_parse_small_trailing:wwNN 1 #1 ; #2; #3 #4 - { - #1 #2 - \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f: - \token_to_str:N #4 - \exp_after:wN \@@_parse_small_round:NN - \exp_after:wN #4 - \exp:w - \else: - 0 \@@_parse_exponent:Nw #4 - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP] -% { -% \@@_parse_pack_trailing:NNNNNNww , -% \@@_parse_pack_leading:NNNNNww , -% \@@_parse_pack_carry:w -% } -% Those functions are expanded after all the digits are found, we took -% care of the rounding, as well as the exponent. The last argument is -% the exponent. The previous five arguments are $8$~digits which we -% pack in groups of~$4$, and the argument before that is~$1$, except -% in the rare case where rounding lead to a carry, in which case the -% argument is~$2$. The \texttt{trailing} function has an exponent -% shift as its first argument, which we add to the exponent found in -% the |e...| syntax. If the trailing digits cause a carry, the -% integer expression for the leading digits is incremented (|+1| -% in the code below). If the leading digits propagate this carry all -% the way up, the function \cs{@@_parse_pack_carry:w} increments the -% exponent, and changes the significand from |0000...| to |1000...|: -% this is simple because such a carry can only occur to give rise to a -% power of~$10$. -% \begin{macrocode} -\cs_new:Npn \@@_parse_pack_trailing:NNNNNNww #1 #2 #3#4#5#6 #7; #8 ; - { - \if_meaning:w 2 #2 + 1 \fi: - ; #8 + #1 ; {#3#4#5#6} {#7}; - } -\cs_new:Npn \@@_parse_pack_leading:NNNNNww #1 #2#3#4#5 #6; #7; - { - + #7 - \if_meaning:w 2 #1 \@@_parse_pack_carry:w \fi: - ; 0 {#2#3#4#5} {#6} - } -\cs_new:Npn \@@_parse_pack_carry:w \fi: ; 0 #1 - { \fi: + 1 ; 0 {1000} } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Number: large significand} -% -% Parsing a significand larger than~$1$ is a little bit more difficult -% than parsing small significands. We need to count the number of -% digits before the decimal separator, and add that to the final -% exponent. We also need to test for the presence of a dot each time we -% run out of digits, and branch to the appropriate \texttt{parse_small} -% function in those cases. -% -% \begin{macro}[EXP]{\@@_parse_large:N} -% This function is followed by the first non-zero digit of a -% \enquote{large} significand ($\geq 1$). It is called within an -% integer expression for the exponent. Grab up to $7$~more digits, -% for a total of $8$~digits. -% \begin{macrocode} -\cs_new:Npn \@@_parse_large:N #1 - { - \exp_after:wN \@@_parse_large_leading:wwNN - \int_value:w 1 \token_to_str:N #1 - \exp_after:wN \@@_parse_digits_vii:N - \exp:w \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_large_leading:wwNN} -% \begin{syntax} -% \cs{@@_parse_large_leading:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token} -% \end{syntax} -% We shift the exponent by the number of digits in~|#1|, namely the -% target number, $8$, minus the \meta{number of zeros} (number of -% digits missing). Then prepare to pack the $8$~first digits. If the -% \meta{next token} is a digit, read up to $6$~more digits (digits -% $10$ to~$15$). If it is a period, try to grab the end of our -% $8$~first digits, branching to the \texttt{small} functions since -% the number of digit does not affect the exponent anymore. Finally, -% if this is the end of the significand, insert the \meta{zeros} to -% complete the $8$~first digits, insert $8$~more, and look for an -% exponent. -% \begin{macrocode} -\cs_new:Npn \@@_parse_large_leading:wwNN 1 #1 ; #2; #3 #4 - { - + \c_@@_half_prec_int - #3 - \exp_after:wN \@@_parse_pack_leading:NNNNNww - \int_value:w \@@_int_eval:w 1 #1 - \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f: - \exp_after:wN \@@_parse_large_trailing:wwNN - \int_value:w 1 \token_to_str:N #4 - \exp_after:wN \@@_parse_digits_vi:N - \exp:w - \else: - \if:w . \exp_not:N #4 - \exp_after:wN \@@_parse_small_leading:wwNN - \int_value:w 1 - \cs:w - @@_parse_digits_ - \@@_int_to_roman:w #3 - :N \exp_after:wN - \cs_end: - \exp:w - \else: - #2 - \exp_after:wN \@@_parse_pack_trailing:NNNNNNww - \exp_after:wN 0 - \int_value:w 1 0000 0000 - \@@_parse_exponent:Nw #4 - \fi: - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_large_trailing:wwNN} -% \begin{syntax} -% \cs{@@_parse_large_trailing:wwNN} |1| \meta{digits} |;| \meta{zeros} |;| \meta{number~of~zeros} \meta{next~token} -% \end{syntax} -% We have just read $15$~digits. If the \meta{next token} is a digit, -% then the exponent shift caused by this block of $8$~digits is~$8$, -% first argument to the \texttt{pack_trailing} function. We keep the -% \meta{digits} and this $16$-th digit, and find how this should be -% rounded using \cs{@@_parse_large_round:NN}. Otherwise, the exponent -% shift is the number of \meta{digits}, $7$~minus the \meta{number of -% zeros}, and we test for a decimal point. This case happens in -% |123451234512345.67| with exactly $15$ digits before the decimal -% separator. Then branch to the appropriate \texttt{small} auxiliary, -% grabbing a few more digits to complement the digits we already -% grabbed. Finally, if this is truly the end of the significand, look -% for an exponent after using the \meta{zeros} and providing a $16$-th -% digit of~$0$. -% \begin{macrocode} -\cs_new:Npn \@@_parse_large_trailing:wwNN 1 #1 ; #2; #3 #4 - { - \if_int_compare:w 9 < 1 \token_to_str:N #4 \exp_stop_f: - \exp_after:wN \@@_parse_pack_trailing:NNNNNNww - \exp_after:wN \c_@@_half_prec_int - \int_value:w \@@_int_eval:w 1 #1 \token_to_str:N #4 - \exp_after:wN \@@_parse_large_round:NN - \exp_after:wN #4 - \exp:w - \else: - \exp_after:wN \@@_parse_pack_trailing:NNNNNNww - \int_value:w \@@_int_eval:w 7 - #3 \exp_stop_f: - \int_value:w \@@_int_eval:w 1 #1 - \if:w . \exp_not:N #4 - \exp_after:wN \@@_parse_small_trailing:wwNN - \int_value:w 1 - \cs:w - @@_parse_digits_ - \@@_int_to_roman:w #3 - :N \exp_after:wN - \cs_end: - \exp:w - \else: - #2 0 \@@_parse_exponent:Nw #4 - \fi: - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Number: beyond 16 digits, rounding} -% -% \begin{macro}[rEXP]{\@@_parse_round_loop:N, \@@_parse_round_up:N} -% This loop is called when rounding a number (whether the mantissa is -% small or large). It should appear in an integer expression. This -% function reads digits one by one, until reaching a non-digit, and -% adds~$1$ to the integer expression for each digit. If all digits -% found are~$0$, the function ends the expression by |;0|, -% otherwise by |;1|. This is done by switching the loop to -% |round_up| at the first non-zero digit, thus we avoid to test -% whether digits are~$0$ or not once we see a first non-zero digit. -% \begin{macrocode} -\cs_new:Npn \@@_parse_round_loop:N #1 - { - \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f: - + 1 - \if:w 0 \token_to_str:N #1 - \exp_after:wN \@@_parse_round_loop:N - \exp:w - \else: - \exp_after:wN \@@_parse_round_up:N - \exp:w - \fi: - \else: - \@@_parse_return_semicolon:w 0 #1 - \fi: - \@@_parse_expand:w - } -\cs_new:Npn \@@_parse_round_up:N #1 - { - \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f: - + 1 - \exp_after:wN \@@_parse_round_up:N - \exp:w - \else: - \@@_parse_return_semicolon:w 1 #1 - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_round_after:wN} -% After the loop \cs{@@_parse_round_loop:N}, this function fetches an -% exponent with \cs{@@_parse_exponent:N}, and combines it with the -% number of digits counted by \cs{@@_parse_round_loop:N}. At the same -% time, the result |0| or |1| is added to the -% surrounding integer expression. -% \begin{macrocode} -\cs_new:Npn \@@_parse_round_after:wN #1; #2 - { - + #2 \exp_after:wN ; - \int_value:w \@@_int_eval:w #1 + \@@_parse_exponent:N - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP] -% {\@@_parse_small_round:NN, \@@_parse_round_after:wN} -% Here, |#1|~is the digit that we are currently rounding (we only care -% whether it is even or odd). If |#2|~is not a digit, then fetch an -% exponent and expand to |;|\meta{exponent} only. Otherwise, we -% expand to |+0| or |+1|, then |;|\meta{exponent}. To -% decide which, call \cs{@@_round_s:NNNw} to know whether to round up, -% giving it as arguments a sign~$0$ (all explicit numbers are -% positive), the digit |#1|~to round, the first following digit~|#2|, -% and either |+0| or |+1| depending on whether the -% following digits are all zero or not. This last argument is -% obtained by \cs{@@_parse_round_loop:N}, whose number of digits we -% discard by multiplying it by~$0$. The exponent which follows the -% number is also fetched by \cs{@@_parse_round_after:wN}. -% \begin{macrocode} -\cs_new:Npn \@@_parse_small_round:NN #1#2 - { - \if_int_compare:w 9 < 1 \token_to_str:N #2 \exp_stop_f: - + - \exp_after:wN \@@_round_s:NNNw - \exp_after:wN 0 - \exp_after:wN #1 - \exp_after:wN #2 - \int_value:w \@@_int_eval:w - \exp_after:wN \@@_parse_round_after:wN - \int_value:w \@@_int_eval:w 0 * \@@_int_eval:w 0 - \exp_after:wN \@@_parse_round_loop:N - \exp:w - \else: - \@@_parse_exponent:Nw #2 - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% -% \begin{macro}[rEXP] -% { -% \@@_parse_large_round:NN, -% \@@_parse_large_round_test:NN, -% \@@_parse_large_round_aux:wNN, -% } -% Large numbers are harder to round, as there may be a period in the -% way. Again, |#1|~is the digit that we are currently rounding (we -% only care whether it is even or odd). If there are no more digits -% (|#2|~is not a digit), then we must test for a period: if there is -% one, then switch to the rounding function for small significands, -% otherwise fetch an exponent. If there are more digits (|#2|~is a -% digit), then round, checking with \cs{@@_parse_round_loop:N} if all -% further digits vanish, or some are non-zero. This loop is not -% enough, as it is stopped by a period. After the loop, the -% \texttt{aux} function tests for a period: if it is present, then we -% must continue looking for digits, this time discarding the number of -% digits we find. -% \begin{macrocode} -\cs_new:Npn \@@_parse_large_round:NN #1#2 - { - \if_int_compare:w 9 < 1 \token_to_str:N #2 \exp_stop_f: - + - \exp_after:wN \@@_round_s:NNNw - \exp_after:wN 0 - \exp_after:wN #1 - \exp_after:wN #2 - \int_value:w \@@_int_eval:w - \exp_after:wN \@@_parse_large_round_aux:wNN - \int_value:w \@@_int_eval:w 1 - \exp_after:wN \@@_parse_round_loop:N - \else: %^^A could be dot, or e, or other - \exp_after:wN \@@_parse_large_round_test:NN - \exp_after:wN #1 - \exp_after:wN #2 - \fi: - } -\cs_new:Npn \@@_parse_large_round_test:NN #1#2 - { - \if:w . \exp_not:N #2 - \exp_after:wN \@@_parse_small_round:NN - \exp_after:wN #1 - \exp:w - \else: - \@@_parse_exponent:Nw #2 - \fi: - \@@_parse_expand:w - } -\cs_new:Npn \@@_parse_large_round_aux:wNN #1 ; #2 #3 - { - + #2 - \exp_after:wN \@@_parse_round_after:wN - \int_value:w \@@_int_eval:w #1 - \if:w . \exp_not:N #3 - + 0 * \@@_int_eval:w 0 - \exp_after:wN \@@_parse_round_loop:N - \exp:w \exp_after:wN \@@_parse_expand:w - \else: - \exp_after:wN ; - \exp_after:wN 0 - \exp_after:wN #3 - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Number: finding the exponent} -% -% Expansion is a little bit tricky here, in part because we accept input -% where multiplication is implicit. -% \begin{syntax} -% \cs{@@_parse:n} |{ 3.2 erf(0.1) }| -% \cs{@@_parse:n} |{ 3.2 e\l_my_int }| -% \cs{@@_parse:n} |{ 3.2 \c_pi_fp }| -% \end{syntax} -% The first case indicates that just looking one character ahead for an -% \enquote{\texttt{e}} is not enough, since we would mistake the -% function \texttt{erf} for an exponent of \enquote{\texttt{rf}}. An -% alternative would be to look two tokens ahead and check if what -% follows is a sign or a digit, considering in that case that we must be -% finding an exponent. But taking care of the second case requires that -% we unpack registers after \texttt{e}. However, blindly expanding the -% two tokens ahead completely would break the third example (unpacking -% is even worse). Indeed, in the course of reading $3.2$, \cs{c_pi_fp} -% is expanded to \cs{s_@@} \cs{@@_chk:w} |1| |0| |{-1}| |{3141}| -% $\cdots$ |;| and \cs{s_@@} stops the expansion. Expanding two tokens -% ahead would then force the expansion of \cs{@@_chk:w} (despite it -% being protected), and that function tries to produce an error. -% -% What can we do? Really, the reason why this last case breaks is that -% just as \TeX{} does, we should read ahead as little as possible. -% Here, the only case where there may be an exponent is if the first -% token ahead is |e|. Then we expand (and possibly unpack) the second -% token. -% -% \begin{macro}[rEXP]{\@@_parse_exponent:Nw} -% This auxiliary is convenient to smuggle some material through -% \cs{fi:} ending conditional processing. We place those \cs{fi:} -% (argument~|#2|) at a very odd place because this allows us to insert -% \cs{@@_int_eval:w} \ldots{} there if needed. -% \begin{macrocode} -\cs_new:Npn \@@_parse_exponent:Nw #1 #2 \@@_parse_expand:w - { - \exp_after:wN ; - \int_value:w #2 \@@_parse_exponent:N #1 - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP] -% {\@@_parse_exponent:N, \@@_parse_exponent_aux:NN} -% This function should be called within an \cs{int_value:w} -% expansion (or within an integer expression). It leaves digits of the -% exponent behind it in the input stream, and terminates the expansion -% with a semicolon. If there is no~|e| (or~|E|), leave an exponent of~$0$. If -% there is an~|e| or~|E|, expand the next token to run some tests on it. The -% first rough test is that if the character code of~|#1| is greater -% than that of~|9| (largest code valid for an exponent, less than any -% code valid for an identifier), there was in fact no exponent; -% otherwise, we search for the sign of the exponent. -% \begin{macrocode} -\cs_new:Npn \@@_parse_exponent:N #1 - { - \if:w e \if:w E \exp_not:N #1 e \else: \exp_not:N #1 \fi: - \exp_after:wN \@@_parse_exponent_aux:NN - \exp_after:wN #1 - \exp:w - \else: - 0 \@@_parse_return_semicolon:w #1 - \fi: - \@@_parse_expand:w - } -\cs_new:Npn \@@_parse_exponent_aux:NN #1#2 - { - \if_int_compare:w \if_catcode:w \scan_stop: \exp_not:N #2 - 0 \else: `#2 \fi: > `9 \exp_stop_f: - 0 \exp_after:wN ; \exp_after:wN #1 - \else: - \exp_after:wN \@@_parse_exponent_sign:N - \fi: - #2 - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_exponent_sign:N} -% Read signs one by one (if there is any). -% \begin{macrocode} -\cs_new:Npn \@@_parse_exponent_sign:N #1 - { - \if:w + \if:w - \exp_not:N #1 + \fi: \token_to_str:N #1 - \exp_after:wN \@@_parse_exponent_sign:N - \exp:w \exp_after:wN \@@_parse_expand:w - \else: - \exp_after:wN \@@_parse_exponent_body:N - \exp_after:wN #1 - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_exponent_body:N} -% An exponent can be an explicit integer (most common case), or -% various other things (most of which are invalid). -% \begin{macrocode} -\cs_new:Npn \@@_parse_exponent_body:N #1 - { - \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f: - \token_to_str:N #1 - \exp_after:wN \@@_parse_exponent_digits:N - \exp:w - \else: - \@@_parse_exponent_keep:NTF #1 - { \@@_parse_return_semicolon:w #1 } - { - \exp_after:wN ; - \exp:w - } - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_exponent_digits:N} -% Read digits one by one, and leave them behind in the input stream. -% When finding a non-digit, stop, and insert a semicolon. Note that -% we do not check for overflow of the exponent, hence there can be a -% \TeX{} error. It is mostly harmless, except when parsing -% |0e9876543210|, which should be a valid representation of $0$, but -% is not. -% \begin{macrocode} -\cs_new:Npn \@@_parse_exponent_digits:N #1 - { - \if_int_compare:w 9 < 1 \token_to_str:N #1 \exp_stop_f: - \token_to_str:N #1 - \exp_after:wN \@@_parse_exponent_digits:N - \exp:w - \else: - \@@_parse_return_semicolon:w #1 - \fi: - \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_parse_exponent_keep:NTF} -% This is the last building block for parsing exponents. The -% argument~|#1| is already fully expanded, and neither |+| nor~|-| nor -% a digit. It can be: -% \begin{itemize} -% \item \cs{s_@@}, marking the start of an internal floating point, -% invalid here; -% \item another control sequence equal to \tn{relax}, probably a bad -% variable; -% \item a register: in this case we make sure that it is an integer -% register, not a dimension; -% \item a character other than |+|, |-| or digits, again, an error. -% \end{itemize} -% \begin{macrocode} -\prg_new_conditional:Npnn \@@_parse_exponent_keep:N #1 { TF } - { - \if_catcode:w \scan_stop: \exp_not:N #1 - \if_meaning:w \scan_stop: #1 - \if:w 0 \@@_str_if_eq:nn { \s_@@ } { \exp_not:N #1 } - 0 - \msg_expandable_error:nnn - { fp } { after-e } { floating~point~ } - \prg_return_true: - \else: - 0 - \msg_expandable_error:nnn - { kernel } { bad-variable } {#1} - \prg_return_false: - \fi: - \else: - \if:w 0 \@@_str_if_eq:nn { \int_value:w #1 } { \tex_the:D #1 } - \int_value:w #1 - \else: - 0 - \msg_expandable_error:nnn - { fp } { after-e } { dimension~#1 } - \fi: - \prg_return_false: - \fi: - \else: - 0 - \msg_expandable_error:nnn - { fp } { missing } { exponent } - \prg_return_true: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \subsection{Constants, functions and prefix operators} -% -% \subsubsection{Prefix operators} -% -% \begin{macro}[EXP]{\@@_parse_prefix_+:Nw} -% A unary~|+| does nothing: we should continue looking for a number. -% \begin{macrocode} -\cs_new_eq:cN { @@_parse_prefix_+:Nw } \@@_parse_one:Nw -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_apply_function:NNNwN} -% Here, |#1| is a precedence, |#2| is some extra data used by some -% functions, |#3| is \emph{e.g.}, \cs{@@_sin_o:w}, and expands once -% after the calculation, |#4| is the operand, and |#5| is a -% \cs[no-index]{@@_parse_infix_\ldots{}:N} function. We feed the data~|#2|, and the -% argument~|#4|, to the function~|#3|, which expands -% \cs{exp:w} thus the \texttt{infix} function~|#5|. -% \begin{macrocode} -\cs_new:Npn \@@_parse_apply_function:NNNwN #1#2#3#4@#5 - { - #3 #2 #4 @ - \exp:w \exp_end_continue_f:w #5 #1 - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_apply_unary:NNNwN} -% \begin{macro}[EXP]{\@@_parse_apply_unary_chk:NwNw, \@@_parse_apply_unary_chk:nNNNw} -% \begin{macro}[EXP]{\@@_parse_apply_unary_type:NNN, \@@_parse_apply_unary_error:NNw} -% In contrast to \cs{@@_parse_apply_function:NNNwN}, this checks that -% the operand |#4| is a single argument (namely there is a single -% |;|). We use the fact that any floating point starts with a -% \enquote{safe} token like \cs{s_@@}. If there is no argument -% produce the |fp-no-arg| error; if there are at least two produce -% |fp-multi-arg|. For the error message extract the mathematical -% function name (such as |sin|) from the \pkg{expl3} function that -% computes it, such as \cs{@@_sin_o:w}. -% -% In addition, since there is a single argument we can dispatch on -% type and check that the resulting function exists. This catches -% things like |sin((1,2))| where it does not make sense to take the -% sine of a tuple. -% \begin{macrocode} -\cs_new:Npn \@@_parse_apply_unary:NNNwN #1#2#3#4@#5 - { - \@@_parse_apply_unary_chk:NwNw #4 @ ; . \s_@@_stop - \@@_parse_apply_unary_type:NNN - #3 #2 #4 @ - \exp:w \exp_end_continue_f:w #5 #1 - } -\cs_new:Npn \@@_parse_apply_unary_chk:NwNw #1#2 ; #3#4 \s_@@_stop - { - \if_meaning:w @ #3 \else: - \token_if_eq_meaning:NNTF . #3 - { \@@_parse_apply_unary_chk:nNNNNw { no } } - { \@@_parse_apply_unary_chk:nNNNNw { multi } } - \fi: - } -\cs_new:Npn \@@_parse_apply_unary_chk:nNNNNw #1#2#3#4#5#6 @ - { - #2 - \@@_error:nffn { #1-arg } { \@@_func_to_name:N #4 } { } { } - \exp_after:wN #4 \exp_after:wN #5 \c_nan_fp @ - } -\cs_new:Npn \@@_parse_apply_unary_type:NNN #1#2#3 - { - \@@_change_func_type:NNN #3 #1 \@@_parse_apply_unary_error:NNw - #2 #3 - } -\cs_new:Npn \@@_parse_apply_unary_error:NNw #1#2#3 @ - { \@@_invalid_operation_o:fw { \@@_func_to_name:N #1 } #3 } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_prefix_-:Nw, \@@_parse_prefix_!:Nw} -% The unary~|-| and boolean not are harder: we parse the operand using -% a precedence equal to the maximum of the previous precedence~|##1| -% and the precedence \cs{c_@@_prec_not_int} of the unary operator, then call -% the appropriate |\__fp_|\meta{operation}|_o:w| function, -% where the \meta{operation} is |set_sign| or |not|. -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1#2#3#4 - { - \cs_new:cpn { @@_parse_prefix_ #1 :Nw } ##1 - { - \exp_after:wN \@@_parse_apply_unary:NNNwN - \exp_after:wN ##1 - \exp_after:wN #4 - \exp_after:wN #3 - \exp:w - \if_int_compare:w #2 < ##1 - \@@_parse_operand:Nw ##1 - \else: - \@@_parse_operand:Nw #2 - \fi: - \@@_parse_expand:w - } - } -\@@_tmp:w - \c_@@_prec_not_int \@@_set_sign_o:w 2 -\@@_tmp:w ! \c_@@_prec_not_int \@@_not_o:w ? -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_prefix_.:Nw} -% Numbers which start with a decimal separator (a~period) end up here. -% Of course, we do not look for an operand, but for the rest of the -% number. This function is very similar to \cs{@@_parse_one_digit:NN} -% but calls \cs{@@_parse_strim_zeros:N} to trim zeros after the -% decimal point, rather than the \texttt{trim_zeros} function for -% zeros before the decimal point. -% \begin{macrocode} -\cs_new:cpn { @@_parse_prefix_.:Nw } #1 - { - \exp_after:wN \@@_parse_infix_after_operand:NwN - \exp_after:wN #1 - \exp:w \exp_end_continue_f:w - \exp_after:wN \@@_sanitize:wN - \int_value:w \@@_int_eval:w 0 \@@_parse_strim_zeros:N - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP] -% {\@@_parse_prefix_(:Nw, \@@_parse_lparen_after:NwN} -% The left parenthesis is treated as a unary prefix operator because -% it appears in exactly the same settings. If the previous precedence -% is \cs{c_@@_prec_func_int} we are parsing arguments of a function -% and commas should not build tuples; otherwise commas should build -% tuples. We distinguish these cases by precedence: -% \cs{c_@@_prec_comma_int} for the case of arguments, -% \cs{c_@@_prec_tuple_int} for the case of tuples. -% Once the operand is found, the \texttt{lparen_after} auxiliary makes -% sure that there was a closing parenthesis (otherwise it complains), -% and leaves in the input stream an operand, -% fetching the following infix operator. -% \begin{macrocode} -\cs_new:cpn { @@_parse_prefix_(:Nw } #1 - { - \exp_after:wN \@@_parse_lparen_after:NwN - \exp_after:wN #1 - \exp:w - \if_int_compare:w #1 = \c_@@_prec_func_int - \@@_parse_operand:Nw \c_@@_prec_comma_int - \else: - \@@_parse_operand:Nw \c_@@_prec_tuple_int - \fi: - \@@_parse_expand:w - } -\cs_new:Npe \@@_parse_lparen_after:NwN #1#2 @ #3 - { - \exp_not:N \token_if_eq_meaning:NNTF #3 - \exp_not:c { @@_parse_infix_):N } - { - \exp_not:N \@@_exp_after_array_f:w #2 \s_@@_expr_stop - \exp_not:N \exp_after:wN - \exp_not:N \@@_parse_infix_after_paren:NN - \exp_not:N \exp_after:wN #1 - \exp_not:N \exp:w - \exp_not:N \@@_parse_expand:w - } - { - \exp_not:N \msg_expandable_error:nnn - { fp } { missing } { ) } - \exp_not:N \tl_if_empty:nT {#2} \exp_not:N \c_@@_empty_tuple_fp - #2 @ - \exp_not:N \use_none:n #3 - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_prefix_):Nw} -% The right parenthesis can appear as a prefix in two similar cases: -% in an empty tuple or tuple ending with a comma, or in an empty -% argument list or argument list ending with a comma, such as in -% |max(1,2,)| or in |rand()|. -% \begin{macrocode} -\cs_new:cpn { @@_parse_prefix_):Nw } #1 - { - \if_int_compare:w #1 = \c_@@_prec_comma_int - \else: - \if_int_compare:w #1 = \c_@@_prec_tuple_int - \exp_after:wN \c_@@_empty_tuple_fp \exp:w - \else: - \msg_expandable_error:nnn - { fp } { missing-number } { ) } - \exp_after:wN \c_nan_fp \exp:w - \fi: - \exp_end_continue_f:w - \fi: - \@@_parse_infix_after_paren:NN #1 ) - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Constants} -% -% \begin{macro}[EXP] -% { -% \@@_parse_word_inf:N , \@@_parse_word_nan:N , -% \@@_parse_word_pi:N , \@@_parse_word_deg:N , -% \@@_parse_word_true:N , \@@_parse_word_false:N , -% } -% Some words correspond to constant floating points. The floating -% point constant is left as a result of \cs{@@_parse_one:Nw} after -% expanding \cs{@@_parse_infix:NN}. -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1 #2 - { - \cs_new:cpn { @@_parse_word_#1:N } - { \exp_after:wN #2 \exp:w \exp_end_continue_f:w \@@_parse_infix:NN } - } -\@@_tmp:w { inf } \c_inf_fp -\@@_tmp:w { nan } \c_nan_fp -\@@_tmp:w { pi } \c_pi_fp -\@@_tmp:w { deg } \c_one_degree_fp -\@@_tmp:w { true } \c_one_fp -\@@_tmp:w { false } \c_zero_fp -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP] -% { -% \@@_parse_caseless_inf:N, -% \@@_parse_caseless_infinity:N, -% \@@_parse_caseless_nan:N -% } -% Copies of \cs[no-index]{@@_parse_word_\ldots{}:N} commands, to allow -% arbitrary case as mandated by the standard. -% \begin{macrocode} -\cs_new_eq:NN \@@_parse_caseless_inf:N \@@_parse_word_inf:N -\cs_new_eq:NN \@@_parse_caseless_infinity:N \@@_parse_word_inf:N -\cs_new_eq:NN \@@_parse_caseless_nan:N \@@_parse_word_nan:N -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP] -% { -% \@@_parse_word_pt:N , \@@_parse_word_in:N , -% \@@_parse_word_pc:N , \@@_parse_word_cm:N , \@@_parse_word_mm:N , -% \@@_parse_word_dd:N , \@@_parse_word_cc:N , \@@_parse_word_nd:N , -% \@@_parse_word_nc:N , \@@_parse_word_bp:N , \@@_parse_word_sp:N , -% } -% Dimension units are also floating point constants but their value is -% not stored as a floating point constant. We give the values -% explicitly here. -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1 #2 - { - \cs_new:cpn { @@_parse_word_#1:N } - { - \@@_exp_after_f:nw { \@@_parse_infix:NN } - \s_@@ \@@_chk:w 10 #2 ; - } - } -\@@_tmp:w {pt} { {1} {1000} {0000} {0000} {0000} } -\@@_tmp:w {in} { {2} {7227} {0000} {0000} {0000} } -\@@_tmp:w {pc} { {2} {1200} {0000} {0000} {0000} } -\@@_tmp:w {cm} { {2} {2845} {2755} {9055} {1181} } -\@@_tmp:w {mm} { {1} {2845} {2755} {9055} {1181} } -\@@_tmp:w {dd} { {1} {1070} {0085} {6496} {0630} } -\@@_tmp:w {cc} { {2} {1284} {0102} {7795} {2756} } -\@@_tmp:w {nd} { {1} {1066} {9783} {4645} {6693} } -\@@_tmp:w {nc} { {2} {1280} {3740} {1574} {8031} } -\@@_tmp:w {bp} { {1} {1003} {7500} {0000} {0000} } -\@@_tmp:w {sp} { {-4} {1525} {8789} {0625} {0000} } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_word_em:N, \@@_parse_word_ex:N} -% The font-dependent units |em| and |ex| must be evaluated on the fly. -% We reuse an auxiliary of \cs{dim_to_fp:n}. -% \begin{macrocode} -\tl_map_inline:nn { {em} {ex} } - { - \cs_new:cpn { @@_parse_word_#1:N } - { - \exp_after:wN \@@_from_dim_test:ww - \exp_after:wN 0 \exp_after:wN , - \int_value:w \dim_to_decimal_in_sp:n { 1 #1 } \exp_after:wN ; - \exp:w \exp_end_continue_f:w \@@_parse_infix:NN - } - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Functions} -% -% ^^A begin[todo] -% -% \begin{macro}[EXP] -% {\@@_parse_unary_function:NNN, \@@_parse_function:NNN} -% \begin{macrocode} -\cs_new:Npn \@@_parse_unary_function:NNN #1#2#3 - { - \exp_after:wN \@@_parse_apply_unary:NNNwN - \exp_after:wN #3 - \exp_after:wN #2 - \exp_after:wN #1 - \exp:w - \@@_parse_operand:Nw \c_@@_prec_func_int \@@_parse_expand:w - } -\cs_new:Npn \@@_parse_function:NNN #1#2#3 - { - \exp_after:wN \@@_parse_apply_function:NNNwN - \exp_after:wN #3 - \exp_after:wN #2 - \exp_after:wN #1 - \exp:w - \@@_parse_operand:Nw \c_@@_prec_func_int \@@_parse_expand:w - } -% \end{macrocode} -% \end{macro} -% -% \subsection{Main functions} -% -% \begin{macro}[EXP]{\@@_parse:n, \@@_parse_o:n} -% \begin{macro}[EXP]{\@@_parse_after:ww} -% Start an \cs{exp:w} expansion so that \cs{@@_parse:n} expands -% in two steps. The \cs{@@_parse_operand:Nw} function performs -% computations until reaching an operation with precedence -% \cs{c_@@_prec_end_int} or less, namely, the end of the expression. The -% marker \cs{s_@@_expr_mark} indicates that the next token is an already -% parsed version of an infix operator, and \cs{@@_parse_infix_end:N} -% has infinitely negative precedence. Finally, clean up a -% (well-defined) set of extra tokens and stop the initial expansion -% with \cs{exp_end:}. -% \begin{macrocode} -\cs_new:Npn \@@_parse:n #1 - { - \exp:w - \exp_after:wN \@@_parse_after:ww - \exp:w - \@@_parse_operand:Nw \c_@@_prec_end_int - \@@_parse_expand:w #1 - \s_@@_expr_mark \@@_parse_infix_end:N - \s_@@_expr_stop - \exp_end: - } -\cs_new:Npn \@@_parse_after:ww - #1@ \@@_parse_infix_end:N \s_@@_expr_stop #2 { #2 #1 } -\cs_new:Npn \@@_parse_o:n #1 - { - \exp:w - \exp_after:wN \@@_parse_after:ww - \exp:w - \@@_parse_operand:Nw \c_@@_prec_end_int - \@@_parse_expand:w #1 - \s_@@_expr_mark \@@_parse_infix_end:N - \s_@@_expr_stop - { - \exp_end_continue_f:w - \@@_exp_after_any_f:nw { \exp_after:wN \exp_stop_f: } - } - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_operand:Nw} -% \begin{macro}[EXP]{\@@_parse_continue:NwN} -% This is just a shorthand which sets up both \cs{@@_parse_continue:NwN} -% and \cs{@@_parse_one:Nw} with the same precedence. Note the -% trailing \cs{exp:w}. -% \begin{macrocode} -\cs_new:Npn \@@_parse_operand:Nw #1 - { - \exp_end_continue_f:w - \exp_after:wN \@@_parse_continue:NwN - \exp_after:wN #1 - \exp:w \exp_end_continue_f:w - \exp_after:wN \@@_parse_one:Nw - \exp_after:wN #1 - \exp:w - } -\cs_new:Npn \@@_parse_continue:NwN #1 #2 @ #3 { #3 #1 #2 @ } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_apply_binary:NwNwN} -% \begin{macro}[EXP] -% {\@@_parse_apply_binary_chk:NN, \@@_parse_apply_binary_error:NNN} -% Receives \meta{precedence} \meta{operand_1} |@| \meta{operation} -% \meta{operand_2} |@| \meta{infix command}. Builds the appropriate -% call to the \meta{operation}~|#3|, dispatching on both types. -% If the resulting control sequence does not exist, the operation is -% not allowed. -% -% This is redefined in \pkg{l3fp-extras}. -% \begin{macrocode} -\cs_new:Npn \@@_parse_apply_binary:NwNwN #1 #2#3@ #4 #5#6@ #7 - { - \exp_after:wN \@@_parse_continue:NwN - \exp_after:wN #1 - \exp:w \exp_end_continue_f:w - \exp_after:wN \@@_parse_apply_binary_chk:NN - \cs:w - @@ - \@@_type_from_scan:N #2 - _#4 - \@@_type_from_scan:N #5 - _o:ww - \cs_end: - #4 - #2#3 #5#6 - \exp:w \exp_end_continue_f:w #7 #1 - } -\cs_new:Npn \@@_parse_apply_binary_chk:NN #1#2 - { - \if_meaning:w \scan_stop: #1 - \@@_parse_apply_binary_error:NNN #2 - \fi: - #1 - } -\cs_new:Npn \@@_parse_apply_binary_error:NNN #1#2#3 - { - #2 - \@@_invalid_operation_o:Nww #1 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_binary_type_o:Nww, \@@_binary_rev_type_o:Nww} -% Applies the operator |#1| to its two arguments, dispatching -% according to their types, and expands once after the result. -% The |rev| version swaps its arguments before doing this. -% \begin{macrocode} -\cs_new:Npn \@@_binary_type_o:Nww #1 #2#3 ; #4 - { - \exp_after:wN \@@_parse_apply_binary_chk:NN - \cs:w - @@ - \@@_type_from_scan:N #2 - _ #1 - \@@_type_from_scan:N #4 - _o:ww - \cs_end: - #1 - #2 #3 ; #4 - } -\cs_new:Npn \@@_binary_rev_type_o:Nww #1 #2#3 ; #4#5 ; - { - \exp_after:wN \@@_parse_apply_binary_chk:NN - \cs:w - @@ - \@@_type_from_scan:N #4 - _ #1 - \@@_type_from_scan:N #2 - _o:ww - \cs_end: - #1 - #4 #5 ; #2 #3 ; - } -% \end{macrocode} -% \end{macro} -% -% \subsection{Infix operators} -% -% \begin{macro}[EXP]{\@@_parse_infix_after_operand:NwN} -% \begin{macrocode} -\cs_new:Npn \@@_parse_infix_after_operand:NwN #1 #2; - { - \@@_exp_after_f:nw { \@@_parse_infix:NN #1 } - #2; - } -\cs_new:Npn \@@_parse_infix:NN #1 #2 - { - \if_catcode:w \scan_stop: \exp_not:N #2 - \if:w 0 \@@_str_if_eq:nn { \s_@@_expr_mark } { \exp_not:N #2 } - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_infix_mark:NNN - \else: - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_infix_juxt:N - \fi: - \else: - \if_int_compare:w - \@@_int_eval:w - ( `#2 \if_int_compare:w `#2 > `Z - 32 \fi: ) / 26 - = 3 \exp_stop_f: - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_infix_juxt:N - \else: - \exp_after:wN \@@_parse_infix_check:NNN - \cs:w - @@_parse_infix_ \token_to_str:N #2 :N - \exp_after:wN \exp_after:wN \exp_after:wN - \cs_end: - \fi: - \fi: - #1 - #2 - } -\cs_new:Npn \@@_parse_infix_check:NNN #1#2#3 - { - \if_meaning:w \scan_stop: #1 - \msg_expandable_error:nnn - { fp } { missing } { * } - \exp_after:wN \@@_parse_infix_mul:N - \exp_after:wN #2 - \exp_after:wN #3 - \else: - \exp_after:wN #1 - \exp_after:wN #2 - \exp:w \exp_after:wN \@@_parse_expand:w - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_parse_infix_after_paren:NN} -% Variant of \cs{@@_parse_infix:NN} for use after a closing -% parenthesis. The only difference is that \cs{@@_parse_infix_juxt:N} -% is replaced by \cs{@@_parse_infix_mul:N}. -% \begin{macrocode} -\cs_new:Npn \@@_parse_infix_after_paren:NN #1 #2 - { - \if_catcode:w \scan_stop: \exp_not:N #2 - \if:w 0 \@@_str_if_eq:nn { \s_@@_expr_mark } { \exp_not:N #2 } - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_infix_mark:NNN - \else: - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_infix_mul:N - \fi: - \else: - \if_int_compare:w - \@@_int_eval:w - ( `#2 \if_int_compare:w `#2 > `Z - 32 \fi: ) / 26 - = 3 \exp_stop_f: - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_parse_infix_mul:N - \else: - \exp_after:wN \@@_parse_infix_check:NNN - \cs:w - @@_parse_infix_ \token_to_str:N #2 :N - \exp_after:wN \exp_after:wN \exp_after:wN - \cs_end: - \fi: - \fi: - #1 - #2 - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Closing parentheses and commas} -% -% \begin{macro}[EXP]{\@@_parse_infix_mark:NNN} -% As an infix operator, \cs{s_@@_expr_mark} means that the next -% token~(|#3|) has already gone through \cs{@@_parse_infix:NN} and -% should be provided the precedence~|#1|. The scan mark~|#2| is -% discarded. -% \begin{macrocode} -\cs_new:Npn \@@_parse_infix_mark:NNN #1#2#3 { #3 #1 } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_infix_end:N} -% This one is a little bit odd: force every previous operator to end, -% regardless of the precedence. -% \begin{macrocode} -\cs_new:Npn \@@_parse_infix_end:N #1 - { @ \use_none:n \@@_parse_infix_end:N } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]+\@@_parse_infix_):N+ -% This is very similar to \cs{@@_parse_infix_end:N}, complaining about -% an extra closing parenthesis if the previous operator was the -% beginning of the expression, with precedence \cs{c_@@_prec_end_int}. -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1 - { - \cs_new:Npn #1 ##1 - { - \if_int_compare:w ##1 > \c_@@_prec_end_int - \exp_after:wN @ - \exp_after:wN \use_none:n - \exp_after:wN #1 - \else: - \msg_expandable_error:nnn { fp } { extra } { ) } - \exp_after:wN \@@_parse_infix:NN - \exp_after:wN ##1 - \exp:w \exp_after:wN \@@_parse_expand:w - \fi: - } - } -\exp_args:Nc \@@_tmp:w { @@_parse_infix_):N } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[verb, EXP]{\__fp_parse_infix_,:N} -% \begin{macro}[EXP]{\@@_parse_infix_comma:w, \@@_parse_apply_comma:NwNwN} -% As for other infix operations, if the previous operations has higher -% precedence the comma waits. Otherwise we call -% \cs{@@_parse_operand:Nw} to read more comma-delimited arguments that -% \cs{@@_parse_infix_comma:w} simply concatenates into a |@|-delimited -% array. The first comma in a tuple that is not a function argument -% is distinguished: in that case call \cs{@@_parse_apply_comma:NwNwN} -% whose job is to convert the first item of the tuple and an array of -% the remaining items into a tuple. In contrast to -% \cs{@@_parse_apply_binary:NwNwN} this function's operands are not -% single-object arrays. -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1 - { - \cs_new:Npn #1 ##1 - { - \if_int_compare:w ##1 > \c_@@_prec_comma_int - \exp_after:wN @ - \exp_after:wN \use_none:n - \exp_after:wN #1 - \else: - \if_int_compare:w ##1 < \c_@@_prec_comma_int - \exp_after:wN @ - \exp_after:wN \@@_parse_apply_comma:NwNwN - \exp_after:wN , - \exp:w - \else: - \exp_after:wN \@@_parse_infix_comma:w - \exp:w - \fi: - \@@_parse_operand:Nw \c_@@_prec_comma_int - \exp_after:wN \@@_parse_expand:w - \fi: - } - } -\exp_args:Nc \@@_tmp:w { @@_parse_infix_,:N } -\cs_new:Npn \@@_parse_infix_comma:w #1 @ - { #1 @ \use_none:n } -\cs_new:Npn \@@_parse_apply_comma:NwNwN #1 #2@ #3 #4@ #5 - { - \exp_after:wN \@@_parse_continue:NwN - \exp_after:wN #1 - \exp:w \exp_end_continue_f:w - \@@_exp_after_tuple_f:nw { } - \s_@@_tuple \@@_tuple_chk:w { #2 #4 } ; - #5 #1 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{Usual infix operators} -% -% \begin{macro}[EXP] -% { -% \@@_parse_infix_+:N, \@@_parse_infix_-:N, -% \@@_parse_infix_juxt:N, -% \@@_parse_infix_/:N, \@@_parse_infix_mul:N, -% \@@_parse_infix_and:N, \@@_parse_infix_or:N, -% } -% \begin{macro}[EXP]+\@@_parse_infix_^:N+ -% As described in the \enquote{work plan}, each infix operator has an -% associated |\..._infix_...| function, a computing function, and -% precedence, given as arguments to \cs{@@_tmp:w}. Using the general -% mechanism for arithmetic operations. The power operation must be -% associative in the opposite order from all others. For this, we use -% two distinct precedences. -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1#2#3#4 - { - \cs_new:Npn #1 ##1 - { - \if_int_compare:w ##1 < #3 - \exp_after:wN @ - \exp_after:wN \@@_parse_apply_binary:NwNwN - \exp_after:wN #2 - \exp:w - \@@_parse_operand:Nw #4 - \exp_after:wN \@@_parse_expand:w - \else: - \exp_after:wN @ - \exp_after:wN \use_none:n - \exp_after:wN #1 - \fi: - } - } -\exp_args:Nc \@@_tmp:w { @@_parse_infix_^:N } ^ - \c_@@_prec_hatii_int \c_@@_prec_hat_int -\exp_args:Nc \@@_tmp:w { @@_parse_infix_juxt:N } * - \c_@@_prec_juxt_int \c_@@_prec_juxt_int -\exp_args:Nc \@@_tmp:w { @@_parse_infix_/:N } / - \c_@@_prec_times_int \c_@@_prec_times_int -\exp_args:Nc \@@_tmp:w { @@_parse_infix_mul:N } * - \c_@@_prec_times_int \c_@@_prec_times_int -\exp_args:Nc \@@_tmp:w { @@_parse_infix_-:N } - - \c_@@_prec_plus_int \c_@@_prec_plus_int -\exp_args:Nc \@@_tmp:w { @@_parse_infix_+:N } + - \c_@@_prec_plus_int \c_@@_prec_plus_int -\exp_args:Nc \@@_tmp:w { @@_parse_infix_and:N } & - \c_@@_prec_and_int \c_@@_prec_and_int -\exp_args:Nc \@@_tmp:w { @@_parse_infix_or:N } | - \c_@@_prec_or_int \c_@@_prec_or_int -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{Juxtaposition} -% -% \begin{macro}[EXP]+\@@_parse_infix_(:N+ -% When an opening parenthesis appears where we expect an infix -% operator, we compute the product of the previous operand and the -% contents of the parentheses using \cs{@@_parse_infix_mul:N}. -% \begin{macrocode} -\cs_new:cpn { @@_parse_infix_(:N } #1 - { \@@_parse_infix_mul:N #1 ( } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Multi-character cases} -% -% \begin{macro}[EXP]{\@@_parse_infix_*:N} -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1 - { - \cs_new:cpn { @@_parse_infix_*:N } ##1##2 - { - \if:w * \exp_not:N ##2 - \exp_after:wN #1 - \exp_after:wN ##1 - \else: - \exp_after:wN \@@_parse_infix_mul:N - \exp_after:wN ##1 - \exp_after:wN ##2 - \fi: - } - } -\exp_args:Nc \@@_tmp:w { @@_parse_infix_^:N } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]+\@@_parse_infix_|:Nw+ -% \begin{macro}[EXP]+\@@_parse_infix_&:Nw+ -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1#2#3 - { - \cs_new:Npn #1 ##1##2 - { - \if:w #2 \exp_not:N ##2 - \exp_after:wN #1 - \exp_after:wN ##1 - \exp:w \exp_after:wN \@@_parse_expand:w - \else: - \exp_after:wN #3 - \exp_after:wN ##1 - \exp_after:wN ##2 - \fi: - } - } -\exp_args:Nc \@@_tmp:w { @@_parse_infix_|:N } | \@@_parse_infix_or:N -\exp_args:Nc \@@_tmp:w { @@_parse_infix_&:N } & \@@_parse_infix_and:N -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsubsection{Ternary operator} -% -% \begin{macro}[EXP]{\@@_parse_infix_?:N, \@@_parse_infix_::N} -% \begin{macrocode} -\cs_set_protected:Npn \@@_tmp:w #1#2#3#4 - { - \cs_new:Npn #1 ##1 - { - \if_int_compare:w ##1 < \c_@@_prec_quest_int - #4 - \exp_after:wN @ - \exp_after:wN #2 - \exp:w - \@@_parse_operand:Nw #3 - \exp_after:wN \@@_parse_expand:w - \else: - \exp_after:wN @ - \exp_after:wN \use_none:n - \exp_after:wN #1 - \fi: - } - } -\exp_args:Nc \@@_tmp:w { @@_parse_infix_?:N } - \@@_ternary:NwwN \c_@@_prec_quest_int { } -\exp_args:Nc \@@_tmp:w { @@_parse_infix_::N } - \@@_ternary_auxii:NwwN \c_@@_prec_colon_int - { - \msg_expandable_error:nnnn - { fp } { missing } { ? } { ~for~?: } - } -% \end{macrocode} -% \end{macro} -% -% \subsubsection{Comparisons} -% -% \begin{macro}[EXP] -% { -% \@@_parse_infix_<:N, \@@_parse_infix_=:N, -% \@@_parse_infix_>:N, \@@_parse_infix_!:N -% } -% \begin{macro}[EXP] -% { -% \@@_parse_excl_error:, -% \@@_parse_compare:NNNNNNN, -% \@@_parse_compare_auxi:NNNNNNN, -% \@@_parse_compare_auxii:NNNNN, -% \@@_parse_compare_end:NNNNw, -% \@@_compare:wNNNNw, -% } -% \begin{macrocode} -\cs_new:cpn { @@_parse_infix_<:N } #1 - { \@@_parse_compare:NNNNNNN #1 1 0 0 0 0 < } -\cs_new:cpn { @@_parse_infix_=:N } #1 - { \@@_parse_compare:NNNNNNN #1 1 0 0 0 0 = } -\cs_new:cpn { @@_parse_infix_>:N } #1 - { \@@_parse_compare:NNNNNNN #1 1 0 0 0 0 > } -\cs_new:cpn { @@_parse_infix_!:N } #1 - { - \exp_after:wN \@@_parse_compare:NNNNNNN - \exp_after:wN #1 - \exp_after:wN 0 - \exp_after:wN 1 - \exp_after:wN 1 - \exp_after:wN 1 - \exp_after:wN 1 - } -\cs_new:Npn \@@_parse_excl_error: - { - \msg_expandable_error:nnnn - { fp } { missing } { = } { ~after~!. } - } -\cs_new:Npn \@@_parse_compare:NNNNNNN #1 - { - \if_int_compare:w #1 < \c_@@_prec_comp_int - \exp_after:wN \@@_parse_compare_auxi:NNNNNNN - \exp_after:wN \@@_parse_excl_error: - \else: - \exp_after:wN @ - \exp_after:wN \use_none:n - \exp_after:wN \@@_parse_compare:NNNNNNN - \fi: - } -\cs_new:Npn \@@_parse_compare_auxi:NNNNNNN #1#2#3#4#5#6#7 - { - \if_case:w - \@@_int_eval:w \exp_after:wN ` \token_to_str:N #7 - `< - \@@_int_eval_end: - \@@_parse_compare_auxii:NNNNN #2#2#4#5#6 - \or: \@@_parse_compare_auxii:NNNNN #2#3#2#5#6 - \or: \@@_parse_compare_auxii:NNNNN #2#3#4#2#6 - \or: \@@_parse_compare_auxii:NNNNN #2#3#4#5#2 - \else: #1 \@@_parse_compare_end:NNNNw #3#4#5#6#7 - \fi: - } -\cs_new:Npn \@@_parse_compare_auxii:NNNNN #1#2#3#4#5 - { - \exp_after:wN \@@_parse_compare_auxi:NNNNNNN - \exp_after:wN \prg_do_nothing: - \exp_after:wN #1 - \exp_after:wN #2 - \exp_after:wN #3 - \exp_after:wN #4 - \exp_after:wN #5 - \exp:w \exp_after:wN \@@_parse_expand:w - } -\cs_new:Npn \@@_parse_compare_end:NNNNw #1#2#3#4#5 \fi: - { - \fi: - \exp_after:wN @ - \exp_after:wN \@@_parse_apply_compare:NwNNNNNwN - \exp_after:wN \c_one_fp - \exp_after:wN #1 - \exp_after:wN #2 - \exp_after:wN #3 - \exp_after:wN #4 - \exp:w - \@@_parse_operand:Nw \c_@@_prec_comp_int \@@_parse_expand:w #5 - } -\cs_new:Npn \@@_parse_apply_compare:NwNNNNNwN - #1 #2@ #3 #4#5#6#7 #8@ #9 - { - \if_int_odd:w - \if_meaning:w \c_zero_fp #3 - 0 - \else: - \if_case:w \@@_compare_back_any:ww #8 #2 \exp_stop_f: - #5 \or: #6 \or: #7 \else: #4 - \fi: - \fi: - \exp_stop_f: - \exp_after:wN \@@_parse_apply_compare_aux:NNwN - \exp_after:wN \c_one_fp - \else: - \exp_after:wN \@@_parse_apply_compare_aux:NNwN - \exp_after:wN \c_zero_fp - \fi: - #1 #8 #9 - } -\cs_new:Npn \@@_parse_apply_compare_aux:NNwN #1 #2 #3; #4 - { - \if_meaning:w \@@_parse_compare:NNNNNNN #4 - \exp_after:wN \@@_parse_continue_compare:NNwNN - \exp_after:wN #1 - \exp_after:wN #2 - \exp:w \exp_end_continue_f:w - \@@_exp_after_o:w #3; - \exp:w \exp_end_continue_f:w - \else: - \exp_after:wN \@@_parse_continue:NwN - \exp_after:wN #2 - \exp:w \exp_end_continue_f:w - \exp_after:wN #1 - \exp:w \exp_end_continue_f:w - \fi: - #4 #2 - } -\cs_new:Npn \@@_parse_continue_compare:NNwNN #1#2 #3@ #4#5 - { #4 #2 #3@ #1 } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Tools for functions} -% -% \begin{macro}[EXP]{\@@_parse_function_all_fp_o:fnw} -% Followed by \Arg{function name} \Arg{code} \meta{float array} |@| -% this checks all floats are floating point numbers (no tuples). -% \begin{macrocode} -\cs_new:Npn \@@_parse_function_all_fp_o:fnw #1#2#3 @ - { - \@@_array_if_all_fp:nTF {#3} - { #2 #3 @ } - { - \@@_error:nffn { bad-args } - {#1} - { \fp_to_tl:n { \s_@@_tuple \@@_tuple_chk:w {#3} ; } } - { } - \exp_after:wN \c_nan_fp - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_parse_function_one_two:nnw} -% \begin{macro}[EXP] -% { -% \@@_parse_function_one_two_error_o:w, -% \@@_parse_function_one_two_aux:nnw, -% \@@_parse_function_one_two_auxii:nnw -% } -% This is followed by \Arg{function name} \Arg{code} \meta{float -% array} |@|. It checks that the \meta{float array} consists of one -% or two floating point numbers (not tuples), then leaves the -% \meta{code} (if there is one float) or its tail (if there are two -% floats) followed by the \meta{float array}. The \meta{code} should -% start with a single token such as \cs{@@_atan_default:w} that deals -% with the single-float case. -% -% The first \cs{@@_if_type_fp:NTwFw} test catches the case of no -% argument and the case of a tuple argument. The next one -% distinguishes the case of a single argument (no error, just add -% \cs{c_one_fp}) from a tuple second argument. Finally check there is -% no further argument. -% \begin{macrocode} -\cs_new:Npn \@@_parse_function_one_two:nnw #1#2#3 - { - \@@_if_type_fp:NTwFw - #3 { } \s_@@ \@@_parse_function_one_two_error_o:w \s_@@_stop - \@@_parse_function_one_two_aux:nnw {#1} {#2} #3 - } -\cs_new:Npn \@@_parse_function_one_two_error_o:w #1#2#3#4 @ - { - \@@_error:nffn { bad-args } - {#2} - { \fp_to_tl:n { \s_@@_tuple \@@_tuple_chk:w {#4} ; } } - { } - \exp_after:wN \c_nan_fp - } -\cs_new:Npn \@@_parse_function_one_two_aux:nnw #1#2 #3; #4 - { - \@@_if_type_fp:NTwFw - #4 { } - \s_@@ - { - \if_meaning:w @ #4 - \exp_after:wN \use_iv:nnnn - \fi: - \@@_parse_function_one_two_error_o:w - } - \s_@@_stop - \@@_parse_function_one_two_auxii:nnw {#1} {#2} #3; #4 - } -\cs_new:Npn \@@_parse_function_one_two_auxii:nnw #1#2#3; #4; #5 - { - \if_meaning:w @ #5 \else: - \exp_after:wN \@@_parse_function_one_two_error_o:w - \fi: - \use_ii:nn {#1} { \use_none:n #2 } #3; #4; #5 - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_tuple_map_o:nw, \@@_tuple_map_loop_o:nw} -% Apply |#1| to all items in the following tuple and expand once -% afterwards. The code |#1| should itself expand once after its -% result. -% \begin{macrocode} -\cs_new:Npn \@@_tuple_map_o:nw #1 \s_@@_tuple \@@_tuple_chk:w #2 ; - { - \exp_after:wN \s_@@_tuple - \exp_after:wN \@@_tuple_chk:w - \exp_after:wN { - \exp:w \exp_end_continue_f:w - \@@_tuple_map_loop_o:nw {#1} #2 - { \s_@@ \prg_break: } ; - \prg_break_point: - \exp_after:wN } \exp_after:wN ; - } -\cs_new:Npn \@@_tuple_map_loop_o:nw #1#2#3 ; - { - \use_none:n #2 - #1 #2 #3 ; - \exp:w \exp_end_continue_f:w - \@@_tuple_map_loop_o:nw {#1} - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_tuple_mapthread_o:nww, \@@_tuple_mapthread_loop_o:nw} -% Apply |#1| to pairs of items in the two following tuples and expand once -% afterwards. -% \begin{macrocode} -\cs_new:Npn \@@_tuple_mapthread_o:nww #1 - \s_@@_tuple \@@_tuple_chk:w #2 ; - \s_@@_tuple \@@_tuple_chk:w #3 ; - { - \exp_after:wN \s_@@_tuple - \exp_after:wN \@@_tuple_chk:w - \exp_after:wN { - \exp:w \exp_end_continue_f:w - \@@_tuple_mapthread_loop_o:nw {#1} - #2 { \s_@@ \prg_break: } ; @ - #3 { \s_@@ \prg_break: } ; - \prg_break_point: - \exp_after:wN } \exp_after:wN ; - } -\cs_new:Npn \@@_tuple_mapthread_loop_o:nw #1#2#3 ; #4 @ #5#6 ; - { - \use_none:n #2 - \use_none:n #5 - #1 #2 #3 ; #5 #6 ; - \exp:w \exp_end_continue_f:w - \@@_tuple_mapthread_loop_o:nw {#1} #4 @ - } -% \end{macrocode} -% \end{macro} -% -% ^^A end[todo] -% -% \subsection{Messages} -% -% \begin{macrocode} -\msg_new:nnn { fp } { deprecated } - { '#1'~deprecated;~use~'#2' } -\msg_new:nnn { fp } { unknown-fp-word } - { Unknown~fp~word~#1. } -\msg_new:nnn { fp } { missing } - { Missing~#1~inserted #2. } -\msg_new:nnn { fp } { extra } - { Extra~#1~ignored. } -\msg_new:nnn { fp } { early-end } - { Premature~end~in~fp~expression. } -\msg_new:nnn { fp } { after-e } - { Cannot~use~#1 after~'e'. } -\msg_new:nnn { fp } { missing-number } - { Missing~number~before~'#1'. } -\msg_new:nnn { fp } { unknown-symbol } - { Unknown~symbol~#1~ignored. } -\msg_new:nnn { fp } { extra-comma } - { Unexpected~comma~turned~to~nan~result. } -\msg_new:nnn { fp } { no-arg } - { #1~got~no~argument;~used~nan. } -\msg_new:nnn { fp } { multi-arg } - { #1~got~more~than~one~argument;~used~nan. } -\msg_new:nnn { fp } { num-args } - { #1~expects~between~#2~and~#3~arguments. } -\msg_new:nnn { fp } { bad-args } - { Arguments~in~#1#2~are~invalid. } -\msg_new:nnn { fp } { infty-pi } - { Math~command~#1 is~not~an~fp } -\cs_if_exist:cT { @unexpandable@protect } - { - \msg_new:nnn { fp } { robust-cmd } - { Robust~command~#1 invalid~in~fp~expression! } - } -% \end{macrocode} -% -% \begin{macrocode} -%</package> -% \end{macrocode} -% -% \end{implementation} -% -% \PrintChanges -% -% \PrintIndex |