% \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} % % This module sets up evaluation of integer expressions and allows % mixing |int| and |num| registers. % % An integer expression is one that contains integers in the form of % numbers, registers containg numbers, i.e., |int| and |num| registers % plus constants like |\c_one|, standard operators "+", "-", "/" and % "*" and parentheses to group sub-expressions. % % \section{Functions} % % \begin{function}{% % \intexpr_eval:n / (EXP) % } % \begin{syntax} % "\intexpr_eval:n" \Arg{int~expr} % \end{syntax} % The result of this expansion is a properly terminated , % i.e., one that can be used with "\if_case:w" and others. For example, % \begin{quote} % |\intexpr_eval:n{ 5 + 4*3 - (3+4*5) }| % \end{quote} % evaluates to $-6$. The result is returned after two expansions so % if you find that you need to pass on the result to another function % using the expansion engine, the recommendation is to use an "f" type % expansion if in an expandable context or "x" otherwise. % \end{function} % % % \begin{function}{% % \intexpr_compare_p:n / (EXP) | % \intexpr_compare:n / (TF)(EXP) % } % \begin{syntax} % "\intexpr_compare_p:n" \Arg{ } % \end{syntax} % Compares with using C-like relational % operators, i.e. % \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} % 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} % "=" is added for the sake of \TeX\ users accustomed to using a % single equal sign. % \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} % Compares with using one of the relations % "=", ">" or "<". This is faster than the variant above but at the % cost of requiring a little more typing and not supporting the % extended set of relational operators. Note that if both expressions % are normal integer variables as in % \begin{quote} % "\intexpr_compare:nNnTF \l_temp_int < \c_zero {negative}{non-negative}" % \end{quote} % you can safely omit the braces. % \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} % Return the largest or smallest of two integer expressions. % \end{function} % % \begin{function}{% % \intexpr_abs:n / (EXP)| % } % \begin{syntax} % "\intexpr_abs:n" \Arg{int~expr} % \end{syntax} % Return the numerical value of an integer expression. % \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} % These functions test if an integer expression is even or odd. % \end{function} % % % % % % % \begin{function}{% % \intexpr_div_truncate:nn / (EXP) | % \intexpr_div_round:nn / (EXP) | % \intexpr_mod:nn / (EXP) | % } % \begin{syntax} % "\intexpr_div_truncate:n" \Arg{int~expr} \Arg{int~expr} \\ % "\intexpr_mod:nn" \Arg{int~expr} \Arg{int~expr} % \end{syntax} % If % you want the result of a division to be truncated use % "\intexpr_div_truncate:nn". "\intexpr_div_round:nn" is added for % completeness. "\intexpr_mod:nn" returns the remainder of a division. % \end{function} % % % % % % % % % % % % \section{Primitive functions} % % % \begin{function}{% % \intexpr_value:w | % } % \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 | % \intexpr_eval_end: | % } % \begin{syntax} % "\intexpr_eval:w" "\intexpr_eval_end:" % \end{syntax} % Evaluates . The evaluation stops when an % unexpandable token of catcode other than 12 is reached or % "\intexpr_end:" is read. The latter is gobbled by the scanner % mechanism. % \begin{texnote} % This is the \eTeX{} primitive \tn{numexpr}. % \end{texnote} % \end{function} % % \begin{function}{% % \if_intexpr_compare:w | % } % \begin{syntax} % "\if_intexpr_compare:w" "\else:" "\fi:" % \end{syntax} % Compare two numbers. It is recommended to use "\intexpr_eval:n" to % correctly evaluate and terminate these numbers. is one of % "<", "=" or ">" with catcode 12. % \begin{texnote} % This is the \TeX{} primitive \tn{ifnum}. % \end{texnote} % \end{function} % % \begin{function}{% % \if_intexpr_odd:w | % } % \begin{syntax} % "\if_intexpr_odd:w" "\else:" "\fi:" % \end{syntax} % Execute if is odd, otherwise. % \begin{texnote} % This is the \TeX{} primitive \tn{ifodd}. % \end{texnote} % \end{function} % % \begin{function}{% % \if_intexpr_case:w | % \or: | % } % \begin{syntax} % "\if_intexpr_case:w" "\or:" "\or:" "..." "\else:" % "\fi:" % \end{syntax} % Chooses case . If you wish to use negative numbers as well, % you can offset them with "\intexpr_eval:n". % \begin{texnote} % These are the \TeX{} primitives \tn{ifcase} and \tn{or}. % \end{texnote} % \end{function} % %^^A Keep the documenation-checking happy %\ExplSyntaxOn %\seq_gput_right:Nx \g_doc_macros_seq { \token_to_str:N \or: } %\ExplSyntaxOff % % \begin{function}{% % \intexpr_while_do:nn | % \intexpr_until_do:nn | % \intexpr_do_while:nn | % \intexpr_do_until:nn | % } % \begin{syntax} % "\intexpr_while_do:nn" \Arg{ } \Arg{code} % \end{syntax} % "\intexpr_while_do:nn" tests the integer expressions against each % other using a C-like as in "\intexpr_compare_p:n" and if true % performs the until the test fails. "\intexpr_do_while:nn" is % similar but executes the first and then performs the check, % thus ensuring that the body is executed at least once. The `until' % versions are similar but continue the loop as long as the test is % false. They could be omitted as it is just a matter of switching the % arguments in the test. % \end{function} % % \begin{function}{% % \intexpr_while_do:nNnn | % \intexpr_until_do:nNnn | % \intexpr_do_while:nNnn | % \intexpr_do_until:nNnn | % } % \begin{syntax} % "\intexpr_while_do:nNnn" \Arg{code} % \end{syntax} % Exactly as above but instead using the syntax of % "\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}{\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{macrocode} % % \end{macrocode} % % \end{implementation} % \PrintIndex % % \endinput