2025-02-14 13:35:25 Hello, is there a way to write an IRC bot in forth? 2025-02-14 13:35:47 I am new to forth language and to practice my knowledge I would like to make a IRC bot in Forth 2025-02-14 13:41:05 Hi ghodawalaaman. The common incarnations of Forth such as GForth are complete languages that give you access to all of the capabilities of your computer, so yes, you ought to be able to do that. I've not done it myself; you'd just need to visit your system's documentation to learn how to do the various OS specific things required. As far as the general computational actions go, though, sure - 2025-02-14 13:41:07 you can do anything in Forth you can do in C, Python, or any other language. 2025-02-14 13:42:25 I think it's a fine goal to have, but if you're just beginning to learn about Forth you might be better off starting with some simpler problems - possibly little tools you could then use when you attempt your bot. 2025-02-14 13:43:48 Write a little toolkit to, say, manipulate linked lists, etc. 2025-02-14 13:44:08 yeah, maybe you are right. I have only learned RPN and how to define my own custom "WORD"s and some basic command like DUP, OVER etc. 2025-02-14 13:44:36 Right - getting "comfortable" with Forth's RPN nature and so on is usually a bit of an adjustment for folks. 2025-02-14 13:44:46 would it be sufficient for implementing linked list in forth? 2025-02-14 13:46:22 I don't quite follow - would what be sufficient? Forth can certainly do that. Doubly linked lists are particularly interesting, I've found - it felt to me when I did that that there is a "good" way to do it (meaning it seems efficient and relatively compact), but it took a bit of work to find it. I think it's a very good training exercise. 2025-02-14 13:47:54 I guess my motivation for suggesting this is to keep you focused on "Forth itself" while you learn; I think a problem like a bot is going to take you off into how to do networking and things like that that are not really "core" to the language. 2025-02-14 13:48:17 And on top of that a lot of those "side functionalities" you will need will be done differently in different Forths. 2025-02-14 13:48:50 Whereas what you really want to master first are those parts of Forth that are more or less universal. 2025-02-14 13:50:02 I was kind of lucky here - the very first device I ever learned to program was an HP-41CV scientific calculator - I used it in college. It's RPN, so I got comfortable thinking that way before I learned any other way of thinking about programming. 2025-02-14 13:50:53 I was asking if knowing just how to define WORD's and basic command would be sufficient to implement a linked list or do I have to learn more advance forth to do it 2025-02-14 13:51:41 Oh, well, yes - that is how you program in Forth; you define words. The idea is to invent yourself a little "language for talking about your problem," and then you implement the words of that language. That "lexicon" is tailored to your problem at hand. 2025-02-14 13:52:41 I see 2025-02-14 13:52:55 Say you wanted to maintain a sorted doubly linked list of names and ages. You'd need words for marching along the list in either direction, a word to insert new items, a word to search for an item, delete an item, etc. 2025-02-14 13:53:59 One thing you'll see pretty quick is that Forth is pretty limited right out of the box. For example, even manipulating strings is somewhat clunky - you have to allocate the memory for the string data, copy the data into it, etc. You can't just say something like "name" ! 2025-02-14 13:54:16 The only truly native "data type" in Forth is integers. 2025-02-14 13:54:31 one thing I am thinking how do I get addresses in forth, I mean we need pointers to access Linked List 2025-02-14 13:55:25 yeah, also integers are pretty limited in size 2025-02-14 13:55:45 Yes, you manage your memory by hand in Forth. A particular Forth might give you something akin to malloc and free, but the core language only has "the dictionary." You can allocate the next N bytes of the dictionary for some purpose by saying ALLOT. 2025-02-14 13:56:04 At anny given time the word HERE will leave an address on the stack. That's the address of the first unused byte in RAM. 2025-02-14 13:56:07 In the dictionary. 2025-02-14 13:56:20 ALLOT just moves that pointer forward bytes. 2025-02-14 13:56:32 So say you need a 100-byte buffer. 2025-02-14 13:57:07 HERE 100 ALLOT is what you do - the HERE puts the address of your buffer on the data stack, and the 100 ALLOT reserves those 100 bytes. 2025-02-14 13:57:14 Then you do anything with that address you want. 2025-02-14 13:57:52 Anything you do that defines anything moves that pointer. For example, when you make a definition: 2025-02-14 13:58:02 : foo bar bam boom ; 2025-02-14 13:58:24 That puts the data associated with that definition in RAM and adjusts the dictionary pointer to reserve that RAM. 2025-02-14 13:58:45 Basically the dictionary just grows upward in RAM, and the "free space" is always just the space after everything you've used. 2025-02-14 13:59:51 HERE 100 ALLOT ok 1 2025-02-14 13:59:52 . 140102110258264 ok 2025-02-14 13:59:58 In the early days there was just one RAM range and you just worked your way through it. These days systems keep different sorts of data in different regions, so each region would need its own pointer. So it might not be as simple as HERE in all systems, but you can usually count on HERE to give you an address in your primary data storage region. 2025-02-14 14:00:14 Yes, that number is the address of your 100 bytes. 2025-02-14 14:00:21 I see 2025-02-14 14:00:57 emanuele6 told me 2 days ago that we have 3 types of stack in forth 2025-02-14 14:01:18 I have only worked with 1 stack so far in Forth 2025-02-14 14:01:19 Well, there's the data stack, that words like SWAP DUP OVER manipulates. 2025-02-14 14:01:43 Then the return stack is how you transfer control between your words. When a word calls another word, the return address is stored there. 2025-02-14 14:01:54 That's just like any language, except in Forth you can access it manually. 2025-02-14 14:02:25 >R will move a value from the data stack to the return stack, and R> will move the other way. But those don't work interpretively - you can only use them in definitions. 2025-02-14 14:02:40 And they have to balance - if you >R in a definition, you must R> before you return. 2025-02-14 14:02:52 But what it allows you to do is play games with control flow. 2025-02-14 14:03:05 You can actually dicker around with the return addresses on that stack. 2025-02-14 14:03:16 I'm not sure what the third stack would be - most Forths only have two. 2025-02-14 14:03:43 ohk so first is data stack and other on is return stack 2025-02-14 14:03:48 hmm makes sense so far 2025-02-14 14:04:14 Let me give you a simple example of doing interesting things with the return stack. Consider this definition: 2025-02-14 14:04:29 : foo swap over ." this is a test" ; 2025-02-14 14:05:11 That definition will have a call to swap, a call to over, and then a call to a "runtime" associated with ." After that the string "this is a test" will sit there right in the definition, and finally after it will be a return operation compiled by ; 2025-02-14 14:06:02 So when you execute that, swap executes, over executes, and then that runtime for ." will use the return address on the return stack to FIND THE STRING, print it, and then will modify that return address to jump it over the string, so that it points to the return word. Then the return executes. 2025-02-14 14:06:16 So that ." runtime has toyed with the return stack to accomplish its purpose. 2025-02-14 14:06:42 If it didn't modify the return address, then the system would try to execute the string data, and that wouldn't go well. 2025-02-14 14:07:39 let me run that program in gforth 2025-02-14 14:08:39 It throws stack underflow, maybe because there is nothing on the stack and it tries to call swap on a empty stack 2025-02-14 14:08:41 I should also point out to you that there are a number of different "styles" of Forth systems these days. Early Forths stored definitions as a list of addresses - just a data structure - that some code in the system would process to execute your code. But some Forth systems these days compile your Forth all the way to machine code, and the "return stack" is essentially just the microprocessor's 2025-02-14 14:08:43 native stack. 2025-02-14 14:09:20 Oh, well, right - swap and dup in that word I gave you have to have something to work on. Put two numbers on the stack first. 2025-02-14 14:09:33 I was really focused on the ." in that example; the rest was just filler. 2025-02-14 14:09:59 I see 2025-02-14 14:10:53 ok, now it works, I put 1 2 on the stack 2025-02-14 14:11:07 yeah, there are 3 elements on the stack 2025-02-14 14:11:08 SWAP takes you from 1 2 to 2 1, and dup gives you 2 1 1 2025-02-14 14:11:32 Have you heard about Starting Forth and Thinking Forth? 2025-02-14 14:11:42 Both are books you can find online which are generally considered useful. 2025-02-14 14:11:52 yes, I am reading Starting Forth book, it's free! 2025-02-14 14:12:22 I have learned till around 50 pages of the book 2025-02-14 14:12:23 Yep, Thinking Forth is too. Starting Forth is more about the nuts and bolts, and Thinking Forth more about actual software development with a Forth focus. 2025-02-14 14:13:08 ACTION going afk, brb 2025-02-14 14:13:09 I think Thinking Forth may help you get more of a handle on actually doing stuff with Forth. 2025-02-14 14:13:14 Good luck! 2025-02-14 14:23:09 ghodawalaaman: https://www.forth.com/wp-content/uploads/2018/11/thinking-forth-color.pdf 2025-02-14 14:49:19 ghodawalaaman: I have an (older) example IRC bot in retroforth at https://retroforth.org/examples/irc-bot.retro.html (glossary at https://retroforth.org/examples/irc-bot.retro.glossary); note that retro is not a standard forth model 2025-02-14 15:03:55 Thank you for the link KipIngram, crc! 2025-02-14 15:09:28 ghodawalaaman: I'm curious about that third stack your friend referred to - if you get clear on what they meant please let me know. 2025-02-14 15:10:55 The only thing I can think of is the dictionary itself, which you can view as a stack of sorts if you squint. When you remove things from the dictionary, it's a last in, first out thing. If you define new words foo bar and bam, you can't get rid of bar without also getting rid of bam, or foo without getting rid of bar and bam. 2025-02-14 15:11:13 That said, we don't normally think of the dictionary as a "stack" per se. 2025-02-14 15:11:58 Oh, also I told you that if you make a new definition it moves HERE to allocate the RAM. If you then remove that definition, HERE will go back down. 2025-02-14 15:15:29 Here's a little gforth example: 2025-02-14 15:15:30 https://pastebin.com/1HwDqYNw 2025-02-14 15:15:48 "marker" is a word you use in Gforth to restore the dictionary to an earlier state. 2025-02-14 15:17:00 marker alpha creates a word alpha that snapshots the state of the dictionary BEFORE alpha is created. Later execution of alpha trims the dictionary back to that state. 2025-02-14 15:17:27 So once you execute alpha, it also is gone from the dictionary - you can't execute it again without defining it again. 2025-02-14 15:17:56 Older Forths use the word FORGET - you just say FORGET and everything back to and including is tossed out. 2025-02-14 15:18:38 I see 2025-02-14 15:18:45 It was completely sufficient back when Forth memory structures were simpler, but things became more involved over time, and the marker mechanism handles the new complexityh. 2025-02-14 15:21:11 So when I executed alpha in that example, it not only removed alpha from the dictionary, but beta and test as well. 2025-02-14 15:22:35 it's little bit complex for me tbh 2025-02-14 15:23:02 Compared to other programming languages, it's probably the return stack that will take the most getting used to for you. That calculator I learned on didn't have an exposed return stack, and even now, decades later, it's easy for me to overlook some of the possibilities the return stack offers me. 2025-02-14 15:23:44 You don't really need it for most application work, but it can come in really handy when you're trying to add new "basic capabilities" to your setup. 2025-02-14 15:25:54 The most common use people put it to is a handy bit of scratch space. Let's say you want to write a word that reverses to second and third items on the stack. That is, you type 1 2 3, and you want a word that swaps the 1 and the 2. 2025-02-14 15:25:59 The handiest way to write that is 2025-02-14 15:26:12 : swap23 >r swap r> ; 2025-02-14 15:26:40 >r just gets the 3 out of the way momentarily, you swap the 1 and the 2, and then you pull the 3 back. 2025-02-14 15:27:16 ( swap23 --> swap items 2 and 3 on the stack ) 2025-02-14 15:28:34 And the reason you can't use >r and r> from the interpreter is because that interpreter is Forth code that is running as it processes your input - it will find >r, say, in your input stream and will execute it, but that just fouls up its own control flow. 2025-02-14 15:29:50 But when a definition you've written is running, the whole system belongs to you and you can do anything that makes sense. 2025-02-14 15:31:08 I mostly use the return stack as a temporary variable 2025-02-14 15:31:18 And in this context "making sense" means that your >r's and your r>'s have to be balanced within each definition. Unless they don't need to be - it is possible to put R> DROP in a definition, and when that definition finishes control will return not to the word that called the definition, but to the caller's caller. 2025-02-14 15:31:42 xentrac: Right - the other uses for it are less common. 2025-02-14 15:32:26 set it up with >r, read it with r@, and finally consume it with r> 2025-02-14 15:32:37 data stack, control-flow stack, return stack; standard forth only 2025-02-14 15:32:37 gives you functions to interact with the return stack; the control 2025-02-14 15:32:37 flow stack is for the 2025-02-14 15:32:47 KipIngram: this is the answer I got from emanuele6 2025-02-14 15:33:32 usually the control-flow stack is the data stack, as that subsection explains 2025-02-14 15:33:36 Control flow stack. Ok, fair enough. I'm kind of old fashioned - I think in the system's I've written I just use the data stack for my "control flow stack." It's something that comes up when compiling nested control structures. 2025-02-14 15:33:42 But that answer makes sense; thanks. 2025-02-14 15:34:40 but they wanted to write the standard to permit Forth implementations that handle control-flow nesting differently, and not to constrain how many items each control structure puts on the data stack 2025-02-14 15:35:47 the control-flow stack is syntactic nesting 2025-02-14 15:36:38 ghodawalaaman: Say you write a definition that has IF ... THEN in it. That IF compiles a conditional jump, but at the time it's compiled it doesn't know where the jump needs to go to (it needs to go just past the THEN). So it leaves some info on the control flow stack which includes the address in RAM where the jump target needs to be placed. 2025-02-14 15:36:51 Then later when THEN is compiled it will use that info to fill in that jump target. 2025-02-14 15:37:22 And sense you can nest IF ... THEN and other control structures, that implies a stack structure. 2025-02-14 15:38:33 interesting 2025-02-14 15:38:43 THEN doesn't actually compile anything itself - filling in that jump target is its only action. 2025-02-14 15:40:26 And this all involves HERE - as each word in your ... code is compiled, it's placed at HERE and HERE is nudged forward. So the jump target THEN writes into that jump instruction is just HERE at the time THEN executes. 2025-02-14 15:40:42 But since THEN doesn't add any new code, it doesn't actually nudge HERE. 2025-02-14 15:40:43 similarly when you're compiling JavaScript `if (x < 3) { return null }` the compiler needs to keep track of the `if` on a stack so that it can make the `return null` run conditionally, but the stuff after it not 2025-02-14 15:41:00 in whatever way it does that 2025-02-14 15:42:09 I don't think the standard guarantees then doesn't nudge here: https://forth-standard.org/standard/core/THEN 2025-02-14 15:42:18 but that is typically true 2025-02-14 15:49:34 What would it do? That page just says it "continues execution." I think I agree that it doesn't PROMISE no change to HERE, but I can't think of anything that it would need to put there. 2025-02-14 15:49:47 I'm kind of simple-minded on things like this, though. 2025-02-14 15:51:51 you could imagine various kinds of debugging-related things like appending a byte to a trace buffer 2025-02-14 15:52:13 I haven't seen anybody do that, though 2025-02-14 16:15:37 KipIngram: I've implemented an IF/THEN that creates & terminates quotations (so that `IF ... THEN` becomes essentially `[ ... ] if`). In this case, THEN modifies HERE while closing off the quotation and compiling in the call to the `if` combinator. 2025-02-14 16:21:51 crc: not that it needs to be, but is that potentially standards-compliant? 2025-02-14 16:23:54 certainly not fully standard. It's part of code to aid in porting standard forth code to retroforth. 2025-02-14 16:25:04 There's some limits, particularly involving things that do stuff like early exits within the conditional. (I have some constraints here; the VM has a conditional call instruction, but no conditional jumps) 2025-02-14 16:25:44 Oh, right, dup 0< if exit then is standards-compliant code but wouldn't work that way 2025-02-14 16:27:15 yes, that wouldn't work in my system 2025-02-14 16:28:54 which is a totally reasonable choice 2025-02-14 16:29:26 by itself it doesn't say much about what then can or can't do in standards-compliant systems, but it does suggest the following possibility: 2025-02-14 16:30:56 what if if compiles a conditional jump to a new hunk of code (which becomes the new here) and then compiles an unconditional jump back to after the if (and points here back there)? offhand I can't think of a way that would violate the standard 2025-02-14 16:31:24 and it's something you might reasonably want to do in an optimizing compiler, at least some of the time 2025-02-14 16:33:04 actually https://forth-standard.org/standard/core/HERE seems to impose basically no requirements on the behavior of here when you're compiling a colon definition 2025-02-14 16:34:26 "A system guarantees that a region of data space allocated using ALLOT, , (comma), C, (c-comma), and ALIGN shall be contiguous with the last region allocated with one of the above words, unless the restrictions in the following paragraphs apply. The data-space pointer HERE always identifies the beginning of the next data-space region to be allocated. As successive allocations are made, the data-space 2025-02-14 16:34:32 pointer increases. A program may perform address arithmetic within contiguously allocated regions." 2025-02-14 16:34:40 that should be allowable as far I understand the standard 2025-02-14 16:34:53 crc: I see. Ok, makes sense. Some of the fancy stuff you do just isn't stuff I've really considered very much. My approach is generally fairly primitive. 2025-02-14 16:35:32 Almost FIG in its simplicity for most things. 2025-02-14 16:36:44 Probably the biggest deviation I've made from the FIG structure is that I do keep headers and bodies separate. 2025-02-14 16:39:20 Makes sense on systems with caches, reduces cache pollution 2025-02-14 16:40:44 and in principle means headers don't need to be mapped RWX 2025-02-14 16:41:59 also makes sense if you're target-compiling to for a microcontroller 2025-02-14 16:42:28 My main motivation for it was the notion that I might want to use the thing to build an executable for a micro or something, in which case I'd move just the executable stuff and not the headers to that target. 2025-02-14 16:42:37 W^X doesn't really relate to segregated headers 2025-02-14 16:42:59 it does relate to segregating data space and code space 2025-02-14 16:43:08 And also I frequently compile sequences of words where one just falls through into the next - I don't have to jump around an intervening header. 2025-02-14 16:43:13 KipIngram: I wouldn't necessarily consider my approach to be fancy, just different 2025-02-14 16:43:16 In the case of retro, since I don't have a conditional jump instruction in the vm, traditional if/then, loops, etc aren't doable in an efficient way 2025-02-14 16:43:37 forth is much more convenient with lots of variable and value, but i'm probably biased since i write it on a desktop 2025-02-14 16:43:53 I was thinking of your quotations - that bit of your work has come up here a number of times. I have nothing akin to it. 2025-02-14 16:44:44 It's fairly common for me to have something like this: 2025-02-14 16:44:51 : word ...initialize a loop... 2025-02-14 16:45:01 : (word) ...loop body... ; 2025-02-14 16:45:39 Because the only looping construct I have is "loop back to beginning of latest word." 2025-02-14 16:46:08 Usually (word) will be compiled with that flag I use that lets me trim names out of the dictionary later. 2025-02-14 16:46:56 quotations are obviously the right thing if you're doing GC 2025-02-14 16:46:59 makes sense. my use of quotations kind of fell out of my personal preferences around factoring, having words which operate on other words, and a desire to have fewer syntax forms 2025-02-14 16:47:29 collatz conjecture in forth http://0x0.st/8NP8.forth 2025-02-14 16:47:36 if you're allocating space for code with a traditional pointer-bumping allocator, they have this kind of annoying characteristic where you need an unconditional jump around them 2025-02-14 16:48:33 ACTION has a `gc` combinator, but it's not a real gc. More like `: gc here >r execute r.  2025-02-14 16:48:44 r> heap ! ; 2025-02-14 16:58:06 ? 2025-02-14 17:00:03 do we have forth eval bot here? 2025-02-14 17:01:19 ghodawalaaman: no 2025-02-14 17:02:09 hmm, I have seen evalbot in almost evey IRC channel in Libera 2025-02-14 17:02:14 crc: :o 2025-02-14 17:02:18 : gc ( addr -- ) here >r execute r> heap ! ; (rough translation to standard forth, apart from the code to reset the address for here) 2025-02-14 17:05:19 ghodawalaaman: if you want to run one, that's fine by me 2025-02-14 17:05:41 ghodawalaaman: the issue is that there's a million billion implementations of forth 2025-02-14 17:05:51 and some of them are slightly compatible 2025-02-14 17:06:02 (some issues to consider: preventing abuse, locking down the host access, and as amby notes, which forth would you provide?) 2025-02-14 17:07:26 I have made powershell eval bot using docker containers, this is the most straight forward way of running a eval bot 2025-02-14 17:08:15 amby: we can support most used forth's implementations, eg, gforth 2025-02-14 17:08:37 crc: yeah, it will take some efforts to do so 2025-02-14 17:09:10 I am still learning forth, I have just discovered forth two days ago when emanuele6 mentioned it 2025-02-14 17:13:08 if you decide to run a forth bot, please let me know the nick it runs under 2025-02-14 17:14:42 yeah, sure! 2025-02-14 17:15:44 docker is not really designed to securely contain malicious code 2025-02-14 17:15:57 and if you put an evalbot on Libera, people will sometimes test it with malicious code 2025-02-14 17:17:57 or spam it, so rate limiting may also be advised 2025-02-14 17:18:14 or offer private queries so they can spam it there 2025-02-14 17:19:17 I will keep that in mind 2025-02-14 19:33:12 Know what, maybe the best feature of forth is just bringing a few like minded people together. :) 2025-02-14 22:05:26 user51: :-)