% \iffalse %% File: l3intexpr.dtx Copyright (C) 2009 LaTeX3 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 %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the ``expl3 bundle'' (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX Project Team. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} % %\fi \GetIdInfo$Id: l3intexpr.dtx 1086 2009-03-20 19:29:35Z morten $ {L3 Integer Expressions} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass[full]{l3doc} \begin{document} \DocInput{\filename.\filenameext} \end{document} % % \fi % % % \title{The \textsf{l3intexpr} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Integer expressions} % \author{\Team} % \date{\filedate} % \maketitle % % \begin{documentation} % % Calculation and comparison of integer values can be carried out % using literal numbers, \texttt{int} registers, constants and % integers stored in token list variables. The standard operators % \texttt{+}, \texttt{-}, \texttt{/} and \texttt{*} and % parentheses can be used within such expressions to carry % arithmetic operations. This module carries out these functions % on \emph{integer expressions} (`\texttt{int expr}'). % %\section{Calculating and comparing integers} % % \begin{function}{\intexpr_eval:n / (EXP)} % \begin{syntax} % "\intexpr_eval:n" \Arg{int~expr} % \end{syntax} % Evaluates an , expanding to a properly % terminated that can be used in any situation that % demands one, or which can be typeset. For example, %\begin{verbatim} % \intexpr_eval:n{ 5 + 4*3 - (3+4*5) } %\end{verbatim} % evaluates to \(-6\). Two expansions are necessary to convert the % into the it represents. Full expansion to % the can be carried out using an \texttt{f} expansion % in an expandable context or a \texttt{x} expansion in other % cases. % \end{function} % %\begin{function}{ % \intexpr_compare_p:n / (EXP) | % \intexpr_compare:n / (TF) (EXP) %} % \begin{syntax} % "\intexpr_compare_p:n" \Arg{ } % "\intexpr_compare:nTF" \Arg{ } % ~~~~ % \end{syntax} % Evaluates and as % described for \cs{intexpr_eval:n}, and then carries out a % comparison of the resulting integers using C-like operators: % \begin{center} % \begin{tabular}{ll@{\hspace{2cm}}ll} % Less than & "<" & Less than or equal & "<=" \\ % Greater than & "<" & Greater than or equal & ">=" \\ % Equal & "==" or "=" & Not equal & "!=" % \end{tabular} % \end{center} % Based on the result of the comparison either the % or is executed. Both integer expressions are evaluated % fully in the process. Note the syntax, which allows natural input in % the style of % \begin{quote} % |\intexpr_compare_p:n {5+3 != \l_tmpb_int}| % \end{quote} % \texttt{=} is available as comparator (in addition to those % familiar to C users) as standard \TeX\ practice is to compare % values using a single \texttt{=}. % \end{function} % % %\begin{function}{ % \intexpr_compare_p:nNn / (EXP) | % \intexpr_compare:nNn / (TF)(EXP) %} % \begin{syntax} % "\intexpr_compare_p:nNn" \Arg{int~expr1} \Arg{int~expr2} % \end{syntax} % Evaluates and as % described for \cs{intexpr_eval:n}, then compares the two % results using one of the relations \texttt{=}, "<" or % ">". These functions are faster than the \texttt{n} % variants described above but do not support an extended set % of relational operators. %\end{function} % % %\begin{function}{ % \intexpr_max:nn / (EXP)| % \intexpr_min:nn / (EXP) %} % \begin{syntax} % "\intexpr_max:nn" \Arg{int~expr1} \Arg{int~expr2} % \end{syntax} % Evaluates and as % described for \cs{intexpr_eval:n}, expanding to the larger or % smaller of the two resulting (for \texttt{max} and % \texttt{min}, respectively). % \end{function} % %\begin{function}{\intexpr_abs:n / (EXP)} % \begin{syntax} % "\intexpr_abs:n" \Arg{int~expr} % \end{syntax} % Evaluates as described for \cs{intexpr_eval:n} % and expands to the absolute value of the resulting . % \end{function} % %\begin{function}{ % \intexpr_if_odd:n / (EXP)(TF) | % \intexpr_if_odd_p:n / (EXP) | % \intexpr_if_even:n / (EXP)(TF) | % \intexpr_if_even_p:n / (EXP) | %} % \begin{syntax} % "\intexpr_if_odd:nTF" \Arg{int~expr} \Arg{true} \Arg{false} % \end{syntax} % Evaluates as described for \cs{intexpr_eval:n} % and execute or depending on whether % the resulting is odd or even. % \end{function} % %\begin{function}{ % \intexpr_div_truncate:nn / (EXP) | % \intexpr_div_round:nn / (EXP) | % \intexpr_mod:nn / (EXP) | %} % \begin{syntax} % "\intexpr_div_truncate:nn" \Arg{int~expr1} \Arg{int~expr2} % "\intexpr_mod:nn" \Arg{int~expr1} \Arg{int~expr2} % \end{syntax} % Evaluates and as % described for \cs{intexpr_eval:n}, expanding to the appropriate % result of division of the resulting . The % \texttt{truncate} function expands to the integer part of the % division with the decimal simply discarded, whereas % \texttt{round} will use the decimal part to round the integer % up if appropriate. The \texttt{mod} function expands to the integer % remainder of the division. %\end{function} % % \section{Primitive (internal) functions} % %\begin{function}{ % \if_num:w / (EXP) | % \if_inexpr_compare:w / (EXP) %} % \begin{syntax} % "\if_num:w" "\else:" "\fi:" % \end{syntax} % Compare two integers using , which must be one of % \texttt{=}, "<" or ">" with category code \(12\). % The \cs{else:} branch is optional. % \begin{texnote} % These are both names for the \TeX\ primitive \cs{ifnum}. % \end{texnote} %\end{function} % %\begin{function}{ % \if_intexpr_case:w / (EXP) | % \if_case:w / (EXP) | % \or: / (EXP) %} % \begin{syntax} % "\if_case:w" "\or:" "\or:" "..." "\else:" % "\fi:" % \end{syntax} % Selects a case to execute based on the value of . The first % case () is executed if is \(0\), the second % () if the is \(1\), \emph{etc}. The % may be a literal, a constant or an integer % expression (\emph{e.g}.~using \cs{intexpr_eval:n}). % \begin{texnote} % These are the \TeX\ primitives \cs{ifcase} (with two % different names depending on context) and \cs{or}. % \end{texnote} %\end{function} % %\begin{function}{\intexpr_value:w / (EXP)} % \begin{syntax} % "\intexpr_value:w" % "\intexpr_value:w" % \end{syntax} % Expands until an is formed. One space may be % gobbled in the process. % \begin{texnote} % This is the \TeX\ primitive \tn{number}. % \end{texnote} %\end{function} % %\begin{function}{ % \intexpr_eval:w / (EXP) | % \intexpr_eval_end: %} % \begin{syntax} % "\intexpr_eval:w" "\intexpr_eval_end:" % \end{syntax} % Evaluates as described for \cs{intexpr_eval:n}. % The evalution stops when an unexpandable token with category code % other than \(12\) is read or when \cs{intexpr_eval_end:} is % reached. The latter is gobbled by the scanner mechanism: % \cs{intexpr_eval_end:} itself is unexpandable but used correctly % the entire construct is expandable. % \begin{texnote} % This is the \eTeX\ primitive \cs{numexpr}. % \end{texnote} %\end{function} % %\begin{function}{\if_intexpr_odd:w / (EXP)} % \begin{syntax} % "\if_intexpr_odd:w" "\else:" "\fi:" % "\if_intexpr_odd:w" "\else:" "\fi:" % \end{syntax} % Expands until a non-numeric tokens is found, and % tests whether the resulting is odd. If so, % is executed. The \cs{else:} branch is optional. % \begin{texnote} % This is the \TeX\ primitive \cs{ifodd}. % \end{texnote} %\end{function} % %\begin{function}{ % \intexpr_while_do:nn / (EXP) | % \intexpr_until_do:nn / (EXP) | % \intexpr_do_while:nn / (EXP) | % \intexpr_do_until:nn / (EXP) %} % \begin{syntax} % "\intexpr_while_do:nn" \Arg{ } \Arg{code} % \end{syntax} % In the case of the \texttt{while_do} version, the integer % comparison is evaluated as described for \cs{intexpr_compare_p:n}, % and if \texttt{true} execute the . The test and code then % alternate until the result is . The \texttt{do_while} % alternative first executes the and then evaluates the integer % comparison. In the \texttt{until} cases, the is executed % if the test is \texttt{false}: the loop is ended when the relation % is \texttt{true}. % \end{function} % %\begin{function}{ % \intexpr_while_do:nNnn / (EXP) | % \intexpr_until_do:nNnn / (EXP) | % \intexpr_do_while:nNnn / (EXP) | % \intexpr_do_until:nNnn / (EXP) %} % \begin{syntax} % "\intexpr_while_do:nNnn" \Arg{code} % \end{syntax} % These behave in the same manner as the preceding loops but use the % relation logic described for \cs{intexpr_compare_p:nNn}. %\end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3intexpr} implementation} % % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %<*package> \ProvidesExplPackage {\filename}{\filedate}{\fileversion}{\filedescription} \package_check_loaded_expl: % %<*initex|package> % \end{macrocode} % % \begin{macro}{\if_num:w} % \begin{macro}{\if_case:w} % Here are the remaining primitives for number comparisons and % expressions. % \begin{macrocode} \cs_new_eq:NN \if_num:w \tex_ifnum:D \cs_new_eq:NN \if_case:w \tex_ifcase:D % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\intexpr_value:w} % \begin{macro}{\intexpr_eval:n,\intexpr_eval:w,\intexpr_eval_end:} % \begin{macro}{\if_intexpr_compare:w} % \begin{macro}{\if_intexpr_odd:w} % \begin{macro}{\if_intexpr_case:w} % Here are the remaining primitives for number comparisons and % expressions. % \begin{macrocode} \cs_set_eq:NN \intexpr_value:w \tex_number:D \cs_set_eq:NN \intexpr_eval:w \etex_numexpr:D \cs_set_protected:Npn \intexpr_eval_end: {\tex_relax:D} \cs_set_eq:NN \if_intexpr_compare:w \tex_ifnum:D \cs_set_eq:NN \if_intexpr_odd:w \tex_ifodd:D \cs_set_eq:NN \if_intexpr_case:w \tex_ifcase:D \cs_set:Npn \intexpr_eval:n #1{ \intexpr_value:w \intexpr_eval:w #1\intexpr_eval_end: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % % % % % \begin{macro}{\intexpr_compare_p:n} % \begin{macro}[TF]{\intexpr_compare:n} % Comparison tests using a simple syntax where only one set of braces % is required and additional operators such as "!=" and ">=" are % supported. First some notes on the idea behind this. We wish to % support writing code like % \begin{verbatim} % \intexpr_compare_p:n { 5 + \l_tmpa_int != 4 - \l_tmpb_int } % \end{verbatim} % In other words, we want to somehow add the missing "\intexpr_eval:w" % where required. We can start evaluating from the left using % "\intexpr:w", and we know that since the relation symbols "<", ">", % "=" and "!" are not allowed in such expressions, they will terminate % the expression. Therefore, we first let \TeX\ evaluate this left % hand side of the (in)equality. % \begin{macrocode} \prg_set_conditional:Npnn \intexpr_compare:n #1{p,TF,T,F}{ \exp_after:wN \intexpr_compare_auxi:w \intexpr_value:w \intexpr_eval:w #1\q_stop } % \end{macrocode} % Then the next step is to figure out which relation we should use, so % we have to somehow get rid of the first evaluation so that we can % see what stopped it. "\tex_romannumeral:D" is handy here since its % expansion given a non-positive number is \m{null}. We therefore % simply check if the first token of the left hand side evaluation is % a minus. If not, we insert it and issue "\tex_romannumeral:D", % thereby ridding us of the left hand side evaluation. We do however % save it for later. % \begin{macrocode} \cs_set:Npn \intexpr_compare_auxi:w #1#2\q_stop{ \exp_after:wN \intexpr_compare_auxii:w \tex_romannumeral:D \if:w #1- \else: -\fi: #1#2 \q_stop #1#2 \q_nil } % \end{macrocode} % This leaves the first relation symbol in front and assuming the % right hand side has been input, at least one other token as well. We % support the following forms: |=|, |<|, |>| and the extended |!=|, % |==|, |<=| and |>=|. All the extended forms have an extra |=| so we % check if that is present as well. Then use specific function to % perform the test. % \begin{macrocode} \cs_set:Npn \intexpr_compare_auxii:w #1#2#3\q_stop{ \use:c{ intexpr_compare_ #1 \if_meaning:w =#2 = \fi: :w} } % \end{macrocode} % The actual comparisons are then simple function calls, using the % relation as delimiter for a delimited argument. % Equality is easy: % \begin{macrocode} \cs_set:cpn {intexpr_compare_=:w} #1=#2\q_nil{ \if_intexpr_compare:w #1=\intexpr_eval:w #2 \intexpr_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % So is the one using |==| -- we just have to use |==| in the % parameter text. % \begin{macrocode} \cs_set:cpn {intexpr_compare_==:w} #1==#2\q_nil{ \if_intexpr_compare:w #1=\intexpr_eval:w #2 \intexpr_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % Not equal is just about reversing the truth value. % \begin{macrocode} \cs_set:cpn {intexpr_compare_!=:w} #1!=#2\q_nil{ \if_intexpr_compare:w #1=\intexpr_eval:w #2 \intexpr_eval_end: \prg_return_false: \else: \prg_return_true: \fi: } % \end{macrocode} % Less than and greater than are also straight forward. % \begin{macrocode} \cs_set:cpn {intexpr_compare_<:w} #1<#2\q_nil{ \if_intexpr_compare:w #1<\intexpr_eval:w #2 \intexpr_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } \cs_set:cpn {intexpr_compare_>:w} #1>#2\q_nil{ \if_intexpr_compare:w #1>\intexpr_eval:w #2 \intexpr_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % The less than or equal operation is just the opposite of the greater % than operation. Vice versa for less than or equal. % \begin{macrocode} \cs_set:cpn {intexpr_compare_<=:w} #1<=#2\q_nil{ \if_intexpr_compare:w #1>\intexpr_eval:w #2 \intexpr_eval_end: \prg_return_false: \else: \prg_return_true: \fi: } \cs_set:cpn {intexpr_compare_>=:w} #1>=#2\q_nil{ \if_intexpr_compare:w #1<\intexpr_eval:w #2 \intexpr_eval_end: \prg_return_false: \else: \prg_return_true: \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\intexpr_compare_p:nNn} % \begin{macro}[TF]{\intexpr_compare:nNn} % More efficient but less natural in typing. % \begin{macrocode} \prg_set_conditional:Npnn \intexpr_compare:nNn #1#2#3{p,TF,T,F}{ \if_intexpr_compare:w \intexpr_eval:w #1 #2 \intexpr_eval:w #3 \intexpr_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\intexpr_max:nn} % \begin{macro}{\intexpr_min:nn} % \begin{macro}{\intexpr_abs:n} % Functions for $\min$, $\max$, and absolute value. % \begin{macrocode} \cs_set:Npn \intexpr_abs:n #1{ \intexpr_value:w \if_intexpr_compare:w \intexpr_eval:w #1<\c_zero - \fi: \intexpr_eval:w #1\intexpr_eval_end: } \cs_set:Npn \intexpr_max:nn #1#2{ \intexpr_value:w \intexpr_eval:w \if_intexpr_compare:w \intexpr_eval:w #1>\intexpr_eval:w #2\intexpr_eval_end: #1 \else: #2 \fi: \intexpr_eval_end: } \cs_set:Npn \intexpr_min:nn #1#2{ \intexpr_value:w \intexpr_eval:w \if_intexpr_compare:w \intexpr_eval:w #1<\intexpr_eval:w #2\intexpr_eval_end: #1 \else: #2 \fi: \intexpr_eval_end: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\intexpr_div_truncate:nn} % \begin{macro}{\intexpr_div_round:nn} % \begin{macro}{\intexpr_mod:nn} % As "\intexpr_eval:w" rounds the result of a division we also % provide a version that truncates the result. % \begin{macrocode} % \end{macrocode} % Initial version didn't work correctly with e\TeX's implementation. % \begin{macrocode} %\cs_set:Npn \intexpr_div_truncate_raw:nn #1#2 { % \intexpr_eval:n{ (2*#1 - #2) / (2* #2) } %} % \end{macrocode} % New version by Heiko: % \begin{macrocode} \cs_set:Npn \intexpr_div_truncate:nn #1#2 { \intexpr_value:w \intexpr_eval:w \if_intexpr_compare:w \intexpr_eval:w #1 = \c_zero 0 \else: (#1 \if_intexpr_compare:w \intexpr_eval:w #1 < \c_zero \if_intexpr_compare:w \intexpr_eval:w #2 < \c_zero -( #2 + \else: +( #2 - \fi: \else: \if_intexpr_compare:w \intexpr_eval:w #2 < \c_zero +( #2 + \else: -( #2 - \fi: \fi: 1)/2) \fi: /(#2) \intexpr_eval_end: } % \end{macrocode} % For the sake of completeness: % \begin{macrocode} \cs_set:Npn \intexpr_div_round:nn #1#2 {\intexpr_eval:n{(#1)/(#2)}} % \end{macrocode} % Finally there's the modulus operation. % \begin{macrocode} \cs_set:Npn \intexpr_mod:nn #1#2 { \intexpr_value:w \intexpr_eval:w #1 - \intexpr_div_truncate:nn {#1}{#2} * (#2) \intexpr_eval_end: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\intexpr_if_odd_p:n} % \begin{macro}[TF]{\intexpr_if_odd:n} % \begin{macro}{\intexpr_if_even_p:n} % \begin{macro}[TF]{\intexpr_if_even:n} % A predicate function. % \begin{macrocode} \prg_set_conditional:Npnn \intexpr_if_odd:n #1 {p,TF,T,F} { \if_intexpr_odd:w \intexpr_eval:w #1\intexpr_eval_end: \prg_return_true: \else: \prg_return_false: \fi: } \prg_set_conditional:Npnn \intexpr_if_even:n #1 {p,TF,T,F} { \if_intexpr_odd:w \intexpr_eval:w #1\intexpr_eval_end: \prg_return_false: \else: \prg_return_true: \fi: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\intexpr_while_do:nn} % \begin{macro}{\intexpr_until_do:nn} % \begin{macro}{\intexpr_do_while:nn} % \begin{macro}{\intexpr_do_until:nn} % These are quite easy given the above functions. The "while" versions % test first and then execute the body. The "do_while" does it the % other way round. % \begin{macrocode} \cs_set:Npn \intexpr_while_do:nn #1#2{ \intexpr_compare:nT {#1}{#2 \intexpr_while_do:nn {#1}{#2}} } \cs_set:Npn \intexpr_until_do:nn #1#2{ \intexpr_compare:nF {#1}{#2 \intexpr_until_do:nn {#1}{#2}} } \cs_set:Npn \intexpr_do_while:nn #1#2{ #2 \intexpr_compare:nT {#1}{\intexpr_do_while:nNnn {#1}{#2}} } \cs_set:Npn \intexpr_do_until:nn #1#2{ #2 \intexpr_compare:nF {#1}{\intexpr_do_until:nn {#1}{#2}} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\intexpr_while_do:nNnn} % \begin{macro}{\intexpr_until_do:nNnn} % \begin{macro}{\intexpr_do_while:nNnn} % \begin{macro}{\intexpr_do_until:nNnn} % As above but not using the more natural syntax. % \begin{macrocode} \cs_set:Npn \intexpr_while_do:nNnn #1#2#3#4{ \intexpr_compare:nNnT {#1}#2{#3}{#4 \intexpr_while_do:nNnn {#1}#2{#3}{#4}} } \cs_set:Npn \intexpr_until_do:nNnn #1#2#3#4{ \intexpr_compare:nNnF {#1}#2{#3}{#4 \intexpr_until_do:nNnn {#1}#2{#3}{#4}} } \cs_set:Npn \intexpr_do_while:nNnn #1#2#3#4{ #4 \intexpr_compare:nNnT {#1}#2{#3}{\intexpr_do_while:nNnn {#1}#2{#3}{#4}} } \cs_set:Npn \intexpr_do_until:nNnn #1#2#3#4{ #4 \intexpr_compare:nNnF {#1}#2{#3}{\intexpr_do_until:nNnn {#1}#2{#3}{#4}} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % %\begin{macro}{\c_max_register_int} % This is here as this particular integer is needed both in package % mode and to bootstrap \pkg{l3alloc} % \begin{macrocode} \tex_mathchardef:D \c_max_register_int = 32767 \scan_stop: % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % \PrintIndex % % \endinput