Il principale vantaggio di inserire liste di token in registri\toksè che fino a quando non vengono ‘liberate’ non sono soggette all’espansione e le possiamo modificare in modo abbastanza agevole. Le prime due tecniche sono molto simili a quanto visto a proposito del testo di sostituzione di una macro. Se dobbiamo aggiungere token alla fine di una lista data, contenuta in un registro token, la tecnica è semplice:
\newcommand\toksappend[2]{#1=\expandafter{\the#1#2}}
dove come primo argomento diamo il nome del registro e come secondo la lista di token da aggiungere, per esempio
\toksappend{\pippo}{aa\relax\xyz}
Si deve fare molta attenzione a quello che mettiamo nel secondo argomento se il primo è un registro esplicito (temporaneo, per esempio); infatti con
\toksappend{\toks0}{1 b} otterremmo come espansione
\toks0=\expandafter{\the\toks01 b}
e quindi ne risulterebbe la lista contenuta nel registro\toks1, non proprio quello che vogliamo! Per TEX,01è un 〈numero 〉 e vale 1. In questo caso si scriva uno fra
\toksappend{\toks0}{ 1 b} \toksappend{\toks0 }{1 b}
perché lo spazio dopo lo zero sarà ignorato, dato che segue una costante richiesta dalla sintassi. Non c’è pericolo di un circolo vizioso, perché\the\toks0o, in genera-le,\the〈registro token 〉 viene valutato prima che sia eseguita l’assegnazione effettiva, come già osservato.
* In LATEX c’è già\toksappende si chiama\addto@hook, con la stessa definizione. Si potrebbe curare il problema della non arbitrarietà degli argomenti definendo
\newcommand\addto@hook#1#2{% \toks@=#1%
#1=\expandafter{\the\toks@#2}}
ma non vale la pena di prendere precauzioni che possono servire solo in casi veramente eccezionali. Se per caso si desse come primo argomento proprio\toks@l’assegnazione sulla seconda riga non farebbe nulla di pericoloso.
Se dobbiamo aggiungere una lista di token davanti al contenuto di un registro possiamo usare ancora una strategia simile a quella per\g@laddto@macro:
\newcommand\toksprepend[2]{% \toks@={#2}\@temptokena={#3}%
#1=\expandafter{\the\expandafter\toks@\the#1}}
dove il primo argomento è un registro che non sia\toks@e il secondo è la lista di token da aggiungere.
Se vogliamo concatenare due registri token, possiamo fare in modo analogo:
\newcommand\concatenate[3]{% \toks@=#2\@temptokena=#3%
(adoperiamo qui il registro\tokstemporaneo\@temptokenaallocato dal nucleo di LATEX). I tre argomenti devono essere nomi di registri token (esclusi\toks@e \@temptokena), come primo possiamo anche usare uno degli altri due; vediamo l’e-spansione di\concatenate{\pippo}{\pippo}{\pluto}supponendo che\pippo e\plutosiano due registri\toks:
\pippo=\expandafter{\the\expandafter\toks@\the\@temptokena} e, come già visto in un caso analogo, l’\expandafteresterno causa l’espansione di\theche provoca quella dell’\expandafterinterno e tutto torna: viene espanso \the\plutoal suo contenuto, poi viene espanso\the\pippoal suo contenuto e la lista risultante viene assegnata al registro\pippo. I registri temporanei sono stati caricati con copie del contenuto di\pippoe\pluto; in questo modo funziona anche
\concatenate{\pippo}{\toks255}{\pluto}
Vediamo un esempio di uso di queste tecniche. Vogliamo costruire una lista di nomi dei quali non si conosce a priori il numero; ciascuno di questi nomi sarà inserito dall’utente come argomento del comando\Relatoree alla fine la lista dovrà essere composta come tabella tramite il comando\put@adv@list.
\def\put@adv@list{% \begin{tabular}{l}
\textbf{Relator\ifnum\adv@count>1 e\else i\fi}\\[3pt] \the\adv@toks \end{tabular}} \newcount\adv@count \newtoks\adv@toks \newcommand{\Relatore}[1]{% \adv@toks=\expandafter{\the\adv@toks#1\\}% \advance\adv@count\@ne}
Questi comandi andranno nel file.styche definisce il frontespizio nel quale compa-rirà la lista dei relatori. Non c’è bisogno di azzerare il registro\tokse il contatore, perché questa costruzione si userà una volta sola; all’utente finale resta solo da elencare i suoi relatori nell’ordine in cui desidera che compaiano:
\Relatore{Albert Einstein} \Relatore{Niels Bohr} \Relatore{Enrico Fermi}
Il pacchetto poi emetterà il comando\put@adv@listal momento giusto, quando i comandi saranno già stati letti. Si sarebbe potuta usare la macro\toksappend, ma la tecnica è così semplice che non vale la pena di definire una macro apposita.
La macro non è perfetta, perché rimane un\\alla fine, ma non è poi così grave. Lo si potrebbe correggere, se proprio lo si ritenesse necessario con\test@forend definito come
\def\test@forend{\@ifnextchar\end{}{\\}}
Usiamo qui un’altra volta il fatto che\@ifnextcharguarda qual è il token che segue, che può anche non essere un carattere. Se il relatore in questione non è l’ultimo, il token successivo sarà parte del suo nome; altrimenti il token successivo sarà\end
che, ricordiamo, non viene tolto dalla lista di token in conseguenza dell’espansione di\@ifnextchar.
In altri casi occorre dare una struttura più complessa ai token che inseriamo progressivamente nel registro. Supponiamo che l’autore annoti nel suo documento certi appunti e che voglia poi stamparli alla fine; possiamo pensare ad annotazioni di modifiche, con la data, il numero di versione, lo stato, un commento e il responsabile. È ragionevole un modo di annotare del tipo
\addlogentry{30/06/2006}{0.1}{pre}{C1}{Giovanni Episcopo} Ora vogliamo definire\addlogentryin modo che con\printlogtablesi stampi l’intera lista limitandola a data e autore, oppure
\printlogtablex{author}{comment}{version}{}{}
\printlogtablex{date}{author}{comment}{status}{version}
dove come argomenti inseriamo i nomi dei campi che vogliamo stampare, scelti fra i cinque possibili, in ordine qualsiasi, lasciando eventualmente campi vuoti alla fine. Prevediamo anche un argomento opzionale, il preambolo di tabella, dando come usualelllll, ma con la possibilità di scrivere
\printlogtablex[clr]{author}{version}{date}{}{}
Per risolvere il problema possiamo decidere di inserire i cinque campi come argomen-ti ad altrettante macro, delimitando ciascun gruppo di daargomen-ti con i token\rt@entry e\rt@endentry. Potremo quindi eseguire la lista di token che abbiamo ottenuto dando significati diversi ai due delimitatori e alle cinque macro.
\newtoks\rt@toks \newcommand{\addlogentry}[5]{% \rt@toks=\expandafter{\the\rt@toks \rt@entry\rt@date{#1}\rt@ver{#2}\rt@status{#3} \rt@comment{#4}\rt@author{#5}\rt@endentry} }
La scelta del prefissortè del tutto arbitraria, ovviamente. Allochiamo un registro e poi definiamo come previsto la macro\addlogentry.
\def\printlogtable{% \begingroup \let\rt@entry\relax \def\rt@date##1{##1&}% \let\rt@ver\@gobble \let\rt@status\@gobble \let\rt@comment\@gobble \def\rt@author##1{##1}% \def\rt@endentry{\\} \begin{tabular}{ll} \toprule
\multicolumn{2}{c}{Elenco delle modifiche}\\ \the\rt@toks
\bottomrule \end{tabular}% \endgroup}
In un gruppo diamo significati opportuni alle macro: rendiamo quelle che conten-gono dati inutili equivalenti a\@gobble. Il campo data verrà prodotto insieme al delimitatore di colonna&, il delimitatore di destra diventa il fine riga (si notino i comandi dibooktabsper migliorare la tabella).
Ora veniamo alla parte meno facile. Definiremo\printlogtablexcon il compi-to di valutare l’argomencompi-to opzionale e di chiamare poi la macro responsabile per il resto. \newcommand\printlogtablex[1][lllll]{% \def\rt@logtablepreamble{#1}\rt@printlogtablex} \def\rt@printlogtablex#1#2#3#4#5{% \begingroup \let\rt@entry\relax \def\rt@date##1{\gdef\rt@idate{##1}}% \def\rt@ver##1{\gdef\rt@iver{##1}}% \def\rt@status##1{\gdef\rt@istatus{##1}}% \def\rt@comment##1{\gdef\rt@icomment{##1}}% \def\rt@author##1{\gdef\rt@iauthor{##1}}% \let\rt@i\@gobble \def\rt@endentry{% \csname rt@i#1\endcsname& \csname rt@i#2\endcsname& \csname rt@i#3\endcsname& \csname rt@i#4\endcsname& \csname rt@i#5\endcsname& \\} \begin{tabular}{\rt@logtablepreamble @{}l} \the\rt@toks \end{tabular}% \endgroup}
Usiamo qui un approccio molto indiretto: i nostri dati sono stati inseriti senza sapere a priori in quale ordine vogliamo stamparli. Perciò definiamo\rt@datein modo che definisca un’altra macro e analogamente per le altre. Poi definiamo\rt@endentry in modo che usi le macro appena definite. Se il primo argomento è, per esempio, date, nella prima colonna della tabella andrà l’espansione attuale di\rt@idate; se un argomento è vuoto, l’espansione di\rt@iè\@gobbleche si mangerà&. Dan-do l’argomento opzionalercl, il preambolo della tabella saràrcl@{}l, altrimenti lllll@{}l; lo scopo dell’ultima colonna è di essere vuota, ma di mettere a posto lo spazio finale.
Si provino le macro con il seguente codice:
\addlogentry{30/06/2006}{0.1}{pre}{C1}{A. U. Tore} \addlogentry{30/01/2006}{0.2}{pre}{C2}{S. C. Rittore} \addlogentry{30/03/2006}{0.3}{pre}{C3}{B. Irra} \addlogentry{30/04/2006}{0.3beta}{beta}{C4}{V. Ino} \printlogtable \printlogtablex{author}{date}{ver}{comment}{status} \printlogtablex[crl]{author}{ver}{date}{}{}
Nel capitolo sugli argomenti speciali tratteremo la questione dei doppi#, che abbiamo già incontrato. A parte questo, dovrebbe essere evidente che dando struttura alle liste di token che accumuliamo, possiamo ottenere vari effetti con gli stessi dati.