[HN Gopher] Jonesforth - A sometimes minimal Forth compiler and ...
       ___________________________________________________________________
        
       Jonesforth - A sometimes minimal Forth compiler and tutorial (2007)
        
       Author : Tomte
       Score  : 84 points
       Date   : 2022-05-13 14:36 UTC (8 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | [deleted]
        
       | mftb wrote:
       | What a cool thing and this thread also appears to be full of
       | gems. I'm on a Lisp journey for the next little while, but I'll
       | eventually get to Forth. Filing all this away for later...
        
         | codr7 wrote:
         | I would recommend going the other way as it will probably be
         | easier to appreciate both that way, just from my own experience
         | both learning and writing interpreters for both.
         | 
         | Lisp is sort of the next step after Forth if you ask me, adding
         | slightly more syntax to get better abstractions.
        
           | samatman wrote:
           | I'm inclined to agree with you, just chiming in to say that
           | historically, Chuck Moore was a student of John McCarthy, so
           | Forth was one of many 'next steps' after Lisp. Which is a
           | very old language.
        
       | dmytrish wrote:
       | It was a lot of fun for me to reimplement this in MIPS assembler
       | on CI20 [0]
       | 
       | JonesForth could be more clear about the high-level logic of its
       | interpreter part. I tried to make this part as clean as possible,
       | hopefully did not miss anything.
       | 
       | Maybe I will make a RISCV version in my _copious free time_ in
       | the future.
       | 
       | [0] https://github.com/EarlGray/language-
       | incubator/blob/29755c32...
        
         | drivers99 wrote:
         | I want to write one for bare metal (non-Linux) raspberry pi
         | (ARMv6 32 bit on Raspberry Pi 1 and Zero; ARMv7 and ARMv8 on
         | higher models and also supports 64 bit). I want to have no
         | dependencies required though so was thinking of bootstrapping
         | it with nothing but machine code (determined initially with the
         | help of an assembler and documentation of course). Someone has
         | already ported jonesforth the Raspberry Pi[1] but using serial
         | i/o as the user interface and it has dependecies to build it,
         | but I should be able to get ideas from how they coded their
         | assembly parts compared to the original jonesforth. I want to
         | be able to use HDMI for the screen (already tried it out with
         | some bare metal tutorials in assembly so that's do-able) and
         | again, with no dependencies. And I want to show people how to
         | do it themselves, not just have it be something to run that
         | they don't understand fully. It should also be possible to have
         | the forth kernel build/assemble itself if needed, or cross-
         | target another platform.
         | 
         | I know I'm all talk right now, like you say, I need to manage
         | my free time so that I would have the "copious free time" to
         | work on this.
         | 
         | The only reason I was thinking Raspberry Pi was I wanted
         | something that would be readily available to anyone (although,
         | at the moment it's out of stock due to supply chain issues). I
         | was actually looking at whether anything similar was available
         | with RISC-V (like you mentioned) to target, since that would be
         | interesting.
         | 
         | [1] https://github.com/organix/pijFORTHos
        
       | bowsamic wrote:
       | The only thing anyone ever seems to do with forths is write
       | another forth. Why is this?
       | 
       | Unrelatedly (perhaps) I tried writing some basic software in
       | forth and it was pretty horrific. Even something as simple as
       | representing a variable length array feels like fighting the
       | language
        
         | adastra22 wrote:
         | It is the community that surrounds forth, and the type of
         | hobbyists that are attracted to forth, as well as what they are
         | attracted to.
         | 
         | It's a bit like saying the only thing anyone ever seems to do
         | with Common Lisp is to make macros which redefine the syntax of
         | language. How frustrating! We'll if they didn't want to make
         | use of macros, why were they using lisp in the first place?
         | 
         | Part of the appeal of forth is making your own forth
         | environment. That is the whole answer I think.
        
         | orthoxerox wrote:
         | Because forth is an exercise in minimalism, its answer to most
         | features is YAGNI. The coolest thing about it is how easy
         | something as weird as forth maps to the quite different
         | different underlying (register-based) hardware, so you can use
         | a forth to bootstrap something with more sugar.
        
         | Gordonjcp wrote:
         | Possibly a variable-length array wasn't a good fit for the
         | problem you were trying to solve.
        
         | zozbot234 wrote:
         | > Unrelatedly (perhaps) I tried writing some basic software in
         | forth and it was pretty horrific.
         | 
         | It might be instructive to compare FORTH to e.g. the previously
         | discussed language K, which is similarly terse in some ways. It
         | turns out that a few convenience features - including first-
         | class- and higher-order- functions, neither of which really sit
         | well within the FORTH stack-focused model - can make a real
         | difference.
        
         | fmakunbound wrote:
         | If you've seen one Forth, you've seen one Forth.
        
       | nikolay wrote:
       | It's strange that Lisp became so popular, and Forth - not so
       | much! I've enjoyed GraFORTH on Apple ][ and then using it to
       | generate it in PostScript to generate logos and complex graphics
       | programmatically not using an editor.
        
       | codr7 wrote:
       | Forth is a great place to start, I've done several remixes in
       | different languages along the way:
       | 
       | https://github.com/codr7/fibr
       | 
       | https://github.com/codr7/forthy2
       | 
       | https://github.com/codr7/gfoo
       | 
       | https://github.com/codr7/fipl
        
       | haolez wrote:
       | When I see FORTH stuff like this, I cannot avoid thinking that in
       | a post apocalyptic world, we would be scavenging computer parts
       | and writing FORTHs to use them :)
        
         | mncharity wrote:
         | For a different apocalypse poem, allow everything existing to
         | be used, but the coming population collapse demands a full
         | stack replacement. To preserve existing capabilities and
         | progress, but supported by far fewer people.
         | 
         | We've had environments with far greater individual programmer
         | productivity than is currently common. But while forth starts
         | out nicely with simple systems, costs escalate unhappily with
         | goal complexity. Similarly with smalltalk, lispms, prolog,
         | haskell. The perennial "we'll easily do a full-stack rewrite in
         | our wonderful X" efforts... haven't.
         | 
         | Past/current efforts avoid implausible goals, like LLVM-quality
         | compilation has to become a one-person project. Or slather on
         | viability constraints, like must run on M in time T, and be
         | accessible to population P. Or "we don't know how to compile
         | that leverage efficiently and consistently - that paper hasn't
         | been written yet - so you can't have it".
         | 
         | But there are increasingly opportunities to do things
         | differently now, if narrower goals demanded it. Community-wide
         | compilation caches - "it ok that the type proof / bulk code
         | translation / whatever sometimes takes days, it only needs to
         | happen once". Compiler runs spinning up 10000 cloud instances.
         | And so on.
         | 
         | What might it look like, to attempt not merely a bootstrap, but
         | a subsuming breakaway?
        
           | eternityforest wrote:
           | I think the current system would be supportable with a
           | collapse. You have fewer developers... but also fewer
           | hackers, so I would guess security stays the same, other than
           | if the collapse created extra crime incentive.
           | 
           | We could just freeze all the fundamentals. If it was a real
           | emergency, we could mostly stop working on new niche
           | languages,Stop adding language features, stop deprecating
           | stuff, and just focus on essential applications with only the
           | tech we have.
           | 
           | We'd obviously want some level or new work on the
           | fundamentals and language level stuff, but we'd just focus on
           | things that help you code with less people and poorly trained
           | people(Replacing C with Rust could be the big project of the
           | century).
           | 
           | Tech is pretty great at the moment, seems like we could just
           | get by for centuries, totally long enough to rebuild, if we
           | just had what we have now, and enough hardware infrastructure
           | to keep the fabs running. We don't really need a new kernel
           | or a new graphics card architecture until society is stable
           | again.
        
         | 7373737373 wrote:
         | See https://bootstrapping.miraheze.org/wiki/Main_Page
         | 
         | > This wiki is about bootstrapping, i.e., building up compilers
         | and interpreters and tools from nothing.
        
         | carapace wrote:
         | I just used Jonesforth as a guide/model to write a Forth for
         | the Project Oberon RISC chip last week. It's not finished yet
         | but it works:
         | 
         | https://git.sr.ht/~sforman/PythonOberon/tree/master/item/for...
         | 
         | https://git.sr.ht/~sforman/PythonOberon/tree/master/item/for...
         | 
         | The idea is to make something like (or a port of) CollapseOS,
         | but with a 32-bit machine. The Oberon RISC chip is big enough
         | to be more useful than 8-bit systems yet simple enough that you
         | could build one out of discreet components if you had to. It's
         | really _really_ simple.
        
         | stevekemp wrote:
         | On that theme, collapse-OS has a discussion:
         | 
         | http://collapseos.org/forth.html
        
           | WalterGR wrote:
           | "Forth isn't particularly fast either. As an interpreted
           | language, it is blazing fast, but the speed tax of the
           | threaded model still has to be paid, so it will generally be
           | slower than code produced by a C compiler."
           | 
           | Not being familiar with this sense of "thread," I found a
           | good explainer here:
           | https://www.complang.tuwien.ac.at/forth/threaded-code.html
           | 
           | And, as always, Wikipedia:
           | https://en.m.wikipedia.org/wiki/Threaded_code
        
             | shadowofneptune wrote:
             | Theaded code always interests me, but there definitely is a
             | price to it. Should be noted though that a lot of newer
             | Forths diverge from the classic threaded code model.
             | Because it is a concatenative language, it is possible to
             | have one that compiles native code by copying inlined
             | subroutines (https://citeseerx.ist.psu.edu/viewdoc/download
             | ?doi=10.1.1.56...).
             | 
             | For example to compile : SQUARE DUP + ; all the compiler
             | has to do is copy the machine code of DUP to the place
             | where SQUARE is being compiled, remove the ret instruction
             | at the end of it, and copy the machine code of + after it.
             | It can also do some small optimizations to remove redundant
             | instructions.
             | 
             | You can do this with other languages, but concatenative
             | languages can make it as simple as literally concatenating
             | bits of code.
        
               | kragen wrote:
               | Yeah, that's pretty much how Ur-Scheme compiles, inspired
               | by bigForth: http://canonical.org/~kragen/sw/urscheme
        
               | j6a wrote:
               | kragen, I emailed you on the 28th, can you please check
               | it?
        
               | 0xdeadbeefbabe wrote:
               | It's like the compiler becomes the CPU you wanted in the
               | first place.
        
             | rwmj wrote:
             | There are a few issues here. Running threaded code
             | interacts badly with branch prediction. Essentially every
             | "word" (operation) is followed by a branch to the next
             | word, and those seem hard to predict (or at least with
             | 2010-era hardware they were very hard to predict, maybe
             | more modern branch prediction can do better?). The reason
             | is that a popular word, say, +/add, might be called from
             | all over the program. Only one copy of the word exists and
             | the indirect jump to the next word could go anywhere.
             | 
             | However Forth does allow you to "inline" words, basically
             | form a new word by chaining together existing words, which
             | avoids this overhead. This doesn't optimise adjacent words,
             | but it still gets semi-reasonable performance. (Inlining in
             | JONESFORTH: https://github.com/nornagon/jonesforth/blob/d97
             | a25bb0b06fb58...)
             | 
             | Modern Forths just have regular optimising compilers so
             | none of this stuff applies, but they don't have the simple
             | purity of one that you write and fully understand yourself.
        
               | kaba0 wrote:
               | Just an anecdotal experience, but I'm currently writing a
               | JVM in Rust with a naive, interpreter loop. OpenJDK's
               | interpreter is a so-called template interpreter which
               | looks at the method's byte code and generates a given
               | machine code snippet for each instruction, puts them
               | serially next to each other and executes this buffer. The
               | advantage of the latter is that in the interpreter loop
               | model, one jumps back to the switch statement which will
               | jump to the next instruction's implementation, etc, while
               | OpenJDK's solution just continues execution serially,
               | taking advantage of the branch predictor.
               | 
               | In my benchmarks that are definitely not suitable to
               | infer much, OpenJDK without JIT can perform 1.5-8x
               | better, though of course the whole implementation is
               | different so don't read too much into that.
        
               | cmrdporcupine wrote:
               | It's amazing to me in general how much of a divergence in
               | expectations of performance vs reality that branch
               | prediction misses causes in modern software.
               | 
               | So many techniques that would improve performance on a
               | 1980s processor can be woefully inefficient on a 21st
               | century one. It's so easy to be still holding the
               | computing model of the former in your head.
        
               | kaba0 wrote:
               | What is absolutely crazy is that many "primitive
               | computation" is basically free. Like, there is more than
               | likely some memory stalls either way and they just happen
               | in the pauses not causing longer execution time.
        
             | retrac wrote:
             | As with all languages, the compiled/interpreted distinction
             | is a thing of convention/existing tools. Interpreted Forth
             | is small, and tolerable speed-wise for tiny systems. But
             | Forth can also be compiled directly to native machine code.
             | 
             | Relatively easily, you can get rid of the interpreter
             | overhead by writing blocks of machine code that do each
             | Forth word's action, instead of bytecode to dispatch the
             | interpreter to each of those routines. Forth can be adapted
             | for that easily enough, and some Forths do support this on
             | a per-word basis, allowing you to pick how you want your
             | words compiled.
             | 
             | Forth can also get the whole optimizing compiler treatment.
             | Some optimizing Forth compilers have been released, but I
             | don't know how good they were/are. Certainly never needed
             | that kind of speed myself. I don't know if any Forth yet
             | benefited from it, but a lot of work was put into Java, on
             | approaches for optimizing stack machine-style code to
             | reasonably fast native code for register machines.
        
       | siraben wrote:
       | Some time ago I wrote an implementation of Forth that runs on the
       | TI-84+ and TI-83+ calculators directly inspired by Jonesforth.[0]
       | It runs under TI-OS as well, but the amount of available space is
       | somewhat limited. On another implementation I wrote[1] you have
       | full access to the calculator hardware and memory from Forth.
       | 
       | [0] https://github.com/siraben/ti84-forth
       | 
       | [1] https://github.com/siraben/zkeme80
        
       | stevekemp wrote:
       | Here's one of the many forks that brings it up to 64-bit:
       | 
       | https://github.com/matematikaadit/jombloforth
       | 
       | If you like forth there's an awesome series of comments here on
       | hacker news on building a simple variant in a few simple steps:
       | 
       | https://news.ycombinator.com/item?id=13082825
       | 
       | I took that, and built a simple forth-like system, in golang
       | following the original recipe and breaking it down into simple
       | steps for learning-purposes:
       | 
       | https://github.com/skx/foth
        
       | zevv wrote:
       | [SSP] Assembly is of course nice, but not always practical. For
       | those interested in a compact, embeddable and portable little
       | Forth written in C, take a peek at zForth:
       | https://github.com/zevv/zForth.
        
       ___________________________________________________________________
       (page generated 2022-05-13 23:00 UTC)