			Variables et accs  la mmoire
			*******************************

1 Organisation de la mmoire en FORTH
*************************************

	On peut distinguer trois parties essentielles de la mmoire lorsqu'on
se trouve sous l'interprteur du FORTH:
	1 : le buffer contenant le texte saisi sous l'diteur (1/6 de la mmoire
limit  512 ko, ou valeur fixe dans FORTH.INF)
	2 : le dictionnaire (3/4 de la mmoire ou valeur fixe dans
FORTH.INF)
	3 : la mmoire laisse au systme (1/4 de la mmoire ou ce qui reste
selon FORTH.INF).

	C'est le dictionnaire qui nous intresse ici plus particulirement. Dans
cette zone sont ranges ( partir du bas) les variables (numriques ou
chaines) et les dfinitions des nouveaux mots (procdures ou fonctions
comme on voudra). Y sont ranges galement ( partir du haut) les variables
alloues dynamiquement (cres ou dtruites en cours de programme et
dont le nombre ne peut pas tre dtermin au lancement).
	Son fonctionnement est simple, une variable est cre? La place
ncessaire lui est alloue et le pointeur de fin de dictionnaire est augment
d'autant. C'est le mme principe pour une nouvelle fonction, une chaine de
caractres, etc...

here
----
	dpose 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 ,    : dpose en fin de dictionnaire la valeur x sur 4 octets. w, ralise
la mme opration 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 dfinition assemble 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 dfinir
allot ainsi:
		: allot  here swap top +! ;

allot0
------
	n  allot0  :  quivalent  allot, sauf que la zone est initialise  0.

free
full
----
	renvoient la taille en octets de la zone libre (free) du dictionnaire ou
de la zone dj occupe (full).

remember
restore
--------
	remember garde en mmoir l'tat actuel du dictionnaire, restore
permet de lui redonner cet tat aprs un certain nombre de modifications.
Restore excut sans aucun remember pralable redonne au dictionnaire
l'tat initial. Attention, restore n'efface pas les variables cres aprs
remember, si il en existe, elles pointeraient donc vers des zones considres
comme libres et risqueraient d'tre effaces.

top>
----
	adr  top>  :  change la valeur de top avec celle sur la pile. Ceci
permet de dplacer momentanment la position "logique" du dictionnaire en
mmoire. Permet alors l'utilisation de "w," de "c,"  de ","  sur d'autres zones
ou mme 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 mmoire
***************************

@
	adr @  :  ramne 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@
------
	mme 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!
------
	mme 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
prsent 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  crer des variables pour conserver
certaines valeurs.

variable
--------
	variable XXX  :  cre un mot XXX qui sera une variable sur 4 octets. A
l'excution XXX laisse simplement l'adresse d'une zone de 4 octets en
mmoire. Puisqu'il se comporte comme une adresse, tous les mots
prcdents sont valables pour XXX :
	variable  p		\ cre 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 accde donc avec w@ et w!.

array
-----
	n  array  XXX  :  cre 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'lment ainsi point:
	10 array TABLEAU	\ cre 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 accde avec w@ et w!.

constant
--------
	x  constant XXX  :  cre un mot XXX qui aura systmatiquement pour
valeur x. A l'xcution, XXX laisse x sur la pile.

table
-----
	table XXX  :  cre un tableau de constantes. On remarque qu'aucune
dimension n'est indique, en fait, il faut remplir ce tableau immdiatement
aprs sa dfinition:
	table TEST
	7 , 9 , 15 , -6 , 3 ,		\ dpose 5 valeurs
	0 TEST			\ ramne TEST(0), c'est  dire 7.
	3 TEST			\ ramne TEST(3), c'est  dire -6.
	2 TEST 4 TEST +		\ calcule TEST(2)+TEST(4), donc 18.
	Pour plus de dtails sur le mot "," se rfrer  la partie traitant du
dictionnaire.


	Les variables peuvent servir  pointer des zones mmoires, voici une srie
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 dfaut, la taille est .w.

-(@
---
	p -(@	: dcrmente d'abord la variable p de la taille spcifie avec
size, puis ramne sur la pile la valeur (1, 2 ou 4 octets) pointe par p.

+(@
---
	p +(@  :  incrmente d'abord p puis ramne la valeur pointe par p.
)-@
---
	p )-@  :  ramne la valeur pointe par p puis dcrmente p.

)+@
---
	p )+@  :  ramne la valeur pointe par p puis incrmente p.

-(!
---
	x  p  -(!  :  dcrmente p puis range x  l'adresse pointe par p.

+(!
---
	x  p  +(!  :  incrmente p puis range x  l'adresse pointe par p.

)-!
---
	x  p  )-!  :  range x  l'adresse pointe par p puis dcrmente p.

)+!
---
	x  p  )+!  :  range x  l'adresse pointe par p puis incrmente 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 passe  size) de adr vers adr'. La routine tient compte du fait que
les zones peuvent se recouvrir en partie et ralise la copie soit par la fin, soit
par le dbut 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 
dplacer, autant dplacer deux fois moins de mots (.w).

4 les chaines de caractres
***************************

	Un problme se pose pour la gestion des chaines par rapport  celle des
nombres. Le rsultat de n'importe quel calcul est de toutes faons un entier de 4
octets (taille fixe). De ce fait le dposer sur la pile n'est pas un problme. Par
contre, le rsultat d'une opration de chaine peut tre une chaine de 10000 octets,
la pile serait alors vite dborde. La solution est de ne dposer sur la pile que
l'adresse de la chaine (4 octets), les caractres eux mme tant rangs dans une
chaine propre au FORTH (pad) ou dans des variables de chaines dclares par
l'utilisateur.
	Les chaines FORTH peuvent contenir jusqu' 32763 octets, elles seront
toujours termines par un 0 final assurant la compatibilit avec les fonctions de la
ROM.

string
------
	l  string XXX  :  cre un mot XXX qui sera une chaine de l octets
maximum. A l'excution, XXX laisse l'adresse du premier caractre de la
chaine.

array$
------
	l  n  array$ XXX  :  cre 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 pointe:
	14  8  array$  TEST	\ 8 chaines de 14 octets
	5 TEST		\ adresse de la sixime chaine
	0 TEST 1 TEST $=	\ compare les deux premires chaines.

" "
---
	" xxxxx"  :  dpose sur la pile l'adresse de la chaine encadre par " et ".
Remarquez l'espace ncessaire entre le premier guillemet et le dbut du
texte. Il faudra accder  cette chaine uniquement en lecture car elle est
temporaire. Si sa valeur doit tre conserve il faut la transfrer dans une
chaine cre avec string.

pad
---
	dpose sur la pile l'adresse de la chaine servant de mmoire tampon
pour les rsultats de certaines oprations.

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

mlen
----
	chaine  len  :  renvoie la taille maximale de la chaine (celle passe 
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 aprs la chaine2
(selon l'ordre ASCII), 0 sinon.

asc
---
	chaine  asc  :  renvoit le code ASCII du premier caractre de la chaine.


chr$
----
	c  chr$  :  cre dans pad une chaine de 1 caractre de code ASCII c,
pad est laiss sur la pile.

str$
----
	x  str$  :  cre dans pad une chaine reprsentant le nombre x dans la
base courante, pad est laiss sur la pile.

val
---
	chaine  val  :  renvoie sur la pile le nombre reprsent par la chaine
dans la base courante.

instr
-----
	chaine1 chaine2 n instr  :  cherche si chaine2 est une sous chaine de
chaine1  partir du nime caractre (la numrotation commenant  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 caractres de chaine
et laisse pad sur la pile.

mid$
----
	chaine k  n  mid$  :  envoie dans pad n caractres de chaine  partir
du kime et laisse pad sur la pile.

right$
------
	chaine n right$  :  envoie dans pad les n derniers caractres 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  :  rcupre dans la chaine FORTH les octets prsents
 partir de adr, jusqu' trouver un 0.

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

	Un ensemble est un objet dont le nombre maximal et la valeur des lments
sont prdfinis par l'utilisateur. L'objet ensemble, lui, contient une suite
d'indicateurs attestant la prsence ou l'absence de chaque lment.
	Il y a deux sortes d'ensembles en FORTH, les numrs (on donnera
explicitement la liste des lments) ou les segments (tous les entiers compris entre
deux valeurs). Les segments sont crs directements, les ensembles numrs sont
crs  partir d'un modle de rfrence.
	Comme pour les chaines de caractres, les ensembles ne se dposent pas
sur la pile, seule leur adresse y est. On a donc encore une fois recours  un
ensemble "pads" prdfini dans lequel iront les rsultats de certaines oprations.

&segment
--------
	sup  inf  &segment  XXX  :  cre 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 dpart l'ensemble est vide,  l'excution
XXX laisse sur la pile l'adresse de l'ensemble:
	adr		: inf
	adr+2		: n = nombre d'lments (sup-inf+1)
	adr+4		: suite de n bits (0=lment absent, 1=prsent).

&( ...  & ...  &)
-----------------
	&( elem1 & elem2 & ..... & elemn &) XXX  :  cre n mots (elem1 
elemn) qui seront les noms des lments de l'ensemble. Le modle lui mme
s'appelant XXX. A l'excution XXX laisse sur la pile l'adresse d'un en-tte
d'ensemble:
	adr		: code de elem1
	adr+2		: n, nombre d'lments.
	A l'excution, chaque elemi laisse sur la pile son code FORTH. Puisque
les mots ont t crs les un  la suite des autres, leurs codes se suivent,
donc cet ensemble se comporte comme un segment.

&setof
------
	modle  &setof  XXX  :  cre un ensemble dont le type est calqu sur le
modle, celui cr avec &( &). Au dpart, cet ensemble est vide et laisse 
l'excution l'adresse du bloc suivant:
	adr		: code de elem1
	adr+2		: n=nombre d'lments
	adr+4		: suite de n bits.

pads
----
	ensemble prdfini recevant les rsultats de certaines oprations. Son
type (valeur inf et nombre d'lments) est automatiquement calqu sur celui
des oprandes.

initset
-------
	e  initset  :  donne  pads le type de l'ensemble e (e peut aussi tre un
modle), pads ne contient alors aucun lment.

elmt+   elmt-
-------------
	x  e  elmt+	:  ajoute  l'ensemble e l'lment x.
	x  e  elmt-	: retire l'lment 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 nime lment prsent
dans l'ensemble e, renvoit inf-1 sinon.

card
----
	e  card  :  renvoit le nombre d'lments actuellement prsents 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 mme type (allez savoir pourquoi...), ils le deviennent. Par
contre si l'ensemble e' utilisait moins de mmoire que e il se produit un
dbordement 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 diffrence (lments de e pas dans e').
	e      -set	: calcule le complmentaire d'un ensemble.
	Pour chacune de ces quatre instructions, le rsultat est envoy dans
pads dont l'adresse est laisse 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-		\ enlve 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		\ lment i dans OCTET ?
		if
			i . space		\ si oui, on l'affiche
		then
	loop
	Cette boucle affiche tous les lment d'OCTET.

	Exemple pour les ensembles numrs:
	&( lun & mar & mer & jeu & ven & sam & dim &) SEMAINE
				\ cre le modle semaine
	SEMAINE &setof MOI
	SEMAINE &setof ELLE   \ deux ensembles semaines vides


	\ ce mot liste les lments 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            \ lment prsent?
			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			\ complmentaire, jours ou tous 2 libres

6 Les nombres rels
*******************

&float
------
	&float XXX  :  cre un mot XXX qui sera une variable de type rel (8
octets au format double IEEE). A l'excution XXX laisse sur la pile l'adresse
d'une zone de 8 octets.

f@
--
	adr  f@  :  ramne sur la pile le rel point par l'adresse adr. Peut
aussi servir  ramener plus rapidement deux entiers longs.

f!
--
	x  adr  f!  :  range le rel x  l'adresse adr.

	Par exemple:
	&float REEL				\ cre une variable relle
	%f1.23  REEL f!			\ REEL vaut 1,23
	REEL f@				\ ramne 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 diffrents
qui dans l'application sont logiquement lis. Ce qui permet de les crer, les dtruire
ou les transfrer en bloc. Contrairement aux autres variables qui sont cres dans la
zone basse du dictionnaire, les stuctures sont cres dynamiquement en zone haute
et peuvent de ce fait tre effaces et librer la place mmoire prcdemment
utilise.
	Pour illustrer les instructions nous allons crer une structure
correspondante aux informations sur une personne (nom, prnom, age).

struct  ....  &name
-------------------
	prpare le modle d'une structure. Ce modle se trouvera en mmoire
basse, les structures cres par lui seront en mmoire haute. Entre struct et
&name se trouvent la dfinitions des composant de la structure:
	struct
		40 string NOM		\ nom sur 40 caractres
		20 string PRENOM		\ prnom sur 20 caractres
		variable AGE			\ l'age est une variable numrique
	&name  HUMAIN			\ nom global du modle.

	Pour accder  une composante de la structure il faut d'abord dposer
l'adresse de la structure suivie du nom de la composante.

screate
-------
	modle  screate  :  cre une structure en utilisant le modle (ce
modle peut tre remplac par une autre structure correspondant au mme
modle). 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 prnom
	34 p @ AGE !				\ son age

	\ ce mot affiche les composantes de la structure dont l'adresse est
	\ passe 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!  :  transfre le contenu de la structure s1 vers s2.

	p @ q @ s!		\ maintenant Pierre dupont est en double
	q @ voir		\ affiche les mmes donnes
	15 q @ AGE +!	\ modifie l'age en y ajoutant 15 ans.
	p @ voir		\ le jeunot de 34 ans
	p @ voir		\ le mme  49 ans.

sdelete
-------
	adr sdelete  :  libre la mmoire utilise par la structure se trouvant 
l'adresse adr. Cet emplacement pourra tre rallou plus tard.
	p @ sdelete		\ Pierre Dupont n'existe plus.
	q @ sdelete		\ son vieux double non plus

sizeof
------
	s sizeof  :  fournit la taille mmoire d'une structure.

	On voit que ces structures utilises ainsi ne sont pas forcment simples, en
effet, il faut une variable diffrente pour garder l'adresse de chaque structure. Or,
leur intrt est d'tre cres ou dtruites  volont, donc sans limitation pralable
de nombre, ce qui est en contradiction avec l'utilisation de variables qui sont en
nombre connu (puisque dclares nommment une  une).
	On a alors recours aux chaines de structures. Chaque lment contenant
l'adresse d'un autre lment. Il suffit de garder dans une variable l'adresse du
premier lment et on peut parcourir ainsi une chaine de taille indfinie 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 dbutde la chaine

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

pchain
------
	p  modle  pchain	: cre et insre une structure copie du modle en
tte de chaine, cette chaine tant pointe par la variable p. Aprs cette
fonction, p pointe sur le nouvel lment et cet lment pointe sur l'ancien
dbut de chaine.

	p HUMAIN pchain	\ p pointe sur un nouvel lment, 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 lment (Oncle Tom)
	p @ next voir		\ montre le second (Pierre Dupont)
	p @ next next .	\ affiche 0, c'est la fin.

	\ ce mot affiche tous les lments de la chaine pointe par p

	: tous
		p @			\ le dbut
		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  :  enlve de la chaine pointe par p l'lment dont
l'adresse est prcise. Comme avec sdelete, la mmoire est alors libre.

pinchain
--------
	p  adr  pinchain  :  ajoute en tte de la chaine pointe par p l'lment
dj existant en mmoire point par l'adresse adr. Celui-ci pointera sur
l'ancienne tte de chaine. (Cet lment aura t cr par screate par
exemple).

pempty
------
	p pempty  :  vide totalement la chaine pointe par p, tous les lments
sont dtruits et p=0. Si on dsire simplement crer une nouvelle chaine p=0
suffit (d'ailleurs pempty serait une erreur, car p aurait au dpart une valeur
quelconque et non un pointeur sur une structure).

	Toutes les oprations ont t jusqu'ici ralises en tte de chaine. Ceci ne
sera pas toujours souhaitable, voici donc les instructions ncessaires pour obtenir
les mmes rsultats en milieu de chaine:

chain
-----
	adr chain  :  adr est l'adresse d'une structure insre dans une chaine.
Chain cre une nouvelle structure semblable  la prcdente et l'insre dans
la chaine juste aprs.
	Cette fonction renvoit l'adresse du nouvel lment (pour l'initialiser
par exemple).

unchain
-------
	adr1 adr2 unchain  :  supprime l'lment adr2 de la chaine, libre
galement la mmoire qu'il occupait,  cet effet adr1 doit tre un lment le
prcdant dand la chaine (pas forcment celui juste avant) afin de raliser le
dchainage correctement.

inchain
-------
	adr1 adr2 inchain  :  insre l'lment dj 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'lment point par adr,
celui-ci non compris, il devient alors le dernier de la chaine (son pointeur 
0) et la place mmoire occupe par ses suivants est  nouveau disponible.

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

previous
--------
	adr1 adr2 previous  :  recherche dans la chaine l'lment prcdant
adr2 (donc celui qui pointe sur adr2). A cet effet adr1 doit tre l'adresse d'un
lment prcdant adr2 (la tte de liste le plus souvent). Si le dbut de
chaine est rang dans une variable p, on utilise:
	p @ adr2 previous	\ p @ donnant l'adresse du premier lment.
	Pour raliser ceci, le programme parcourt toute la chaine jusqu'
trouver l'lment dont le pointeur est adr2. Si cet lment existe, son adresse
est laisse sur la pile, sinon on obtient 0 (c'est le cas si adr2 est lui mme en
tte 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 considre comme libre  nouveau.
	n  settable  : (n>0), cre une nouvelle table de n octets et l'initialise,
la partie haute du dictionnaire est considre comme libre  nouveau.

	Cette table sert  grer les allocations et dsallocations de structures
en haut du dictionnaire. Pour illustrer son principe, supposons qu'on cre 
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 mmoire) 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 efface
	pointeur sur un bloc libre		: celui qu'on vient d'effacer
	pointeur sur un bloc occup	: ceux aprs la structure
	pointeur sur un bloc libre		: le reste de la mmoire
	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 occups,
500 sur des blocs libres et l'indicateur de fin de table: 500*4 + 500*4 + 4,
c'est  dire 4004 octets.
	Tout ceci dpend donc de la manire dont votre programme va agir.
Si il libre les structures dans l'ordre inverse (ou le mme ordre) ou il les
cre, 20 octets seront largement suffisants, si par contre le jeu des allocations
et librations de mmoire est plus sauvage il faudra prvoir au moins 4 fois
le nombre maximal de structures que vous pensez crer, plus 4 octets pour
l'indicateur de fin.
	Par dfaut, la table est longue de 1028 octets, ce qui permet de grer
jusqu'a 256 lments et d'en arriver au pire (la libration d'un sur deux). De
toutes faons, lorsqu'une structure est cre on tente de la rattacher  un
bloc dj existant, ceci n'augmente donc pas la taille de la table (puisque le
nombre de blocs est le mme!), parfois ce nouvel lment permet de
raccrocher deux blocs, ainsi la table est mme rduite!

	Les mots prcdents sont adapts au stuctures cres par le FORTH lui
mme (il s'occupe des pointeurs, des allocations et dsallocations de mmoire,
etc... Mais il se peut que les donnes soient dj en mmoire et qu'on ait besoin d'y
accder de manire claire  l'aide des structures. Pensons en particulier aux
fichiers *.RSC dont chaque objet est dfini par une structure.
	Puisque dans ce cas les donnes existent dj, il nous suffit d'un en-tte de
stucture dont l'adresse des donnes sera fixe par l'utilisateur, c'est justement ce
que fait &pointer.

&pointer
--------
	modle  &pointer  XXX  :  cre le mot XXX qui sera un simple pointeur
sur une sructure conforme au modle. Aucune place mmoire n'est alloue
pour les donnes. Pour fixer l'adresse des donnes, XXX se comporte comme
une variable simple:
	adr  XXX !		\ fixe l'adresse
	A l'excution, XXX laisse l'adresse d'un en-tte.

	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 donnes

	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
						\ donnes, il pointe sur le 5!
	objet ob_x  get_xylh			\ ramne ses 4 coordonnes

	En pratique, si les structures sont colles les unes aux autres, toutes de
mme taille et commenant  l'adresse ADR, la formule est celle-ci pour accder
aux donnes de l'objet d'indice i (indices commenant  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 Crer un type de donnes
**************************

	On a parfois besion de donnes particulires qui ne peuvent pas
s'exprimer  l'aide des types de base. Il faut donc crer un type. Ce type sera
un mot quivalent  variable ou &float ou array etc... qui lui mme crera 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 crer
	2- rserver une zone de 4 octets
	3- donner comme comportement  la variable celui de dposer
l'adresse des 4 octets.

	La syntaxe gnrale d'un type sera:

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

	Le fait que le nom commence par le caractre & assure l'action n1,
c'est  dire l'inclusion du mot suivant dans le vocabulaire (comme &float, ou
&wvar, &name...). Les <actions2> sont donc les initialisations (rservation
de mmoire par exemple, la partie entre :does> et ;end correspondra au
comportement du nouveau mot, le reste, <autres> contiendra des actions
supplmentaires, c'est  dire rien le plus souvent.

:does>   ;end
-------------
	ils encadrent la dfinition d'un mot nouvellement cr. :does> a un
comportement un peu spcial: si il rencontre sur la pile une valeur non nulle,
il l'inclut dans la dfinition du mot en la considrant comme un paramtre
issu des initialisations (souvent l'adresse des donnes), si il rencontre la
valeur 0 rien n'est ajout  la dfinition. De ce fait, 0 ne peut pas tre un
paramtre!

	Crons (ou recrons) le type variable:
	: &VAR
		4 allot		\ rserve de la place et renvoit l'adresse
		:does>	\ l'adresse est place dans la dfinition
		;end		\ la variable ne fait rien d'autre qu'empiler
				\ l'adresse!
	;

	&VAR a		\ cre la variable a
	&VAR b		\ mme chose pour b

	Crons un tableau de nombres rels (genre array mais avec 8 octets
par nombre), le nombre dlments sera pass sur la pile:

	: &farray
		8 * allot0		\ rserve 8*nombre dlments
		:does>		\ adresse passe dans la dfinition
			swap 8 * +	\ caculera adr+8*i
		;end
	;

	5 &farray TABLEAU		\ tableau de 5 rels
	%f5.36  			\ dpose 5.36
	2  TABLEAU 			\ adresse du 3 lment (adr+8*2)
	f!				\ range 5.36  l'adresse indique

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

	Crons 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 mmes
		then
	;
	20  &CONST vingt		\ vingt sera une constante gale  20.
	0 &CONST zro		\ zro sera une constante gale  0.

	Ceci montre que plusieurs :does> ;end sont possibles dans le mme
type pourvu qu'une seule paire soit excute.

::does>   ;end
--------------
	Mme principe que :does> ;end sauf qu'a chaque nouvelle cration de
mot, sa dfinition sera assemble et non interprte. Ce mot sera utilisable
dans un mot assembl (ou compil).