Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'Register'-like variable push & pop #1

Open
mcspr opened this issue Feb 19, 2020 · 2 comments
Open

'Register'-like variable push & pop #1

mcspr opened this issue Feb 19, 2020 · 2 comments

Comments

@mcspr
Copy link

mcspr commented Feb 19, 2020

While it is possible to register variable externally via rpn_variable_set(), it is not possible to store some stack variable or retrieve it later.

Possible syntax:
0 pusha -> $ra is now 0
popa -> $ra is now unset and 0 is on the stack
peeka -> $a is still set to 0, 0 is on the stack

@mcspr
Copy link
Author

mcspr commented Feb 22, 2020

Just to log some work-in-progress which I will document some time later
(possibly in the readme of the fork, or possibly a PR)
master...mcspr:objs

One register implementation is dc(1) from coreutils:
https://en.wikipedia.org/wiki/Dc_(computer_program)#Registers

dc provides at least 256 memory registers, each named by a single character. You can store a number or a string in a register and retrieve it later.

sr Pop the value off the top of the stack and store it into register r.
lr Copy the value in register r and push it onto the stack. The value 0 is retrieved if the register is uninitialized. This does not alter the contents of r.

Each register also contains its own stack. The current register value is the top of the register's stack.

Which is a nice and all, but now we have two storage places for almost the same thing.
Instead, since we already have variable concept, I slightly reworked stack variable and helpers to allow to store arbitrary (within some made-up limits) value and allow to back-reference variables.

struct rpn_value is replacing raw float as value, implementing bare-bones variant type through union { int32_t, uint32_t, double, char* }. Now it is a null-able type (idk, maybe there is some other way to do this without null).
struct rpn_variable stores a reference to the rpn_value
struct rpn_stack_value always stores rpn_value and optionally rpn_variable. This allows us to 'notice' variable use, and now it is possible to implement operators that can consume value and know that it came from a variable.

See runner.cpp for an example, rpnlib_operators.cpp now has p operator for _rpn_debug function and = operator to assign variable some value from the stack:

> 15 p
15.000000
> $var p
null
> "hello world" $var = $var p
"hello world"

Code is mvp, runner binary is the only way I have tested it. There are printfs hidden in the rpnlib somewhere and the core implementation uses std::string instead of String since I haven't added testing mock here.

Another possible approach is to have separate stacks for each type and force operator to choose which one it wants. This may help avoid union / variant type of stuff.

@mcspr
Copy link
Author

mcspr commented Feb 28, 2020

This turned out in a bit more changes than I originally though. Which are almost done, published this as 0.4.0-pre1 at https://github.com/mcspr/rpnlib
(as idk whether to expect PR review here, given the rewrite's size)

Main things that I wanted:

  • strings in expressions as "...value...", strings in variables
  • boolean in expressions as true and false, simplify casts in operators
  • generalized math, implemented in core type instead of operators. operator instead forces the type it wants. edit: now, we can also do fun things like "hello" " world" + -> "hello world"
  • we can also supply double as fundamental type, since we keep string in the struct and won't really save any memory (besides maybe saving some computation times when dealing with large doubles)
  • fs_math is also supported

I though about adding unsigned to support bit-wise stuff, but not really sure if it is really needed.

There are some subtle bugs (like "1 2 3 4 is parsed as string 1 2 3 4), still, but mostly things are working. I haven't done any proper real device tests yet, but I've built a small local testing script through CMakeLists.txt and all piotest tests pass. It is not pio test, as the test framework is closely bound to the Core version and we can't exactly have an exported library (at least not yet). At this point I will look into improving test coverage of operators and parsing.
When building:

$ cmake ../ -DESP8266=~/.platformio/packages/frameworkd-arduinoespressif8266 -DUNITY=~/.platformio/packages/tool-unity
$ cmake --build .

./runner will call simple repl. this is wip, as i still need to tweak some debugging output
./piotest will call the binary produced from the test/piotest/main.cpp built with the ESP8266 Core testing framework.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant