Dernière intervention le 25/11/2003
Premier projet : lire le fichier texte contenu dans cette page et le
transformer en fichier HTML en ajoutant :
- un en-tête simplifié
- les balises de fin de paragraphe
- la fin de fichier
Sur l'internet, on peut trouver des propositions de code pour la
concaténation en utilisant la syntaxe de Gforth. C'est le
cas de la séquence suivante ...
Le codage me semble très inspiré de "la
pensée unique C" et ne me satisfait pas. Ce qui suit propose
une approche différente, dont on pourra choisir de
s'inspirer ou non.
Le texte contenu dans la chaine exemple servira pour
différents tests, ce qui explique son contenu un peu
surprenant.
Gforth dispose du mot ***D s" ***F pour empiler une chaîne
(sur la pile... pléonasme).
Par exemple, la séquence :
s" ##Ceci est le titre de rang deux, il sera suivi d'une
[http://lerautal.free.fr->Adresse de mon site ainsi que du texte
{en italique} et même {{en gras}}" ok
...empile successivement l'adresse de la chaîne
puis sa longueur.
Il est facile de vérifier ceci en entrant frappant .s
{ exemple : }
.s <2> 134691336 152 ok
(ici <2> = profondeur de la pile, 134691336
= adresse de la chaîne, 152 = longueur de celle-ci.
Remarque : la documentation de Gforth signale que le comportement de s"
est différent à la compilation et à
l'exécution.
Gforth dispose de deux mots complémentaires :
create
crée une entrée dans le dictionnaire
(et crée donc la variable);
nb allot
réserve "nb" octets pour le stockage dans cette
variable.
Application : créer une variable appelée source,
de 256 octets (dont le premier sera réservé pour
stocker la "longueur utile".
create depart 256 allot
Vérification :
depart
(empile l'adresse de la variable)
.s <3> 134691336 152 1075479616 ok
(ici la pile s'est augmentée d'une valeur qui
correspond à l'adresse de la variable).
Les conventions suivantes ont été choisies :
- le premier octet contient la "longueur utile" de la chaine
- les octets suivants contiennent le texte lui-même
- la longueur utile représente le nombre d'octets du texte
effectivement rangé dans la chaine. Par exemple si l'on
range "pomme" dans une chaine de 256 caractères, la longueur
utile sera de 5 caractères.
On charge la longueur utile ainsi :
depart longueur c!
Gforth dispose du mot ***Dcmove ***F qui est décrit ainsi
dans la documentation de Gforth :
cmove c-from c-to u -- string ``c-move''
Copy the contents of ucount characters from data space at c-from to
c-to. The copy proceeds char-by-char from low address to high address;
i.e., for overlapping areas it is safe if c-to=<c-from.
Syntaxe :
addr_source addr_cible 1 + nb_d'octets_à_copier
cmove
Si maintenant, nous entrons au clavier
s" texte..." variable cmove
... nous allons rencontrer une difficulté du
fait que nb_d'octets_à_copier est mal placé dans
l'ordre d'exécution.
La bonne liste d'instruction est
s" ##Ceci est le titre de rang deux, il sera suivi d'une
[http://lerautal.free.fr->Adresse de mon site] ainsi que du
texte {en italique} et même {{en gras}}" ( texte et longueur
empilés -- adr1 nb )
dup ( -- adr1 nb nb )
depart dup ( -- adr1 nb nb adr2 adr2 )
rot ( -- adr1 nb adr2 adr2 nb )
swap ( -- adr1 nb adr2 nb adr2 )
c! ( -- adr1 nb adr2 )
1 + ( -- adr1 nb adr2+1 )
swap cmove ( -- ) ***F
Gforth dispose du mot
type
Syntaxe :
addr_variable nb_caracteres type
{Exemples :}
depart 1 + 10 type
donne
"##Ceci est "
depart 11 + 20 type
donne
"le titre de rang de"
Remarque : l'adresse de début d'affichage a
été décalée de 10
caractères.
Pour afficher la chaîne sans connaitre sa longueur, on fera :
depart dup c@ swap 1 + swap type
On pourra même créer un mot listant
le contenu de la chaîne :
: l-chaine dup c@ swap 1 + swap type ;
que l'on utilisera ainsi :
depart l-chaine
Voici le code source du script chaine.fs qui permet de
vérifier ce qui a été écrit
ci-dessus.
#! /usr/local/bin/gforth
create depart 256 allot
: l-chaine dup c@ swap 1 + swap type ;
s" ##Ceci est le titre de rang deux, il sera suivi d'une
[http://lerautal.free.fr->Adresse de mon site] ainsi que du
texte {en italique} et même {{en gras}}" ( texte et longueur
empilés -- adr1 nb )
dup ( -- adr1 nb nb )
depart dup ( -- adr1 nb nb adr2 adr2 )
rot ( -- adr1 nb adr2 adr2 nb )
swap ( -- adr1 nb adr2 nb adr2 )
c! ( -- adr1 nb adr2 )
1 + ( -- adr1 nb adr2+1 )
swap cmove ( -- )
depart l-chaine
bye
Nous allons nous occuper d'un traitement
élémentaire : ajouter <br />
à la fin de chaque paragraphe du fichier texte.
Pour pouvoir manipuler, nous garderons la chaîne "depart" de
l'exemple précédent.
adr1 désigne l'adresse du contenu à
concaténer (ici "<br />")
nb1 désigne la longueur de cette chaine
adr2 désigne l'adresse de début de la chaine
cible (ici la variable depart)
nb2 désigne la longueur utile de cette chaine
adr3+1 désigne le début de la zone où
doit s'effectuer la copie de "<br/>"
A la fin, le premier octet de depart contient la nouvelle longueur.
depart ( -- adr2 )
dup ( -- adr2 adr2 )
c@ ( -- adr2 nb2 )
+ ( -- adr3 )
s" <br/>" ( -- adr3 adr1 nb1 )
dup ( -- adr3 adr1 nb1 nb1 )
depart ( -- adr3 adr1 nb1 nb1 adr2 )
c@ ( -- adr3 adr1 nb1 nb1 nb2 )
+ ( -- adr3 adr1 nb1 nb3 )
depart ( -- adr3 adr1 nb1 nb3 adr2 )
c! ( -- adr3 adr1 nb1 )
rot ( -- adr1 nb1 adr3 )
1 + ( -- adr1 nb1 adr3+1 )
swap ( -- adr1 adr3+1 nb1 )
cmove ( -- )
Vérification par
depart l-chaine ( liste le contenu )
Le travail présenté aux paragraphes 10 et 11
est-il cohérent avec ce qui se passe quand on lit et
écrit un fichier de texte ?
Le script suivant permet de vérifier :
#! /usr/local/bin/gforth
256 Constant max-line
Create chaine max-line allot
( ouverture du fichier source )
s" page.txt" r/o open-file throw Value fd-in
( charge la première ligne du fichier texte dans la variable
chaine )
chaine max-line fd-in read-line throw
fd-in close-file throw ( ferme le fichier source )
chaine c@ . donne 71
Or 71 est le code
ASCI de la lettre G, qui est la première lettre du texte, et
non dsa longueur.
Si maintenant, on veut lister la chaine, on pourra entrer :
chaine 50 type qui donne :
Gloire au dix-septième
ÌÌÌÌÌ3...
On constate un saut à la ligne (FF = code ASCI
12) au 22ème caractère.
La longueur utile de la chaine est ici de 22 caractères. Y
avait-il un moyen de le savoir ?
Une réponse un peu plus attentive de la documentation de
Gforth permet de répondre oui.
La définition de read-line est la suivante :
read-line c_addr u1 wfileid - u2 flag wior
... et l'on remarque que u2, longueur de la chaine fait
partie des éléments transmis par le mot Forth.
Nous allons récupérer cette valeur dans une
variable numérque appelée n1 par :
variable n1 0
chaine max-line fd-in read-line drop drop n1 !
... puis vérifier que le résultat
est le bon par :
." longueur : " n1 @ .
cr
." contenu : " chaine n1 @ type
Il est possible de récupérer la longueur de la
chaîne au moment où on la lit dans le fichier
texte.
Le script ci-dessous, appelé creepageconcat.fs, permet la
réalisation du premier projet :
#! /usr/local/bin/gforth
256 Constant max-line
Create chaine max-line allot
variable n1 0 ( longueur de la chaine lue dans le fichier )
variable n2 0 ( longueur de la chaine ajoutée )
variable n3 0 ( longueur résultante )
( ouverture des fichiers cible et source )
s" /home/alain/siteforth/page3.html" w/o create-file throw Value fd-out
s" /home/alain/siteforth/page3.txt" r/o open-file throw Value fd-in
: ecri-dans ( écrit dans le fichier cible ) fd-out
write-file throw ;
: ferm-dans ( ferme le fichier cible ) fd-out close-file throw ;
: ferm-source ( ferme le fichier source ) fd-in close-file throw ;
: concat_br ( concaténation )
s" <br />" dup n2 !
chaine n1 @ + swap cmove
n2 @ n1 @ + n3 !
12 n3 @ chaine + c! ;
: vide-fichier ( effectue le transfert source vers cible )
begin
chaine max-line fd-in read-line throw
swap dup n1 ! swap
while
concat_br
chaine n3 @ ecri-dans
repeat ;
( création de la page web cible )
s" <html> <body>" ecri-dans
vide-fichier
s" </body></html>" ecri-dans
( fermeture des deux fichiers )
ferm-source
ferm-dans
bye
Le script permet de réaliser le premier projet.
Il faut parfois expérimenter beaucoup... surtout si on lit
mal la documentation.
Haut de page