# Forth/Conserver des données

N'importe quel programme a besoin de conserver des informations en mémoire. Un jeu vidéo, par exemple, a besoin à tout moment de pouvoir accéder à des données telles que la vie, la force ou la position d'un personnage. De telles données sont appelées des variables : les valeurs sont entreposées à un certain emplacement dans la mémoire, emplacement qu'on pourra lire (accéder à une variable) ou sur lequel on pourra écrire (modifier une variable).

## En bricolant nous-mêmes

Manipuler la mémoire est une opération triviale en Forth. Pour l’heure, la mémoire que nous allons être ammenés à manipuler est celle du dictionnaire, c'est-à-dire l'espace où nos mots sont conservés sous forme compilée (ce n'est donc absolument pas au même endroit que la pile).

### DP, @ et !

Un mot permet d'obtenir l'adresse du prochain emplacement libre dans le dictionnaire ; c’est à cet emplacement que nous stockerons nos données. Ce mot est HERE (ici). Un appel à HERE place donc une adresse sur la pile :
Cette adresse est libre. Ça ne signifie pas qu’il n'y a rien d'écrit à cet emplacement, mais plutôt que ce qui est écrit n'a pas d'importance et n’est pas défini. Vous savez désormais que le dictionnaire se remplit au fur et à mesure qu'on y ajoute des définitions, par conséquent la valeur que nous donne HERE est loin d’être constante : à chaque fois qu'on crée un mot ou une variable, on progresse dans la mémoire :
Que se passe-t-il ici ?
* on pose l'adresse du prochain espace libre du dictionnaire sur la pile ;
* on défini un nouveau mot, donc on repousse l'adresse du prochain espace libre ;
* on soustrait l'ancienne adresse à l'actuelle, et on s'aperçoit que HERE pointe 28 octets plus loin dans la mémoire : notre mot TEST a occupé 28 octets du dictionnaire.
Et si on regardait la définition de HERE ?
Que peut bien signifier DP @ ? C'est très simple :

#### DP ( -- addr )

    Empile l'adresse qui contient l'adresse du prochain emplacement libre du dictionnaire.

#### @ ( addr -- value )

    fetch lit la valeur « value » située à addr, et la pose sur la pile.
D'où :

#### HERE ( -- addr )

    Empile l'adresse du prochain espace libre du dictionnaire.
Il est maintenant important de saisir une nuance :
* HERE récupère une valeur (l'adresse du prochain espace libre) à une adresse donnée, et la pose sur la pile ;
* DP donne cette adresse.
« DP » signifie Dictionnary Pointer, le « pointeur du dictionnaire », parce qu’il pointe sur un emplacement du dictionnaire.
Bien que répandu, ce mot n'est pas standard et il est tout à fait possible que DP porte un autre nom si vous n'utilisez pas GForth. Pour le connaître, utilisez SEE s'il est disponible ou alors référez-vous au manuel de votre système.
Nous savons désormais lire des informations grâce à @ (fetch). Étudions maintenant le mot qui nous permet d'écrire de l'information :

#### ! ( value addr -- )

    Store place value à l'adresse addr.
Rien de bien compliqué :
Il est toutefois nécessaire d’être prudent lorsqu'on utilise ! (store), il ne vérifie parfois pas la validité de l'adresse, auquel cas vous pourriez par mégarde écraser des données importantes pour le système.
Amusons-nous à éditer DP :
Voilà, DP pointe désormais vers l'adresse 0. Comme un certain nombre de mots se basent sur HERE pour fonctionner, cette petite fantaisie risque bien de paralyser rapidement le système Forth. Ne faites donc pas n’importe quoi avec store !

### CREATE

Cette section est difficile à comprendre. Même si elle ne fait intervenir que des notions du niveau indiqué, il est conseillé d'avoir du recul sur les notions présentées pour bien assimiler ce qui suit.
En Forth, une variable est un mot qui pointe vers un endroit en mémoire : sa valeur. DP est donc une variable :
* de nom DP ;
* qui vaut DP @, la prochaine adresse libre du dictionnaire.
Vous savez placer une information en mémoire, mais vous ne savez pas associer cet espace à un nom ; c’est le travail du mot CREATE :

#### CREATE ( "<spaces>name" -- )

    Prépare le terrain pour l'affectation. Associe name au prochain emplacement libre dans la mémoire.
Un exemple pour mieux comprendre :
TROIS permet donc de récupérer une adresse bien précise, celle qui suivait la sienne propre lors de sa création via CREATE. Définissons une autre variable :
Aïe, en définissant DEUX (qui vient se placer sur HERE) on a écrasé la valeur vers laquelle pointait QUATRE ; désormais QUATRE pointe sur l'adresse de DEUX ! Afin d’éviter cela, il suffit d'avancer DP en conséquence :
Normalement, +! (plus-store) doit vous déconcerter. Il signifie « stocker en additionnant » :

#### +! ( value addr -- )

    Ajoute value à la valeur contenue en addr.
C'est donc un raccourci pour TUCK @ + SWAP !.

#### ? ( addr -- )

    What imprime en sortie la valeur contenue en addr.
C'est donc un raccourci (non standard, mais généralement défini) pour @ . (fetch dot) ; je l’utiliserai régulièrement.
Et si on automatisait tout cela ? Définissons le mot VAR, qui crée une variable et l'initialise avec une valeur donnée :
Pas mal, n'est-ce pas ? Mais il est clair que tout ces préparatifs sont franchement agaçants pour une opération aussi triviale que la définition d'une variable. Comparez avec un code Perl :
Y'a pas photo, c’est beaucoup plus simple que de réécrire VAR dans chacun de nos programmes. Heureusement, la norme impose aux systèmes Forth un ensemble de mots très pratiques pour créer des variables, et même plus.

## En Forth standard

Reprenons notre définition du mot VAR :

### Allouer de la mémoire

Lorsque nous souhaitons conserver une information, nous la plaçons au premier espace libre et nous avançons de x le pointeur du dictionnaire : on dit qu'on a alloué x de mémoire.
Notre façons de faire (CELL DP +!) est loin d’être irréprochable :
* que se passe-t-il s'il n'y a plus de mémoire disponible ?
* à suivre
Pour cela, ANS Forth défini le mot ALLOT :

#### ALLOT ( size -- )

    Alloue size de mémoire.
| Structure d'un programme | Branchements |