% \iffalse %% File: l3int.dtx Copyright (C) 1990-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: l3int.dtx 1362 2009-05-28 20:19:21Z joseph $ {L3 Experimental Integer module} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass[full]{l3doc} \begin{document} \DocInput{l3int.dtx} \end{document} % % \fi % % % \title{The \textsf{l3int} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Integers/counters} % \author{\Team} % \date{\filedate} % \maketitle % % \begin{documentation} % % \LaTeX3 maintains two type of integer registers for internal use. % One (associated with the name "num") for low level uses in the % allocation mechanism using macros only and "int": the one described % here. % % The "int" type uses the built-in counter registers of \TeX{} and is % therefore relatively fast compared to the "num" type and should be % preferred in all cases as there is little chance we should ever run % out of registers when being based on at least \eTeX. % % \section{Functions} % % \begin{function}{% % \int_new:N | % \int_new:c | %^^A \int_new_l:N | % } % \begin{syntax} % "\int_new:N" % \end{syntax} % Globally defines to be a new variable of type "int" although % you can still choose if it should be a an "\l_" or "\g_" type. % There is no way to define constant counters with these functions. %^^A The function "\int_new_l:N" defines locally only. % \begin{texnote} % "\int_new:N" is the equivalent to plain \TeX{}'s \tn{newcount}. % However, the internal register allocation is done differently. % \end{texnote} % \end{function} % % \begin{function}{% % \int_incr:N | % \int_incr:c | % \int_gincr:N | % \int_gincr:c | % } % \begin{syntax} % "\int_incr:N" % \end{syntax} % Increments by one. For global variables the global versions % should be used. % \end{function} % % \begin{function}{% % \int_decr:N | % \int_decr:c | % \int_gdecr:N | % \int_gdecr:c | % } % \begin{syntax} % "\int_decr:N" % \end{syntax} % Decrements by one. For global variables the global versions % should be used. % \end{function} % % \begin{function}{% % \int_set:Nn | % \int_set:cn | % \int_gset:Nn | % \int_gset:cn | % } % \begin{syntax} % "\int_set:Nn" \Arg{integer expr} % \end{syntax} % These functions will set the register to the % value. This value can contain simple calc-like expressions as % provided by \eTeX. % \end{function} % % % \begin{function}{% % \int_zero:N | % \int_zero:c | % \int_gzero:N | % \int_gzero:c | % } % \begin{syntax} % "\int_zero:N" % \end{syntax} % These functions sets the register to zero either locally % or globally. % \end{function} % % % \begin{function}{% % \int_add:Nn | % \int_add:cn | % \int_gadd:Nn | % \int_gadd:cn | % } % \begin{syntax} % "\int_add:Nn" \Arg{integer expr} % \end{syntax} % These functions will add to the register the value . If the second argument is a register too, the % surrounding braces can be left out. % \end{function} % % \begin{function}{% % \int_sub:Nn | % \int_sub:cn | % \int_gsub:Nn | % \int_gsub:cn | % } % \begin{syntax} % "\int_gsub:Nn" \Arg{integer expr} % \end{syntax} % These functions will subtract from the register the value % . If the second argument is a register too, the % surrounding braces can be left out. % \end{function} % % \begin{function}{% % \int_use:N | % \int_use:c | % } % \begin{syntax} % "\int_use:N" % \end{syntax} % This function returns the integer value kept in in a way % suitable for further processing. % \begin{texnote} % The function "\int_use:N" could be implemented directly as the \TeX{} % primitive "\tex_the:D" which is also responsible to produce the values for % other internal quantities. We have chosen to use individual functions % for counters, dimensions etc.\ to allow checks and to make the code % more self-explaining. % \end{texnote} % \end{function} % % \begin{function}{ \int_show:N | % \int_show:c } % \begin{syntax} % "\int_show:N" % \end{syntax} % This function pauses the compilation and displays the integer value kept % in in the console output and log file. % \begin{texnote} % The function "\int_show:N" could be implemented directly as the \TeX{} % primitive "\tex_showthe:D" which is also responsible to produce the values for % other internal quantities. We have chosen to use individual functions % for counters, dimensions etc.\ to allow checks and to make the code % more self-explaining. % \end{texnote} % \end{function} % % \section{Formatting a counter value} % % \begin{function}{ % \int_to_arabic:n / (EXP) | % \int_to_alph:n / (EXP) | % \int_to_Alph:n / (EXP) | % \int_to_roman:n / (EXP) | % \int_to_Roman:n / (EXP) | % \int_to_symbol:n / (EXP) | % } % \begin{syntax} % "\int_to_alph:n" \Arg{integer} % "\int_to_alph:n" % \end{syntax} % If some or the the current value of a should be % displayed or typeset in a special ways (e.g., as uppercase roman % numerals) these function can be used. We need braces if the % argument is a simple , they can be omitted in case of a % . By default the letters produced by "\int_to_roman:n" and % "\int_to_Roman:n" have catcode~11. % % All functions are fully expandable and will therefore produce the % correct output when used inside of deferred writes, etc. In case the % number in an |alph| or |Alph| function is greater than the default % base number (26) it follows a simple conversion rule so that 27 is % turned into |aa|, 50 into |ax| and so on and so forth. These two % functions can be modified quite easily to take a different base % number and conversion rule so that other languages can be supported. % \begin{texnote} % These are more or less the internal \LaTeX2 functions \tn{@arabic}, % \tn{@alph}, \tn{Alph}, \tn{@roman}, \tn{@Roman}, and \tn{@fnsymbol} % except that "\int_to_symbol:n" is also allowed outside math mode. % \end{texnote} % \end{function} % % \subsection{Internal functions} % % \begin{function}{\int_to_roman:w / (EXP)} % \begin{syntax} % "\int_to_roman:w" \textit{or} % \end{syntax} % Converts to it lowercase roman representation. Note that % it produces a string of letters with catcode 12. % \begin{texnote} % This is the \TeX{} primitive \tn{romannumeral} renamed. % \end{texnote} % \end{function} % % \begin{function}{\int_to_number:w / (EXP)} % \begin{syntax} % "\int_to_number:w" % \end{syntax} % Converts to its numerical string. Note that % it produces a string of letters with catcode 12. % \begin{texnote} % This is the \TeX{} primitive \tn{number} renamed. % \end{texnote} % \end{function} % % \begin{function}{ % \int_roman_lcuc_mapping:Nnn | % \int_to_roman_lcuc:NN | % } % \begin{syntax} % "\int_roman_lcuc_mapping:Nnn" \Arg{licr} \Arg{LICR} % "\int_to_roman_lcuc:NN" % \end{syntax} % "\int_roman_lcuc_mapping:Nnn" specifies how the roman % numeral (i, v, x, l, c, d, or m) should be % interpreted when converting the number. is the lower case and % is the uppercase mapping. "\int_to_roman_lcuc:NN" is a % recursive function converting the roman numerals. % \end{function} % % % \begin{function}{ % \int_convert_number_with_rule:nnN | % \int_alph_default_conversion_rule:n | % \int_Alph_default_conversion_rule:n | % \int_symbol_math_conversion_rule:n | % \int_symbol_text_conversion_rule:n | % } % \begin{syntax} % "\int_convert_number_with_rule:nnN" \Arg{int1} \Arg{int2} % "\int_alph_default_conversion_rule:n" \Arg{int} % \end{syntax} % "\int_convert_number_with_rule:nnN" converts into letters, % symbols, whatever as defined by . denotes the base % number for the conversion. % \end{function} % % % % % % % \section{Variable and constants} % % \begin{function}{% % \int_const:Nn | % } % \begin{syntax} % "\int_const:Nn" "\c_" \Arg{value} % \end{syntax} % Defines an integer constant of a certain . If the constant is negative % or very large it internally uses an register. % \end{function} % % \begin{variable}{ \c_minus_one | \c_zero | \c_one | \c_two | \c_three | % \c_four | \c_five | \c_six | \c_seven | \c_eight | % \c_nine | \c_ten | \c_eleven | \c_twelve | \c_thirteen | % \c_fourteen | \c_fifteen | \c_sixteen | \c_thirty_two | % \c_hundred_one | % \c_twohundred_fifty_five | \c_twohundred_fifty_six | % \c_thousand | % \c_ten_thousand | \c_ten_thousand_one | % \c_ten_thousand_two | \c_ten_thousand_three | % \c_ten_thousand_four | \c_twenty_thousand } % Set of constants denoting useful values. % \begin{texnote} % Some of these constants have been available under \LaTeX2 under names % like \tn{m@ne}, \tn{z@}, \tn{@ne},\tn{tw@}, \tn{thr@@}, etc. % \end{texnote} % \end{variable} % % \begin{variable}{% % \c_max_int | % } % Constant that denote the maximum value which can be stored in an % register. % \end{variable} % % % \begin{variable}{% % \l_tmpa_int | % \l_tmpb_int | % \l_tmpc_int | % \g_tmpa_int | % \g_tmpb_int | % } % Scratch register for immediate use. They are not used by conditionals % or predicate functions. % \end{variable} % % % % % \section{Conversion} % % \begin{function}{% % \int_convert_from_base_ten:nn | % } % \begin{syntax} % "\int_convert_from_base_ten:nn" \Arg{number} \Arg{base} % \end{syntax} % Converts the base~10 number into its equivalent % representation written in base~. Expandable. % \end{function} % % % \begin{function}{% % \int_convert_to_base_ten:nn | % } % \begin{syntax} % "\int_convert_to_base_ten:nn" \Arg{number} \Arg{base} % \end{syntax} % Converts the base~ number into its equivalent % representation written in base~10. can consist of digits % and ascii letters. Expandable. % \end{function} % % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3int} implementation} % % \subsection{Internal functions and variables} % % \begin{function}{\int_advance:w} % \begin{syntax} % "\int_advance:w" % \end{syntax} % Increments the count register by the specified amount. % \begin{texnote} % This is \TeX's \tn{advance}. % \end{texnote} % \end{function} % % % \begin{function}{\int_convert_number_to_letter:n / (EXP)} % \begin{syntax} % "\int_convert_number_to_letter:n" \Arg{integer expression} % \end{syntax} % Internal function for turning a number for a different base into a letter or digit. % \end{function} % % \begin{function}{\int_pre_eval_one_arg:Nn | \int_pre_eval_two_args:Nnn} % \begin{syntax} % "\int_pre_eval_one_arg:Nn" \Arg{integer expression} % "\int_pre_eval_one_arg:Nnn" \Arg{int~expr~1} \Arg{int~expr~2} % \end{syntax} % These are expansion helpers; they evaluate their integer expressions % before handing them off to the specified . % \end{function} % % \begin{function}{ \int_get_sign_and_digits:n / (EXP) | % \int_get_sign:n / (EXP ) | % \int_get_digits:n / (EXP) } % \begin{syntax} % "\int_get_sign_and_digits:n" \Arg{number} % \end{syntax} % From an argument that may or may not include a "+" or "-" sign, these % functions expand to the respective components of the number. % \end{function} % % \subsection{Module loading and primitives definitions} % % 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}{\int_to_roman:w} % \begin{macro}{\int_to_number:w} % \begin{macro}{\int_advance:w} % A new name for the primitives. % \begin{macrocode} \cs_new_eq:NN \int_to_roman:w \tex_romannumeral:D \cs_new_eq:NN \int_to_number:w \tex_number:D \cs_new_eq:NN \int_advance:w \tex_advance:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % Functions that support \LaTeX's user accessible counters should be % added here, too. But first the internal counters. % % \subsection{Allocation and setting} % % \begin{macro}{\int_new:N,\int_new:c} %^^A \begin{macro}{\int_new_l:N} % Allocation of a new internal counter is already done above. Here we define % the next likely variant. % % For the \LaTeX3 format: % \begin{macrocode} %<*initex> \alloc_setup_type:nnn {int} {11} \c_max_register_num \cs_new_nopar:Npn \int_new:N #1 {\alloc_reg:NnNN g {int} \tex_countdef:D#1} \cs_new_nopar:Npn \int_new_l:N #1 {\alloc_reg:NnNN l {int} \tex_countdef:D#1} % % \end{macrocode} % For `l3in2e': % \begin{macrocode} %<*package> \cs_new_nopar:Npn \int_new:N #1 { \chk_if_free_cs:N #1 \newcount #1 } % % \end{macrocode} % \begin{macrocode} \cs_generate_variant:Nn \int_new:N {c} % \end{macrocode} % \end{macro} %^^A \end{macro} % % % \begin{macro}{\int_set:Nn} % \begin{macro}{\int_set:cn} % \begin{macro}{\int_gset:Nn} % \begin{macro}{\int_gset:cn} % Setting counters is again something that I would like to make % uniform at the moment to get a better overview. % \begin{macrocode} \cs_new_nopar:Npn \int_set:Nn #1#2{#1 \intexpr_eval:w #2\intexpr_eval_end: %<*check> \chk_local_or_pref_global:N #1 % } \cs_new_nopar:Npn \int_gset:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_set:Nn } \cs_generate_variant:Nn\int_set:Nn {cn} \cs_generate_variant:Nn\int_gset:Nn {cn} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_incr:N} % \begin{macro}{\int_decr:N} % \begin{macro}{\int_gincr:N} % \begin{macro}{\int_gdecr:N} % \begin{macro}{\int_incr:c} % \begin{macro}{\int_decr:c} % \begin{macro}{\int_gincr:c} % \begin{macro}{\int_gdecr:c} % Incrementing and decrementing of integer registers is done with % the following functions. % \begin{macrocode} \cs_new_nopar:Npn \int_incr:N #1{\int_advance:w#1\c_one %<*check> \chk_local_or_pref_global:N #1 % } \cs_new_nopar:Npn \int_decr:N #1{\int_advance:w#1\c_minus_one %<*check> \chk_local_or_pref_global:N #1 % } \cs_new_nopar:Npn \int_gincr:N { % \end{macrocode} % We make sure that a local variable is not updated globally by % changing the internal test (i.e.\ |\chk_local_or_pref_global:N|) before % making the assignment. This is done by |\pref_global_chk:| which also % issues the necessary |\pref_global:D|. This is not very efficient, but % this code will be only included for debugging purposes. Using % |\pref_global:D| in front of the local function is better in the % production versions. % \begin{macrocode} %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_incr:N} \cs_new_nopar:Npn \int_gdecr:N { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_decr:N} % \end{macrocode} % With the |\int_add:Nn| functions we can shorten the above code. % If this makes it too slow \ldots % \begin{macrocode} \cs_set_nopar:Npn \int_incr:N #1{\int_add:Nn#1\c_one} \cs_set_nopar:Npn \int_decr:N #1{\int_add:Nn#1\c_minus_one} \cs_set_nopar:Npn \int_gincr:N #1{\int_gadd:Nn#1\c_one} \cs_set_nopar:Npn \int_gdecr:N #1{\int_gadd:Nn#1\c_minus_one} % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \int_incr:N {c} \cs_generate_variant:Nn \int_decr:N {c} \cs_generate_variant:Nn \int_gincr:N {c} \cs_generate_variant:Nn \int_gdecr:N {c} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_zero:N} % \begin{macro}{\int_zero:c} % \begin{macro}{\int_gzero:N} % \begin{macro}{\int_gzero:c} % Functions that reset an \m{int} register to zero. % \begin{macrocode} \cs_new_nopar:Npn \int_zero:N #1 {#1=\c_zero} \cs_generate_variant:Nn \int_zero:N {c} % \end{macrocode} % % \begin{macrocode} \cs_new_nopar:Npn \int_gzero:N #1 {\pref_global:D #1=\c_zero} \cs_generate_variant:Nn \int_gzero:N {c} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_add:Nn} % \begin{macro}{\int_add:cn} % \begin{macro}{\int_gadd:Nn} % \begin{macro}{\int_gadd:cn} % \begin{macro}{\int_sub:Nn} % \begin{macro}{\int_sub:cn} % \begin{macro}{\int_gsub:Nn} % \begin{macro}{\int_gsub:cn} % Adding and substracting to and from a counter \ldots % We should think of using these functions % \begin{macrocode} \cs_new_nopar:Npn \int_add:Nn #1#2{ % \end{macrocode} % We need to say |by| in case the first argument is a register % accessed by its number, e.g., |\count23|. Not that it should % ever happen but\dots % \begin{macrocode} \int_advance:w #1 by \intexpr_eval:w #2\intexpr_eval_end: %<*check> \chk_local_or_pref_global:N #1 % } \cs_new_nopar:Npn \int_sub:Nn #1#2{ \int_advance:w #1-\intexpr_eval:w #2\intexpr_eval_end: %<*check> \chk_local_or_pref_global:N #1 % } \cs_new_nopar:Npn \int_gadd:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_add:Nn } \cs_new_nopar:Npn \int_gsub:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_sub:Nn } \cs_generate_variant:Nn \int_add:Nn {cn} \cs_generate_variant:Nn \int_gadd:Nn {cn} \cs_generate_variant:Nn \int_sub:Nn {cn} \cs_generate_variant:Nn \int_gsub:Nn {cn} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_use:N} % \begin{macro}{\int_use:c} % Here is how counters are accessed: % \begin{macrocode} \cs_new_eq:NN \int_use:N \tex_the:D \cs_new_nopar:Npn \int_use:c #1{\int_use:N \cs:w#1\cs_end:} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_show:N} % \begin{macro}{\int_show:c} % Diagnostics. % \begin{macrocode} \cs_new_eq:NN \int_show:N \tex_showthe:D \cs_new_nopar:Npn \int_show:c {\exp_args:Nc \int_show:N } % \end{macrocode} % \end{macro} % \end{macro} % % % % % \begin{macro}{\int_to_arabic:n} % Nothing exciting here. % \begin{macrocode} \cs_new_nopar:Npn \int_to_arabic:n #1{ \intexpr_eval:n{#1}} % \end{macrocode} % \end{macro} % % % % \begin{macro}{\int_roman_lcuc_mapping:Nnn} % Using \TeX's built-in feature for producing roman numerals has some % surprising features. One is the the characters resulting from % |\int_to_roman:w| have category code~12 so they may fail in % certain comparison tests. Therefore we use a mapping from the % character \TeX{} produces to the character we actually want which % will give us letters with category code~11.% % \begin{macrocode} \cs_new_nopar:Npn \int_roman_lcuc_mapping:Nnn #1#2#3{ \cs_set_nopar:cpn {int_to_lc_roman_#1:}{#2} \cs_set_nopar:cpn {int_to_uc_roman_#1:}{#3} } % \end{macrocode} % \end{macro} % Here are the default mappings. I haven't found any examples of say % Turkish doing the mapping |i \i I| but at least there is a % possibility for it if needed. Note: I have now asked a Turkish % person and he tells me they do the |i I| mapping. % \begin{macrocode} \int_roman_lcuc_mapping:Nnn i i I \int_roman_lcuc_mapping:Nnn v v V \int_roman_lcuc_mapping:Nnn x x X \int_roman_lcuc_mapping:Nnn l l L \int_roman_lcuc_mapping:Nnn c c C \int_roman_lcuc_mapping:Nnn d d D \int_roman_lcuc_mapping:Nnn m m M % \end{macrocode} % For the delimiter we cheat and let it gobble its arguments instead. % \begin{macrocode} \int_roman_lcuc_mapping:Nnn Q \use_none:nn \use_none:nn % \end{macrocode} % % \begin{macro}{\int_to_roman:n} % \begin{macro}{\int_to_Roman:n} % \begin{macro}{\int_to_roman_lcuc:NN} % The commands for producing the lower and upper case roman numerals % run a loop on one character at a time and also carries some % information for upper or lower case with it. We put it through % |\intexpr_eval:n| first which is safer and more flexible. % \begin{macrocode} \cs_new_nopar:Npn \int_to_roman:n #1 { \exp_after:wN \int_to_roman_lcuc:NN \exp_after:wN l \int_to_roman:w \intexpr_eval:n {#1} Q } \cs_new_nopar:Npn \int_to_Roman:n #1 { \exp_after:wN \int_to_roman_lcuc:NN \exp_after:wN u \int_to_roman:w \intexpr_eval:n {#1} Q } \cs_new_nopar:Npn \int_to_roman_lcuc:NN #1#2{ \use:c {int_to_#1c_roman_#2:} \int_to_roman_lcuc:NN #1 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % % \begin{macro}{\int_convert_number_with_rule:nnN} % This is our major workhorse for conversions. |#1| is the number we % want converted, |#2| is the base number, and |#3| is the function % converting the number. This function expects to receive a % non-negative integer and as such is ideal for something using % |\if_case:w| internally. % % The basic example is this: We want to convert the number 50 (|#1|) % into an alphabetic equivalent |ax|. For the English language our % list contains 26 elements so this is our argument |#2| while the % function |#3| just turns |1| into |a|, |2| into |b|, etc. Hence our % goal is to turn 50 into the sequence |#3{1}#1{24}| so what we do is % to first divide 50 by 26 and truncating the result returning 1. % Then before we execute this we call the function again but this time % on the result of the remainder of the division. This goes on until % the remainder is less than or equal to the base number where we just % call the function |#3| directly on the number. % % We do a little pre-expansion of the arguments below as they % otherwise have a tendency to grow quite large. % \begin{macrocode} \cs_set_nopar:Npn \int_convert_number_with_rule:nnN #1#2#3{ \intexpr_compare:nNnTF {#1}>{#2} { \exp_args:Nf \int_convert_number_with_rule:nnN { \intexpr_div_truncate:nn {#1-1}{#2} }{#2} #3 % \end{macrocode} % Note that we have to nudge our modulus function so it won't % return~$0$ as that wouldn't work with |\if_case:w| when that % expects a positive number to produce a letter. % \begin{macrocode} \exp_args:Nf #3 { \intexpr_eval:n{1+\intexpr_mod:nn {#1-1}{#2}} } } { \exp_args:Nf #3{ \intexpr_eval:n{#1} } } } % \end{macrocode} % As can be seen it is even simpler to convert to number systems % that contain 0, since then we don't have to add or subtract 1 % here and there. % \end{macro} % % \begin{macro}{\int_alph_default_conversion_rule:n} % \begin{macro}{\int_Alph_default_conversion_rule:n} % Now we just set up a default conversion rule. Ideally every language % should have one such rule, as say in Danish there are 29 letters in % the alphabet. % \begin{macrocode} \cs_new_nopar:Npn \int_alph_default_conversion_rule:n #1{ \if_case:w #1 \or: a\or: b\or: c\or: d\or: e\or: f \or: g\or: h\or: i\or: j\or: k\or: l \or: m\or: n\or: o\or: p\or: q\or: r \or: s\or: t\or: u\or: v\or: w\or: x \or: y\or: z \fi: } \cs_new_nopar:Npn \int_Alph_default_conversion_rule:n #1{ \if_case:w #1 \or: A\or: B\or: C\or: D\or: E\or: F \or: G\or: H\or: I\or: J\or: K\or: L \or: M\or: N\or: O\or: P\or: Q\or: R \or: S\or: T\or: U\or: V\or: W\or: X \or: Y\or: Z \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\int_to_alph:n} % \begin{macro}{\int_to_Alph:n} % The actual functions are just instances of the generic function. The % second argument of |\int_convert_number_with_rule:nnN| should of % course match the number of |\or:|s in the conversion rule. % \begin{macrocode} \cs_new_nopar:Npn \int_to_alph:n #1{ \int_convert_number_with_rule:nnN {#1}{26} \int_alph_default_conversion_rule:n } \cs_new_nopar:Npn \int_to_Alph:n #1{ \int_convert_number_with_rule:nnN {#1}{26} \int_Alph_default_conversion_rule:n } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_to_symbol:n} % Turning a number into a symbol is also easy enough. % \begin{macrocode} \cs_new_nopar:Npn \int_to_symbol:n #1{ \mode_if_math:TF { \int_convert_number_with_rule:nnN {#1}{9} \int_symbol_math_conversion_rule:n } { \int_convert_number_with_rule:nnN {#1}{9} \int_symbol_text_conversion_rule:n } } % \end{macrocode} % \end{macro} % \begin{macro}{\int_symbol_math_conversion_rule:n} % \begin{macro}{\int_symbol_text_conversion_rule:n} % Nothing spectacular here. % \begin{macrocode} \cs_new_nopar:Npn \int_symbol_math_conversion_rule:n #1 { \if_case:w #1 \or: * \or: \dagger \or: \ddagger \or: \mathsection \or: \mathparagraph \or: \| \or: ** \or: \dagger\dagger \or: \ddagger\ddagger \fi: } \cs_new_nopar:Npn \int_symbol_text_conversion_rule:n #1 { \if_case:w #1 \or: \textasteriskcentered \or: \textdagger \or: \textdaggerdbl \or: \textsection \or: \textparagraph \or: \textbardbl \or: \textasteriskcentered\textasteriskcentered \or: \textdagger\textdagger \or: \textdaggerdbl\textdaggerdbl \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\l_tmpa_int} % \begin{macro}{\l_tmpb_int} % \begin{macro}{\l_tmpc_int} % \begin{macro}{\g_tmpa_int} % \begin{macro}{\g_tmpb_int} % We provide four local and two global scratch counters, maybe we % need more or less. % \begin{macrocode} \int_new:N \l_tmpa_int \int_new:N \l_tmpb_int \int_new:N \l_tmpc_int \int_new:N \g_tmpa_int \int_new:N \g_tmpb_int % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % % % \begin{macro}{\int_pre_eval_one_arg:Nn} % \begin{macro}{\int_pre_eval_two_args:Nnn} % These are handy when handing down values to other % functions. All they do is evaluate the number in advance. % \begin{macrocode} \cs_set_nopar:Npn \int_pre_eval_one_arg:Nn #1#2{ \exp_args:Nf#1{\intexpr_eval:n{#2}}} \cs_set_nopar:Npn \int_pre_eval_two_args:Nnn #1#2#3{ \exp_args:Nff#1{\intexpr_eval:n{#2}}{\intexpr_eval:n{#3}} } % \end{macrocode} % \end{macro} % \end{macro} % % % % % \subsection{Defining constants} % \begin{macro}{\int_const:Nn} % As stated, most constants can be defined as |\tex_chardef:D| or % |\tex_mathchardef:D| but that's engine dependent. % \begin{macrocode} \cs_new_nopar:Npn \int_const:Nn #1#2 { \intexpr_compare:nNnTF {#2} > \c_minus_one { \intexpr_compare:nNnTF {#2} > \c_max_register_num { \int_new:N #1 \int_set:Nn #1{#2} } { \chk_if_free_cs:N #1 \tex_mathchardef:D #1 = \intexpr_eval:n{#2} } } { \int_new:N #1 \int_set:Nn #1{#2} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\c_minus_one, % \c_zero, \c_one, \c_two, \c_three, \c_four, \c_five, \c_six, % \c_seven, \c_eight, \c_nine, \c_ten, % \c_eleven, \c_twelve, \c_thirteen, \c_fourteen, \c_fifteen, % \c_sixteen, \c_thirty_two, % \c_hundred_one, % \c_twohundred_fifty_five, \c_twohundred_fifty_six, % \c_thousand, % \c_ten_thousand, % \c_ten_thousand_one, \c_ten_thousand_two, % \c_ten_thousand_three, \c_ten_thousand_four, % \c_twenty_thousand} % And the usual constants, others are still missing. Please, make % every constant a real constant at least for the moment. We can % easily convert things in the end when we have found what % constants are used in critical places and what not. % \begin{macrocode} %% \tex_countdef:D \c_minus_one = 10 \scan_stop: %% \c_minus_one = -1 \scan_stop: %% in l3basics %\int_const:Nn \c_zero {0} \int_const:Nn \c_one {1} \int_const:Nn \c_two {2} \int_const:Nn \c_three {3} \int_const:Nn \c_four {4} \int_const:Nn \c_five {5} \int_const:Nn \c_six {6} \int_const:Nn \c_seven {7} \int_const:Nn \c_eight {8} \int_const:Nn \c_nine {9} \int_const:Nn \c_ten {10} \int_const:Nn \c_eleven {11} \int_const:Nn \c_twelve {12} \int_const:Nn \c_thirteen {13} \int_const:Nn \c_fourteen {14} \int_const:Nn \c_fifteen {15} %% \tex_chardef:D \c_sixteen = 16\scan_stop: %% in l3basics \int_const:Nn \c_thirty_two {32} % \end{macrocode} % The next one may seem a little odd (obviously!) but is useful when % dealing with logical operators. % \begin{macrocode} \int_const:Nn \c_hundred_one {101} \int_const:Nn \c_twohundred_fifty_five{255} \int_const:Nn \c_twohundred_fifty_six {256} \int_const:Nn \c_thousand {1000} \int_const:Nn \c_ten_thousand {10000} \int_const:Nn \c_ten_thousand_one {10001} \int_const:Nn \c_ten_thousand_two {10002} \int_const:Nn \c_ten_thousand_three {10003} \int_const:Nn \c_ten_thousand_four {10004} \int_const:Nn \c_twenty_thousand {20000} % \end{macrocode} % \end{macro} % % \begin{macro}{\c_max_int} % The largest number allowed is $2^{31}-1$ % \begin{macrocode} \int_const:Nn \c_max_int {2147483647} % \end{macrocode} % \end{macro} % % % % \subsection{Scanning and conversion} % % % Conversion between different numbering schemes requires meticulous % work. A number can be preceeded by any number of |+| and/or |-|. We % define a generic function which will return the sign and/or the % remainder. % % \begin{macro}{\int_get_sign_and_digits:n} % \begin{macro}{\int_get_sign:n} % \begin{macro}{\int_get_digits:n} % \begin{macro}[aux]{\int_get_sign_and_digits_aux:nNNN} % \begin{macro}[aux]{\int_get_sign_and_digits_aux:oNNN} % A number may be preceeded by any number of |+|s and |-|s. Start out % by assuming we have a positive number. % \begin{macrocode} \cs_new_nopar:Npn \int_get_sign_and_digits:n #1{ \int_get_sign_and_digits_aux:nNNN {#1} \c_true_bool \c_true_bool \c_true_bool } \cs_new_nopar:Npn \int_get_sign:n #1{ \int_get_sign_and_digits_aux:nNNN {#1} \c_true_bool \c_true_bool \c_false_bool } \cs_new_nopar:Npn \int_get_digits:n #1{ \int_get_sign_and_digits_aux:nNNN {#1} \c_true_bool \c_false_bool \c_true_bool } % \end{macrocode} % Now check the first character in the string. Only a |-| can change % if a number is positive or negative, hence we reverse the boolean % governing this. Then gobble the |-| and start over. % \begin{macrocode} \cs_new_nopar:Npn \int_get_sign_and_digits_aux:nNNN #1#2#3#4{ \tl_if_head_eq_charcode:fNTF {#1} - { \bool_if:NTF #2 { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} \c_false_bool #3#4 } { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} \c_true_bool #3#4 } } % \end{macrocode} % The other cases are much simpler since we either just have to gobble % the |+| or exit immediately and insert the correct sign. % \begin{macrocode} { \tl_if_head_eq_charcode:fNTF {#1} + { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} #2#3#4} { % \end{macrocode} % The boolean |#3| is for printing the sign while |#4| is for printing % the digits. % \begin{macrocode} \bool_if:NT #3 { \bool_if:NF #2 - } \bool_if:NT #4 {#1} } } } \cs_generate_variant:Nn \int_get_sign_and_digits_aux:nNNN {oNNN} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_convert_from_base_ten:nn} % \begin{macro}[aux]{\int_convert_from_base_ten_aux:nnn} % \begin{macro}[aux]{\int_convert_from_base_ten_aux:non} % \begin{macro}[aux]{\int_convert_from_base_ten_aux:fon} % |#1| is the base 10 number to be converted to base |#2|. We split % off the sign first, print if if there and then convert only the % number. Since this is supposedly a base~10 number we can let \TeX\ % do the reading of |+| and |-|. % \begin{macrocode} \cs_set_nopar:Npn \int_convert_from_base_ten:nn#1#2{ \intexpr_compare:nNnTF {#1}<\c_zero { - \int_convert_from_base_ten_aux:nfn {} { \intexpr_eval:n {-#1} } } { \int_convert_from_base_ten_aux:nfn {} { \intexpr_eval:n {#1} } } {#2} } % \end{macrocode} % The algorithm runs like this: % \begin{enumerate} % \item If the number \meta{num} is greater than \meta{base}, % calculate modulus of \meta{num} and \meta{base} and carry that % over for next round. The remainder is calculated as a truncated % division of \meta{num} and \meta{base}. Start over with these new % values. % \item If \meta{num} is less than or equal to \meta{base} convert it % to the correct symbol, print the previously calculated digits and % exit. % \end{enumerate} % |#1| is the carried over result, |#2| the remainder and |#3| the % base number. % \begin{macrocode} \cs_new_nopar:Npn \int_convert_from_base_ten_aux:nnn#1#2#3{ \intexpr_compare:nNnTF {#2}<{#3} { \int_convert_number_to_letter:n{#2} #1 } { \int_convert_from_base_ten_aux:ffn { \int_convert_number_to_letter:n {\intexpr_mod:nn {#2}{#3}} #1 } { \intexpr_div_truncate:nn{#2}{#3}} {#3} } } \cs_generate_variant:Nn \int_convert_from_base_ten_aux:nnn {nfn} \cs_generate_variant:Nn \int_convert_from_base_ten_aux:nnn {ffn} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_convert_number_to_letter:n} % Turning a number for a different base into a letter or digit. % \begin{macrocode} \cs_set_nopar:Npn \int_convert_number_to_letter:n #1{ \if_case:w \intexpr_eval:w #1-10\intexpr_eval_end: \exp_after:wN A \or: \exp_after:wN B \or: \exp_after:wN C \or: \exp_after:wN D \or: \exp_after:wN E \or: \exp_after:wN F \or: \exp_after:wN G \or: \exp_after:wN H \or: \exp_after:wN I \or: \exp_after:wN J \or: \exp_after:wN K \or: \exp_after:wN L \or: \exp_after:wN M \or: \exp_after:wN N \or: \exp_after:wN O \or: \exp_after:wN P \or: \exp_after:wN Q \or: \exp_after:wN R \or: \exp_after:wN S \or: \exp_after:wN T \or: \exp_after:wN U \or: \exp_after:wN V \or: \exp_after:wN W \or: \exp_after:wN X \or: \exp_after:wN Y \or: \exp_after:wN Z \else: \use_i_after_fi:nw{ #1 }\fi: } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_convert_to_base_ten:nn} % |#1| is the number, |#2| is its base. First we get the sign, then % use only the digits/letters from it and pass that onto a new % function. % \begin{macrocode} \cs_set_nopar:Npn \int_convert_to_base_ten:nn #1#2 { \intexpr_eval:n{ \int_get_sign:n{#1} \exp_args:Nf\int_convert_to_base_ten_aux:nn {\int_get_digits:n{#1}}{#2} } } % \end{macrocode} % This is an intermediate function to get things started. % \begin{macrocode} \cs_new_nopar:Npn \int_convert_to_base_ten_aux:nn #1#2{ \int_convert_to_base_ten_auxi:nnN {0}{#2} #1 \q_nil } % \end{macrocode} % Here we check each letter/digit and calculate the next number. |#1| % is the previously calculated result (to be multiplied by the base), % |#2| is the base and |#3| is the next letter/digit to be added. % \begin{macrocode} \cs_new_nopar:Npn \int_convert_to_base_ten_auxi:nnN#1#2#3{ \quark_if_nil:NTF #3 {#1} {\exp_args:Nf\int_convert_to_base_ten_auxi:nnN {\intexpr_eval:n{ #1*#2+\int_convert_letter_to_number:N #3} } {#2} } } % \end{macrocode} % This is for turning a letter or digit into a number. This function % also takes care of handling lowercase and uppercase letters. Hence % |a| is turned into |11| and so is |A|. % \begin{macrocode} \cs_set_nopar:Npn \int_convert_letter_to_number:N #1{ \intexpr_compare:nNnTF{`#1}<{58}{#1} { \intexpr_eval:n{ `#1 - \intexpr_compare:nNnTF{`#1}<{91}{ 55 }{ 87 } } } } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % Show token usage: % \begin{macrocode} %<*showmemory> \showMemUsage % % \end{macrocode} % % \end{implementation} % \PrintIndex % % % \endinput