Taqoz Reloaded 2.8 - Better Readability: Named Local Variables
It does not help to deny, that Forth source code can be hard to read!
In my opinion, there are several reasons for this problem.
1. RPN: operands first followed by operators. - Well, we will not change this, because it makes Forth compact and fast.
2. Source code writing style. - In old systems source code was written in screens of 16 lines only. This led to compact style, sometimes all comments have been moved to a separate "shadow" screen. This is no longer necessary. Today Forth source code can be written more vertically with nice indentation.
3. Several operands needed in a word hidden and moving on the stack. - We will tackle this here:
Example:
Let's assume, you want to build a word (function) which gives TRUE, if a number is within bounds.
: inbds ( testval lowLimit hiLimit -- false_true ) \ traditional 3RD > rot rot \ to get the first result out of the way nop > and ;
nop is only needed because this ??? formatting here
There are 2 issues:
1. You need testval twice, which is solved here by 3RD.
2. The first logical result is on top of stack and gets in the way, which is solved by rot rot. If your function word is a little bit longer, it will be easy to loose track of the content of the stack and it's positions.
So here is version with locals which have fixed names a...e and can be accessed with a> and >a:
: inbods loc_a_b_c ( testval lowLimit hiLimit -- false_true ) \ fixed named locals a> b> > a> c> < and endloc ;
And here is the new version with named locals:
: inbounds {: testval lowLimit hiLimit -- false_true } \ with named locals testval lowLimit > testval hiLimit < AND ;
This uses a modified stack diagram as syntax for the definition of the variable names.
{: starts the definitions of names of initialized local variables
, starts the definitions of names of non-initialized local variables ( not used here )
-- starts comment
} finish of the modified stack diagram
These locals are of type VALUE and can be written with a preceding to or +to.
Implementation:
Separate stacks are used for locals of each cog. Unnamed and named locals use the same stack, which holds fixed stack frames of 5 numbers. These frames are allocated and freed as a block each.
It took me a while to find a way to implement named locals. Some difficulty is given because the stack diagram follows the already begun colon definition. In Taqoz there are 2 separate parts of the dictionary. So it is possible to define ALIAS names for the locals while the compilation of the new word is already running. The compiler will then instantly use the new names. No modification of the compiler itself is necessary.
Limitations:
- Number of local variables is limited to 5 per word by choice. - I had started with 3 only and then incremented this. 5 seems to cover most.
- The ALIAS function might overwrite old words.
- Decompiling with SEE or DECOMP will show the last ALIAS names for the local variables. So it is advisable to use these directly following the word definition.
- If there is an error while compiling a name of a local will be displayed instead of the name the word and you have to FORGET the faulty word.
For the rest of the file see:
https://forums.parallax.com/discussion/173841/p2-taqoz-forth-v2-8-some-tools-value-simple-local-variables-dcf77#latest
Have fun!
Christof
Comments
yes that is my main problem with forth, i like it because compact but it is sort of a write only language, reading forth is sort of a challenge
Mike
Good layout and comments are so often missing in forth on the www in a kind of macho display of 'look how small my source code is'. I quite often adopt other peoples' work for use in Taqoz and such source has to be 'decoded'. Without comments and stack notation, it's a challenge to translate into taqoz. I wish more folks would paste tachyon / taqoz snippets here, too. There's many aspects of these languages I still know little about - and you can't have too many examples.
Well, in my experience the RPN part of it is something that you can get accustomed to quite easily and it is well worth the effort. The modern interactive competitor Micropython is way slower and needs way more storage. Lua might be a compromise sometimes. The Forth tradition to create short words, which can be debugged easily due to the possibility of interactive testing is really satisfying because it gives better efficiency during programming in my experience. You always make small progress.
For me these locals solve the part of "stack juggling" and do help a lot. It is kind of funny, that without these, it is sometimes more easy and straight forward to write code in assembler, because you can then use several registers. And those old Forth specialists are all capable of doing it. A good example is FIBO in extend.fth, which uses a special word BOUNDS, which is cog assembler.
The only problem with locals is, that this part of Forth was not standardised, but many more modern versions support it with similar syntax.
win32forth.sourceforge.net/doc/p-locals.htm or https://complang.tuwien.ac.at/forth/gforth/Docs-html/Gforth-locals.html or
https://esp32forth.appspot.com/ESP32forth.html
Unfortunately Peter used up { to start multiline comments (which are a very good idea), so I had to resort to something different and used {: .
Have fun!
Christof
So now I have updated Auto.I in the first post to use some assembler.
And included several versions of fibonacci for speed comparison in file fiboTestsA.fth
This algorithm does work a lot with variables, so it is their speed, which is measured.
The assembler version holds all variables in cog ram.
Well, the speed penalty to use these locals is quiet heavy.
Have fun, Christof
See here for update: https://forums.parallax.com/discussion/174970/p2-taqoz-v2-8-lutlongs-value-type-variables-locals-now-in-lut-and-faster/p1?new=1