questions on forth

44 views
Skip to first unread message

p da

unread,
Jan 22, 2025, 10:00:43 AMJan 22
to 4th-co...@googlegroups.com
Hello,

This is a bit off-topic since it is not strictly related to 4th but Forth

I have a few questions about forh I couldn't resolve searching for info
first is about word :NONAME, I would like to know where it is compiled, I mean where in memory are saved the words in its definition. As far as I know after reading info is the compilation of a :NONAME definition is implementation dependent, it could be stored in dictionary or in dinyamic memory or whatever. is there any standard stating where to store the definition?

Second question is about a way to alter stack  "programmatically" so I can do pointer arithmeting with stack, i.e:  rather than simply "3" something like "3 TOS !"  so I could also do "3 TOS 2 + !" to set second word in stack  (assuming stack grows downwards and cell size is 2 bytes)

Finally I would like to know how to generate an executable file for a word, let's say I write a program in forth and my entry point is a word called MAIN which is a colon word. What I'd like is to generate machine code for MAIN definition and all words used for MAIN and use MAIN address as entry point in the executable archive, let's say an ELF or PE file.

I've seen most forth implementations allow this by saving the entire forth interpreter (let's say all current memory used by the current forth) and indicate a entry word to call when executing the file (using a special variable or so), for example writing full memory used by interpreted (with all definitions) to ELF file indicating the address of forth entry point as entry point in the ELF file, thus executing forth and execution means to get word to automatically execute and call to NEXT or something like that (for example pushing the word xt and calling EXECUTE).  I'd like to know the exact mechanism of doing this or at least one posible solution (I suppose the process is implementation dependent)

thanks and regards

--
Andrés

~ La mejor manera de librarse de la tentación es caer en ella. ~ Oscar Wilde ~

The Beez

unread,
Jan 23, 2025, 7:30:40 AMJan 23
to 4tH-compiler
Ok, this would be more of a question for comp.lang.forth - because in 4tH, it's either crystal clear - or forbidden. I will answer your question twice, once for 4tH, once for ANS.

1. :NONAME
In 4tH, the code is stored in the Code Segment, the xt is placed on the data stack - and there is NO entry in the symbol table;
In ANS, it is suggested in 3.4.5 and 6.2.0455 a :NONAME definition is placed in the dictionary. It seems the most logical place for it: "During the compilation of the current definition, a program shall not execute any defining word, :NONAME, or any definition that allocates dictionary data space.", "Create an execution token xt, enter compilation state and start the current definition, producing colon-sys."

2. Using ! on data stack items
In 4tH, you can't obtain an address for stack items. In other words: IT'S EXPLICITLY FORBIDDEN;
In ANS, I couldn't find any quote that explicitly forbids it. However, it's a very DIRTY way to do your bidding. It's saying to the world: "Hey, I'm a n00b who thinks he's very clever". Note some Forth implementations store the TOS in a register for performance reasons. There is NO guarantee that the data stack area is either contiguous or static. In short, if it works, it won't be portable - and you will be driven out of the Forth community in tar and feathers. If you want locals, either use the LOCALS word set or define your own; https://www.youtube.com/watch?v=Y7cax2fDS84

3. Turnkey applications
In 4tH, generate a C source and compile it against the 4tH library; https://www.youtube.com/watch?v=cGVpq5gvMAE
In ANS, there is no guarantee whatsoever you can make a standalone executable - so your mileage may vary. AFAIK, you can't do this in Gforth - but in lina or mina you can. I've tried this in the distant past, but I've never been able to produce a viable executable. BTW, it's one of the reasons I created 4tH - to reliably make small Forth executables.

So there you got my take on these issues. Please respond when I've failed to (properly) address one of the subjects you brought on.

Hans Bezemer

p da

unread,
Jan 23, 2025, 12:34:45 PMJan 23
to 4th-co...@googlegroups.com
Thanks a lot for your answers both 4th and ANS

After reading your reply I have some more questions...

1. As far as I remember from 4th manual reading Code Segment is the memory where all code is stored, in particular, colon word definitions. If so, this is equivalent to dictionary in classical forths, so you can say both 4th and most forths "store :noname definitions in dictionary as anonymous words"  since they are anonymous you cannot look them up using FIND or similar, there's no way to locate a created :noname word after creation.  Ok, so the only way to use it is saving its xt somewhere after creation, for example in a variable defined in your code.

But then my question is, how do you free the memory used by a :noname word?  in most forths storing :noname words in dictionary means dictionary will grow with every :noname word created without any way to reclaim the memory, same in 4th as you cannot reclaim the memory in code segment, I understand.

But my understanding is :noname word is a temporary word by definition, you use a :noname word as anonymous code similar to lambdas in other languages, code you pass or use locally and temporally. If it's temporal it should be possible to free up the memory use when not needed anymore (automatically by the system or manually by the user)

It can be argued :noname words are not temporal because you can use it for entire program life (for example using them in defers or storing in a variable for common and frequent use) but then what is the advantage of using :noname words rather than normal defined words?

I suppose :noname is somehow related to quotations but I find quotations much more interesting and useful since you can use combinators  (also I suppose quotation code is compiled in the same word using the quotation, in its parameter field)

Also if :noname hasn't got a name and no entry in the symbol table, how do you locate it to remove it from memory?  I suppose the only way is to find its xt and maybe long traversing the symbol table (or dictionary) but so the system have to keep track of all :noname xt's created,  It's not clear to me, can you explain deeper the internals in 4th?

2. I faced this issue for a very specific problem, not common at all, I know of the special kind of question and very weird programming. 

The problem I faced is in a fig-forth implementation for a old 8-bit computer: abersoft forth for zx spectrum. I have the need to create an autorun program in this forth in a way the forth code is loaded from tape and automatically run after loaded. Abersoft forth has a basic interface to zx spectrum basic, you can exit to basic with a forth word and then do a warm or cold entry from basic into forth. So I can make a loader and saver in basic that saves or load chunks of code or even the whole memory with current state of forth interpreter with all words I have created. The problem is how to tell forth, from basic, to call a word and execute it. My first idea was to push an xt into stack from basic and then do a EXECUTE in forth, in order to do this I need to access the forth stack from basic and so I need to know the real address of SP and poke values directly into stack memory from basic.  As I said very specific issue, but from there I was thinking about how would you do this in forth itself, just for fun  (I didn't find a way at least not a good way).

As you can see my intention was not to use locals, but access forth stack from basic in order to communicate with it.  Anyway I've seen your video about locals already (I'm very fan of you back and forth content) but honestly I didn't understand it very much, I know its about playing with return stack but it's a bit advanced  code for me. Anyway I'm not a big fan of locals ;-)

3. The 4th solution is very clean and smart because you can also cheat the resulting C code, as far as I remember the C code is more or less a big array with all forth code, all 4th segments and a interpreter in C to run the code, very similar to a VM implemented in C. The only cons if any is you dump all code to C, there's no way to translate to C only the words you really need , I know it's a minor complaint anyway.  Is there any limitation in size of programs?  I mean how 4th handles the problem of having several memory segments?  (i mean a segment for code (.text). data (.data) etc, in a segmented memory map common to x86 processors)

thanks a lot for your replies and videos, I always learn a lot from you

regards


--
You received this message because you are subscribed to the Google Groups "4tH-compiler" group.
To unsubscribe from this group and stop receiving emails from it, send an email to 4th-compiler...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/4th-compiler/ee7050fd-d1ee-4752-90d8-ede1e4b81506n%40googlegroups.com.

The Beez

unread,
Jan 23, 2025, 1:17:58 PMJan 23
to 4tH-compiler
1. Well, concerning freeing up memory in the Code Segment / dictionary taken up by :NONAME words - I can be short: YOU DON'T. Yes, the Code Segment / dictionary grows with every :NONAME you define, but that's the way it is. The same goes for "dead code" in libraries I import (code that isn't called by the program). The reason is very simple. This code could be called in a variety of ways - even from references loaded from disk (an XT is just an ordinary number). I can never be assured there isn't some devious scheme involved calling that code. So the safest thing is to keep it in.

2. I have to look into this WARM and COLD things. I've played with those a long time ago using Artic Forth. If you could point it somewhere, you could put it to a word that uses variables or constants. IMHO you can patch those constants (or variables).

3. 4tH saves all initialized data. The Symbol table is discarded and the Character and Integer Segments (which includes the stacks) are allocated at invocation (i.e. exec_4th()) - and destroyed when exiting. And no - nothing is dumped. However, careful inclusion of "just the code you need" will keep the size down. I've once translated Kingdom in Brainf*** to 4tH - and that resulted in millions of opcodes. No problem. As long as you don't exceed the sizes (32/64 bit integers) I guess you're fine. 4tH doesn't deal with .TEXT, .DATA and such. It's all allocated in user space. There is only executable bytecode - not executable machinecode. Yeah, it's still quite fast. That was the hard part ;-)

Hans Bezemer

The Beez

unread,
Jan 23, 2025, 5:41:44 PMJan 23
to 4tH-compiler
Hi!

I looked into the WARM and COLD words on Abersoft Forth and they seem to be just vectors to either start the thing WITH the added definitions (WARM) - or without (COLD). They don't seem to be direct jumps to a startup word. BTW, I'd create VARIABLEs for your parameters and get their addresses - so you can POKE in the required values.

BTW, I used this book for getting my information: https://archive.org/details/AdvancedSpectrumFORTH

Hans Bezemer

On Thursday, January 23, 2025 at 6:34:45 PM UTC+1 euke...@gmail.com wrote:

p da

unread,
Jan 27, 2025, 6:23:32 PMJan 27
to 4th-co...@googlegroups.com
Thanks for the link to the book,  I was reading it and doesn't fully understand what it means with "links numbers" when listing the words in dictionary, I assume is the position in dictionary of every word struct so 1 means the first word and not exactly the contents of the link area in struct.

Anyway, there's a global position in memory (5E45) with an absolute jump to 6DB0 what it supposed to be a jump to WARM word at 6DB0 but that address don't correspond to any field of WARM word, as far as I know (PFA=6DAC CFA=6DAA LFA=6DA8 NFA=6DA3)

Anyway if I understand correctly you suggest to define a variable in Forth and the poke that variable addres in basic to store a xt for the word I want to exec. If so I've already did it but using directly a memory address (40000) rather that a forth variable, and it works but that is not what I really wanted.

What I did is:
FORTH:  ' myword cfa u.  --->   42000 ok  / copy the address to use it in basic
BASIC:  poke 40000, 16: poke 40001,164: goto 3 : REM warm entry to forth
FORTH:  42000 @ execute

if I understand what you say, it's simply to use a variable rather than a hardcoded address:
FORTH:  variable v_myword   v_myword u. --->  25600 ok
BASIC:     poke 25600, 16: poke 25601,164: goto 3
FORTH:   v_myword @ execute

thanks for you replies.


The Beez

unread,
Mar 5, 2025, 8:38:43 AMMar 5
to 4tH-compiler
Eukelade!

BTW, if you're still using Abersoft Forth, this might be of interest to you: http://programandala.net/en.program.abersoft_forth.html

Hans Bezemer
Reply all
Reply to author
Forward
0 new messages