Last active
August 12, 2019 23:54
-
-
Save texdraft/fb93aa8edca268f657895ff8c4b529b0 to your computer and use it in GitHub Desktop.
Sketching goto in TeX (with a bonus at the end)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
% Towards goto in plain TeX. | |
% This works in LaTeX (after adding \documentclass and | |
% \begin{documen} too. | |
% Surely this would have more legitimacy if it were wrapped in a snazzy macro | |
% that let you say \goto and not manually set the program counter. | |
% E.g.: | |
% | |
% \tagbody{ % (homage to Common Lisp) | |
% \label\A | |
% first | |
% \goto\C | |
% \label\B | |
% third | |
% \return | |
% \label\C | |
% second | |
% \goto\B | |
% } | |
% | |
% If implementing this for LaTeX, \label should be changed to something else, | |
% such as \lab. As another Lisp homage, I'd suggest \tag, but that's a LaTeX | |
% command too. Or redefine \label (or \tag) within \tagbody. Of course, in | |
% LaTeX \tagbody should probably be made implemented as an environment. | |
% I believe that there's a BASIC interpreter embedded in Haskell as a DSL which | |
% works by ``overloading'' numbers to handle the beginning line number labels. | |
% A similar solution could be pursued so something like | |
% | |
% \tagbody { | |
% 1: | |
% first | |
% \goto3 | |
% 2: | |
% third | |
% \return | |
% 3: | |
% second | |
% \goto2 | |
% } | |
% | |
% would work, using some magic (looking ahead to see if sequence of digits ends | |
% with a colon, perhaps). A different approach could be taken to allow the | |
% following to be possible: | |
% | |
% \tagbody { | |
% \A: | |
% first | |
% \goto\C | |
% \B: | |
% third | |
% \return | |
% \C: | |
% second | |
% \goto\B | |
% } | |
% | |
% (Possible solution: make some other character the escape character, like the | |
% at sign, make backslash active, and do @def\#1:{...} to be like \label#1, if | |
% the control sequence named by #1 isn't already defined (to allow people to | |
% use commands followed by colons in ordinary test); if it is defined then just | |
% expand into that command.) | |
% \goto could possibly be defined to immediately end execution and | |
% ``jump'' to the label reqeusted. | |
% Anyway, here are some ways to approach goto-like functionality. | |
% See also Guy Steele's ``Debunking the `expensive procedure call' myth'' | |
% (AKA Lambda: The Ultimate GOTO) at https://dspace.mit.edu/handle/1721.1/5753. | |
\newcount\pc | |
\pc=0 | |
\newif\ifnotdone | |
\let\return=\notdonefalse | |
% Simple version | |
% The output is A B C D E F G | |
\notdonetrue | |
\loop | |
\ifnum\pc=0 % | |
\immediate\write16{Entry} | |
\pc=1 | |
\else\ifnum\pc=1 % | |
A | |
\message{Statement 1} | |
\pc=3 | |
\else\ifnum\pc=2 % | |
G | |
\message{Statement 2} | |
\return | |
\else\ifnum\pc=3 % | |
B | |
\message{Statement 3} | |
\pc=6 | |
\else\ifnum\pc=4 % | |
D | |
\message{Statement 4} | |
\pc=7 | |
\else\ifnum\pc=7 % | |
E | |
\message{Statement 7} | |
\pc=5 | |
\else\ifnum\pc=6 % | |
C | |
\message{Statement 6} | |
\pc=4 | |
\else\ifnum\pc=5 % | |
F | |
\message{Statement 5} | |
\pc=2 | |
\fi\fi\fi\fi\fi\fi\fi\fi | |
\ifnotdone | |
\repeat | |
% Here's a different form, which allows for code to happen between | |
% ``branches''. | |
% Each backwards jump causes another iteration, whereas in the previous one | |
% every single jump caused another iteration; therefore, this version might be | |
% faster. In this case, there are two, so LOOP is printed three times. | |
\pc=0 | |
\notdonetrue | |
\loop\immediate\write16{LOOP}% this prints every iteration | |
\ifnum\pc=0% | |
\immediate\write16{Entry} | |
\pc=1 | |
\fi | |
\ifnum\pc=1 % | |
A | |
\message{Statement 1} | |
\pc=3 | |
\fi | |
\message{This will also print every iteration,.} | |
\ifnum\pc=2 % | |
G | |
\message{Statement 2} | |
\return | |
\fi | |
\ifnum\pc=3 % | |
B | |
\message{Statement 3} | |
\pc=6 | |
\fi | |
\ifnum\pc=4 % | |
D | |
\message{Statement 4} | |
\pc=7 | |
\fi | |
\ifnum\pc=7 % | |
E | |
\message{Statement 7} | |
\pc=5 | |
\fi | |
\ifnum\pc=6 % | |
C | |
\message{Statement 6} | |
\pc=4 | |
\fi | |
\ifnum\pc=5 % | |
F | |
\message{Statement 5} | |
\pc=2 | |
\fi | |
\ifnotdone | |
\repeat | |
% Here's one with only backwards branches (very inneficient), and with font | |
% changing. Each font command only affects the branches above it, and until the | |
% next font command. More statements have been added to better illustrate this. | |
\pc=0 | |
\notdonetrue | |
\loop\immediate\write16{LOOP}% prints 11 times | |
\ifnum\pc=1 % Roman J | |
J | |
\message{Statement 1} | |
\return | |
\fi | |
\ifnum\pc=2 % bold I | |
I\rm | |
\message{Statement 2} | |
\pc=1 | |
\fi | |
\ifnum\pc=3 % Roman H | |
H\bf | |
\message{Statement 3} | |
\pc=2 | |
\fi | |
\ifnum\pc=4 % italic G | |
G\rm | |
\message{Statement 4} | |
\pc=3 | |
\fi | |
\ifnum\pc=5 % | |
F% italic F | |
\message{Statement 5} | |
\pc=4 | |
\fi | |
\ifnum\pc=6 % | |
E% italic E | |
\message{Statement 6} | |
\pc=5 | |
\fi | |
\ifnum\pc=7 % slanted D | |
D\it | |
\message{Statement 7} | |
\pc=6 | |
\fi | |
\ifnum\pc=8 % bold C | |
C\sl | |
\message{Statement 8} | |
\pc=7 | |
\fi | |
\ifnum\pc=9 % | |
B% bold B | |
\message{Statement 9} | |
\pc=8 | |
\fi | |
\ifnum\pc=10 % Roman A | |
A\bf | |
\message{Statement 10} | |
\pc=9 | |
\fi | |
\ifnum\pc=0 % | |
\immediate\write16{Entry} | |
\pc=10 | |
\fi | |
\ifnotdone | |
\repeat | |
% Finally, here's something like Duff's device, whose original form is the | |
% following (in pre-ANSI C): | |
% send(to, from, count) | |
% register short *to, *from; | |
% register count; | |
% { | |
% register n=(count+7)/8; | |
% switch(count%8) { | |
% case 0: do{ *to = *from++; | |
% case 7: *to = *from++; | |
% case 6: *to = *from++; | |
% case 5: *to = *from++; | |
% case 4: *to = *from++; | |
% case 3: *to = *from++; | |
% case 2: *to = *from++; | |
% case 1: *to = *from++; | |
% } while(--n>0); | |
% } | |
% } | |
% (See https://www.lysator.liu.se/c/duffs-device.html) | |
% This is just a curiosity and not really agreat showcase of a goto. It's also | |
% untested, and wouldn't actually `work' regardless: \duffsend will certainly | |
% NOT ``copy an array of shorts to the Programmed IO data register of an Evans | |
% & Sutherland Picture System II'' as the original does :). | |
% There's surely a way to simulate C's pointers etc. to make it functional, but | |
% (1) why? and (2) that's difficult. | |
% Parameters | |
\newcount\ptrto % register short *to | |
\newcount\ptrfrom % register short *from | |
\newcount\regcount % register [int] count | |
% Note that TeX has special meanings of both `register' and `count'! | |
% You could use e-TeX's \numexpr to simplify this, but this works with any | |
% engine. | |
\newcount\n % = (count+7)/8 | |
\n=\regcount | |
\advance\n by 7 | |
\divide\n by 8 | |
\newcount\swcount % will be (count%8) | |
\swcount=\regcount | |
\divide\swcount by 8 | |
\multiply\swcount by 8 | |
\multiply\swcount by -1 | |
\advance\swcount by \regcount\relax | |
\pc=0 | |
\notdonetrue | |
\def\duffsend{ | |
\loop | |
\pc=\swcount % switch(count%8) { | |
\ifnum\pc=0 % case 0: do { | |
\advance\ptrfrom by 1% *from++ | |
\advance\ptrto by \ptrfrom % *to = *from | |
\pc=7 | |
\fi | |
\ifnum\pc>6 % case 7: | |
\advance\ptrfrom by 1 | |
\advance\ptrto by \ptrfrom | |
\pc=7 | |
\fi | |
\ifnum\pc>5 % case 6: | |
\advance\ptrfrom by 1 | |
\advance\ptrto by \ptrfrom | |
\pc=7 | |
\fi | |
\ifnum\pc>4 % case 5 | |
\advance\ptrfrom by 1 | |
\advance\ptrto by \ptrfrom | |
\pc=7 | |
\fi | |
\ifnum\pc>3 % case 4 | |
\advance\ptrfrom by 1 | |
\advance\ptrto by \ptrfrom | |
\pc=7 | |
\fi | |
\ifnum\pc>2 % case 3 | |
\advance\ptrfrom by 1 | |
\advance\ptrto by \ptrfrom | |
\pc=7 | |
\fi | |
\ifnum\pc>1 % case 2 | |
\advance\ptrfrom by 1 | |
\advance\ptrto by \ptrfrom | |
\pc=7 | |
\fi | |
\ifnum\pc>0 % case 1 | |
\advance\ptrfrom by 1 | |
\advance\ptrto by \ptrfrom | |
\pc=7 | |
\fi | |
\advance\n by -1 % --n | |
\ifnum\n=0 % } while(n>0) | |
\return | |
\fi | |
\ifnotdone | |
\repeat % } | |
} | |
\end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment