capsite

Ressources et outils pour la génération de ma capsule et de mon site
git clone git://git.asteride.xyz/capsite.git
Journaux | Fichiers | Références

aplat_1_documents_structures_unix.conv (15374B)


      1 titre:aplat(1) : documents structurés pour Unix
      2 date_pub:21a1
      3 date_mod:23ef
      4 auteur:~ldp
      5 type:article
      6 description:Présentation d’aplat(1), un utilitaire qui aide les utilitaires classiques Unix à manipuler des documents hiérarchiques.
      7 uuid:89352ae7-b5d5-4c87-bf51-edd280ae0c62
      8 
      9 Les utilitaires classiques de Unix se prêtent très bien à la manipulation de données structurées par des listes ou par des tableaux, c’est-à-dire à la manipulation de données qu’on encode aisément avec des lignes et des champs. Un bon nombre de ces utilitaires (grep, sed, awk, cut, sort, diff, uniq, etc.) ont en effet été conçus spécialement pour l’analyse et le traitement des données ligne par ligne. Aussi, ils offrent souvent la possibilité de reconnaître des segments de ligne séparés par un délimitateur arbitraire, faisant émerger ce deuxième niveau d’organisation qu’est le champs.
     10 
     11 Il existe cependant d’autres types de strutures de données qu’on ne représente pas instinctivement par ces éléments, et les utilitaires qui s’attendent à trouver des données organisées ligne par ligne ont évidemment bien souvent de la difficulté à traiter correctement les formats de document structurés selon un autre principe. Parmi ces formats, on compte notamment le XML, le TeX, le Markdown, etc., mais aussi le C, le Shell, le Scheme, etc. Parce qu’ils supposent une structure au nombre de niveaux fixe et assez limité (souvent deux : la ligne et le champ), ces utilitaires semblent parfaitement inadaptés au traitement de ces autres formats, d’autant plus que plusieurs d’entre eux ont une structure récursive, admettant donc un nombre illimité de niveaux.
     12 
     13 Bien que, donc, les utilitaires de traitement de texte conçus pour bien fonctionner dans un environnement de type Unix n’ont pas une portée absolument générale, ils restent très utiles pour mener à bien un grand nombre de tâches. Comme beaucoup d’autres, j’attribue cette utilité à leur simplicité, à leur (relative) cohérence, à leur composabilité et à leur omniprésence. Je les trouve en outre agréables à utiliser. Mais je ne venterai pas davantage leurs mérites, car le programme informatique que cet article doit présenter s’adresse avant tout à ceux que ces mérites séduisent déjà, surtout que ce programme est parfaitement inutile lorsqu’utilisé seul et qu’il ne trouve sa valeur que dans la coopérations avec ces autres utilitaires.
     14 
     15 Puisqu’il est de toute façon utile d’apprendre à maîtriser ces utilitaires Unix et que je suis maintenant devenu à l’aise avec eux, je me suis donné pour objectif d’étendre leur portée en créant un format de document structuré selon le principe des lignes et des champs qui permettrait de représenter des données structurées selon n’importe quel autre principe.
     16 
     17 Je présente ici le programme aplat(1) et les deux formats qu’il utilise. Le programme lit en entrée standard un document dans un certain format et exporte en sortie standard sa représentation dans un format pont organisé selon des lignes et des champs.
     18 
     19 J’ai conçu le format de sortie pour qu’il soit facile pour les utilitaires classiques de Unix de le manipuler. Puisqu’il présente la structure des documents sous une forme applatie, j’ai décidé de lui donner le nom de plat.
     20 
     21 J’ai conçu le format d’entrée pour qu’il soit facile pour une personne de le manipuler. C’est un format beaucoup plus simple à comprendre et selon moi beaucoup moins pénible à écrire à la main que le XML. Il s’inspire beaucoup du SXML. Puisqu’il s’oppose en quelque sorte au format plat(5), je lui ai donné le nom de aplat (non-plat). Il s’agit d’un a privatif, qu’un trouve par exemple dans des mots comme apatride ou anonyme.
     22 
     23 Quant au programme, il se serait appelé àplat si la tradition restreignait pas le nom des programmes à l’ensemble des suite de caractères ASCII affichables. Sa tâche est en effet de passer d’aplat(5) à plat(5).
     24 
     25 ## aplat(5)
     26 
     27 Le format aplat(5) permet une organisation hiérarchique de données étiquettées. Il est inspiré du SXML et est aussi puissant que lui. C’est surtout pour des raisons de simplicité que j’ai choisi de créer un nouveau format de document plutôt que d’en utiliser un qui existait déjà. Bien que cette entreprise aurait été tout à fait possible, je ne voulais pas avoir à composer avec la complexité du XML, par exemple. Aussi, la création d’un nouveau format de toutes pièces donne une liberté bien plus grande. De toute façon, l’intérêt d’aplat(1)se trouve selon moi bien plus dans son format de sortie que dans son format d’entrée, et il est possible de créer un programme distinct traduisant le XML, le SXML, le HTML ou n’importe quel autre format vers plat(5).
     28 
     29 Voici un exemple de document valide.
     30 
     31 ```
     32 (doc
     33   (titre Un\ programme\ en\ C)
     34   (auteur ~ldp)
     35   (date-pub 2023 - 11 - 18)
     36   (date-mod (vide))
     37   (par "Voici un exemple de document dans le format aplat.")
     38   (lien
     39     (url "https://asteride.xyz/exemple.txt")
     40     (texte "Un exemple d’URL"))
     41   (pre
     42 """ langue=C
     43 #include <stdio.h>
     44 
     45 int
     46 main(void)
     47 {
     48 	printf("Bonjour tout le monde!\n");
     49 	return 0;
     50 }
     51 """
     52   )
     53   (par "Ce paragraphe affiche " (it "Bonjour tout le monde!")))
     54 ```
     55 
     56 Je veux faire quelques remarques sur le contenu de cet exemple. Sachez cependant que cet article complète plutôt qu’il ne remplace les pages du manuel livrées avec le programme.
     57 
     58 => /man/aplat.1.txt aplat(1)
     59 => /man/aplat.5.txt aplat(5)
     60 => /man/plat.5.txt plat(5)
     61 
     62 La structure hiérarchique d’un document aplat(5) est explicitée par les parenthèses qui encadrent une section de ce document. J’appelle domaine l’espace se trouvant entre deux parenthèses de même niveau.
     63 
     64 Un domaine, s’il n’est pas vide, est composé d’atomes. Un atome est une chaîne de caractères séparés par une parenthèse ou par des blancs (espaces, caractères de tabulation ou nouvelles lignes).
     65 
     66 Le premier atome d’un domaine correspond à l’étiquette. Il nomme un domaine. Tous les autres atomes d’un même domaine sont comme concatenés pour former une longue chaîne de caractères. Je nomme cette chaîne le contenu. « doc », « titre », « auteur », « vide », etc. sont tous des exemples d’étiquettes ; « ~ldp » est un exemple de contenu. Aussi, notons que, puisque les atomes adjacents sont concatenés, le segment « 2023 - 11 - 18 » correspond à l’atome « 2023-11-18 ».
     67 
     68 Il est possible d’inclure des caractères spéciaux dans des atomes en les échappant. Ils seront alors traités comme des caractères normaux.
     69 
     70 Il existe trois manières d’échapper des caractères spéciaux.
     71 
     72 D’abord, on peut utiliser la barre oblique inversée (« \\ »). Son effet varie selon le caractère échappé. Les parenthèses, les espaces normaux, les caractères de tabulation, les guillemets et le caractère d’échappement lui-même sont interprétés dans leur sens littéral lorsque ce caractère les précède. Cependant, une nouvelle ligne échappée est ignorée. Dans l’exemple ci-dessus, la chaîne « Un\ programme\ en\ C » est interprété comme un seul atome et correspond à « Un programme en C ».
     73 
     74 Ensuite, on peut placer les caractères à échapper entre guillemets. Les parenthèses et les blancs placés entre deux guillemets reçoivent leur interprétation littérale. Par exemple, ici la chaîne « "Voici un exemple de document dans le format aplat." » forme un seul atome.
     75 
     76 Finalement, on peut créer un bloc en plaçant les caractères à échapper entre deux triples guillemets droits doubles (« """ »). Tous les caractères reçoivent alors leur interprétation littérale. À l’intérieur d’un bloc, il est possible d’échapper la séquence « """ » en la faisant suivre d’un point d’exclamation (« """! »).
     77 
     78 Tous les caractères entre la séquence d’ouverture d’un bloc et la première nouvelle ligne, inclusivement sont ignorés. C’est pour faciliter le travail de préprocesseurs, qui fonctionneront d’une manière analogue à ceux de troff. Ces préprocesseurs, contrairement aux postprocesseurs, opéreront sur l’entrée de aplat(1) plutôt que sur sa sortie. On pourra alors leur fournir de l’information sur cette première ligne.
     79 
     80 Les blocs sont utiles pour inclure verbatim un bloc de texte, comme un programme informatique ou un document HTML.
     81 
     82 ### Métaformats
     83 
     84 À partir de cette description, il est possible — nécessaire, même — de créer un métaformat adapté à certains besoins. Ainsi, on peut imaginer une manière de représenter les métadonnées comme le fait le XML. Cette idée est empruntée au SXML. Est une métadonnée (paire attribut-valeur) un domaines et son contenu s’ils se trouvent à l’intérieur d’un domaine étiquetté avec « @ ».
     85 
     86 Voici l’exemple précédent converti à cette convention.
     87 
     88 ```
     89 (doc
     90   (@ (titre      "Un programme en C")
     91      (auteur     "~ldp")
     92      (date-pub   "2023-11-18")
     93      (date-mod   (vide))
     94      (métaformat "genre-de-sxml"))
     95   (par "Voici un exemple de document dans le format aplat.")
     96   (lien (@ (ref "https://asteride.xyz/exemple.txt"))
     97 	 "Un exemple d’URL")
     98   (pre
     99 """ lang=C
    100 #include <stdio.h>
    101 
    102 int
    103 main(void)
    104 {
    105 	printf("Bonjour tout le monde!\n");
    106 	return 0;
    107 }
    108 """
    109   )
    110   (par "Ce paragraphe affiche " (it "Bonjour tout le monde!")))
    111 ```
    112 
    113 Ici, les attributs « titre », « auteur », « date-pub », etc. portent sur le domaine nommé « doc » et l’attribut « ref » porte sur celui nommé « lien ».
    114 
    115 ## plat(5)
    116 
    117 Le format plat(5) est une représentation équivalente au aplat(5), au XML, etc.
    118 
    119 Voici la représentation en plat du dernier exemple en aplat.
    120 
    121 ```
    122 :doc:	(	
    123 :doc:@:	(	
    124 :doc:@:titre:	()	Un programme en C
    125 :doc:@:auteur:	()	~ldp
    126 :doc:@:date-pub:	()	2023-11-18
    127 :doc:@:date-mod:	(	
    128 :doc:@:date-mod:vide:	()	
    129 :doc:@:date-mod:	)	
    130 :doc:@:métaformat:	()	genre-de-sxml
    131 :doc:@:	)	
    132 :doc:par:	()	Voici un exemple de document dans le format aplat.
    133 :doc:lien:	(	
    134 :doc:lien:@:	(	
    135 :doc:lien:@:ref:	()	https://asteride.xyz/exemple.txt
    136 :doc:lien:@:	)	
    137 :doc:lien:	)	Un exemple d’URL
    138 :doc:pre:	()	#include <stdio.h>\n\nint\nmain(void)\n{\n\tprintf("Bonjour tout le monde!\\n");\n\treturn 0;\n}
    139 :doc:par:	(	Ce paragraphe affiche 
    140 :doc:par:it:	()	Bonjour tout le monde!
    141 :doc:par:	)	
    142 :doc:	)	
    143 ```
    144 
    145 On voit tout de suite pourquoi ce format n’est pas destiné à être manipulé par des humains. Il est en revanche très adapté à des outils analysant les fichiers ligne par ligne et champ par champ.
    146 
    147 Un document plat(5) est composé d’une série de lignes et de trois champs, séparés par des caractères de tabulation.
    148 
    149 Le premier champ correspond au nom du domaine. Il prend la forme de la liste des toutes les étiquettes des domaines parents, précédées d’un deux-points (« : »). La dernière étiquette est aussi suivie d’un deux-points. Il n’est pas possible d’échapper ce caractère, car plusieurs outils auraient du mal à composer avec une telle syntaxe.
    150 
    151 J’appelle domaine cadet le domaine le plus imbriqué. Ainsi, à la ligne commençant par « :doc:@:date-mod:vide: », le domaine cadet est « :vide: », alors qu’à la première ligne le domaine cadet est « :doc: ».
    152 
    153 Tout nom de domaine doit apparaître au moins une fois en position de domaine cadet, et ce même s’il est vide. Par exemple, bien que « :@: », dans le domaine « :doc:@: », ne renferme que d’autres domaines, il a droit à sa ligne, de même que « :vide: ».
    154 
    155 Le second champ est une liste de drapeaux. Pour l’instant — et je ne pense pas en ajouter de si tôt —, il en existe deux: la parenthèse ouvrante (« ( ») et la parenthèse fermante (« ) »), dénotant respectivement la limite initiale et la limite finale d’un domaine.
    156 
    157 Le troisième champ correspond au « contenu » du format aplat(5).
    158 
    159 plat(5) est organisé selon le principe des lignes et des champs ; les lignes sont séparées par le caractère de saut de ligne et les champs par un caractère de tabulation. Pour utiliser ces caractères au sens propre, il suffit de les échapper. On peut voir le mécanisme d’échappement à l’œuvre à la ligne commençant par « :doc:pre: » dans l’exemple ci-dessus.
    160 
    161 ## Utilisation d’aplat(1)
    162 
    163 Le programme aplat(1) ne lit aucun argument en ligne de commandes : ni options ni nom de fichier ; il se contente de lire en entrée standard et d’écrire en sortie standard.
    164 
    165 Il s’ulitise donc de la manière suivante.
    166 
    167 ```
    168 $ aplat <entree.aplat >sortie.plat
    169 ```
    170 
    171 En supposant que le document aplat(5) de l’exemple précédent se trouve dans le fichier bonjour.aplat, on pourrait écrire la séquence de commandes suivantes pour en extraire le programme, le compiler et l’exécuter.
    172 
    173 ```
    174 $ aplat <bonjour.aplat | grep '^:doc:pre:	' | cut -f3 |
    175 	{ tr -d '\n'; echo; } | xargs -0 printf '%b' |
    176 	cc -o bonjour -x c - && ./bonjour
    177 Bonjour tout le monde!
    178 ```
    179 
    180 Ici, aplat fait passer du format aplat(5) au format plat(5) le contenu du fichier bonjour.aplat ; grep ne retient de la sortie de la commande précédente que les lignes dont l’étiquette est :doc:pre: ; cut isole le troisième champ ; tr fusionne toutes les lignes en supprimant tous les caractère de saut de ligne ; echo réinsère la dernière nouvelle ligne, que tr avait supprimé en trop ; xargs -0 printf '%b' a pour effet de déséchapper les caractères de nouvelle ligne et de tabulation, cc compile le texte résultant et, finalement, ./bonjour exécute le programme.
    181 
    182 ## Conclusion
    183 
    184 J’ai créé cet utilitaire après de nombreuses heures de patentatage avec les solutions existantes. Je cherchais un format de document sémantique qui soit à la fois agréable à utiliser et qui s’intégre bien avec les utilitaires Unix. Je suis content de dire que cette recherche est maintenant terminée ; je suis satisfait de ma création.
    185 
    186 Je ne prétends pas que ce programme et que les formats qu’il utilise soient d’une utilité universelle. On a vu dans le dernier exemple que les chaînes de commandes qui manipulent des documents plat(5) sont assez complexes. Cet exemple est même relativement simple dans son genre, puisqu’il ignore complètement le deuxième champ, celui des parenthèses, dont on n’aurait pas pu se passer si on n’avait pas préssuposé que le champ ne contiendrait qu’un seul domaine avec l’étiquette :doc:pre:. Aussi le format plat(5) est-il mieux adapté à être manipulé dans des scripts qu’à la ligne de commandes. On peut cependant abstraire une partie de la chaîne de commandes de cet exemple et en la plaçant dans un fichier compiler_c.
    187 
    188 ```
    189 $ cat compiler_c
    190 #!/bin/sh
    191 
    192 grep '^:doc:pre:	' |
    193 	cut -f3 |
    194 	{ tr -d '\n'; echo; } |
    195 	xargs -0 printf '%b' |
    196 	cc -o "$1" -x c -
    197 $ chmod +x compiler_c
    198 ```
    199 
    200 On peut alors composer :
    201 
    202 ```
    203 $ aplat <bonjour.aplat | ./compiler_c "bonjour" && ./bonjour
    204 Bonjour tout le monde!
    205 ```
    206 
    207 J’ai de nombreuses idées de programmes auxiliaires qui permettront de faciliter l’utilisation des formats aplat(5) et plat(5). Je leur dédierai certainement d’autres articles.
    208 
    209 ## Voir aussi
    210 
    211 => /publications/aplat/aplat.tgz Télécharger aplat(1)
    212 => https://git.asteride.xyz/aplat/ Dépôt git du programme.