Forth has a history of precedig the code routine with the dictionary header. These headers are typically comprised of the name, count, attributes, and link to the previous header. But what if we wanted to strip out header records that are no longer needed either to reclaim memory or to limit access to these functions? While the name could be erased, it wouldn't reclaim memory, and if memory were reclaimed, then code would be moved and other code that pointed to it will at the very least, no longer work.
In Tachyon on the P1 which only has 32k RAM for code, dictionary, and data etc it was a requirement that dictionary header names could be stripped if need be. The only practical way of doing this is to separate the dictionary from the code. Now if dictionary headers could be placed one after the other without any gaps due to code, then there is no longer any need for dictionary links and headers can be removed and the two sections joined so as to free up memory outside of the new dictionary boundaries. But now the dictionary header needs to point to code, which it does. So this is how the dictionary looks in Tachyon and TAQOZ.
TAQOZ# NFA' DUP $20 DUMP --- 1F280: 03 44 55 50 83 00 04 4F 56 45 52 86 00 03 33 52 '.DUP...OVER...3R' 1F290: 44 88 00 03 34 54 48 8A 00 05 4F 56 45 52 2B 8C 'D...4TH...OVER+.' ok
NFA' is similar to the tick symbol ' which returns the code address of the name that follows it, but NFA' returns the "Name Field Address".
First byte is a combination of the count and upper bits are attribute flags (none) 03
Next the name in plain ASCII 44 55 50
Then finally the code pointer address or CPA which is a 16-bit word 83 00
In Tachyon this CPA needs to be on a word boundary so it might have an extra null byte for padding. Here are two ways of finding the code address, with the latter simply a demonstration of how the code address is derived.
TAQOZ# ' DUP .W --- $0083 ok TAQOZ# NFA' DUP CPA W@ .W --- $0083 ok
The next header in the dictionary comes straight after this and so on, so it's very easy to skip over headers since a count byte is supplied. To facilitate growing code areas and growing dictionary areas, the dictionary is arranged to grow down towards the code growing towards it. So newer words will have a higher code address than other words, but a lower name field address.
In order to automatically strip unwanted headers and reclaim memory, it is helpful if at the time they were created that this could be indicated. Fortunately in addition to the normal : word to create a new defintiion, Tachyon also uses "pub" for those who are familiar with Spin. So pub is a public name and visible and we also have pri that creates a private name with the pri attribute set in the header. Now we have a flag to indicate which ones can be reclaimed which is what the word RECLAIM does. This also strips out any security sensitive names too that are no longer needed, while the code remains intact.
Tachyon does not use IMMEDIATE!
Forth uses dictionary header flags to indicate immediate words such as IF and THEN which execute immediately when used inside a definition as it is being compiled Normally all words and numbers are compiled, but an immediate word says "No, just execute me instead". They do this to calculate and compile something different. The ( and \ symbols are immediate words since they do not compile any comments and instead skip over them. So instead of : <name> code IMMEDIATE ; Tachyon starts the definition with "pre" to indicate a preemptive action. These words are always public as they are only useful in that mode.</name>
The "public" and "private" directives will also control the attributes for variables and constants etc as well as : definitions.
: pub pri pre public private
NOTE:
On the subject of IF THEN BEGIN AGAIN etc that while they executed immediately when they are encountered, that in Tachyon this also means outside of a definition as in an interactive one-liner, since Tachyon compiles everything before execution. The exceptions to this immediate execution are DO LOOP FOR NEXT since they do not need to do anything at compile time nor compile a runtime substitute, but instead are compiled like any other instructions. See the wiki about "Interactive compilation" for further information.