2023-05-20 00:01:49 what name would you use for a word that reads a whole file into a string? 2023-05-20 00:02:05 I had FILE-STRING 2023-05-20 00:02:08 but meh 2023-05-20 00:02:42 and there's also the sister word that writes a file from a string 2023-05-20 00:02:50 it was TO-FILE 2023-05-20 00:03:00 I'd like to find a better name for both 2023-05-20 00:03:12 and possibly more related 2023-05-20 01:16:29 SWaLLOW maybe? 2023-05-20 01:16:35 SWALLOW 2023-05-20 01:16:44 SLURP 2023-05-20 01:16:51 READ 2023-05-20 01:17:23 RD 2023-05-20 01:17:38 slurp is the "word" perl already uses 2023-05-20 01:18:17 I suppose I'll end with that 2023-05-20 01:18:26 but I don't really like it 2023-05-20 01:19:14 I like file.string but I can't use a similar word for writing to a file like string.file as it's a bit confusing 2023-05-20 01:19:50 scheme would do it like file->string and string->file 2023-05-20 01:20:10 -> means conversion or "to" 2023-05-20 01:21:01 I just don't like long verbose naumes that take up a quarter or more of my source line. 2023-05-20 01:21:08 :D 2023-05-20 01:21:18 I usually won't go over 4-5 chars tops. 2023-05-20 01:21:31 I like them, I feel like they make it more readable 2023-05-20 01:22:05 I'd like if the program can resemble to pseudocode 2023-05-20 01:28:43 KipIngram: do you have variables? 2023-05-20 01:29:42 is VARIABLE an immediate word? 2023-05-20 01:30:22 if a colon word creates a new variable, the variable will be now a word in the dictionary 2023-05-20 01:30:44 but when compiling the definition of that colon word, the variable did not exist 2023-05-20 01:30:58 what does the compiler when it finds that name? 2023-05-20 01:31:11 shouldn't trigger an error as it does not yet exist? 2023-05-20 01:33:06 I have to solve this problem 2023-05-20 01:33:58 the lazy solution is to not compile a word I don't recognize and fallback to the interpreter 2023-05-20 01:34:27 I just defer the interpretation of that word 2023-05-20 01:34:55 but still it's a problem if I want to set a word that already exists 2023-05-20 01:37:51 for example I have: 24 :var which will create a new word on the dictionary named var that will push the value 24 2023-05-20 01:38:00 : oh 24 :var var ; 2023-05-20 01:38:27 the compiler understands :var and knows what to do, but when it finds var, var does not exist 2023-05-20 01:38:46 and if exists, it will put that definition instead 2023-05-20 01:39:08 the only solution I see is to use another syntax for variables 2023-05-20 01:39:17 which I don't really like 2023-05-20 01:40:44 I can't rely on finding all :var definitions to let the compiler which ones are variables 2023-05-20 01:40:57 but :var could be something like a create does 2023-05-20 01:41:30 yes, if it's immediate I can let the compiler be aware of the new variables 2023-05-20 01:43:29 and I can rely on finding them all anyways 2023-05-20 01:59:52 my immediate words are a bit different. I don't have a compiling flag and they don't create entries or add stuff in the dictionary, except for ':', but they optionally can return values 2023-05-20 02:00:17 I realize they are lisp macros actually 2023-05-20 02:00:54 the compiler executes them and if return a result it will create a function that pushes those results 2023-05-20 02:01:46 also the compiler is recursive 2023-05-20 02:02:44 it's actually the same as the interpreter, but returning functions with the code of what the interpreter would do 2023-05-20 02:03:50 immediate words are also aware of other immediate words, acting like the compiler 2023-05-20 02:04:32 for example : will execute itself if it finds another : inside its definition 2023-05-20 02:05:51 it's also how [ is implemented, which builds a list and it's immediate 2023-05-20 02:06:30 [ when finds another [ executes itself and pushes the returned value of [ on the list is building 2023-05-20 07:57:55 Yes, I have variables. I call that defining word var 2023-05-20 07:58:55 My var isn't immediate, but it could be. It wouldn't make a lot of sense, though, because it would introduce a varible cell into the middle of a definition. 2023-05-20 07:59:25 My dictionary is entirely global. Other than vocabularies it's all just one flat big namespace. 2023-05-20 08:00:16 If I put var inside a definition right now, it will not run var until the definition is executed. 2023-05-20 08:00:25 And it will parse the name from the input stream then. 2023-05-20 08:00:49 : foo ...code... var ...code... ; 2023-05-20 08:00:59 foo bar 2023-05-20 08:01:21 that will run foo which will create variable bar. 2023-05-20 08:02:00 My vars don't take initial values. 2023-05-20 08:02:12 I have const though: 2023-05-20 08:02:17 24 const foo 2023-05-20 08:02:25 that creates a word foo which puts 24 on the stack. 2023-05-20 08:03:28 My : word is immediate. 2023-05-20 08:03:43 : foo ...code1... : bar ...code2 ... ; 2023-05-20 08:04:05 creates two named words. foo will execute ...code1... ...ode2... and bar will execute just ...code2... 2023-05-20 08:04:43 All : does is create a name in the dictionary which causes execution to go to the "then next" place in the code body. 2023-05-20 08:05:07 At any given time there is a "next byte that will be used in the dictionary." 2023-05-20 08:05:32 : just creates word and when it's executed execution goes to that location, so by then I better have put some code there. 2023-05-20 08:06:06 If I did make var immediate, and did this: 2023-05-20 08:06:19 : foo ...code... var bar ...code ... ; 2023-05-20 08:06:57 Then I would have a location named bar that I could store a pair of word xt's into and after I did that foo would execute them when it came to those locations. 2023-05-20 08:07:22 It would give me a way of doing "modifiable" code, and bar would be my handle to the location to modify to control what executed at that point in foo. 2023-05-20 08:07:51 My definition code slots are 32 bits, though, and var allocates 64 bits - that's why there would be room for two. 2023-05-20 08:08:07 Say I did this: 2023-05-20 08:08:19 : foo ...code1... var bar ...code2... ; 2023-05-20 08:08:59 find alpha base.h @ - 32 << find beta base.h @ - + bar ! 2023-05-20 08:09:17 then when I ran foo I'd get ...code1... alpha beta ...code2... 2023-05-20 08:09:37 By storing to bar I'd have "inserted" "alpha beta" into the definition. 2023-05-20 08:09:45 That's IF var was immediate, which it's not. 2023-05-20 08:10:13 With it non-immediate that definition of foo would fail because bar would be undefined. 2023-05-20 08:11:22 Keep in mind that in my system the stream of executable cells is in one memory region and the name headers are in another. 2023-05-20 08:11:55 the value in base.b is the base address of the executable code region; base.h is a variable with the base address of the header region. 2023-05-20 08:12:41 find alpha gives me a 64-bit address. find alpha base.h @ - gives me a 32-bit offset of that same address within the header region. 2023-05-20 08:13:28 I've got too many things like base.h @ + and base.h @ - in my code - I need to create little words with those sequences and use them instead. 2023-05-20 08:13:40 Maybe body+ body- head+ head- 2023-05-20 08:13:53 Or just b+ b- h+ h- 2023-05-20 08:21:18 So, when I restore a system snapshot when I'm recovering from an error, that overwrites my return stack region. On the new system it won't, because I'll allocate stack regions separately, but in the current system it does. 2023-05-20 08:22:00 That will crash the system if I'm not careful. So "unsnap" runs a word that pops the top of the return stack into a scratch register, copies the image back, and then runs a word that pushes that value back to the return stack. 2023-05-20 08:22:16 It's a kludge - the stack really should just be in a separate small region. 2023-05-20 08:22:45 After I run unsnap I quickly reset the stack pointers anyway - I only need that one return value currently. 2023-05-20 08:23:20 I was using r>a and a>r for that, but that meaant that errors wiped my A address register value. 2023-05-20 08:23:32 so yesterday I changed it to an otherwise unused register. 2023-05-20 08:23:54 But this problem will just go away on the new system. 2023-05-20 08:30:50 In that iterator code I wrote yesterday, iter ends with the sequence >r 4+ r> which advances the return address over the next cell, so that return goes one slot further along than it otherwise would. 2023-05-20 08:31:51 That really ought to be a word. Functionally, it would basically just be : skip r> 4+ >r ; but it would need to be a primitive - otherwise it would cover up that top return stack location. 2023-05-20 08:32:36 I'm a little bothered by how usage of >r r> spoils my ability to factor, since it makes it impossible to return when you've put anything over there. 2023-05-20 08:33:23 It caused me to think that perhaps there should be a separate small stack for that sort of "temporary data motion." 2023-05-20 08:33:32 Maybe >s s> s@ 2023-05-20 08:33:43 "scratch stack." 2023-05-20 08:34:31 You'd still want the others too, because sometimes you want at the return stack to play games with return values. 2023-05-20 08:35:31 That would demand a new register if you wanted the best performance, though. 2023-05-20 08:38:56 var scratch 8 cells allot s dup ! 2023-05-20 08:38:57 : >s cell scratch +! scratch @ ! ; 2023-05-20 08:38:59 : s> scratch @ cell scratch -! ; 2023-05-20 08:39:01 : s@ scratch @ @ ; 2023-05-20 08:39:33 Ooops - s/s dup/scratch dup/ 2023-05-20 08:40:14 And that of course would only work for one thread. 2023-05-20 08:41:42 If user variables existed that would multi-thread it. 2023-05-20 09:00:50 https://www.synaptics.com/products/low-power-edge-ai 2023-05-20 09:02:23 I'm still scratching my head over whether that fifo idea is worth anything. 2023-05-20 09:02:43 I particularly didn't understand what they planned to do with it re: return addresses and the dictionary. 2023-05-20 09:03:57 i think it might have been intended as an auxiliary data processing channel instead of replacing the data stack altogether 2023-05-20 09:04:19 Yeah, that's the "mode of my head scratching." It would be fairly easy to add one. 2023-05-20 09:04:20 hard to say without seeing what he had done with the concept though 2023-05-20 09:04:51 Yeah, that slide deck mostly had kind of a "Hey, what if..." flavor to it. 2023-05-20 09:04:56 Nothing "finished." 2023-05-20 09:08:21 "deckware" 2023-05-20 09:14:19 I like that iterator thing. I think I'll be able to generate all of those conditional primitives in maybe 20-ish lnes of code or something. 2023-05-20 09:14:55 The code came out nice and compact, but it's a bit intricate. 2023-05-20 09:27:02 To go with it I will need a nice way to create a string table in memory. Something like 2023-05-20 09:27:20 strings string string ... string 2023-05-20 09:27:47 strings will allocate cells for pointers and then just lay the strings out after. 2023-05-20 09:28:05 So
winds up an array of pointers. 2023-05-20 09:30:07 39 word 39 word would get me the next ' delimited string in the word buffer. 2023-05-20 09:30:37 I'd just set the next pointer and copy that to the dictionary. 2023-05-20 10:36:39 Write it so that
leaves the address of that string on the stack. 2023-05-20 10:36:55 Oh, no - scratch that. 2023-05-20 10:37:03 I just need the normal address to pass to iter. 2023-05-20 10:37:21 iter will supply the string addresses one by one. 2023-05-20 13:04:45 I think I'm beginning to get my arms around this portability layer, though I'm merging ideas around that with the auto-generated code concept. 2023-05-20 13:05:14 I'm starting to think that just a couple of blocks may get me all of my primitives. 2023-05-20 13:06:17 I'm sure there are a few that will have to be hand coded (in portable instructions), but auto-gen looks like it can do a LOT. 2023-05-20 13:06:49 And the nice thing about that is that once its right, there won't be any individual typos plaguing it. 2023-05-20 14:56:26 So what I'm thinking at this point is that it breaks into various categories. First, there's that critical bit of code that implements NEXT, entering new definitions, and handling the tick counter expiration. That gets coded by hand - on x86_64 it's nine lines of code. Then there are portable operations to modify registers in place. Then operations to move a couple of registers to / from the stack 2023-05-20 14:56:27 regions. Then all of the control flow words get auto-generated, and all of the binary data operations get auto-generated (using the register mod and to/from stack operations). The binary operators get auto-generated too, using those same tools. And finally we auto-generate the memory access operations. 2023-05-20 14:56:45 Then there's "whatever's left," which will consist of things that involve system calls and so on. 2023-05-20 15:06:58 I think as far as modifying registers goes, I need not, negate, and adding / subtracting 1, 2, 4, or 8. And I need to be able to do this to TOS, SP, RP, and a "scratch" register. I won't write all those individually - I'll have an add/subtract word that takes a quantity and a register parameter. 2023-05-20 15:08:07 not and negate will take reg parameter. So that looks like four operations to me. Not, negate, add, subtract. 2023-05-20 15:11:03 'halt' is implied 2023-05-20 15:11:43 So + will look something like scratch, sp PREP ; tos sp MADD ; 8 SP+ ; NEXT 2023-05-20 15:12:01 PREP is the one that would be empty on CISC like x86. 2023-05-20 17:31:00 For +! I will need PREP and POST, both of which will be empty on CISC, but will handle the memory transfers on RISC. 2023-05-20 21:31:33 Well, looks like I have 261 primitives in my system, of which 120 are script-generated conditional control words. 2023-05-20 21:32:10 About 50 are memory access words of various sizes or flavors, which can also be auto-generated. Some of the remaining ones can be too.