GOTO (etc) zu einer nicht existierenden Zeile?

Dec 07 2020

Das Schreiben eines BASIC-Interpreters hat eine Reihe interessanter Informationen ergeben, die in der Dokumentation häufig nicht erwähnt werden. Beispielsweise:

10 PRINT"ONE";:IF 1=2 THEN PRINT"TWO":PRINT"THREE"

Wird ONEauf von Microsoft abgeleiteten BASICs drucken , während Dartmouth produzieren wird ONETHREE. Das heißt, MS behandelt den gesamten Rest der Linie als Teil der THEN, was ... seltsam (und meiner Meinung nach falsch) ist. Ich bemerkte nur , weil der Beispielcode hatte ich habe die letzte Anweisung ausführen, die Super Star Trek verursacht scheitern.

Ich bin auf ein anderes Beispiel gestoßen, das ich dem Hoi Polloi öffnen möchte. Betrachten Sie dieses Programm:

10 PRINT"HELLO"
20 GOTO 25
30 PRINT"WORLD"

Der Beispielcode, den ich habe, würde Zeile 25 oder die nächsthöhere Anweisung nachschlagen . In diesem Code würde also Zeile 30 ausgeführt. Dies ist definitiv nicht der Fall für Commodore BASIC, das "UNDEFN'D STATEMENT" zurückgibt.

Also ... kennt jemand eine Version von BASIC, die auf diese Weise funktioniert, oder ist dies (wie ich stark vermute) einfach ein Fehler im Beispielcode?

Antworten

5 Brian Dec 09 2020 at 22:36

Sinclair BASIC auf dem ZX Spectrum würde zur nächsten verfügbaren Zeilennummer springen. Das Handbuch sagt

Wenn sich die Zeilennummer in einem GO TO-Befehl auf eine nicht vorhandene Zeile bezieht, erfolgt der Sprung zur nächsten Zeile nach der angegebenen Nummer. Gleiches gilt für RUN; Tatsächlich bedeutet RUN für sich genommen RUN 0.

13 Chromatix Dec 07 2020 at 21:04

Es ist bekannt, dass BASIC-Dialekte in Details sehr unterschiedlich sind. Eine der definitiveren Versionen ist BBC BASIC, die Folgendes tut:

Beachten Sie das IF-THEN-ELSE-Konstrukt, das die Verwendung von IF-THEN-Körpern mit mehreren Anweisungen rechtfertigt - die in der Praxis tatsächlich nützlich sind.

BBC BASIC V fügte ein ENDIF-Schlüsselwort und die Möglichkeit für mehrzeilige IF-THEN-ELSE-ENDIF-Blöcke hinzu. Im Allgemeinen ist BBC BASIC darauf ausgerichtet, die strukturierte Programmierung einfacher zu machen als die meisten früheren Mikrocomputer-BASICs.

13 snips-n-snails Dec 08 2020 at 01:54

Die Beispiele sind keine Fehler, sondern undefiniertes Verhalten, das auch in anderen Sprachen üblich ist. Wenn Sie plattformübergreifende Kompatibilität erwarten, tun Sie einfach nichts, was zu undefiniertem Verhalten führt.

Darüber hinaus ist die Absicht des Programmierers im ersten Beispiel unklar, was zu Fehlern führen kann, die schwer zu beheben sind. Mach das auch nicht. Das zweite Beispiel ist besser, da es entweder wie vom Programmierer beabsichtigt funktioniert oder der Parser sich beschwert, wodurch es einfach ist, den Fehler schnell zu finden und zu beheben.

10 Raffzahn Dec 07 2020 at 22:18

10 PRINT"ONE";:IF 1=2 THEN PRINT"TWO":PRINT"THREE"

Druckt ONE auf von Microsoft abgeleiteten BASICs, während Dartmouth ONETHREE produziert. Das heißt, MS behandelt den gesamten Rest der Linie als Teil des DANN, was ... seltsam (und meiner Meinung nach falsch) ist.

Nun, ich denke, es gibt kein Richtig oder Falsch, aber jeder BASIC hat seinen eigenen Weg. Der Weg von MS ermöglicht im Wesentlichen die Erstellung eines Codeblocks innerhalb einer THEN-Klausel, ohne dass GOTO erforderlich ist. Bei Dartmouth, das zu diesem Zeitpunkt wie FORTRAN zuvor funktioniert, muss das THEN in den Codeblock springen, gefolgt von einem GOTO, um herumzukommen:

10 PRINT"ONE";
20 IF 1=2 THEN GOTO 40
30 GOTO 50
40 PRINT"TWO"
50 PRINT"THREE"
60 REM

Oder verwenden Sie eine invertierte Klausel, um den Codeblock zu umgehen. Weder ein wirklich tolles Konstrukt.

Es muss beachtet werden, dass das Zulassen willkürlicher Aussagen nach THEN ein späteres Add-On ist, das in Dartmouth BASIC nicht vorhanden ist. Das gleiche gilt für mehrere durch Doppelpunkte getrennte Anweisungen.

Mit der Methode von MS, die gesamte (Rest der) Linie als Teil des Then-Blocks zu behandeln, können diese Konstrukte ohne viel Gehirn-Jogging und Gotos erstellt werden.

Aber es wurde nicht von MS erfunden, sondern nur von DEC BASIC-PLUS von 1972 (schließlich ist MS BASIC ein Klon von DEC BASIC), wie auf S. 3-12 des Handbuchs beschrieben:

Hier sind also nach DANN mehrere Anweisungen zulässig, die jedoch entweder als Ganzes ausgeführt werden (wenn die Bedingung erfüllt ist) oder überhaupt nicht.

Wenn Sie nun nach den „richtigen“ Wegen suchen, ist es normalerweise am besten, zuerst die BASIC-Standards zu betrachten. Der erste hier könnte sein

  • ECMA 55 Minimal BASIC von 1978

    Dies beschreibt das Minimum, das jeder BASIC einhalten muss, um tragbar zu sein. Im Wesentlichen kodifiziert es Dartmouth BASIC (Thomas Kurtz war einer der Herausgeber) in seinen späteren Inkarnationen auf klare und reproduzierbare Weise. Hier erlauben THEN-Anweisungen nur das Springen einer Zeilennummer.

  • ANSI Minimal BASIC von 1979

    Im Wesentlichen die ANSI-Version von ECMA-55.

Dies ist übrigens der Zeitpunkt, an dem MS-BASIC zu einer normativen Kraft wurde

  • ECMA 116 BASIC von 1986 , auch "Full BASIC" genannt

    Hier sind Multi-Statement- und Multi-Line-THEN-Konstrukte und deren Mischungen möglich. Die Multi-Anweisung funktioniert wie die 'MS-Methode', während die Multi-Zeile eine ENDIF- (oder ELSE / ELSEIF-) Anweisung benötigt, um den Block zu schließen. (Es hat auch viele andere nie Funktionen aus modernen BASICs bekannt, nur mit Zeilennummern)

  • ANSI / ISO / IEC Full BASIC von 1987

    Im Wesentlichen ECMA-116 mit einigen Klarstellungen / Erweiterungen.

MS folgt also dem, was ECMA-116 sagt ... nun, oder besser, der Standard kodifiziert, was MS zuvor getan hat, und wurde so zum Defacto-Standard. In diese Standards wurde viel Arbeit gesteckt, um einen funktionsfähigen gemeinsamen Platz für BASIC zu schaffen. Dies schließt insbesondere Randfälle scheinbar klarer Probleme ein. Ich würde es als bewährte Methode betrachten, sie zu überprüfen, wenn etwas zur Diskussion steht. Vor allem, weil sie auch auf Themen hinweisen, über die noch nicht entschieden wurde / die noch interpretiert werden können.

Der Beispielcode, den ich habe, würde Zeile 25 oder die nächsthöhere Anweisung [...] nachschlagen.

Also ... kennt jemand eine Version von BASIC, die auf diese Weise funktioniert, oder ist dies (wie ich stark vermute) einfach ein Fehler im Beispielcode?

Ich erinnere mich an ein TINY BASIC, das es erlaubte, zwischen Zeilen zu springen, um das berechnete GOTO zu vereinfachen, aber die ursprüngliche Quelle zu betrachten, die so aussieht, war eine Modifikation.

Im Gegensatz dazu gibt ECMA-55 an, welche Ziele in THEN / GOTO / GOSUB als Ziele verwendet werden:

All line-numbers in control-statements shall refer to lines in the program.
1 Davislor Dec 08 2020 at 07:35

In pragmatischen Begriffen,

  1. Entscheiden Sie, welchen Legacy-Code Ihr Interpreter ausführen soll

  2. Entscheiden Sie, welche inkompatiblen Dialekte Sie gegebenenfalls als Optionen unterstützen möchten

  3. Mach das Gleiche wie sie.

Wie Raffzahn anführt, ist das Verhalten von Microsoft praktischer als das von Dartmouth, da Sie mit Microsoft BASIC einen bedingten Block mit mehreren Anweisungen schreiben können. Sie sagen auch, dass Sie Programme ausführen möchten, die das Verhalten von Microsoft erwarten.

Ebenso ist es sehr unwahrscheinlich, dass ein Legacy-Code absichtlich GOTOeine Zeile enthält, die nicht vorhanden ist, aber es ist möglich, dass ein vorhandenes Programm trotz eines Tippfehlers wie GOTO 24statt korrekt ausgeführt wird GOTO 25.

Wenn Sie auch Code ausführen müssen, der von inkompatiblem Verhalten abhängt, können Sie diesen als Option bereitstellen.

1 h22 Dec 09 2020 at 21:57

Der von mir verwendete Dialekt bestand darin, die Kontrolle an die vorhandene Zeile mit der nächstgrößeren Nummer weiterzugeben, falls eine solche vorhanden war. Wenn nicht, war dies der legitime Weg, um das Programm ohne Fehlermeldung zu beenden.

Durch Übergeben der Steuerung in die Mitte des Bereichs konnten Linien zu beiden Seiten des Einstiegspunkts hinzugefügt werden. Dies hat sehr geholfen, da das Refactoring auch sehr mühsam war: Es gab keine Suche und die einzige Möglichkeit, die Zeile zu ändern, bestand darin, sie vollständig in voller Länge neu einzugeben. Diese Version hatte keine automatische Zeilenumzählung.

Die Maschine war eine Art sowjetische "Elektronika", aber ich kann mich nicht genau erinnern. Es sah eher aus wie ein sehr hochwertiger Taschenrechner mit einer eigenen zweireihigen LED-Anzeige auf der Konsole, unterstützte jedoch bereits externen Monitor und Tastatur.