LE COMPILATEUR FORTH

Le langage FORTH est d'un fonctionnement tout à fait original car il intègre à la fois un interpréteur, un compilateur et un assembleur. La version F83 dispose même de trois interpréteurs:

-l'interpréteur externe avec lequel vous avez déjà fait connaissance en exécutant les manipulations précédemment décrites.

-l'interpréteur d'exécution pas à pas qui opère sur une définition et permet la mise au point des routines délicates.

-l'interpréteur d'adresse interne.

Les deux premiers sont écrits en FORTH, le dernier est écrit en langage machine.

Le compilateur FORTH travaille en une seule passe et sans gérer de table de référence. So rôle est d'accroître les fonctions disponibles dans le dictionnaire.

L'assembleur FORTH peut traiter les branchements avant en utilisant des structures de contrôle évoluées à la place d'étiquettes ou de labels. Une séquence écrite en code machine peut être assemblée entre deux définitions compilées en FORTH avec CODE ... END-CODE, et même dans une définition en forth avec ASM[ ... ]FORTH.

A. Compilation d'une définition

La compilation d'une définition ordinaire débute par le mot : (deux-points) et s'achève par le mot ; (point- virgule). Le mot : est suivi du libellé du mot à définir. Tout ce qui se trouve entre ce mot et le mot ; fait partie de la définition du mot et sera ensuite exécuté, soit directement depuis l'interpréteur, soit depuis une autre définition de mot FORTH. Pour exemple, compilons une définition que l'on nommera AFFICHE-BINAIRE et dont le rôle sera d'afficher en binaire un nombre préalablement déposé au sommet de la pile de données:

: AFFICHE-BINAIRE
2 BASE ! . DECIMAL ;

Le mot : (deux-points) ouvre une séquence de compilation et est suivi du libellé du mot à définir. Le nom peut être composé de tous les caractères ASCII dont le code est compris entre 33 et 126 à l'exclusion de tout espace ou caractère de contrôle. La longueur d'un mot est comprise entre 1 et 31 caractères maximum.

Le nom est suivi de la définition:

2 BASE ! \ passage en base numérique binaire .
\ affichage du nombre précédemment empilé
DECIMAL \ restitution de la base numérique décimale

La fin de la séquence de compilation est marquée par le mot ; (point-virgule). Forth revient en mode interprétation. Cette définition peut être tapée depuis le clavier ou faire partie d'un fichier ASCII. Dans ce cas, sa compilation sera exécutée en tapant:

INCLUDE <fichier>

où <fichier> est le nom du fichier contenant le texte à compiler. Les fichiers compilables par TURBO-Forth ont l'extension FTH par défaut, pour toute autre extension, la préciser.

A titre d'exercice, éditez un fichier que vous nommerez BINAIRE.FTH, tapez la petite définition donnée en exemple, sauvegardez votre fichier et revenez sous TURBO, puis tapez INCLUDE BINAIRE.

Maintenant la nouvelle définition fait partie du dictionnaire FORTH, comme on peut le constater en tapant WORDS. Pour essayer le fonctionnement du mot qui vient d'être créé, il suffit de taper:

14 AFFICHE-BINAIRE affiche 1110 756
AFFICHE-BINAIRE affiche 1011110100

Si vous trouvez qu'AFFICHE-BINAIRE est trop long, réécrivez votre définition en l'appelant AFBIN ou mieux en définissant AFBIN comme suit: :

: AFBIN AFFICHE-BINAIRE ;

Tout mot compilé dans le dictionnaire FORTH peut être intégré à une nouvelle définition. En FORTH, un mot peut être considéré comme programme principal ou comme procédure d'un programme plus général.

Lors de la compilation d'une nouvelle définition tapée au clavier, vous pouvez taper sur <RET> à peu près n'importe quand:

: AFBIN 2 BASE ! . DECIMAL ; puis <RET>

Cette définition peut être tapée depuis le clavier en plusieurs fois de la manière suivante:

: AFBIN <RET>
2 BASE <RET>
! . <RET>
DECIMAL <RET>
; <RET>

La disposition des mots, le nombre d'espaces entre les mots, ainsi que la frappe en majuscule ou minuscule importe peu:

:     afbin 2 BaSe !         .     DecimaL         ;

sera également accepté pourvu que le format des nombres soit cohérent et que les mots utilisés soient définis dans le dictionnaire.

Une restriction cependant est à signaler concernant la différence entre caractères majuscules et minuscules: elle peut être prise en compte selon l'état de la variable CAPS servant de flag booléen sur le contrôle du flux d'entrée:

CAPS ON : truc ; WORDS
affiche en tête de dictionnaire le mot TRUC

CAPS OFF : truc ; WORDS
affiche en tête de dictionnaire le mot truc Si CAPS est à l'état OFF, FORTH fera la différence entre caractères majuscules et minuscules dans le libellé d'un mot.

A ce jour, le langage FORTH est le seul langage connu acceptant de compiler du code source tapé directement depuis le clavier de manière aussi interactive. Cette dualité interpréteur/compilateur est également exploitable lorsque l'on veut compiler le contenu d'un fichier.

B. Compilation et chaînage de fichiers source

Pour charger le contenu d'un fichier source, il faut utiliser le mot INCLUDE suivi du nom du fichier à traiter. L'extension du fichier est par défaut FTH et peut être omise. Dans le cas contraire, préciser l'extension. Le fichier peut provenir d'un lecteur disque ou d'un répertoire différent du lecteur courant ou répertoire courant:

INCLUDE TEST.TXT traite TEST.TXT
INCLUDE b:BINAIRE traite BINAIRE.FTH
INCLUDE c:\TF83\F-PACK traite F-PACK.FTH contenu dans C:\TF83

Si vous ne savez plus où se trouve le fichier à traiter, il faut utiliser DIR avec les mêmes options que la commande DIR sous MSDOS:

DIR *.*              affiche directory lecteur courant
DIR b:*.*               affiche directory lecteur b:
DIR C:\TF83\*.FTH       affiche les fichiers d'extension FTH de c:\TF83

Pour visualiser le contenu d'un fichier avant chargement et compilation, le mot LIST suivi du nom du fichier à lister affiche son contenu. Un appui sur une touche quelconque autre que la touche <RET> interrompt provisoirement le défilement, un nouvel appui relance le défilement. Deux appuis successifs sur <RET> interrompent définitivement le défilement.

Comme cela a déjà été expliqué brièvement, TURBO- Forth peut compiler des définitions provenant d'un fichier ASCII. Mais TURBO-Forth peut aussi interpréter une série de commandes ou d'opérations placées dans ces mêmes fichiers.

En fait, le langage FORTH ne fait pas de distinction entre le clavier et un fichier source: charger un fichier avec INCLUDE est équivalent à saisir au clavier chacune des lignes de ce fichier.

Reprenez le contenu du fichier BINAIRE.FTH que vous avez créé pour tester le précédent exemple et rajoutez après AFBIN les lignes suivantes:

CR 1 AFBIN
CR 8 AFBIN
CR 25 AFBIN

sauvegardez à nouveau BINAIRE.FTH et recompilez son contenu depuis TURBO-Forth par INCLUDE BINAIRE. TURBO-Forth compilera le contenu du fichier BINAIRE.FTH et exécutera les trois lignes qui ont été rajoutées.

Cette dualité interprétation/compilation est très utile, car elle permet de modifier le contexte FORTH en cours de compilation:

HEX
C0 EMIT 10 C4 REPLICATE D9 EMIT CR
DECIMAL

Ce programme sera parfaitement exécuté. Le contenu d'un fichier ASCII contenant des instructions FORTH est normalement compilé ou interprété depuis le début du fichier jusqu'à la fin physique du fichier. Mais on peut provoquer une fin artificielle de fichier en exécutant en mode interprété le mot EOF, c'est à dire en le plaçant en dehors d'une définition "deux-points".

Dès que le mot EOF est exécuté, la compilation ou interprétation se poursuit vers le programme appelant ou rend la main à l'utilisateur. Tout texte situé après EOF ne sera pas chargé en mémoire, donc ni interprété, ni compilé. Le mot EOF a deux utilités:

-placé après le source à interpréter ou compiler, il permet de commenter le programme, voire de le documenter.

-placé n'importe où dans un fichier source en cours de mise au point, il permet de limiter la compilation et de rechercher plus facilement les erreurs de compilation.

Lorsqu'un fichier est en cours de compilation ou d'interprétation, on peut suivre la compilation en positionnant la variable ECHO avec un flag booléen vrai:

ECHO ON
INCLUDE BINAIRE

affiche le programme au fur et à mesure de la compilation/interprétation du programme.

La séquence ECHO OFF supprime l'affichage du fichier en cours de compilation. Les directives ECHO ON et ECHO OFF peuvent être utilisées au sein d'un fichier aussi souvent que vous le souhaitez.

Si vous envisagez de développer une application de taille conséquente, il est souhaitable dans un premier temps, de la fractionner en plusieurs fichiers de petite taille. Eventuellement, une partie de programme peut être réutilisée par un autre programme et dans ce cas, le morcellement devient nécessaire. Exemple, supposons que nous ayons créé un programme dont le source est réparti sur trois fichiers PART1.FTH, PART2.FTH et PART3.FTH:

-on peut le compiler en tapant INCLUDE PART1 INCLUDE PART2 INCLUDE PART3 depuis le clavier.

-on peut créer un autre fichier, nommé GENERAL par exemple contenant les lignes suivantes:

INCLUDE PART1
INCLUDE PART2
INCLUDE PART3

puis compiler toute l'application en tapant INCLUDE GENERAL.

TURBO-Forth accepte jusqu'à huit niveaux d'imbrications de fichiers. Un même ficher peut appeler une infinité de sous-fichiers:

INCLUDE PART1
INCLUDE PART2
...etc...
INCLUDE PART1000

Tout fichier dont la compilation est achevée fait remonter les imbrications de fichiers d'un niveau dans la hiérarchie des imbrications.

Prenez soin de toujours bien commenter vos programmes source. Il y a trois manière de commenter les programmes:

-le mot ( (parenthèse ouvrante) ouvre une zone commentaire qui s'achève après le premier caractère ) rencontré.

-le mot \ déclare le reste de la ligne courante comme zone commentaire

-le mot EOF déclare le reste du fichier courant comme zone commentaire.

Exemple:

: .NBR ( n ---)
  BASE @ >R
  \ sauvegarde valeur initiale de BASE
  DUP CR DECIMAL ." Dec: " 5 .R
  \ affiche n en décimal
  DUP CR HEX ." Hex: " 5 .R
  \ puis en hexadéimal
  CR OCTAL ." Oct: " 5 .R
  \ et enfin en octal
  R> BASE ! ;
    \ restaure valeur initiale de BASE ( fin de définition )
EOF

Le mot .NBR affiche un nombre entier 16 bits signé sur trois lignes séparées en décimal, hexadécimal et octal, ceci quelque soit la base numérique initiale. Ex:

2 BASE !
1010 .NBR affiche
Dec: 10
Hex: A
Oct: 12

Lors de la compilation de ce programme, les parties de définitions situées entre parentèses, celles comprises entre \ et la fin de ligne et celles écrites après EOF seront ignorées.

C. Les mots dans le dictionnaire

1. Ordre des mots dans le dictionnaire

Une fois la compilation d'un nouveau mot achevée, il fait partie du dictionnaire au même titre que tous les mots déjà définis. On peut contrôler à tout instant la présence des mots définis en utilisant WORDS. Le dernier mot défini est le premier de la liste affichée par l'exécution de WORDS. Exemple:

: MOT1 ;
: MOT2 ;
: MOT3 ;
WORDS affichera MOT3 MOT2 MOT1 ...suite du dictionnaire..

Lors de l'exécution de WORDS, les mots définis par vous ou ceux déjà pré-définis apparaissent dans l'ordre inverse de leur création, à savoir que le mot le plus récemment défini est affiché en premier.

Seuls les mots appartenant au vocabulaire courant sont affichés:

FORTH WORDS affiche les mots du vocabulaire FORTH
ASSEMBLER WORDS affiche les mots du vocabulaire ASSEMBLER
FORTH vous ramène dans le vocabulaire FORTH

TURBO-Forth dispose d'un certain nombre de vocabulaires pré-définis dont vous pouvez lister les noms en exécutant VOCS. La connaissance du contenu de ces divers vocabulaire n'est pas indispensable pour le moment.

Tous les mots FORTH sont chaînés entre eux et l'entrée dans cette chaîne a toujours lieu à partir du dernier mot défini dans le vocabulaire courant.

Lorsqu'une définition d'un mot fait référence à des mots du dictionnaire, chaque adresse correspondante est exprimée en adressage absolu au sein de la nouvelle définition. Ainsi, la définition d'un mot FORTH n'est pas relogeable en mémoire sous sa forme compilée.

2. Mots définis plusieurs fois

Si deux mots portent le même nom, seul le dernier mot défini sera exécutable en interprétation:

: TEST1 ." Premier test " CR ;
: TEST1 ." Second test " CR ;

(Ne tenez pas compte du message TEST1 existe déjà:)

TEST1 affiche SECOND TEST

L'interpréteur accède au contenu du dictionnaire à partir du dernier mot défini et exécute la définition la plus récemment définie parmi deux ou plusieurs définitions de même nom. Si une définition utilise la première version de TEST1, la création d'un nouveau mot portant également le nom TEST1 ne modifie pas le comportement de cette définition:

: TEST1 ." Premier test " CR ;
: REGARDE TEST1 ;
: TEST1 ." Second test " CR ;
REGARDE affiche Premier test

Pour modifier REGARDE et lui faire utiliser la nouvelle version de TEST, il faut également recompiler REGARDE:

: TEST1 ." Premier test " CR ;
: REGARDE TEST1 ;
: TEST1 ." Second test " CR ;
: REGARDE TEST1 ;
REGARDE affiche Second test

Cette homonymie tolérée par FORTH permet de compiler successivement plusieurs programmes comportant des définitions de même nom sans avoir à rééditer le programme source pour renommer les noms de définitions identiques.

Cependant, dans une phase de mise au point de définition, on peut être gêné par la présence d'homonymes, et il est souhaitable de supprimer les versions de certaines définitions devenues inutiles, soit pour conserver la cohérence du programme, soit pour récupérer de l'espace mémoire ou toute autre raison pratique.

Enfin, l'existence de plusieurs vocabulaires définis par le programme est une façon élégante de levre les ambiguités entre homonymes.

3. Supprimer un mot du dictionnaire

Pour supprimer un mot du dictionnaire, il faut exécuter le mot FORGET suivi du nom de la définition à supprimer:

FORGET MOT1

supprime du dictionnaire MOT1 et tous les mots définis après lui. Si MOT1 est défini plusieurs fois, seule la dernière version de MOT1 est supprimée. Exemple:

: TEST1 ." Premier test " CR ;
: REGARDE TEST1 ;
: TEST1 ." Second test " CR ;
: REGARDE TEST1 ;

WORDS       affiche       REGARDE MOT1 REGARDE MOT1 ...etc...

FORGET MOT1       affiche             REGARDE MOT1 ...etc...

Pour oublier tous les mots définis depuis le lancement de TURBO-Forth, taper EMPTY.

Vous pouvez marquer le début d'une application en exécutant MARK suivi du nom de l'application. Exemple, soit à compiler les fonctions graphiques contenues dans le fichier GRAPHIC.FTH, puis à compiler un programme utilisant ces fonctions graphiques:

INCLUDE GRAPHIC
MARK DESSIN
INCLUDE <fichier> \ ici donner nom de votre application

Si le contenu de a été modifié et doit être recompilé, il ne sera pas nécessaire de taper EMPTY puis de tout recompiler; en tapant DESSIN, vous supprimerez du dictionnaire les seules définitions compilées après le mot DESSIN.

Si vous essayez de supprimer une primitive du dictionnaire, un message d'erreur s'affichera:

FORGET DUP       affiche       Partie dictionnaire protégée

Il est possible de protéger son application contre une destruction accidentelle en tapant la séquence:

HERE FENCE !

Exemple:

: TEST1 ." Troisième test " CR ;
: REGARDE TEST1 ;
HERE FENCE !
FORGET TEST1    affiche      Partie dictionnaire protégée

Le mot FORGET teste d'abord la valeur contenue dans la variable FENCE; si son contenu est inférieur à l'adresse de compilation du mot à supprimer, le mot est supprimé du dictionnaire; dans le cas contraire, un message d'erreur s'affiche. La séquence HERE FENCE ! réinitilialise le contenu de FENCE en lui attribuant la valeur du pointeur de dictionnaire actuelle, c'est à dire une valeur supérieure à l'adresse de compilation de TEST1, ainsi TEST1 et REGARDE deviennent des mots protégés.

D. Constantes et variables simple précision

Tout programme écrit en FORTH, aussi sophistiqué soit-il, ne peut pas toujours traiter des données provenant de la pile de données. Dans certains cas on fera appel à des constantes et des variables. Les constantes sont définies à l'aide du mot CONSTANT:

1988 CONSTANT ANNEE

Les variables sont définies à l'aide du mot VARIABLE:

VARIABLE JOURS

La constante ANNEE et la variable JOURS figurent maintenant dans le dictionnaire FORTH, c'est-à-dire qu'elles sont disponibles au même titre qu'un mot compilé par : (deux-points) ou n'importe quelle autre primitive déjà définie dans FORTH. Seule l'exécution de ces mots diffère de celle d'un mot défini par : (deux-points).

Une constante dépose au sommet de la pile de données la valeur affectée au moment de sa définition:

ANNEE . affiche 1988

Une variable dépose au sommet de la pile de données l'adresse contenant la valeur qui lui a été affectée ou qui devra y être affectée.

JOURS .   affiche   une adresse 16 bits

Le contenu de cette adresse est déposé sur la pile de données par l'exécution du mot @:

JOURS @ .   affiche   0

Zéro est la valeur attribuée par défaut à une variable lors de sa création.

Une valeur numérique 16 bits peut être stockée dans une variable par l'exécution du mot !:

15 JOURS !
JOURS @ .   affiche   15

En fait, les mots @ et ! agissent sur n'importe quelle adresse mémoire. Si vous tapez:

256 @ .

FORTH affichera le contenu 16 bits des adresses 256 et 257 selon le mécanisme suivant:

L'inversion des valeurs a et b est valable pour les versions F83 tournant sur des systèmes équipés de microprocesseur Z80, 8080 ou 8086 (octet de poids faible d'abord). Sur les autres systèmes, le mécanisme peut différer, mais le résultat figurant au sommet de la pile de données sera identique.

Le mot ? combine l'action de @ et . et s'utilise comme suit:

16 JOURS !
JOURS ?   affiche   16

Le mot +! incrémente le contenu d'une variable:

2 JOURS +!
JOURS ?   affiche   18

Pour décrémenter le contenu d'une variable, il suffit de l'incrémenter avec une valeur négative:

-10 JOURS +!
JOURS ?   affiche   8

Si cette incrémentation ou décrémentation est d'une seule unité, on utilisera de préférence les mots 1+! et 1-!:

JOURS 1+! JOURS ?   affiche   9
JOURS 1-! JOURS ?   affiche   8

Dans certaines situations, on peut considérer le contenu d'une variable 16 bits comme un flag booléen et non comme une valeur littérale. Dans ce cas, toute valeur non nulle sera considérée comme vraie et toute valeur nulle comme fausse:

VARIABLE VIVANT
: .HERITAGE ( ---)
VIVANT @
IF ." Attendez encore pour hériter"
ELSE ." Maintenant, courrez chez le notaire"
THEN ;
0 VIVANT ! \ considère mort
.HERITAGE   affiche   Maintenant, courrez chez le notaire

Pour traiter sans équivoque les valeurs booléennes, on restreindra les valeurs affectables à une variable 16 bits, considérée comme flag booléen, les seules valeurs 0 ou -1.

Pour augmenter la lisibilité des programmes FORTH, deux constantes pré-définies, TRUE et FALSE reprennent ces valeurs:

TRUE .   affiche   -1
FALSE .   affiche     0
TRUE VIVANT !
.HERITAGE   affiche   Attendez encore pour hériter

Les affectations booléennes ont été simplifiées et peuvent être exécutées par ON et OFF:

VIVANT ON .HERITAGE
affiche Attendez encore pour hériter
VIVANT OFF .HERITAGE   affiche   Maintenant, courrez chez le notaire

Le mot OFF peut aussi servir à remettre à zéro n'importe quelle variable 16 bits ou emplacement mémoire 16 bits. Exemple:

VARIABLE SCRORE
10 SCORE +! SCORE ?   affiche   10
SCORE OFF SCORE ?   affiche   0

E. Constantes et variables double précision

Si l'intervalle de définition d'une constante ou d'une variable définie par CONSTANT ou VARIABLE est trop restreint pour une application particulière, on peut faire appel aux constantes et aux variables double précision.

Une constante double précision est définie par le mot 2CONSTANT:

150000. 2CONSTANT JACKPOT

Une variable double précision est définie par le mot 2VARIABLE:

2VARIABLE SCORE

Une valeur double précision est affectée à une variable double précision par le mot 2!:

120000. SCORE 2!

Le contenu d'une variable double précision est déposé au sommet de la pile de données par l'exécution du mot 2@:

SCORE 2@ D. affiche 120000

Il n'y a pas d'équivalent à +!, 1+!, 1-!, ON et OFF en 32 bits, mais il est aisé de les définir soi-même:

: D+! ( d adr ---)
DUP >R \ duplique et sauvegarde adresse de variable
2@ \ empile valeur 32 bits contenue à adresse adr
D+ \ fait la somme 32 bits
R> 2! ; \ range résultat 32 bits à l'adresse adr
: D1+! ( adr ---)
>R 1. R> D+! ;
: D1-! ( adr ---)
>R -1. R> D+! ;
: D-ON ( adr ---)
>R TRUE S>D R> 2! ;
: D-OFF ( adr ---)
>R FALSE S>D R> 2! ;

F. Définition de variables alphanumériques

Pour définir une variable alphanumérique, il faut utiliser le mot de définition STRING précédé de la capacité maximale que peut atteindre la chaîne en cours d'utilisation. Cette taille est comprise entre 1 et 255:

80 STRING A$

crée une variable chaîne A$ dont la capacité maximale est de 80 caractères. L'affectation d'un contenu à une chaîne, en interprétation ou compilation, est exécutée par le mot $! comme suit:

" TEST" A$ $!
\ syntaxe: contenu contenant affectation

L'exécution du mot A$ dépose sur la pile l'adresse et la longueur de la chaîne de caractères contenue dans la zone paramétrique de A$.

A$ TYPE   affiche   TEST

Le contenu d'une variable chaîne peut être modifié:

" CECI EST UN AUTRE TEST" A$ $!
A$ TYPE affiche CECI EST UN AUTRE TEST

Pour concaténer une chaîne à une variable chaîne, utiliser APPEND$ comme suit:

" DE CONCATENATION" A$ APPEND$
A$ TYPE affiche CECI EST UN AUTRE TEST DE CONCATENATION

Les mots $! et APPEND$ n'autorisent pas l'affectation d'un nombre de caractères supérieur à la capacité maximale de la variable alphanumérique définie par STRING.(Pour toutes les autres manipulations de chaînes, reportez-vour au chapitres "caractères de chaînes")

G. Les mots d'exécution vectorisée

Les mots d'exécution vectorisée sont définis par le mot de définition DEFER. Pour en comprendre les mécanismes et l'intérêt à exploiter ce type de mot, voyons plus en détail le fonctionnement de l'interpréteur interne du langage FORTH.

1. Création et initialisation d'un vecteur

Toute définition compilée par : (deux-points) contient une suite d'adresses codées sur seize bits correspondant aux champs de code des mots précédemment compilés. Au coeur du système FORTH, le mot EXECUTE admet comme paramètre ces adresses de champ de code, adresses que nous abrégerons par cfa pour Code Field Address. Tout mot FORTH a un cfa et cette adresse est exploitée par l'interpréteur interne de FORTH:

' <mot>   dépose le cfa de <mot> sur la pile de données.

Exemple:

' WORDS   empile le cfa de WORDS.

A partir de ce cfa, connu comme seule valeur littérale, l'exécution du mot est provoquée par EXECUTE:

' WORDS EXECUTE

exécute WORDS. Bien entendu, il aurait été plus simple de taper directement WORDS. A partir du moment où un cfa est disponible comme seule valeur littérale, il peut être manipulé et notamment stocké dans une variable:

VARIABLE VECTEUR
' WORDS VECTEUR !
VECTEUR ?

affiche le cfa de WORDS stocké dans la variable VECTEUR

VECTEUR @ EXECUTE

lance l'exécution du mot dont le cfa a été stocké dans la variable VECTEUR puis remis sur la pile avant utilisation par EXECUTE.

C'est un mécanisme similaire qui est exploité par la partie exécution du mot de définition DEFER. Pour simplifier, DEFER crée un en-tête dans le dictionnaire, à la manière de VARIABLE ou CONSTANT, mais au lieu de déposer simplement une adresse ou une valeur sur la pile, il lance l'exécution du mot dont le cfa a été stocké dans la zone paramétrique du mot défini par DEFER.

L'intialisation d'un mot défini par DEFER est réalisée par IS:

DEFER VECTEUR
' WORDS IS VECTEUR

L'exécution de VECTEUR provoque l'exécution du mot dont le cfa a été précédemment affecté:

VECTEUR   exécute   WORDS

Un mot créé par DEFER sert à exécuter un autre mot sans faire appel explicitement à ce mot. Le principal intérêt de ce type de mot réside surtout dans la possibilité de modifier le mot à exécuter:

' DARK IS VECTEUR

VECTEUR exécute maintenant DARK et non plus WORDS.

On utilise essentiellement les mots définis par DEFER dans deux situations:

-définition d'une référence avant;
- définition d'un mot dépendant du contexte d'exploitation.

Dans le premier cas, la définition d'une référence avant permet de surmonter les contraintes de la sacro- sainte précédence des définitions.

Dans le second cas, la définition d'un mot dépendant du contexte d'exploitation permet de résoudre la plupart des problèmes d'interfaçage avec un environnement logiciel évolutif, de conserver la portabilité des applications, d'adapter le comportement d'un programme à des situations contrôlées par divers paramètres sans nuire aux performances logicielles.

2. Définition d'une référence avant

Contrairement à d'autres compilateurs, FORTH n'autorise pas la compilation d'un mot dans une définition avant qu'il ne soit défini. C'est le principe de la précédence des définitions:

: MOT1 ( ---) ... MOT2 ... ;
: MOT2 ( ---) ............ ;

génère une erreur à la compilation de MOT1, car MOT2 n'est pas encore défini.

DEFER MOT2
: MOT1 ( ---) ... MOT2 ... ;
: (MOT2) ( ---) ............ ;
' (MOT2) IS MOT2

Cette fois-ci, MOT1 a été compilé sans erreur. Il n'est pas nécessaire d'affecter un cfa au mot d'exécution vectorisée MOT2. Ce n'est qu'après la définition de (MOT2) que la zone paramétrique du MOT2 est mise à jour. Après affectation du mot d'exécution vectorisée MOT2, MOT1 pourra exécuter sans erreur le contenu de sa définition. L'exploitation des mots créés par DEFER dans cette situation doit rester exceptionnel.

3. Dépendance envers le contexte d'exploitation

Les systèmes IBM et compatibles de type PC, XT, AT et PS peuvent être interfacés avec toute sorte de terminaux ou cartes d'extension. Un des interfaces les plus simples et les plus répandus est l'interface de liaison série sur lequel on peut notamment connecter un MINITEL.

Techniquement, la liaison est réalisée en reliant le MINITEL au PC via un cfble équipé coté MINITEL d'une fiche DIN 5 broches, coté PC d'une fiche CANON 9 ou 25 roches. L'interfaçage logiciel FORTH entre le PC et le MINITEL permettant d'exploiter cette liaison série, dépend de la primitive (RSEMIT) à définir:

HEX
: (RSEMIT) ( n ---)
03F8 PC! ;
\ 03F8 pour port COM1:   ;   02F8 pour port COM2:
DECIMAL

Cette primitive envoie au port série le code ASCII correspondant au paramètre empilé. On initialise le port COM1 ou COM2 en tapant la commande suivante:

" COM1:1200" PASS PROGRAM MODE.COM pour le port série COM1: " COM2:1200" PASS PROGRAM MODE.COM pour le port série COM2:

Le programme MODE.COM est fourni avec votre disquette système MSDOS. Si MODE.COM n'est pas dans le répertoire courant, indiquez le chemin o- il est accessible:

" COM1:1200" PASS PROGRAM C:\DOS\MODE.COM

Après initialisation du port série COM1: ou COM2:, on envoie un caractère vers le port série comme suit:

ASCII A (RSEMIT)

Si le MINITEL est raccordé au port série de votre PC et allumé, vous devez voir apparaître la lettre A sur l'écran du minitel. Le mot EMIT du langage FORTH est un mot d'exécution vectorisée, c'est à dire que l'on peut mofifier le contenu de sa zone paramétrique:

' (RSEMIT) IS EMIT

Tous les caractères normalement affichés sur l'écran du PC sont envoyés vers le port série et visualisés sur l'écran du MINITEL.Mais les caractéristiques de la transmission série ne permettent pas de traiter les codes ASCII à la même cadence que sur le terminal vidéo du PC. Il y aura saturation de la transmission si le débit des caractères est trop important. On y remédie en temporisant l'action de (RSEMIT):

 

HEX
: (RSEMIT) ( n ---)
03F8 PC!
\ 03F8 pour port COM1:; 02F8 pour port COM2:
100 MS ;
\ délai 100 millisecondes, ajuster éventuellement FUDJE
\ par n FUDGE !

DECIMAL
' (RSEMIT) IS EMIT

Maintenant, l'écran du MINITEL reproduit exactement les caractères ASCII du PC dont le code est situé dans l'intervalle 32..127. On peut définir une nouvelle primitive qui affichera les caractères simultanément sur le PC et le MINITEL:

HEX
: (RSEMIT) ( n ---)
DUP (EMIT) \ affichage sur écran vidéo PC
03F8 PC! \ 03F8 pour port COM1:; 02F8 pour port COM2:
100 MS ; \ délai 100 millisecondes, ajuster éventuellement FUDJE par n FUDGE ! DECIMAL
' (RSEMIT) IS EMIT

On peut poursuivre en faisant traduire les caractères du PC situés dans l'intervalle 128..255 par des caractères approchants quand c'est possible, dont voici la première ébauche:

HEX
: (RSEMIT) ( n ---)
DUP (EMIT) \ affichage sur écran vidéo PC
CASE
ASCII é OF ... ENDOF
ASCII è OF ... ENDOF
ASCII ê OF ... ENDOF ENDCASE
03F8 PC! \ 03F8 pour port COM1:; 02F8 pour port COM2:
100 MS ; \ délai 100 millisecondes, ajuster éventuellement FUDJE par n FUDGE ! DECIMAL
' (RSEMIT) IS EMIT

Les caractères accentués, exprimés par un code ASCII spécifique sur PC, sont traduits en une séquence de trois codes vers le MINITEL. Après achèvement de l'interfaçage logiciel, il reste à créer les définitions activant et désactivant cet interfaçage:

: RS-ON ( ---) \ activation de la liaison série
['] (RSEMIT) IS EMIT ;
: RS-OFF ( ---) \ désactivation de la liaison série
['] (EMIT) IS EMIT ;

Avec un interfaçage complet en entrée et en sortie, il est possible de développer une application tournant indifférement sur site PC ou à partir d'un terminal relié au site central via le port série. La modification d'un mot d'exécution vectorisée, EMIT dans notre exemple, peut s'appliquer à un programme déjà compilé.

H. Les vecteurs à choix multiples

Si vous avez été, ou êtes encore, un pratiquant assidu du langage BASIC, peut-être qu'une structure de la forme:

ON n GOSUB xxx1,xxx2,xxx3, etc...

vous manque. FORTH permet de définir un mot à l'aide de CASE: et dont le mécanisme est similaire. Alors que DEFER ne permet de définir qu'un seul mot avec un seul vecteur associé, CASE: définit un mot auquel on associe plusieurs vecteurs:

: MOT0 ... ;
: MOT1 ... ;
: MOT2 ... ;
3 CASE: MOTS ( n --- en exécution)
MOT0 MOT1 MOT2 ;

Les indices admis par MOTS sont situés dans l'intervalle [0..3[ (0 inclus à 3 exclus).

0 MOTS   exécute   MOT0
1 MOTS   excéute   MOT1
2 MOTS   exécute   MOT2

La sélection puis l'exécution d'un mot est réalisée par le paramètre empilé avant exécution du vecteur à choix multiple défini par CASE:. Si le paramètre est ors intervalle, un message d'erreur s'affiche lors de l'exécution du mot défini par CASE:. En principe, les mots compilés dans un vecteur à choix multiple ne peuvent être remplacés par d'autres mots.

On utilisera CASE: en remplacement de CASE.. OF.. ENDOF.. ENDCASE chaque fois que cette structure comporte un trop grand nombre de choix et que chaque choix peut être réduit à une définition séparée.

I. Définition de mots de définition

Comme on a pu le constater, Forth dispose de nombreux mots de définition.A chaque mot de définition correspond un type d'action: action deux-pooints, constante, variable, chaîne, etc...

Si la définition de procédures permet d'élaborer un code exéccutable exteêmement compact, Forth va plus loin en permettant aussi de définir de nouveaux mots de définition.Exemple:

: PAVE-GRIS ( ---)
  177 emit ;
: PAVE-BLANC ( ---)
  219 emit ;

 

Dans cest deux définition, la seule différence réside dans le paramêtre empilé avant l'action EMIT. Ec créant un nouveau mot de définition, PAVE par exemple, on pourra réduite le code exécutable:

le mot de définition PAVE fonctionne comme le mot CONSTANT: il prend le paramètre préalablement empilé et l'affecte à la zone paramétrique du mot dont l'entête est créé par CREATE. Une fois le mot créé, la partie de définition sityée ente DOES> et ; définit l'action à exécuter par le mot PAVE-GRIS ou PAVE-BLANC/

PAVE-GRIS affiche un caractère semi-graphique grisé.

l'actiojn de création paut être plus complexe, de même que l'action à exécuter. En reprenant l'exemple ci-dessus, on s'interdit de compiler un mot dont le code à affecter ne coresspondrait pas à un caractère semi-graphique:


177 PAVE PAVE-GRIS       compile PAVE-GRIS
155 PAVE PAVE-JAUNE   affiche "Caractère non semi-graphique"

Le mot de définition PAVE dispose maintenant d'une sécurité à la compilation. ll refuse de créer un mot si le paramètre qui doit lui être accecté dans sa zone paramétrique ne fait pas partie des valeurs contenues dans le tableau GRAPHISMES.

Pour compléter PAVE, on peut ausi rajouter une sécurité à l'exécution. On peut par exemple interdire l'affichage du pavé grisé sur les trous premières lignes de l'écran vidéo:


177 PAVE PAVE-GRIS
0 0 AT PAVE-GRIS   n'affiche rien
5 5 AT PAVE-GRIS   affiche un pavé gris

Lorsque le mot créé par un mot de définition est exécuté, il dépose sur la pile l'adresse de sa zone paramétrique. Cette action est similaire à celle exécutée par une variable définie par VARIABLE. Dans le cas des mots définis par PAVE, l'action définie après DOES> récupère la donnée stockée à cette adresse et affiche le caractère correspondant.

------------------------------------
--------------------------------
-----------------------------
------------------------
-------------

Pour les petits futés..... un test de mise au point.
(Bien entendu Bruno tu n'aura pas droit de poster ta réponse le premier car tu auras le texte avant les autres.)

Donc le premier qui donne le programme ci dessous fonctionnel aura son nom dans le générique du site.


soit à générer une suite de traits et de points correspondants au code Morse des caractères A..Z,0..9 et caractère espace:

DEFER .P \ définition du vecteur .P
DEFER .T \ définition du vecteur .T
: POINT ( ---) \ affiche un point
ASCII . EMIT ;
: TRAIT ( ---) \ affiche un trait
ASCII - EMIT ;
' POINT IS .P \ initialisation du vecteur .P
' TRAIT IS .T \ initialisation du vecteur .T
: .BLANC ( ---) \ espace en MORSE ;
...etc...
37 CASE: (.MORSE) ( n ---)
.BLANC .A .B .C .D .E .F .G .H .I .J . K .L .M .N .O .P .Q .R .S .T .U .V .W .X .Y .Z .0 .1 .2 .3 .4 .5 .6 .7 .8 .9 ;

 

Pour ceusses qui veulent en savoir un peu plus sur le morse
http://www.multimania.com/f5tci/

 

 

-- hautdepage -- page d'accueil --