mikaelpatel / Arduino-Shell

RPN Postscript/Forth Command Shell for Arduino
19 stars 5 forks source link

Enhance: Named functions #15

Closed dpharris closed 8 years ago

dpharris commented 8 years ago

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.

mikaelpatel commented 8 years ago

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.

dpharris commented 8 years ago

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.

dpharris commented 8 years ago

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.

mikaelpatel commented 8 years ago

First steps towards named functions; copy code block to heap. Please see commit https://github.com/mikaelpatel/Arduino-Shell/commit/c3a61b11391956684f26006c141bf54d91023800.

mikaelpatel commented 8 years ago

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
dpharris commented 8 years ago

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

mikaelpatel commented 8 years ago

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).

dpharris commented 8 years ago

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 https://github.com/mikaelpatel/Arduino-Shell/issues/15#issuecomment-189935254 .

mikaelpatel commented 8 years ago

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>".

dpharris commented 8 years ago

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

mikaelpatel commented 8 years ago

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.

dpharris commented 8 years ago

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

dpharris commented 8 years ago

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:

mikaelpatel commented 8 years ago

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).

dpharris commented 8 years ago

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.

mikaelpatel commented 8 years ago

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).

dpharris commented 8 years ago

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.