mirror of
https://github.com/eledio-devices/thirdparty-tinyexpr.git
synced 2025-10-30 16:15:41 +01:00
Refactored docs.
This commit is contained in:
177
README.md
177
README.md
@@ -26,30 +26,91 @@ Here is a minimal example to evaluate an expression at runtime.
|
|||||||
|
|
||||||
```C
|
```C
|
||||||
#include "tinyexpr.h"
|
#include "tinyexpr.h"
|
||||||
#include <stdio.h>
|
printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
const char *c = "sqrt(5^2+7^2+11^2+(8-2)^2)";
|
|
||||||
double r = te_interp(c, 0);
|
|
||||||
printf("The expression:\n\t%s\nevaluates to:\n\t%f\n", c, r);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
That produces the following output:
|
##Usage
|
||||||
|
|
||||||
The expression:
|
TINYEXPR defines only four functions:
|
||||||
sqrt(5^2+7^2+11^2+(8-2)^2)
|
|
||||||
evaluates to:
|
|
||||||
15.198684
|
|
||||||
|
|
||||||
|
```C
|
||||||
|
double te_interp(const char *expression, int *error);
|
||||||
|
te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error);
|
||||||
|
double te_eval(const te_expr *n);
|
||||||
|
void te_free(te_expr *n);
|
||||||
|
```
|
||||||
|
|
||||||
|
##te_interp
|
||||||
|
```C
|
||||||
|
double te_interp(const char *expression, int *error);
|
||||||
|
```
|
||||||
|
|
||||||
|
`te_interp()` takes an expression and immediately returns the result of it. If there
|
||||||
|
is a parse error, `te_interp()` returns NaN.
|
||||||
|
|
||||||
|
If the `error` pointer argument is not 0, then `te_interp()` will set `*error` to the position
|
||||||
|
of the parse error on failure, and set `*error` to 0 on success.
|
||||||
|
|
||||||
|
**example usage:**
|
||||||
|
|
||||||
|
```C
|
||||||
|
int error;
|
||||||
|
|
||||||
|
double a = te_interp("(5+5)", 0); /* Returns 10. */
|
||||||
|
double a = te_interp("(5+5)", &error); /* Returns 10, error is set to 0. */
|
||||||
|
double b = te_interp("(5+5", &error); /* Returns NaN, error is set to 4. */
|
||||||
|
```
|
||||||
|
|
||||||
|
##te_compile, te_eval, te_free
|
||||||
|
```C
|
||||||
|
te_expr *te_compile(const char *expression, const te_variable *lookup, int lookup_len, int *error);
|
||||||
|
double te_eval(const te_expr *n);
|
||||||
|
void te_free(te_expr *n);
|
||||||
|
```
|
||||||
|
|
||||||
|
Give `te_compile()` an expression with unbound variables and a list of
|
||||||
|
variable names and pointers. `te_compile()` will return a `te_expr*` which can
|
||||||
|
be evaluated later using `te_eval()`. On failure, `te_compile()` will return 0
|
||||||
|
and optionally set the passed in `*error` to the location of the parse error.
|
||||||
|
|
||||||
|
You may also compile expressions without variables by passing `te_compile()`'s second
|
||||||
|
and thrid arguments as 0.
|
||||||
|
|
||||||
|
Give `te_eval()` a `te_expr*` from `te_compile()`. `te_eval()` will evaluate the expression
|
||||||
|
using the current variable values.
|
||||||
|
|
||||||
|
After you're finished, make sure to call `te_free()`.
|
||||||
|
|
||||||
|
**example usage:**
|
||||||
|
|
||||||
|
```C
|
||||||
|
double x, y;
|
||||||
|
/* Store variable names and pointers. */
|
||||||
|
te_variable vars[] = {{"x", &x}, {"y", &y}};
|
||||||
|
|
||||||
|
int err;
|
||||||
|
/* Compile the expression with variables. */
|
||||||
|
te_expr *expr = te_compile("sqrt(x^2+y^2)", vars, 2, &err);
|
||||||
|
|
||||||
|
if (expr) {
|
||||||
|
x = 3; y = 4;
|
||||||
|
const double h1 = te_eval(expr); /* Returns 5. */
|
||||||
|
|
||||||
|
x = 5; y = 12;
|
||||||
|
const double h2 = te_eval(expr); /* Returns 13. */
|
||||||
|
|
||||||
|
te_free(expr);
|
||||||
|
} else {
|
||||||
|
printf("Parse error at %d\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
##Longer Example
|
##Longer Example
|
||||||
|
|
||||||
Here is an example that will evaluate an expression passed in from the command
|
Here is a complete example that will evaluate an expression passed in from the command
|
||||||
line. It also does error checking and binds the variables *x* and *y*.
|
line. It also does error checking and binds the variables `x` and `y` to *3* and *4*, respectively.
|
||||||
|
|
||||||
```C
|
```C
|
||||||
#include "tinyexpr.h"
|
#include "tinyexpr.h"
|
||||||
@@ -58,7 +119,7 @@ line. It also does error checking and binds the variables *x* and *y*.
|
|||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("Usage: example2 \"expression\"\n", argv[0]);
|
printf("Usage: example2 \"expression\"\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,21 +135,18 @@ line. It also does error checking and binds the variables *x* and *y*.
|
|||||||
int err;
|
int err;
|
||||||
te_expr *n = te_compile(expression, vars, 2, &err);
|
te_expr *n = te_compile(expression, vars, 2, &err);
|
||||||
|
|
||||||
if (!err) {
|
if (n) {
|
||||||
/* The variables can be changed here, and eval can be called as many
|
/* The variables can be changed here, and eval can be called as many
|
||||||
* times as you like. This is fairly efficient because the parsing has
|
* times as you like. This is fairly efficient because the parsing has
|
||||||
* already been done. */
|
* already been done. */
|
||||||
x = 3;
|
x = 3; y = 4;
|
||||||
y = 4;
|
const double r = te_eval(n); printf("Result:\n\t%f\n", r);
|
||||||
const double r = te_eval(n); printf("Result:\n\t%f\n", r); }
|
te_free(n);
|
||||||
else {
|
} else {
|
||||||
/* Show the user where the error is at. */
|
/* Show the user where the error is at. */
|
||||||
printf("\t%*s^\nError near here", err-1, "");
|
printf("\t%*s^\nError near here", err-1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* te_free is safe to call on null. */
|
|
||||||
te_free(n);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -110,75 +168,25 @@ This produces the output:
|
|||||||
5.000000
|
5.000000
|
||||||
|
|
||||||
|
|
||||||
##Usage
|
|
||||||
|
|
||||||
TINYEXPR defines only five functions:
|
|
||||||
|
|
||||||
```C
|
|
||||||
double te_interp(const char *expression, int *error);
|
|
||||||
te_expr *te_compile(const char *expression, const te_variable *lookup, int lookup_len, int *error);
|
|
||||||
double te_eval(const te_expr *n);
|
|
||||||
void te_print(const te_expr *n);
|
|
||||||
void te_free(te_expr *n);
|
|
||||||
```
|
|
||||||
|
|
||||||
**te_interp** takes an expression and immediately returns the result of it. If
|
|
||||||
an error pointer is passed in, *te_interp* will set it to 0 for success or
|
|
||||||
approximately the position of the error for failure. If you don't care about
|
|
||||||
errors, just pass in 0. *te_interp* will return NaN for bad expressions regardless.
|
|
||||||
|
|
||||||
**te_interp example:**
|
|
||||||
|
|
||||||
```C
|
|
||||||
double x = te_interp("5+5", 0);
|
|
||||||
```
|
|
||||||
|
|
||||||
**te_compile** will compile an expression with unbound variables, which will
|
|
||||||
be suitable to evaluate later. **te_eval** can then be called on the compiled
|
|
||||||
expression repeatedly to evaluate it with different variable values. **te_free**
|
|
||||||
should be called after you're finished.
|
|
||||||
|
|
||||||
**te_compile example:**
|
|
||||||
|
|
||||||
```C
|
|
||||||
double x, y;
|
|
||||||
te_variable vars[] = {{"x", &x}, {"y", &y}};
|
|
||||||
|
|
||||||
int err;
|
|
||||||
te_expr *expr = te_compile("sqrt(x^2+y^2)", vars, 2, &err);
|
|
||||||
|
|
||||||
if (!err) {
|
|
||||||
x = 3; y = 4;
|
|
||||||
const double h1 = te_eval(expr);
|
|
||||||
|
|
||||||
x = 5; y = 7;
|
|
||||||
const double h2 = te_eval(expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
te_free(expr);
|
|
||||||
```
|
|
||||||
|
|
||||||
**te_print** will display some (possibly not so) useful debugging
|
|
||||||
information about the return value of *te_compile*.
|
|
||||||
|
|
||||||
|
|
||||||
##How it works
|
##How it works
|
||||||
|
|
||||||
**te_compile** uses a simple recursive descent parser to compile your
|
`te_compile()` uses a simple recursive descent parser to compile your
|
||||||
expression into a syntax tree. For example, the expression "sin x + 1/4"
|
expression into a syntax tree. For example, the expression `"sin x + 1/4"`
|
||||||
parses as:
|
parses as:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**te_compile** also automatically prunes constant branches. In this example,
|
`te_compile()` also automatically prunes constant branches. In this example,
|
||||||
the compiled expression returned by *te_compile* is:
|
the compiled expression returned by `te_compile()` would become:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**te_eval** will automatically load in any variables by their pointer, then evaluate
|
`te_eval()` will automatically load in any variables by their pointer, and then evaluate
|
||||||
and return the result of the expression.
|
and return the result of the expression.
|
||||||
|
|
||||||
**te_free** should always be called when you're done with the compiled expression.
|
`te_free()` should always be called when you're done with the compiled expression.
|
||||||
|
|
||||||
|
|
||||||
##Speed
|
##Speed
|
||||||
@@ -186,11 +194,11 @@ and return the result of the expression.
|
|||||||
|
|
||||||
TINYEXPR is pretty fast compared to C when the expression is short, when the
|
TINYEXPR is pretty fast compared to C when the expression is short, when the
|
||||||
expression does hard calculations (e.g. exponentiation), and when some of the
|
expression does hard calculations (e.g. exponentiation), and when some of the
|
||||||
work can be simplified by *te_compile*. TINYEXPR is slow compared to C when the
|
work can be simplified by `te_compile()`. TINYEXPR is slow compared to C when the
|
||||||
expression is long and involves only basic arithmetic.
|
expression is long and involves only basic arithmetic.
|
||||||
|
|
||||||
Here is some example performance numbers taken from the included
|
Here is some example performance numbers taken from the included
|
||||||
*benchmark.c* program:
|
**benchmark.c** program:
|
||||||
|
|
||||||
| Expression | te_eval time | native C time | slowdown |
|
| Expression | te_eval time | native C time | slowdown |
|
||||||
| :------------- |-------------:| -----:|----:|
|
| :------------- |-------------:| -----:|----:|
|
||||||
@@ -235,9 +243,6 @@ In addition, the following C math functions are also supported:
|
|||||||
|
|
||||||
- All functions/types start with the letters *te*.
|
- All functions/types start with the letters *te*.
|
||||||
|
|
||||||
- If there is an error, you can usually still evaluate the first part of the
|
|
||||||
expression. This may or may not be useful to you.
|
|
||||||
|
|
||||||
- To allow constant optimization, surround constant expressions in parentheses.
|
- To allow constant optimization, surround constant expressions in parentheses.
|
||||||
For example "x+(1+5)" will evaluate the "(1+5)" expression at compile time and
|
For example "x+(1+5)" will evaluate the "(1+5)" expression at compile time and
|
||||||
compile the entire expression as "x+6", saving a runtime calculation. The
|
compile the entire expression as "x+6", saving a runtime calculation. The
|
||||||
|
|||||||
13
example2.c
13
example2.c
@@ -20,20 +20,19 @@ int main(int argc, char *argv[])
|
|||||||
int err;
|
int err;
|
||||||
te_expr *n = te_compile(expression, vars, 2, &err);
|
te_expr *n = te_compile(expression, vars, 2, &err);
|
||||||
|
|
||||||
if (!err) {
|
if (n) {
|
||||||
/* The variables can be changed here, and eval can be called as many
|
/* The variables can be changed here, and eval can be called as many
|
||||||
* times as you like. This is fairly efficient because the parsing has
|
* times as you like. This is fairly efficient because the parsing has
|
||||||
* already been done. */
|
* already been done. */
|
||||||
x = 3;
|
x = 3; y = 4;
|
||||||
y = 4;
|
const double r = te_eval(n); printf("Result:\n\t%f\n", r);
|
||||||
const double r = te_eval(n); printf("Result:\n\t%f\n", r); }
|
|
||||||
else {
|
te_free(n);
|
||||||
|
} else {
|
||||||
/* Show the user where the error is at. */
|
/* Show the user where the error is at. */
|
||||||
printf("\t%*s^\nError near here", err-1, "");
|
printf("\t%*s^\nError near here", err-1, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* te_free is safe to call on null. */
|
|
||||||
te_free(n);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user