capsite

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

aplat_1_documents_structures_unix.conv (15321B)


      1 titre:aplat(1) : documents structurés pour Unix
      2 date_pub:25 janvier 2024
      3 date_mod:4 juin 2024
      4 date_pub:21a1
      5 date_mod:2224
      6 auteur:~ldp
      7 type:article
      8 uuid:89352ae7-b5d5-4c87-bf51-edd280ae0c62
      9 
     10 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.
     11 
     12 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.
     13 
     14 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.
     15 
     16 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.
     17 
     18 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.
     19 
     20 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.
     21 
     22 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.
     23 
     24 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).
     25 
     26 ## aplat(5)
     27 
     28 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).
     29 
     30 Voici un exemple de document valide.
     31 
     32 ```
     33 (doc
     34   (titre Un\ programme\ en\ C)
     35   (auteur ~ldp)
     36   (date-pub 2023 - 11 - 18)
     37   (date-mod (vide))
     38   (par "Voici un exemple de document dans le format aplat.")
     39   (lien
     40     (url "https://asteride.xyz/~ldp/exemple.txt")
     41     (texte "Un exemple d’URL"))
     42   (pre
     43 """ langue=C
     44 #include <stdio.h>
     45 
     46 int
     47 main(void)
     48 {
     49 	printf("Bonjour tout le monde!\n");
     50 	return 0;
     51 }
     52 """
     53   )
     54   (par "Ce paragraphe affiche " (it "Bonjour tout le monde!")))
     55 ```
     56 
     57 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.
     58 
     59 => /~ldp/man/aplat.1.txt aplat(1)
     60 => /~ldp/man/aplat.5.txt aplat(5)
     61 => /~ldp/man/plat.5.txt plat(5)
     62 
     63 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.
     64 
     65 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).
     66 
     67 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 ».
     68 
     69 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.
     70 
     71 Il existe trois manières d’échapper des caractères spéciaux.
     72 
     73 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 ».
     74 
     75 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.
     76 
     77 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 (« """! »).
     78 
     79 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.
     80 
     81 Les blocs sont utiles pour inclure verbatim un bloc de texte, comme un programme informatique ou un document HTML.
     82 
     83 ### Métaformats
     84 
     85 À 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 « @ ».
     86 
     87 Voici l’exemple précédent converti à cette convention.
     88 
     89 ```
     90 (doc
     91   (@ (titre      "Un programme en C")
     92      (auteur     "~ldp")
     93      (date-pub   "2023-11-18")
     94      (date-mod   (vide))
     95      (métaformat "genre-de-sxml"))
     96   (par "Voici un exemple de document dans le format aplat.")
     97   (lien (@ (ref "https://asteride.xyz/~ldp/exemple.txt"))
     98 	 "Un exemple d’URL")
     99   (pre
    100 """ lang=C
    101 #include <stdio.h>
    102 
    103 int
    104 main(void)
    105 {
    106 	printf("Bonjour tout le monde!\n");
    107 	return 0;
    108 }
    109 """
    110   )
    111   (par "Ce paragraphe affiche " (it "Bonjour tout le monde!")))
    112 ```
    113 
    114 Ici, les attributs « titre », « auteur », « date-pub », etc. portent sur le domaine nommé « doc » et l’attribut « ref » porte sur celui nommé « lien ».
    115 
    116 ## plat(5)
    117 
    118 Le format plat(5) est une représentation équivalente au aplat(5), au XML, etc.
    119 
    120 Voici la représentation en plat du dernier exemple en aplat.
    121 
    122 ```
    123 :doc:	(	
    124 :doc:@:	(	
    125 :doc:@:titre:	()	Un programme en C
    126 :doc:@:auteur:	()	~ldp
    127 :doc:@:date-pub:	()	2023-11-18
    128 :doc:@:date-mod:	(	
    129 :doc:@:date-mod:vide:	()	
    130 :doc:@:date-mod:	)	
    131 :doc:@:métaformat:	()	genre-de-sxml
    132 :doc:@:	)	
    133 :doc:par:	()	Voici un exemple de document dans le format aplat.
    134 :doc:lien:	(	
    135 :doc:lien:@:	(	
    136 :doc:lien:@:ref:	()	https://asteride.xyz/~ldp/exemple.txt
    137 :doc:lien:@:	)	
    138 :doc:lien:	)	Un exemple d’URL
    139 :doc:pre:	()	#include <stdio.h>\n\nint\nmain(void)\n{\n\tprintf("Bonjour tout le monde!\\n");\n\treturn 0;\n}
    140 :doc:par:	(	Ce paragraphe affiche 
    141 :doc:par:it:	()	Bonjour tout le monde!
    142 :doc:par:	)	
    143 :doc:	)	
    144 ```
    145 
    146 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.
    147 
    148 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.
    149 
    150 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.
    151 
    152 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: ».
    153 
    154 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: ».
    155 
    156 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.
    157 
    158 Le troisième champ correspond au « contenu » du format aplat(5).
    159 
    160 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.
    161 
    162 ## Utilisation d’aplat(1)
    163 
    164 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.
    165 
    166 Il s’ulitise donc de la manière suivante.
    167 
    168 ```
    169 $ aplat <entree.aplat >sortie.plat
    170 ```
    171 
    172 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.
    173 
    174 ```
    175 $ aplat <bonjour.aplat | grep '^:doc:pre:	' | cut -f3 |
    176 	{ tr -d '\n'; echo; } | xargs -0 printf '%b' |
    177 	cc -o bonjour -x c - && ./bonjour
    178 Bonjour tout le monde!
    179 ```
    180 
    181 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.
    182 
    183 ## Conclusion
    184 
    185 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.
    186 
    187 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.
    188 
    189 ```
    190 $ cat compiler_c
    191 #!/bin/sh
    192 
    193 grep '^:doc:pre:	' |
    194 	cut -f3 |
    195 	{ tr -d '\n'; echo; } |
    196 	xargs -0 printf '%b' |
    197 	cc -o "$1" -x c -
    198 $ chmod +x compiler_c
    199 ```
    200 
    201 On peut alors composer :
    202 
    203 ```
    204 $ aplat <bonjour.aplat | ./compiler_c "bonjour" && ./bonjour
    205 Bonjour tout le monde!
    206 ```
    207 
    208 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.
    209 
    210 ## Voir aussi
    211 
    212 => /~ldp/publications/aplat/aplat.tgz Télécharger aplat(1)
    213 => https://git.asteride.xyz/~selve/aplat/ Dépôt git du programme.