pdragon wrote:
1. use some external preprocessor to inline and remove constants in the forth source before compiling
This is not an unreasonable thing to do. I believe Druzyek wrote a tool to replace all names (variables, constants, words) with short names (not quite what you are suggesting, and his system has multiple banks of RAM so his solution is even more complicated, but this was done to reduce dictionary size).
http://forum.6502.org/viewtopic.php?f=9&t=5911&start=15#p73213 Note that this can be done in Forth itself, if you want, as long as you have storage to write the results to so that you can run the result afterwards.
pdragon wrote:
2. use a wordlist to hold all the symbols and then throw it away (can I cleanly recover all the space?)
The entries are compiled into the dictionary as they are encountered. If you were to use something like MARKER to eliminate the unneeded words, it would forget the final words you compiled using those constants as well. There isn't an easy way to keep newly compiled stuff while forgetting older compiled stuff (some Forths can do this, but Tali doesn't currently support it).
pdragon wrote:
3. write some store / fetch symbol words that mange compile #define's in a separate associative array that I can discard after
This might not be a bad way to go - it's what the C compilers do. I'd recommend using ram starting just before the history buffers and growing downwards towards smaller addresses, as the dictionary will be growing upwards towards larger addresses. There isn't an easy way to manage "holes" in the allocated dictionary space, so this avoids that issue entirely by only compiling things into the dictionary that you want there.
pdragon wrote:
Constants in Forth behave differently from their equivalents in other programming languages. In other languages, a constant (such as an EQU in assembler or a #define in C) only exists at compile-time ... Some Forth compilers attempt to optimise constants by in-lining them where they are used.
Tali does not currently inline constants, so they will be compiled as a JSR to where they are defined in the dictionary. It's true that constants are handled differently, but everything in Forth is centered around the dictionary so it should be no surprise that that is where they go.
When you "run" a constant by using its name, it actually runs a little bit of code that looks up its value and places it on the stack. Tali saves constants in memory by compiling a JSR to doconst (the name of that bit of code) and the value is placed in memory just after the JSR. The doconst routine looks at where it was called from, gets the constant value that is next in memory, and then adjusts its return address on the stack before doing an RTS so that it returns to just after the value, esentialy hopping over the value after using it.
pdragon wrote:
You can force Gforth to in-line a constant like this ...
Code:
: someword ... [ my-const ] ... ;
You are missing the important LITERAL that comes right after the [ my-const ]. LITERAL takes a value off the stack and compiles it into the word as a constant literal. The square brackes are just to get you out of compiling mode and back into inerpreting mode so that your constant will RUN and place its value on the stack immediately, rather than COMPILE which would arrange for that to be run later. This ends up using more memory, as you will now have two copies of the constant in memory - one with a name and one without, but it will run very slightly faster.
pdragon wrote:
However, the definition of the constant still remains in the dictionary. Some Forth compilers provide a mechanism for controlling a second dictionary for holding transient words such that this second dictionary can be deleted later in order to recover memory space. However, there is no standard way of doing this.
This is all true. Some Forths have the capability to forget individual words, but Tali is not one of them. You are almost entering the topic of metacompiling at this point, so that might be a topic for you to research (there are several interesting threads on metacompiling).
I think option 1 is likely your fastest path to get what you want.
Option 3 looks interesting, so if you decide to go that route, certainly let us know. If you need help fleshing out what a solution might look like, just ask.
As an option 4, if you have mass storage on your system, you can also use screens as a virtual memory to store data. It would be slower, but you could move all of your named constants there with some helper words to look them up.