Warum haben alte BASICs (und vielleicht auch andere Sprachen) Zeilennummern als Teil des Quellcodes verwendet?
Ich meine, welche Probleme hat es gelöst (versucht)?
Warum haben alte BASICs (und vielleicht auch andere Sprachen) Zeilennummern als Teil des Quellcodes verwendet?
Ich meine, welche Probleme hat es gelöst (versucht)?
Antworten:
BASIC muss in einen Kontext mit den heutigen Sprachen gebracht werden: Early Fortran, Cobol und Assembly.
Damals, als ich mit 6502-Baugruppen ohne Beschriftungen experimentierte , bedeutete dies, dass Sie, als Sie feststellten, dass Sie irgendwo in der Mitte des dicht gepackten Codes eine Anweisung hinzufügen mussten (später fügte ich NOPs hinzu ), den gesamten Sprung wiederholen mussten Adressen. Das war zeitaufwändig.
Fortran war ein zeilenbasiertes System vor BASIC. In Fortran waren die Spalten 1 bis 5 eine Zeilennummer, die für Verzweigungsziele verwendet werden sollte. Das Wichtigste bei Fortran war, dass die Compiler tendenziell etwas intelligenter waren als der BASIC-Interpreter. Das Hinzufügen einiger Anweisungen bedeutete lediglich, einige Karten zu stanzen und sie an der richtigen Stelle in das Deck zu legen.
BASIC hingegen musste alle Anweisungen befolgen. Es gab nicht viel von einem Konzept einer "Fortsetzung der vorherigen Zeile". Stattdessen wurde in Applesoft BASIC (einer der am häufigsten verwendeten Dialekte, mit denen ich vertraut bin und über die ich Informationen finden kann) jede Zeile im Speicher wie folgt dargestellt:
NN NN TT TT AA BB CC DD .. .. 00
Es hatte zwei Bytes für die Adresse der nächsten Zeile ( NN NN
). Zwei Bytes für die Zeilennummer dieser Zeile ( TT TT
) und dann eine Liste von Token ( AA BB CC DD .. ..
), gefolgt von der Markierung für das Zeilenende ( 00
). (Dies ist von Seite 84-88 von Inside the Apple // e )
Ein wichtiger Punkt bei der Betrachtung dieser Speicherdarstellung ist, dass die Zeilen nicht in der richtigen Reihenfolge gespeichert werden können. Die Struktur des Speichers war die einer verknüpften Liste mit einem Zeiger auf die nächste Zeile in der Struktur. Dies machte es einfach, neue Zeilen zwischen zwei Zeilen einzufügen - aber Sie mussten jede Zeile nummerieren, damit es richtig funktioniert.
Viele Male, als Sie mit BASIC gearbeitet haben, haben Sie tatsächlich in BASIC selbst gearbeitet. Insbesondere war eine bestimmte Zeichenfolge entweder eine Zeilennummer und BASIC-Anweisungen oder ein Befehl an den Basisinterpreter RUN
oder LIST
. Dies machte es einfach, den Code von den Befehlen zu unterscheiden - jeder Code beginnt mit Zahlen.
Diese beiden Informationen geben Aufschluss darüber, warum Zahlen verwendet wurden. Sie können viele Informationen in 16 Bit abrufen. Zeichenketten-basierte Etiketten benötigen viel mehr Platz und sind schwerer zu bestellen. Zahlen sind einfach zu verarbeiten, verständlich und einfacher darzustellen.
Spätere BASIC-Dialekte, bei denen Sie nicht die ganze Zeit im Interpreter waren, konnten alle nummerierten Zeilen entfernen und mussten stattdessen nur die Zeilen nummerieren, die Zweigziele waren. In der Tat Etiketten.
] PRINT "FOO"
wurde sofort vom BASIC-Interpreter ausgeführt. Es ist eine Aussage. Wenn Sie es später ausführen möchten, würden Sie ] 10 PRINT "FOO"
und dann tun ] RUN
. In der AppleSoft BASIC-Umgebung konnte jede BASIC-Anweisung sofort oder verzögert ausgeführt werden - es gab nur sehr wenige von DOS bereitgestellte Befehle, die keine gültigen BASIC-Anweisungen waren. Die Unterscheidung zwischen einer Anweisung jetzt und einer Anweisung später war die Zeilennummer. Sie können eine verzögerte Anweisung auch ändern, indem Sie die entsprechende Zeilennummer erneut eingeben. Sie können auch mehrere Anweisungen in eine Zeile setzen::
Auf frühen Mikrocomputern basierte die Bearbeitung auf Zeilen. Sie konnten sich nicht einfach frei im Quellcode bewegen und bearbeiten. Sie hatten eine einzelne Zeile am unteren Bildschirmrand, in die Sie Befehle eingeben und Code eingeben konnten. Der Rest des Bildschirms bestand aus schreibgeschützten Codeauflistungen und Befehlsausgaben. Wenn Sie beispielsweise Zeile 90 in dem Programm bearbeiten möchten, das Sie " EDIT 90
" geschrieben haben, wird der Inhalt der Zeile 90
in den einzeiligen Bearbeitungspuffer eingegeben. Nachdem Sie die Zeile bearbeitet haben, drücken Sie die Eingabetaste, und die Programmliste wurde aktualisiert. Sie brauchten also Zeilennummern, um das Programm bearbeiten zu können.
Als die Code-Editoren fortgeschrittener wurden und Sie den Cursor in der Codeliste bewegen konnten, brauchten Sie keine Zeilennummern mehr.
Wenn Sie an BASIC-Dialekte der 8-Bit-Heim-Mikrocomputer der 80er Jahre denken, hatten diese Computer keine Texteditoren (es sei denn, Sie haben eine Textverarbeitungssoftware gekauft). Es gab keine Möglichkeit, den gesamten BASIC-Programm-Quellcode "in einem Editor zu öffnen", wie Sie es heute bei der Programmierung getan hätten. Der Programmierer würde das Programm nicht einmal wirklich als Quellcodedatei oder Text betrachten.
Nehmen wir also an, Sie haben ein einfaches Programm ohne Zeilennummern im Kopf:
FOR I=1 TO 42
PRINT I
NEXT I
Sie starten Ihren Computer. Sie haben eine Eingabeaufforderung "bereit" oder so ähnlich, und der Cursor sitzt in der nächsten Zeile. Dies ähnelt den heutigen REPL- Umgebungen mit verschiedenen Skriptsprachen, ist jedoch weniger strikt zeilenbasiert als vielmehr bildschirmbasiert. Also nicht ganz wie die heutigen REPLs, aber nah dran.
Wenn Sie jetzt mit der Eingabe des Programms beginnen, wird möglicherweise nach der ersten Zeile ein Fehler angezeigt, da der BASIC-Interpreter versucht, das Programm sofort auszuführen (und zu vergessen). Ohne NEXT ist es nicht sinnvoll, die Schleife zu beenden. Dies ist kein Texteditor, in dem Sie Text bearbeiten, sondern dem Computer Befehle erteilen!
Sie müssen also sagen, das ist die Programmzeile, speichern Sie sie! Sie könnten einen speziellen Befehl oder nur ein Symbol haben, das besagt, dass hey, das ist die Programmzeile, speichern Sie es. Stellen wir uns vor:
#FOR I=1 TO 42
#PRINT I
#NEXT I
Ok, jetzt hat unser imaginärer BASIC-Interpreter das Programm gespeichert und Sie können es ausführen. Nun möchten Sie die PRINT-Zeile bearbeiten. Wie machst du das? Sie befinden sich nicht in einem Texteditor. Sie können den Cursor nicht einfach auf die Zeile bewegen und sie bearbeiten. Oder Sie möchten eine weitere Zeile wie LET COUNT=COUNT+1
in der Schleife hinzufügen . Wie geben Sie an, wo die neue Zeile eingefügt werden soll?
Zeilennummern lösen dies auf sehr einfache, wenn auch klobige Weise. Wenn Sie eine Programmzeile mit einer bereits vorhandenen Nummer eingeben, wird die alte Zeile ersetzt. Nun ist die Bildschirm-basierte REPL Umgebung wird nützlich, weil Sie gerade Cursor auf Programm bewegen kann Eintrag auf dem Bildschirm, bearbeiten Sie die Zeile auf dem Bildschirm und drücken Sie die Eingabetaste zu speichern. Dies scheint, als würden Sie die Zeile bearbeiten, wenn Sie tatsächlich Text auf dem Bildschirm bearbeiten und dann die gesamte Zeile durch eine neue auf dem Bildschirm ersetzen. Außerdem wird das Einfügen neuer Zeilen zum Kinderspiel, wenn Sie nicht verwendete Nummern dazwischen belassen. Demonstrieren:
10 FOR I=1 TO 42
20 PRINT I
30 NEXT I
Nach dem erneuten Eingeben von Zeile 20 mit Änderungen und dem Hinzufügen neuer Zeilen könnte dies der Fall sein
5 LET COUNT=0
10 FOR I=1 TO 42
20 PRINT "Index", I
25 LET COUNT=COUNT+1
30 NEXT I
Es gibt den Vorteil (oder den Fluch, der den berühmten BASIC-Spaghetti-Code ermöglicht), Zeilennummern als Sprachkonstrukt zu verwenden, zumindest als Ziel von GOTO
AND- GOSUB
Befehlen. Dies könnte durch Bezeichnungen ersetzt werden, aber die Verwendung von Zeilennummern ist im BASIC-Interpreter viel einfacher zu implementieren, was in einem typischen 8-Bit-Heimcomputer der 80er Jahre noch ein deutlicher Vorteil war.
Noch wichtiger ist, dass Zeilennummern aus Sicht der Benutzererfahrung eine überraschend einfache und dennoch vollständige Oberfläche für die Bearbeitung des Codes darstellen. Geben Sie einfach eine Zeile ein, die mit einer Zahl beginnt, um einen neuen Code einzufügen. Verwenden Sie LIST 100-200
, um die Zeilen 100-200 anzuzeigen. Um eine Zeile zu bearbeiten, listen Sie sie auf dem Bildschirm auf, bearbeiten Sie den Text auf dem Bildschirm und geben Sie die Zeile erneut ein. Wenn Sie eine Zeile entfernen möchten, müssen Sie sie so bearbeiten, dass sie leer ist. Geben Sie also einfach die Zeilennummer ein, hinter der nichts steht. Ein Absatz, um dies zu beschreiben. Vergleichen Sie den Versuch, die Verwendung alter Texteditoren wie edlin von DOS oder ed oder ex von Unix zu beschreiben: Sie benötigen einen Absatz (nur leichte Übertreibung), um zu erklären, wie der Benutzer sie beenden kann, wenn er sie versehentlich startet!
Andere Antworten erklären, wie es zu Zeilennummern kam. Ich versuche hier zu erläutern, warum die Zeilennummern so lange überlebt haben, wie sie ein reales Problem gelöst haben: Sie boten eine Möglichkeit, die eigentliche Programmierung auf sehr einfache Weise ohne einen echten Editor durchzuführen. Sobald die richtigen, benutzerfreundlichen Vollbild-Texteditoren die gängige Methode zum Bearbeiten von Code waren, sowohl mit dem Verschwinden von Hardwareeinschränkungen als auch mit der Überwindung der Trägheit von Menschen, die sich an neue Dinge anpassen, verschwanden zeilennummernbasierte BASIC-Dialekte recht schnell aus der Verwendung Das Kernproblem der Benutzerfreundlichkeit, das sie gelöst haben, war kein Problem mehr.
In der Zeit, als Basic entwickelt wurde, war das beste verfügbare E / A-Gerät ein Teletyp. Das Bearbeiten eines Programms erfolgte durch Drucken (auf Papier) einer Liste des gesamten Programms oder des interessanten Teils davon und anschließendes Eingeben von Ersatzzeilen mit Zeilennummern.
Das ist auch der Grund, warum die Standard-Zeilennummerierung 10 war, sodass zwischen vorhandenen Zeilen nicht verwendete Nummern vorhanden waren.
ren
den Befehl, neu zu nummerieren. Ein typischer Aufruf war ren 10, 10
(Umnummerieren ab zehn, inkrementieren um zehn - das Standardverhalten, wenn man es nur eingibt ren
. Die Befehle goto
und gosub
und then (linenumber)
werden automatisch aktualisiert. Aber dies war definitiv nicht in den frühesten BASICs verfügbar. Aber IIRC war in Apple verfügbar Ganzzahlig Basic, Applesoft FP Basic, TI Basic / Erweitert Basic, MS Basic / GW Basic usw.
"Zeilennummern" bedeuten ein paar verschiedene Dinge.
Denken Sie vor allem daran, dass das Konzept der "Linien" nicht immer existiert. Viele Programmiersprachen in dieser Ära verwendeten Lochkarten , und die Sequenznummern (normalerweise in den letzten Spalten der Karte) halfen Ihnen, Ihr Deck in der richtigen Reihenfolge wiederherzustellen, wenn Sie es fallen ließen oder etwas Schreckliches im Kartenleser passierte. Es gab Maschinen, die dies automatisch erledigten.
Zeilennummern zur Verwendung als Ziele von GOTO
Anweisungen sind ein völlig anderes Konzept. In FORTRAN IV waren sie optional und standen vor der Anweisung (in den Spalten 1-5). Das Konzept des berechneten und zugewiesenen GOTO war nicht nur einfacher zu implementieren als Freiform-Labels, sondern ermöglichte es Ihnen auch, zu einer beliebigen Zeilennummer zu springen. Dies war etwas, über das die meisten modernen Programmiersprachen nicht verfügten (obwohl sich die switch
Anweisungen annähern), war jedoch für Assembler-Programmierer ein bekannter Trick.
BASIC wurde von FORTRAN abgeleitet und sollte einfacher zu implementieren und zu verstehen sein. Daher war es wahrscheinlich eine Designentscheidung aus diesem Grund, für jede "Zeile" eine Zeilennummer (sowohl für die Sequenzierung als auch als Ziel von GOTO
/ GOSUB
Anweisungen) festzulegen.
goto array_of_labels[some_computation()];
GOTO
(oder ASSIGN
) und die ursprüngliche aka Arithmetik aka Dreifach IF
, und (selten verwendete) abwechselnde Rückgaben in CALL
und Art von Zielen (wohl Begrenzer) von DO
und FORMAT
Anweisungen. Bei anderen Aussagen waren sie optional.
GOTO 1000+N*100
, um eine switch
Anweisung zu emulieren .
Ich fing an, in COBOL zu programmieren, wobei Zeilennummern in den Spalten 1-6 jeder Zeile verwendet wurden. Da es in den 1970er Jahren keine IDEs gab, wurde alles über Lochkarten gemacht und die Zeilennummer wurde verwendet, um zu identifizieren, welche Zeilen in der ursprünglichen Quelle ersetzt und welche neuen Zeilen hinzugefügt wurden. Früher haben wir die Zeilennummern um 100 erhöht, um Platz für weitere Zeilen zu schaffen.
BASIC entstand später als FORTRAN im Line-Terminal-Zeitalter. Es gab eine Lese-Exe-Print-Loop-Umgebung, die interaktiver war als ein Kartenspiel.
Ich habe gelernt, in BASIC auf einem einzeiligen Display mit 24 Zeichen zu programmieren . Zeilennummern waren eine natürliche Methode, um anzugeben, wo eine Zeile eingefügt werden soll, unabhängig davon, ob eine Zeile bearbeitet oder zwischen anderen eingefügt werden soll.
Ich kann mir wirklich nicht vorstellen, wie du es sonst machen würdest.
Ein Punkt, den noch niemand erwähnt hat, ist, dass Anfänger leichter über den Programmfluss nachdenken können, wenn die Verzweigungsziele explizit angegeben sind. Anstatt mit (möglicherweise verschachtelten) BEGIN / END-Anweisungen übereinzustimmen (oder welche Blocktrennzeichen auch immer verwendet wurden), war es ziemlich offensichtlich, wohin der Kontrollfluss führte. Dies war wahrscheinlich für die Zielgruppe von BASIC nützlich (es ist schließlich der symbolische Allzweckanweisungscode für Anfänger ).
Das Dartmouth Time Sharing System verwendete eine Teletypschnittstelle. Daher wurde eine befehlsbasierte Schnittstelle verwendet. Ursprünglich wurden Zeilennummern nur zum Bearbeiten des Programms verwendet. Sie können eine Zeilennummer einfügen, ersetzen oder löschen. Es scheint nicht, dass die frühe Version Zeilennummern für goto-Anweisungen verwendete, aber dies war eine spätere Ergänzung der Sprache.