MOGWAI (langage)

MOGWAI est une bibliothèque développée par GUYZMO permettant de doter les applications d’un moteur d’exécution de scripts. Il devient ainsi possible de modifier une partie du code sans recompiler ni republier. Cette bibliothèque est écrite en .NET Standard et existe aussi pour iOS (écrite en SWIFT). Une version native Android est prévue.
Pour le moment (mais ça va évoluer rapidement) MOGWAI tourne donc sous Windows PC, tablette, phone (RIP) et aussi sous Raspberry PI 3 (grâce à Windows 10 IoT), et sous iOS.
Pourquoi créer un moteur d’exécution ?
Chez GUYZMO nous codons énormément d’applications utilisant le Bluetooth Low Energy (BLE). Suivant le type de périphérique auquel nous nous connectons, il faut effectuer une série d’opérations pour se mettre par exemple dans un état particulier de fonctionnement puis lancer une série de tests centrés sur les échanges BLE. Ce type de manipulations est très courant pendant le développement de l’application pour le client.
Sans ce type de moteur, il faudrait créer pour chaque projet une application de tests permettant d’effectuer toutes les opérations.
Avec ce type de moteur, l’application de tests native reste très générique en effectuant toutes les opérations nécessaires sous la directive d’un code qui est modifiable à volonté, en temps réel, sans recompilation, car c’est le code du moteur de script qui va s’occuper de toute la partie « logique » des tests. Il suffira de stocker pour chaque périphérique un jeu de scripts adapté à son mode de fonctionnement et adapté aux tests à réaliser. La souplesse obtenue est énorme !
Nous avons d’ailleurs créé un outil dans ce sens en utilisant MOGWAI. Un article complet lui est consacré sur ce blog.
Pile et notation polonaise inversée
Pour être efficace et permettre des temps de parsing et d’exécution les plus rapides possibles il était impératif d’utiliser une syntaxe simple évitant au maximum les complexes étapes d’analyse de l’arbre syntaxique et toutes les joyeusetés qui vont avec.
MOGWAI est un langage qui utilise une pile et la notation polonaise inversée (comme le langage Forth). La syntaxe, un peu déroutante au début, est souvent dans l’ordre inverse des langages classiques.
Par exemple, pour demander un nombre aléatoire compris entre 0 et 1, le multiplier par 100, ne garder que la partie entière et le stocker dans la variable « x » on va écrire en MOGWAI :
rand 100 * ->int 'x' sto
et non
x = int(rand() * 100)
Le parent spirituel de MOGWAI est le RPL
Cette manière de coder est très fortement inspirée du langage RPL des calculatrices scientifiques HP. Ce langage est utilisé par HP depuis plusieurs décennies, et s’avère à l’usage efficace et puissant.

Calculatrices HP 48 SX et GX
Le fait que le RPL soit un langage utilisant une pile avec une syntaxe très simple en a fait tout naturellement une source d’inspiration pour créer MOGWAI. Pour ne rien vous cacher, j’ai eu dans ma jeunesse beaucoup de satisfaction à utiliser le RPL pour créer des programmes sympathiques sur ma HP 48 SX (que j’ai toujours et qui fonctionne comme au 1er jour) à l’époque où je passait beaucoup de temps à coder sur tout et n’importe quoi avec tous les langages qui me tombaient sous la main (dit comme ça, on dirait un névrosé qui parle, ça fait peur).
Pile et notation polonaise inversée
La base de tout MOGWAI est là. Quand on sait manipuler la pile et que l’on est à l’aise avec la notation polonaise inversée (RPN, à ne pas confondre avec le langage RPL), coder en MOGWAI s’avère très simple.
Si vous voulez ajouter 2 nombres, il suffit de les placer sur la pile, et d’invoquer la fonction d’addition. Cette fonction va prendre 2 paramètres sur la pile, les ajouter et placer le résultat… sur la pile, tout simplement.
la séquence suivante ajoute les nombres 5 et 9 et place le résultat (14) sur la pile :
5 9 +
Si maintenant je veux multiplier par 10 le résultat :
10 *
Il reste sur la pile la valeur 140
Si on regarde l’état de la pile à chaque étape ça donne ceci :
Etape 1, on pose 5 sur la pile
- Niveau 1 = 5
- Niveau 2 = Vide
Etape 2, on pose 9 sur le pile
- Niveau 1 = 9
- Niveau 2 = 5
- Niveau 3 = Vide
Etape 3, on appelle la fonction +
- Niveau 1 = 14
- Niveau 2 = Vide
Etape 4, on place 10 sur la pile
- Niveau 1 = 10
- Niveau 2 = 14
- Niveau 3 = Vide
Etape 5, on appelle la fonction *
- Niveau 1 = 140
- Niveau 2 = Vide
Cette manière de faire permet de se passer des parenthèses pour indiquer l’ordre des opérations.
Pour calculer (5 + 7) * (17 – 12) * 5 il suffit d’écrire en MOGWAI :
5 7 + 17 12 - * 5 *
Et on obtient sur la pile, au 1er niveau, la valeur 300
Ca marche aussi avec d’autre choses que des nombres :
"bonjou" "r" +
Pose « bonjour » sur la pile (le résultat de la somme de « bonjou » et « r »)
Les paramètres en premier, la fonction en dernier
L’usage systématique de la pile pour passer les paramètres impose d’avoir en 1er les paramètres puis la fonction qui va les utiliser. Comme on l’a vu par exemple pour les fonctions + ou *
2 5 +
et non 2+5
10 20 *
et non 10*20
Quelques points à savoir
Avant de continuer, il faut savoir que :
- Les noms (pour nommer les variables par exemple) sont écrits avec des quotes (ex ‘a’ ‘toto’ ‘essai’)
- Les variables posées sur la pile sont directement évaluées (remplacées par leur valeur) et son écrites sans les quotes
- Les bocks de code sont écrit entre { }
- Les fonctions de conversion commencent par -> (ex ->int pour convertir en entier)
- Qu’au bout d’un moment on s’y fait
Pour stocker une valeur dans une variable on utilise la fonction sto
50 'a' sto
stocke 50 dans la variable a
"HELLO" 'message' sto
stocke « HELLO » dans la variable message
Pour tester si une valeur est plus grande qu’une autre on utilise la fonction >
30 50 >
pose false sur la pile car 30 n’est pas plus grand que 50
30 30 ==
pose true sur la pile car 30 est bien égal à 30
Comment faire un simple IF ?
Pour effectuer un test du genre (en syntaxe type basic) : if a > 50 then b = 30 il faut penser pile+RPN ce qui donne :
test { code à exécuter si le test est positif } IF
en MOGWAI ça donne :
a 50 > { 30 'b' sto } IF
Ce qui je vous l’accorde n’est pas très facile à lire, mais nous allons voir un peu plus loin que ça va s’arranger.
Comment se passe l’exécution de ce code au niveau de la pile ?
Etape 1, on pose sur la pile a (on va dire que dans a il y a la valeur 90, c’est donc 90 qui est posé sur la pile)
- Niveau 1 = 90
- Niveau 2 = Vide
Etape 2, on pose 50 sur la pile
- Niveau 1 = 50
- Niveau 2 = 90
- Niveau 3 = Vide
Etape 3, on appelle la fonction > qui va prendre 2 éléments de la pile et tester si le 1er est > au 2ème et placer le résultat (true ou false) sur la pile. Comme 90 est bien > à 50 donc true est posé sur la pile :
- Niveau 1 = true
- Niveau 2 = Vide
Etape 4, le bloc de code à exécuter si le test est vrai est placé sur la pile :
- Niveau 1 = { 30 ‘b’ sto }
- Niveau 2 = true
Etape 5, on appelle la fonction IF qui va prendre le bloc de code et la valeur booléenne de la pile et exécuter le bloc de code uniquement si la valeur booléenne est vraie (ce qui est le cas ici) :
- Niveau 1 = Vide
Etape 6, le bloc que code est exécuté, on place 30 sur la pile :
- Niveau 1 = 30
- Niveau 2 = Vide
Etape 7, on place le nom ‘b’ sur la pile :
- Niveau 1 = ‘b’
- Niveau 2 = 30
Etape 8, on appelle la fonction sto qui va donc stocker 30 dans la variable b. La pile termine vide :
- Niveau 1 = Vide
Simplification de certaines expressions
Comme vous avez pu le voir avec l’exemple du simple IF, la syntaxe 100% polonaise inversée n’est pas très naturelle. Heureusement MOGWAI possède quelques mécanismes qui permettent (pour certaines expressions) une écriture plus classique.
Ainsi pour le IF, au lieu d’utiliser directement la fonction IF 100% RPN, on peut utiliser l’expression if qui se construit de la manière suivante :
if { bloc de code servant à effectuer le test } then { bloc de code à exécuter si le test est vrai } :
if { a 50 > } then { 30 'b' sto }
Ce qui est plus facile à lire.
La version avec ELSE existe aussi :
if { a 50 > } then { 30 'b' sto } else { 10 'b' sto }
En plaçant les instructions sur plusieurs lignes on retrouve une syntaxe plus habituelle :
if { a 50 > } then { 30 'b' sto } else { 20 'b' sto }
Les expressions suivantes bénéficient du système de simplification et s’écrivent avec une syntaxe plus classique :
- if
- if else
- repeat
- for
- for step
- while
- foreach
- try catch
- onEvent
- timer
Nous verrons en détails chacune de ces instructions tout au long des différents articles qui seront consacrés à MOGWAI .
Les listes
Les listes sont des collections pouvant contenir n’import quel type de base. Elles sont notées avec des parenthèses et chaque élément est séparé par un espace :
( 1 3 4 "hello" ( true "Guyzmo" 156.7 ) "x" "y" 'somme' maVariable )
Celle liste contient 9 éléments différents (3 nombres, 1 chaine, une autre liste, 2 chaines, un nom, un mot)
Il est possible de manipuler les listes avec toute une série de fonctions (qui seront détaillées plus tard).
Le code suivant permet de créer une liste composées de 10 nombres aléatoires compris entre 0 et 99 :
( ) 10 repeat { rand 100 * ->int + }
Pour résumer, ce code place sur la pile une liste vide, puis 10 fois de suite ajoute à la liste présente sur la pile un nombre aléatoire compris entre 0 et 99.
Si on exécute ce code lui-même 10 fois on obtiendra 10 listes de 10 éléments aléatoires compris entre 0 et 99.
10 repeat { ( ) 10 repeat { rand 100 * ->int + } }
Il y a un moyen d’aller encore plus vite (au niveau vitesse d’exécution) en utilisant massivement la pile pour composer une liste :
10 repeat { rand 100 * ->int } 10 ->list
Je vous laisse méditer sur ce petit bout de code qui crée une seule liste de 10 éléments bien plus vite.
Les types manipulables par MOGWAI
MOGWAI sait manipuler les types suivants :
- Nombres (décimaux, hexadécimaux et binaires)
- Chaînes de caractères
- Dates et durées
- Listes (on vient d’en parler)
- Noms
- Mots
- Evénements
- Tâches
- Timers
- Enregistrements (dictionnaires)
- Clés (pour les enregistrements principalement)
- Tableaux d’octets
Les fonctions actuellement disponibles
MOGWAI propose un grand nombre de fonctions de base. Il est possible de l’étendre en utilisant une communication basée sur l’échange avec son hôte via un système d’interfaces et de délégués.
Voici la liste actuelle des fonctions disponibles, certaines vous paraitrons évidentes, d’autres moins et c’est bien normal.
Dans de prochains articles nous regarderons de plus prêt certaines d’entres elles.
+ - * / rand sin cos tan asin acos atan sqr PI max min sum mean abs floor ceil ->deg ->rad sleep halt return reset exit raise ->int ->str ->num ->key ->name ->list ->date ->time ->rec ->bytes eval type tron troff clr dup drop over rot swap pick depth lsto lsto+ lsto- lsto* lsto/ sto sto+ sto- sto* sto/ rcl purge vars save load < <= > >= == != isnull ->not and or IF IFELSE REPEAT FOR FORSTEP WHILE FOREACH DURING break print input trap error clrError debug clrDebug TRYCATCH size get put rem keys last first sub copy now day month year hour minute second time days hours minutes seconds AFTER EVERY DI EI timer.purge timer.suspend timer.resume TASK task.wait task.run task.retval task.running task.purge ONEVENT event.purge event.raise & | ^ >> <<
Conclusion
Voici une première présentation de MOGWAI. Prochainement je vous présenterai MOGWAI Studio et je vous détaillerai d’autres éléments du langage tels que :
- Les enregistrements
- La gestion des variables locales et globales
- La récursivité
- Les expressions for, while et foreach
- L’affichage d’un message
- La saisie d’une valeur
Alors à très bientôt pour la suite de la présentation de MOGWAI et n’hésitez pas à poster des commentaires si le sujet vous intéresse.

Stéphane SIBUE CTO GUYZMO