MitchBradley/cforth

How to make extension word?

Closed this issue · 10 comments

I have a function defined like this, LVGL active root screen

static lv_obj_t * lv_scr_act(void);

I tried adding it into ccall, but that doesn't work.

cell ((* const ccalls[])()) = {
	C(lv_scr_act)		//c lv-scr-act		{-- i.addr}
	C(build_date_adr)       //c 'build-date     { -- a.value }

I want it to put that pointer onto the stack.

ok lv_scr_act

lv_scr_act ?
Error at: lv_scr_act |  

Aborted
ok lv-scr-act

lv-scr-act ?
Error at: lv-scr-act |  

Aborted
ok 

So it needs to get into dict.h and rodict.c somehow. I will go figure that out.

This should be equivalent to the makeccalls program:

 grep -oP "\/\/c\K.*" extend.c | nl -v 0 -w1 | sed  's/\(^\S*\)/#\1 ccall:/'

Not sure if cforth can be an Espressif component, their components don't appear to have any concept of compiling host tools and I need makebi. I can add the tools to my own app, but I not sure if component is possible.

quozl commented

On your original problem on this issue, sorry, don't know what's wrong, but this is what I do;

  • add the new function somewhere,
  • add the new word to extend.c, in the ccalls structure,
  • re-run the build, e.g. make,
  • check that ccalls.fth was regenerated (by makeccalls),
  • check that app.dic was regenerated (by ./forth forth.dic ccalls.fth app.fth),
  • check that the word is in the dictionary.

I agree that a build system that does not allow execution of host tools won't work easily with the way CForth does build. I had to overcome this to get the PlatformIO build working.

The original problem was that I was unaware those comments were being processed into code. The issue with host tools is that these build systems are cross platform -- Linux, Mac and Windows. For right now I'll just copy the needed binaries into the build of my app.

An alternative solution to processing comments is to use the C++ pre-processor to construct a syntax (app stays C, just use the pre-processor).

If you can figure out a way to do it with the preprocessor, go for it. Make sure that it works with both GCC and Clang.

For a long time I have wanted to abstract the implementation of a wordlist, so that the ccalls could be in a separate wordlist, with an implementation that could be compiled directly into the target dictionary from C code. Each ccall would be defined with a struct that has the C symbol, the stack specification, and the name.

But that would not completely solve the problem, it would just push it around. The fundamental problem is the creation of the builtin dictionary. If you want the application dictionary image to include Forth application words that invoke ccall words, then the host forth needs to have the same ccalls wordlist. That could be done by compiling the host forth with the ccall definitions, ignoring the C symbol portion. But that still does not solve the IDF component problem. You still have to execute a host program, namely the host Forth. Once you figure out how to do that in the context of the build system, you can probably use the same mechanism to execute other host programs.

I can call ./forth (and others) in my app build system since I know I am on Linux and can pre-compile. Not sure how to do that if cforth is an Espressif component, so I will skip the component bit for now. So first I will get things working in a system similar to the one you are using, then I can look at possible changes. I do see that Jos has defined quite a few more ESP APIs in the WIP branch.

Looking at your tree, extend.c doesn't have to be built by your make system, right? It could be added to build/esp32/sdk_build/main/component.mk and be built that way instead. It would still be processed by makeccalls. If it is built by the espressif build system then it can include ESP headers removing the need to redeclare everything in interface.h

Or maybe I should just go with the flow and and redeclare everything? Do you end up having to rewrite most calls to make them forth compatible?

To the extent that extend.c interfaces to the rest of forth.o via only the ccalls array, it indeed might make sense to build it in espressif land. There could be an issue with callback_up but maybe there is a better way to handle that, perhaps by passing it it in to an alarm_init routine or something.

Do you end up having to rewrite most calls to make them forth compatible?

I wouldn't say "most", but then I have never really counted. I am certainly often tempted to make easier-to-use interfaces to system functions that are very low-level and picky.