mikaelpatel/Arduino-Shell

Enhance: Named functions

dpharris opened this issue · 17 comments

One example showed defining a function, and then it being used as a macro. Perhaps one could have named blocks and activate them with : as an escape character.
Eg:
{rot swap over swap > swap rot < or not};W
10 5 100 :W.
Script:
{rsos>sr<|~};W10,5,100:W.-10,5,100:W.110,5,100:W.

Obviously this impacts memory etc etc and may have complications and unintended consequencies.

I actually plan to add something just like that but with full names. Was thinking of a twist on the Postscript syntax.

{ block }\foo
_foo

But this is basically what you are suggesting. Nice to see that you have already caught on how this tiny script language works!

{rsos>sr<|~}\within
10,5,100_within

This has a dependency to storing scripts in PROGMEM or EEMEM.

Yes, I like your plan to use PS syntax. I was trying to maintain the small footprint of the scripts by using songle chars - but your plan doesn't limit that.

I started to modify your code so that I could define functions by storing the block-address in a variable.

Then I realized that you already have this!!! Its documented in the Variable section.

c{12.}2!,,2@x,,5{2@x}l

clear { 12 print } 2! 5 { 2@x } loop

works, too.

First steps towards named functions; copy code block to heap. Please see commit c3a61b1.

New format for allocating a code block. \ gets the length of the block, a copies the block to the heap and pushes the new block address.

 { code-block }\a      -- allocate on heap
 { code-block}\a0!     -- assign variable with allocated block address
 0@x                   -- read variable and execute block

Why did you add \and a, rather than a single operator?

It is a symmetry thing :). \ being an outer interpreter function and a an inner.

alloc ( buf1 len -- buf2 )
free (buf -- )

But things will change along the road. Need to work with it a while to see what "feels natural" and gives a good flow.

Alloc and free may soon be removed when introducing a traditional forth here and alloc. The variable table and the stack would become the top and bottom of a memory area for the shell. The input buffer could be at here. In that case there is no need for a copy. Simply moving dp dictionary pointer will be sufficient. This is actually one of the reasons for changing the stack direction (in the latest commits).

OK. I do like the 'ultimate simplicity' of Arduino-Shell so far. Adding
extras in may ruin that .. but I respect your long association with forth,
so you will have a better feel for it.
You are planning to include function names inline? This keeps the whole
thing in a set part of memory.

On Sun, Feb 28, 2016 at 12:00 PM, Mikael Patel notifications@github.com
wrote:

It is a symmetry thing :). \ being an outer interpreter function and a an
inner.

alloc ( buf1 len -- buf2 )
free (buf -- )

But things will change along the road. Need to work with it a while to see
what "feels natural" and gives a good flow.

Alloc and free may soon be removed when introducing a traditional forth
here and alloc. The variable table and the stack would become the top and
bottom of a memory area for the shell. The input buffer could be at here.
In that case there is no need for a copy. Simply moving dp dictionary
pointer will be sufficient. This is actually one of the reasons for
changing the stack direction (in the latest commits).


Reply to this email directly or view it on GitHub
#15 (comment)
.

Reopening this issue as it is soon time to implement. Current proposed design and syntax for named functions is:

:name code-block; 
\name

This is more of less the forth style but with an explicit call operator "". This would replace the block allocate/deallocate.

The ":" operator would add the "name" to a dictionary and copy the code block until ";". The "" is run-time lookup and execute of the "name". To make this even more interesting the "name" is associated with a variable and given the type code-block. This will give an internal mechanism much like forth "create-does>".

Of the top:
Is this copying to dict space?
Do you need ; if you have {}? You could have {...}:name!
Is \name a reference? So \name@x?
I guess f becomes forget: \name f

Yes, and no. It has to do with how much logic is behind the "\name". In forth this depends on the type of name; colon, variable, constant and create-does> to generalize this. The dict space is often just a linear address space, and "forget" steps back the allocation point.

The construct ":name" is a nice postfix notation and might work well with the control structures. My concern is the state of the parse.

In my original proposal "\name" is a lookup and execute. "\name@" implies that "\name" is actually a lookup and push of an address in the variable vector. In that case the block allocate and deallocate are still needed.

The ":name code-block;" does away with all that.

So, :fnc ... ; and \fnc and reclaim \ and a. Sounds good.
Works for naming everything:

  • variables: :nitems 12; and \nitems.
  • vectors: :event0 [12 34 45 56 67 78];
    I like it.

Please consider calling a trap on failure of the Shell to find a matching dict entry. This would allow quite easy extensions with useful names.
\sqrt \spi

Please also consider allowing any characters in a function name, as this would allow:

  • [] " *+
    This would probably require white-space after the name definition and use.

First version up and running. A small step forward.

{ code-block };\fun!
\fun@x
\fun:

10 \x !
\x @ 

Names are only alpha characters (for now).

Boy, you are a moving target :-) (I discovered t-->Z, c -->C, S)
Here is SHOW '{v{uXv 1+ uX0#}w'}vm using my X trap.
I defined \add and 0 as functions, and discovered that the names assign in order to the vars. I think that is ok.

Perhaps a different 'address-space' would be better, but I will have to play with it a bit. Might work very well in my application, since I plan to have multiple scripts, one for each event, and each of those will want to have parameters. Now I can name them, which will make life easier for the users.

Boy, you are a moving target

Yepp, it is all about refactoring.

BW: c@, <c@ and c! will enter the word list with other string functions when things start to be more stable. The printable ASCII characters are almost covered. Some logical changes remain. I was reserving uppercase characters for the Arduino function but now it also included typical extensions such as C(lear), T(race toggle) and S(tack dump). Also I need to add a level of configuration so that the instructions can be add/removed depending on the applications.

For most users the address of the variables/functions is not really of interest. Also in contrast to forth the dictionary is searched from first entry to last (latest). And there is only one entry per name.

There is a simple transformation from \name to variable address which gives possible compression. The block scan is an issue for large blocks (as discussed before). There are a few possible optimizations; 1) cache resolved addresses (end of block), 2) replace "{" with offset (it is always forward and there are 128 8-bit values available for that, i.e. replace "{" with 0x80+offset).

Hmmm -- the simplicity may be fading. At the moment I am impressed that
the ascii script = tokens.

If you exchange a '{' with a 0x80+offset, then the script is no longer
simple ascii (although easy to replace >0x7F with '{', I suppose, when
displaying).

Agree, the use of variable 0-n is useful, if compression is required.

I kind of liked your idea of (forth-like) :fnc ... ; and \fnc executing
immediately. One can always use 0@, 0@x and 0! if one wants to mess with
the script.

My + + forms are problematic somewhat, as they would require what-space
to distinguish them. One could include ',' in the white-space category, so
something like [2 3 4 5 6] {
} \f+,. , where \f+ takes an block, applies
to each item and sums the result.

I expect you have a gameplay, and probably too complicated to explain ... I
will just follow along :-)

Great work.