			Variables et accŠs … la m‚moire
			*******************************

1 Organisation de la m‚moire en FORTH
*************************************

	On peut distinguer trois parties essentielles de la m‚moire lorsqu'on
se trouve sous l'interpr‚teur du FORTH:
	1 : le buffer contenant le texte saisi sous l'‚diteur (1/6 de la m‚moire
limit‚ … 512 ko, ou valeur fix‚e dans FORTH.INF)
	2 : le dictionnaire (3/4 de la m‚moire ou valeur fix‚e dans
FORTH.INF)
	3 : la m‚moire laiss‚e au systŠme (1/4 de la m‚moire ou ce qui reste
selon FORTH.INF).

	C'est le dictionnaire qui nous int‚resse ici plus particuliŠrement. Dans
cette zone sont rang‚es (… partir du bas) les variables (num‚riques ou
chaines) et les d‚finitions des nouveaux mots (proc‚dures ou fonctions
comme on voudra). Y sont rang‚es ‚galement (… partir du haut) les variables
allou‚es dynamiquement (cr‚‚es ou d‚truites en cours de programme et
dont le nombre ne peut pas ˆtre d‚termin‚ au lancement).
	Son fonctionnement est simple, une variable est cr‚‚e? La place
n‚cessaire lui est allou‚e et le pointeur de fin de dictionnaire est augment‚
d'autant. C'est le mˆme principe pour une nouvelle fonction, une chaine de
caractŠres, etc...

here
----
	d‚pose sur la pile la valeur du pointeur de fin de dictionnaire.

top
---
	variable contenant la valeur de here. Elle se manipule comme une
variable FORTH:
	top @		: est ‚quivalent … here.
	100 top +!	: avance de 100 octets dans le dictionnaire.

,   w,   c,
-----------
	x ,    : d‚pose en fin de dictionnaire la valeur x sur 4 octets. w, r‚alise
la mˆme op‚ration mais sur 2 octets et c, sur un octet. Attention, avec c, le
pointeur n'augmentant que de 1, il risque de ne plus ˆtre pair (ce qui est
indispensable si en suivant se trouve la d‚finition assembl‚e d'une fonction).

even
----
	assure la parit‚ de top lui ajoutant 1 si il est impair.

allot
-----
	n  allot  :  alloue n octets dans le dictionnaire et fournit en retour
l'adresse de cette zone (l'ancienne valeur here en fait). On pourrait d‚finir
allot ainsi:
		: allot  here swap top +! ;

allot0
------
	n  allot0  :  ‚quivalent … allot, sauf que la zone est initialis‚e … 0.

free
full
----
	renvoient la taille en octets de la zone libre (free) du dictionnaire ou
de la zone d‚j… occup‚e (full).

remember
restore
--------
	remember garde en m‚moir l'‚tat actuel du dictionnaire, restore
permet de lui redonner cet ‚tat aprŠs un certain nombre de modifications.
Restore ex‚cut‚ sans aucun remember pr‚alable redonne au dictionnaire
l'‚tat initial. Attention, restore n'efface pas les variables cr‚‚es aprŠs
remember, si il en existe, elles pointeraient donc vers des zones consid‚r‚es
comme libres et risqueraient d'ˆtre effac‚es.

top>
----
	adr  top>  :  ‚change la valeur de top avec celle sur la pile. Ceci
permet de d‚placer momentan‚ment la position "logique" du dictionnaire en
m‚moire. Permet alors l'utilisation de "w," de "c,"  de ","  sur d'autres zones
ou mˆme l'assemblage d'instructions 68000 ailleurs que dans le dictionnaire.

>top
----
	reprend la valeur sur la pile et la remet dans top.

2 Lire et ‚crire en m‚moire
***************************

@
	adr @  :  ramŠne sur la pile l'entier long (4 octets) point‚ par adr.

!
	x  adr  !  :  range l'entier long x … l'adresse adr.

?
	adr  ?  :  affiche la valeur sur 4 octets contenue … l'adresse adr.

w@  c@
------
	mˆme principe que @ mais pour des mots (W=2octets) ou des octets
(C=1octet). Le signe des valeurs n'est pas ‚tendu … 4 octets, pour l'‚tendre
in faudra utiliser extwl pour un mot ou extbl pour un octet.

w!  c!
------
	mˆme principe que ! mais avec des mots ou des octets. Les valeurs
correspondent au mot ou … l'octet de poids faible de l'entier sur 4 octets
pr‚sent sur la pile.

extbl
-----
	‚tend le signe d'un octet … 4 octets. Par exemple 255 devient -1.

extwl
-----
	‚tend le signe d'un mot … un mot long, par exemple 65535 devient -1.

extbw
-----
	‚tend le signe d'un octet … un mot. Par exemple 255 devient 65535.

+!
--
	x  adr  +!  : ajoute x au mot long point‚ par adr.

-!
--
	x  adr  -!  :  soustrait x au mot long point‚ par adr.

1+!
---
	adr 1+!  :  ajoute 1 au mot long point‚ par adr.

1-!
---
	adr  1-!  : soustait 1 au mot long point‚ par adr.

2*!
---
	adr  2*!  : multiplie par 2 le mot long point‚ par adr.

2/!
---
	adr 2/!  :  divise par 2 le mot long point‚ par adr.

w*!
---
	x  adr  w*!  :  multiplie par x le mot long point‚ par adr (avec les
limitations de w*).

w/!
---
	x  adr  w/!  :  divise par x le mot long point‚ par adr  ( avec les
limitations de w/).

3 Les variables et les tableaux
*******************************

	Ne pouvant pas tout le temps travailler avec la pile, les mouvements
deviendraient trop complexes, on est amen‚ … cr‚er des variables pour conserver
certaines valeurs.

variable
--------
	variable XXX  :  cr‚e un mot XXX qui sera une variable sur 4 octets. A
l'ex‚cution XXX laisse simplement l'adresse d'une zone de 4 octets en
m‚moire. Puisqu'il se comporte comme une adresse, tous les mots
pr‚c‚dents sont valables pour XXX :
	variable  p		\ cr‚e la variable
	50 p !			\ maintenant p=50
	21 p +!		\ p=50+21=71
	p 2/!			\ p=71/2=35 (en nombre entier)
	p ?			\ affiche la valeur 35.

&wvar
-----
	&wvar XXX  : ‚quivalent … variable, sauf que la valeur est sur 2 octets.
On y accŠde donc avec w@ et w!.

array
-----
	n  array  XXX  :  cr‚e un mot XXX qui sera un tableau de n entiers
longs. Le mot XXX a besoin d'un indice sur la pile, il renvoie l'adresse de
l'‚l‚ment ainsi point‚:
	10 array TABLEAU	\ cr‚e le tableau
	50 3 TABLEAU !	\ TABLEAU(3)=50
	0 TABLEAU ?		\ affiche la valeur de TABLEAU(0)
	84 5 TABLEAU +!	\ ajoute 84 … TABLEAU(5)
	Les indices commencent … 0 et vont jusqu'… n-1, donc dans un tableau
de 10 valeurs les indices vont de 0 … 9.

&warray
-------
	n  &warray  XXX  : ‚quivalent … array, sauf que les entiers sont sur 2
octets, on y accŠde avec w@ et w!.

constant
--------
	x  constant XXX  :  cr‚e un mot XXX qui aura syst‚matiquement pour
valeur x. A l'‚x‚cution, XXX laisse x sur la pile.

table
-----
	table XXX  :  cr‚e un tableau de constantes. On remarque qu'aucune
dimension n'est indiqu‚e, en fait, il faut remplir ce tableau imm‚diatement
aprŠs sa d‚finition:
	table TEST
	7 , 9 , 15 , -6 , 3 ,		\ d‚pose 5 valeurs
	0 TEST			\ ramŠne TEST(0), c'est … dire 7.
	3 TEST			\ ramŠne TEST(3), c'est … dire -6.
	2 TEST 4 TEST +		\ calcule TEST(2)+TEST(4), donc 18.
	Pour plus de d‚tails sur le mot "," se r‚f‚rer … la partie traitant du
dictionnaire.


	Les variables peuvent servir … pointer des zones m‚moires, voici une s‚rie
de mots utiles pour balayer un bloc point‚ par une variable:

.b  .w  .l
----------
size
----
	indique la taille (.b=1 octet, .w=2 octets, .l=4 octets) des nombres …
traiter avec les mots qui suivent. Par d‚faut, la taille est .w.

-(@
---
	p -(@	: d‚cr‚mente d'abord la variable p de la taille sp‚cifi‚e avec
size, puis ramŠne sur la pile la valeur (1, 2 ou 4 octets) point‚e par p.

+(@
---
	p +(@  :  incr‚mente d'abord p puis ramŠne la valeur point‚e par p.
)-@
---
	p )-@  :  ramŠne la valeur point‚e par p puis d‚cr‚mente p.

)+@
---
	p )+@  :  ramŠne la valeur point‚e par p puis incr‚mente p.

-(!
---
	x  p  -(!  :  d‚cr‚mente p puis range x … l'adresse point‚e par p.

+(!
---
	x  p  +(!  :  incr‚mente p puis range x … l'adresse point‚e par p.

)-!
---
	x  p  )-!  :  range x … l'adresse point‚e par p puis d‚cr‚mente p.

)+!
---
	x  p  )+!  :  range x … l'adresse point‚e par p puis incr‚mente p.

	Exemple, on veut copier 100 mots de zone1 vers zone2:

	variable p    zone1 p !
	variable q    zone2 q !
	.w size
	100 ndo p )+@ q )+! nloop

cmove
-----
	adr  adr'  n  cmove  :  transvase n octets, ou mots ou mots longs (selon
la valeur pass‚e … size) de adr vers adr'. La routine tient compte du fait que
les zones peuvent se recouvrir en partie et r‚alise la copie soit par la fin, soit
par le d‚but pour ‚viter les erreurs. La copie est plus lente pour des octets, et
si on est certain d'avoir des adresses paires et un nombre pair d'octet …
d‚placer, autant d‚placer deux fois moins de mots (.w).

4 les chaines de caractŠres
***************************

	Un problŠme se pose pour la gestion des chaines par rapport … celle des
nombres. Le r‚sultat de n'importe quel calcul est de toutes fa‡ons un entier de 4
octets (taille fixe). De ce fait le d‚poser sur la pile n'est pas un problŠme. Par
contre, le r‚sultat d'une op‚ration de chaine peut ˆtre une chaine de 10000 octets,
la pile serait alors vite d‚bord‚e. La solution est de ne d‚poser sur la pile que
l'adresse de la chaine (4 octets), les caractŠres eux mˆme ‚tant rang‚s dans une
chaine propre au FORTH (pad) ou dans des variables de chaines d‚clar‚es par
l'utilisateur.
	Les chaines FORTH peuvent contenir jusqu'… 32763 octets, elles seront
toujours termin‚es par un 0 final assurant la compatibilit‚ avec les fonctions de la
ROM.

string
------
	l  string XXX  :  cr‚e un mot XXX qui sera une chaine de l octets
maximum. A l'ex‚cution, XXX laisse l'adresse du premier caractŠre de la
chaine.

array$
------
	l  n  array$ XXX  :  cr‚e un mot XXX qui sera un tableau de n chaines
de l octets chacune. XXX a besion d'un indice sur la pile, il renvoit l'adresse
du premier octet de la chaine ainsi point‚e:
	14  8  array$  TEST	\ 8 chaines de 14 octets
	5 TEST		\ adresse de la sixiŠme chaine
	0 TEST 1 TEST $=	\ compare les deux premiŠres chaines.

" "
---
	" xxxxx"  :  d‚pose sur la pile l'adresse de la chaine encadr‚e par " et ".
Remarquez l'espace n‚cessaire entre le premier guillemet et le d‚but du
texte. Il faudra acc‚der … cette chaine uniquement en lecture car elle est
temporaire. Si sa valeur doit ˆtre conserv‚e il faut la transf‚rer dans une
chaine cr‚‚e avec string.

pad
---
	d‚pose sur la pile l'adresse de la chaine servant de m‚moire tampon
pour les r‚sultats de certaines op‚rations.

len
---
	chaine  len  :  renvoie la taille actuelle de la chaine.

mlen
----
	chaine  len  :  renvoie la taille maximale de la chaine (celle pass‚e …
string par exemple).

$!
--
	chaine1  chaine2  $!  :  copie la chaine1 dans la chaine2.

$+
--
	chaine1  chaine2  $+  :  ajoute la chaine1 … la suite de la chaine2.

$=
--
	chaine1 chaine2  $=  :  renvoie 1 si les chaines sont ‚gales, 0 sinon.

$<
--
	chaine1  chaine2  $<  :  renvoie 1 si la chaine1 est avant la chaine2
(selon l'ordre ASCII), 0 sinon.

$>
--
	chaine1 chaine2  $>  :  renvoie 1 si la chaine1 est aprŠs la chaine2
(selon l'ordre ASCII), 0 sinon.

asc
---
	chaine  asc  :  renvoit le code ASCII du premier caractŠre de la chaine.


chr$
----
	c  chr$  :  cr‚e dans pad une chaine de 1 caractŠre de code ASCII c,
pad est laiss‚ sur la pile.

str$
----
	x  str$  :  cr‚e dans pad une chaine repr‚sentant le nombre x dans la
base courante, pad est laiss‚ sur la pile.

val
---
	chaine  val  :  renvoie sur la pile le nombre repr‚sent‚ par la chaine
dans la base courante.

instr
-----
	chaine1 chaine2 n instr  :  cherche si chaine2 est une sous chaine de
chaine1 … partir du niŠme caractŠre (la num‚rotation commen‡ant … 1). Si la
recherche est positive renvoie la position de chaine2 dans chaine1, 0 sinon.

left$
-----
	chaine  n  left$  :  envoie dans pad les n premiers caractŠres de chaine
et laisse pad sur la pile.

mid$
----
	chaine k  n  mid$  :  envoie dans pad n caractŠres de chaine … partir
du kiŠme et laisse pad sur la pile.

right$
------
	chaine n right$  :  envoie dans pad les n derniers caractŠres de la
chaine et laisse pad sur la pile.

puts
----
	chaine  adr  puts  :  envoie le contenu de la chaine FORTH … partir de
l'adresse adr (avec un 0 final).

gets
----
	adr  chaine  gets  :  r‚cupŠre dans la chaine FORTH les octets pr‚sents
… partir de adr, jusqu'… trouver un 0.

5 Les ensembles
***************

	Un ensemble est un objet dont le nombre maximal et la valeur des ‚l‚ments
sont pr‚d‚finis par l'utilisateur. L'objet ensemble, lui, contient une suite
d'indicateurs attestant la pr‚sence ou l'absence de chaque ‚l‚ment.
	Il y a deux sortes d'ensembles en FORTH, les ‚num‚r‚s (on donnera
explicitement la liste des ‚l‚ments) ou les segments (tous les entiers compris entre
deux valeurs). Les segments sont cr‚‚s directements, les ensembles ‚num‚r‚s sont
cr‚‚s … partir d'un modŠle de r‚f‚rence.
	Comme pour les chaines de caractŠres, les ensembles ne se d‚posent pas
sur la pile, seule leur adresse y est. On a donc encore une fois recours … un
ensemble "pads" pr‚d‚fini dans lequel iront les r‚sultats de certaines op‚rations.

&segment
--------
	sup  inf  &segment  XXX  :  cr‚e un mot XXX qui sera un ensemble
pouvant contenir tous les entiers de l'intervalle [inf,sup]. Il faut absolument
que -32769<inf<sup<32768. Au d‚part l'ensemble est vide, … l'ex‚cution
XXX laisse sur la pile l'adresse de l'ensemble:
	adr		: inf
	adr+2		: n = nombre d'‚l‚ments (sup-inf+1)
	adr+4		: suite de n bits (0=‚l‚ment absent, 1=pr‚sent).

&( ...  & ...  &)
-----------------
	&( elem1 & elem2 & ..... & elemn &) XXX  :  cr‚e n mots (elem1 …
elemn) qui seront les noms des ‚l‚ments de l'ensemble. Le modŠle lui mˆme
s'appelant XXX. A l'ex‚cution XXX laisse sur la pile l'adresse d'un en-tˆte
d'ensemble:
	adr		: code de elem1
	adr+2		: n, nombre d'‚l‚ments.
	A l'ex‚cution, chaque elemi laisse sur la pile son code FORTH. Puisque
les mots ont ‚t‚ cr‚‚s les un … la suite des autres, leurs codes se suivent,
donc cet ensemble se comporte comme un segment.

&setof
------
	modŠle  &setof  XXX  :  cr‚e un ensemble dont le type est calqu‚ sur le
modŠle, celui cr‚‚ avec &( &). Au d‚part, cet ensemble est vide et laisse …
l'ex‚cution l'adresse du bloc suivant:
	adr		: code de elem1
	adr+2		: n=nombre d'‚l‚ments
	adr+4		: suite de n bits.

pads
----
	ensemble pr‚d‚fini recevant les r‚sultats de certaines op‚rations. Son
type (valeur inf et nombre d'‚l‚ments) est automatiquement calqu‚ sur celui
des op‚randes.

initset
-------
	e  initset  :  donne … pads le type de l'ensemble e (e peut aussi ˆtre un
modŠle), pads ne contient alors aucun ‚l‚ment.

elmt+   elmt-
-------------
	x  e  elmt+	:  ajoute … l'ensemble e l'‚l‚ment x.
	x  e  elmt-	: retire l'‚l‚ment x de l'ensemble e.

elmtin
------
	x  e  elmtin	: renvoit 1 si x appartient … l'ensemble e, 0 sinon.

elmt@
-----
	n  e  elmt@	: renvoit sur la pile la valeur du niŠme ‚l‚ment pr‚sent
dans l'ensemble e, renvoit inf-1 sinon.

card
----
	e  card  :  renvoit le nombre d'‚l‚ments actuellement pr‚sents dans
l'ensemble e, donc 0 si il est vide.

set!
----
	e  e'  set!  :  donne … e' la valeur (et le type) de l'ensemble e. Si e et e'
n'‚taient pas du mˆme type (allez savoir pourquoi...), ils le deviennent. Par
contre si l'ensemble e' utilisait moins de m‚moire que e il se produit un
d‚bordement dangereux.

set=
----
	e  e'  set=  : renvoit 1 si les ensembles e et e' sont ‚gaux, 0 sinon.

setin
-----
	e  e'  setin  :  renvoit 1 si l'ensemble e est contenu dans l'ensemble e',
0 sinon.

set+   set*   set-   -set
-------------------------
	e  e'  set+	: calcule l'union des deux ensembles.
	e  e'  set*	: calcule l'intersection des deux ensembles.
	e  e'  set-	: calcule leur diff‚rence (‚l‚ments de e pas dans e').
	e      -set	: calcule le compl‚mentaire d'un ensemble.
	Pour chacune de ces quatre instructions, le r‚sultat est envoy‚ dans
pads dont l'adresse est laiss‚e sur la pile.

	Exemple pour les segments:
	255 0 &segment OCTET		\ OCTET est inclus dans [0,255]
	255 0 do
		i OCTET elmt+		\ tous les nombres pairs
		2
	+loop
	255 0 do
		i OCTET elmt-		\ enlŠve les multiples de 3
		3
	+loop
	Maintenant OCTET contient tous les nombres pairs non multiples de 3
entre 0 et 255 (c'est … dire 2, 4, 8, 10, ...)
	255 0 do
		i OCTET elmtin		\ ‚l‚ment i dans OCTET ?
		if
			i . space		\ si oui, on l'affiche
		then
	loop
	Cette boucle affiche tous les ‚l‚ment d'OCTET.

	Exemple pour les ensembles ‚num‚r‚s:
	&( lun & mar & mer & jeu & ven & sam & dim &) SEMAINE
				\ cr‚e le modŠle semaine
	SEMAINE &setof MOI
	SEMAINE &setof ELLE   \ deux ensembles semaines vides


	\ ce mot liste les ‚l‚ments de l'ensemble dont l'adresse est sur la pile

	variable p

	: voir
		p !				\ adresse dans p
		dim 1+ lun do 		\ boucle de lun … dim
			i  p @ elmtin            \ ‚l‚ment pr‚sent?
			if i word$ type space  \ si oui l'affiche
			then
		loop
	;

	list
		lun mar jeu ven sam
	dolist
		i MOI elmt+
	lloop	MOI voir			\ ma semaine de travail

	list
		mar mer jeu ven sam
	dolist
		i ELLE elmt+
	lloop	ELLE voir			\ la sienne

	MOI ELLE set* voir		\ intersection, jours ou les 2 travaillent
	MOI ELLE set- voir		\ je travaille mais pas elle
	MOI ELLE set+ 		\ jours ou l'un travaille
	-set voir			\ compl‚mentaire, jours ou tous 2 libres

6 Les nombres r‚els
*******************

&float
------
	&float XXX  :  cr‚e un mot XXX qui sera une variable de type r‚el (8
octets au format double IEEE). A l'ex‚cution XXX laisse sur la pile l'adresse
d'une zone de 8 octets.

f@
--
	adr  f@  :  ramŠne sur la pile le r‚el point‚ par l'adresse adr. Peut
aussi servir … ramener plus rapidement deux entiers longs.

f!
--
	x  adr  f!  :  range le r‚el x … l'adresse adr.

	Par exemple:
	&float REEL				\ cr‚e une variable r‚elle
	%f1.23  REEL f!			\ REEL vaut 1,23
	REEL f@				\ ramŠne 1,23 sur la pile
	frac  f.					\ partie fractionnaire 0.23 qu'on
						\ affiche
7 Les structures
****************

	Permettent de grouper sous un seul nom plusieurs objets de types diff‚rents
qui dans l'application sont logiquement li‚s. Ce qui permet de les cr‚er, les d‚truire
ou les transf‚rer en bloc. Contrairement aux autres variables qui sont cr‚es dans la
zone basse du dictionnaire, les stuctures sont cr‚es dynamiquement en zone haute
et peuvent de ce fait ˆtre effac‚es et lib‚rer la place m‚moire pr‚c‚demment
utilis‚e.
	Pour illustrer les instructions nous allons cr‚er une structure
correspondante aux informations sur une personne (nom, pr‚nom, age).

struct  ....  &name
-------------------
	pr‚pare le modŠle d'une structure. Ce modŠle se trouvera en m‚moire
basse, les structures cr‚es par lui seront en m‚moire haute. Entre struct et
&name se trouvent la d‚finitions des composant de la structure:
	struct
		40 string NOM		\ nom sur 40 caractŠres
		20 string PRENOM		\ pr‚nom sur 20 caractŠres
		variable AGE			\ l'age est une variable num‚rique
	&name  HUMAIN			\ nom global du modŠle.

	Pour acc‚der … une composante de la structure il faut d'abord d‚poser
l'adresse de la structure suivie du nom de la composante.

screate
-------
	modŠle  screate  :  cr‚e une structure en utilisant le modŠle (ce
modŠle peut ˆtre remplac‚ par une autre structure correspondant au mˆme
modŠle). Renvoit sur la pile l'adresse de cette structure.

	variable p
	HUMAIN screate  p !			\ p=adresse d'un nouvel humain

	" DUPONT" p @ NOM $!		\ son nom
	" PIERRE" p @ PRENOM $!		\ son pr‚nom
	34 p @ AGE !				\ son age

	\ ce mot affiche les composantes de la structure dont l'adresse est
	\ pass‚e sur la pile.

	: voir
		dup NOM type cr
		dup PRENOM type cr
		AGE ? cr
	;

	p @ voir	\ affiche DUPONT, PIERRE, 34.

	variable q
	HUMAIN screate q !		\ encore un humain

s!
--
	s1  s2  s!  :  transfŠre le contenu de la structure s1 vers s2.

	p @ q @ s!		\ maintenant Pierre dupont est en double
	q @ voir		\ affiche les mˆmes donn‚es
	15 q @ AGE +!	\ modifie l'age en y ajoutant 15 ans.
	p @ voir		\ le jeunot de 34 ans
	p @ voir		\ le mˆme … 49 ans.

sdelete
-------
	adr sdelete  :  libŠre la m‚moire utilis‚e par la structure se trouvant …
l'adresse adr. Cet emplacement pourra ˆtre r‚allou‚ plus tard.
	p @ sdelete		\ Pierre Dupont n'existe plus.
	q @ sdelete		\ son vieux double non plus

sizeof
------
	s sizeof  :  fournit la taille m‚moire d'une structure.

	On voit que ces structures utilis‚es ainsi ne sont pas forc‚ment simples, en
effet, il faut une variable diff‚rente pour garder l'adresse de chaque structure. Or,
leur int‚rˆt est d'ˆtre cr‚‚es ou d‚truites … volont‚, donc sans limitation pr‚alable
de nombre, ce qui est en contradiction avec l'utilisation de variables qui sont en
nombre connu (puisque d‚clar‚es nomm‚ment une … une).
	On a alors recours aux chaines de structures. Chaque ‚l‚ment contenant
l'adresse d'un autre ‚l‚ment. Il suffit de garder dans une variable l'adresse du
premier ‚l‚ment et on peut parcourir ainsi une chaine de taille ind‚finie en
n'utilisant qu'une variable!

	\ ce mot servira … remplir les trois champs d'un humain

	: remplir
		>r		\ adresse structure sur pile des retours
		r@ AGE !
		r @ PRENOM $!
		r> NOM $!
	;

	\ cette variable contiendra l'adresse du d‚butde la chaine

	variable p
	0 p !			\ p=0, chaine vide.

pchain
------
	p  modŠle  pchain	: cr‚e et insŠre une structure copie du modŠle en
tˆte de chaine, cette chaine ‚tant point‚e par la variable p. AprŠs cette
fonction, p pointe sur le nouvel ‚l‚ment et cet ‚l‚ment pointe sur l'ancien
d‚but de chaine.

	p HUMAIN pchain	\ p pointe sur un nouvel ‚l‚ment, celui-ci
				\ pointant sur 0 (avant p contenait 0!)
	" Dupont" " Pierre" 34 p @ remplir		\ initialise ce bonhomme

	p HUMAIN pchain	\ p pointe sur un nouveau, celui-ci pointe sur
				\ pierre dupont et dupont sur 0.

	" Tom"  " Oncle"  95 p @ remplir		\ initialise le nouveau

next
----
	s  next  :  fournit l'adresse de la structure qui suit la structure s dans la
chaine. Renvoit 0 si c'est la fin.

	p @ voir		\ montre le premier ‚l‚ment (Oncle Tom)
	p @ next voir		\ montre le second (Pierre Dupont)
	p @ next next .	\ affiche 0, c'est la fin.

	\ ce mot affiche tous les ‚l‚ments de la chaine point‚e par p

	: tous
		p @			\ le d‚but
		begin
			?dup		\ duplique si non nul
		while
			dup voir cr	\ si non nul, affiche et saut de ligne
			next		\ adresse suivante
		repeat
	;

punchain
--------
	p  adr  punchain  :  enlŠve de la chaine point‚e par p l'‚l‚ment dont
l'adresse est pr‚cis‚e. Comme avec sdelete, la m‚moire est alors lib‚r‚e.

pinchain
--------
	p  adr  pinchain  :  ajoute en tˆte de la chaine point‚e par p l'‚l‚ment
d‚j… existant en m‚moire point‚ par l'adresse adr. Celui-ci pointera sur
l'ancienne tˆte de chaine. (Cet ‚l‚ment aura ‚t‚ cr‚‚ par screate par
exemple).

pempty
------
	p pempty  :  vide totalement la chaine point‚e par p, tous les ‚l‚ments
sont d‚truits et p=0. Si on d‚sire simplement cr‚er une nouvelle chaine p=0
suffit (d'ailleurs pempty serait une erreur, car p aurait au d‚part une valeur
quelconque et non un pointeur sur une structure).

	Toutes les op‚rations ont ‚t‚ jusqu'ici r‚alis‚es en tˆte de chaine. Ceci ne
sera pas toujours souhaitable, voici donc les instructions n‚cessaires pour obtenir
les mˆmes r‚sultats en milieu de chaine:

chain
-----
	adr chain  :  adr est l'adresse d'une structure ins‚r‚e dans une chaine.
Chain cr‚e une nouvelle structure semblable … la pr‚c‚dente et l'insŠre dans
la chaine juste aprŠs.
	Cette fonction renvoit l'adresse du nouvel ‚l‚ment (pour l'initialiser
par exemple).

unchain
-------
	adr1 adr2 unchain  :  supprime l'‚l‚ment adr2 de la chaine, libŠre
‚galement la m‚moire qu'il occupait, … cet effet adr1 doit ˆtre un ‚l‚ment le
pr‚c‚dant dand la chaine (pas forc‚ment celui juste avant) afin de r‚aliser le
d‚chainage correctement.

inchain
-------
	adr1 adr2 inchain  :  insŠre l'‚l‚ment d‚j… existant point‚ par adr2
juste … la suite de celui point‚ par adr1. Ce dernier doit faire partie d'une
chaine.

empty
-----
	adr  empty  :  vide la chaine … partir de l'‚l‚ment point‚ par adr,
celui-ci non compris, il devient alors le dernier de la chaine (son pointeur …
0) et la place m‚moire occup‚e par ses suivants est … nouveau disponible.

islast
------
	adr  islast  :  d‚finit l'‚l‚ment point‚ par adr comme ‚tant le dernier
en annulant son pointeur. Contrairement … empty aucun ‚l‚ment n'est
effac‚. Ceci peut servir … commencer une chaine dont (adr) serait le premier
‚l‚ment (sans utiliser de variable).

previous
--------
	adr1 adr2 previous  :  recherche dans la chaine l'‚l‚ment pr‚c‚dant
adr2 (donc celui qui pointe sur adr2). A cet effet adr1 doit ˆtre l'adresse d'un
‚l‚ment pr‚c‚dant adr2 (la tˆte de liste le plus souvent). Si le d‚but de
chaine est rang‚ dans une variable p, on utilise:
	p @ adr2 previous	\ p @ donnant l'adresse du premier ‚l‚ment.
	Pour r‚aliser ceci, le programme parcourt toute la chaine jusqu'…
trouver l'‚l‚ment dont le pointeur est adr2. Si cet ‚l‚ment existe, son adresse
est laiss‚e sur la pile, sinon on obtient 0 (c'est le cas si adr2 est lui mˆme en
tˆte de chaine, cette valeur 0 correspond donc bien … une "fin" de chaine
parcourue … l'envers).

settable
--------
	-1 settable  :  initialise la table en conservant sa taille. La partie haute
du dictionnaire est consid‚r‚e comme libre … nouveau.
	n  settable  : (n>0), cr‚e une nouvelle table de n octets et l'initialise,
la partie haute du dictionnaire est consid‚r‚e comme libre … nouveau.

	Cette table sert … g‚rer les allocations et d‚sallocations de structures
en haut du dictionnaire. Pour illustrer son principe, supposons qu'on cr‚e …
la suite 1000 structures, elles forment un bloc compact. La table contiendra
donc un seul pointeur (4 octets) sur un bloc occup‚, un seul (4 octets) sur un
bloc libre (le reste de la m‚moire) et un indicateur de fin de table (-1 sur 4
octets). La table ne demandera alors que 12 octets de gestion.
	Supposons maintenant qu'on efface une structure au milieu du bloc.
La table sera alors:
	pointeur sur un bloc occup‚	: ceux avant la structure effac‚e
	pointeur sur un bloc libre		: celui qu'on vient d'effacer
	pointeur sur un bloc occup‚	: ceux aprŠs la structure
	pointeur sur un bloc libre		: le reste de la m‚moire
	fin de table				: -1
	La table demandera alors 20 octets avec une structure de moins. Si
pour finir j'efface exactement une structure sur deux pour avoir un
maximum de trous, j'aurai besoin de 500 pointeurs sur des blocs occup‚s,
500 sur des blocs libres et l'indicateur de fin de table: 500*4 + 500*4 + 4,
c'est … dire 4004 octets.
	Tout ceci d‚pend donc de la maniŠre dont votre programme va agir.
Si il libŠre les structures dans l'ordre inverse (ou le mˆme ordre) ou il les
cr‚e, 20 octets seront largement suffisants, si par contre le jeu des allocations
et lib‚rations de m‚moire est plus sauvage il faudra pr‚voir au moins 4 fois
le nombre maximal de structures que vous pensez cr‚er, plus 4 octets pour
l'indicateur de fin.
	Par d‚faut, la table est longue de 1028 octets, ce qui permet de g‚rer
jusqu'a 256 ‚l‚ments et d'en arriver au pire (la lib‚ration d'un sur deux). De
toutes fa‡ons, lorsqu'une structure est cr‚‚e on tente de la rattacher … un
bloc d‚j… existant, ceci n'augmente donc pas la taille de la table (puisque le
nombre de blocs est le mˆme!), parfois ce nouvel ‚l‚ment permet de
raccrocher deux blocs, ainsi la table est mˆme r‚duite!

	Les mots pr‚c‚dents sont adapt‚s au stuctures cr‚es par le FORTH lui
mˆme (il s'occupe des pointeurs, des allocations et d‚sallocations de m‚moire,
etc... Mais il se peut que les donn‚es soient d‚j… en m‚moire et qu'on ait besoin d'y
acc‚der de maniŠre claire … l'aide des structures. Pensons en particulier aux
fichiers *.RSC dont chaque objet est d‚fini par une structure.
	Puisque dans ce cas les donn‚es existent d‚j…, il nous suffit d'un en-tˆte de
stucture dont l'adresse des donn‚es sera fix‚e par l'utilisateur, c'est justement ce
que fait &pointer.

&pointer
--------
	modŠle  &pointer  XXX  :  cr‚e le mot XXX qui sera un simple pointeur
sur une sructure conforme au modŠle. Aucune place m‚moire n'est allou‚e
pour les donn‚es. Pour fixer l'adresse des donn‚es, XXX se comporte comme
une variable simple:
	adr  XXX !		\ fixe l'adresse
	A l'ex‚cution, XXX laisse l'adresse d'un en-tˆte.

	Reprenons donc l'exemple des arbres d'objets:

	struct
		&wvar		ob_next
		&wvar		ob_head
		&wvar		ob_tail
		&wvar		ob_type
		&wvar		ob_flags
		&wvar		ob_state
		variable	ob_spec
		&wvar		ob_x
		&wvar		ob_y
		&wvar		ob_width
		&wvar		ob_height
	&name	OBJECT

	Supposons maintenant qu'… la suite du chargement du fichier on obtienne
l'adresse de l'arbre avec rsrc_gaddr qu'on a rang‚ dans la constante TREE.

	OBJECT &pointer objet		\ pointeur sans donn‚es

	TREE objet !				\ il pointe sur le premier objet!
	objet ob_flags w@ b.		\ affiche ses flags
	0 objet ob_state w!			\ annule state (apparence normale)

	objet sizeof 5 *			\ taille de 5 objets
	objet +!				\ qu'on ajoute … l'adresse des
						\ donn‚es, il pointe sur le 5ø!
	objet ob_x  get_xylh			\ ramŠne ses 4 coordonn‚es

	En pratique, si les structures sont coll‚es les unes aux autres, toutes de
mˆme taille et commen‡ant … l'adresse ADR, la formule est celle-ci pour acc‚der
aux donn‚es de l'objet d'indice i (indices commen‡ant … 0):

	ADR objet sizeof i * + objet !

	Pour les objets GEM la taille est toujours 24 octets, on pourra donc
remplacer objet sizeof par 24.

8 Cr‚er un type de donn‚es
**************************

	On a parfois besion de donn‚es particuliŠres qui ne peuvent pas
s'exprimer … l'aide des types de base. Il faut donc cr‚er un type. Ce type sera
un mot ‚quivalent … variable ou &float ou array etc... qui lui mˆme cr‚era un
autre mot lui donnant un certain comportement.
	Par exemple, le mot variable a trois actions successives:
	1- le mot qui suit est nouveau, il faut le cr‚er
	2- r‚server une zone de 4 octets
	3- donner comme comportement … la variable celui de d‚poser
l'adresse des 4 octets.

	La syntaxe g‚n‚rale d'un type sera:

	: &TYPE  <actions2>  :does>  <actions3>  ;end  <autres> ;

	Le fait que le nom commence par le caractŠre & assure l'action nø1,
c'est … dire l'inclusion du mot suivant dans le vocabulaire (comme &float, ou
&wvar, &name...). Les <actions2> sont donc les initialisations (r‚servation
de m‚moire par exemple, la partie entre :does> et ;end correspondra au
comportement du nouveau mot, le reste, <autres> contiendra des actions
suppl‚mentaires, c'est … dire rien le plus souvent.

:does>   ;end
-------------
	ils encadrent la d‚finition d'un mot nouvellement cr‚‚. :does> a un
comportement un peu sp‚cial: si il rencontre sur la pile une valeur non nulle,
il l'inclut dans la d‚finition du mot en la consid‚rant comme un paramŠtre
issu des initialisations (souvent l'adresse des donn‚es), si il rencontre la
valeur 0 rien n'est ajout‚ … la d‚finition. De ce fait, 0 ne peut pas ˆtre un
paramŠtre!

	Cr‚ons (ou recr‚ons) le type variable:
	: &VAR
		4 allot		\ r‚serve de la place et renvoit l'adresse
		:does>	\ l'adresse est plac‚e dans la d‚finition
		;end		\ la variable ne fait rien d'autre qu'empiler
				\ l'adresse!
	;

	&VAR a		\ cr‚e la variable a
	&VAR b		\ mˆme chose pour b

	Cr‚ons un tableau de nombres r‚els (genre array mais avec 8 octets
par nombre), le nombre d‚l‚ments sera pass‚ sur la pile:

	: &farray
		8 * allot0		\ r‚serve 8*nombre d‚l‚ments
		:does>		\ adresse pass‚e dans la d‚finition
			swap 8 * +	\ caculera adr+8*i
		;end
	;

	5 &farray TABLEAU		\ tableau de 5 r‚els
	%f5.36  			\ d‚pose 5.36
	2  TABLEAU 			\ adresse du 3ø ‚l‚ment (adr+8*2)
	f!				\ range 5.36 … l'adresse indiqu‚e

	5 0 do				\ boucle de 0 … 4
		i TABLEAU f@ f. cr	\ affiche l'‚l‚ment i
	loop

	Cr‚ons la constante:
	: &CONST
		?dup if			\ duplique si non nul
			:does> ;end		\ si <>0, valeur dans definition
		else
			:does> 0 ;end	\ si 0, on doit la passer nous mˆmes
		then
	;
	20  &CONST vingt		\ vingt sera une constante ‚gale … 20.
	0 &CONST z‚ro		\ z‚ro sera une constante ‚gale … 0.

	Ceci montre que plusieurs :does> ;end sont possibles dans le mˆme
type pourvu qu'une seule paire soit ex‚cut‚e.

::does>   ;end
--------------
	Mˆme principe que :does> ;end sauf qu'a chaque nouvelle cr‚ation de
mot, sa d‚finition sera assembl‚e et non interpr‚t‚e. Ce mot sera utilisable
dans un mot assembl‚ (ou compil‚).