Une première réponse est brutale, après tout nous écrivons plutôt en LATEX. Néanmoins la question mérite d’être un peu approfondie, car elle permet de mieux définir les objectifs d’un traducteur.
Rappelons que LATEX est en fait un ensemble de macros TEX. LATEX est généralement préféré car il se charge de maints détails de mise en page et de composition, ce qui doit permettre à l’auteur de se concentrer sur l’écriture de son texte et non pas sur sa composition.
De fait, le source TEX apparaît comme celui d’un langage très influencé par son implantation. Autrement dit, il faut comprendre comment fonctionne TEX pour pouvoir s’en servir. Une telle démarche est raisonnable pour l’auteur qui compose finement son texte, elle est dissuasive pour l’auteur qui veut simplement écrire. LATEX propose un langage source qui met plus en avant les concepts que leur réalisation. Typiquement, pour comprendre, par exemple, un changement de style des polices de caractères, on doit en TEX se référer à un ≪ état courant ≫ du moteur interne, tandis que LATEX propose des concepts de plus haut niveaux, comme une commande qui compose son argument avec un attribut de police déterminé. De même un des concepts centraux de TEX est la boite, qui de plus peut être horizontale (un mot) ou verticale (un paragraphe), ce concept provient du monde de l’imprimerie et intéresse finalement peu l’auteur du document.
Une conséquence intéressante est qu’un document écrit en LATEX ressemble beaucoup plus à un programme écrit dans un langage moderne (donc réputé de haut-niveau), qu’un document écrit en TEX qui lui ressemble à de l’assembleur. On peut même penser qu’il est impossible d’écrire un traducteur complet de TEX vers html, car html n’offre pas énormément de contrôle sur l’aspect final du document, qui d’ailleurs dépend fortement du dispositif utilisé pour le visualiser (cependant, un traducteur commercial TEXpider [9] suit cette démarche, mais il y a fort à parier que ce programme est bien plus complexe qu’HEVEA).
En résumé, traduire LATEX vers html est possible et raisonnable, parce que ces deux langages sont tous deux des langages qui spécifient une certaine structure du document, plus qu’ils ne décrivent complètement quel sera l’aspect du produit final. En outre, le langage LATEX est relativement uniforme, toutes les constructions ayant sensiblement la même syntaxe, ce qui facilite grandement sa compréhension par un programme.
Classiquement, un traducteur d’un langage vers un autre possède une phase initiale d’analyse syntaxique qui, à partir du source construit un arbre de syntaxe abstraite. Cet arbre est en fait le support de la sémantique du langage, qui très souvent procède par assemblage récursif de sous-eléments. La traduction finale se fait ensuite par un parcours de cet arbre ou d’un arbre transformé. Les compilateurs rapides et peu optimisants font l’économie de la construction de l’arbre de syntaxe et génèrent directement leur produit dans la phase d’analyse syntaxique. Dans notre cas, c’est cette démarche qui est adoptée, tant pour des raisons d’efficacité que parce que, comme on va le voir, les langages LATEX et html ont des structures syntaxiques proches. En outre il n’est pas immédiat de définir complètement LATEX sous forme d’une grammaire BNF, un préalable indispensable si l’on veut effectivement construire un arbre de syntaxe abstraite d’un document LATEX. Ici, on se contente d’admettre que les documents ont des structures comparables dans les deux langages, sans expliciter exactement ce qu’est cette structure.
Donc, il est frappant de constater que les documents LATEX et
html ont nombre de structures communes. Les environnements LATEX
(ouverts par “\begin{
env}
” et refermés par
“\end{
env}
” correspondent aux éléments de niveau
bloc html (≪ block-level elements ≫, ouverts par la balise
“<
bloc>
” et
refermés par la balise “</
bloc>
”).
Les documents complets sont structurés selon le même modèle de sections et
sous-sections (les ≪ sectional units ≫ de LATEX, introduites par les
commandes “\section{
…}
”,
“\subsection{
…}
”, etc et les ≪ headers
elements ≫ “<H1>
…</H1>
”,
“<H2>
…</H2>
”, etc. de html).
Le principe général de la traduction est donc celui d’une traduction lexicale : reconnaître les entités lexicales et les traduire une à une la structuration du document restant inchangée. Par entité lexicale, j’entends ici un groupe de caractères significatif et de taille réduite. Par exemple:
\begin{quote} \begin{flushright} Ceci est une citation de deux lignes,\\ avec fer \begin{em}à droite\end{em}. \end{flushright} \end{quote}
Se formate comme suit:
Une traduction simple et logique en html est:
<BLOCKQUOTE><DIV ALIGN=right> Ceci est une citation de deux lignes,<BR> avec fer <EM>à droite</EM>. </DIV> </BLOCKQUOTE>
On a donc traduit \begin{quote}
en <BLOCKQUOTE>
,
la construction \begin{flushright}
en <DIV ALIGN=right>
,
\\
en
<BR>
, etc.
L’imbrication des environnement et des éléments est la même dans les deux
langages.
De même la traduction d’une liste est particulièrement directe. En LATEX, on a:
\begin{itemize} \item Premier item. \item Deuxième item. \end{itemize}
En html, il vient:
<UL> <LI>Premier item. <LI>Deuxième item. </UL>
Évidemment, les structures des documents LATEX et html ne sont pas identiques en tout point. Par exemple, l’effet des déclarations de changement de style LATEX court de leur occurrence à la fin de l’environnement ou du groupe courant, tandis que les éléments de niveau texte html (≪ text-level elements ≫) ont une structure bien parenthésée, leur effet courant entre une balise d’ouverture et une balise de fermeture. Ainsi, le texte ≪ normal, en italique normal ≫ est obtenu à partir du source LATEX suivant :
normal, {\itshape en italique} normal
Une traduction possible en html est :
normal, <I>en italique</I> normal
En outre, la définition de html [8] interdit la présence d’éléments de niveau bloc à l’intérieur des éléments de niveau texte. Nous verrons à la section 3, comment HEVEA garantit le bon parenthésage de toutes les balises d’ouverture et de fermeture, ainsi que le respect de cette contrainte.
Pour traiter cette différence de structure entre les deux langages, ainsi que d’autres comme les commandes définies par l’utilisateur, HEVEA s’écarte de la pure traduction lexicale pour revenir à un modèle plus proche de TeX, où les diverses commandes sont interprétées comme des ordres de modification de l’état courant du traducteur.
La traduction d’HEVEA se divise en deux sous-tâches, d’une part reconnaître du source LATEX que l’on supposera correct, et d’autre part produire du html correct. Le programme HEVEA s’articule donc en deux sous-unités, d’une part un analyseur lexical principal et d’autre part un gestionnaire de sortie. L’interaction entre les deux sous-unités est simple : l’analyseur réalise des appels aux fonctions du gestionnaire de sortie.
L’analyseur se garde bien d’échouer sur une entrée incorrecte, lorsque l’incorrection n’est pas trop grave (par exemple, une commande inconnue). En effet, ces erreurs peuvent résulter d’une insuffisance d’HEVEA et elle ne présagent pas d’une traduction inacceptable. Néanmoins, un avertissement est donné à l’utilisateur, afin de lui permettre de contrôler visuellement le résultat. En revanche le gestionnaire de sortie échoue lorqu’il a pu détecter qu’il est en train d’émettre du html incorrect.
HEVEA lit des documents composés de plusieurs fichiers sources, car
il interprète correctement la construction \input
de LATEX,
mais sa sortie est un fichier html unique.
Le résultat d’HEVEA peut ensuite être segmenté en
plusieurs fichiers par un autre programme HACHA, qui est inclus dans
la distribution d’HEVEA.
HEVEA s’efforce de réaliser toutes les constructions LATEX
décrites dans le ≪ Blue Book ≫ [4], à
l’exception de certains packages.
L’analyseur lexical principal est compilé par ocamllex, le générateur d’analyseurs lexicaux inclus dans la distribution d’Objective Caml [5], il est réalisé par le module Scan. Le gestionnaire de sortie est réalisé directement en Objective Caml par le module Html. HEVEA comprend de nombreux autres modules, Le total du source d’HEVEA et de HACHA s’élevant à un peu moins de 7000 lignes de code. Enfin le développement d’HEVEA, à partir du prototype htmlgen [6] de X. Leroy et la rédaction de la documentation [7] m’ont pris de l’ordre de quatre ou cinq mois à mi-temps.
Les dépendances entre les modules sont données à la figure 1, on notera l’analyseur principal Scan et le gestionnaire de sortie Html et leur dépendance. HEVEA comprend d’autres analyseurs lexicaux, ce sont les modules :
Trois modules réalisent la gestion des entrées et des sorties :
Le module Out présente une abstraction d’un flot de sortie. Ce flot peut être un fichier ou un tampon mémoire. Tous les analyseurs lexicaux produisent et rendent leur résultat par des appels aux fonctions de ce module.
Les autres modules réalisent certaines des fonctionnalités d’HEVEA :