ohhh noooo I am definitely going to write a 16-bit x86 Forth as a scripting language for my game, this is happeniiiiing

· · Web · 2 · 3 · 9

Ok after I calmed down I decided to try writing my Forth in C, at least to start. I don't mind if it's kinda slow, and it turns out interactive debuggers are nice and I like them

nnngg reading more Forth implementations and there's so many improvements I wanna make to Forp RIGHT NOW but I'm at work and have other stuff to do tonight

Woo I added immediate words and if/else/then and refactored my interpreter loops and it's much less bullshit now

Next time I'll add the ability to load code from files and hook it up to my game engine

Slowly dawning on me why people write editors in forth

Like, I have a repl, and it's great, but what I really need is a window next to my repl with all my code in it, and that's not a thing I get to have on a single-tasking system which will run over a serial port, sorry

A little decompiler would be pretty easy to write and would be a good 80% solution though

Pretty much the first time in over a month of recreational coding that I've genuinely missed the creature comforts of 2019 tho

Ahaha I wrote a decompiler in 7 lines of forth but it can't quite decompile itself because when it gets to the part that checks if it's finished, it mistakes the literal reference to _RET for the actual end of the word

Now that I've got a working kernel, and I added the ability to load source from a file, it is so much fun to flesh out the language from inside itself!

I refactored if/else/then into forth words after reading the source to another forth and realizing how close I already was. Then I wrote a looping construct begin/while/repeat in forth 'cause it was really not any harder than writing if/else/then. Then I implemented comments. Should probably take on string literals next.

I also added a really nice feature where it just dumps the whole interactive session to a log file, so I can develop new words interactively and I don't have to memorize the code I wrote in order to keep it.

One of the really nice things about writing your own forth is that there is so much useful documentation still out there about how to implement various features. Brad Rodriguez's writing in particular is a treasure; today's gem is this wonderful overview of multitasking bradrodriguez.com/papers/mtask

The answer to "how do I do X in forth" is invariably "there is an extremely simple version that fits in about two screenfuls of code and someone has written about it"

So I implemented cooperative multitasking yesterday, which means:
* I can run the serial port REPL in its own isolated task (necessary if I want to interactively define multilline words while the main game loop is running)
* I can write high-level coroutine-style scripts, like dialogue trees, very easily, which is the whole reason I wanted an interpreted language for my game in the first place

I haven't quite actually hooked up the serial port REPL, but I also refactored key/emit so that I could do so without that code becoming even more spaghetti mess than it was

and let me tell you, introducing new bugs in how i/o works in forth is not super fun to debug

That refactoring was also the first time I added the possibility of having forp code that called C code that called forp code and I'm pretty sure there's still a couple of ugly bugs with that

One thing that I'm definitely noticing is that defining everything as words and defining most context as implicit means you have a LOT of leverage in changing the implementation of things.

Before I implemented multitasking, "STATE" (meaning "should the interpreter loop act as a compiler or an interpreter") was a global C variable. I tweaked it to be stored in the task-specific "user data" area of memory, parameterized by the currently-running task, and no code that used it had to know.

So, the more you define a domain-specific vocabulary, the less locked-in to implementation decisions you become - and forth forces you to define a domain-specific vocabulary much more quickly than most other languages, if you want to have a hope of understanding and changing your code

Show newer

@SpindleyQ Have you used forth before? It's like programming in assembly on a CPU designed by an alien. It'll be a long learning curve before it's a workflow improvement on writing x86 asm directly.

Like, obviously you're doing a lot of things the hard way on purpose right now. But know what you're getting into!

It's quicker to write but much longer to read for sure. I say go for it either way, it's a very interesting language

@mogwai_poet oh yeah, I got deeeeep into trying to figure out Forth in my early twenties. Part of what makes it so attractive right now, as part of this project, is that I didn't _quite_ have the chops to build my own back then. _Everything_ I'm doing for this game is like that.

I think there's a reasonable tiny subset I can build quickly that'll be worth the trouble; I'm not out to build an OS out of it or anything.

@SpindleyQ I'm planning to port a C-Forth to 286.

Possible candidates I'm looking at:



WIll your Forth be available as well?

@cstrotm I haven't thought too much about distribution yet, but the reason my Forth exists is basically because I wanted to try writing a Forth, and it is likely to be extremely feature-poor, idiosyncratic, and poorly-architected. Literally threw this together in a few hours, still not sure how to write IF.

But it might show up in a public git repo someday, sure

@SpindleyQ I would be interested to have a look once it is usable.

Which C-Compiler are you using?

@cstrotm I believe it's Turbo C++ 1.01 with TASM 2, but I honestly forget exact versions. 1990-era Borland, anyway. Not using C++.

It's an indirect threaded interpreter, using bradrodriguez.com/papers/movin as a reference, with pointers to standard C functions in the code field. I want to use an external return stack rather than the C stack so that I can have tail calls & easily suspend computations (specifically when fetching the next input character) but right now it's a weird buggy mix of both.

@SpindleyQ I'm planning to use the new 16bit backend of GCC


Turbo-C is good for old code or for writing new code for old machines, but for porting existing code or creating portable code GCC might be easier (my hope).

4th thebeez.home.xs4all.nl/4tH/
does an incredible job of being portable from old Turbo-C to current C-Compiler. But I'm not a C language expert enough to reach the same level of portability.

@cstrotm Is there any documentation for that backend? Curious to know what the memory models are & how / if they handle far pointers.

AFAIK Turbo C is ANSI-compliant - I've read that you can build fairly recent versions of Lua with it.

excellent #retrocomputing thread on writing a #forth using 1990's era #Borland C for purposes of game scriptification!

all it needs is a few hashtags

thanks to @elb for sharing.


Sign in to participate in the conversation

The original server operated by the Mastodon gGmbH non-profit