diff options
author | Karl Berry <karl@freefriends.org> | 2009-06-09 23:31:15 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-06-09 23:31:15 +0000 |
commit | 215b9a864d5829070bdc66ba736986eb72e5143e (patch) | |
tree | fe0882c81fc4ec945cee4b512f72eaa21ea5f791 /Master/texmf-dist/source/latex/expl3/l3intexpr.dtx | |
parent | df90ec06321940c2f066b05e12f1b5ab099105da (diff) |
expl3 1407 (9jun09)
git-svn-id: svn://tug.org/texlive/trunk@13686 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3intexpr.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3intexpr.dtx | 642 |
1 files changed, 642 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx b/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx new file mode 100644 index 00000000000..6b454a8ab80 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3intexpr.dtx @@ -0,0 +1,642 @@ +% \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} +%</driver|package> +%\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} +%</driver> +% \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 <number>, +% 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{<int~expr1> <rel> <int~expr2>} +% \end{syntax} +% Compares <int~expr1> with <int~expr2> 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}<rel>\Arg{int~expr2} +% \end{syntax} +% Compares <int~expr1> with <int~expr2> 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" <integer> \\ +% "\intexpr_value:w" <tokens> <optional space> +% \end{syntax} +% Expands <tokens> until an <integer> 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" <int expr> "\intexpr_eval_end:" +% \end{syntax} +% Evaluates <int expr>. 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" <number1> <rel> <number2> <true> "\else:" <false> "\fi:" +% \end{syntax} +% Compare two numbers. It is recommended to use "\intexpr_eval:n" to +% correctly evaluate and terminate these numbers. <rel> 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" <number> <true> "\else:" <false> "\fi:" +% \end{syntax} +% Execute <true> if <number> is odd, <false> 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" <number> <case0> "\or:" <case1> "\or:" "..." "\else:" +% <default> "\fi:" +% \end{syntax} +% Chooses case <number>. 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} +% +% +% +% \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{<int~expr1> <rel> <int~expr2>} \Arg{code} +% \end{syntax} +% "\intexpr_while_do:nn" tests the integer expressions against each +% other using a C-like <rel> as in "\intexpr_compare_p:n" and if true +% performs the <code> until the test fails. "\intexpr_do_while:nn" is +% similar but executes the <code> 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" <int expr> <rel> <int~expr> \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: +%</package> +%<*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} +% For the less than or equal operation, we simply add $1$ to the right +% hand side and then use a less than test. A similar trick for the +% greater than or equal test except there we subtract $1$. +% \begin{macrocode} +\cs_set:cpn {intexpr_compare_<=:w} #1<=#2\q_nil{ + \if_intexpr_compare:w #1<\intexpr_eval:w #2 +\c_one \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 - \c_one \intexpr_eval_end: + \prg_return_true: \else: \prg_return_false: \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} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% \PrintIndex +% +% \endinput |