%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Repeat loop macro, version 0.93, May 2003 % Copyright Victor Eijkhout 2000 % file name: repeat.tex % % Author: % Victor Eijkhout % Department of Computer Science % University of Tennessee, Knoxville TN 37996 % % victor@eijkhout.net % % This program is free software; you can redistribute it and/or % modify it under the terms of the GNU General Public License % as published by the Free Software Foundation; either version 2 % of the License, or (at your option) any later version. % % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % For a copy of the GNU General Public License, write to the % Free Software Foundation, Inc., % 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, % or find it on the net, for instance at % http://www.gnu.org/copyleft/gpl.html % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % General loop macro: % \repeat % \for{} \from{} \by{} \to{} \downto{} % \until{} \while{} % \do { } % where all control sequences in between \repeat and \do are optional. % The space after each argument is mandatory! % (This implies that you will have to write "\from\i" as "\from{\i}".) % % 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. % % 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, eliminated unwanted space caused by % "\for{ijk} \do{...}", December 2000 % 0.93 added missing percent signs at end of lines to prevent unwanted % spaces, May 2003 ({\'E}. Dupuis). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %% %% Prevent multiple loading of this file %% \expandafter\ifx\csname REPdepth\endcsname\relax \message{Loading loop macro, version 0.93}% \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} %\def\cscsarg#1#2#3{\expandafter#1\expandafter#2\csname#3\endcsname} %\def\REPcsREPcsargrom#1#2#3{\expandafter#1\expandafter#2% % \csname#3\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}}% %% %% 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}}\REPtmp}% \def\from##1 {\REPcsargrom\global{REPcount}##1\relax}% \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}}\REPtmp}% \def\downto##1 {\gdef\REPsign{-}\gdef\REPcomp{<}\to{##1}}% \def\by##1 {\ifnum##1<0 \message{REPEAT: increment has to be >0}% \REPcsargrom\gdef{REPinc}{-##1}\else% \REPcsargrom\gdef{REPinc}{##1}\fi}% \def\until##1 {\edef\REPtmp{\global\REPcsargrom\noexpand{REPutest}=% {\noexpand##1\relax% \noexpand\expandafter \noexpand\breakrepeat \noexpand\fi}}\REPtmp}% \def\while##1 {\edef\REPtmp{\global\REPcsargrom\noexpand{REPwtest}=% {\noexpand##1\relax \noexpand\else% \noexpand\expandafter \noexpand\breakrepeat \noexpand\fi}}\REPtmp}% \from{1} \by{1} #1% \endgroup}% \def\REPzero% {\REPcsrom{REPtoks}{}\REPcsrom{REPutest}{}\REPcsrom{REPwtest}{}% \REPcsargrom\def{REPbody}{}}% \endinput %\tracingmacros2 \repeat \for{i} \by{2} \do { \ifnum\i=13 \expandafter\breakrepeat \fi \message{doing \number\i} } \repeat \for{iii} \to{8} \do {} \message{After loop: \number\iii} \repeat \for{i} \from{10} \by{2} \downto{0} \do { \message{countdown \number\i} } \repeat \for{x} \while{\ifnum\x<7} \do { \message{going \number\x} } \repeat \to{3} \do { \message{hello there!} } \newcount\tmpcount \repeat \for{j} \until{\tmpcount\j \divide\tmpcount by 37 \noexpand\ifnum\tmpcount=1} \do { \message{testing \number\j} } \repeat \for{i} \by{2} \to{10} \do {\repeat \for{j} \from{\i} \by{3} \to{18} \do {\message{(\number\i.\number\j)} }} % infinite loop %\repeat \do {} \bye