sorry to hear you gave up; how do things like luajit and node handle the x^w thing? also, i thought jonesforth was entirely interpretive; i didn't think it generated new machine code at runtime?

a standard approach for target-compiling forth applications onto small machines, as i understand it, is to put some dictionary fields in one memory area and some dictionary fields in another. things like the immediate bit and the name go in memory area a; things like the cfa and dfa go in memory area b. then you only put memory area b in the rom image, thus saving space

it seems like, if you want to generate new machine code at runtime in a forth system with x^w, you probably want to do a similar kind of segregation thing where code and (at least mutable) data go in different memory areas. data compiled with c, or , goes in the data area, and probably things like the immediate bit and the name; newly generated machine code goes in the code area. the header for the word points at the code, as usual, via a pointer (let's say a bare pointer, not a jump; doing this kind of separation with direct threading would be more challenging), the cfa

how do you handle switching the page between writable and executable? well, you could do it after every word you compile, just in case the next word calls it as immediate (say, inside of [ ]). but maybe that's too wasteful of pages, because it means each word gets its own page. (and you get terrible instruction cache contention if you put them all at the beginning of the page). probably the forth way would be to have a word you have to call explicitly to make all the previously defined words executable, but the automatic way that occurred to me is to initially point all the cfas at a trampoline routine. the trampoline, when invoked, moves the machine code for the currently-being-compiled word (if any) to a new page, updates the compilation state appropriately, and then changes the protection on all the previously compiled code that's trampolined out from writable to executable, and iterates over all the already-defined words in the dictionary, changing their cfa from pointers to itself to instead point at the new native code it's just made executable; when it reaches the point in the dictionary where it was previously invoked, it stops

you say 'actually modify the core compiler itself', but normally you don't modify existing definitions in a forth dictionary; you just add new ones to the end of it, which shadow the previous ones. i think in colorforth and some other nonstandard systems, the global namespace works more like in lisp or python, where, if you redefine an existing word, all the words that called the old definition start calling your new definition instead. this is useful for interactive experimentation because you don't have to forget (or, worse, marker). if you want to implement that, you still don't have to actually change the existing machine code; you can compile your new machine code onto a new page and point the cfa of the old definition to the new definition. this is normally what you'd want to do with a traditional forth dictionary structure anyway because the definitions are packed tightly one after the other, with no padding in between, so if you were to overwrite a definition in place with a new, longer definition, you would also be overwriting the beginning of the definition after it

as for tcp/ip, there are a pretty small number of implementations of tcp/ip in history. bsd unix's tcp/ip was copied into basically every unix and also microsoft windows and vax/vms wollongong tcp/ip (though the vax i used was on tgv multinet instead, whose provenance i don't know, though rumor has it 'tgv' was 'two guys and a vax' https://news.ycombinator.com/item?id=28190718). i don't know if cutcp (clarkson university tcp/ip) derived from the bsd code or not. plan9's i'm pretty sure didn't.

there have been a few independent reimplementations of tcp/ip, but really a surprisingly small number—not just in forth, in any language. two of them are lwip and uip from contiki; they are small and simple, though uip in particular is hardly rock-solid, and may be good information about the minimal amount you need to implement to have a usable tcp/ip stack

uip https://github.com/adamdunkels/uip is 2900 lines of c (uip/uip/ and uip/lib/); its example webclient is another 500. couple that with tweetnacl and you might have a worked example of how to get online

lwip is described by wikipedia as 'widely used', and the current version https://github.com/lwip-tcpip/lwip is 125000 lines of c. but if you only count lwip/src/core/, lwip/src/include/, and lwp/src/api/ it's 'only' 41000 lines. of that about 10% is ipv6 support

but if you git checkout 3551b2a2 you have version 1.2.0 from 02006 which is 'only' 26000 lines and already supports ip (v4 and v6), arp, tcp, udp, dhcp, snmp, slip, ppp, and ethernet. boehm's cocomo model estimates this as 6.2 person-years of work based on the number of lines of code (generated using david a. wheeler's 'sloccount'), so it's clearly not a career-long research project, and maybe it could be a lot faster if you're cloning an existing working system like this instead of designing something from scratch

plausibly in forth you could do a better job, because forth is better at embedded dsls, and as vpri showed, implementing tcp/ip really benefits a lot from embedded dsls