Newsgroup: it.comp.software.tex
Titolo: plainTeX. Un separatore che non separa niente

Scusate una domanda probabilmente stupida:
Perché il separatore pt del secondo argomento non lo separa e la macro
invece cerca di continuare a leggere il #2?
Sicuramente sto usando male l'\expandafter, ma non riesco a capire dove
sbaglio.
%=====================================================
\newcount\result
\def\macro#1#2pt{#1=#2\relax#1=2#1\relax}
\expandafter\macro\expandafter\result\the\hsize
The result is \the\result. It should be twice the \hsize.
\bye
%=====================================================
Grazie tante in anticipo.
Tomáš

 scrive:

Vediamo le espansioni, assumo che \hsize=469.75499pt, 
com'è in Plain TeX.
1) \expandafter\macro\expandafter\result\the\hsize
Il primo \expandafter espande il secondo che a sua volta
espande \the
2) \macro\result469.75499pt
Adesso si espande \macro
3) Il primo argomento, non delimitato, è \result. Il secondo
argomento è delimitato, ma TeX non riesce a trovare il
delimitatore e, secondo le regole, si ferma al \par e infatti
ottieni il messaggio di errore
  ! Paragraph ended before \macro was complete.
Perché? Semplice, ma sottile. L'espansione di \the\hsize è una
stringa di caratteri di categoria 12 (TeXbook, pagina 214,
penultima "doppia curva pericolosa"). Nella definizione di
\macro i due token `p' e `t' hanno categoria 11.
Occorre qualcosa di più complicato per avere quello che
chiedi. Nel tuo caso, codice per \macro non contiene altre
`p' e `t', così il seguente trucco funziona:
{
\catcode`p=12 \catcode`t=12
\gdef\macro#1#2pt{#1=#2\relax#1=2#1\relax}
}
Si inserisce la definizione in un gruppo dove si imposta
il corretto codice di categoria. E se i caratteri `p' e `t'
comparissero? Ugualmente "abbastanza" facile.
\begingroup
\uccode`?=p \uccode`!=t
\uppercase{\endgroup\def\macro#1#2?!}{#1=#2\relax#1=2#1\relax}
Il comando \uppercase percorre la token list che ha come
argomento e cambia tutti i token semplici (i caratteri ma
_non_ i comandi) negli equivalenti maiuscoli impostati nella
tabella degli \uccode. Nel gruppo abbiamo impostato la
conversione di ? in p e quella di ! in t; \uppercase non
cambia il codice di categoria, che è 12 per `?' e `!'. Alla
fine \uppercase rimette i token così formati al posto di
quelli letti e quindi si ha
\endgroup\def\macro#1#2pt{...}
ma adesso `p' e `t' hanno categoria 12. Nota che \endgroup
viene "visto" solo adesso e quindi il suo unico effetto è
di cancellare le assegnazioni fatte con \uccode. :)
Piccolo problema: adesso la tua \macro trova il secondo
argomento correttamente, ma non sa che farsene. Ritorniamo
infatti all'espansione di \macro\result469.75499pt
Ora #1 è ancora \result, mentre #2 è 469.75499, così la
sostituzione porta a
\result=469.75499\relax\result=2\result\relax
Qui ci sono vari errori: \result è un contatore e quindi
accetta solo valori interi; inoltre non è possibile
modificare un contatore con un'assegnazione del tipo
\result=2\result
che funziona solo per registri \dimen o \skip.
Ciò che ottieni è solo che a \result viene prima assegnato
il valore 469; poi .75499 viene stampato; a questo punto
a \result viene assegnato il valore 2 e poi c'è un messaggio
di errore
! Missing number, treated as zero
perché TeX trova \result\relax che è un'assegnazione incompleta.
Che cosa vuoi fare, di preciso?
Ciao
Enrico

Grazie, non avevo notato la categoria prodotta dal \the. Ora è tutto chiaro:
- La moltiplicazione del registro <dimen> la faccio prima.
- Poi mi definisco una \macro usando il trucco con \uppercase.
- Il numero entrato nel suo parametro lo metto in un registro <tokens>
invece di <number>.
E adesso funziona.
%================================================
\newtoks\result
\def\dimtonum#1{#1=2#1\expandafter\macro\the#1}
\begingroup
\uccode`?=`p \uccode`!=`t
\uppercase{\endgroup\def\macro#1?!}{\result={#1}}
\dimtonum\hsize
The result is \the\result.
\bye
%================================================
Per rispondere alla domanda:
Cerco di cambiare certe dimensioni in numeri senza nessun'unità,
moltiplicandole con un fattore perché i numeri risultanti corrispondano
alle dimensioni in bp. I numeri vanno scritti in un file di testo che
TeX legge durante una seconda compilazione e utilizza i numeri per
disegnare uno sfondo (dipendente dalle dimensioni di paragrafi) per
mezzo del \pdfliteral.
Tante grazie ancora!
Tomáš

 Tomáš
==== tobp.tex ====
\catcode`\@=11
\def\@car#1#2\@nil{#1}
\begingroup
  \catcode`P=12 \catcode`T=12
\lowercase{\endgroup
  \def\round@two#1.#2#3PT{#1.#2\@car#3\@nil}}
\def\getbp#1{%
  \expandafter\round@two\the\dimexpr.996264#1+0.005pt\relax}
\newwrite\auxdimen
\immediate\openout\auxdimen=tobp.dat
\def\writeinbp#1{\dimen@=#1\relax
  \immediate\write\auxdimen{\getbp\dimen@}}
\catcode`\@=12
\writeinbp{365pt}
\writeinbp{\hsize}
\writeinbp{2\hsize}
\newdimen\mylen
\mylen=1in
\writeinbp{\mylen}
\bye
==== END ====
Compilando questo con pdftex, si produce il file tobp.dat che
contiene
==== tobp.dat ====
363.64
468.00
936.00
72.00
==== END ====
Il valore magico 0.996264 č il fattore di conversione da pt a bp.
Ciao
Enrico