%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Repeat loop macro, version 0.93a, September 2006 % Copyright Victor Eijkhout 1999-2006 % file name: repeat.tex % % Author: % Victor Eijkhout % Texas Advanced Computing Center % The University of Texas at Austin, Austin TX 78758, USA % % victor@eijkhout.net % % This program is released under the LaTeX Project Public License % see for further information. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % General loop macro: % \repeat % \for{} \from{} \by{} \to{} \downto{} % \until{} \while{} % \do { } % where all control sequences in between \repeat and \do are optional. % % var: characters to form a control sequence; % after \for{index} you can access the loop counter as \index. % This is a count register; to print it use \number\index. % start,step,end: integers with obvious relations to the loop counter; % start and step have a default value of 1 % cond: (sequence of commands ending in) any TeX \if... test. % % Count down instead of up with \downto; the increment given in \by % is always positive, and is added or subtracted accordingly. % % Tests: \until is evaluated at the end of the loop body; \while % at the beginning of the loop body. % % Exit from middle of loop: \breakrepeat % use this at any place in the loop; in case of a conditional use % \ifsomething ... \expandafter \breakrepeat \fi % % There are some examples at the end of this file, after the \endinput line; % remove the \endinput statement to see the examples executed. % Note that the line ends do not cause spaces in the output. % % Technical details: % The loop body is not executed in a group: the braces are those % of a token list. % The `for' variable is \let to a \count register. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % revision history: % 0.9 first release, January 1999 % 0.91 documentation update, % csarg-like control sequences made REP... % counter update made global in case the body issues grouping, % copyright notice, February 1999 % 0.92 installed trace switches % 0.93 spaces are now ignored after each argument group. Author info updated. % 0.93a removed \bye from \endinput line. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %% %% Prevent multiple loading of this file %% \expandafter\ifx\csname REPdepth\endcsname\relax \message{Loading loop macro, version 0.93a}% \else \endinput \fi %% %% Auxiliary stuff %% \def\REPcsarg#1#2{\expandafter#1\csname#2\endcsname} \def\REPcsrom#1{\csname #1\romannumeral\REPdepth\endcsname} \def\REPcsargrom#1#2{\expandafter#1\csname#2\romannumeral\REPdepth\endcsname} \newcount\REPdepth \let\endrepeat\relax \def\csprotect{} % Trace switches may later be defined by PAC_utils \let\REPtraceinit\relax \let\REPtraceexit\relax %% %% Main repeat macro %% - go to next level and allocate unique counter/toks if this is the %% first time we visit this level %% - setup: gather bounds and termination conditions %% - scoop up body in token list; after the assignment define and %% execute body %% \def\repeat#1\do{\REPtraceinit % exit in \breakrepeat \advance\REPdepth by 1\relax \REPcsargrom\ifx{REPcount}\relax \REPcsargrom{\csname newcount\expandafter\endcsname}{REPcount}% \REPcsargrom{\csname newtoks\expandafter\endcsname}{REPtoks}% \REPcsargrom{\csname newtoks\expandafter\endcsname}{REPwtest}% \REPcsargrom{\csname newtoks\expandafter\endcsname}{REPutest}% \fi \REPzero \def\REPsign{}\def\REPcomp{>}\REPsetup{#1}% \edef\REPtmp {\def\REPcsargrom\noexpand{REPrepeat}{\REPcsargrom\noexpand{REPbody}}}\REPtmp \afterassignment\REPdxbody\REPcsrom{REPtoks}} %% %% Define and execute loop body %% This is done with an \edef to construct the actual sequence %% \def\REPdxbody{\REPcsargrom\edef{REPbody}{% \REPcsargrom\the{REPwtest}% \noexpand\the\REPcsargrom\noexpand{REPtoks}% \REPcsargrom\the{REPutest}% \global\REPcsargrom\advance{REPcount} by \REPsign\REPcsrom{REPinc}\relax \noexpand\endrepeat \REPcsargrom\noexpand{REPrepeat}}% \REPcsrom{REPbody}\ignorespaces} %% %% Stop test %% In order to stop, issue a %% \breakrepeat which scoops up the rest of the body and exits %% \def\breakrepeat#1\endrepeat{\REPzero\REPcsargrom\let{REPrepeat}\relax \advance\REPdepth by -1 \REPtraceexit } %% %% Setup %% gather bounds and termination conditions %% \def\REPsetup#1{% \begingroup \def\for##1{% \edef\REPtmp{% \global\let\REPcsarg\noexpand{##1}\REPcsrom{REPcount}\ignorespaces}% \REPtmp}% \def\from##1{\REPcsargrom\global{REPcount}##1\ignorespaces}% \def\to##1{% \edef\REPtmp{\global\REPcsargrom\noexpand{REPwtest}= {\REPcsargrom\the{REPwtest}% \noexpand\ifnum\REPcsargrom\noexpand{REPcount}\REPcomp##1\relax \noexpand\expandafter \noexpand\breakrepeat \noexpand\fi}\ignorespaces}% \REPtmp}% \def\downto##1{% \gdef\REPsign{-}\gdef\REPcomp{<}\to{##1}\ignorespaces}% \def\by##1{\ifnum##1<0 \message{REPEAT: increment has to be >0}% \REPcsargrom\gdef{REPinc}{-##1}\else \REPcsargrom\gdef{REPinc}{##1}\fi\ignorespaces}% \def\until##1{% \edef\REPtmp{\global\REPcsargrom\noexpand{REPutest}= {\noexpand##1\relax \noexpand\expandafter \noexpand\breakrepeat \noexpand\fi}\ignorespaces}% \REPtmp}% \def\while##1{% \edef\REPtmp{\global\REPcsargrom\noexpand{REPwtest}= {\noexpand##1\relax \noexpand\else \noexpand\expandafter \noexpand\breakrepeat \noexpand\fi}\ignorespaces}% \REPtmp}% \from{1}\by{1}#1% \endgroup} \def\REPzero {\REPcsrom{REPtoks}{}\REPcsrom{REPutest}{}\REPcsrom{REPwtest}{}% \REPcsargrom\def{REPbody}{}} \endinput %\tracingmacros2 \newcount\tmpcount % used in some examples below 1 \repeat \for{i} \by{2} \do {% \ifnum\i=13 \expandafter\breakrepeat \fi \message{doing \number\i}% }% 2 \repeat \for{iii} \to{8} \do {} \message{After loop: \number\iii}% 3 \repeat \for{i} \from{10} \by{2} \downto{0} \do {\message{countdown \number\i}} 4 \repeat \for{x} \while{\ifnum\x<7} \do {\message{going \number\x}} 5 \repeat \to{3} \do {\message{hello there!}} 6 \repeat \for{j} \until{\tmpcount\j \divide\tmpcount by 37 \noexpand\ifnum\tmpcount=1} \do {\message{testing \number\j}} 7 \repeat \for{i} \by{2} \to{10} \do {\repeat \for{j} \from{\i} \by{3} \to{18} \do {\message{(\number\i.\number\j)}} } 8 1 2 3 4 5 6 7 8 % infinite loop %\repeat \do {} \bye