Comme on l’a déjà abondamment évoqué, un document html est structuré selon des éléments de niveau bloc imbriqués. Cette structure est naturellement reprise par le module Html.
Un bloc du gestionnaire de sortie est caractérisé d’abord par un canal
de sortie.
Le canal de sortie du premier bloc ouvert est un fichier, tandis que
la sortie de tous les autres blocs ouverts ultérieurement
sont des tampons mémoire.
Les deux types de canaux présentent une interface uniforme et sont
définis dans un autre module, le module Out.
En plus du canal de sortie, un bloc comprend une étiquette (qui est
le nom de l’élément html représenté par le bloc,
un argument de bloc (certaines balise d’ouverture ont des
arguments comme “<DIV ALIGN=right>
” par exemple),
ainsi que deux
listes de changements de style : les changements
de style effectués et les changements de style en attente.
Par définition, les changements de style actifs sont la concaténation
des changements de style effectués et des changements de style en
attente.
Les changements de styles sont rendus par
des éléments de niveau texte. Du point de vue d’HEVEA, ces éléments
sont de trois sortes, purs changements de style (par exemple,
“<I>
”), changement de taille (par exemple
“<FONT SIZE=4>
”) et changement
de couleur (par exemple “<FONT COLOR=blue>
”).
Ces styles sont rendus par le type style
du
module Macros :
type style = Style of string | Size of int | Color of string
Voici ensuite une interface simplifiée pour le module Html, qui va permettre une première description du gestionnaire de sortie.
val open_block : string -> string -> unit val close_block : string -> unit val open_mod : Macros.style -> unit val put : string -> unit
Le gestionnaire de sortie maintient une pile de blocs ouverts
et l’appel de open_block
déclenche l’empilage du bloc courant.
Un nouveau bloc est ensuite ouvert,
son canal de sortie est un nouveau tampon, sa liste de
changements de style effectués est vide et sa liste de changements
de style en attente est constituée des changements de style
actifs du bloc précédent.
L’appel à put
effectue la copie de son argument dans le canal
de sortie courant. En outre, cette fonction
effectue les changements
de style en attente.
C’est à dire qu’elle émet les balises d’ouverture appropriées et
transfère les styles correspondants dans la liste des changements
de styles effectués.
La reconnaissance d’une déclaration LATEX de changement de style
(par exemple “\itshape
”) entraîne
un ou plusieurs appels à open_mod
qui prennent chacun un style
en argument (par exemple “Style "I"
”).
La fonction open_mod
se contente de placer le style donné en
argument en tête des changements en attente.
Enfin, la dernière fonction close_block
ferme le bloc courant.
Dans un premier temps, l’argument de close_block
est comparé à l’étiquette courante, en cas de différence
une erreur fatale est signalée.
Puis, elle émet les balises de fermeture
correspondant aux changements de styles effectués, qui sont donc
écrits en fin du canal à fermer.
Ensuite, le bloc en sommet de pile est dépilé, son canal de sortie devient
donc le canal courant et les listes de changement de style retrouvent
leurs anciennes valeurs.
Puis, le gestionnaire de sortie émet la liste des balises de
fermeture des changements de style effectués (qui ont été
potentiellement refermées à l’ouverture du sous-bloc qui vient d’être
fermé), transfère ces changement de style de la liste des changements
effectués vers la liste des changements en attente,
émet la balise d’ouverture du bloc fermé augmentée de son éventuel argument,
copie le contenu du bloc fermé et émet
sa balise de fermeture.
Le retardement de l’émission des balises permet d’annuler un bloc
facilement, dans ce cas on se contente de dépiler le bloc en sommet de
pile après vérification de l’étiquette donnée en argument à
close_block
et rien n’est émis.
Cette procédure s’applique en particulier lorsque le tampon mémoire du
bloc refermé est vide, une situation provoquée entre autres par les
groupes LATEX vides “{}
”, qui souvent utilisés pour indiquer
une séparation de lexème comme dans “groupes \LaTeX{} vides
”.
L’architecture du gestionnaire de sortie impose le bon parenthésage
des balises et un respect de la bonne imbrication des
deux types d’éléments html, à condition bien entendu
d’ouvrir et de fermer tous les éléments de niveau bloc par
open_block
et close_block
, et d’amorcer tous les
changements de style par open_mod
.
C’est évident pour les éléments de niveau bloc, par l’existence de la
pile des blocs ouverts et le contrôle à la fermeture des blocs.
Le cas des changements de style est à peine plus compliqué,
toutes les balises ouvertes lors de la réalisation effective des
changements de style
sont fermées avant d’émettre la balise de fermeture du bloc courant.
Enfin, la fermeture des changements de style effectués
avant toute ouverture de bloc garantit que l’on ouvrira jamais
d’élément de niveau bloc à l’intérieur d’un élément de niveau texte.
Considérons à nouveau l’exemple suivant :
\begin{quote} normal, {\itshape en italique} normal \end{quote}
à traduire en :
<BLOCKQUOTE> normal, <I>en italique</I> normal </BLOCKQUOTE>
Le mécanisme des blocs réalisé par le module Html de la
section précédente produit effectivement cette traduction,
si, anticipant sur la reconnaissance de LATEX, on admet
que l’environnement quote
se traduit par un
élément de niveau bloc BLOCKQUOTE
(ouvert par “Html.open_block "BLOCKQUOTE" ""
” et refermé par
“Html.close_block "BLOCKQUOTE"
”), le groupe
{
… }
par un bloc sans argument et de nom vide ""
,
“\itshape
” par un appel
“Html.open_mod (Style "I")
” et que tout autre caractère c donne
lieu à un appel “Html.put
c”.
LATEX et html n’offrent pas exactement les même possibilités
de changer les attributs des polices de caractères.
En effet, d’une part, ces attributs sont
plus nombreux
en LATEX ; d’autre part les documents html peuvent
facilement inclure des changements de couleur.
Une traduction possible des nombreux attributs de style LATEX vers
html est donc une combinaison de changements d’attributs
et de couleurs.
La table 1 décrit quelques-uns des choix par défaut d’HEVEA pour
rendre les différentes variations de forme des police
(déclarations “\
…shape
”).
Ainsi, la reconnaissance de “\slshape
”, par exemple,
entraîne deux appels à “open_mod
”, avec les arguments successifs
“Style "I"
” et “Color "maroon"
”.
italique \itshape
ou\it
<I>
penchée \slshape
ou\sl
<I>
<FONT COLOR=maroon>
petites capitales \scshape
ou\sc
<FONT COLOR=blue>
normal \upshape
annule les autres déclarations
Le cas de la déclaration \upshape
est le plus délicat.
Par exemple, le source
{\itshape en italique {\upshape normal} en italique aussi.}
est formaté comme suit :
Le point de vue de LATEX est que
les formes italiques et
droites sont simplement deux valeurs distinctes des formes de polices.
Mais html ne possède pas d’élément équivalent à
la déclaration “\upshape
”, pour lui une lettre de forme
droite est simplement une lettre de forme normale.
On ne pourra donc traduire la déclaration
“\upshape
” dans un contexte où
“\itshape
” est actif qu’en refermant l’élément “I
” actif.
Dans le cas de l’exemple, on souhaite donc la traduction suivante :
<I>en italique </I>normal<I> en italique aussi.</I>
Plus généralement, le sens de “\upshape
” ne peut être que
de fermer toutes les
balises de style actives qui traduisent les autres changements de forme,
c’est à dire ici “<I>
”, “<FONT COLOR=maroon>
” et
“<FONT COLOR=blue>
”.
Le module Html fournit donc une fonction supplémentaire
val erase_mods : Macro.style list -> unit
Cette nouvelle fonction annule la liste des styles passée en argument de la façon suivante : les changements de style à annuler et encore non-effectués sont simplement retirés de la liste des changements de style en attente, tandis que les changements de style effectués qui précèdent le dernier changement à annuler sont effectivement refermés. Les changements refermés et qui ne doivent pas être annulés sont ensuite rouverts en attente.
Ainsi, le source:
\slshape {\bfseries penché et gras \upshape droit et gras} penché et fin
qui se formate ainsi:
donnera:
<I><FONT COLOR=maroon><B>penché et gras </B></FONT></I><B>droit et gras</B> <I><FONT COLOR=maroon>penché et fin</FONT></I>
(Les sauts de ligne produits ont été changés).
Remarquons que toutes les balises actives avant le texte
“droit et gras
”
sont fermées puis que la balise “<B>
” est rouverte.
L’utilisation de tampons mémoire et le retardement des changements de style permet de limiter l’émission des balises de style inutiles. Par exemple, étant donné le source suivant :
\itshape{\bfseries italiques grasses} italiques
On obtient en sortie:
<I><B>italiques grasses</B></I><I> italiques</I>
Cette sortie appelle deux remarques:
I
” n’est pas encore ouvert au moment de
la traduction du groupe
“{\bfseries...
” car le changement de style
“Style "I"
” est encore en attente.On comparera avec:
\itshape italiques {\bfseries italiques grasses} italiques
qui se traduit en
<I>italiques </I><I><B>italiques grasses</B></I><I> italiques</I>
</I><I>
” à la traduction de “}
”.
Plus généralement, on pourrait éviter
de fermer puis de rouvrir
les styles déjà effectués au moment de l’ouverture d’un sous-bloc à
l’intérieur des quels ces styles ne sont pas refermés.
J’ai préféré éviter de compliquer encore le gestionnaire de sortie.