Parsing et dialectes
Article paru dans le magazine Login numéro 85
Reproduction interdite. Tous droits réservés à Posse Press et Olivier Auverlot
Ce mois ci, nous allons aborder deux aspects complémentaires du langage: le parsing et les dialectes. Si le premier est déjà connu par les utilisateurs d'autres langages comme Perl ou Javascript, le second est inédit et constitue un des points forts de Rebol. La combinaison d'un puissant outil de manipulation de chaînes de caractères et de la possibilité de définir des dialectes, véritables langages métiers, fait de Rebol un outil unique et profondément expressif.
Le parsing (ou l'art de la manipulation des chaînes de caractères)
Ce n'est un secret pour personne : la manipulation des chaînes de caractères est une opération répétitive, pénible et lassante. Nous sommes tous régulièrement confrontés à des algorithmes destinés à extraire des données d'un fichier plat ou d'une page HTML, à vérifier la concordance avec un format précis, etc. La plupart des langages n'offrent au programmeur que quelques fonctionnalités destinées à ajouter des caractères ou à rechercher une chaîne dans une autre. En général, cela ne va pas très loin et montre rapidement ses limites. Heureusement pour nous, certains développeurs en ont eu assez de répéter inutilement et indéfiniment les mêmes tortures intellectuelles. Ils ont donc eu l'idée que la manipulation des chaînes de caractères pouvait être modélisée en un ensemble de règles : c'est la technique du parsing. Perl de Larry Wall, destiné à l'origine à l'extraction de données et à la génération de rapports, est l'un des langages les plus réputés pour ses possibilités dans le domaine du parsing. En quelques caractères, il est possible de définir un traitement qui sera appliqué à tous les signes d'une chaîne.
Rebol et le parsing
Rebol est un messaging language. Sa fonction première est d'obtenir, de traiter et de communiquer l'information. Sur le web, la plupart des données étant stockées dans des pages HTML ou des fichiers XML qui sont tous deux des fichiers textes, il est logique que Rebol dispose d'un outil d'analyse et d'extraction d'informations présentes dans des chaînes de caractères.
La vision du parsing par Rebol est beaucoup plus moderne que celle implémentée dans la plupart des autres langages. Il ne s'agit pas ici de saisir des suites de caractères absconses mais d'utiliser un véritable langage conçu pour ce type d'opération : un dialecte.
Le parsing utilise un dialecte
Un dialecte est un langage métier qui est intégré à Rebol. C'est un langage dans le langage. Il est dédié à une tâche particulière et ne fait que cela. Le dialecte du parsing est ici le premier que vous découvrez mais sachez que Rebol comporte plusieurs autres dialectes. Ainsi, lorsque nous aborderons bientôt la création d'interfaces graphiques à l'aide de Rebol/View, nous utiliserons le dialecte VID (Visual Interface Dialect) dont l'objectif est de définir les composants graphiques d'une application. PREZ est un autre dialecte permettant la conception de présentations graphiques et gérant l'affichage des données ainsi que la synchronisation et les effets graphiques. Ce qui est vraiment génial avec les dialectes, c'est que nous pouvons utiliser des langages métiers ultra performants dans leur domaine mais également définir nos propres dialectes. Il est tout à fait envisageable d'implémenter un interpréteur Basic dans Rebol, permettant ainsi de mixer les deux langages.
Les dialectes ont également un autre intérêt : celui de permettre la découpe d'une application en quatre parties :

L'architecture des applications en Rebol peut être hautement modulable
Si dans les applications actuelles nous avons la possibilité de paramétrer le logiciel (valeur maximale, valeur par défaut, etc), grâce aux dialectes, nous avons maintenant la possibilité d'extraire du corps de l'application la logique fonctionnelle. Le paramétrage d'un programme s'étend maintenant à sa logique interne, à son comportement. Toute la difficulté est maintenant de définir un dialecte spécialisé qui sera le plus polyvalent possible…
Un peu de parsing
En Rebol, il faut utiliser le mot PARSE pour effectuer une opération de parsing sur une chaîne de caractères. Les deux arguments de ce mot sont la chaîne de caractères manipulée et un bloc contenant les règles de traitement qui seront appliquées. Si l'opération ne consiste qu'en la découpe de la chaîne selon un caractère séparateur, nous pouvons indiquer uniquement, à la place de bloc, le caractère utilisé ou une chaîne contenant plusieurs caractères séparateurs. La valeur NONE indique que les mots de la chaîne doivent être découpés selon les espaces et les autres caractères séparateurs standards tel que la virgule.
Supposons que nous ayons une chaîne TXT contenant la phrase "Quelques mots sur Rebol", nous pouvons séparer les différents mots les uns des autres à l'aide de la syntaxe : parse txt none. Nous obtenons alors un bloc contenant différentes chaînes de caractères correspondantes à chaque mot.
Dans ce second exemple, nous avons une chaîne TXT contenant les caractères "abcdefg". Nous voulons ici découper la chaîne selon les caractères séparateurs "b" et "e". Il nous suffit de faire : parse txt "be" pour obtenir le résultat escompté.
Il est possible également de vérifier la concordance d'une chaîne avec un modèle. La chaîne suivante contient-elle uniquement deux séquences de caractères "xx" ?
txt: "xx xx"parse txt [ 2 "xx" ]
Nous utilisons ici une règle vérifiant la présence de deux chaînes "xx" dans une autre chaîne. Le mot PARSE retourne alors une valeur booléenne.
Nous pouvons également extraire des données d'une chaîne selon une règle. Par exemple, nous voulons prélever les caractères présents entre les chaînes "xx" et "yy" :
txt: "quelques xx mots yy sur Rebol"parse txt [thru "xx"copy chaineto "yy"( print chaine )]
Nous découpons ici le contenu de TXT à partir de "xx" jusque "yy". Le résultat est sauvegardé dans le mot CHAINE qui est affiché à l'aide de PRINT. Le dialecte de parsing permet l'exécution d'instructions Rebol à l'intérieur de son propre code.
Définir un dialecte
Créer un dialecte revient en fait à définir des règles d'analyse. Si la syntaxe est correcte, les instructions du dialecte sont exécutées. A titre d'exemple, nous pouvons mettre en place un dialecte nommé CURSOR pour manipuler le curseur de la console de Rebol. Nous allons définir deux instructions :
Les règles sont simples. Si Rebol rencontre le mot CLS, il efface l'écran. Par contre, si c'est le mot AT qui est trouvé, il faut obligatoirement qu'il soit suivi d'une donnée de type pair!. Les règles sont exclusives. L'instruction exécutée est l'une de celles qui ont été définies (ANY) mais il n'y a qu'une seule instruction qui puisse correspondre au modèle recherché. Pour cela, on utilise le caractère "|" qui correspond à "ou". Une fonction nommée CURSOR reçoit en paramètre le bloc de code devant être analysé et exécute le parsing. A l'aide du mot COMPOSE, toute expression entourée par des parenthèses est évaluée et remplacée par sa valeur. Cette fonctionnalité nous permet d'insérer des variables ou du code Rebol au sein même d'un code rédigé avec un dialecte.
REBOL [Subject: "dialecte cursor"Author: "Olivier Auverlot"]cursor-rules: [any ['CLS (print "^(1B)[J") |'AT set pos pair! (prin join "^(1B)[" [ pos/y ";" pos/x "H" ])]]cursor: function [ code ] [] [ parse (compose code) cursor-rules ]
Nous pouvons maintenant utiliser notre dialecte dans nos scripts Rebol. L'exemple qui suit efface l'écran, affiche une chaîne de caractères en haut de l'écran et dessine ensuite une ligne de vingt caractères juste en dessous :
cursor [clsat 10x2]prin "Bonjour !"p: 1x4for x 1 20 1 [p/x: xcursor [ at (p) ]prin "="]

Un exemple d'utilisation de notre dialecte
Et la prochaine fois ?
Dans le prochain numéro, nous allons attaquer un autre aspect fantastique de Rebol : les protocoles réseaux. Nous allons découvrir la puissance de ce langage, conçu pour transmettre et recevoir des informations.
Olivier Auverlot