More FOR nonsense

David Hembrow noted on Mastodon that you can do some very odd things in Sinclair BASIC with code “hidden” after a REM statement:

   10 LET three=3
   20 FOR f=1 TO 0
   30 REM hello again: NEXT f: FOR g=SGN f TO three: PRINT g: NEXT g: PRINT "woops": INPUT 
   40 NEXT g
   50 PRINT f
   60 NEXT f

Entering a colon in a REM statement will put you in command entry mode, except not quite enough to parse constants correctly. Hence the need for SGN f TO three to make the loop in the REM statement run.

3 Likes

Executing code after a REM statement is something quite special!

I suspect another 8-bit memory constraint optimisation there though…

-Gordon

I typed this in - quite tricky with a normal keyboard - it didn’t like my attempt at line 30.

Could you perhaps show us what you see?

(I don’t understand what line 40 is doing at all…)

I’m not sure it ever gets to line 40. The code should look like this

I’ve put a zipped tape image here, because ZX Spectrum keyboards are bad: https://scruss.com/wordpress/wp-content/uploads/2026/05/zxspectrum-basic-woops.zip

When run it will print 1 2 3 woops (on separate lines), then fail with an error:

This will run on a ZX Spectrum 128 if you load it from tape, but not if you enter it from the keyboard in 128 mode. It won’t work at all on a ZX81 as multiple BASIC commands on a line aren’t allowed.

That half-baked state of the tokeniser is quite special.

As to whether it’s expected or not to see a NEXT that’s behind a REM, that very much depends on where your expectations come from!

In BBC Basic, DATA is a token which needs to be scanned for, and it has to be the first token on the line. Similarly, DEF. And in both cases, they also act like REM in that the rest of the line is skipped at execution time. One way to look at that picture is that the program is line-oriented, even though it allows for multi statement lines.

1 Like

I’m unfamiliar with the ZX Spectrum, so had to do some looking to find out that the error message is not a language war commentary. ‘C’ is an error code that happens to mean a statement wasn’t valid BASIC code.

1 Like

It’s slightly half-baked, but if you watch the cursor while entering a line of BASIC, it starts in Keywords mode, goes into Letters mode after REM, and goes back into Keywords mode after you type a colon in the same line:

spec_rem

It’s trying to do a lot with a little code, and always switching to Keywords after a colon makes some sense. It also helps to explain why some keywords (such as TO) are entered like punctuation: they force the parser out of Letters mode and back into Keywords mode.

2 Likes

The Mastodon link gave a 404.
I haven’t worked with a Sinclair for years.
Not sure if “LET three=3” works or if three results just in a “t”
Or F=1 needs a space.
The output: Nonsense in BASIC.. is also not standard.

Yes, sorry about that. Seems my friend keeps their feed private.

LET three=3 defines the variable named ‘three’ with value 3. Code after a REM statement doesn’t tokenize constants, so you have to use workarounds like SGN f for 1 and the variable three.

BASIC doesn’t define standard error messages. Sinclair’s ones are unusual, but likely encoded to be small. Better than the two letter codes from PDP-8 BASIC.

Could one have used INT PI instead of the intermediate variable ‘three’?

Not quite on topic, in this multi-part article on Efficient Basic Coding (which is specifically about ZX Basic) I see something most unexpected:

Another special case of expression with numeric values occurs when we wish to increment a variable cyclically , that is, to assign increasing values from 1 to n and then to 1 again. This can be done without IF in this way: LET v = v + 1 OR v = n

1 Like

Oh gosh, that’s fabulous. Relies on TRUE == 1.

I’m sure INT PI would work for 3, too.

2 Likes

Not sure where I’ve explored this before, but I remembered I’d previously thought about using conditional NEXT statements. I’d hoped it could be faster than GOTO - not sure I ever tested that. But they do allow conditional jumps without executing GOTO each time. Here’s a test I did today. I can use conditional NEXT to restart the current loop or jump into another loop.


I hadn’t worked out if conditional FOR could be useful - maybe you have “FOR x” in two places, and whichever had been executed would be jumped to when you do “NEXT x” - but I haven’t tested it.

Was this “More FOR nonsense” a reference to a previous discussion about FOR nonsense?

Yes indeed, it was a part of this discussion:

1 Like

Thanks. I see that also had conditional NEXT, but used differently.

I had a brainwave and came to understand something I’ve seen once or twice done in BBC Basic - the deliberate use of a non-anonymous NEXT to act as a break:

PROCstopat3
PRINT ;"stopped at "N
END

DEFPROCstopat3
FOR I=1 TO 0
FOR N=1 TO 10
IF N=3 THEN NEXT I:ENDPROC
PRINT N
NEXT
NEXT
ENDPROC

Without something like this, we need to set the loop variable to something which will exit and then do NEXT, which is a bit clunky:

IF N=3 THEN N=11:NEXT:ENDPROC

This idiom as written does rely on FOR I running at least once, but it also works with

FOR I=1 TO 1
1 Like