mardi 8 octobre 2013

brève introduction à forth (4e4th)

Le premier contact avec un programme écris en forth peut générer un certain mouvement de recul car la syntaxe n'a pas grand chose à voir avec celle des langages les plus courants comme C, pascal, basic ou python. Gardez présent à l'esprit les faits suivants concernant la syntaxe du forth:

  • Le seul séparateur de mot est l'espace
  • un identificateur, que se soit le nom d'un variable, d'une constante ou d'une fonction (mot forth) peut utilisé n'importe quel caractère sauf l'espace.
  • Les arguments s'écrivent avant la fonction (mot forth).
  • En forth un fonction ou sous-routine s'appelle un mot et la définition de chaque mot est conesrvée dans un dictionnaire.

Calculatrice forth

Je présume que vous avez configuré votre launchpad tel que décris dans ma chronique précédente et que présentement l'émulateur de terminal de votre choix est connecté à celui-ci.

Entrez dans le terminal la ligne suivante:

3 4 * . <ENTER>

Après avoir fait la touche <ENTER> le nombre 12 devrait apparaître dans la fenêtre terminal suivit de ok. Lorsque la ligne que vous avez saisie est sans erreur ok s'affiche à la suite du texte que vous avez saisi ou de la réponse s'il y en a une et le curseur passe à la ligne suivante. L'interpréteur est prêt à recevoir une nouvelle commande.

Donc ici on a saisi les paramètres '3', '4', le mot '*' et finalement le mot '.' . On a donc calculé le produit de 3 et 4 et on l'a imprimé. Le mot '.' sert à imprimer le nombre qui est au sommet de la pile des paramètres. Lorsqu'on imprime ainsi la valeur au sommet de la pile cette valeur disparait de la pile, elle est consommée. Mais si on ne l'avait pas imprimée elle serait restée au sommet de la pile. Essayons ceci.

3 4 * <ENTER>
2 / <ENTER>
. <ENTER>

Après la dernière commande le nombre 6 devrait apparaître. Le nombre intermédiaire 12 n'a pas été imprimé car on ne l'a pas demandé. La deuxième ligne de commande a divisé ce nombre qui était au sommet de la pile par 2. Et finalement la troisième ligne a imprimé la valeur au sommet de la pile. Important on ne peut écrire 3 4*2/ chaque mot doit être séparé des autres par un espace. En forth il n'y a aucun mot ou symbole réservé même les chiffres ne sont pas réservés. Je pourrais définir un nouveau mot forth qui s'appellerais '3' et le système l'accepterais. L'embêtant est que le nombre 3 ne pourrait plus être utilisé mais le chiffre 3 pourrait-être inclus dans un autre nombre.

Lorsque forth cherche un mot dans le dictionnaire il commence toujours par le dernier mot qui a été défini donc on peut masquer un mot en le redéfinissant. La première définition demeure dans le dictionnaire mais n'est plus accessible. Forth procède comme suis lorsqu'il analyse la ligne de commande:

  1. A partir de la position courante saute les espaces.
  2. Le premier caractère qui n'est pas un espace est le début du mot suivant.
  3. Avance le curseur jusqu'au premier espace qui suit le mot.
  4. Cherche le mot dans le dictionnaire en commençant par la fin (plus récent).
  5. Si le mot est trouvé l'exécute immédiatement et recommence à 1 jusqu'à ce que toute la ligne de commande est été analysée ou qu'il y est une erreur.
  6. Si le mot n'est pas trouvé essai de le convertir en nombre, s'il réussi il met ce nombre au sommet de la pile des paramètres et retourne au point 1. Sinon affiche une erreur, vide la pile des arguments et retourne à la ligne de commande.

Voici comment évolue la pile des arguments pour la commande que nous avons entré précédemment.


'3' n'est pas dans le dictionnaire mais c'est un nombre donc il est empilé. Idem pour '4'. '*' est trouvé dans le dictionnaire il est exécuté. Ce mot fait le produit des 2 arguments au sommet de la pile et les remplaces par le résultat '12'. '2' est encore un nombre et est empilé. '/' est trouvé dans le dictionnaire et a pour effet de diviser le deuxième élément de la pile par le premier et de les remplacer par le résultat '6'. '.' est trouvé dans le dictionnaire et est exécuté. Il a pour effet d'enlever le nombre au sommet de la pile et de l'imprimer au terminal.

Entrez au terminal les 2 lignes suivantes:

variable j <ENTER>
3 constant trois <ENTER>

On viens de créé une variable nommé j et une constante nommée trois. ici les noms suivent le mot. C'est normal pour certains mots le ou les arguments suivent le mot forth contrairement à ce que j'ai dis plus haut. C'est vrai en autre pour les mots qui ajoute une entrée dans le dictionnaire comme le mot ':' que nous verrons plus loin ainsi que ces 2 là. Donc les noms de constantes et de variables sont aussi conservés dans le dictionnaire.
Entrez les 2 lignes suivantes:

trois . <ENTER>
j . <ENTER>

On a saisi trois qui est le nom d'une constante et sa valeur a été empilé on a ensuite imprimé cette valeur. C'est sans surprise mais que ce passe-t'il avec j? Ce nombre qui c'est imprimé c'est l'adresse mémoire ou la valeur de j est enregistré. Si on avait voulu imprimer la valeur de j il aurait fallu faire:

j @ . <ENTER>

Le mot '@' se prononce fetch et sert à lire la valeur de la variable dont l'adresse est au sommet de la pile. La valeur remplace l'adresse. Comme j n'avait pas été initialisée la valeur imprimée ne signifie pas grand chose non plus.

2 4 * j ! <ENTER>
j @ . <ENTER>

Ceci devrait affiché un 8 à l'écran du terminal. Sur la première ligne on a multiplié 2 par 4 ensuite on a enregistré le résultat dans la variable j. Le mot '!' qui se prononce store est le complément de @. Il sert à enregistrer une valeur dans une variable. L'adresse de la variable est au sommet de la pile et la valeur en seconde position. Après l'exécution ces 2 arguments sont disparus de la pile.
Sur la deuxième ligne on a été cherché la valeur de j pour l'imprimer.

maintenant on va voir comment compiler un nouveau mot dans le dictionnaire.

: carre dup * ; ( n|u -- n|u) \ calcule le carré

Le mot ':' sert à définir un nouveau mot dans le dictionnaire. Il est suivit du nom du mot qu'on va définir carre. Ce mot est très simple, il se compose de dup et *. Le mot 'dup' sert à cloner la valeur au sommet de la pile. Après son exécution les 2 premiers éléments de la pile sont donc identiques. Le mot '*' a déjà été présenté. Le mot ';' indique la fin de la définition. Ce qui viens après le point-virgule sont des commentaires. Il y a deux mots pour les commentaires en forth, le mot '(' introduit un commentaire qui est terminé par le délimiteur ')'. Le mot '\' introduit un commentaire qui se termine avec la fin de la ligne. Notez bien que j'ai écris qu'il s'agissait de mots. On doit donc laissé un espace avant et après chacun d'eux. Par contre la parenthèse de droite n'est pas un mot c'est un délimiteur. Cette forme de commentaire est une convention en forth. Le commentaire entre parenthèse décris l'état de la pile avant et après l'exécution du mot. On dit qu'au départ on a un nombre signé 'n' ou non signé 'u' et qu'après l'exécution du mot on a le même type de nombre au sommet de la pile en remplacement du nombre initial. Ici le symbole '|' indique une alternative (c'est l'un ou l'autre). Après ce commentaire un peut utiliser le mot '\' pour donner une brève description de ce que fait ce mot.

Premier programme en forth

Vous vous rappelez sans doute que la première fois que vous avez branché votre carte launchpad les LEDS verte et rouge se sont misent à clignoter en alternance. Mais maintenant qu'on a installé 4e4th dans le MCU ce programme a été écrasé. On va recréer ce programme en forth. Et vous allez être étonnés de la simplicité avec laquelle on fait ça. Mais d'abord entrez les lignes suivantes dans le terminal.

green .s drop drop <ENTER>
red .s 2drop <ENTER>

Je vous présente 5 nouveaux mots. 'green', 'red', '.s', 'drop' et '2drop'.

  • green empile les valeurs 64 et 33. 64 est le masque du bit P1.6 et 33 est l'adresse du port 1. Le LED vert est bien branché sur P1.6
  • red empile les valeurs 1 et 33. 1 est le masque du bit P1.0 et 33 encore un fois l'adresse du port 1. Le LED rouge est bien branché sur P1.0
  • .s est un mot utile pour le débogage. Il imprime le contenu de la pile sans la modifier. Le nombre entre '<' et '>' est le nombre d'éléments qu'il y a sur la pile. Suis les valeurs. La plus profonde à gauche et le sommet à droite.
  • drop jette la valeur qui est au sommet de la pile. Dans le première commande je l'ai utilisé 2 fois car je voulais jeter les 2 valeurs empilées par le mot green
  • 2drop jette les 2 valeurs qui sont au sommets de la pile. Plutôt que d'utiliser 2 fois drop.
Il existe plusieurs mots qui permettent de manipuler les valeurs sur la pile, ils sont parmis les premiers qu'il faut apprendre: swap, rot, over, tuck, nip, etc.
Voyons maintenant notre premier programme forth. Saisissez les lignes suivantes au terminal.

: rouge-vert ( -- ) \ allume en alternance les LEDS rouge et verte <ENTER>
green cclr <ENTER>
red cset <ENTER>
begin green ctoggle red ctoggle <ENTER>
250 ms <ENTER>
s2? until <ENTER>
green cclr red cclr ; <ENTER>
rouge-vert <ENTER>

La majorité des mots utilisés dans cette définition sont spécifique 4e4th sur launchpad et vous ne les retrouverez pas sur une autre plateforme. Donc on difini le mot rouge-vert.

  • cclr Ce mot prend l'adresse du port et le masque qui sont au sommet de la pile et met le(s) bit(s) correspondant(s) à zéro.
  • cset Ce mot prend l'adresse du port et le masque qui sont au sommet de la pile et met le(s) bit(s) correspondant(s) à 1.
  • ctoggle Ce mot prend l'adresse du port et le masque qui sont au sommet de la pile et inverse la valeur de(s) bit(s) correspondant(s).
  • begin Ce mot débute une boucle.
  • until Ce mot termine la boucle si la valeur au sommet de la pile est vrai.
  • s2? Ce mot vérifie l'état du bouton s2 qui est sur la carte et met la valeur vrai au sommet de la pile si le bonton est enfoncé, sinon mais la valeur faux.
  • ms Ce mot créé un délais en millisecondes dont la durée est spécifiée par la valeur au sommet de la pile.

Description du programme

Notre programme est un mot qui s'appelle rouge-vert. On commence par initialisé l'état des LEDs en inverse. Au départ on éteint la verte (ligne 2) et allume la rouge (ligne 3). Ensuite on crée une boucle dans laquelle à chaque cycle on inverse l'état des 2 LEDS (ligne 4). A la ligne 5 on crée un délais de 250 millisecondes. A la ligne 6 on vérifie l'état du bouton s2 qui est sur la carte et on termine la le programme si le bouton est enfoncé. Mais avant de quitter le programme on éteint les 2 LEDS. Une fois qu'un mot est définie dans le dictionnaire il suffit de taper son nom pour l'exécuter.

Conclusion

Si cette brève introduction au forth vous donne le goût d'en savoir plus, vous trouverez dans l'internet tout ce qu'il faut pour satisfaire votre soif de connaissance. Voici quelques liens pour débuter.

  • Vous pouvez télécharger et installer gforth sur votre ordinateur. Ce forth est conforme au standard ANS.
  • Vous pouvez aussi visiter le site Forth Interest Group
  • Les 2 livres de Leo Brodie sont disponible gratuitement dans l'internet. Thinking forth est disponible en PDF et Starting forth peut-être lu en ligne ici.
  • Je ne crois pas qu'il soit encore disponible sinon peut-être dans une bibliothèque publique, Programmer le forth de Robert Van loo aux éditions Marabout est une bonne introduction.

Aucun commentaire:

Publier un commentaire