2023-10-04 00:00:05 I lay my headers out like this: 2023-10-04 00:00:30 2023-10-04 00:00:58 As I said, though, you can do this in many ways; it's a flexible concept. 2023-10-04 00:01:03 ACTION KipIngram: That is an awesome amount of info thank you! I think what I'm after is if there would be any gotchyas that I'm not thinking of. (I'm implementing this in WebAssembly if that's relevant) 2023-10-04 00:01:22 I don't see any show-stopper problems in your design. 2023-10-04 00:01:41 You have the name string "not in the middle" of the other fields, and that's good. 2023-10-04 00:01:50 One issue. 2023-10-04 00:02:05 forth normally uses "counted strings," which means a count byte followed by the string bytes. 2023-10-04 00:02:32 Your name fields are not laid out that way, so you won't be able to treat dictionary name fields using standard counted string words you use in your own definitions. 2023-10-04 00:02:34 ACTION Yeah, I'm kind of inverting and aligning it. But at this low level it makes all the math easier for me. 2023-10-04 00:02:40 You have . 2023-10-04 00:02:59 If you did all counted strings that way I suppose it could be made to work, but it's just unusual. 2023-10-04 00:03:53 would the definition data for a word immediately follow its header? 2023-10-04 00:04:02 Yeah that's my plan. 2023-10-04 00:04:06 That's how the oldest Forths did it. 2023-10-04 00:04:31 I keep my headers in a different section of RAM from my definition data, so I have a pointer to the definition data. That's what I referred to as above. 2023-10-04 00:04:50 I was just about to ask. If I compare your header to Moving Forth would it be accurate to say that your headers are token threaded in his vernacular? https://www.bradrodriguez.com/papers/moving1.htm 2023-10-04 00:04:53 it's not that I'm right and you're wrong - it's just two different ways of doing it. my way is slightly less space efficient. 2023-10-04 00:05:09 No, it's not a token threaded design. 2023-10-04 00:05:23 The definition data still looks like standard indirect threaded Forth. 2023-10-04 00:05:48 I just have it somewhere else and point to it, instead of having it "right there." 2023-10-04 00:05:49 ACTION Ahhh 2023-10-04 00:05:53 It's perfectly fine to have the definition "right there.' 2023-10-04 00:06:25 The only real advice I'd give you is to say put your name count byte before the character data, and move the name string to the end instead of the beginning. 2023-10-04 00:06:49 well, wait. 2023-10-04 00:06:59 That's not really a good idea if you're g oing to have the definitions right there. 2023-10-04 00:07:01 so scratch that. 2023-10-04 00:07:13 It's only a reasonably workable plan if you use a pointer like me. 2023-10-04 00:07:30 I'd still move the count byte to the front of the name, though - I think you'll be happier long term if you do that. 2023-10-04 00:07:40 I was kinda thinking to the left of the xt is an indeterminate amount of bytes + the link. then to the right of the xt is the code. 2023-10-04 00:08:34 Yes, depending on how you lay it out you might find you have to traverse the name. In one direction you can use the count to jump over the name, but in the other direction you have to scan. 2023-10-04 00:09:22 I think you're going to have fun with this - building a Forth system is just a fun project. 2023-10-04 00:09:31 I'm already having a blast! 2023-10-04 00:09:34 And the rush you get when first begins to work - really nice. 2023-10-04 00:10:21 So let me explain why I put my definitions 'elsewhere.' 2023-10-04 00:10:35 By doing so, I can write something like this: 2023-10-04 00:10:41 : foo ... 2023-10-04 00:10:45 : bar ... ; 2023-10-04 00:10:45 ACTION I started by trying to hack on WAForth, but found that for my project I really wanted to be able to reset the instruction pointer so here I am :) https://github.com/remko/waforth 2023-10-04 00:10:52 Note the absence of a ; at the end of foo. 2023-10-04 00:11:04 When that's compiled, if I run foo, it will run both ... code sections. 2023-10-04 00:11:10 foo "falls through" into bar. 2023-10-04 00:11:20 So it lets me define multiple entry points to the same section of code. 2023-10-04 00:11:25 That sounds like something I want... 2023-10-04 00:11:26 The header of bar isn't sitting in the way. 2023-10-04 00:11:49 You could still support that feature, but you'd have to compile a jump at the end of foo to jump over the header. 2023-10-04 00:12:57 But separating headers from definitions does mean you have more RAM blocks to manage. 2023-10-04 00:13:07 And it does require that extra pointer in the headers. 2023-10-04 00:13:25 I'll be honest, that sounds annoying. I'm starting to like yours... 2023-10-04 00:13:29 I just felt the benefit was worth it. that was just a personal preference though. 2023-10-04 00:13:33 Feel free to rip it off. 2023-10-04 00:13:46 It really originated here in this channel. 2023-10-04 00:13:55 I'm really glad I asked :) Thank you for the help! 2023-10-04 00:14:07 I had a different one before and we talked about it here one day, and I just decided I liked the new layout better, so I ripped into my code and changed it. 2023-10-04 00:14:13 What tool are you using to develop? 2023-10-04 00:14:19 wat2wasm 2023-10-04 00:14:25 I've most recently used nasm. 2023-10-04 00:14:38 I'm just typing up the assembly 2023-10-04 00:14:38 Ok. If it has a good macro facility you may be able to write macros to create your headers. 2023-10-04 00:14:44 No macros 2023-10-04 00:14:56 It's mildly annoying, but github copilot helps a lot 2023-10-04 00:15:13 Here's what a word definition looks like in my nasm source: 2023-10-04 00:15:15 ;;; : interpret find tasks 0=me exec me [ 2023-10-04 00:15:16 It does the pointer arithmetic form me 2023-10-04 00:15:17 def "interpret", interpret 2023-10-04 00:15:19 run find, tasks, zeme, 16+do, exec, me, 28+do 2023-10-04 00:15:25 def is a macro. It creates the dicionary entry. 2023-10-04 00:15:37 run is also a macro - it uses that list of labels to build the definition. 2023-10-04 00:16:28 Here's what a primitive definition looks like: 2023-10-04 00:16:30 code "b>", bfrom 2023-10-04 00:16:32 decd rrSP 2023-10-04 00:16:34 putd rrSP, rrTOS 2023-10-04 00:16:36 mov rrTOS, rrB 2023-10-04 00:16:38 next 2023-10-04 00:16:40 code is also a macro that creates a header. 2023-10-04 00:16:55 decd, putd, and next are macros too. 2023-10-04 00:17:13 But the lines after the "code" line you should just regard as assembly. 2023-10-04 00:19:18 I'm not sure you have any interest, but I went ahead and pushed what I have https://github.com/seepel/flea-scheme/blob/master/forth32.wat No comments or anything so maybe it doesn't even make sense ¯\_(ツ)_/¯ 2023-10-04 00:20:09 I'll take a look at it tomorrow. 2023-10-04 00:20:56 Really only if you're interested, don't feel obligated. In any case, you've been so helpful, thanks again! 2023-10-04 00:21:00 I'm planning a new system myself right now, that is going to be token-threaded and uses Chuck Moore's F18A processor as "inspiration." 2023-10-04 00:21:13 You're welcome - let us know how it's coming along. 2023-10-04 00:21:57 The F18A is documented here: 2023-10-04 00:21:59 https://www.greenarraychips.com/home/documents/greg/DB001-221113-F18A.pdf 2023-10-04 00:22:33 Oh you know what, I did briefly look at that a while back and then got to intimidated :) 2023-10-04 00:23:41 Sounds like you're starting out in a good way to me. 2023-10-04 00:23:54 I doubt it will be the last Forth you ever write. :-) 2023-10-04 00:24:25 On the other hand, I'm hoping this one will be my last one. 2023-10-04 00:24:32 One that I'll hang onto and actually use. 2023-10-04 00:25:00 I've got a little microcontroller board, the MAX32655, that I want to put it on, and then use that for hobby electronics projects in the future. 2023-10-04 00:25:13 It's a tiny board and will be easy to solder ontO 'whole project boards'. 2023-10-04 00:40:03 Ahhh, now that I work through your header I see that the PFA is the back pointer 2023-10-04 00:40:11 Is that right? 2023-10-04 00:41:48 No, the PFA points off to the definition addresses. 2023-10-04 00:42:01 the CFA would point to the "docol" code, for a : definition. 2023-10-04 00:42:08 Did I leave out link? 2023-10-04 00:42:12 ACTION No 2023-10-04 00:42:50 is the number of bytes back from its own address to the previous word's link address. 2023-10-04 00:43:05 So, it's a "relative" pointer. 2023-10-04 00:43:11 ACTION You had link  2023-10-04 00:43:19 But the PFA and CFA pointers are addresses. 2023-10-04 00:44:03 So for a : definition, says "this is a colon definition," and says "and here are the definition details. 2023-10-04 00:46:16 I redid my diagram of what I thought an entry would look like with that header and this is what I came up with. 2023-10-04 00:46:36 https://www.irccloud.com/pastebin/GKf0RnbX/ 2023-10-04 00:48:26 Yes, that looks like what my current system does. 2023-10-04 00:48:44 I've been quite happy with it. 2023-10-04 00:49:34 So those just "grow" in some region of RAM as you define new words. 2023-10-04 00:50:05 And in some other region your "implementations" (the spaces you actually store your variables in, your definitions, and so on) just grow. 2023-10-04 00:50:41 Older Forths use a variable named DP to point to the next free byte in RAM. : HERE DP @ ; 2023-10-04 00:50:59 I have to have two variables for that, since I have a "bodies" region and a "headers" region. 2023-10-04 00:51:07 Yeah, this seems great. Though I suppose ENTER should actually just be the CFA? 2023-10-04 00:51:43 I'm not sure what you mean by those ENTER items. 2023-10-04 00:52:26 That's the previous word? 2023-10-04 00:52:31 ENTER here is the same as DOCOL 2023-10-04 00:52:38 Ah. 2023-10-04 00:52:53 I think I picked that up from Moving Forth and I liked how it matched EXIT :) 2023-10-04 00:53:21 Well, if you separate headers and definitions, then the header region will just string the headers together. just before PFA pointer would be the name bytes of the prior word. 2023-10-04 00:53:40 Maybe with a couple of bytes of padding - you probably should align the beginning of each header in some appropriate way. 2023-10-04 00:54:16 For a : definition, would point to docol. 2023-10-04 00:55:45 That makes sense to me. 2023-10-04 00:58:00 So docol would push the instruction pointer to the return stack and load the instruction pointer with the value pointed to by 2023-10-04 00:58:33 What's your background, seepel? 2023-10-04 00:59:50 Oh gosh. I started as a High Energy Physicist, then went and built iOS apps, then went and built a low code platform, and now I'm building generative AI applications 2023-10-04 01:00:13 Ah, you sound like me in terms of moving around. 2023-10-04 01:00:25 I like learning new things :) 2023-10-04 01:00:37 It's a good trait. 2023-10-04 01:01:15 I'm an EE but I've worked in several different focus areas. 2023-10-04 01:01:56 Equipment for electronic manufacturing, seismic, down-hole oilwell tools, data storage, and university research. 2023-10-04 01:02:57 I love physics. 2023-10-04 01:03:15 Spend a good chunk of my time finding stuff to learn online in physics and math. 2023-10-04 01:05:57 What field of physics do you like to read about? 2023-10-04 01:08:53 Oh gosh. 2023-10-04 01:09:24 All over, really. Interpretation issues in quantum mechanics is a perennial interest. But really, so much of it. 2023-10-04 01:09:38 I just try to get "more." 2023-10-04 01:09:51 I'm quite fond of statistical mechanics. 2023-10-04 01:10:24 I think of it as a particularly "beautiful" process, watching the macroscopic thermo laws pop up out of treating molecules as an ensemble of little balls flying around. 2023-10-04 01:15:32 I also like cosmology, relativity, etc. - probably the "usual hit list." 2023-10-04 01:29:26 Hmm, turns out I'm still struggling. If the name is at the end of the dictionary entry, how can you implement CREATE? 2023-10-04 01:29:58 You need to know when the body ends so that you can write the name right? 2023-10-04 01:44:30 If you are separating headers and definitions, then they are in two completely fifferent RAM regions. 2023-10-04 01:44:50 If you're not, the body goes after the header, not before. 2023-10-04 01:47:47 Remember in a colon definition the name comes first, so you make the header as soon as you see the word in the input stream. 2023-10-04 01:47:59 Then you move on to compiling the definition after. 2023-10-04 01:48:08 I see 2023-10-04 08:59:40 seepel: The name isn't visible until end because the header isn't linked into the word list until ; is executed 2023-10-04 09:00:27 See for example https://github.com/Veltas/Tebbi-Forth/blob/main/tebbi-forth.4th#L29 2023-10-04 09:02:06 Which is a chicken-and-egg way of writing : ; [COMPILE] EXIT [COMPILE] [ CURRENT @ ! ; IMMEDIATE 2023-10-04 09:02:50 CURRENT @ ! sets the wordlist stored in CURRENT to point to the address on the stack, which is the header address produced by : 2023-10-04 09:36:57 That can vary depending on the system. In my system it's immediately available. 2023-10-04 09:38:04 I believe in colorForth Chuck made it immediately visible as well; it's how he did looping. 2023-10-04 09:38:45 You can't do tail recursion unless it's visible (or you provided some other way). 2023-10-04 09:42:02 And in fact, if you want it to be invisible until ; is done, you have to deliberately write it that way - the "simplest default" is for it to be visible as soon as CREATE updates the pointer to the latest word. 2023-10-04 09:45:44 my systems also make the name immediately visible 2023-10-04 09:47:33 Do you have a way to refer to an earlier definition with the same name? 2023-10-04 09:47:47 seepel: Systems that don't have a word visible until its definition is complete usually do so by having what they call a "smudge" bit in the header. CREATE will set that bit when it creates the header - it's only purpose is to make searches fail. In those cases ; clears the bit. 2023-10-04 09:47:52 No. 2023-10-04 09:48:04 Unless you make an access word. 2023-10-04 09:48:09 : foo ... ; 2023-10-04 09:48:15 : bar foo ; 2023-10-04 09:48:27 : foo ...another definition... ; 2023-10-04 09:48:48 Now foo will always run the second definition, but bar will still run the original one. 2023-10-04 09:49:49 And that's important to understand that - someone else that dropped by the other day felt that bar should switch to the new definition, but that's not how it works. 2023-10-04 09:50:26 The names are evaluated at compile time, and the finished definitions have no knowledge of what the NAMES were that were used to build them. 2023-10-04 09:50:30 They're just lists of addresses. 2023-10-04 09:53:11 GeDaMo: Word searches continue until they find a match and look no further, and they run in reverse chronological order in each vocabulary. 2023-10-04 09:53:30 Yeah 2023-10-04 09:58:05 GeDaMo: on my system, I'd define a quote & then attach a name afterwards (e.g., `[ ... name ... ] \name`) 2023-10-04 10:00:14 crc: does that quote leave a reference to the "code string" on the stack? 2023-10-04 10:00:24 in the past I had `prior` (used as `prior name`) for this, but I dropped that a number of years ago 2023-10-04 10:01:02 code string? 2023-10-04 10:01:50 [ ... ] leaves a pointer to the compiled function; \name creates a new header for `name` and assigns it to point to the address from the stack 2023-10-04 10:33:23 That was what I was asking. By "code string" I meant the definition you just compiled. 2023-10-04 10:33:53 Honestly doing it that way - caching the definition on the stack and then "storing" it somehow seems more "RPN-oriented" to me than the way we normally do it. 2023-10-04 10:34:34 That's similar to POstscript 2023-10-04 10:36:53 And it also then puts you in a position to do... "other things" with your compiled definitions. You could make a table of them, or whatever. 2023-10-04 10:38:45 is that definition created initially in its permanent location, or does the naming operation copy it somewhere? 2023-10-04 10:42:52 it's created at its permanent location 2023-10-04 10:45:46 (my system only supports absolute addressing, so I can't just copy the compiled code around) 2023-10-04 10:47:17 Gotcha. 2023-10-04 10:47:52 I think the new work I'm planning will put me in a position to copy compiled code around, but only up until such time as there's an external reference to it. 2023-10-04 10:48:14 I don't think anything "internal to the definition" will nail it to a fixed spot. 2023-10-04 11:20:49 So I had some further thoughts about how to recognize vectors in a type-supporting system. 2023-10-04 11:21:05 In APL a vector is just a list of items: 1 2 3 would be a vector. 2023-10-04 11:21:26 In an RPN system we face how to tell the difference between that and three separate integers. 2023-10-04 11:21:52 it occurred to me that our RPN calculators deal with this same problem, except instead of numbers and vectors we're working with digits and numbers. 2023-10-04 11:21:58 And that's what the Enter key is for. 2023-10-04 11:22:07 "Stop adding digits to this number and start a new number." 2023-10-04 11:22:12 It's exactly the same problem> 2023-10-04 11:22:31 So it seems like the right answer is to have some symbol that plays the role of "stack item separator." 2023-10-04 11:22:56 A function will end construction of a stack item, so you could think of this as some sort of "noop function.' 2023-10-04 11:23:26 APL uses ⋄ as an expression separator - it seemed like a reasonable candidate to me. 2023-10-04 11:24:12 The down side of doing it that way is that when you were entering a lot of numbers you'd need a lot of ⋄'s. 2023-10-04 11:24:32 Whereas if vectors used some sort of brackets, then numbers could continue to be space-delimited. 2023-10-04 11:24:37 Pros and cons both ways. 2023-10-04 11:25:13 You could treat consecutive numbers as an array 2023-10-04 11:27:29 Yes, that's like APL. 2023-10-04 11:27:45 and then use ⋄ to terminate that if I wanted to start a second array. 2023-10-04 11:28:11 1 2 3 ⋄ 4 5 6 == two vectors. 2023-10-04 11:28:30 Or (1 2 3) (4 5 6) 2023-10-04 11:28:40 Those are sort of the two possibilities. 2023-10-04 11:29:00 not necessarily ( and ), but some type of "bracket>" 2023-10-04 14:56:29 KipIngram: recursion in ANS is done with RECURSE 2023-10-04 14:56:52 Not having current def visible is quite useful for 'enhancing' previous definitions 2023-10-04 14:57:16 But it does mean you want to have some kind of 'prior' feature sometimes, especially for LOCATE or SEE 2023-10-04 14:57:54 Yeah, I use ME to recurse. 2023-10-04 14:59:05 And conditional variants for other looping. 2023-10-04 15:01:29 But I *could* recurse by name. 2023-10-04 15:13:29 I only loop to "start of word" as a matter of design - I factor to make that be what I need to do. 2023-10-04 15:58:06 KiIngram I experimented with something like your array delimiter. I treated the top of stack as a type tag. The first byte was the tag, and then the other three bytes were type specific data. The rest of the data was then spread across the stack. I did the typical least two significant bits of the 32bit word breaking it up into 2023-10-04 15:58:06 00 -> pointer 2023-10-04 15:59:30 ACTION Full disclosure, I haven't used the system extensively. It is still mostly a thought experiment. 2023-10-04 16:00:41 *KipIngram 2023-10-04 16:02:33 What I envision is a stack of pointers, and at the pointer destination I'd find my type information. I've also considered a hybrid stack item, where the low bits are an address and the high bits encode a type. 2023-10-04 16:03:02 But I don't want an object to require multiple stack items - I want all the stack manipulation words to work in the usual way. 2023-10-04 16:03:32 Swap the top two items - you've swapped the top two objects, regardless of what they are. 2023-10-04 16:03:47 I should make clear that I don't plan to have my system work that way out of the box. 2023-10-04 16:03:55 at power up it will just be basic Forth. 2023-10-04 16:04:12 The type-aware stuff will require loading some source code and launching a more sophisticated interpreter. 2023-10-04 16:05:20 seepel: I've got a strong interest in scientific computing - number crunching. So I want that higher tier system to work really well with vectors and matrices and stuff like that. 2023-10-04 16:05:36 That's why I've been interested in APL; looking for "stealables." 2023-10-04 16:06:08 That makes a lot of sense. APL is a language I haven't gotten to learning yet, but it seems quite intriguing. 2023-10-04 16:09:34 It really is, and it not like picking up "yet another mainstream language." It's quite different, and learning those symbols adds a layer of memorization to it. I found a tutorial that I thought was helpful: 2023-10-04 16:09:49 https://tutorial.dyalog.com/next.html 2023-10-04 16:10:03 You probably don't need the /next 2023-10-04 16:10:19 It's a little time consuming, but there's a lot to learn. 2023-10-04 16:10:41 I've done "most of it" once - I'll need to repeat some of it. 2023-10-04 16:11:29 APL is infix rather than postfix, and I'm struggling a little with how to move all of the features to a postfix setting. 2023-10-04 16:11:44 Without uglying up the way code looks too much. 2023-10-04 16:12:10 Yup, I started with lisp, then a little Agda, the Forth. I feel like something like APL is next on the list :) 2023-10-04 16:13:07 In APL a lot of the symbols can function either with right operands only (monadic) or with both left and right (dyadic). APL works in a way that makes it possible to figure out which should be used in each case - that's one of the things that will be harder in RPN. 2023-10-04 16:13:30 there the stack will be sitting - but no way to tell whether the intent was monadic or dyadic. 2023-10-04 16:14:09 Someone posted a link here a few days ago to an RPN APL-like language called uiua. They solved the issue by just limiting each symbol to one specific way of operating. 2023-10-04 16:14:15 But that means a bunch of new symbols. 2023-10-04 16:14:42 That you wouldn't be able to easily find keyboard support for. 2023-10-04 16:15:34 KipIngram: can you explain monads? 2023-10-04 16:16:13 Not in a proper way. I used the word there just to refer to a function that takes one operand. 2023-10-04 16:16:46 aah, that is, one arity function then 2023-10-04 16:17:16 arity saying on how many arguments a function or method takes 2023-10-04 16:17:26 Right. I don't really know the fancy computer science usages of the term. 2023-10-04 16:19:53 you can turn a multi arity function into single arity function via currying 2023-10-04 16:20:10 Ok. That fits with my limited knowledge. 2023-10-04 16:20:12 but many find that too spicy 2023-10-04 16:23:01 :-) 2023-10-04 16:23:27 Well, the idea of "pinning down" some of the parameters of a function to get a function with fewer parameters - that in itself isn't terribly challenging. 2023-10-04 16:23:45 But I bet they have some fancy notation for how to write it all down that would be unfamiliar to me. 2023-10-04 16:23:54 there's always "high lingo." 2023-10-04 16:28:16 now currying is like just making a function or closure that captures the value of the argument being curried 2023-10-04 16:29:18 partial evaluation on the other foot is way more interesting as that allows for use of optimazations that generally done in compilers 2023-10-04 16:30:54 leads to stuff like explained in http://blog.sigfpe.com/2009/05/three-projections-of-doctor-futamura.html 2023-10-04 16:33:15 I want to think I've looked that over - maybe you mentioned it to me previously. 2023-10-04 16:34:28 Anyway, the two rubs I see in this are 1) the monadic/dyadic decision I talked about above and 2) deciding when to treat several consecutive items in the input as a vector vs. giving each one its own stack element. 2023-10-04 16:34:51 And I want to resolve those things without making everything see TOO much less tight and terse compared to APL. 2023-10-04 16:35:27 The "obvious" way to handle 2 is to put vector elements inside some sort of brackets, but that really rubs me the wrong way visually. 2023-10-04 16:52:22 The absence of parentheses is one of the nicest things about Forth. One of the things I just discovered in APL is the commute operator ⍨ which flips the arguments the function right before it expects. It can be used to weed parentheses out of an expression, and that was... pleasing. 2023-10-04 17:12:24 KipIngram: just wait until you learn of trains, forks, and pointless style in general 2023-10-04 17:12:55 forks are done with the iota operator ∘ 2023-10-04 17:15:30 F∘G is like {⍺F∘G⍵} for dyads, {F∘G⍵} for monads 2023-10-04 17:15:37 i.e. it allows you to compose functions 2023-10-04 17:18:44 I thought iota was ⍳ 2023-10-04 17:19:02 That little circle isn't a Greek letter, is it? 2023-10-04 17:19:07 sorry, jot not iota 2023-10-04 17:19:12 Gotcha. 2023-10-04 17:22:40 I've been poking at APL off and on for a year or so, so I've seen at least a couple of references to trains and point free, though I'm nothing like "familiar' with them.