ZX81 BASIC programs

40 views
Skip to first unread message

The Beez

unread,
Mar 28, 2025, 8:54:56 AMMar 28
to 4tH-compiler
Hi 4tH-ers!

This is a uBasic/4tH thingy, so if that is not your thing, then you can leave it be.

Yesterday I picked up on my ZX81 programs. Most of 'em are forgotten and I doubt whether they will ever gather any interest apart from 8-bit enthusiasts. 

But to me these are a treasure chest, because:
(a) They are usually very short;
(b) They use single letter variables; 
(c) Their memory requirements are very modest. 

Of course, if FP is used, I can use fixed point calculations (we got the library) and most of the graphics can be replaced by bare ASCII. Just when it comes to direct screen position addressing, machinecode and INKEY$, I have to pass up.

Another thing that bothers me (but can be fixed) is that arrays (and strings) are 1-based, instead of zero.

It doesn't take too long to do a conversion - and that will give them a few more years of usefulness. Most of these thingies are trivial or just simple games, but that doesn't mean they're not educational or fun.

Anyways, I find it relaxing to convert a few every now and then. You'll find them in the repository.

Hans Bezemer

Lionel G

unread,
Mar 28, 2025, 10:39:44 AMMar 28
to 4th-co...@googlegroups.com
Hi Beez!
It seems to me that there was a Forth for the ZX81 (Z80?), is it complicated to adapt a Basic code for ZX in Forth language?  
Just a question, I'm not a specialist.
Bon vent, and by the way: where's the repository you're talking about? on github?

--
You received this message because you are subscribed to the Google Groups "4tH-compiler" group.
To unsubscribe from this group and stop receiving emails from it, send an email to 4th-compiler...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/4th-compiler/49bc76bf-bb01-4bf0-9534-83d3fc31c7b6n%40googlegroups.com.

The Beez

unread,
Mar 29, 2025, 11:17:58 AMMar 29
to 4tH-compiler
Hi Euchcat!

There were/are several Forths for the ZX81. AFAIK CamelForth and Toddy Forth are modern implementations for the ZX81, based on Forth-79. Artic Forth, of course (also sold for the US TS-1000), was also sold by Sinclair themselves. I don't know whether the ZX Spectrum Sinclair Artic Forth was derived from this version. BTW, the latter was my first Forth! Then we got the Husband ROM version of Forth for the ZX81. And that's about it as far as I know. You see, porting a Z80 Forth to the Sinclair family of machines was not a huge task, so I wouldn't be surprised if there were several more.

A few links:

As always, if you want to convert a BASIC program to Forth, you have to go beyond a simple syntactic conversion - like I do for uBasic/4tH. There I just convert the syntax and see if it performs like it should. If the input and output appears sane - we're done ;-)

However, if you want to convert to Forth, you have to know EXACTLY what every statement does, how the flow control works, which variable pops into scope at which moment, etc.  See: https://www.youtube.com/watch?v=gfE8arB3uWk

So this is what we have to work with:

100 DIM X(6)
110 PRINT "SOLUTIONS TO 2 EQUATIONS:"
120 PRINT "A*X + B*Y + C =0",,,"ENTER DATA"
130 FOR I=1 TO 6
140 PRINT CHR$ (37+I-INT ((I-1)/3)*3),
150 INPUT X(I)
160 PRINT X(I)
170 NEXT I
300 LET D = X(2)*X(4)-X(1)*X(5)
310 IF D=0 THEN GOTO 360
320 LET A = ( X(3)*X(5) - X(2)*X(6) ) / D
330 LET B = ( X(1)*X(6) - X(3)*X(4) ) / D
340 PRINT "SOLUTIONS ARE:" : PRINT "X=" ; A , , "Y=" ; B
350 STOP
360 PRINT "DEGENERATE: NO SOLUTIONS"

Then we (optionally) transform it to a more structured form:

Print "Solutions To 2 Equations:"
Print "A*X + B*Y + C = 0"

For I=0 To 5
  If I%3=0 Then Print
  Print Chr(I%3+Ord("A"));
  Input @(I)
Next

D = @(1)*@(3)-@(0)*@(4) : Print

If D = 0 Then
  Print "Degenerate: no solutions"
Else
  A = (@(2)*@(4)-@(1)*@(5))/D
  B = (@(0)*@(5)-@(2)*@(3))/D
  Print "Solutions are:","","X=";A,"","Y=";B
Endif


And finally transform it to Forth. I'll come back to that.. ;-)

Hans Bezemer

The Beez

unread,
Mar 29, 2025, 11:56:33 AMMar 29
to 4tH-compiler
I got back to it.

include lib/enter.4th

6 constant /z                          \ two expressions, three unknowns
/z array z                             \ allocate space for expressions

: z@ z /z bounds ?do i @ loop ;        ( -- #0 #1 #2 #3 #4 #5)
: .'A' 3 mod dup unless cr then [char] A + emit space ;
: calc-D drop rot drop >r rot r> * >r * r> - ;
: calc-A rot drop -rot * -rot * - nip over / ;
: calc-B >r drop * r> rot drop rot * swap - swap / ;

." Solutions To 2 Equations:" cr ." A*X + B*Y + C = 0" cr
                                       ( D = #1*#3-#0*#4)
/z 0 ?do i .'A' enter z i th ! loop cr z@ calc-D
dup unless drop ." Degenerate: no solutions" cr ;then
                                       ( A = #2*#4-#1*#5/D)
z@ calc-A >r z@ calc-B r> ." Solutions are: X=" . ." Y=" . cr
                                       ( B = #0*#5-#2*#3/D)

Notice how elegantly I sneaked all stack acrobatics in three single liners in order to fake a structure. ;-)

Hans Bezemer

The Beez

unread,
Mar 29, 2025, 12:36:08 PMMar 29
to 4tH-compiler
This is my final bid. I took care that calc-A and calc-B have the same stack diagram. I let my program STACKOPT.4TH figure out the acrobatics and consequently could extract some stack effects into a new word. This program basically puts the parameters in a almost optimal position so they're easy to process afterwards.

include lib/enter.4th

6 constant /z                          \ two expressions, three unknowns
/z array z                             \ allocate space for expressions

: junk drop rot drop ;                 ( n1 n2 n3 n4 -- n2 n3)

: z@ z /z bounds ?do i @ loop ;        ( -- #0 #1 #2 #3 #4 #5)
: .'A' 3 mod dup unless cr then [char] A + emit space ;
: calc-D junk -rot * -rot * - ;        ( D = #1*#3-#0*#4)
: calc-A >r >r junk r> rot r> * >r * r> - swap / ;
: calc-B >r junk rot r> * -rot * - swap / ;
                                       ( n1 -- n2/n1)

." Solutions To 2 Equations:" cr ." A*X + B*Y + C = 0" cr
/z 0 ?do i .'A' enter z i th ! loop cr z@ calc-D
dup unless drop ." Degenerate: no solutions" cr ;then dup
z@ calc-A >r z@ calc-B r>              ( A = #2*#4-#1*#5/D)

." Solutions are: X=" . ." Y=" . cr    ( B = #0*#5-#2*#3/D)

Hans Bezemer

Lionel G

unread,
Mar 29, 2025, 6:47:47 PMMar 29
to 4th-co...@googlegroups.com

Lionel G

unread,
Mar 29, 2025, 7:02:43 PMMar 29
to 4th-co...@googlegroups.com
Fantastic, great job ! Thank you !

The Beez

unread,
Mar 30, 2025, 8:33:38 AMMar 30
to 4tH-compiler
Hi 4tHers!

While converting a ZX81 program, the uBasic/4tH interpreter started to behave erratically. That's always frightening - when your carefully crafted abstractions start falling apart.
Well, I found the culprit: token may be no longer than 96 characters. Otherwise, it starts to clobber things.

Now this parsing routine is in the middle of the action. It is called constantly. Adding a check in the middle would deteriorate the performance significantly. So what to do?
First, I redesigned those routines (because I had learned a few tricks in the meanwhile), so they were more comprehensible and leaner. 

Then I thought - "Why should I check those addresses the whole time? When done, I can check the pointers anyway. If they're foul, I can bomb out. If they're very foul, 4tH itself will throw an exception."

So, that's how it was done. Performance didn't suffer and a new error message was easily added. Source is in SVN (the repository). Which is here: https://sourceforge.net/projects/forth-4th/ Try the tab "Code", browse till the directory "4th.src". The name of the code is (of course) ubasic.4th

Hans Bezemer

The Beez

unread,
Mar 30, 2025, 8:39:19 AMMar 30
to 4tH-compiler
You're welcome! BTW, several sources have gone this way. 23match.4th and 23match.bas are an example. lander.bas, lander.4th and lander.4pp are another, if I'm correct.

Hans Bezemer
Reply all
Reply to author
Forward
0 new messages