Another full circle!

27 views
Skip to first unread message

The Beez

unread,
May 5, 2025, 7:17:43 AMMay 5
to 4tH-compiler
Hi 4tH-ers!

Yeah, I kind of like to complete circles. ;-)

Now - imagine you are browsing around in a new release of uBasic/4tH (this is gonna be Forth, I promise!) and you think, "Let's execute this FSTARFRT.BAS file".

And it does nothing - it only issues:

$ ubasic fstarfrt.bas
Please transpile this program first by using "uBForth.bas".

Whazzat?! So you enter:

$ ubasic ubforth.bas fstarfrt.bas basic.bas
>> Transpiling "fstarfrt.bas" to "basic.bas" <<


And then issue:

$ ubasic basic.bas

Which results in:

1 little 2 little 3 little indians  
4 little 5 little 6 little indians  
7 little 8 little 9 little indians  
10 little indian boys.  

year  1    balance 1060  
year  2    balance 1124  
year  3    balance 1191  
year  4    balance 1262  
year  5    balance 1338  
year  6    balance 1418  
year  7    balance 1503  
year  8    balance 1593  
year  9    balance 1689  
year 10    balance 1790  
year 11    balance 1897  
year 12    balance 2011  

More than doubled in 12 years  

0 OK, -501917632107277148:456

And you recognize that output: it is from an example program in "Starting Forth!". So curiously, you open the source file and see:

Rem Forth
Rem : poem  cr 11 1 do  i . ." little "
Rem       i 3 mod 0= if ." indians " cr then
Rem    loop  ." indian boys. " cr ;
Rem
Rem : percent * 10 /  5 +  10 / ;
Rem : show dup 10 < if space then . ;
Rem
Rem : doubled
Rem    6 1000 21 1 do  cr ." year " i show
Rem       over over percent +  dup ."    balance " .
Rem       dup 2000 > if  cr cr ." More than doubled in "
Rem       i . ." years " cr leave then
Rem    loop drop drop ;
Rem uBasic

   
Proc _poem
Proc _doubled

Forth?! In a BASIC program? Called by BASIC? What is this?!

Well, I got the idea when I watched this YT video: https://www.youtube.com/watch?v=xyfXxW8UuBM&t=47s

I've always loved the ZX Spectrum - and there are still lot of ZX Spectrumisms in 4tH. The device presented in the video, the Currah MicroSource, allowed you to embed Forth and Assembler in ZX Basic.

So even while watching that video my brain started to play with the idea. uBasic/4tH has a LOT of Forth features which it inherited from its 4tH foundation. I could do this. So I started working on a program that could do just that.

In the end, it supported over 80 Forth words. It's enough to compile simple programs. E.g. this source is transpiled to:

If 0 Then
_poem
Print : Push 11 : Push 1
For i=Pop() To Pop()-1
Push i : Print Pop();" "; : Print "little ";
Push i : Push 3 : Proc _mod : Push Pop()=0 : If Pop() Then
Print "indians "; : Print
Endif
Next
Print "indian boys. "; : Print
Return
EndIf

If 0 Then
_percent
Proc _mul : Push 10 : Proc _div : Push 5 : Proc _plus : Push 10 : Proc _div
Return
EndIf

If 0 Then
_show
Push Tos() : Push 10 : Proc _less : If Pop() Then
Print " ";
Endif
Print Pop();" ";
Return
EndIf

If 0 Then
_doubled
Push 6 : Push 1000 : Push 21 : Push 1
For i=Pop() To Pop()-1
Print : Print "year "; : Push i : Proc _show
Proc _over : Proc _over : Proc _percent : Proc _plus : Push Tos() : Print "   balance "; : Print Pop();" ";
Push Tos() : Push 2000 : Proc _greater : If Pop() Then
Print : Print : Print "More than doubled in ";
Push i : Print Pop();" "; : Print "years "; : Print : Break
Endif
Next
Proc _drop : Proc _drop
Return
EndIf

Proc _poem
Proc _doubled

End

So -- although you think you wrote Forth, it is actually uBasic/4tH. Most words are directly translated to their uBasic/4tH equivalent. Other depend on the small "runtime" that is automatically attached to the program - here a few snippets:

_clip Param (2) : Return (Clip(a@, b@))
_append Param (2) : Return (Join(a@, b@))
_drop Param (1) : Return
_swap Param (2) : Push b@, a@ : Return
_over Param (2) : Push a@, b@, a@ : Return

Of course, there are several restrictions:
  1. There is no Return Stack;
  2. Names that are not valid uBasic/4tH names don't work;
  3. You cannot define variables, strings or array. The predefined uBasic/4tH resources is all you got. They appear as VALUEs, and yes, TO and +TO a supported. Retrieving their values requires you prepend them with a "&";
  4. +LOOP and nested DO..LOOPs are not supported. The variable "i" is used by a DO..LOOP;
  5. Strings require only one single item on the stack. Thus, string functions require not two, but only one item. A count can be acquired by the non-ANS word LEN;
  6. 0 THROW has effect and is not ignored!
But all in all it's a cute package that allows you - like it's inspiration, the MicroSource - to mix Forth and BASIC. Note you can inline Forth within a BASIC function or procedure and BASIC into a Forth word:

Rem : calculate                            ( g v1 h1 f1 u -- g v2 h2 f2 flag)
Rem   to u to f to h to v to g
Rem uBasic
      Let f = f - u
      Let h = h - v
      Let v = (((v + g) * 10) - (u * 2)) / 10
Rem Forth
Rem   &g &v &h &f over 0> 0=               \ return height and fuel
Rem ;

I think that's neat! Also note how you can use BASIC variables in Forth and vice versa! Of course, it's not "true" Forth, it's transpiled Forth.

So - we started with Forth (4tH) that gave rise to BASIC (uBasic/4tH) that supported Forth. I'd say that's full circle!

Hans Bezemer


Reply all
Reply to author
Forward
0 new messages