15

Writing a BASIC interpreter has revealed a number of interesting bits of information that tend not to be mentioned in the documentation. For instance:

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

Will print ONE on Microsoft-derived BASICs, while Dartmouth will produce ONETHREE. That is, MS treats the entire rest of the line as part of the THEN, which is... weird (and wrong IMHO). I only noticed this because the example code I had did run the last statement, which caused Super Star Trek to fail.

I've come across another example I'd like to throw open to the hoi polloi. Consider this program:

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

The example code I have would look up line 25 or the next higher statement. So in that code, line 30 would be run. This is definitely not the case for Commodore BASIC, which returns "UNDEFN'D STATEMENT".

So... does anyone know a version of BASIC that works in this fashion, or is this (as I strongly suspect) simply a bug in the example code?

25
  • 28
    Correction: we are not the "hoi polloi", we are elite custodians of history :-) Dec 7, 2020 at 13:56
  • 1
    I'm pretty sure but I can't check right now that GW-BASIC would goto line 30 in that case. The Sinclair BASICs would throw an error along the lines of LINE NOT FOUND Dec 7, 2020 at 13:57
  • 2
    @OmarL - I just tried with GW-BASIC: it gives the same error
    – scruss
    Dec 7, 2020 at 15:25
  • 3
    @tofro 4K integer BASIC on the ZX80, 8K floating-point BASIC on the ZX80 and ZX81, and ZX Spectrum BASIC also exhibit this behaviour. The BASIC on the QL is called SuperBASIC. Dec 7, 2020 at 22:21
  • 2
    @RobbieGoodwin That's not how we decide what's on-topic. Please read scope.
    – wizzwizz4
    Dec 11, 2020 at 7:28

8 Answers 8

6

Sinclair BASIC on the ZX Spectrum would jump to the next available line number. The manual says

If the line number in a GO TO command refers to a non-existent line, then the jump is to the next line after the given number. The same goes for RUN; in fact RUN on its own actually means RUN 0.

3
  • Although it isn't explicit in the manual, I did a test with GOSUB and that seems to work the same way. If the specified line number doesn't exist, it picks the next line.
    – Brian
    Dec 9, 2020 at 21:29
  • Taking this to extremes, what's the behavior when the line number is near integer overflow, e.g. line numbers near 65535? (or +32768, although IIRC Spectrum integers were unsigned). I don't think the Spectrum did wraparound.
    – smci
    Dec 10, 2020 at 5:42
  • 1
    @smci Line numbers can go only up to 9999, line editor won't let you pass the syntactic check otherwise. Though you can get line numbers up to 65535 by modifying the RAM (e.g. POKE). However, trying to GO TO to a number above 32767 will give you either N Statement lost or B Integer out of range error. Dec 11, 2020 at 14:22
14

BASIC dialects are known to vary in details quite a lot. One of the more definitive versions is BBC BASIC, which does the following:

enter image description here

Note the IF-THEN-ELSE construct, which justifies the use of multi-statement IF-THEN bodies - which are in fact useful in practice.

BBC BASIC V added an ENDIF keyword and the facility for multi-line IF-THEN-ELSE-ENDIF blocks. In general BBC BASIC is geared to make structured programming easier than most earlier microcomputer BASICs.

13
  • Oh good point about the then...else, I hadn't considered that because my dialect does not yet support that. So BBC follows MS for GOTO. Dec 7, 2020 at 14:05
  • 1
    @MauryMarkowitz In general you can try out BBC BASIC easily at bbc.godbolt.org . Select the B model for BBC BASIC II, the Master model for BBC BASIC IV, and in both cases enter MODE 0 to get the high-resolution screen I used above.
    – Chromatix
    Dec 7, 2020 at 14:10
  • Almost everyone followed MS - and MS followed DEC.
    – Raffzahn
    Dec 7, 2020 at 15:22
  • @Raffzahn - BBC BASIC was quite different, but the BBC Micro specification did request MS BASIC 5.0 compatibility, which it didn't quite bring: no PRINT USING, for example. Internally, it does things quite differently
    – scruss
    Dec 7, 2020 at 15:36
  • 6
    No matter how much you love BBC BASIC, "One of the more definitive versions is BBC BASIC" is a pretty baseless statement.
    – RonJohn
    Dec 8, 2020 at 7:31
14

The examples are not bugs but undefined behavior, which is common in other languages as well. If you expect cross-platform compatibility, simply don't do things that result in undefined behavior.

Moreover, the programmer's intention in the first example is unclear, which can lead to bugs that are difficult to fix. Again, don't do that. The second example is better because either it works as the programmer intended or the parser complains, making it easy to find and fix the bug quickly.

1
  • 2
    Ok, but the answer to the question is...? OP did not write the code you are criticising.
    – pipe
    Dec 10, 2020 at 0:39
10

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

Will print ONE on Microsoft-derived BASICs, while Dartmouth will produce ONETHREE. That is, MS treats the entire rest of the line as part of the THEN, which is... weird (and wrong IMHO).

Well, I guess there is no right or wrong, but each BASIC's own way. MS' way essentially allow the creation of a code block within a THEN clause without the need of GOTO. With Dartmouth, which works at that point like FORTRAN before, the THEN needs to jump into the code block, followed by a GOTO to get around:

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

Well, or use an inverted clause to jump around the code block. Neither a really great construct.

It must be noted that allowing arbitrary statements after THEN is a later add-on, not present in Dartmouth BASIC. The same goes with multiple statements separated by colon.

With MS' way of treating the whole (rest of the) line as part of the then block allows this constructs without a lot of brain jogging and gotos.

But it wasn't invented by MS, they just took it from DEC BASIC-PLUS of 1972 (After all, MS BASIC is a clone of DEC BASIC) as described on p.3-12 of the manual:

enter image description here

So here after a THEN multiple statements are allowed, but either executed as whole (if the condition is true) or not at all.

Now, when looking for the 'right' ways, it is usually best to first take a look BASIC standards. The first here might be

  • ECMA 55 Minimal BASIC of 1978

    This describes the very minimum every BASIC needs to comply with to be portable. Essentially it codifies Dartmouth BASIC (Thomas Kurtz was one of the editors) in it's later incarnations in a clear and reproducible way. Here THEN statements only allow a line number to jump to.

  • ANSI Minimal BASIC of 1979

    Essentially the ANSI version of ECMA-55.

This is BTW, the point in time were MS-BASIC started to become a normative force

  • ECMA 116 BASIC of 1986, also called 'Full BASIC'

    Here multi statement and multi line THEN constructs and mixtures thereof are possible. Multi statement works like the 'MS way', while multi line needs an ENDIF (or ELSE/ELSEIF) statement to close the block. (It also got many other nie features known from modern BASICs, just with line numbers)

  • ANSI/ISO/IEC Full BASIC of 1987

    Essentially ECMA-116 with a few clarifications/extensions.

So MS does follow what ECMA-116 says ... well, or better maybe the standard codifies what MS did before and thus became defacto standard. A lot of work has been put into these standards to capture a workable common place for BASIC. This includes especially edge cases of seemingly clear issues. I'd consider it best practice to check them whenever there is something open for discussion. Especially because they as well point out issues that have been not decided on/are still open to interpretation.

The example code I have would look up line 25 or the next higher statement [...]

So... does anyone know a version of BASIC that works in this fashion, or is this (as I strongly suspect) simply a bug in the example code?

I do remember a TINY BASIC that allowed to jump 'between' lines to ease computed GOTO, but looking at the original source it seams like this was a modification.

In contrast ECMA-55 states on targets used as targets in THEN/GOTO/GOSUB:

All line-numbers in control-statements shall refer to lines in the program.
1
  • At least DEC had the decency to call it something other than just "BASIC". Dec 7, 2020 at 18:00
1

In pragmatic terms,

  1. Decide what legacy code you want your interpreter to be able to run

  2. Decide which incompatible dialects, if any, you want to support as options

  3. Do the same thing they do.

As Raffzahn brings up, Microsoft’s behavior is more handy than Dartmouth’s, because Microsoft BASIC allows you to write a conditional block with multiple statements. You also say you want to run programs that expect Microsoft’s behavior.

Similarly, it is very unlikely that any legacy code will intentionally GOTO a line that does not exist, but it is possible that some existing program might run correctly despite a typo like GOTO 24 instead of GOTO 25.

If you also need to run code that depends on incompatible behavior, you might provide that as an option.

1

The dialect I used was passing control to the existing line with the closest larger number, if such existed. If not, this was the legitimate way to terminate the program without any error message.

Passing control into the middle of the range allowed adding lines to either side of the entry point. This helped a lot because refactoring was also very tedious: there was no search and the only way to change the line was by retyping it full length in completeness. That version did not have any automated line renumeration.

The machine was some kind of Soviet "Elektronika" but I no not remember precisely. It looked more like a very high end calculator with the own two row LED display on the console, but already supported external monitor and keyboard.

0
-1

As another data point, the BASIC as implemented in the Radio Shack Tandy TRS-80 would report an

UL ERROR

for attempts to GOTO or GOSUB to a non-existing line. UL being the abbreviation for undefined line. So the answer to your question appears to lean towards "it's a bug, not a feature."

-1

Since you are using a basic interpreter to run your program, in most cases it will only process lines of code that it executes.

So if you have a goto statement in your program that is never used, no error will be issued.

A basic compiler would scan every line of code and would 'notice' the invalid goto statement

1
  • 3
    OP is not "using a BASIC interpreter to run [his] program." OP is writing a BASIC interpreter and, In looking for some vintage examples of BASIC code to try out in it, has found one that looks as if it should not run. He is asking if anybody knows of a BASIC implementation that would have run the example without complaining. Dec 9, 2020 at 19:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .