zevv / zForth

zForth: tiny, embeddable, flexible, compact Forth scripting language for embedded systems
MIT License
350 stars 47 forks source link

Loop iterator "j" #3

Closed PolyVinalDistillate closed 6 years ago

PolyVinalDistillate commented 7 years ago

Hello zevv,

I recently forked your Forth to a minimal, self-contained PSoC 5 / USBUART test project with which I was learning Forth and testing its viability for use in a scary monster project I've been working on. It will effectively be taking the place of php, linked into all sorts of C helper functions, for a PSoC webserver as well as providing some low-level interfacing to an automation system.

During tests, I believe I've found an error in your "j" word. When I execute the following:

: CRLF 10 13 emit emit ; : ts 10 0 do 10 0 do 42 i + j + emit loop CRLF loop ; ts

j does not increment, as can be seen by the following output:

456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=> 456789:;<=>

edit: Also note that the output doesn't begin with '*'!

Modifying the definition of j to: : j ' lit , 2 , ' pickr , ; immediate fixes the issue.

There's an outside chance that I introduced an error when I hacked-in a modification to your code to avoid getting stuck in zf_eval() during a forth loop, but I'm almost 100 % certain forth code still executes correctly. I've not run into any other oddities while I've been developing my forth skills!

Sadly, I'm still slightly confuddled trying to understand how the do/loop words operate, so I can't entirely trust my judgement as to whether j is incorrectly defined or not.

I'll be looking to see if j operates as intended in your implementation, because if it does it implies I have problems with my modifications!

Cheers, Nick.

zevv commented 7 years ago

Hi Nick,

Quoting Nick (2017-06-16 07:11:17)

Hello zevv,

I recently forked your Forth to a minimal, self-contained PSoC 5 / USBUART test project with which I was learning Forth and testing its viability for use in a scary monster project I've been working on. It will effectively be taking the place of php, linked into all sorts of C helper functions, for a PSoC webserver as well as providing some low-level interfacing to an automation system.

Are you sure Forth is the right tool here, let alone a toy-forth implementation like zForth? Even I don't use it in production :) (You might want to take a look at Lua: pretty small, very neat and flexible language, with very smooth integration to C code)

: CRLF 10 13 emit emit ; : ts 10 0 do 10 0 do 42 i + j + emit loop CRLF loop ; ts

I'll have a look, but I must admit I haven't actually been doing any forth since I 'finished' the implementation a few years ago.

Sadly, I'm still slightly confuddled trying to understand how the do/loop words operate, so I can't entirely trust my judgement as to whether j is incorrectly defined or not.

It all starts with 'Starting Forth' by Brodie. It feels like a childrens' book, but it's still a good source for grokking the inner workings of the Forth universe.

-- :wq ^X^Cy^K^X^C^C^C^C

PolyVinalDistillate commented 7 years ago

Hello,

I appreciate your suggestion, however zForth seems to be pretty much perfect for my requirements - I did a fair bit of hunting around before I settled on it, and decided that with its tiny memory requirements and powerful extensibility it fits my application nicely. I'll admit I'm new to the world of embedded scripting so I can't guarantee it's the best choice available but its strengths from my point of view (in no particular order of importance) are:

I have about 4 K of RAM available and could stretch to 8 at an absolute maximum. I also have limited ROM. The system has 256 K, but I need to reserve as much of that as possible for embedding HTML/Javascript files. The zForth footprint is sufficiently small that it's perfect for this environment without sacrificing the various language constructs I need to implement the automation side of the project. It also proved relatively easy to wrap in an ISR to perform execution completely transparently to the rest of the codebase, allowing me to effectively sandbox it from the rest of the environment. Execution speed isn't too important, so breaking the execution into little chunks performed on 100 us intervals works well without blocking other system functions. Effectively I'm implementing a poor-man's RTOS with zForth as one of the tasks.

Its link with the webserver side of things is basically just to provide a user interface for sytem control - typically form descriptions transferred as AJAX requests - Forth constructs a form with all the required user input via functions mapped to C. C sends it on the next AJAX request, Browser sends response when user submits form, Forth detects the response from within a loop by calling a C function, finally Forth extracts relevant data from the response via C function calls and continues executing the high-level automation based on user input. The actual automation tasks can be flowcharted on a sheet of A3 paper, so it's not expected to run massive programs.

In fact, what I've come to question is whether I could have saved myself a lot of time by writing a frontend for the PC in C++ instead of implementing a web-based interface. HTML and Javascript was not designed with limited memory in mind.. and that's to say nothing of HTTP... These have been my major headaches, and zForth has been a comparative walk in the park!

As to "Starting Forth", I've read most of that twice now, but certain concepts still haven't quite gelled. I've not managed to quite wrap my head around exactly what "immediate" and "postpone" are doing - I'm tantilisingly close, but no further! I wrote a rudimentary printf to get to grips with Forth, but managed to keep my distance from these keywords!

So all in all, "Toy" Forth is perfect. If I had the time I'd probably re-implement it to make better use of the Cortex M3 hardware to streamline it (and I suspect in the future I will do just that), but having discovered Forth I'm of the opinion that alternative scripting languages pretty much just add lots of icing without adding better basic capabilities.

kiryam commented 7 years ago

I fully agree with @PolyVinalDistillate about, size, memory, and I also been super happy, after found that library. I also try to understand postpone and literal (tick) Also I done reading "Thinking Forth" by Leo Brodie. nice book, but it is not about implementation.

zevv commented 7 years ago

Quoting Nick (2017-06-16 10:59:50)

I appreciate your suggestion, however zForth seems to be pretty much perfect for my requirements - I did a fair bit of hunting around before I settled on it, and decided that with its tiny memory requirements and powerful extensibility it fits my application nicely.

My original goal was to use it as an scripting language in a few-kb-sized embedded system as well. It has since been implemented and shipped, but it just sits there without being used.

  • The smiles it brings to the faces of colleagues as they remember doing Forth courses when I was about 3.

That's a huge pro. You might be interested one of my other side projects, an IBM Model-M buckle spring keyboard sound simulator, which comes from about the same are as Forth :0

  • Affinity with assembly language which will remain my favourite form of coding for all time since the Z80.

One of my goals of zForth was exactly the opposite: a lot of forth implementations are made in assembly. One part of me still loves doing asm, but the other part loathes this. Hard to maintain, not at all portable. There is basically no use for something as simple as zForth, the C implementation is very small and low-level as it is now, and runs on about any existing platform with a C compiler - which is a nice thing.

I have about 4 K of RAM available and could stretch to 8 at an absolute maximum. I also have limited ROM. The system has 256 K, but I need to reserve as much of that as possible for embedding HTML/Javascript files.

No Lua here fore sure.

on the next AJAX request, Browser sends response when user submits form, Forth detects the response from within a loop by calling a C function, finally Forth extracts relevant data from the response via C function calls and continues executing the high-level automation based on user input.

That's pretty cool, Forth meets Web2.0!

As to "Starting Forth", I've read most of that twice now, but certain concepts still haven't quite gelled.

It was the same with me: in the beginning it all feels quite alien. Then there's the moment you realise the whole thing is built on only a few tiny primitives, and for the rest it is turtles all the way down: Forth is mostly written in Forth!

The common solution for the problem of not-quite-understanding-all-of-it is to make your own Forth implementation - of which zForth is the result.

So all in all, "Toy" Forth is perfect. If I had the time I'd probably re-implement it to make better use of the Cortex M3 hardware to streamline it (and I suspect in the future I will do just that),

I wonder where you'll be able to make speedups. The main execution loop is pretty optimal as the big switch in do_prim() is usually compiled into a jump table. Keep me informed!

having discovered Forth I'm of the opinion that alternative scripting languages pretty much just add lots of icing without adding better basic capabilities.

Glad to hear! Ask your boss to send me a nice bottle of Whisky if it all works out for you :)

-- :wq ^X^Cy^K^X^C^C^C^C

PolyVinalDistillate commented 7 years ago

My original goal was to use it as an scripting language in a few-kb-sized embedded system as well. It has since been implemented and shipped, but it just sits there without being used.

It'll probably sit in my system mostly invisible too.. I'm in charge of the control system side of the project and my colleague is taking care of the mechanical side. The problem is that I can't be sure of exactly how the system will be implemented until it's wired up and operational, so some scripting capability seemed the best way to cover all possible use cases and configure the system on-site.

That's a huge pro. You might be interested one of my other side projects, an IBM Model-M buckle spring keyboard sound simulator, which comes from about the same are as Forth :0

Funny you should mention that - I saw that project on your github and it amused me :D I actually have a couple of original buckling spring keyboards kicking about - the problem is that the plastic degraded and the enter buttons started jamming! I eventually bought some modern equivalents from Unicomp - they use the same design, but they're pretty expensive. The "Windows" key takes away from the originality a little.. I remember having to press Ctrl+Esc when I first got Win 95 up.

One of my goals of zForth was exactly the opposite: a lot of forth implementations are made in assembly. One part of me still loves doing asm, but the other part loathes this. Hard to maintain, not at all portable. There is basically no use for something as simple as zForth, the C implementation is very small and low-level as it is now, and runs on about any existing platform with a C compiler - which is a nice thing.

When I say affinity, I don't mean how it's implemented so much as how it's used. The primitives are very reminiscent of ASM :)

I wonder where you'll be able to make speedups. The main execution loop is pretty optimal as the big switch in do_prim() is usually compiled into a jump table. Keep me informed!

I'd sacrifice the portability in the process, but I was considering implementing the main primitives in inline assembly, making use of the M3 stack hardware and the likes. Possibly implementing my own Forth based on what I've seen of yours entirely in assembly. But that will have to wait until I actually have the time for it!

Glad to hear! Ask your boss to send me a nice bottle of Whisky if it all works out for you :)

It's almost like you know I'm based in Scotland! Did I put that in my profile? :o I think the bottle will come from me, as I don't have a boss as such for this project! What's your poison? :D

zevv commented 7 years ago

Quoting Nick (2017-06-16 20:35:18)

It'll probably sit in my system mostly invisible too.. I'm in charge of the control system side of the project and my colleague is taking care of the mechanical side. The problem is that I can't be sure of exactly how the system will be implemented until it's wired up and operational, so some scripting capability seemed the best way to cover all possible use cases and configure the system on-site.

Exactly my reason for the initial implementation. I did have some nice use of the scripting during initial setup and debugging. Especially providing raw memory access is powerful, as it allows you to control hardware through register access.

Funny you should mention that - I saw that project on your github and it amused me :D I actually have a couple of original buckling spring keyboards kicking about - the problem is that the plastic degraded and the enter buttons started jamming! I eventually bought some modern equivalents from Unicomp - they use the same design, but they're pretty expensive.

I looked into those, but then I found an original Model M still in its original box, a variant without numpad. I built in a USB <-> PS/2 converter, and it's still going strong!

One of my goals of zForth was exactly the opposite: a lot of forth implementations are made in assembly. One part of me still loves doing asm, but the other part loathes this. Hard to maintain, not at all portable. There is basically no use for something as simple as zForth, the C implementation is very small and low-level as it is now, and runs on about any existing platform with a C compiler - which is a nice thing.

When I say affinity, I don't mean how it's implemented so much as how it's used. The primitives are very reminiscent of ASM :)

That's the fun part. If you're serious about implementing your own, and if you want to understand everything under the hood, this is a great read:

https://github.com/AlexandreAbreu/jonesforth

Start at

https://github.com/AlexandreAbreu/jonesforth/blob/master/jonesforth.S

In literate programming style the basic building blocks for a Forth are brought in and jolted down on the fly in small assembly snippets. Everything just fits together nicely, and at once poof control is passed to actual Forth code, running in the compiler/interpreter that was just written. It's a great journey for a rainy sunday afternoon!

Glad to hear! Ask your boss to send me a nice bottle of Whisky if it all works out for you :)

It's almost like you know I'm based in Scotland! Did I put that in my profile? :o I think the bottle will come from me, as I don't have a boss as such for this project!

Well, I figured you must be from this part of the planet because of your timezone, and you're probably a native english speaker, but I didn't give it any thought in relation to any local brews :)

What's your poison? :D

Finish your project first, we'll talk booze when you're all done!

-- :wq ^X^Cy^K^X^C^C^C^C

zevv commented 6 years ago

Hey Nick,

Just looking through the issue list to see what's still relevant and what's not. Did everything work out for you in the end?

PolyVinalDistillate commented 6 years ago

Hello, I had to drop the project for several months due to an excessively heavy teaching schedule! Plan to return to it fairly soon now though. I still believe you have an issue in your definition of "j" in core.zf. I have the core definitions hard-coded as a string in my code, and have defined "j" with: : j ' lit , 2 , ' pickr , ; immediate rather than : j ' lit , 3 , ' pickr , ; immediate This works for me in both my main implementation and the test implementation that runs only zforth.

zevv commented 6 years ago

Yeah, that's funny, you're absolutely right. I was using I and J myself like this:

: cols 4 1 do j i * . loop cr ; 
: rows 4 1 do cols loop ;

in which case it works just fine - with the extra call, that is.

My implementation is wrong however when doing stuff like

: table  cr 11 1 do
            11 1 do  i j * .  loop
         cr loop ;

So I guess I will have to fix my J, and any of my own programs depending on it.