00:00:00 --- log: started forth/21.06.25 00:41:17 --- join: rain3 joined #forth 00:51:01 MrMobius: You can exit BEGIN..AGAIN with WHILE 00:51:50 i.e. BEGIN .. cond WHILE .. AGAIN THEN 01:41:40 --- join: gustaf joined #forth 02:03:48 --- join: ni291187 joined #forth 02:10:35 --- quit: ni291187 (Connection closed) 02:44:30 --- join: andrei-n joined #forth 02:46:21 --- join: Glider_IRC__ joined #forth 02:49:13 --- quit: Glider_IRC_ (Ping timeout: 120 seconds) 03:16:18 --- quit: Vedran (Ping timeout: 120 seconds) 03:16:38 --- join: Vedran joined #forth 03:43:26 --- quit: Vedran (Ping timeout: 120 seconds) 03:43:49 --- join: Vedran joined #forth 03:48:39 --- join: rain3_ joined #forth 03:49:28 --- quit: rain3 (Connection closed) 04:07:38 --- quit: andrei-n (Connection closed) 05:37:08 hello 06:33:45 --- join: Bogen85 joined #forth 06:33:45 --- mode: ChanServ set +o :Bogen85 06:34:15 --- part: Bogen85 left #forth 07:22:05 --- quit: rain3_ (Ping timeout: 120 seconds) 09:10:28 <+KipIngram> brainfunnel: Yes, sequencing is really a more suitable word, but the whole Forth community uses "threading," so... What would you call the list of pointers to words that gets executed? 'sequence'? 09:18:57 Yeah, I think so, or just "list." 09:19:11 "definition list," or something like that. 09:19:35 It functions as code, so "Forth code" would work too. 09:19:57 I sometimes use the word "body" to refer to that part of a definition. 09:20:09 As distinct from the "header." 09:20:52 In a traditional FIG system the body immediately followed the header, so the header had a pointer to the code associated with the word and then the body came right after. 09:21:13 In my system headers and bodies are in separate memory regions, so my header has the usual pointer to code and then a pointer to the body. 09:22:07 That makes all words "re-vectorable." The list items in compiled definitions are pointers to headers. So by changing the body pointer of a header you can completely redefine that word, and all compiled references to it will use that new definition. 09:22:46 In FIG "vector words" were special - that extra level of indirection was added above and beyond the standard definition. But it's a "perk" of my architecture that I can do that to any word, any time. 09:23:03 The penalty is that my headers are one cell larger than they would be in a FIG system. 09:23:42 But by separating the pieces like that, my bodies are contiguous with one another, so execution can flow right from one body into the next body if I want it to. 09:23:47 So words can have multiple entry points. 09:59:06 proteusguy: hi 11:29:18 KipIngram: Interesting. Do the bodies contain pointers to the headers, then? 11:39:27 Yes, that's correct. Each body is a list of pointers to the headers of the component words. 11:41:41 To the code field of the header, specifically. So the inner interpreter loads an item from the list, de-references it (so that now it's pointing to the code field of that word's header) and does a jump to the code designated by that code field. Primitives don't need anything else - you just run the code. But if the word being executed is a new : def, then the (:) code will de-reference again from the body 11:41:41 pointer just after the code pointer (still in the header), and that gives it a pointer to the first item of the new definition, which it just loads into IP (after saving IP on the return stack). 11:42:09 So I can globally replace a word's definition by creating the new definition body and aiming that second pointer at the new list. 11:43:12 One nuance - if the definition I replaced was a "second entry point" of some larger definition, then the fall-through from the earlier part would still use the old definition - it would have no way of knowing that a new definition had been substituted. 11:43:22 What I'm talking about here is this: 11:43:35 : foo ... : bar ... ; 11:43:53 I could change the definition of bar by doing that pointer replacement. 11:44:08 But when foo executed it doesn't use that pointer to find bar - it just "flows through." So that wouldn't change. 11:44:42 Separating headers and bodies means that the two ... sections in that example are immediately adjacent to each other, with nothing in between. 11:45:08 In a FIG system you can't do that - the header for bar goes right after the end of foo, so foo would have to end with a ; or else you'd try to execute into a header. 11:46:07 As a side note, once you're finished compiling references to a word, you no longer need the name string and the link field of the header. 11:46:30 But that pair of pointers - the code pointer and the body pointer, must stick around; that part is critical to later execution. 11:46:49 In my last system I was able to completely get rid of no-longer-needed portions of headers. 11:47:07 In the new system I'm working on I'll just unlink those names from the vocabulary list, but the bytes will still be there in RAM. 11:47:13 I see. I like to implement IS by poking a jump at the beginning of the code — I use direct threading, so it will always fit over the call to DOCOL 11:47:21 Slightly wasteful, but RAM is cheap and it was much simpler to do it that way. 11:47:34 Did you do something like a compacting GC before? 11:47:37 Right - that absolutely works. 11:48:04 was repointing all the code to the new positions of the headers feasible? 11:48:20 No, I had a simpler memory manager that used fixed size blocks (4kB) so it didn't need to garbage collect. When I de-alloctaed a page it just went onto a free list, that I always checked before advancing the "top pointer" into virgin RAM. 11:48:20 how does it work if you can have arbitrary alloted data in the dictionary space? 11:48:39 Allot just makes that space after the last-compiled body. 11:48:55 Variables and constants appear in that same region as well, in order of compilation. 11:49:22 Here's an interest trick I could do: 11:49:36 : foo ...foo-code... 11:49:47 variable bar 11:49:55 : bam ...bam-code... ; 11:50:27 Now I could store a pointer in bar, and when I executed foo it would execute foo-code, execute using the pointer I stowed in bar, and then execute bam-code. 11:50:36 So it would be a word with a vectorable item within it, accessible by name. 11:51:03 Because the "body" of bar is just that cell the variable value goes in, and it gets squashed in between the bodies of foo and bam. 11:51:22 Obviously I'd have to initialize bar before executing foo. :-) 11:52:12 The point here of course is that there's no ; after foo-code, so execution doesn't stop - just plows right on forward into bar and bam. 11:53:37 If I didn't need to execute bam directly I could make it a disposable definition; I'd just use .: just before it instead of : and then later run .wipe to unlink bam from the linked list. 11:53:51 But, I could just do this: 11:53:59 : foo ...foo-code... 11:54:02 variable bar 11:54:11 ] ...bam-code... ; 11:54:24 And there would never be a bam in the dictionary. 11:54:33 Oh, I'm sorry. 11:54:52 I need [ after ...foo-code... to get out of compile mode before declaring the variable. 11:55:06 I suppose I could make variable immediate and not have to do that. 11:55:48 Anyway, there's a lot of flexibility to be had by not sticking your headers in the midst of your bodies. 11:56:36 In the assembly code I used section management to implement that - I have macros that make headers, and they first switch to the header section, make the header, and then switch back to the body section. It's all extremely clean. 11:56:48 That's in nasmforth, but I suppose you could do it in any good assembler. 11:56:53 I'm sorry - in nasm. 11:57:02 nasmforth was just the name of my previous forth. 11:57:47 I often use [ instead of ; when a word ends with an unconditional jump. 11:57:56 No point in compiling a (;) after a jump. 12:16:32 okay, but > In my last system I was able to completely get rid of no-longer-needed portions of headers. < 12:16:32 wouldn't that move all the other headers? 12:22:01 No, .: (my temporary compiling word) checked to see if a temporary table yet existed. If it did, it extended it; otherwise it allocated it. It made a full normal header in the temporary page, but also put the pointer pair in the permanent header region. 12:22:21 Later .wipe would drop the temporary page and adjust list linkages appropriately. 12:22:36 Compilation using those words made sure to use the permanent copy of the pointers. 12:22:50 So the pointer pair was the only part of the header that got placed in the permanent header region. 12:23:04 It was more or less perfect - after you were done you had an optimal memory layout. 12:23:22 But it was a bit involved making it all work, and it relied on having a memory manager of some kind. 12:24:13 I could only have one 4kB page full of temporary headers; it wasn't capable of using multiple pages. But that was plenty for my use cases. 12:24:51 NUMBER was a good example - my implementation wound up being 20-25 definitions, all but one of which were temporary, which were 35-40 characters long. 12:25:14 So I did a whole bunch of .: definitions, then the one : definition (NUMBER itself), followed by .wipe. 12:25:58 This time I just decided I didn't want to engrain a memory manager - even a simple one - so deeply into the foundation of my system. 13:47:03 --- join: simpl_e joined #forth 14:46:23 --- join: Glider_IRC_ joined #forth 14:49:16 --- quit: Glider_IRC__ (Ping timeout: 120 seconds) 17:12:53 maw 17:16:05 maw ate stomach to maw 17:16:50 and did so raw 17:17:18 why? no law 18:50:47 --- quit: cbridge_ (Quit: bye) 18:50:58 --- join: cbridge_ joined #forth 20:58:45 --- quit: crab (Ping timeout: 120 seconds) 21:21:18 re maw 22:52:21 veltas, hey there... :-) I don't have tons of time for irc these days, alas. But I try to read posts each day and stay caught up. 23:59:59 --- log: ended forth/21.06.25