2023-02-07 14:51:27 I print ... when compiling. 2023-02-07 14:52:05 Just to indicate "I expect more - you're not done yet." 2023-02-07 14:52:38 probably better than the first unix shell looping forever and the machine usually needed a reboot 2023-02-07 14:54:28 I think the real issue with DONE> isn't really to do with the type of threading. The real issue is that Forth "by structure" offers you access to two arbitrary things when you run a word. You get a pointer to code that will be jumped to, which you can set to anything, and you get a pointer to the "parameter area" of the word (or at least some knowledge of where that is - in old FIG it was just immediately 2023-02-07 14:54:29 after the code pointer). 2023-02-07 14:55:19 But CREATE ... DOES> requires three things. It needs code to jump to, like every word does, and then it needs a pointer to the parameter area and another pointer to the definition that should be executed as the DOES> action. 2023-02-07 14:55:41 So it doesn't fit - you have to kind of kludge something to make it work. The system really isn't "built" to make it work elegantly. 2023-02-07 14:58:06 https://read.seas.harvard.edu/~kohler/class/aosref/ritchie84evolution.pdf might be worth a peep 2023-02-07 14:58:10 One possibility is to create a bit of machine code for each defining word, that sends you to that word's DOES> action hard-wired. But if you want that code to be universal across different definning words, then you've got to put that extra pointer somewhere. 2023-02-07 15:34:36 thrig: worth a peep indeed. 2023-02-07 15:38:15 veltas: Your word RP0 is a constant? 2023-02-07 15:38:38 I notice you wrote RP0 RP! to reset the return stack, rather than RP0 @ RP! 2023-02-07 16:57:27 KipIngram: tock? :) 2023-02-07 16:58:22 KipIngram: heartbeat? beat? periodic? 2023-02-07 16:58:36 :-) tock is amusing. 2023-02-07 16:59:29 good old Intel tick-tock-thud cycle 2023-02-07 17:11:46 KipIngram: CONSTANT or VALUE 2023-02-07 17:11:58 Undecided yet 2023-02-07 17:12:01 Ok. 2023-02-07 17:12:22 I might need to make it a user variable eventually but that's way off in distance 2023-02-07 17:12:23 That one will be a "user" (per-thread) variable for me. 2023-02-07 17:12:38 Great minds think alike lol 2023-02-07 17:13:05 I'll get the main thread working first before worrying about that 2023-02-07 17:21:49 KipIngram: And yes, we share the same understanding of the DOES> problem 2023-02-07 17:22:23 Trying to write a portable C forth means I can't generate code for each DOES>, therefore I need an extra pointer stored with every CREATE'd word 2023-02-07 17:25:30 You are right, you can do this with ITC as well. The issue is doing it with C as far as I know 2023-02-07 17:28:59 thrig: It occurs to me there is a performance advantage of using i-nodes, reading this document 2023-02-07 17:30:41 Because the alternative approach involves referring to a file using its path, and then you need to keep traversing the path to access the file 2023-02-07 17:30:52 Instead with an inode you can just look it up in one array 2023-02-07 17:31:47 You only need to traverse the system once and then you know the file's inode number 2023-02-07 17:49:44 Maybe that's why I found it obtuse - I think most of those memories come from my C implementation. 2023-02-07 17:51:30 Yeah, look it up once. 2023-02-07 17:51:51 Aren't inodes grouped together such that they're a resource pool? 2023-02-07 17:52:03 and you can "run out" and need to do something to make more? 2023-02-07 17:53:40 2-3 years ago I gave a good bit of thought to file systems, and felt like I had a good way of doing one with b-trees. 2023-02-07 17:53:47 but that's all pretty fuzzy for me right now. 2023-02-07 18:25:41 But the way I did that C implementation was to allocate a big block of RAM with malloc, and I built my dictionary in that block. So I wasn't really "hindered" in ability to work with it any way I wanted to. 2023-02-07 18:26:03 The machine code didn't live in there, though - it consisted of some C one-liners in the actual C program. 2023-02-07 18:26:29 I was just getting to the point of proving to myself that I could poke machine code bytes into the array and execute them when I set it aside and began a new one. 2023-02-07 18:26:36 And that time I used nasm. 2023-02-07 18:27:10 But, I was not setting up custom machine code bits for DOES>, so I also faced the extra pointer hurdle. 2023-02-07 18:28:19 I guess if I were going to do it right now, I do something like this. 2023-02-07 18:28:51 When you are compiling the defining word, and you reach DOES>, that the first indication you have that you need to do that. At that point you have compiled the memory allocation words. 2023-02-07 18:29:24 So I think I'd start by allotting one additional cell, which makes room for the amount of memory called out by the CREATE part and for the extra pointer. 2023-02-07 18:29:54 Then I'd compile a call to a word I'll call X for now, and then compile (;). 2023-02-07 18:30:29 So, when you define a word with your defining word, you get N+1 cells allocated, and initially (by CREATE) that is a regular variable style word that will give you a pointer to its address. 2023-02-07 18:30:37 But then you will execute X. 2023-02-07 18:31:52 And it will doctor the header of the new word. The CFA will be changed to point to code I'll call Y, and the PFA will be changed so that the address that will get pushed its one cell beyond what it would have been. 2023-02-07 18:32:20 That first cell we just skipped over will point to the start of the DOES> code, which of course got compiled after I stopped talking about it up above. 2023-02-07 18:32:45 Now I think you have everything. Y makes sure that address gets pushed, but then passes execution to the done code. 2023-02-07 18:33:01 So the new pointer winds up going right after the old one. 2023-02-07 18:33:10 The new word's header winds up looking like 2023-02-07 18:33:16 CFA = Y 2023-02-07 18:33:24 PFA1 = DOES> code 2023-02-07 18:33:27 Still interested to know what you'd call the words I linked earlier, if you are up for that 2023-02-07 18:33:32 PFA2 = Data address. 2023-02-07 18:33:46 Yeah, I'll get to that shortly. 2023-02-07 18:34:21 So the Y code pushes the address contained in PFA1 onto the stack and then passes execution to the Forth definition pointed to by PFA2. 2023-02-07 18:35:12 Over the years I've tried several times to come up with a completely smooth way of "nesting" the CREATE DOES> mechanism to any depth I wanted to. 2023-02-07 18:35:22 Defining words that define defining words that define... etc. 2023-02-07 18:35:34 But I've just never been able to get that to work out in a way that felt "clean" to me. 2023-02-07 18:36:01 It always felt like that's what you'd want to be able to do "unlimited inheritance." 2023-02-07 18:37:17 What does your PARSE-WORD do, exactly? 2023-02-07 18:42:47 KipIngram: Returns address and length of next word in TIB 2023-02-07 18:43:01 Or a zero-length string if there are no more words 2023-02-07 18:52:55 K 2023-02-07 18:54:36 So each call to interpret is doing just one word? 2023-02-07 18:56:41 Well, the top one seems closest to what I called "case," as in "interpret case" vs. "compile case." And I didn't exactly love that word. 2023-02-07 18:57:35 My ?run does the does the actual state check and either handles it, if it's execute, or calls comp if it's compile. 2023-02-07 18:58:12 I think I don't care a lot for calling the last one INTERPRET, because it's also reading your input, and to me "INTERPRET" is something that is given a line of input and processes it. 2023-02-07 18:58:52 But... your code is nice and fairly short, so I don't want to be critical of it. I like the design, actually. 2023-02-07 18:59:39 And I find it easier to understand, coming onto it cold, than mine likely is (it's hard for me to judge because I wrote it, so it's clear to me). 2023-02-07 18:59:45 But I played some... tricks. 2023-02-07 19:00:01 And that's probably less than idea for a pedagogical offering. 2023-02-07 19:01:29 I took advantage of the fact that find returns a CFA, or null. If it came back null, I used some other CFA (lit or nop) to replace it. 2023-02-07 19:02:03 So those lit or nop CFAs that get compiled as literals actually get executed by the same EXECUTE that would have executed the found word, if there had been one. 2023-02-07 19:04:25 If I were going to steward your code, I'd probably name your last instance of INTERPRET (nearest the bottom) REPL 2023-02-07 19:04:49 Since it has charge of both getting input and processing it. 2023-02-07 19:05:14 Even though your loop is actually in QUIT. 2023-02-07 19:05:42 I have two loops; one that loops over reading lines and processing them, and one that loops over words in a line of input. 2023-02-07 19:07:05 And if you're studying my code keep in mind that I also rely on eventually getting the empty string actually returned as a word. It's in the dictionary and it's immediate and it double-returns to break the INTERPRET (I named it eval) loop. 2023-02-07 19:07:41 Which is also a bit of a dirty trick - a newbie could go slowly insane trying to figure out how that works, not knowing about the null word. 2023-02-07 19:07:50 There's no hint of it there in that code. 2023-02-07 19:36:22 So, for now at least I've just called my expired timer word "task." 2023-02-07 19:36:32 I may replace that with something, but it'll do as a placeholder.