diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3calc.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3calc.dtx | 930 |
1 files changed, 930 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3calc.dtx b/Master/texmf-dist/source/latex/expl3/l3calc.dtx new file mode 100644 index 00000000000..f00c2941940 --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3calc.dtx @@ -0,0 +1,930 @@ +% \iffalse +%% File: l3calc.dtx Copyright (C) 2006 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/cgi-bin/cvsweb.cgi/ +%% +%% 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. +%% +%% ----------------------------------------------------------------------- +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3calc.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental calc module} +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3calc.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3calc} package\thanks{This file has version +% number \fileversion, last +% revised \filedate.}\\ +% Infix notation arithmetic in \LaTeX3} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \section{Infix notation arithmetic} +% +% This is pretty much a straight adaption of the \textsf{calc} package +% and as such has same syntax for the \meta{calc expression}. However, +% there are some noticeable differences. +% \begin{itemize} +% \item The calc expression is expanded fully, which means there are +% no problems with unfinished conditionals. However, the contents of +% |\widthof| etc.\ is not expanded at all. +% \item Muskip registers are supported although they can only be used +% in |\ratio| if already evaluating a muskip expression. For the +% other three register types, you can use points. +% \item All results are rounded, not truncated. More precisely, the +% primitive \TeX\ operations |\divide| and |\multiply| are not used. +% \end{itemize} +% +% \begin{function}{ +% \calc_int_set:Nn | +% \calc_int_gset:Nn | +% \calc_int_add:Nn | +% \calc_int_gadd:Nn | +% \calc_int_sub:Nn | +% \calc_int_gsub:Nn | +% } +% \begin{syntax} +% "\calc_int_set:Nn" <int> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <int> or sets <int> to it. These operations can also be global. +% \end{function} +% +% +% \begin{function}{ +% \calc_dim_set:Nn | +% \calc_dim_gset:Nn | +% \calc_dim_add:Nn | +% \calc_dim_gadd:Nn | +% \calc_dim_sub:Nn | +% \calc_dim_gsub:Nn | +% } +% \begin{syntax} +% "\calc_dim_set:Nn" <dim> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <dim> or sets <dim> to it. These operations can also be global. +% \end{function} +% +% +% \begin{function}{ +% \calc_skip_set:Nn | +% \calc_skip_gset:Nn | +% \calc_skip_add:Nn | +% \calc_skip_gadd:Nn | +% \calc_skip_sub:Nn | +% \calc_skip_gsub:Nn | +% } +% \begin{syntax} +% "\calc_skip_set:Nn" <skip> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <skip> or sets <skip> to it. These operations can also be global. +% \end{function} +% +% +% \begin{function}{ +% \calc_muskip_set:Nn | +% \calc_muskip_gset:Nn | +% \calc_muskip_add:Nn | +% \calc_muskip_gadd:Nn | +% \calc_muskip_sub:Nn | +% \calc_muskip_gsub:Nn | +% } +% \begin{syntax} +% "\calc_muskip_set:Nn" <muskip> "{"<calc expression>"}" +% \end{syntax} +% Evaluates <calc expression> and either adds or subtracts it from +% <muskip> or sets <muskip> to it. These operations can also be +% global. +% \end{function} +% +% +% \begin{function}{ +% \calc_calculate_box_size:nnn | +% } +% \begin{syntax} +% "\calc_calculate_box_size:nnn" "{"<dim-set>"}" \\ +% "{"<item 1> <item 2> ... <item n>"}" "{"<contents>"}" +% \end{syntax} +% Sets <contents> in a temporary box "\l_tmpa_box". Then <dim-set> +% is put in front of a loop that inserts "+"\meta{item$\sb{i}$} in +% front of "\l_tmpa_box" and this is evaluated. For instance, if we +% wanted to determine the total height of the text "xyz" and store +% it in "\l_tmpa_dim", we would call it as. +% \begin{verbatim} +% \calc_calculate_box_size:nnn +% {\dim_set:Nn\l_tmpa_dim}{\box_ht:N\box_dp:N}{xyz} +% \end{verbatim} +% Similarly, if we wanted the difference between height and depth, +% we could call it as +% \begin{verbatim} +% \calc_calculate_box_size:nnn +% {\dim_set:Nn\l_tmpa_dim}{\box_ht:N{-\box_dp:N}}{xyz} +% \end{verbatim} +% \end{function} +% +% \StopEventually{} +% +% \subsection{The Implementation} +% +% Since this is basically a re-worked version of the \textsf{calc} +% package, I haven't bothered with too many comments except for in the +% places where this package differs. This may (and should) change at +% some point. +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\RequirePackage{l3int} +\RequirePackage{l3skip} +\RequirePackage{l3box} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% \begin{macro}{\l_calc_expression_tlp} +% \begin{macro}{\g_calc_A_register} +% \begin{macro}{\l_calc_B_register} +% \begin{macro}{\l_calc_current_type_int} +% Here we define some registers and pointers we will need. +% \begin{macrocode} +\tlp_new:Nn\l_calc_expression_tlp{} +\def_new:Npn \g_calc_A_register{} +\def_new:Npn \l_calc_B_register{} +\int_new:N \l_calc_current_type_int +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\g_calc_A_int} +% \begin{macro}{\l_calc_B_int} +% \begin{macro}{\l_calc_C_int} +% \begin{macro}{\g_calc_A_dim} +% \begin{macro}{\l_calc_B_dim} +% \begin{macro}{\l_calc_C_dim} +% \begin{macro}{\g_calc_A_skip} +% \begin{macro}{\l_calc_B_skip} +% \begin{macro}{\l_calc_C_skip} +% \begin{macro}{\g_calc_A_muskip} +% \begin{macro}{\l_calc_B_muskip} +% \begin{macro}{\l_calc_C_muskip} +% For each type of register we will need three registers to do our +% manipulations. +% \begin{macrocode} +\int_new:N \g_calc_A_int +\int_new:N \l_calc_B_int +\int_new:N \l_calc_C_int +\dim_new:N \g_calc_A_dim +\dim_new:N \l_calc_B_dim +\dim_new:N \l_calc_C_dim +\skip_new:N \g_calc_A_skip +\skip_new:N \l_calc_B_skip +\skip_new:N \l_calc_C_skip +\muskip_new:N \g_calc_A_muskip +\muskip_new:N \l_calc_B_muskip +\muskip_new:N \l_calc_C_muskip +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\calc_assign_generic:NNNNNn} +% The generic function. |#1| is a number denoting which type we are +% doing. (0=int, 1=dim, 2=skip, 3=muskip), |#2| = temp register A, +% |#3| = temp register B, |#4| is a function acting on |#5| which is +% the register to be set. |#6| is the calc expression. This version +% relies on |\real| and |\ratio| having our definitions. +% \begin{macrocode} +\def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{ + \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3 + \int_set:Nn \l_calc_current_type_int {#1} + \tlp_set:Nx\l_calc_expression_tlp{#6} + \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp! + \pref_global:D\g_calc_A_register\l_calc_B_register + \group_end: + #4#5\l_calc_B_register +} +% \end{macrocode} +% One could lift these restrictions by defining |\calc_generic:NNNNNn| +% like this: +% \begin{verbatim} +% \def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{ +% \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3 +% \int_set:Nn \l_calc_current_type_int {#1} +% \group_begin: +% \let:NN \real\calc_real:n +% \let:NN \ratio\calc_ratio:nn +% \tlp_set:Nx\l_calc_expression_tlp{#6} +% \exp_after:NN +% \group_end: +% \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp! +% \pref_global:D\g_calc_A_register\l_calc_B_register +% \group_end: +% #4#5\l_calc_B_register +% } +% \end{verbatim} +% \end{macro} +% +% +% +% \begin{macro}{\calc_int_set:Nn} +% \begin{macro}{\calc_int_gset:Nn} +% \begin{macro}{\calc_int_add:Nn} +% \begin{macro}{\calc_int_gadd:Nn} +% \begin{macro}{\calc_int_sub:Nn} +% \begin{macro}{\calc_int_gsub:Nn} +% Here are the individual versions for the different register +% types. First integer registers. +% \begin{macrocode} +\def_new:Npn\calc_int_set:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_set:Nn +} +\def_new:Npn\calc_int_gset:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gset:Nn +} +\def_new:Npn\calc_int_add:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_add:Nn +} +\def_new:Npn\calc_int_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gadd:Nn +} +\def_new:Npn\calc_int_sub:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_sub:Nn +} +\def_new:Npn\calc_int_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gsub:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_dim_set:Nn} +% \begin{macro}{\calc_dim_gset:Nn} +% \begin{macro}{\calc_dim_add:Nn} +% \begin{macro}{\calc_dim_gadd:Nn} +% \begin{macro}{\calc_dim_sub:Nn} +% \begin{macro}{\calc_dim_gsub:Nn} +% Dimens. +% \begin{macrocode} +\def_new:Npn\calc_dim_set:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_set:Nn +} +\def_new:Npn\calc_dim_gset:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gset:Nn +} +\def_new:Npn\calc_dim_add:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_add:Nn +} +\def_new:Npn\calc_dim_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gadd:Nn +} +\def_new:Npn\calc_dim_sub:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_sub:Nn +} +\def_new:Npn\calc_dim_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_gsub:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_skip_set:Nn} +% \begin{macro}{\calc_skip_gset:Nn} +% \begin{macro}{\calc_skip_add:Nn} +% \begin{macro}{\calc_skip_gadd:Nn} +% \begin{macro}{\calc_skip_sub:Nn} +% \begin{macro}{\calc_skip_gsub:Nn} +% Skips. +% \begin{macrocode} +\def_new:Npn\calc_skip_set:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_set:Nn +} +\def_new:Npn\calc_skip_gset:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gset:Nn +} +\def_new:Npn\calc_skip_add:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_add:Nn +} +\def_new:Npn\calc_skip_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gadd:Nn +} +\def_new:Npn\calc_skip_sub:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_sub:Nn +} +\def_new:Npn\calc_skip_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gsub:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_muskip_set:Nn} +% \begin{macro}{\calc_muskip_gset:Nn} +% \begin{macro}{\calc_muskip_add:Nn} +% \begin{macro}{\calc_muskip_gadd:Nn} +% \begin{macro}{\calc_muskip_sub:Nn} +% \begin{macro}{\calc_muskip_gsub:Nn} +% Muskips. +% \begin{macrocode} +\def_new:Npn\calc_muskip_set:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_set:Nn +} +\def_new:Npn\calc_muskip_gset:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gset:Nn +} +\def_new:Npn\calc_muskip_add:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn +} +\def_new:Npn\calc_muskip_gadd:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn +} +\def_new:Npn\calc_muskip_sub:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn +} +\def_new:Npn\calc_muskip_gsub:Nn{ + \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\calc_pre_scan:N} +% In case we found one of the special operations, this should just +% be executed. +% \begin{macrocode} +\def_new:Npn \calc_pre_scan:N #1{ + \if_meaning:NN(#1 + \exp_after:NN\calc_open:w + \else: + \if_meaning:NN \calc_textsize:Nn #1 + \else: + \if_meaning:NN \calc_maxmin_operation:Nnn #1 + \else: +% \end{macrocode} +% |\calc_numeric:| uses a primitive assignment so doesn't care about +% these dangling |\fi:|s. +% \begin{macrocode} + \calc_numeric: + \fi: + \fi: + \fi: + #1} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_open:w} +% \begin{macrocode} +\def_new:Npn \calc_open:w({ + \group_begin:\group_execute_after:N\calc_init_B: + \group_begin:\group_execute_after:N\calc_init_B: + \calc_pre_scan:N +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_init_B:} +% \begin{macro}{\calc_numeric:} +% \begin{macro}{\calc_close:} +% \begin{macrocode} +\def_new:Npn\calc_init_B:{\l_calc_B_register\g_calc_A_register} +\def_new:Npn\calc_numeric:{ + \tex_afterassignment:D\calc_post_scan:N + \pref_global:D\g_calc_A_register +} +\def_new:Npn\calc_close:{ + \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register + \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register + \calc_post_scan:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_post_scan:N} +% Look at what token we have and decide where to go. +% \begin{macrocode} +\def_new:Npn\calc_post_scan:N#1{ + \if_meaning:NN#1!\let:NN\calc_next:w\group_end: \else: + \if_meaning:NN#1+\let:NN\calc_next:w\calc_add: \else: + \if_meaning:NN#1-\let:NN\calc_next:w\calc_subtract: \else: + \if_meaning:NN#1*\let:NN\calc_next:w\calc_multiply:N \else: + \if_meaning:NN#1/\let:NN\calc_next:w\calc_divide:N \else: + \if_meaning:NN#1)\let:NN\calc_next:w\calc_close: \else: +% \end{macrocode} +% If we get here, there is an error but let's also disable +% |\calc_next:w| since it is otherwise undefined. No need to give +% extra errors just for that. +% \begin{macrocode} + \let:NN \calc_next:w \scan_stop: + \calc_error:N#1 + \fi: + \fi: + \fi: + \fi: + \fi: + \fi: + \calc_next:w} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_multiply:N} +% \begin{macro}{\calc_divide:N} +% The switches for multiplication and division. +% \begin{macrocode} +\def_new:Npn \calc_multiply:N #1{ + \if_meaning:NN \calc_maxmin_operation:Nnn #1 + \let:NN \calc_next:w \calc_maxmin_multiply: + \else: + \if_meaning:NN \calc_ratio_multiply:nn #1 + \let:NN \calc_next:w \calc_ratio_multiply:nn + \else: + \if_meaning:NN \calc_real_evaluate:nn #1 + \let:NN \calc_next:w \calc_real_multiply:n + \else: + \def:Npn \calc_next:w{\calc_multiply: #1} + \fi: + \fi: + \fi: + \calc_next:w +} +\def_new:Npn \calc_divide:N #1{ + \if_meaning:NN \calc_maxmin_operation:Nnn #1 + \let:NN \calc_next:w \calc_maxmin_divide: + \else: + \if_meaning:NN \calc_ratio_multiply:nn #1 + \let:NN \calc_next:w \calc_ratio_divide:nn + \else: + \if_meaning:NN \calc_real_evaluate:nn #1 + \let:NN \calc_next:w \calc_real_divide:n + \else: + \def:Npn \calc_next:w{\calc_divide: #1} + \fi: + \fi: + \fi: + \calc_next:w +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_generic_add:N} +% \begin{macro}{\calc_add:} +% \begin{macro}{\calc_subtract:} +% \begin{macro}{\calc_add_A_to_B:} +% \begin{macro}{\calc_subtract_A_from_B:} +% Here is how we add and subtract. +% \begin{macrocode} +\def_new:Npn\calc_generic_add_or_subtract:N#1{ + \group_end: + \pref_global:D\g_calc_A_register\l_calc_B_register\group_end: + \group_begin:\group_execute_after:N#1\group_begin: + \group_execute_after:N\calc_init_B: + \calc_pre_scan:N} +\def_new:Npn\calc_add:{\calc_generic_add_or_subtract:N\calc_add_A_to_B:} +\def_new:Npn\calc_subtract:{ + \calc_generic_add_or_subtract:N\calc_subtract_A_from_B:} +% \end{macrocode} +% Don't use |\tex_advance:D| since it allows overflows. +% \begin{macrocode} +\def_new:Npn\calc_add_A_to_B:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register + \g_calc_A_register\scan_stop: +} +\def_new:Npn\calc_subtract_A_from_B:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register - \g_calc_A_register\scan_stop: +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_generic_multiply_or_divide:N} +% \begin{macro}{\calc_multiply_B_by_A:} +% \begin{macro}{\calc_divide_B_by_A:} +% \begin{macro}{\calc_multiply:} +% \begin{macro}{\calc_divide:} +% And here is how we multiply and divide. Note that we do not use the +% primitive \TeX{} operations but the expandable operations provided +% by \eTeX. This means that all results are rounded not truncated! +% \begin{macrocode} +\def_new:Npn\calc_generic_multiply_or_divide:N#1{ + \group_end: + \group_begin: + \let:NN\g_calc_A_register\g_calc_A_int + \let:NN\l_calc_B_register\l_calc_B_int + \group_execute_after:N#1\calc_pre_scan:N +} +\def_new:Npn\calc_multiply_B_by_A:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register*\g_calc_A_int\scan_stop: +} +\def_new:Npn\calc_divide_B_by_A:{ + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register/\g_calc_A_int\scan_stop: +} +\def_new:Npn\calc_multiply:{ + \calc_generic_multiply_or_divide:N\calc_multiply_B_by_A:} +\def_new:Npn\calc_divide:{ + \calc_generic_multiply_or_divide:N\calc_divide_B_by_A:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_calculate_box_size:nnn} +% \begin{macro}{\calc_calculate_box_size_aux:n} +% Put something in a box and measure it. |#1| is a list of +% |\box_ht:N| etc., |#2| should be |\dim_set:Nn|\meta{dim register} +% or |\dim_gset:Nn|\meta{dim register} and |#3| is the contents. +% \begin{macrocode} +\def_long_new:Npn \calc_calculate_box_size:nnn #1#2#3{ + \hbox_set:Nn \l_tmpa_box {{#3}} + #2{\c_zero_dim \tlist_map_function:nN{#1}\calc_calculate_box_size_aux:n} +} +% \end{macrocode} +% Helper for calculating the final dimension. +% \begin{macrocode} +\def:Npn \calc_calculate_box_size_aux:n#1{ + #1\l_tmpa_box} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\calc_textsize:Nn} +% Now we can define |\calc_textsize:Nn|. +% \begin{macrocode} +\def_protected_long:Npn \calc_textsize:Nn#1#2{ + \group_begin: + \let:NN\widthof\box_wd:N + \let:NN\heightof\box_ht:N + \let:NN\depthof\box_dp:N + \def:Npn\totalheightof{\box_ht:N\box_dp:N} + \exp_args:No\calc_calculate_box_size:nnn{#1} + {\dim_gset:Nn\g_calc_A_register} +% \end{macrocode} +% Restore the four user commands here since there might be a recursive +% call. +% \begin{macrocode} + { + \let:NN \depthof\calc_depthof:n + \let:NN \widthof\calc_widthof:n + \let:NN \heightof\calc_heightof:n + \let:NN \totalheightof\calc_totalheightof:n + #2 + } + \group_end: + \calc_post_scan:N +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\calc_ratio_multiply:nn} +% \begin{macro}{\calc_ratio_divide:nn} +% Evaluate a ratio. If we were already evaluation a \meta{muskip} +% register, the ratio is probably also done with this type and we'll +% have to convert them to regular points. +% \begin{macrocode} +\def_protected_long:Npn\calc_ratio_multiply:nn#1#2{ + \group_end:\group_begin: + \if_num:w\l_calc_current_type_int < \c_three + \calc_dim_set:Nn\l_calc_B_int{#1} + \calc_dim_set:Nn\l_calc_C_int{#2} + \else: + \calc_dim_muskip:Nn{\l_calc_B_int\etex_mutoglue:D}{#1} + \calc_dim_muskip:Nn{\l_calc_C_int\etex_mutoglue:D}{#2} + \fi: +% \end{macrocode} +% Then store the ratio as a fraction, which we just pass on. +% \begin{macrocode} + \gdef:Npx\calc_calculated_ratio:{ + \int_use:N\l_calc_B_int/\int_use:N\l_calc_C_int + } + \group_end: +% \end{macrocode} +% Here we set the new value of |\l_calc_B_register| and remember to +% evaluate it as the correct type. Note that the intermediate +% calculation is a scaled operation (meaning the intermediate value is +% 64-bit) so we don't get into trouble when first multiplying by a +% large number and then dividing. +% \begin{macrocode} + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register*\calc_calculated_ratio:\scan_stop: + \group_begin: + \calc_post_scan:N} +% \end{macrocode} +% Division is just flipping the arguments around. +% \begin{macrocode} +\def_long_new:Npn \calc_ratio_divide:nn#1#2{\calc_ratio_multiply:nn{#2}{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_real_evaluate:nn} +% \begin{macro}{\calc_real_multiply:n} +% \begin{macro}{\calc_real_divide:n} +% Although we could define the |\real| function as a subcase of +% |\ratio|, this is horribly inefficient since we just want to convert +% the decimal to a fraction. +% \begin{macrocode} +\def_protected_new:Npn\calc_real_evaluate:nn #1#2{ + \group_end: + \l_calc_B_register + \if_case:w\l_calc_current_type_int + \etex_numexpr:D\or: + \etex_dimexpr:D\or: + \etex_glueexpr:D\or: + \etex_muexpr:D\fi: + \l_calc_B_register * + \tex_number:D \dim_eval:n{#1pt}/ + \tex_number:D\dim_eval:n{#2pt} + \scan_stop: + \group_begin: + \calc_post_scan:N} +\def_new:Npn \calc_real_multiply:n #1{\calc_real_evaluate:nn{#1}{1}} +\def_new:Npn \calc_real_divide:n {\calc_real_evaluate:nn{1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_maxmin_operation:Nnn} +% \begin{macro}{\calc_maxmin_generic:Nnn} +% \begin{macro}{\calc_maxmin_div_or_mul:NNnn} +% \begin{macro}{\calc_maxmin_multiply:} +% \begin{macro}{\calc_maxmin_multiply:} +% The max and min functions. +% \begin{macrocode} +\def_protected_long:Npn\calc_maxmin_operation:Nnn#1#2#3{ + \group_begin: + \calc_maxmin_generic:Nnn#1{#2}{#3} + \group_end: + \calc_post_scan:N +} +% \end{macrocode} +% |#1| is either |>| or |<| and was expanded into this initially. +% \begin{macrocode} +\def_protected_long_new:Npn \calc_maxmin_generic:Nnn#1#2#3{ + \group_begin: + \if_case:w\l_calc_current_type_int + \calc_int_set:Nn\l_calc_C_int{#2}% + \calc_int_set:Nn\l_calc_B_int{#3}% + \pref_global:D\g_calc_A_register + \if_num:w\l_calc_C_int#1\l_calc_B_int + \l_calc_C_int\else:\l_calc_B_int\fi: + \or: + \calc_dim_set:Nn\l_calc_C_dim{#2}% + \calc_dim_set:Nn\l_calc_B_dim{#3}% + \pref_global:D\g_calc_A_register + \if_dim:w\l_calc_C_dim#1\l_calc_B_dim + \l_calc_C_dim\else:\l_calc_B_dim\fi: + \or: + \calc_skip_set:Nn\l_calc_C_skip{#2}% + \calc_skip_set:Nn\l_calc_B_skip{#3}% + \pref_global:D\g_calc_A_register + \if_dim:w\l_calc_C_skip#1\l_calc_B_skip + \l_calc_C_skip\else:\l_calc_B_skip\fi: + \else: + \calc_muskip_set:Nn\l_calc_C_muskip{#2}% + \calc_muskip_set:Nn\l_calc_B_muskip{#3}% + \pref_global:D\g_calc_A_register + \if_dim:w\l_calc_C_muskip#1\l_calc_B_muskip + \l_calc_C_muskip\else:\l_calc_B_muskip\fi: + \fi: + \group_end: +} +\def_long_new:Npn\calc_maxmin_div_or_mul:NNnn#1#2#3#4{ + \group_end: + \group_begin: + \int_zero:N\l_calc_current_type_int + \group_execute_after:N#1 + \calc_maxmin_generic:Nnn#2{#3}{#4} + \group_end: + \group_begin: + \calc_post_scan:N +} +\def_new:Npn\calc_maxmin_multiply:{ + \calc_maxmin_div_or_mul:NNnn\calc_multiply_B_by_A:} +\def_new:Npn\calc_maxmin_divide: { + \calc_maxmin_div_or_mul:NNnn\calc_divide_B_by_A:} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_error:N} +% The error message. +% \begin{macrocode} +\def_new:Npn\calc_error:N#1{ + \PackageError{calc} + {`\token_to_string:N#1'~ invalid~ at~ this~ point} + {I~ expected~ to~ see~ one~ of:~ +~ -~ *~ /~ )} +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Higher level commands} +% +% The various operations allowed. +% +% \begin{macro}{\calc_maxof:nn} +% \begin{macro}{\calc_minof:nn} +% \begin{macro}{\maxof} +% \begin{macro}{\minof} +% Max and min operations +% \begin{macrocode} +\def_long_new:Npn \calc_maxof:nn#1#2{ + \calc_maxmin_operation:Nnn > \exp_not:n{{#1}{#2}} +} +\def_long_new:Npn \calc_minof:nn#1#2{ + \calc_maxmin_operation:Nnn < \exp_not:n{{#1}{#2}} +} +\let_new:NN \maxof \calc_maxof:nn +\let_new:NN \minof \calc_minof:nn +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_widthof:n} +% \begin{macro}{\calc_heightof:n} +% \begin{macro}{\calc_depthof:n} +% \begin{macro}{\calc_totalheightof:n} +% \begin{macro}{\widthof} +% \begin{macro}{\heightof} +% \begin{macro}{\depthof} +% \begin{macro}{\totalheightof} +% Text dimension commands. +% \begin{macrocode} +\def_long_new:Npn \calc_widthof:n#1{ + \calc_textsize:Nn \exp_not:N\widthof\exp_not:n{{#1}} +} +\def_long_new:Npn \calc_heightof:n#1{ + \calc_textsize:Nn \exp_not:N\heightof\exp_not:n{{#1}} +} +\def_long_new:Npn \calc_depthof:n#1{ + \calc_textsize:Nn \exp_not:N\depthof\exp_not:n{{#1}} +} +\def_long_new:Npn \calc_totalheightof:n#1{ + \calc_textsize:Nn \exp_not:N\totalheightof\exp_not:n{{#1}} +} +\let:NN \depthof\calc_depthof:n +\let:NN \widthof\calc_widthof:n +\let:NN \heightof\calc_heightof:n +\let:NN \totalheightof\calc_totalheightof:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\calc_ratio:nn} +% \begin{macro}{\calc_real:n} +% \begin{macro}{\ratio} +% \begin{macro}{\real} +% Ratio and real. +% \begin{macrocode} +\def_long_new:Npn \calc_ratio:nn#1#2{ + \calc_ratio_multiply:nn\exp_not:n{{#1}{#2}}} +\let_new:NN \calc_real:n \calc_real_evaluate:nn +% \end{macrocode} +% We can implement real and ratio without actually using these +% names. We'll see. +% \begin{macrocode} +\let_new:NN \ratio\calc_ratio:nn +\let_new:NN \real\calc_real:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.2 2006/01/27 23:11:47 morten +% Fixed bug in \calc_pre_scan:N and avoid using \advance in order to +% catch overflows. +% +% Revision 1.1 2006/01/27 07:51:13 morten +% Initial version of a calc module +% |