Pourquoi les anciens BASIC (et peut-être d'autres langues) ont-ils utilisé des numéros de ligne dans le code source?
Je veux dire, quels problèmes at-il (essayé de) résoudre?
Pourquoi les anciens BASIC (et peut-être d'autres langues) ont-ils utilisé des numéros de ligne dans le code source?
Je veux dire, quels problèmes at-il (essayé de) résoudre?
Réponses:
BASIC doit être mis en contexte avec ses langages contemporains: débutant, débutant, assemblé.
À l'époque où je barbouillais l'assemblage 6502 sans étiquettes, cela signifiait que lorsque vous réalisiez que vous deviez ajouter une instruction quelque part au milieu d'un code très serré (j'ai ajouté plus tard des NOP ), vous deviez exécuter et refaire tous les sauts. adresses. Cela prenait du temps.
Fortran était un système numéroté par ligne qui précédait BASIC. Dans Fortran, les colonnes 1 à 5 étaient un numéro de ligne à utiliser pour les cibles pour la création de branches. L’important dans Fortran était que les compilateurs avaient tendance à être un peu plus intelligents que l’interprète BASIC et qu’ajouter quelques instructions consistait simplement à perforer des cartes et à les placer au bon endroit.
BASIC, d'autre part, devait garder toutes ses instructions commandées. Il n'y avait pas beaucoup de concept de "continuation de la ligne précédente". Au lieu de cela, dans Applesoft BASIC (l'un des dialectes largement utilisés que je connais et que je peux trouver des informations), chaque ligne en mémoire était représentée par:
NN NN TT TT AA BB CC DD .. .. 00
Il avait deux octets pour l'adresse de la ligne suivante ( NN NN
). Deux octets pour le numéro de ligne de cette ligne ( TT TT
), puis une liste de tokens ( AA BB CC DD .. ..
) suivie du marqueur de fin de ligne ( 00
). (Ceci est tiré de la page 84-88 de À l'intérieur de la pomme // e )
Un point important à prendre en compte lorsque vous regardez cette représentation en mémoire est que les lignes peuvent être stockées dans la mémoire dans l’ordre. La structure de la mémoire était celle d'une liste chaînée avec un pointeur «ligne suivante» dans la structure. Cela facilitait l'ajout de nouvelles lignes entre deux lignes - mais vous deviez numéroter chaque ligne pour que celle-ci fonctionne correctement.
Plusieurs fois, lorsque vous travailliez avec BASIC, vous travailliez réellement dans BASIC lui-même. En particulier, une chaîne donnée était soit un numéro de ligne et des instructions BASIC, soit une commande destinée à l'interpréteur de base pour RUN
ou LIST
. Cela a rendu facile la distinction du code des commandes - tout code commence par des nombres.
Ces deux informations identifient pourquoi les nombres ont été utilisés - vous pouvez obtenir beaucoup d'informations en 16 bits. Les étiquettes basées sur des chaînes prendraient beaucoup plus d'espace et sont plus difficiles à commander. Les chiffres sont faciles à utiliser, compréhensibles et faciles à représenter.
Plus tard, les dialectes BASIC pour lesquels vous n’êtes pas tout le temps dans l’interprète ont pu supprimer toutes les lignes numérotées et n’avaient besoin que de numéroter les lignes qui étaient des branches cibles. En effet, les étiquettes.
] PRINT "FOO"
été immédiatement géré par l'interprète BASIC. C'est une déclaration. Si vous vouliez l'exécuter plus tard, vous le feriez ] 10 PRINT "FOO"
et ensuite ] RUN
. Dans l'environnement AppleSoft BASIC, chaque instruction BASIC pouvait être exécutée immédiatement ou différée. Seules quelques commandes fournies par DOS n'étaient pas des instructions BASIC valides. La différence entre une déclaration maintenant et une déclaration ultérieure était le numéro de ligne. Vous pouvez également modifier une instruction différée en ressaisissant le numéro de ligne correspondant. Vous pouvez également mettre plusieurs déclarations sur une même ligne::
Au début, l’édition était basée sur les lignes. Vous ne pouvez pas simplement vous déplacer librement dans le code source et le modifier. Vous avez une seule ligne au bas de l'écran où vous pouvez taper des commandes et entrer le code. Le reste de l'écran était constitué de listes de codes en lecture seule et d'une sortie de commande. Si vous voulez éditer, dites la ligne 90 dans le programme que vous avez écrit " EDIT 90
", et le contenu de la ligne est 90
entré dans le tampon d'édition d'une seule ligne. Lorsque vous avez modifié la ligne que vous avez appuyée, entrez, et la liste des programmes a été mise à jour. Vous avez donc besoin de numéros de ligne pour pouvoir modifier le programme.
Lorsque les éditeurs de code sont devenus plus avancés et vous ont permis de déplacer le curseur dans la liste de codes, vous n'avez plus besoin des numéros de ligne.
Si vous songez aux dialectes BASIC des micro-ordinateurs domestiques 8 bits des années 80, ces ordinateurs n’avaient pas d’éditeur de texte (à moins que vous n’ayez acheté une application de traitement de texte). Il n'y avait aucun moyen d'avoir le code source entier du programme BASIC "ouvert dans un éditeur", comme vous le feriez avec la programmation d'aujourd'hui. Le programmeur ne penserait même pas au programme comme un fichier de code source, ou un texte, vraiment.
Alors, disons que vous avez un programme simple sans numéros de ligne dans votre tête:
FOR I=1 TO 42
PRINT I
NEXT I
Vous démarrez votre ordinateur. Vous avez une invite "prêt" ou quelque chose comme ça, et le curseur assis dans la ligne suivante. Cela ressemble beaucoup aux environnements REPL actuels de différents langages de script, bien qu'ils ne soient pas aussi strictement basés sur des lignes, mais plutôt sur des écrans. Donc, pas tout à fait comme les REPLs d'aujourd'hui, mais proches.
Maintenant, si vous commencez à entrer dans le programme, vous risquez d'obtenir une erreur après la première ligne, parce que l'interpréteur BASIC essaie de l'exécuter immédiatement (et de l'oublier), et cela n'a pas de sens si NEXT ne met pas fin à la boucle. Ce n'est pas un éditeur de texte où vous éditez du texte, c'est ici que vous donnez des commandes à l'ordinateur!
Donc, vous avez besoin d'un moyen de dire, c'est la ligne de programme, stockez-le! Vous pouvez avoir une commande spéciale ou juste un symbole disant que c'est une ligne de programme, stockez-la. Imaginons ceci:
#FOR I=1 TO 42
#PRINT I
#NEXT I
Ok, notre interprète BASIC imaginaire a maintenant enregistré le programme et vous pouvez le lancer. Mais maintenant, vous voulez éditer la ligne PRINT. Comment faites-vous? Vous n'êtes pas dans un éditeur de texte, vous ne pouvez pas simplement déplacer le curseur sur la ligne et la modifier. Ou vous voulez ajouter une autre ligne comme LET COUNT=COUNT+1
dans la boucle. Comment indiquez-vous où la nouvelle ligne doit être insérée?
Les numéros de ligne permettent de résoudre ce problème très facilement, bien que plutôt klunky. Si vous entrez une ligne de programme avec un numéro qui existe déjà, l'ancienne ligne est remplacée. Maintenant, l'environnement REPL basé sur un écran devient utile car il vous suffit de déplacer le curseur sur la liste des programmes à l'écran, de modifier la ligne à l'écran et d'appuyer sur ENTREE pour le stocker. On dirait que vous modifiez la ligne, alors que vous éditez du texte à l’écran puis que vous remplacez la ligne entière par une nouvelle à partir de l’écran. En outre, l'insertion de nouvelles lignes devient facile si vous laissez des numéros inutilisés entre les deux. Démontrer:
10 FOR I=1 TO 42
20 PRINT I
30 NEXT I
Après avoir réintégré la ligne 20 avec les modifications et ajouté de nouvelles lignes, il pourrait être
5 LET COUNT=0
10 FOR I=1 TO 42
20 PRINT "Index", I
25 LET COUNT=COUNT+1
30 NEXT I
Il y a l'avantage (ou la malédiction, car il permet le fameux code spaghetti BASIC) de pouvoir utiliser les numéros de ligne comme construction de langage, au moins comme cible des commandes GOTO
AND GOSUB
. Cela pourrait être remplacé par des étiquettes, mais l'utilisation de numéros de ligne est beaucoup plus simple à implémenter dans un interpréteur BASIC, ce qui était tout de même un avantage certain pour un ordinateur domestique typique à 8 bits des années 80.
Plus important encore, du point de vue de l'expérience utilisateur, les numéros de ligne constituent une interface étonnamment simple mais complète pour l'édition du code. Il suffit de taper une ligne commençant par un nombre pour insérer le nouveau code. Utilisez LIST 100-200
pour afficher les lignes 100-200. Pour modifier une ligne, affichez-la à l'écran, modifiez le texte à l'écran et entrez à nouveau la ligne. Pour supprimer une ligne, éditez-la pour qu'elle soit vide, c'est-à-dire donnez simplement le numéro de ligne suivi de rien. Un paragraphe pour décrire cela. Comparez en essayant de décrire l'utilisation d'anciens éditeurs de texte comme edlin de DOS, ed ou ex d'Unix: vous avez besoin d'un paragraphe (seule une légère hyperbole) pour expliquer comment l'utilisateur peut les quitter, lorsqu'il est démarré accidentellement!
D'autres réponses expliquent comment les numéros de ligne ont été créés. J'essaie de décrire ici pourquoi les numéros de ligne ont survécu aussi longtemps, comment ils ont continué à résoudre un problème concret: ils ont proposé un moyen très simple de faire la programmation proprement dite sans véritable éditeur. Une fois que les éditeurs de texte plein écran appropriés et faciles à utiliser sont devenus le moyen habituel d’éditer le code, à la fois avec la disparition des limitations matérielles et la suppression de l’inertie des personnes adaptant de nouvelles fonctionnalités, les dialectes BASIC basés sur les numéros de ligne ont rapidement disparu, car le problème de convivialité principal qu'ils ont résolu n'était plus un problème.
À la place et à l'époque où Basic a été développé, le meilleur périphérique d'E / S disponible était un télétype. La modification d'un programme consistait à imprimer (sur papier) une liste de l'intégralité du programme ou de sa partie intéressante, puis à saisir des lignes de remplacement avec des numéros de ligne.
C'est aussi pourquoi la numérotation des lignes par défaut était de 10, de sorte qu'il y aurait des numéros inutilisés entre les lignes existantes.
ren
commande ' ', à renuméroter. Une invocation typique était ren 10, 10
(numéroter à partir de dix, incrémenter par dix - le comportement par défaut si l' on tapés ren
. Le goto
et gosub
et then (linenumber)
. Les commandes seront mises à jour automatiquement , mais ce fut certainement pas disponible dans les premiers BASICs Mais IIRC, était disponible dans Apple. Entier de base, Applesoft FP de base, TI de base / étendu, MS de base / GW de base, etc.
"Numéros de ligne" signifie quelques choses différentes.
Tout d’abord, gardez à l’esprit que le concept de «lignes» n’a pas existé depuis toujours. De nombreux langages de programmation de cette époque utilisaient des cartes perforées et le fait de disposer de numéros de séquence (généralement dans les dernières colonnes de la carte) vous permettait de récupérer votre jeu dans le bon ordre si vous le laissiez tomber ou si quelque chose de terrible se produisait dans le lecteur de carte. Il y avait des machines pour le faire automatiquement.
Les numéros de ligne à utiliser comme cibles d' GOTO
énoncés sont un concept totalement différent. Dans FORTRAN IV, ils étaient facultatifs et précédaient l’instruction (dans les colonnes 1 à 5). En plus d'être plus facile à implémenter que les étiquettes de forme libre, il existait également le concept de GOTO calculé et attribué , qui vous permettait de passer à un numéro de ligne arbitraire. C'était quelque chose que la plupart des langages de programmation modernes n'ont pas (bien que les switch
déclarations s'en approchent), mais qui était un truc familier pour les programmeurs assembleurs.
BASIC était dérivé de FORTRAN et devait être plus simple à implémenter et à comprendre. Ainsi, forcer chaque "ligne" à avoir un numéro de ligne (à la fois pour le séquencement et comme cible de GOTO
/ GOSUB
statement) était probablement une décision de conception prise pour cette raison.
goto array_of_labels[some_computation()];
GOTO
(ou ASSIGN
) et l'arithmétique alias d'origine, à trois voies IF
, et (rarement utilisé) les retours alternatifs CALL
, et les sortes (avec des délimiteurs discutables) DO
, et les FORMAT
déclarations. Sur d'autres déclarations, elles étaient facultatives.
GOTO 1000+N*100
pour imiter une switch
instruction.
J'ai commencé à programmer en COBOL en utilisant les numéros de ligne des colonnes 1 à 6 de chaque ligne. Comme il n'y avait pas d'IDE dans les années 1970, tout était fait avec des cartes perforées et le numéro de ligne était utilisé pour identifier les lignes de la source d'origine qui devaient être remplacées et les nouvelles lignes ajoutées. Nous avions l'habitude d'incrémenter les numéros de ligne de 100 pour nous permettre d'ajouter plus de lignes.
BASIC est venu plus tard que FORTRAN, à l’ère des terminaux. Il présentait un environnement de lecture-exe-print-loop plus interactif qu’un jeu de cartes.
J'ai appris à programmer, en BASIC, sur un afficheur d'une ligne contenant 24 caractères. Les numéros de ligne étaient un moyen naturel de spécifier l’endroit où vous vouliez aller, qu’il s’agisse de le modifier ou de l’insérer entre les autres.
Je ne peux vraiment pas imaginer comment vous le feriez autrement.
Un point que personne n’a encore mentionné est qu’il est plus facile pour les débutants de raisonner sur le déroulement du programme lorsque les cibles de branche sont explicites. Ainsi, plutôt que de devoir faire correspondre les instructions BEGIN / END (éventuellement imbriquées) (ou les délimiteurs de bloc utilisés), il était assez évident de savoir où allait le flux de contrôle. Cela était probablement utile étant donné le public cible de BASIC (après tout, il s'agit du code d'instruction symbolique polyvalent du débutant ).
Le système de partage du temps de Dartmouth utilisait une interface de télétype. Ainsi, il utilisait une interface basée sur des commandes. À l'origine, les numéros de ligne n'étaient utilisés que pour modifier le programme. Vous pouvez insérer, remplacer ou supprimer en utilisant un numéro de ligne. Il ne semble pas que la version précédente utilisait des numéros de ligne pour les instructions goto, mais il s’agissait d’un ajout ultérieur à la langue.