ES-TEX Archivos

Usuarios hispanohablantes de TeX

ES-TEX@LISTSERV.REDIRIS.ES

Opciones: Vista Forum

Use Monospaced Font
Por defecto enseñar Text Part
Mostrar todas las cabeceras de correo

Mensaje: [<< Primero] [< Prev] [Siguiente >] [Último >>]
Tema: [<< Primero] [< Prev] [Siguiente >] [Último >>]
Autor: [<< Primero] [< Prev] [Siguiente >] [Último >>]

Print Responder
Subject:
Emisor:
Reply To:
Usuarios hispanohablantes de TeX <[log in para visualizar]>
Fecha:
Mon, 24 May 2004 12:00:26 +0200
Content-Type:
text/plain
Parts/Attachments:
text/plain (250 lines)
Gustavo dijo:

> A mi me interesa. Todo lo que sea TeXnico me interesa ;-) Aunque no sé mucho
> pero me gusta demasiado la parte de programación de LaTeX. Así que me
> gustaría que me explicaras cómo funciona. Alguna idea tengo pero hay
> comandos como el \futurelet que no sé el efecto que producen.

Pues vamos allá.

Este era el código:

\makeatletter
\newenvironment{poema}{
\def\mipar{\futurelet\next\mi@par}
\def\mi@par{\ifx\next\mipar\let\nxt\mi@@par \else\let\nxt\\ \fi\nxt}%
\def\mi@@par{\oldpar\@gobblecr}
\let\par=\mipar\obeylines%
\begin{verse}\let\oldpar=\par\@gobblecr}
{\end{verse}}
\makeatother

Comenzaré por decir algo que ya muchos sabemos, y es que los nombres
de macros en TeX comienzan por el caracter \ y están formados solo por
"letras". Ahora bien, lo que TeX considera una letra es variable!
Mediante el comando \catcode podemos cambiar la categoría de cada
simbolo ASCII (o no ASCII) y decirle a TeX que lo considere letra o
no. Por defecto, se consideran "letras" solo los signos ASCII de la a
a la z y de la A a la Z. Eso excluye la eñe, por ejemplo, por lo que
no podemos hacer una macro que se llame \tamaño. Pero como he dicho
eso se puede cambiar fácilmente haciendo 

 \catcode`ñ=11 

Si hacemos esto, la eñe será una "letra" más, en el sentido de que
puede formar parte del nombre de las macros. Esto no tiene efectos
secundarios con respecto a usar la eñe en otros lugares.

Bueno, todo esto viene al hilo de que el carácter @ no es una "letra"
por defecto para TeX, y por tanto tampoco podría formar parte del
nombre de una macro. Sin embargo los estilos de latex, lo primero que
hacen es cambiar la categoría de @ para que sea letra y así poder
usarla en nombres de macros "para uso interno" como \@z, \@gobble,
\l@section, y miles de ellos más. Antes de "volver" al documento de
usuario, latex vuelve a redefinir @ como "no-letra", de modo que de
nuevo ya no se puede usar como parte de un nombre. Esto evita que
desde su documento el autor pueda definir sin darse cuenta otro
comando que ya había sido definido por latex, o incluso que pueda
llamar a los comandos "internos" de latex. El usuario debería
limitarse a llamar a las macros "exportadas" que son las que no tienen
@ en sus nombres.

Sin embargo tarde o temprano llega el momento de querer cambiar el
comportamiento por defecto de latex, lo que exigirá redefinir alguno
de sus comandos internos, esos que tienen @ en el nombre. Para poder
escribir la nueva definición, necesitamos que @ sea de nuevo una
"letra" normal. El comando \makeatletter hace esto (y en realidad no
es más que \catcode`@=11). Normalmente, una vez realizadas las
definiciones que involucran @, se vuelve a cambiar la categoría de @
para que sea de nuevo "no-letra" mediante \makeatother (que no es más
que \catcode`@=12). Por cierto, que si escribimos nuestras
redefiniciones en un .sty, y lo cargamos con \usepackage{}, no es
necesario nada de esto, ya que \usepackage hace un \makeatletter antes
de cargar el paquete un un \makeatother despues.

Vamos ya con la definción del entorno poema. Primero la filosofía. Lo
que pretendo es tener un entorno "verse", pero en el que cada fin de
línea actúe como un \\, y cada linea en blanco (esto es, dos "fin de
linea" seguidos) actúe como un \par. 

Para lograrlo habría que cambiar la categoría del carácter ^^M (que es
como TeX llama al fin de línea) y convertirlo en un carácter
"activo". Un carácter activo es un carácter que es en sí mismo el
nombre de una macro, sin necesidad de ponerle un \ delante. Así, por
ejemplo, el caracter ~ es activo, y es por tanto el nombre de una
macro. Esta macro, por defecto, se define igual a \nobreakspace, para
generar un espacio irrompible, pero paquetes como babel pueden
redefinirla para que actúe de forma diferente si aparece delante de
una ene, por ejemplo. Babel hace uso y abuso de los caracteres
"activos" (así, por ejemplo, el apóstrofe también puede hacerse activo
para que actúe como un acento, sin necesidad de tener que poner \'a,
si no solo 'a, aunque esto ya apenas se usa desde que inputenc permite
introducir directamente á).

A ver, que me pierdo en disgresiones. Decía que la idea era hacer ^^M
activo, para que sea en sí mismo un comando. Desde este comando podría
examinar si lo que viene despues es otro ^^M (y en ese caso generar un
\par) o si es otra cosa (y en ese caso generar un \\). 

Por suerte tenemos una macro que me evita tener que andar cambiando el
catcode de ^^M, y esta macro es \obeylines. Precisamente lo que hace
esta macro es cambiar el catcode de ^^M para que sea un carácter
activo, y después define el significado de ^^M como equivalente a
\par. Por tanto todo lo que yo tengo que hacer es redefinir
momentaneamente \par para que haga lo que yo quería, en lugar de lo
que haría por defecto.

Esto va perfilando la estrategia:

 1) Programo una macro, digamos \mipar, que según lo que venga detrás
    actúe diferente. Si viene un ^^M, genera un \par "normal" , y
    si no, genera un \\
 
 2) Redefino temporalmente \par para que sea \mipar, y activo
    \obeylines. Esto implica que a partir de ese momento, cada fin de
    línea que se encuentre se convertirá en una llamada a mi macro
    \mipar. Debo ser cuidadoso con los fines de línea a partir de este
    momento, ya que no quiero encontrarme ninguno hasta que no se haya
    leído el primer verso.

 3) Entro en el entorno verse, con cuidado de "tragarme" el fin de
    linea que hay tras el \begin{verse}

Cuidado, aqui hay un bucle infinito acechando. Si yo defino \par para
que se convierta en \mipar, pero despues, desde dentro de \mipar
necesito generar un \par cuando hay un ^^M despues, esto causaría que
este \par se expandiera como \mipar, y así sucesivamente. Por eso debo
guardar el valor "original" de \par en otra macro, \oldpar, y usar
ésta en lugar de \par desde dentro de \mipar.

Vamos a ver cómo definir \mipar. El problema más gordo aqui es que
tengo que actuar de forma diferente según lo que venga detrás. Si
viene otro ^^M (que a estas alturas ya habrá sido traducido por TeX en
un \mipar), debo generar un \oldpar. Pero si no, debo generar un
\\. Por tanto necesito una forma de mirar "qué viene despues", antes
de que TeX lo haya expandido. Esto es lo que hace \futurelet. Esta
macro recibe tres argumentos <t1>, <t2> y <t3> lo que hace viene a ser
algo como:

  \let <t1>=<t3> 
  <t2>
  <t3>

En nuesto caso, he puesto 

\def\mipar{\futurelet\next\mi@par}

Pongamos que las dos primeras líneas del poema son:

  Con cien cañones por banda,
  viento en popa, a toda vela,

Cuando lleguemos al final de la línea 1, hay un ^^M allí, y TeX lo
expandirá como \mipar. Es decir, tenemos algo así:

  Con cien cañones por banda,\mipar viento en popa, a toda vela,

Este \mipar a su vez se expande siguiendo mi definición, por lo que
tenemos:

  Con cien cañones por banda,\futurelet\next\mi@par viento en popa...

Así que los tres argumentos que recibe \futurelet son 
 <t1>=\next
 <t2>=\mi@par
 <t3>=la letra "v" (de viento)

Por lo que viene a hacer algo como:

 \let\next=v
 \mi@par
 v

O sea, he conseguido meter en \next la siguiente letra, y después
llamo a \mi@par, desde donde tendré oportunidad de examinar lo que hay
en \next y decidir si emitir un \oldpar o un \\, Veamos \mi@par:

\def\mi@par{\ifx\next\mipar\let\nxt\mi@@par \else\let\nxt\\ \fi\nxt}%

\ifx permite comparar una macro con otra. Comparo \next con
\mipar. Esto sólo será cierto si la siguiente línea comenzaba por ^^M,
es decir, era una línea en blanco separando estrofas. En este caso
asigno a la macro \nxt el valor de otra macro \mi@@par que será la
encargada de hacer una separación de párrafos. En caso contrario (por
ejemplo en el caso que nos ocupa en que \next vale "v"), asigno a la
macro \nxt el valor de la macro \\. Una vez salgo del "if", ejecuto la
macro \nxt. En el caso que nos ocupa, \nxt tiene el valor de \\, por
lo que todo lo anterior finalmente queda expandido como:

  Con cien cañones por banda,\\ viento en popa, a toda vela,

Supongamos ahora que estamos al final de una estrofa:

  un velero bergantín.

  Bajel pirata que llaman

De momento esto es equivalente a:

  un velero bergantín.\mipar ^^M Bajel pirata que llaman

El primer \mipar se expande, y da lugar a:

  un velero bergantin.\futurelet\next\mi@par \mipar Bajel pirata...

y el futurelet hace algo como:

  \let\next=^^M
  \mi@par
  ^^M

Basicamente lo mismo que antes, asigno a \next el valor del siguiente
token, que es ahora ^^M (o lo que es lo mismo, \mipar), y despues
llamo a \mi@par que tiene una oportunidad de examinar \next y decidir
qué hacer. La diferencia es que antes, después de todo eso se emitía
la letra "v", lo cual era correcto, pero ahora se emitiría ^^M, lo
cual es incorrecto ya que en este caso ese ^^M solo era un separador
de párrafos, y no un real "fin de linea", es decir, queremos
ignorarlo.

En este caso \mi@par se expandirá como \mi@@par, y este a su vez está
definido así:

\def\mi@@par{\oldpar\@gobblecr}

La finalidad de \@gobblecr es tragarse el siguiente fin de línea sin
expandirlo.

Con esto ya está todo listo para el truco:

\let\par=\mipar\obeylines%
\begin{verse}\let\oldpar=\par\@gobblecr}

Asigno a \par el valor de \mipar. A partir de ese momento, cada vez
que haya un \par, se ejecutará en su lugar \mipar. Con \obeylines hago
que cada ^^M se convierta en \par, y por tanto que con cada ^^M se
ejecute \mipar. Debo poner un % al final de esta linea para que TeX no
vea el ^^M que hay al final de ella (si lo viera lo expandiría como
\mipar, pero aun es demasiado pronto, el poema no ha empezado!).

Finalmente empiezo el verso. Salvo el valor que en ese momento tenga
\par en \oldpar, para usarlo desde \mi@@par cuando
corresponda. Finalmente hago otro \@gobblecr para tragarme el ^^M que
aparecerá al final de la primera línea del entorno, justo después del
\begin{poema}.

Esto es todo :-)

¿Habrá otra forma más simple? Probablemente, pero me considero un
novato en la programación TeX, y no he conseguido encontrar una forma
mejor. 

Saludos,
--JL Diaz

----------------------------------------------------
Si tiene algun problema con la utilizacion de la lista.
Pongase en contacto con nosotros a traves de:
[log in para visualizar]
----------------------------------------------------

ATOM RSS1 RSS2