En programmation, toute séquence d'instructions peut être rompue en exécutant un branchement ou une boucle. Le langage BASIC utilise les instructions GOTO ou GOSUB. En FORTH, GOTO est inconnu et GOSUB est implicite. Pour rompre le déroulement linéaire d'une séquence d'instructions, on utilisera des structures de contrôle dont le rôle est de compiler des branchements. Ces branchements sont de deux sortes:
-les branchements conditionnels
- les branchements inconditionnels
Une suite d'instructions sera réexécutée à l'aide d'une boucle. Celles-ci sont également de deux sortes:
-boucles itératives ou répétitives contrôlées par des index de début et de fin de boucle
-boucles indéfinies
Le langage FORTH exploite à travers différentes structures de base, toutes ces possibilités de branchement et de boucles.
Au cours du déroulement d'un programme, le résultat d'un test ou le contenu d'une variable peut être amené à modifier l'ordre d'exécution des instructions. Cette valeur, nommée flag booléen, est à l'état vrai si elle est non nulle, à l'état faux si elle est nulle. Le flag booléen est utilisé par une instruction de branchement marquant le début d'une structure de contrôle:
IF ... THEN ou
IF ... ELSE ... THEN
Le mot IF est un mot d'exécution immédiate et compile un branchement conditionnel. Il n'est utilisable qu'en compilation. Exemple:
et en exécution:
15 CHALEUR ! METEO n'affiche rien
35 CHALEUR ! METEO affiche "Il risque d'y avoir de l'orage"
Le mot METEO teste le contenu de la variable CHALEUR et exécute la partie de définition comprise entre IF et THEN si cette valeur est supérieure à 25. Mais s'il fait 25 degrés ou moins, le mot METEO n'annonce rien.
Pour y remédier, on peut le redéfinir:
Maintenant:
15 CHALEUR ! METEO2
affiche Le temps se rafraîchit
Si le résultat du test exécuté avant IF délivre un flag booléen faux, c'est la partie de définition située entre ELSE et THEN qui sera exécutée.
Un flag booléen peut être le résultat de diverses opérations:
-lecture d'une adresse mémoire,
-empilage du contenu d'un registre en sortie d'exécution d'une définition écrite en code machine,
-résultat d'un calcul arithmétique 16 ou 32 bits, signé ou non,
-résultat d'une opération logique (OR, AND, NOT, XOR) ou d'une combinaison d'opérations logiques,
-paramètre empilé par l'exécution d'une définition exécutée avant IF,
Le mot IF teste et consomme la valeur située au sommet de la pile de données. Voici un autre exemple affichant si un nombre est pair ou non:
Pour les gratouilleurs d'espace mémoire, voici une définition équivalente mais plus compacte:
Avec la structure de type IF.. THEN et IF.. ELSE.. THEN, on ne peut exécuter qu'une partie de définition non répétitive. Pour réitérer une séquence de type faire.. tant-que, il faut exploiter un nouveau type de structure de contrôle: la boucle répétitive indéfinie BEGIN.. UNTIL.
Dans une boucle BEGIN.. UNTIL, la partie de définition située entre ces deux mots est répétée tant que le résultat du test précédant UNTIL délivre un flag booléen faux. Exemple:
L'exécution de DACTYLO affiche tous les caractères tapés au clavier. Seul l'appui sur la touche marquée du signe '$' peut interrompre la répétition. L'appui sur la touche <return> renvoie en début de ligne. Pour faire passer le curseur à la ligne suivante, il faut redéfinir DACTYLO:
Maintenant, l'appui sur <return> renvoie bien en début de ligne suivante. Notez que la structure IF.. ELSE.. THEN est imbriquée dans la structure BEGIN.. UNTIL. C'est ça, la programmation structurée. Il est impossible de définir une structure de la manière suivante:
BEGIN.. <test>
IF.. <test>
UNTIL
THEN
Si le résultat du test précédant UNTIL est toujours faux, on ne peut plus sortir de la boucle BEGIN.. UNTIL. Cette situation a été prévue en FORTH et est exploitée par la boucle BEGIN.. AGAIN. L'utilisation de AGAIN équivaut à BEGIN ... 0 UNTIL. Si on définit DACTYLO par:
On ne pourra plus interrompre la boucle lors de son exécution. Le seul moyen pour s'en sortir sera de taper sur CONTROL C, ou d'interrompre l'alimentation électrique du système.
Avec une boucle BEGIN.. UNTIL ou BEGIN.. AGAIN, l'action est répétée en fin de boucle en fonction du résultat d'un test ou de manière inconditionnelle. Mais on peut exploiter un branchement avant conditionnel depuis une boucle dont la structure est BEGIN.. WHILE.. REPEAT.
Dans cette structure, le test est exécuté avant WHILE. Si le résultat est faux, l'exécution se poursuit après REPEAT. Si le résultat est vrai, la partie de définition comprise entre WHILE et REPEAT est exécutée, puis REPEAT effectue un branchement arrière inconditionnel, c'est à dire renvoie l'exécution à BEGIN.
Pour exemple, réécrivons DACTYLO avec cette nouvelle structure:
Par rapport à notre première définition de DACTYLO avec BEGIN.. UNTIL, cette version diffère par un détail: voyez- vous lequel?
Le dernier cas de figure des diverses structures de contrôle disponibles en FORTH 83-Standard est la boucle DO.. LOOP. Cette structure admet comme paramètres d'entrée deux valeurs qui sont les index initiaux et terminaux contrôlant l'itération.
Exemple:
C'est l'exemple classique du test de performance d'une répétition plus connu en BASIC:
FOR N=0 TO 10000:NEXT
mais s'exécutant incomparablement plus vite en FORTH. Le mot DO, utilisable seulement en compilation, est toujours précédé de deux valeurs n1 n2, où n2 est l'index initial de la boucle, n1 la valeur terminale. La valeur terminale est en général supérieure à la valeur initiale. Exemple:
\ le caractère entre DO et EMIT
\ est un i majuscule
affiche tous les caractères ASCII situés entre 32 et 255. Dans cette définition, le mot I dépose sur la pile la valeur de l'index courant de la boucle. L'index prend successivement toutes les valeurs comprises entre 32 et 256, 256 non comprise. En effet, l'incrémentation et le test de sortie de boucle sont exécutés par LOOP.
Pour incrémenter l'index de boucle d'une quantité différente de une unité, il faut remplacer le mot LOOP par +LOOP et le faire précéder de la valeur de l'incrément de boucle. Exemple:
3 TABLE ! AFFICHE-TABLE
affiche 3 6 9 12 15 ... 30
7 TABLE ! AFFICHE-TABLE
affiche 7 14 21 28 .... 70
L'incrément d'index de boucle située avant +LOOP peut être négatif. Dans ce cas, la première valeur placée avant DO est inférieure à la seconde. Rien ne nous interdit de ré-utiliser AFFICHE-TABLE dans une définition plus générale qui va nous afficher une véritable table de multiplication:
Ne soyez pas étonné par la réutilisation du mot I, déjà exploité dans la définition de AFFICHE-TABLE. L'exécution de I ne fait référence qu'à la boucle dans laquelle il est défini et en cours d'exécution. Par contre, dans le cas de deux boucles imbriquées, pour accéder depuis la boucle imbriquée à l'index de la boucle extérieure, il faut utiliser le mot J. Exemple:
Pour interrompre le déroulement d'une boucle de type DO.. LOOP ou DO.. +LOOP, il faut exécuter le mot LEAVE. Exemple:
Le mot TEMPO-ARRET génère un temps d'arrêt d'environ 100 secondes. Si l'utilisateur enfonce une touche du clavier avant ce délai, la boucle est interrompue et le programme poursuit son exécution. Le mot MS utilisé dans la définition de TEMPO-ARRET provoque une temporisation de n millisecondes. La temporisation peut-être ajustée par modification de la variable FUDGE.
Dans certaines situations, on peut être amené à exécuter une action spécifique au programme en fonction d'une condition précise, parmi d'autres actions également dépendantes de cette condition. La structure de contrôle la plus fréquemment utilisée dans ce cas est la structure de type CASE.. OF.. ENDOF.. ENDCASE. Syntaxe:
CASE
valeur1 OF action1 ENDOF
valeur2 OF action2 ENDOF
...
valeurN OF actionN ENDOF
ENDCASE
La valeur à tester est placée devant le mot OF. Si la valeur figurant au sommet de la pile avant l'exécution de CASE est identique à celle-ci, la partie de définition située entre OF et ENDOF est exécutée, puis l'exécution se poursuit après ENDCASE. Dans le cas contraire, le test ou les tests suivants sont exécutés jusqu'à validité d'un test. Si aucun test n'a pu être vérifié, la partie de définition située le cas échéant entre le dernier ENDOF et ENDCASE est exécutée. Exemple:
Exemples d'exécution:
2 JOUR TYPE affiche MARDI
5 JOUR TYPE affiche VENDREDI
7 JOUR TYPE affiche DIMANCHE
Les puristes affirment qu'un langage informatique est incomplet s'il ne peut traiter la récursivité. D'autres prétendent que l'on peut très bien s'en passer. FORTH va enthousiasmer les premiers, car il est équipé pour traiter ce type de situation.
Comme FORTH ne peut faire explicitement référence au mot en cours de définition, on insérera le mot RECURSE partout o- l'on voudra faire appel à la définition en cours de compilation. Exemple:
La décompilation de FACTORIELLE, exécutée en tapant SEE FACTORIELLE, met en évidence la substitution de RECURSE par FACTORIELLE. Exemples d'exécution de FACTORIELLE:
2 FACTORIELLE . affiche 2
3 FACTORIELLE . affiche 6
4 FACTORIELLE . affiche 24
La récursivité a ses limites: la capacité des piles de données et de retour. Une récursivité mal contrôlée sature la pile de données ou de retour et bloque le système.
Les tests peuvent porter sur des comparaisons de grandeurs numériques au format simple précision (16 bits) ou double précision (32 bits) ou sur des valeurs logiques (flags booléens). Le résultat d'un test est toujours un flag booléen, représenté par un entier 16 bits:
0 pour faux
-1 pour vrai
Un test de comparaison agit de manière identique à un opérateur arithmétique. Ce sont des opérateurs dyadiques:
= < > <= >= <>
U< U> U>= U<=
D= D> D<
DU<testent des entiers 16 bits signés
testent des entiers 16 bits non signés
testent des entiers 32 bits signés
teste deux entiers 32 bits non signés
Exemples:
2 5 = . affiche 0
3 8 < . affiche -1
Les tests de comparaison par rapport à zéro sont déjà définis. Ce sont des opérateurs monadiques:
0= 0< 0> 0<> 0<= 0>=
D0=testent un entier 16 bits signé par rapport à zéro.
teste un entier 32 bits signé par rapport à zéro.
Exemple:
12 0> . affiche -1
Les résultats de ces tests peuvent être combinés en une seule expression à l'aide des opérateurs logiques suivants:
OR AND XOR combinent deux valeurs logiques
NOT inverse l'état d'une valeur logique
Les opérateurs logiques agissent bit à bit sur deux valeurs 16 bits non signés, ce qui permet de les utiliser de manière identique aux fonctions logiques du micro-processeur.
Les constantes prédéfinies TRUE et FALSE, délivrent respectivement un flag booléen vrai et un flag booléen faux:
TRUE . affiche -1
FALSE . affiche 0
-- hautdepage -- page d'accueil --