16

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?

Maury Markowitz
  • 19,803
  • 1
  • 47
  • 138
  • 29
    Correction: we are not the "hoi polloi", we are elite custodians of history :-) – dave Dec 07 '20 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 – Omar and Lorraine Dec 07 '20 at 13:57
  • 2
    @OmarL - I just tried with GW-BASIC: it gives the same error – scruss Dec 07 '20 at 15:25
  • I'm suspecting a typo, too. Every BASIC I've tried gives an error with the GOTO 25 – scruss Dec 07 '20 at 15:34
  • Ok excellent work everyone! GW was the interesting case because I suspect that's what the original code was aiming for. – Maury Markowitz Dec 07 '20 at 16:58
  • 1
    @OmarL "the Sinclair BASIC" for the Sinclair QL GOes TO the next higher line number when a non-existant one is given. – tofro Dec 07 '20 at 17:45
  • 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. – Alex Taylor Dec 07 '20 at 22:21
  • I did this on a TRS-80 model IV. It went to line 30. – Joshua Dec 07 '20 at 22:39
  • I never tried it on a line-controlled BASIC, but being able to use : inside a THEN would be super convenient as opposing to having to GOTO. – Joshua Dec 07 '20 at 22:41
  • I'm pretty sure that Apple Basic would throw a non-existant line error, for the 'goto'. I'm not sure about Pro-Dos. The other line would likely throw a Syntax Error. It has been 30 years since I played with basic though. – Rowan Hawkins Dec 07 '20 at 23:26
  • 1
    @another-dave We’re the hoi polloi who type our PIN number into the ATM machine in the Sahara desert to use our IRA account with the Department of Redundancy Department? – Davislor Dec 08 '20 at 00:19
  • 1
    This is kind of irrelevant to what existing implementations that you want to be backward-compatible with actually do, but: if the IF statement covers all remaining statements on the line, it’s possible to write a conditional block with multiple statements. (Modern languages would use braces or the offside rule.) You can still put another statement that should be executed unconditionally on a separate line. – Davislor Dec 08 '20 at 00:24
  • There's definitely versions which GOTO the next higher line number, as that was my immediate response. Although most of my BASIC was on a Vic-20 or an Amiga, so if Commodore doesn't do it not sure which flavour it was. – Mick O'Hea Dec 08 '20 at 16:55
  • @MickO'Hea - ok I think the solution is to have a command line switch for this. if anyone comes across a version that does this, PLEASE let me know! – Maury Markowitz Dec 09 '20 at 14:34
  • The bit about the IF statement is interesting but doesn't seem to have much to do with this question. I think the question would be stronger if it were omitted, or at least moved to the bottom with a "This doesn't matter for this questions, but you may find it interesting" lead-in. – Wayne Conrad Dec 09 '20 at 16:24
  • I forgot to say: Cool that you're writing a BASIC interpreter. That's great fun! – Wayne Conrad Dec 09 '20 at 16:37
  • I'm sorry to point out, that isn't about Retrocomputing… it's about the language BASIC and even then, about the differences among dialects. – Robbie Goodwin Dec 10 '20 at 21:44
  • @RobbieGoodwin - retrocomputer dialects – Maury Markowitz Dec 10 '20 at 22:17
  • @Maury Markowitz Jolly good… and then what? – Robbie Goodwin Dec 10 '20 at 22:20
  • 1
    @RobbieGoodwin The question is on-topic. – wizzwizz4 Dec 10 '20 at 22:30
  • @wizzwizz4 Jolly good… and then what? GOTO a non-existent line works or fails in the implementation or dialect of BASIC - or whatever other language - you happen to be using. That's not about retro- anything… it's about which implementation of which language you happen to be using.

    If you're suggesting BASIC has no place in modern IT, why not say so, and justify your argument?

    – Robbie Goodwin Dec 10 '20 at 23:55
  • 2
    @RobbieGoodwin That's not how we decide what's on-topic. Please read [meta-tag:scope]. – wizzwizz4 Dec 11 '20 at 07:28
  • ZX Basic does have a "line not found" error, but it's not caused by GOTO or GOSUB. It's most usually caused by corruption of the program representation in memory. – Toby Speight Dec 11 '20 at 20:50
  • @MauryMarkowitz; wizzwizz4 The Question is about Retrocomputing to the extent you show that BASIC is no part of today's IT syllabus.

    IF that's your contention, why not explain?

    ELSE IF BASIC = Retro(owt) THEN

    IF (Scope has no relevance here) THEN GOTO a generic BASIC interpreter

    ELSE IF (some generic BASIC interpreter) has no relevance THEN GOTO OOPS

    ELSE IF (no other excuse) THEN GOTO (dialect definition DD)

    DIALECT DEFINITION DD:

    IF dialect definition insists GOTO in one or all BASIC dialects = Retrocomputing THEN GOTO (Do what, Mate?)

    ELSE duh!

    – Robbie Goodwin Dec 13 '20 at 02:05
  • I tried your examples in Atari BASIC. The first one prints ONE like Microsoft's, but the second example gives an error. – dan04 Jun 25 '21 at 05:47

8 Answers8

15

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.

Chromatix
  • 16,791
  • 1
  • 49
  • 69
  • 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. – Maury Markowitz Dec 07 '20 at 14:05
  • 1
    @MauryMarkowitz In general you can try out BBC BASIC easily at https://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 07 '20 at 14:10
  • Almost everyone followed MS - and MS followed DEC. – Raffzahn Dec 07 '20 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 07 '20 at 15:36
  • @scruss Well, that's the way the qualifier 'almost' works, isn't it. But more important, internal workings were never really of concern here. For the IF/THEN it exactly followed DEC-BASIC and as well MS-BASIC which had that construct in its 5.x version (limited to within one line) – Raffzahn Dec 07 '20 at 15:46
  • @scruss It seems like MS BASIC 5.0 was specified as a fallback position, with the possibility of a superior home-grown dialect explicitly allowed for in the spec. See the early paragraphs. Acorn worked closely with the BBC to develop the new dialect, and the result was a definite improvement over the typical MS-derived version. – Chromatix Dec 07 '20 at 20: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 08 '20 at 07:31
  • @RonJohn - as it was pretty-much the only popular 8-bit BASIC to support named procedures with local variables (kind-of), and just about the only BASIC anywhere to have an inline assembler, as well as including REPEAT-UNTIL loops, which few other contemporary BASICs did, I think the statement is justifiable. – occipita Dec 10 '20 at 18:20
  • @occipita "definitive" means not only "conclusive" and "final" but also authoritative. The closest you'll get the authoritative versions of 8-bit BASIC is MS BASIC. So lets agree that BBC BASIC is the pinnacle of 8-bit BASIC. – RonJohn Dec 10 '20 at 20:21
  • @RonJohn BBC BASIC included those features because the BBC defined the feature set they wanted, for the purposes of defining a language they could use for televised computer literacy education, along with the excellent BBC Microcomputer that embodied it. BBC BASIC was subsequently ported to a large number of non-Acorn platforms by one of the BBC employees who had worked on the spec. Maybe it got less traction in the US than in Europe, but over here it really defined what a high-quality BASIC dialect looked like. – Chromatix Dec 11 '20 at 05:52
  • @Chromatix so... it's the definitive European BASIC. – RonJohn Dec 11 '20 at 07:03
  • @RonJohn Enough to substantiate my original claim, no? – Chromatix Dec 11 '20 at 09:17
  • @Chromatix enough to substantiate it in one specific region. – RonJohn Dec 11 '20 at 13:45
15

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.

snips-n-snails
  • 17,548
  • 3
  • 63
  • 120
  • 2
    Ok, but the answer to the question is...? OP did not write the code you are criticising. – pipe Dec 10 '20 at 00:39
11

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.
Raffzahn
  • 222,541
  • 22
  • 631
  • 918
8

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.

Brian
  • 288
  • 1
  • 5
  • 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 09 '20 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 '20 at 05: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. – Radovan Garabík Dec 11 '20 at 14:22
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.

Davislor
  • 8,686
  • 1
  • 28
  • 34
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.

h22
  • 413
  • 2
  • 10
-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."

Jens
  • 101
  • 3
-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

Dave
  • 99
  • 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. – Solomon Slow Dec 09 '20 at 19:59