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?!
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:
- There is no Return Stack;
- Names that are not valid uBasic/4tH names don't work;
- 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 "&";
- +LOOP and nested DO..LOOPs are not supported. The variable "i" is used by a DO..LOOP;
- 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;
- 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