4

I plan to do the following:

void setup(){
  String term = "12 + (2 * 5)";
  int result = eval(term); // eval function (from Python)
  Serial.println(result); // expecting 22
}

However there is no eval function. Are there any alternatives?

dda
  • 1,595
  • 1
  • 12
  • 17
loucket
  • 41
  • 1
  • 2

3 Answers3

5

TinyExpr does what you want, and more.

TinyExpr is a very small recursive descent parser and evaluation engine for math expressions. It's handy when you want to add the ability to evaluation math expressions at runtime without adding a bunch of cruft to you project.

In addition to the standard math operators and precedence, TinyExpr also supports the standard C math functions and runtime binding of variables.

Your example

You'd just need to save tinyexpr.h and tinyexpr.c next to your Sketch.

#include "tinyexpr.h"

void setup() { Serial.begin(115200); }

void loop() { char term[] = "12 + (2 * 5)"; Serial.println(term); int error; double result = te_interp(term, &error); if (error){ Serial.println("Problem with expression."); } else { Serial.printf(" = %.10g\n", result); } delay(1000); }

It outputs:

12 + (2 * 5)
 = 22

Since term is known at compile-time, this example is not very useful, and it simply outputs 22 in an endless loop.

Basic interactive console

If you use the input from Serial, you can write a very basic interactive console. A String has been used for conciseness, but this example could be rewritten with cstrings:

#include "tinyexpr.h"

void setup() { Serial.begin(115200); }

void loop() { if (Serial.available() > 0) { String expression = Serial.readStringUntil('\n'); Serial.print("> "); Serial.println(expression);

int error;
double result = te_interp(expression.c_str(), &error);

if (error) {
  Serial.print(" ");
  for (int i = 0; i < error; i++) {
    Serial.print(" ");
  }
  Serial.println("↑");
  Serial.println("I didn't understand this part.");
} else {
  Serial.printf(" = %.10g\n", result);
}

}

delay(50); }

TinyExpr knows the order of operations, and it understands many other mathematical expressions:

> 12 + 2 * 5
 = 22
> 3^5
 = 243
> exp(7)
 = 1096.633158
> (1 + sqrt(5)) / 2
 = 1.618033989
> 1 + 2 * 3 + 4 * 5
 = 27
> sin(pi/2)
 = 1
> sin(pi/3)
 = 0.8660254038

If there's a syntax error somewhere, error tells you the position of the first encountered error:

> 3 + 
      ↑
I didn't understand this part.
> sin() * 5
      ↑
I didn't understand this part.
> 3 / (4 + 5 * 7
                ↑
I didn't understand this part.
Eric Duminil
  • 149
  • 1
  • 4
1

No, there are no alternatives. You need to parse the string and perform the operations yourself.

Personally I prefer to use RPN since it is so much easier to parse. Your string could be re-written then as:

2,5,*,12,+

Tokenise on , and look to see if it's a number (push on a stack) or an operator (pop operands off stack, do operation, push result on stack).

Majenko
  • 105,851
  • 5
  • 82
  • 139
0

I Googled and the news isn't good. There isn't an off the shelf function that does this in C/C++. There are plenty of links to algorithms that you could implement. But would you have the memory to do it on an Arduino?

So, looking at the problem for a different perspective why don't you run python on the Arduino? There is a version called pymite which runs on a mega.

Code Gorilla
  • 5,652
  • 1
  • 17
  • 31