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 programacin de LaTeX. As que me
> gustara que me explicaras cmo funciona. Alguna idea tengo pero hay
> comandos como el \futurelet que no s el efecto que producen.

Pues vamos all.

Este era el cdigo:

\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 estn formados solo por
"letras". Ahora bien, lo que TeX considera una letra es variable!
Mediante el comando \catcode podemos cambiar la categora 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 ee, por ejemplo, por lo que
no podemos hacer una macro que se llame \tamao. Pero como he dicho
eso se puede cambiar fcilmente haciendo 

 \catcode`=11 

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

Bueno, todo esto viene al hilo de que el carcter @ no es una "letra"
por defecto para TeX, y por tanto tampoco podra formar parte del
nombre de una macro. Sin embargo los estilos de latex, lo primero que
hacen es cambiar la categora 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 ms. 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 haba sido definido por latex, o incluso que pueda
llamar a los comandos "internos" de latex. El usuario debera
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 definicin, necesitamos que @ sea de nuevo una
"letra" normal. El comando \makeatletter hace esto (y en realidad no
es ms que \catcode`@=11). Normalmente, una vez realizadas las
definiciones que involucran @, se vuelve a cambiar la categora de @
para que sea de nuevo "no-letra" mediante \makeatother (que no es ms
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 defincin del entorno poema. Primero la filosofa. Lo
que pretendo es tener un entorno "verse", pero en el que cada fin de
lnea acte como un \\, y cada linea en blanco (esto es, dos "fin de
linea" seguidos) acte como un \par. 

Para lograrlo habra que cambiar la categora del carcter ^^M (que es
como TeX llama al fin de lnea) y convertirlo en un carcter
"activo". Un carcter activo es un carcter 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 acte de forma diferente si aparece delante de
una ene, por ejemplo. Babel hace uso y abuso de los caracteres
"activos" (as, por ejemplo, el apstrofe tambin puede hacerse activo
para que acte 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. Deca que la idea era hacer ^^M
activo, para que sea en s mismo un comando. Desde este comando podra
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 carcter
activo, y despus 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 quera, en lugar de lo
que hara por defecto.

Esto va perfilando la estrategia:

 1) Programo una macro, digamos \mipar, que segn lo que venga detrs
    acte 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
    lnea que se encuentre se convertir en una llamada a mi macro
    \mipar. Debo ser cuidadoso con los fines de lnea a partir de este
    momento, ya que no quiero encontrarme ninguno hasta que no se haya
    ledo 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 causara 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 cmo definir \mipar. El problema ms gordo aqui es que
tengo que actuar de forma diferente segn lo que venga detrs. 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 lneas del poema son:

  Con cien caones por banda,
  viento en popa, a toda vela,

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

  Con cien caones por banda,\mipar viento en popa, a toda vela,

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

  Con cien caones 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 despus
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 slo ser cierto si la siguiente lnea comenzaba por ^^M,
es decir, era una lnea 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 separacin de prrafos. 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 caones por banda,\\ viento en popa, a toda vela,

Supongamos ahora que estamos al final de una estrofa:

  un velero bergantn.

  Bajel pirata que llaman

De momento esto es equivalente a:

  un velero bergantn.\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, despus de todo eso se emita
la letra "v", lo cual era correcto, pero ahora se emitira ^^M, lo
cual es incorrecto ya que en este caso ese ^^M solo era un separador
de prrafos, 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 lnea 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 expandira 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 lnea del entorno, justo despus del
\begin{poema}.

Esto es todo :-)

Habr otra forma ms simple? Probablemente, pero me considero un
novato en la programacin 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