CODINGCLASSEURS WEKA ★ Comment exploiter toutes les ressources et augmenter les performances de votre AMSTRAD CPC ★

4/1.6.6 - Accélérez vos programmes Basic Les tokens (15e Complément)Coding Classeurs Weka
4/0 - Langages du CPC

4/1.6 - Basic approfondi

4/1.6.6 - Accélérez vos programmes Basic Les tokens

Vous le savez tous, le langage de programmation Basic n'est pas la Formule 1 des langages existants. Ceux qui désirent écrire des programmes performants, en vitesse d'exécution, ce qui est le cas pour bon nombre de jeux d'arcades, de programmes de tri de données, ou de gestion graphique, se sont vite heurtés à la lenteur du Basic.

Beaucoup se sont alors intéressés aux langages compilables auxquels le système d'exploitation CP/M leur permet d'accéder : TURBO-PASCAL et C-BASIC. D'autres, au vu des faibles possibilités graphiques de ces langages, ont dû recourir à l'assembleur.

Outre une mise en œuvre plus fastidieuse (il faut d'abord charger CP/M, appeler ensuite le langage, puis compiler, et enfin revenir à CP/M pour lancer le programme créé), ces programmes demandent une étude structurée qui peut sembler rebutante à certains, surtout à ceux qui ont une expérience de longue date sur Basic.

Nous allons dans ce chapitre vous proposer des trucs, des commandes et un programme qui vous permettront d'accélérer les performances des vôtres. Hormis les quelques trucs utilisables sur tous CPCs, il vous faudra néanmoins posséder une unité de disquette pour l'utilisation du programme que nous avons dénommé "ANTI-REM”.

Préambule

Votre première impression après avoir lu les lignes précédentes est peut-être de vous demander pourquoi nous n'avons pas utilisé toutes les astuces que nous détaillerons dans les paragraphes suivants (élimination des espaces inutiles au fonctionnement, des instructions REM ou ').

Sachez que c'est tout d'abord dans un esprit de clarté que nous introduisons parfois des espaces, séparant le nom d'une variable d'un opérateur. Il en est de même dans les noms des variables, quelquefois longs, mais certainement plus significatifs que l'utilisation de la suite A1, A, A3, ..., B$, C$, ... n'ayant pas de rapport avec l'affectation qui leur sont données. Notre souci est aussi de vous permettre de relire et d'étudier plus facilement les programmes que nous vous proposons.

I. Basic-Tortue

Le langage Basic est lent parce que c'est un langage interprété.

Sans nous étendre sur le fonctionnement précis de l'interpréteur Basic de votre Amstrad, sachez que chaque ligne d'un programme, avant exécution, est traduite par les logiciels des ROMs. Chaque instruction est étudiée puis comparée aux instructions en ROM, les variables sont lues une à une pour reformer leur nom qui sera ensuite recherché dans la RAM, éventuellement créé s'il n'existe pas, etc.

Même dans une boucle, tout ce processus est réitéré à chaque passage ainsi dans les lignes :

10 WHILE A < 10000
20 VARIABLE = VARIABLE + 1:REM INCREMENTATION
30 WEND

La recherche de la variable, après lecture est effectuée 2 x 10000 fois. De plus les différents espaces entre le signe = et le signe + sont lus chacun 10000 fois, de même pour l'instruction REM.

II. Vers le Basic-Lièvre

Pour modifier les programmes Basic afin de les rendre plus performants, nous allons devoir travailler sur les chaînes de caractères composant les lignes numérotées.

Or il est impossible de travailler facilement sur un programme directement en mémoire. Il est aussi très difficile de travailler sur le programme sauvegardé sous la forme classique en fichier .BAS.
Les tokens

Pourquoi ? L'interpréteur Basic, après chaque frappe sur la touche ou suivant chaque ligne de programme, compare toutes les instructions qu'il rencontre par rapport à une table qu'il a en ROM, et les traduit en un code, prenant moins de place mémoire, appelé token.

Nous vous proposons ci-après un court programme permettant de lire certains tokens.

10 MODE 2
20 PRINT "LECTURE DE TOKENs"
30 FOR I = &170 TO &200
40 FOR J = 0 TO 8
50 A = PEEK(I + J)
60 A$ = HEX$(A)
70 IF LEN(A$) = 1 THEN A$ = "0" + A$
80 PRINT A$ : SPACE$(2);
90 NEXT J
100 PRINT SPACE$(5)
110 FOR J = 0 TO 8
120 IF (PEEK(I + J) < 32 OR PEEK(I + J) > 127) THEN A = 46 ELSE A = PEEK(I + J)
130 NEXT J
140 PRINT
150 NEXT I

Il faut d'abord savoir qu'un programme Basic débute à l'adresse &170. Le programme précédent va donc lire à partir de &170 tous les octets jusque l'adresse &200 (arbitraire), et les affiche ainsi que leur traduction ASCII quand elle est possible (sinon il affiche un point).

Après lancement, vous pourrez lire comme première liste, la ligne suivante :

octet08000A00AD201000
adresse&170&171&172&173&174&175&176&177

où 08 00 indique le nombre d'octets comportant la ligne, y compris ces deux valeurs (à remettre dans l'ordre : 0008), 0A00 est le numéro de la ligne (retranscrit en inversant : 000A = 10), AD est le code de MODE (voir le tableau ci-après), 20 l'espace, 10 le code de la constante 2 et 00 signalant la fin de la ligne. Ensuite débute la ligne suivante sous le même principe.

Vous pourrez remarquer que pour le nom des variables, il est ajouté la valeur &80 à la valeur ASCII de la dernière lettre.

Vous pouvez ainsi modifier directement le contenu d'une ligne, par exemple en remplaçant le token AD de MODE, en position &174 par le token de PAPER: &BA. Frappez :

POKE &174,&BA puis LIST

et admirez le résultat.

Il est même possible de modifier un numéro de ligne en pokant à l'adresse &173 ou & 172 une autre valeur. Si vous listez, vous aurez la surprise de constater que le numéro de ligne est modifié, par contre sa position est identique.

Nous vous fournissons ci-dessous la liste des tokens utilisés par l'interpréteur Basic, pour vous permettre d'approfondir le sujet.

Grâce à un désassemblage de la ROM du CPC 6128, nous avons retrouvé la liste des tokens Basic de ce modèle, qui ne doivent pas différer des autres, à part les quelques instructions supplémentaires.

80AFTER81AUTO82BORDER
83CALL84CAT85CHAIN
86CLEAR87CLG88CLOSEIN
89CLOSEOUT8ACLS8BCONT
8CDATA8DDEF8EDEFINT
8FDEFREAL90DEFSTR91DEG
92DELETE93DIM94DRAW
95DRAWR96EDIT97ELSE
98END99ENT9AENV
9BERASE9CERROR9DEVERY
9EFOR9FGOSUBA0GOTO
A1IFA2INKA3INPUT
A4KEYA5LETA6LINE
A7LISTA8LOADA9LOCATE
AAMEMORYABMERGEACMID$
ADMODEAEMOVEAFMOVER
B0NEXTB1NEWB2ON
B3ON BREAKB4ON ERRORB5ON SO
B6OPENINB7OPENOUTB8ORIGIN
B9OUTBAPAPERBBPEN
BCPLOTBDPLOTRBEPOKE
BFPRINTC0'C1RAD
C2RANDOMIZEC3READC4RELEASE
C5REMC6RENUMC7RESTORE
C8RESUMEC9RETURNCARUN
CBSAVECCSOUNDCESTOP
CFSYMBOLD0TAGD1TAGOFF
D2TROND3TROFFD4WAIT
D5WENDD6WHILED7WIDTH
D8WINDOWD9ZONEDAWRITE
DBDIDCEIDDFILL
DEGRAPHICSDFMASKE0FRAME
E1CURSORE2non définiE3ERL
E4FNE5SPSE6STEP
E7SWAPE8non définiE9non défini
EATABEBTHENECTO
EDUSINGEE>EF=
F0> =F1<F2< >
F3< =F4+F5
F6*F7/F8
F9\FAANDFBMOD
FCORFDXORFENOT
FF 00ABSFF 01ASCFF 02ATN
FF 03CHR$FF 04CINTFF 05COS
FF 06CREALFF 07EXPFF 08FIX
FF 09FREFF 0AINKEYFF 0BINP
FF 0CINTFF 0DJOYFF 0ELEN
FF 0FLOGFF 10LOG10FF 11LOWER$
FF 12PEEKFF 13REMAINFF 14SGN
FF 15SINFF 16SPACE$FF 17SQ
FF 18SQRFF 19STR$FF 1ATAN
FF 1BUNTFF 1CUPPER$FF 1DVAL
FF 1E à FF 3F NON AFFECTES
FF 40EOFFF 41ERRFF 42HIMEM
FF 43INKEY$FF 44PIFF 45RND
FF 46TIMEFF 47XPOSFF 48YPOS
FF 49DERRFF 4A à FF 70 NON AFFECTES
FF 71BIN$FF 72DEC$FF 73HEX$
FF 74INSTRFF 75LEFT$FF 76MAX
FF 77MINFF 78POSFF 79RIGHT$
FF 7AROUNDFF 7CTEST
FF 7DTESTRFF 7FVPOS

En plus de ces tokens concernant les instructions, on trouve les tokens signalant les fins de blocs d'instructions, les variables, les constantes, les valeurs de tout type, et fin de ligne :

00 fin de ligne
01 fin de bloc d'instruction
02 variable entière suivie du nom codé en ASCII (plus &80 pour le code ASCII du dernier caractère)
03 variable de caractère (identique à ci-dessus)
04 variable réelle (identique à ci-dessus)
0D variable non définie (identique à ci-dessus)
0E chiffre 0
0F chiffre 1
10 chiffre 2
11 chiffre 3
12 chiffre 4
13 chiffre 5
14 chiffre 6
15 chiffre 7
16 chiffre 8
17 chiffre 9
18 non défini
19 valeur sur un octet suivi de la valeur
1A valeur décimale (2 octets)
1B valeur binaire (2 octets)
1C valeur hexadécimale (2 octets)
1D adresse de ligne
1E numéro de ligne
1F valeur en virgule flottante (5 octets)

Remarques :

Les tokens &1D et &1E :

Lorsque vous entrez une ligne du type :

40 GOTO 20

le renvoi à la ligne 20 est codé une première fois par le numéro de ligne en hexadécimal (on trouvera donc le code &1E le précédant). Puis, lors d'une exécution, l'interpréteur recherche la position de la ligne dans la mémoire, puis remplace le numéro de ligne par son adresse effective, ce qui permettra d'accélérer ensuite l'exécution. Il signale l'adresse en remplaçant le code &1E par le code &1D.

Lors d'un listing, d'une insertion de ligne, ou d'une destruction, il lui sera ensuite facile de retrouver le numéro de ligne, puisqu'il se trouve en troisième et quatrième position à partir de l'adresse.

La sauvegarde ASCII

Sachant, que, lorsque vous sauvegardez le programme Basic sous la forme habituelle :

SAVE "PROG.BAS''

vous comprendrez après toutes les explications précédentes qu'il va devenir fastidieux de traiter tous ces tokens. De plus l'utilisation de l'instruction :

OPENIN "PROG.BAS”

pour récupérer les codes provoque le message d'erreur :

File type error

La solution est de sauvegarder le fichier sous sa forme ASCII, c'est-à-dire caractère par caractère par la commande :

SAVE "PROG.ASC”,A

III. La bonne utilisation des variables

Une première modification possible, mais manuelle, vous permettra de gagner en vitesse d'exécution, notamment dans les boucles de type FOR ... NEXT, WHILE ... WEND et dans les sous-programmes souvent appelés par GOSUB ou ON GOSUB...

Il vous faudra manuellement repérer les variables qui sont utilisées dans le format ENTIER, c'est-à-dire qui ne comporteront que des valeurs de - 32768 à + 32767. Vous pourrez alors les définir de type ENTIER par l'instruction :

DEFINT liste de variables

Par la même occasion, repérer les variables réelles et chaîne de caractères que vous définirez par :

DEFREAL et DEFSTR.

Si cela est possible, utilisez des noms de variables courts, car le programme les relit entièrement avant de les rechercher dans la mémoire.

Vous pourrez aussi regrouper des lignes de programmes non concernées par les branchements de type GOTO, GOSUB... ou les tests (condition IF... THEN... ELSE), en une seule ligne, mais ceci est préjudiciable à la clarté du programme ; vous éviterez donc de l'effectuer sur la version originale.

D'autres possibilités vous sont offertes pour améliorer les temps d'exécutions, nous vous proposons ci-après des programmes qui permettront d'automatiser les actions à effectuer.

IV. Eliminons les blancs inutiles

Un truc connu probablement par beaucoup d'entre vous, pour permettre à l'interpréteur d'éliminer automatiquement les espaces indésirables, est de frapper la commande :

POKE &AC00,1 avant toute entrée de ligne de programme.

Seulement, pour des facilités de corrections ultérieures en cas d'erreur, nous vous conseillons d'entrer nos programmes tels qu'ils sont décrits, ou de frapper les vôtres sans être avare d'espaces.

Nous vous conseillons dans un premier temps de sauvegarder le programme sous une forme de fichier ASCII par la commande :

SAVE "PROG.ASC'',A Une autre possibilité pour sauvegarder le programme sous forme ASCII est d'ouvrir un fichier au nom du programme par l'instruction OPENOUT, puis de lister le programme par l'intermédiaire de l'unité de sauvegarde : OPENOUT "PROG.ASC"

LIST #9 CLOSEOUT

Vous pourrez ensuite utiliser la case mémoire précédente (&AC00) pour éliminer les blancs, mais sous une forme différente. Le truc étant de recharger le programme précédent après avoir frappé le POKE salutaire. Voici donc l'ordre des opérations à effectuer :

SAVE "PROG.ASC",A
POKE &AC00, 1
LOAD "PROG.ASC"
SAVE "PROG.BAS"

Vous disposerez ainsi sur votre unité de sauvegarde de deux versions du programme : la version ASCII que vous pourrez réutiliser ultérieurement afin d'y effectuer des modifications ou des études sur certaines portions, et la version Basic sans blanc, plus optimisée pour l'exécution.

V. Fini le blabla...

Tout comme les espaces, l'instruction REM, utilisée pour ajouter des commentaires, allonge considérablement les temps d'exécution, surtout dans les boucles.

Nous avons donc conçu un programme qui enlève automatiquement les instructions REM et leurs commentaires associés.

La réflexion, qui s'est imposée, concerna les différentes façons d'écrire l'instruction dans un programme.

  • Premièrement REM peut se trouver seul dans une ligne Basic, telle la ligne

10 REM *** PROGRAMME MACHIN ***

Si l'on supprime toute l'instruction, il nous restera une ligne vide portant le numéro 10. Deux cas peuvent alors se présenter :

— soit il est possible de supprimer la ligne sans porter préjudice au fonctionnement du programme ;
— soit une autre ligne fait référence à celle-ci, et dans ce cas il est hors de question de la supprimer, sous peine de plantage.

Il vous appartiendra de vérifier ce deuxième cas, et d'effectuer les modifications nécessaires, pour utiliser l'une ou l'autre version du programme que nous vous proposons.

  • Deuxièmement REM peut se trouver en fin d'une ligne comportant une ou plusieurs instructions, comme par exemple :

20 PRINT "PROGRAMME MACHIN":REM AFFICHAGE

Notre programme devra donc supprimer la fin de la ligne REM + commentaire, mais aussi le caractère : devenu inutile.

  • Troisièmement REM peut faire partie du nom d'une variable :

30 FLAGREM = 2 Il ne faudrait pas supprimer le REM et sa suite.

  • Quatrièmement il faudra être vigilant à ne pas supprimer les REMar-ques insérées entre guillemets, qui sont réservées à l'affichage :

40 INPUT "FRAPPEZ REM POUR LA SUITE";A$

Ce qui serait quelque peu embarrassant pour la compréhension du programme, voire son déroulement.

Nous avons de plus réservé la possibilité quelquefois intéressante de pouvoir mettre des instructions en remarques, instructions qui se trouveraient replacées dans le programme, suite à l'utilisation du logiciel que nous vous proposons. Il suffirait d'insérer le caractère : (deux points) entre la remarque et l'instruction.

50 REM: ON BREAK CONT

ou

50 REM A ELIMINER: ON BREAK CONT

deviendront

50 ON BREAK CONT

L'algorigramme

L'étude des quatre cas précédents nous a permis de préciser le schéma général du programme, que nous avons décomposé en sous-programmes reconnaissant les différentes possibilités.

Voici l'algonigramme proposé pour le programme principal :


On s'aperçoit, qu'après avoir demandé le nom du programme à traiter (en ASCII) le programme va ouvrir un fichier temporaire en écriture pour y sauvegarder les lignes traitées.

Tant que la fin du fichier n'est pas atteinte, chaque ligne sera lue et traitée caractère par caractère. Le compteur est affiché pour signaler au programmeur que le programme n'est pas planté (dans le cas de programmes longs).

Vous remarquerez que lorsque l'instruction REM a été détectée, le compteur est incrémenté sans sauvegarde du caractère en cours de traitement.

Le sous-programme de recherche de guillemets aura la structure suivante :

On remarquera que la variable FLAG (ou indicateur) est une variable que l'on pourrait appeler à bascule, puisqu'elle prendra la valeur 1 si un guillemet est détecté une première fois, puis 0 lorsque l'on refermera ces guillemets.

REM sera traité selon l'algonigramme suivant :

La reconnaissance des deux points signalant la fin d'une instruction REM aura la forme :

Enfin avant de sauvegarder chaque ligne, il faudra vérifier si elle est vide, ce qui sera réalisé par le sous-programme page suivante.

Après lecture du numéro de ligne, signalée par la présence du premier ESPACE de la ligne, le programme recherche si un caractère se présente avant la fin de la ligne, smon il crée une variable de sauvegarde vide.

Le programme

Des algongrammes précédents, voici le programme Basic commenté



Le listing ci-dessus considère qu'aucun saut n'est effectué à une ligne contenant uniquement une instruction REM, donc élimine ces dernières sans pitié.

Au cas où le programme contient des sauts à des adresses de commentaires, vous pouvez modifier la ligne contenant les instructions :

IF COMPT = LONG THEN SAUV = " ":RETURN par IF COMPT = LONG THEN SAUV = CHR$(39):RETURN

Nous allons récapituler la procédure d'amélioration de la rapidité de vos programmes :

a) Sauvegardez une version originale sous forme ASCII par SAVE "PROG1 .ASC",A

b) Déclarez si possible toutes les variables selon leur utilisation.

c) Regroupez les lignes pouvant l'être en une seule ligne.

d) Sauvegardez le programme sous forme ASCII par SAVE "PROG2.ASC",A

e) Entrez POKE &AC00,1 puis chargez le programme par LOAD "PROG2.ASC", que vous resauvegardez aussitôt sous le même nom, et en ASCII comme ci-dessus.

f) Lancez la version que vous aurez choisi du programme suppresseur de REM (il faut obligatoirement un lecteur de disquette à partir de cette étape).

g) Chargez la version temporaire du programme, qui est sauvegardée en ASCII (LOAD "TEMP.ASC") et sauvegardez-la aussitôt en Basic sous le nom final (SAVE "PROG.BAS").

Je participe au site:

» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 061 millisecondes et consultée 470 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.