Forth Interpreteur/Compilateur

English Version



Un manuel complet d'utilisation Manuel du FORTH PDF
Version LibreOffice modifiable Je veux le traduire!

Il s'agit d'un Éditeur, Interpréteur et Compilateur FORTH pour ATARI sous TOS.
  • Versions 68030 (Falcon, TT) et 68000 (STe)
  • Versions française et anglaise
  • Support de la ST et TT Ram
  • Support du FPU, mais travaille également sans.
  • Fonctions Gemdos, Bios, Xbios, VDI, AES
  • Support du Supercharger en coprocesseur
  • Support d'un assembleur extérieur
  • Support des modules M&E de PARX (gestion d'images)
  • Création aisée de menus ou dialogues directement en FORTH
  • Programme compact et rapide, entièrement écrit en assembleur


Version 0.3.2 (25/04/2022):
  • Gestion des modules M&E (charger/sauver des images + effets)
  • réglage automatique du module TRM 2.52
  • Fichier AUTOEXEC.FOR
  • quelques bugs corrigés
Un langage interactif:

Le langage permet une utilisation en mode direct, à la manière d'une calculatrice, mais dans lequel on peut créer de nouveaux mots afin d'enrichir les possibilités.

Ci-contre, imaginons qu'on veuille réduire une série de prix de 20%, on en calcule à chaque fois 80%. Le premier exemple donne le nouveau prix pour un article de 59€: c'est 47€.
Vous remarquez qu'on empile d'abord les valeurs avant d'opérer dessus, le "." sert à afficher le sommet de la pile. Pour éviter de retaper les calculs, on crée le mot reduc avec la paire : ; et on l'utilise sur un prix de 70€ réduit à 56€.
On peut également taper un petit programme avec ici la stucture list..dolist..lloop qui crée une boucle à partir d'une liste hétéroclite de valeurs.
Dans la boucle on affiche l'indice i (prix de départ) puis un espace puis le prix réduit.

system permet de quitter l'interpréteur.

Utilisation en mode direct



Codage d'un message avec une seule variable!
Un programme de codage de message

Écrivons pas à pas un programme sous GEM avec menu pour coder ou décoder un message. Allons d'abord au coeur du sujet...

Nous allons coder un mot qui permet de réaliser un décalage quelconque dans l'alphabet sur un message en majuscules. Pour cela, une seule variable: p qui pointera sur les caractères successifs de la chaîne passée sur la pile.

  • p ! : stocke dans p l'adresse de la chaine
  • .b size : on va travailler sur des bytes
  • begin/while/repeat : pour parcourir la chaine
  • p )@ : ramène l'octet pointé par p
  • while : tant qu'il est différent de zéro
  • dup 65 90 <seg> if : teste si on est entre A et Z
  • over + : dans ce cas ajoute le décalage (relatif)
  • dup 90 > if : si au dela de Z revient dans l'alphabet
  • dup 65 < if : si en dessous de A, remonte dans l'alphabet
  • p )+! : stocke à nouveau l'octet, éventuellement modifié, et incrémente le pointeur
  • drop : retire la valeur n de la pile


Utilisons notre mot

Pour cela, on va passer par la chaine prédéfinie pad qui sert au forth pour certains résultats d'opérations de chaines.

  • On stocke dans pad la chaine "UN TEXTE SECRET !"
  • On réalise un décalage de 17 dans l'alphabet avec 17 pad code
  • pad type affiche la chaîne codée
Pour décoder le message, on utiliserait -17 pad code, mais...

Pour décoder un message sans la clé, on peut lui faire subir les 25 décalages possibles: c'est ce que fait la boucle 25 ndo..nloop suivante.
  • 1 pad code permet de réaliser un nouveau décalage
  • pad type cr affiche la chaîne et saute une ligne
Vous voyez le message apparaître en clair (je n'ai recopié qu'une partie des 25 lignes).




Version utilisable dans un programme.
Codage avec prompt

Nous allons enrober le mot code afin qu'il demande clairement les informations à l'utilisateur et affiche le résultat. C'est ce que fait le mot code-decode.
  • 15 >ifflag : permet une compilation conditionnelle, le flag 15 étant celui de la langue, vrai dans la version française et faux dans la version anglaise.
  • ." Clé : " input cr affiche clé et attend une valeur laissée sur la pile, puis saut de ligne
  • ." Texte : " input$ cr idem mais avec une chaine stockée dans pad
  • code réalise le codage demandé
  • pad type cr affiche finalement le message modifié


La recherche brute

De même, implémentons la recherche brute des 25 décalages si un message est fourni sans sa clé, c'est le mot multi-decode.
  • ." Texte : " input$ cr drop , cette fois-ci l'adresse pad est enlevée de la pile par drop car non utilisée directement.
  • 26 1 do..loop bouclera avec i=1 à i=25 (s'arrête avant 26!)
  • i . space affiche l'indice et un espace
  • 1 pad code décale pad de un dans l'alphabet
  • pad type cr et l'affiche avec un saut de ligne




Créons le menu !

Pour créer ce petit menu, point n'est besoin de passer par un fichier RSC. Le Forth s'occupe de tout à partir d'un tableau de chaînes.
  • 30 10 array$ MENU crée un tableau de 10 chaînes de 30 caractères appelé MENU
  • 16 allot constant BUFFER alloue 16 octets pour le buffer de l'AES (appel evnt_mesag)
  • On remplit ensuite le tableau MENU
  • d'abord les titres puis une chaine vide
  • pour chaque titre son drop-down et une chaine vide
  • 0 MENU menu, l'instruction menu crée l'arbre d'objets en mémoire en tenant compte des accessoires et renvoie l'adresse qu'on conserve dans TREE
  • 7 gemindex 0 TREE menu_ienable sert à griser le séparateur (chaine 7)


Un dernier effort

Un petit mot pour réagir à l'entrée Infos... du menu.

Ce sera une simple boîte d'alerte.




La boucle principale!

Voici une boucle classique de gestion d'événements AES.
  • fastopen drop cls ouvre la fenêtre Forth, jette son handle et efface l'écran
  • 1 TREE menu_bar affiche la barre de menu
  • begin...until boucle jusqu'à ce qu'une valeur non nulle soit renvoyée (par Exit)
  • begin...until va attendre l'arrivée d'un message
  • BUFFER evnt_mesag appelle l'AES et attend un événement
  • BUFFER w@ 10 = le premier mot du buffer est-il 10? (menu selected)
  • BUFFER 8 + w@ ramène l'index GEM de l'entrée du menu
  • strindex convertit cette valeur en numéro de chaîne pour que je m'y retrouve
  • case...endcase traite les 4 cas possibles, seul Exit renvoie 1 pour sortir
  • BUFFER 6 + w@ renvoie l'index GEM de l'entrée du menu passée en vidéo inverse
  • 1 TREE menu_tnormal et remet le menu en vidéo normale
  • 0 TREE menu_bar en quittant, efface la barre de menu.


Lancement automatique ou non

Je veux que sous l'interpréteur, la compilation du source ne lance pas l'exécution du programme afin de garder la main en mode interactif et de tester chaque partie indépendemment.

Par contre, lorsque j'utilise le compilateur externe pour générer un programme indépendant et débuggé, il faut que la procédure se lance.

On utilise à nouveau une compilation conditionnelle avec le flag 13 qui est vrai sous l'interpréteur et faux sous le compilateur.
Note: par défaut, le programme compilé efface la souris, donc on a ajouté v_show_c pour qu'elle revienne.




Codage d'un message puis décodage brut
Notre programme en action !

Le programme se lance, affiche son menu et sa fenêtre.

Il ne vous reste plus qu'à utiliser les différentes entrées pour le tester.

Vue partielle du décodage brut, on retrouve notre message


Téléchargements

FORTH: Interpréteur et compilateur français et anglais.
Versions 68030 et 68000, exécutables et sources.

PARX M&E modules de gestion d'images.
avec l'aimable autorisation de Pierre-Louis Lamballais
et d'Eric Da Cunha.


Codage: source et éxécutable français et anglais du programme présenté ici.




Autres exemples de programmes en FORTH

Lien avec la HP-41 et son interface série
Menu, communication série

Utilisation des instructions pour piloter le Supercharger comme un coprocesseur.
Inclusion assembleur PC, instructions Supercharger

Sauvegarde et restauration des données de la BOSS-DR5 via MIDI.
Menu, fichiers, communication MIDI

Gestion de l'horloge RTC de l'Apollo Vampire V4.
Inclusion assembleur, création dialogue, dialogue en fenêtre




Inclure de l'assembleur

On peut vouloir remplacer le mot code par une routine assembleur. Ceci est très simple:
  • On prépare une routine commençant par le mot 437 sur 16 bits. Ce mot indique au Forth que c'est une routine assembleur.
  • La zone DATA doit commencer par le marqueur "ADD_DEFS" sur 8 octets
  • Chaque routine est ensuite listée, -1 servant de marqueur de fin
  • Chaque nom de mot est ensuite ajouté avec un zéro de séparation
  • On assemble ce source vers F:\_TEMP.PRG" par exemple
  • A la place de la définition de code, on ajoute
  • Votre routine doit simplement préserver a4 et a5 et utiliser a6 comme pointeur de pile


Encore mieux: tout dans un seul source!

Le texte en assembleur ainsi que la génération du PRG à inclure peuvent être pilotés directement depuis le FORTH. Voici comment:
  • Dans votre listing Forth, la directive >export (1) sauve le texte jusqu'à la directive >comp (2) sous le nom fourni: ici F:\_TEMP.S.
  • Ensuite, la directive >exec (3) permet de lancer l'assembleur avec la ligne suivante comme argument.
  • Pour finir, le PRG étant disponible, il est inclus avec la directive >include (4).

Lors de la compilation, vous verrez l'activité de votre assembleur:


Note: vous remarquez un argument 0 pour ces directives, il peut être utilisé en liaison avec un Flag afin d'exécuter ou d'ignorer ces ordres. Par exemple, si vous ne travaillez que sur la partie Forth, il est inutile de resauver et générer le PRG de la partie assembleur à chaque compilation.




Les modules M&E de Parx Systems: lecture d'une image GIF

Dans ce programme, nous allons charger une image GIF avec le module GIF00.RIM et l'adapter à l'écran avec le module PARX252.TRM pour l'afficher quelque soit la résolution.

Définition des variables
variable p       \ le module RIM
variable t       \ le TRM
variable fichier \ adresse du fichier
variable total   \ taille totale fichier
256 string filename		  \ chemin+nom du fichier
1536 allot constant PALs  \ palette source
1536 allot constant PALd  \ palette destination
variable fhd
Chaque module sera pointé par une variable.

Les palettes sont à leur taille maximale pour recevoir 256 couleurs au format VDI:
256 couleurs × 3 composantes × un mot de 2 octets (0 à 1000) = 1536.
Chargement des modules
: main
   " d:\parx.sys\" 1 modset

   0 t !
   " parx252.trm" graphic_card negate t modload drop

   0 p !
   " rim\gif00.rim" -1 p modload drop
  • modset: fixe le chemin du dossier PARX
  • modload: charge le module de tramage PARX252.TRM
    graphic_card negate permet d'adapter le module à n'importe quelle carte graphique
  • modload: charge le module de lecture GIF00.RIM
Lecture et décompression du GIF
   " F:\FORTH\GIPHY.GIF" filename $!

   filename 0 fopensize dup fhd !
   0> if
      total !
      fhd @ total @ dup allot dup fichier ! fread drop
      fichier @ total @ filename fhd @ PALs 1 p dorim drop
  • fopensize : ouvre le fichier GIPHY.GIF
  • fread : si l'ouverture est ok, lit entièrement le fichier en RAM
  • dorim : lance le RIM pour la décompression

L'image en 16 bits
Tramage écran
      mfdbs mfdbd fillmfdb
      work_out 2- w@ mfdbd 12 + w!
      %b1100110 1 PALs PALd 3 t dotrm drop
  • mfdbs/d : sont des descripteurs de blocs d'image utilisés par les modules
  • fillmfdb : duplique le descripteur de notre image source vers destination
  • work_out 2- w@ : nombre de plans de l'écran stocké en destination
  • dotrm : lance le tramage pour modifier le nombre de plans et l'adapter à l'écran
Copie vers l'écran
      mfdbd mfdbs fillmfdb
      PALs savevdipal
      PALd setvdipal
      0 mfdbd ! 0 0 0 0
      mfdbs 4 + w@ mfdbs 6 + w@ 3 vro_cpyfm
      key drop
      fhd @ fclose drop
      PALs setvdipal
   then
   p modunload
   t modunload
;
  • fillmfdb : reprend la destination comme étant la nouvelle source
  • savevdipal : copie la palette courante dans PALs
  • setvdipal : fixe la palette sur celle de la destination
  • 0 mdfdb ! : l'écran devient la nouvelle destination
  • vro_cpyfm : copie mon image à l'écran
  • key : attend une touche
  • fclose : referme le fichier
  • setvdipal : remet la palette courante
  • modunload : libère les modules

L'image en 4 bits avec le même programme
Pour un programme compilé
>comp

-13 >ifflag
   fastopen drop
   main
>endf
  • >ifflag : compilation conditionnelle, sautée par l'interpréteur (flag 13 pour la différence interpréteur, programme indépendant)
  • fastopen : ouvre la fenêtre FORTH
  • main : appelle notre programme

L'image en monochrome avec le même programme



Les modules M&E de Parx Systems: visualiseur d'image quelconque

Ce programme se propose de charger l'ensemble des modules RIM dans un tableau de modules afin de pouvoir lire n'importe quelle image et de l'afficher sur l'écran quelque soit sa résolution.
Ce programme reprend en grande partie le précédent, nous détaillerons les différences pour l'utilisation du tableau de modules.

Définition des variables
variable t       \ le TRM
variable fichier \ adresse du fichier
variable total   \ taille totale fichier
256 string filename
256 string chemin
32 string nom
1536 allot constant PALs
1536 allot constant PALd
20 allot constant MFDB
variable fhd
100 array MODS
variable nMODS
  • chemin/nom : deux chaines s'ajoutent pour le sélecteur de fichier
  • MODS : tableau de 100 valeurs pour pointer sur les modules
  • nMODS : contiendra le nombre total de modules chargés
Choix de l'image
: main
   cls
   " \*.*" chemin $!
   " " nom $!
   chemin nom fsel_input
   chemin nom path filename $!
   cls
  • $! : stocke dans mes chaînes un chemin par défaut
  • fsel_input : ouvre le sélecteur de fichiers
  • path : concatène le chemin et le nom pour l'accès complet
  • cls : efface la fenêtre

Le fichier sélectionné
Chargement des modules
   " d:\parx.sys\" 1 modset

   ." Charment des modules..." cr

   0 t !
   ( " parx252.trm" graphic_card negate t )
      modload drop

   0 0 MODS !
   ( " rim\*.rim" -1 0 MODS )
      modmload .. nMODS !

   ."  modules chargés" cr
  • modmload : mod multi load charge tous les *.rim dans le tableau
  • nMODS : variable recevant en retour le nombre de modules chargés
Chargement de l'image
   ." Chargement du fichier..." cr

   filename 0 fopensize dup fhd !
   0> if
      total !
      ( fhd @ total @ dup allot dup fichier ! )
         fread drop
Même système qu'avant, charge l'image en entier en mémoire.
Recherche du bon WIM
      nMODS @ 0 do
         -1 mfdbs fillmfdb
         ( fichier @ total @ filename fhd @ PALs 1 i MODS )
            dorim
         0<
      ifloop
  • do : boucle de 0 à nMODS-1 pour parcourir tous les modules
  • dorim : teste le module i
  • ifloop : continue la boucle tant qu'il y a erreur (valeur négative)
  • ifloop : sinon dépose sur la pile l'indice de sortie
Résultat de la recherche
      dup nMODS @ =
      if
         drop
         ." Image non reconnue" cr
      else
         MODS modlname type cr
         key drop
  • dup nMODS @ = : compare l'indice de sortie à nMODS
  • si égal : aucun module n'a fonctionné, on le signale
  • sinon : affiche le nom long du module
  • key : attend une touche

Modules chargés et celui qui a détecté l'image
Décodage et affichage
         mfdbs mfdbd fillmfdb

         work_out 2- w@ mfdbd 12 + w!

         ( %b1100110 1 PALs PALd 3 t )
            dotrm drop

         mfdbd mfdbs fillmfdb

         PALs savevdipal
         PALd setvdipal

         ( 0 mfdbd ! 0 0 0 0
         mfdbs 4 + w@ mfdbs 6 + w@ 3 )
            vro_cpyfm
            key drop
         PALs setvdipal
      then
      fhd @ fclose drop
   then
   0 MODS nMODS @ modmunload
   t modunload
;

>comp

-13 >ifflag
   fastopen drop
   main
>endf
Ici la fin du programme est identique au précédent.

On appelle le TRM pour s'adapter à l'écran.

On affiche le bloc avec vro_cpyfm.

modmunload : mod multi unload libère tous les modules du tableau.

L'image TIF affichée en 16 bits



Les modules M&E de Parx Systems: Sauvegarde d'un bloc en TGA

Ce programme copie un bloc d'écran de 320x200 dans la résolution courante et le sauvegarde vers un image TGA 16 bits.

Définition des variables
variable p       \ le module WIM
variable t       \ le TRM
1536 allot constant PALs  \ la palette source (si besoin)
1536 allot constant PALd  \ la palette destination (inutilisée en 16 bits)
Définition classique des variable, comme dans les deux précédents programmes.

Chaque module est pointé par une variable, les palettes sont réservées au maximum de leurs capacités.
Chargement des modules
: main
   absolute
   " d:\parx.sys\" 1 modset

   ." Chargement des modules..." cr

   0 t !
   " parx252.trm" graphic_card negate t modload
   if exit else ."    TRM Ok" cr then

   0 p !
   " wim\tga_tc16.wim" 1 p modload
   if exit else ."    WIM Ok" cr then
   
   remember
  • absolute : passe le VDI en mode absolu (relatif au début de l'écran)
  • exit : les fonctions modload renvoient une valeur différente de zéro si elles échouent, dans ce cas, exit quitte le mot
  • graphic_card : toujours cette indication pour permettre le bon réglage du TRM
  • tga_tc16.wim : le module de sauvegarde en TGA 16 bits
  • remember : conserve le pointeur mémoire FORTH pour vider tous les blocs à la fin
Copie d'un bloc écran


   ." Bloc 320x200 avec palette" cr
   0 mfdbs !
   0 320 200 work_out 2- w@ 0 mfdbd fillmfdb
   mfdbd imagesize allot mfdbd !
   0 0 0 0 320 200 3 vro_cpyfm
   PALs savevdipal
   mfdbd mfdbs fillmfdb
  • 0 mfdbs ! : la source est l'écran
  • fillmdfb : prépare la destination en 320x200
  • imagesize : calcule la taille de l'image pour réserver le bloc avec allot
  • vro_cpyfm : copie le coin haut-gauche de l'écran vers la mémoire
  • savevdipal : sauvegarde la palette actuelle
  • fillmfdb : remet le bloc destination comme nouvelle source pour la suite

Ce que donne le programme à l'exécution
En cas de carte graphique
   ( graphic_card
   work_out 2- w@ 4 8 <seg> ) and
   if
      ." Passage en mode VDI..." cr
      1 mfdbd 10 + w!
      mfdbd imagesize allot mfdbd !
      vr_trnfm
      mfdbd mfdbs fillmfdb
   then
Si on se trouve sur une carte graphique dans un mode 4 ou 8 plans, il faut ramener notre bloc vers le format indépendant VDI, le TRM n'a pas les routines pour.

Dans les modes TC (15, 16, 24 et 32 bits) il gère parfaitement l'encodage.
  • 1 mfdbd 10 + w! : modifie le format destination vers VDI
  • imagesize : recalcule la taille pour un nouveau bloc
  • vr_trnfm : transforme le bloc
  • fillmfdb : remet le bloc destination comme nouvelle source pour la suite
Passage du bloc en 16 bits
   ." Transformation en 16 bits..." cr
   16 mfdbd 12 + w!
   %b0100011 1 PALs PALd 3 t dotrm
   if exit else ."    Dotrm Ok" cr then

   mfdbd mfdbs fillmfdb
  • 16 mfdbd 12 + w! : force à 16 le nombre de plans de la destination
  • dotrm : appelle le TRM pour transformer le bloc
  • fillmfdb : remet le bloc destination comme nouvelle source pour la suite

L'image sauvée à partir d'un mode TC (affichée par GemView)
Sauvegarde de l'image en 16 bits
   ." Sauvegarde en TGA 16 bits..." cr
   " I:\AAA.TGA" PALd 1 p dowim
   if exit else ."    Dowim Ok" cr then
Il ne reste plus qu'à appeler le WIM, notre bloc écran, quelque soit sa résolution d'origine, sera enregistré au format TGA 16 bits.
  • dowim : lance le WIM pour sauver l'image

L'image sauvée en TT Moyenne (affichée par GemView)
Nettoyage de la mémoire
   restore
   t modunload
   p modunload
   relative
;
  • restore : remet la mémoire FORTH dans l'état de l'appel de remember
  • modunload : libère les modules
  • relative : revient aux appels VDI relatifs à la fenêtre FORTH
15 décembre 2007