Programmes - analyse, mots clefs et jetons
Un programme est entreposé, physiquement, sous forme de fichier. Logiquement, il est organisé comme ce qu'on appelle traditionnellement un fichier séquentiel. C'est-à-dire un fichier d'enregistrements (lignes) de longueurs variables, un enregistrement suivant l'autre, séquencé dans l'ordre 1-2-3.
Si vous enregistrez un programme sous forme de fichier ASCII (SAVE "programme", A), il est en fait sorti selon les conventions désormais connues sous le nom de «... fichier séquentiel standard».
Chaque ligne de votre programme est un enregistrement de longueur variable. Les deux derniers octets de chaque enregistrement sont une paire CR/LF (un retour chariot et un saut de ligne). La fin du fichier est marquée par un seul octet (code de Ctrl+Z) immédiatement après le dernier enregistrement. Tous les octets, dans tous les enregistrements, sont des codes de caractères ASCII standard. (Sauf ceux au-dessus de CHR$(127), n'étant pas vraiment ASCII.)
Et à un moment donné, la plupart des programmeurs novices écrivent des programmes expérimentaux pour "lire" les fichiers de programme. Certains passent rapidement à l'étape suivante et écrivent des programmes "écrivant" des programmes.
Les générateurs de programmes, en tant que concept, sont aussi anciens que l'activité de programmation elle-même. La première fois qu'un programmeur très expérimenté doit écrire quelques centaines de lignes se ressemblant beaucoup, il est très probable qu'il écrive un "outil" pour générer ces lignes automatiquement.
Au moment où la plupart des étudiants sont arrivés aussi loin, ils commencent également à souhaiter avoir plus d'outils. Et les vétérans d'autres langages de programmation remarquent très rapidement l'absence flagrante d'outils dans cet environnement.
Cette page cherche à combler un autre vide. Lorsque votre monde dicte le besoin d'outils sur mesure, devant fonctionner sur des programmes tels qu'ils sont en mémoire, ou tels qu'ils sont dans des fichiers ayant été enregistrés en tant que "binaires", ce qui se trouve dans ces octets doit être connu. Ce détail minutieux est fourni ici, mais pas seulement pour le bénéfice des rédacteurs d'outils.
Souffrez que mon affirmation préférée se répète souvent ailleurs : pour pouvoir écrire des programmes s'exécutant aussi efficacement que possible, il faut comprendre le fonctionnement de l'interpréteur. Cette page peut être lu pour approfondir cette idée, en savourant les concepts généraux, en sautant rapidement le cartilage.
Un bref préambule est nécessaire avant d'entrer dans le vif du sujet. Plus une note technique est explicite, plus elle est susceptible de se tromper. Pas à cause d'erreurs (étant certainement possibles), mais plus probablement parce que nous ne voyons pas exactement la même chose. Le monde change constamment autour de nous, et ce cliché est tellement applicable au monde de la programmation. Au cas où vous rencontreriez un octet tordu dans ce qui suit, percevez-le comme un simple caillou dans un ruisseau rapide : pataugez.
Un programme est entreposé, physiquement, sous forme de fichier. Logiquement, il est organisé comme ce qu'on appelle traditionnellement un fichier séquentiel. C'est-à-dire un fichier d'enregistrements (lignes) de longueurs variables, un enregistrement suivant l'autre, séquencé dans l'ordre 1-2-3. Cette répétition est toujours fondamentalement vraie, mais à partir de maintenant, lorsque vous enregistrez un programme sans l'option A-pour-ASCII, c'est un tout nouveau jeu de balle.
Un fichier de programme est, essentiellement, ce que l'on appelle parfois un vidage de mémoire d'image miroir sur le disque. C'est pourquoi l'activité de type LOAD et SAVE est rapide : La lecture et l'écriture se font sur la base de blocs physiques, et non au niveau de la ligne logique, ou de l'enregistrement. En mémoire (et donc sur disque), un programme est toujours organisé en interne sous forme de lignes discrètes, disposées par ordre de numéro de ligne, comme vous les voyez avec LIST ou LLIST.
Certes, cela peut être appris par une lecture attentive de la plupart des manuels. Certains mentionnent que les lignes sont entreposées sous une forme compacte, compressée ou en jeton. Ce qui est à peu près aussi loin que n'importe lequel d'entre eux va. Incontestablement, le programme d'interprétation est un logiciel spécial très sophistiqué, très compliqué. Mais cela reste un programme. Il "traite" votre programme. Cela commence là où vous le faites, sur la première ligne, en examinant chacune de vos déclarations, en faisant ce que vous lui dites de faire, une étape à la fois.
Cette définition grossièrement sous-estimée et trop simplifiée de l'interprète est la perspective fondamentale à partir de laquelle lire ce qui suit. Le but est de voir ce qui se trouve dans les lignes de programme elles-mêmes. Voyant cela, nous pouvons souvent deviner ce que l'interprète doit faire. Comment il le fait réellement peut rester obscur.
Toutes les lignes commencent par les quatre premiers octets ayant le même ordre et le même objectif, et se terminent par un octet égal à CHR$(0). Les deux premiers octets sont une paire d'adresses. Ils contiennent l'adresse réelle du début de la ligne suivante. En commençant par les deux octets suivants, la paire contenant votre numéro de ligne, tout ce qui se trouve dans une ligne est exactement dans le même ordre que lorsqu'elle est vue comme une ligne de texte ASCII. Là s'arrête sa similitude. Les bits dans les octets eux-mêmes sont formulés pour convenir à l'interpréteur.
Certains octets coïncident toujours avec l'ensemble de caractères ASCII et leur interprétation reste inchangée. Étant donné que n'importe quel octet donné peut s'étendre sur le spectre complet de 8 bits de 0 à 255, en nombres décimaux, la plupart d'entre eux ressembleront forcément à des caractères affichables. Mais un octet ressemblant à un CHR$(65) peut ne pas être du tout pour la lettre "A". Il peut s'agir d'un code, ou d'une partie d'un code, ou d'un nombre, ou d'une partie d'un nombre, ou...
Les octets d'une ligne sont analysés comme des codes à 1 octet ou comme des mots (groupes d'octets). Un mot peut être aussi petit que 1 octet. Certains sont 2, d'autres 4, et naturellement, certains sont 8. Saisissez maintenant ce fil qui est tissé tout au long de la programmation en langage machine : des octets de 8 bits utilisés comme mots de 1, 2, 4 ou 8 octets.
Presque tous les soi-disant "mots clefs" en BASIC sont entreposés sous forme de jetons (codes). Lorsque vous tapez une ligne d'un programme à l'aide de l'éditeur BASIC, le texte de ce que vous tapez est traduit. Le mot clef BEEP est entreposé sur un seul octet, par exemple ; il ressemble à un CHR$(197). Lorsque vous voyez BEEP, un jeton égal au nombre 197, en décimal, a été retraduit dans les quatre lettres ASCII majuscules épelant BEEP.
À partir de maintenant, supposons que tous mes nombres sont décimaux. Continuer à utiliser des phrases pour s'assurer que 197 est compris comme signifiant un octet équivalent à CHR$(197) est redondant. Cela ralentit votre lecture, et mon écriture.
De nombreux jetons de mots clefs sont, en fait, des codes à deux octets. Le premier octet sert d'indicateur que le jeton dans l'octet suivant provient d'une autre table de traduction. Le jeton pour SWAP est 164 et le jeton pour LOC est également 164. Ainsi, un octet de jeton de 164 est soit pour SWAP, soit pour LOC, selon la table utilisée pour la traduction, c'est-à-dire si le jeton est précédé ou non d'un octet indicateur d'une table de 255.
En tout, il y a quatre tableaux de mots clefs. Le jeton de 129 octets unique se traduit par END. Un 255 octets suivi de 129 est traduit par LEFT$, un 254 puis un 129 est pour FILES, et 253 suivi de 129 signifie CVI.
Étant donné que le premier octet dicte comment le jeton le suivant doit être traduit, nous pouvons obtenir un aperçu immédiat du fonctionnement réel de l'interpréteur. Il traite une ligne de gauche à droite, un octet à la fois. Sur la base de ce qu'un octet contient, il peut procéder au rythme d'un octet à la fois ou engloutir 2, 4 ou 8 octets pour son tour suivant.
Lorsqu'un programme est "en cours d'exécution", lorsque l'interpréteur tombe sur un 253 octets, par exemple, il sait que l'octet suivant est un jeton, et ce sera un appel de fonction pour faire CVI, CVS, CVD, MKI$, MKS$, MKD$ ou EXTERR (car seuls 7 jetons uniques doivent suivre un octet qui en contient 253).
Remarquez comment "un octet" indique ce qui devrait être attendu ensuite. Être capable d'analyser une ligne - pour la séparer en mots d'unités lexicales) - nécessite simplement un algorithme imitant la logique de la façon dont l'interprète le fait. Et ce n'est pas très compliqué du tout.
Construire un outil traduisant le nombre 145 dans le mot PRINT, par exemple, ne demande pas beaucoup d'efforts. Ce qu'il faut en termes de routines pour exécuter une commande telle que PRINT peut prendre plusieurs centaines de lignes de programme. Sans voir ces lignes, ni même connaître les langages machine, nous pouvons apprécier les longues heures et le travail acharné ayant été consacrés à l'écriture de l'interprète lui-même. En parcourant une ligne, un octet à la fois, tout comme ce programme le fait, nous pouvons cependant saisir les principes de base selon lesquels il fonctionne. Comme ça :
Commencez au début : La première ligne de votre programme. Les deux premiers octets sont une paire d'adresses. Pour obtenir leur valeur décimale, le cas échéant, multipliez le deuxième octet par 256 et ajoutez à cela la valeur du premier octet. Et prenez note. Ce même exploit arithmétique peut être utilisé pour convertir tous les mots de 2 octets représentant des adresses ou des numéros de ligne. (Qui sont entreposés dans le fonctionnement du langage machine, c'est-à-dire à l'envers par rapport à la façon dont nous le ferions dans notre tête.)
Ajoutez 2 à votre pointeur d'octet. La prochaine paire d'octets est également un mot de 2 octets. Faites le calcul. Et voilà, le résultat est égal au numéro de ligne que vous avez utilisé lors de la création de cette ligne de programme. Maintenant, incrémentez votre pointeur d'octet de un et préparez-vous à vous amuser vraiment.
Si l'octet suivant est 32, 44 ou 58, il s'agit d'un espace, d'une virgule ou de deux-points, comme en ASCII. Si l'octet suivant est zéro, vous avez atteint la fin de la ligne. S'il est supérieur à 128, il s'agit d'un jeton de mot clef. Si aucun de ces tests n'est vrai, vous regardez maintenant quelque chose que vous avez inventé - un littéral, une constante ou un nom de variable - ou votre pointeur est au mauvais endroit. Ou vous essayez de lire le courrier de quelqu'un d'autre.
À ce stade, si vous écrivez réellement un outil de programmation, ce que vous voulez voir le plus, ce sont les tableaux à la fin de cette page. Mais ne commencez pas encore à coder. Il serait utile de savoir comment les informations contenues dans ces tableaux ont été compilées. (Au cas où votre version de l'interprète diffère de la mienne.) Et, il y a quelques bribes devant être connues qui ne sont pas évidentes en regardant uniquement les graphiques.
Essayez LCOPY = 1 et vous obtiendrez une erreur de syntaxe. LCOPY 0, en revanche, ne génère aucune erreur, mais ne fait rien non plus. LCOPY est une commande absente. Cela n'a fonctionné que dans une seule version, mais cela fonctionne maintenant simplement comme un Pas d'opération.
Pour savoir exactement quel jeton est utilisé pour représenter un mot clef donné, tapez-le comme premier mot dans un programme BASIC. Enregistrez-le, puis utilisez DEBUG - ou un autre outil - pour voir exactement en quoi l'interpréteur a converti ce mot. Soit dit en passant, le tout premier octet d'un fichier programme sauvegardé est un indicateur de type de fichier. (Il peut s'agir de 255, ce qui indique un programme BASIC "normal" ; 254 indique qu'il a été enregistré avec l'option "protéger".) N'oubliez pas également de sauter les quatre premiers octets au début de chaque ligne avant de commencer à chercher un jeton de mot clef.
Un premier octet de 254 ou 255 ne signifie pas toujours que ce qui suit est un programme BASIC ; c'est simplement ce que l'interpréteur recherche pour "savoir" si le fichier que vous chargez est un programme BASIC en jeton.
Si vous ne connaissez pas tous les mots clefs intégrés à votre version de l'interpréteur, il existe un moyen de le savoir. Mais ce n'est pas particulièrement facile. Malheureusement, ils ne sont pas tous indiqués dans tous les manuels, et certains, bien que contenus dans un manuel, peuvent ne pas figurer dans votre logiciel. Retournons à DEBUG. Videz l'interpréteur lui-même. Recherchez ce qui ressemble aux mots réservés BASIC. Ils ne sont pas entreposés en ASCII pur ; la première lettre d'un mot et la dernière lettre, ou les deux, peuvent ressembler à du charabia, mais les lettres au milieu des plus longues comme RANDOMIZE sont toujours reconnaissables comme des lettres majuscules ASCII.
Plus que de simples tableaux précis de mots clefs et de leurs jetons sont nécessaires. Voici quelques autres choses intéressantes à attendre lors de l'analyse des lignes BASIC. Et quelques informations supplémentaires sur le fonctionnement de l'interpréteur lorsqu'il exécute un programme.
Les littéraux numériques sont entreposés sur une ligne dans exactement le même format que si vous les aviez affectés à la variable la moins précise étant nécessaire pour les contenir. Par exemple : -32000 est entreposé sur deux octets (exactement comme dans une variable entière). Ce littéral en ligne est précédé d'un code - 28 indiquant que ce qui suit est un mot de 2 octets et qu'il doit être traduit par un entier. Voyez maintenant pourquoi il arrive que, bien que vous ayez tapé A=99999, plus tard vous verrez A=99999 ! quand vous faites une LIST. (Les nombres entiers n'obtiennent pas d'un index libre, mais tous les nombres plus grands en ont, ou ils sont lus comme si vous les aviez tapés en utilisant une notation pseudo-scientifique.)
Ce même concept est vrai pour toutes les valeurs en ligne. Ils sont entreposés dans un format prêt à l'emploi. Aucune conversion n'est nécessaire. L'interprète peut saisir un mot de 1, 2, 4 ou 8 octets et l'utiliser instantanément, tel quel. Il est préférable de faire la conversion pendant que vous tapez. Vous ne saurez même pas quand ce sera fait. (Peu de dactylographes peuvent dépasser un micro moderne.) Voyez aussi pourquoi une MERGE peut prendre un certain temps : il y a beaucoup de conversions en cours pendant le processus de chargement.
Il existe un type de conversion ayant lieu pendant l'exécution d'un programme. Si vous fouillez dans la mémoire des programmes pendant qu'un programme est en cours, faites attention à celui-ci.
GOTO, par exemple, est suivi d'un numéro de ligne. Les numéros de ligne sont entreposés dans des mots de 2 octets. Ils sont normalement précédés d'un octet code - 14. Lorsque l'interprète tombe sur le 14, il parcourt votre programme pour trouver la ligne ayant le numéro de ligne correspondant. Maintenant, la partie délicate : les trois octets après le GOTO sont modifiés. Le code passera de 14 à 13 et l'adresse réelle de la ligne cible écrasera les deux octets de numéro de ligne.
La conversion des adresses traduites en numéros de ligne peut être effectuée très rapidement, soit dit en passant. Si vous tombez sur un code - 13, utilisez l'adresse le suivant pour obtenir la paire d'octets inchangée depuis le début (+2) de la ligne cible et modifiez l'octet de tête de 13 à 14.
La plupart du temps, vos variables ressemblent à celles que vous avez saisies. Sous forme de lettres majuscules ASCII, de chiffres et d'index. Une exception est le cas d'un nom de fonction défini par l'utilisateur. Le FN lui-même est converti en un jeton de 1 octet (209), mais le reste de votre nom reste inchangé.
Une confusion - et pas une petite aggravation - peut survenir lorsque vous analysez uniquement des variables. Tous les mots clefs ne sont pas des jetons. Il n'y en a que quelques-uns qui ne le sont pas, mais parce qu'ils sont entreposés en interne sous forme de lettres ASCII, ils doivent être analysés comme s'ils étaient des variables. Ensuite, vous pouvez décider si vous avez inventé le nom ou BASIC. Ceux étant et ceux n'étant pas des mots clefs ont tendance à être parfois différents. (Si vous appelez votre machine PC Junior, faites attention à PALETTE. Les seniors utilisent un jeton, mais certains PC Jr ne le font pas.)
Autre perversité : B et BF peuvent certainement être des noms de variables. Mais il peut aussi s'agir de "mots clefs sans jetons". S'ils suivent la deuxième virgule dans une instruction graphique LINE, ce sont simplement des commutateurs pour conditionner la façon dont cette instruction est exécutée. Pour trouver toutes les variables, uniquement, avec précision, votre algorithme devra devenir sensible au contexte lorsqu'il rencontre le jeton 176 pour LINE. Un jeton 133 peu de temps après signifie que vous avez trouvé LINE INPUT et tout B ou BF ultérieur sont des variables. Sinon, les lettres B ou BF - après une virgule de deux - peuvent être ignorées.
Les instructions DATA sont toujours des lignes entières. Si le premier jeton suivant un numéro de ligne est 132, l'octet suivant doit être 32 (un espace) et le reste de la ligne est en ASCII pur jusqu'au dernier octet (qui est toujours zéro). Notez également que les éléments DATA numériques ne sont convertis au format interne qu'au moment où vous effectuez une lecture. Un autre indice de performance, quoique plutôt petit. (La lecture de chaînes de caractères de littéraux à partir d'instructions DATA n'est pas un moyen efficace de programmer.)
Les déclarations de remarque sont intéressantes et un peu étranges. Un jeton de 143 se traduit par REM, mais seulement si l'octet suivant n'est pas 217. Les deux d'affilée - 143 et 217 - se traduisent par une apostrophe, le symbole abrégé d'une remarque. (Et cette paire est suivie d'un code - 58 imbriqué arbitrairement - deux-points - pour une raison obscure.) Au-delà de cela, tout ce que vous avez tapé est entreposé tel quel, sous forme de caractères ASCII. Notez également que la remarque la plus courte est d'au moins deux octets. Si vous utilisez REM, il est entreposé sous la forme 143 suivi du caractère d'espace syntaxiquement requis (32). Deux octets. Si vous utilisez l'apostrophe, elle est entreposée sous la forme 143, puis 217, puis 58, mais aucun espace n'est requis. Trois octets. Ainsi, REM est moins coûteux que l'apostrophe (mais est moins agréable visuellement).
Autre remarque sur les performances : les instructions DATA et les remarques sont, en fait, des octets ne faisant rien lorsqu'elles sont rencontrées par l'interpréteur pendant qu'il exécute un programme. Pour passer du jeton au début de la ligne suivante, l'interpréteur doit avancer, un octet à la fois, tout en cherchant le zéro à la fin. (Il a apparemment oublié quelle adresse se trouve dans la paire d'octets au début de cette ligne.) Donc, utilisez les remarques librement, mais ne les placez qu'après des déclarations ayant une conclusion emphatique. Après NEXT au lieu de après FOR, par exemple. Et n'intercalez jamais d'instructions DATA dans un flux de lignes exécutables, sauf si vous aimez les programmes s'exécutant plus lentement que nécessaire.
Bien que le jeton pour ELSE (161) provienne de la table des jetons à un octet, il est toujours précédé d'un 58, étant normalement considéré comme un séparateur d'instructions. Ainsi, lorsque vous tombez sur un 58, regardez l'octet suivant avant de supposer que ce qui s'en vient est la prochaine déclaration sur une ligne multi-instructions. (Normalement, ELSE ne devrait venir qu'après THEN, comme nous le savons tous.)
Les guillemets sont également un peu étranges. Ils sont entreposés sous forme de 34, comme en ASCII, mais ils sont censés être utilisés par paires. Si, par exemple, PRINT "bonjour" est rencontré, le premier guillemet désactive la segmentation. Le suivant le rallume. Ainsi, tout ce que vous mettez entre guillemets est entreposé tel que vous l'avez tapé. Et si vous n'en tapez pas un deuxième, tout, depuis le premier guillemet jusqu'à la fin de la ligne, est traité comme une chaîne de caractères de texte continue. Ce qui explique pourquoi vous voyez parfois des trucs marrants. (Une citation manquante peut être la cause de certains bogues pas si drôles.)
Les parenthèses, en revanche, doivent être utilisées dans des paires correspondantes, et elles sont entreposées respectivement sous les codes 40 et 41. Ou vous déclencherez une trappe d'erreur. Le jeton LEFT$, par exemple, devrait toujours être immédiatement suivi d'un octet code - 40.
Un autre aparté : découvrez ci-dessus pourquoi un piège à erreur peut parfois prêter à confusion. Vous l'avez confondu. Les parenthèses et autres "caractères de syntaxe" sont fondamentaux pour l'analyse d'une ligne. Certains codes indiquent que le pointeur d'octet doit avancer d'un nombre spécifique d'octets. Si le code trouvé à ce moment-là n'est pas ce qui est normalement attendu, on peut supposer que celui ayant tapé cette ligne ne respectait pas les règles. La meilleure "erreur" pouvant être donnée est basée sur ce que le pointeur voit maintenant. Les octets écrasés font partie de l'historique.
Et certains octets devraient être historiques. Les octets étant vraiment des bosses ne sont pas différents des dos d'âne dans les stationnements. Ils ralentissent votre programme. Pas toujours beaucoup, peut-être, mais si vous aimez les programmes s'exécutant dans la voie rapide, omettez tout ce qui est "facultatif". Plusieurs fois, le troisième paramètre des expressions MID$ peut être omis. Le signe dièse peut presque toujours être omis. Il est obligatoire avant le numéro de fichier dans les instructions INPUT, PRINT et WRITE. Mais les règles sont incohérentes lorsqu'un numéro de dossier est utilisé entre parenthèses. Comme dans VARPTR(#1), la règle est différente de celle de LOF(1). Ce qui n'est pas la seule incohérence concernant les parenthèses.
Pour une raison étrange, la parenthèse gauche n'est pas entreposée dans une ligne dans deux cas. Les mots clefs TAB et SPC ont leur index final intégré dans les tables de traduction. Leurs jetons ne seront pas suivis d'un code de 40. Et ces deux sont pervers d'une autre manière : ils ne peuvent être utilisés que sous une certaine forme d'instruction PRINT. Vraisemblablement, ces traits génétiques ont quelque chose à voir avec leur héritage.
Un certain nombre de caractéristiques familiales sont perceptibles dans les tableaux de traduction des mots clefs. La plupart de ceux de la première famille sont des commandes (par opposition aux fonctions). On ne s'attend pas à ce que la plupart de ces enfants aient des expressions entre parenthèses derrière eux. Les jetons de cette famille vont de 129 à 244, avec quelques lacunes. Certaines des lacunes sont causées par la mortalité infantile - des mots clefs figurant autrefois dans BASIC mais n'étant plus avec nous. Et certains sont des adoptions récentes, des mots comme COLOR, ayant été ajoutés au fur et à mesure que le langage de programmation s'est développée au fil des ans.
La deuxième famille est un peu plus pure race. C'est le gang gardé par un 255 octets. Tous ces mots clefs sont toujours suivis d'une parenthèse gauche, sauf le mot PEN. (Un cousin inadapté, sans aucun doute. Selon la façon dont il est utilisé, PEN peut ou non avoir un code de 40 octets derrière lui.) Les 37 enfants de ce clan sont numérotés de 129 à 165, et aucun ne manque. Ce qui implique, en l'absence de planification familiale, jusqu'à quatre-vingt-dix autres (166 à 255) pourraient apparaître dans une génération future de la langue.
La famille suivante sur la ligne, gardée par un 254 octets, ressemble à un orphelinat. Ce groupe de 27 jetons va de 129 à 155, sans lacunes. La plupart de ce groupe sont des nouveaux arrivants relatifs; en particulier ceux fournissant une interface avec le système d'exploitation. Pourtant, les plus anciens en haut de la liste existent depuis les versions juvéniles de Disk BASIC. Pendant longtemps, il n'y avait que six membres dans la quatrième famille, celle gardée par un 253 octets. Ces trois ensembles de jumeaux ont été conçus à l'origine pour être utiles pour travailler avec ce que l'on appelle des variables sur le terrain. (Cependant, ils ne sont pas limités à ce terrain de jeu.) Puis vint EXTERR. Remarquez les jetons vides.
Si cette page avait commencé par WHILE, nous sommes maintenant presque prêts pour WEND et une chute vers ces tables de fin. Vous souvenez-vous de ces deux octets au début de chaque ligne adressant le début de la ligne logique suivante ? Cette adresse n'est exacte que lorsqu'un programme réside en mémoire. Lorsque vous enregistrez un programme, ces adresses sont enregistrées, ainsi que tout le reste. Lorsque vous chargez, cependant, l'endroit où le fichier est placé en mémoire à ce moment-là peut être différent de ce qu'il était la dernière fois qu'il a été utilisé. Lors d'un LOAD (ou d'un RUN, ou d'un CHAIN), l'interpréteur doit recalculer toutes ces adresses.
Notez que les valeurs d'adresse sont proportionnellement correctes dans les fichiers de programme entreposés sur le disque. Un seul facteur d'addition ou de soustraction peut être appliqué à tous, pour maintenir leur relation en chaîne de caractères. De même, la différence des entêtes d'adresse de deux lignes successives peut être utilisée comme compte d'octets de la longueur d'une ligne.
Si vous lisez un programme tel qu'il se trouve dans un fichier, les adresses de ligne affichées sont celles étant, il était une fois. Si vous regardez un programme en mémoire, vous voyez les choses telles qu'elles sont maintenant. Quoi qu'il en soit, nous savons maintenant comment voir un programme tel que l'interprète le voit. Même si cette vision est encore un peu floue, cet oubli élargira, espérons-le, l'horizon.
Affectations de code interne
Valeur | Description |
---|---|
0 | Fin d'une ligne de programme |
1 à 10 | Non utilisé (ne devrait pas être rencontré) |
11 | Traduire les 2 octets suivants en Octal, comme &O1024 |
12 | Traduisez les 2 octets suivants en hexadécimal, comme &H7D0B |
13 | Les 2 octets suivants sont l'adresse d'une autre ligne |
14 | Traduire les 2 octets suivants en numéro de ligne. |
15 | Traduire l'octet suivant en un littéral numérique (0 à 255) |
16 | Non utilisé (ne devrait pas être rencontré) |
17 à 26 | Traduire cet octet en chiffre décimal (0 à 9) |
27 | Marque la fin du fichier (précédé d'un octet zéro) |
28 | Traduire les 2 octets suivants en entier |
29 | Traduire les 4 octets suivants en un nombre simple précision |
30 | Non utilisé (ne devrait pas être rencontré) |
31 | Traduire les 8 octets suivants en nombre double précision |
32 à 127 | Traduire en tant que caractères de texte ASCII standard à moins que 58 est suivi de 161 ; traduire cette paire par ELSE |
128 | Non utilisé (ne devrait pas être rencontré) |
129 à 252 | Traduire comme un mot clef du tableau 1 |
253 | Traduire l'octet suivant en mot clef du tableau 4 |
254 | Traduire l'octet suivant en mot clef du tableau 3. Si le 1er octet du fichier, il a été enregistré avec l'option P |
255 | Traduire l'octet suivant en mot clef du tableau 2. Si le 1er octet du fichier, il s'agit d'un programme LOAD et aller à. |
Tableau 1 = Jetons à un octet
Valeur | Description |
---|---|
129 | END |
130 | FOR |
131 | NEXT |
132 | DATA |
133 | INPUT |
134 | DIM |
135 | READ |
136 | LET |
137 | GOTO |
138 | RUN |
139 | IF |
140 | RESTORE |
141 | GOSUB |
142 | RETURN |
143 | REM |
144 | STOP |
145 | |
146 | CLEAR |
147 | LIST |
148 | NEW |
149 | ON |
150 | WAIT |
151 | DEF |
152 | POKE |
153 | CONT |
156 | OUT |
157 | LPRINT |
158 | LLIST |
160 | WIDTH |
161 | ELSE |
162 | TRON |
163 | TROFF |
164 | SWAP |
165 | ERASE |
166 | EDIT |
167 | ERROR |
168 | RESUME |
169 | DELETE |
170 | AUTO |
171 | RENUM |
172 | DEFSTR |
173 | DEFINT |
174 | DEFSNG |
175 | DEFDBL |
176 | LINE |
177 | WHILE |
178 | WEND |
179 | CALL |
183 | WRITE |
184 | OPTION |
185 | RANDOMIZE |
186 | OPEN |
187 | CLOSE |
188 | LOAD |
189 | MERGE |
190 | SAVE |
191 | COLOR |
192 | CLS |
193 | MOTOR |
194 | BSAVE |
195 | BLOAD |
196 | SOUND |
197 | BEEP |
198 | PSET |
199 | PRESET |
200 | SCREEN |
201 | KEY |
202 | LOCATE |
204 | TO |
205 | THEN |
206 | TAB( |
207 | STEP |
208 | USR |
209 | FN |
210 | SPC( |
211 | NOT |
212 | ERL |
213 | ERR |
214 | STRING$ |
215 | USING |
216 | INSTR |
217 | ' (rem) |
218 | VARPTR |
219 | CSRLIN |
220 | POINT |
221 | OFF |
222 | INKEY$ |
(lacunes: 154, 155, 159, 180 à 182, 203, 223-229, 245 à 255) | |
230 | > |
231 | = |
232 | < |
233 | + |
234 | - |
235 | * |
236 | / |
237 | ^ |
238 | AND |
239 | OR |
240 | XOR |
241 | EQV |
242 | IMP |
243 | MOD |
244 | \ |
Tableau 2 = Jetons de mots clefs précédés de 255
Valeur | Description |
---|---|
129 | LEFT$ |
130 | RIGHT$ |
131 | MID$ |
132 | SGN |
133 | INT |
134 | ABS |
135 | SQR |
136 | RND |
137 | SIN |
138 | LOG |
139 | EXP |
140 | COS |
141 | TAN |
142 | ATN |
143 | FRE |
144 | INP |
145 | POS |
146 | LEN |
147 | STR$ |
148 | VAL |
149 | ASC |
150 | CHR$ |
151 | PEEK |
152 | SPACE$ |
153 | OCT$ |
154 | HEX$ |
155 | LPOS |
156 | CINT |
157 | CSNG |
158 | CDBL |
159 | FIX |
160 | PEN |
161 | STICK |
162 | STRIG |
163 | EOF |
164 | LOC |
165 | LOF |
Tableau 3 = Jetons de mots clefs précédés de 254
Valeur | Description |
---|---|
129 | FILES |
130 | FIELD |
131 | SYSTEM |
132 | NAME |
133 | LSET |
134 | RSET |
135 | KILL |
136 | PUT |
137 | GET |
138 | RESET |
139 | COMMON |
140 | CHAIN |
141 | DATE$ |
142 | TIME$ |
143 | PAINT |
144 | COM |
145 | CIRCLE |
146 | DRAW |
147 | PLAY |
148 | TIMER |
149 | ERDEV |
150 | IOCTL |
151 | CHDIR |
152 | MKDIR |
153 | RMDIR |
154 | SHELL |
155 | ENVIRON |
156 | VIEW |
157 | WINDOW |
158 | PMAP |
159 | PALETTE |
160 | LCOPY |
161 | CALLS |
162 | --- |
163 | --- |
164 | --- |
165 | PCOPY |
166 | --- |
167 | LOCK |
168 | UNLOCK |
Tableau 4 = Jetons de mots clefs précédés de 253
Valeur | Description |
---|---|
129 | CVI |
130 | CVS |
131 | CVD |
132 | MKI$ |
133 | MKS$ |
134 | MKD$ |
135 | --- |
136 | --- |
137 | --- |
138 | --- |
139 | EXTERR |
Mots clefs sans jeton (conservés en ASCII)
Mots clefs | Description |
---|---|
ACCESS | comme dans OPEN ... FOR RANDOM ACCESS |
AS | comme dans OPEN ... AS --- et --- FIELD ... AS |
ALL | comme dans CHAIN ... ,ALL |
APPEND | comme dans OPEN ... FOR APPEND |
BASE | comme dans OPTION BASE 0 --- ou --- OPTION BASE 1 |
OUTPUT | comme dans OPEN ... FOR OUTPUT |
RANDOM | comme dans OPEN ... FOR RANDOM |
SHARED | comme dans OPEN ... SHARED |
SEG | comme dans DEF SEG |
Code source
Voici des exemples de code source de manipulant les jetons :
Lien | Langage de programmation | Projet |
---|---|---|
https://github.com/gladir/corail/blob/master/TOKEN2BAS.PAS | Free Pascal/Turbo Pascal | Corail |