1[![Build Status](https://travis-ci.org/codeplea/tinyexpr.svg?branch=master)](https://travis-ci.org/codeplea/tinyexpr) 2 3 4<img alt="TinyExpr logo" src="https://codeplea.com/public/content/tinyexpr_logo.png" align="right"/> 5 6# TinyExpr 7 8TinyExpr is a very small recursive descent parser and evaluation engine for 9math expressions. It's handy when you want to add the ability to evaluation 10math expressions at runtime without adding a bunch of cruft to you project. 11 12In addition to the standard math operators and precedence, TinyExpr also supports 13the standard C math functions and runtime binding of variables. 14 15## Features 16 17- **ANSI C with no dependencies**. 18- Single source file and header file. 19- Simple and fast. 20- Implements standard operators precedence. 21- Exposes standard C math functions (sin, sqrt, ln, etc.). 22- Can add custom functions and variables easily. 23- Can bind variables at eval-time. 24- Released under the zlib license - free for nearly any use. 25- Easy to use and integrate with your code 26- Thread-safe, provided that your *malloc* is. 27 28## Building 29 30TinyExpr is self-contained in two files: `tinyexpr.c` and `tinyexpr.h`. To use 31TinyExpr, simply add those two files to your project. 32 33## Short Example 34 35Here is a minimal example to evaluate an expression at runtime. 36 37```C 38 #include "tinyexpr.h" 39 printf("%f\n", te_interp("5*5", 0)); /* Prints 25. */ 40``` 41 42 43## Usage 44 45TinyExpr defines only four functions: 46 47```C 48 double te_interp(const char *expression, int *error); 49 te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error); 50 double te_eval(const te_expr *expr); 51 void te_free(te_expr *expr); 52``` 53 54## te_interp 55```C 56 double te_interp(const char *expression, int *error); 57``` 58 59`te_interp()` takes an expression and immediately returns the result of it. If there 60is a parse error, `te_interp()` returns NaN. 61 62If the `error` pointer argument is not 0, then `te_interp()` will set `*error` to the position 63of the parse error on failure, and set `*error` to 0 on success. 64 65**example usage:** 66 67```C 68 int error; 69 70 double a = te_interp("(5+5)", 0); /* Returns 10. */ 71 double b = te_interp("(5+5)", &error); /* Returns 10, error is set to 0. */ 72 double c = te_interp("(5+5", &error); /* Returns NaN, error is set to 4. */ 73``` 74 75## te_compile, te_eval, te_free 76```C 77 te_expr *te_compile(const char *expression, const te_variable *lookup, int lookup_len, int *error); 78 double te_eval(const te_expr *n); 79 void te_free(te_expr *n); 80``` 81 82Give `te_compile()` an expression with unbound variables and a list of 83variable names and pointers. `te_compile()` will return a `te_expr*` which can 84be evaluated later using `te_eval()`. On failure, `te_compile()` will return 0 85and optionally set the passed in `*error` to the location of the parse error. 86 87You may also compile expressions without variables by passing `te_compile()`'s second 88and thrid arguments as 0. 89 90Give `te_eval()` a `te_expr*` from `te_compile()`. `te_eval()` will evaluate the expression 91using the current variable values. 92 93After you're finished, make sure to call `te_free()`. 94 95**example usage:** 96 97```C 98 double x, y; 99 /* Store variable names and pointers. */ 100 te_variable vars[] = {{"x", &x}, {"y", &y}}; 101 102 int err; 103 /* Compile the expression with variables. */ 104 te_expr *expr = te_compile("sqrt(x^2+y^2)", vars, 2, &err); 105 106 if (expr) { 107 x = 3; y = 4; 108 const double h1 = te_eval(expr); /* Returns 5. */ 109 110 x = 5; y = 12; 111 const double h2 = te_eval(expr); /* Returns 13. */ 112 113 te_free(expr); 114 } else { 115 printf("Parse error at %d\n", err); 116 } 117 118``` 119 120## Longer Example 121 122Here is a complete example that will evaluate an expression passed in from the command 123line. It also does error checking and binds the variables `x` and `y` to *3* and *4*, respectively. 124 125```C 126 #include "tinyexpr.h" 127 #include <stdio.h> 128 129 int main(int argc, char *argv[]) 130 { 131 if (argc < 2) { 132 printf("Usage: example2 \"expression\"\n"); 133 return 0; 134 } 135 136 const char *expression = argv[1]; 137 printf("Evaluating:\n\t%s\n", expression); 138 139 /* This shows an example where the variables 140 * x and y are bound at eval-time. */ 141 double x, y; 142 te_variable vars[] = {{"x", &x}, {"y", &y}}; 143 144 /* This will compile the expression and check for errors. */ 145 int err; 146 te_expr *n = te_compile(expression, vars, 2, &err); 147 148 if (n) { 149 /* The variables can be changed here, and eval can be called as many 150 * times as you like. This is fairly efficient because the parsing has 151 * already been done. */ 152 x = 3; y = 4; 153 const double r = te_eval(n); printf("Result:\n\t%f\n", r); 154 te_free(n); 155 } else { 156 /* Show the user where the error is at. */ 157 printf("\t%*s^\nError near here", err-1, ""); 158 } 159 160 return 0; 161 } 162``` 163 164 165This produces the output: 166 167 $ example2 "sqrt(x^2+y2)" 168 Evaluating: 169 sqrt(x^2+y2) 170 ^ 171 Error near here 172 173 174 $ example2 "sqrt(x^2+y^2)" 175 Evaluating: 176 sqrt(x^2+y^2) 177 Result: 178 5.000000 179 180 181## Binding to Custom Functions 182 183TinyExpr can also call to custom functions implemented in C. Here is a short example: 184 185```C 186double my_sum(double a, double b) { 187 /* Example C function that adds two numbers together. */ 188 return a + b; 189} 190 191te_variable vars[] = { 192 {"mysum", my_sum, TE_FUNCTION2} /* TE_FUNCTION2 used because my_sum takes two arguments. */ 193}; 194 195te_expr *n = te_compile("mysum(5, 6)", vars, 1, 0); 196 197``` 198 199 200## How it works 201 202`te_compile()` uses a simple recursive descent parser to compile your 203expression into a syntax tree. For example, the expression `"sin x + 1/4"` 204parses as: 205 206![example syntax tree](doc/e1.png?raw=true) 207 208`te_compile()` also automatically prunes constant branches. In this example, 209the compiled expression returned by `te_compile()` would become: 210 211![example syntax tree](doc/e2.png?raw=true) 212 213`te_eval()` will automatically load in any variables by their pointer, and then evaluate 214and return the result of the expression. 215 216`te_free()` should always be called when you're done with the compiled expression. 217 218 219## Speed 220 221 222TinyExpr is pretty fast compared to C when the expression is short, when the 223expression does hard calculations (e.g. exponentiation), and when some of the 224work can be simplified by `te_compile()`. TinyExpr is slow compared to C when the 225expression is long and involves only basic arithmetic. 226 227Here is some example performance numbers taken from the included 228**benchmark.c** program: 229 230| Expression | te_eval time | native C time | slowdown | 231| :------------- |-------------:| -----:|----:| 232| sqrt(a^1.5+a^2.5) | 15,641 ms | 14,478 ms | 8% slower | 233| a+5 | 765 ms | 563 ms | 36% slower | 234| a+(5*2) | 765 ms | 563 ms | 36% slower | 235| (a+5)*2 | 1422 ms | 563 ms | 153% slower | 236| (1/(a+1)+2/(a+2)+3/(a+3)) | 5,516 ms | 1,266 ms | 336% slower | 237 238 239 240## Grammar 241 242TinyExpr parses the following grammar: 243 244 <list> = <expr> {"," <expr>} 245 <expr> = <term> {("+" | "-") <term>} 246 <term> = <factor> {("*" | "/" | "%") <factor>} 247 <factor> = <power> {"^" <power>} 248 <power> = {("-" | "+")} <base> 249 <base> = <constant> 250 | <variable> 251 | <function-0> {"(" ")"} 252 | <function-1> <power> 253 | <function-X> "(" <expr> {"," <expr>} ")" 254 | "(" <list> ")" 255 256In addition, whitespace between tokens is ignored. 257 258Valid variable names consist of a lower case letter followed by any combination 259of: lower case letters *a* through *z*, the digits *0* through *9*, and 260underscore. Constants can be integers, decimal numbers, or in scientific 261notation (e.g. *1e3* for *1000*). A leading zero is not required (e.g. *.5* 262for *0.5*) 263 264 265## Functions supported 266 267TinyExpr supports addition (+), subtraction/negation (-), multiplication (\*), 268division (/), exponentiation (^) and modulus (%) with the normal operator 269precedence (the one exception being that exponentiation is evaluated 270left-to-right, but this can be changed - see below). 271 272The following C math functions are also supported: 273 274- abs (calls to *fabs*), acos, asin, atan, atan2, ceil, cos, cosh, exp, floor, ln (calls to *log*), log (calls to *log10* by default, see below), log10, pow, sin, sinh, sqrt, tan, tanh 275 276The following functions are also built-in and provided by TinyExpr: 277 278- fac (factorials e.g. `fac 5` == 120) 279- ncr (combinations e.g. `ncr(6,2)` == 15) 280- npr (permutations e.g. `npr(6,2)` == 30) 281 282Also, the following constants are available: 283 284- `pi`, `e` 285 286 287## Compile-time options 288 289 290By default, TinyExpr does exponentiation from left to right. For example: 291 292`a^b^c == (a^b)^c` and `-a^b == (-a)^b` 293 294This is by design. It's the way that spreadsheets do it (e.g. Excel, Google Sheets). 295 296 297If you would rather have exponentiation work from right to left, you need to 298define `TE_POW_FROM_RIGHT` when compiling `tinyexpr.c`. There is a 299commented-out define near the top of that file. With this option enabled, the 300behaviour is: 301 302`a^b^c == a^(b^c)` and `-a^b == -(a^b)` 303 304That will match how many scripting languages do it (e.g. Python, Ruby). 305 306Also, if you'd like `log` to default to the natural log instead of `log10`, 307then you can define `TE_NAT_LOG`. 308 309## Hints 310 311- All functions/types start with the letters *te*. 312 313- To allow constant optimization, surround constant expressions in parentheses. 314 For example "x+(1+5)" will evaluate the "(1+5)" expression at compile time and 315 compile the entire expression as "x+6", saving a runtime calculation. The 316 parentheses are important, because TinyExpr will not change the order of 317 evaluation. If you instead compiled "x+1+5" TinyExpr will insist that "1" is 318 added to "x" first, and "5" is added the result second. 319 320