{"id":13629316,"url":"https://github.com/codeplea/tinyexpr","last_synced_at":"2025-05-15T12:04:38.917Z","repository":{"id":37664175,"uuid":"50113629","full_name":"codeplea/tinyexpr","owner":"codeplea","description":"tiny recursive descent expression parser, compiler, and evaluation engine for math expressions","archived":false,"fork":false,"pushed_at":"2024-08-19T12:17:11.000Z","size":138,"stargazers_count":1698,"open_issues_count":31,"forks_count":255,"subscribers_count":55,"default_branch":"master","last_synced_at":"2025-05-10T01:51:30.454Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://codeplea.com/tinyexpr","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"zlib","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codeplea.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-01-21T14:38:55.000Z","updated_at":"2025-05-09T23:25:48.000Z","dependencies_parsed_at":"2024-11-28T11:03:10.341Z","dependency_job_id":"417af5e9-882a-4419-8430-3716f6b981f3","html_url":"https://github.com/codeplea/tinyexpr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeplea%2Ftinyexpr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeplea%2Ftinyexpr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeplea%2Ftinyexpr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeplea%2Ftinyexpr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codeplea","download_url":"https://codeload.github.com/codeplea/tinyexpr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337612,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T22:01:07.264Z","updated_at":"2025-05-15T12:04:33.889Z","avatar_url":"https://github.com/codeplea.png","language":"C","readme":"[![Build Status](https://travis-ci.com/codeplea/tinyexpr.svg?branch=master)](https://travis-ci.com/codeplea/tinyexpr)\n\n\n\u003cimg alt=\"TinyExpr logo\" src=\"https://codeplea.com/public/content/tinyexpr_logo.png\" align=\"right\"/\u003e\n\n# TinyExpr\n\nTinyExpr is a very small recursive descent parser and evaluation engine for\nmath expressions. It's handy when you want to add the ability to evaluate\nmath expressions at runtime without adding a bunch of cruft to your project.\n\nIn addition to the standard math operators and precedence, TinyExpr also supports\nthe standard C math functions and runtime binding of variables.\n\n## Features\n\n- **C99 with no dependencies**.\n- Single source file and header file.\n- Simple and fast.\n- Implements standard operators precedence.\n- Exposes standard C math functions (sin, sqrt, ln, etc.).\n- Can add custom functions and variables easily.\n- Can bind variables at eval-time.\n- Released under the zlib license - free for nearly any use.\n- Easy to use and integrate with your code\n- Thread-safe, provided that your *malloc* is.\n\n## Building\n\nTinyExpr is self-contained in two files: `tinyexpr.c` and `tinyexpr.h`. To use\nTinyExpr, simply add those two files to your project.\n\n## Short Example\n\nHere is a minimal example to evaluate an expression at runtime.\n\n```C\n    #include \"tinyexpr.h\"\n    printf(\"%f\\n\", te_interp(\"5*5\", 0)); /* Prints 25. */\n```\n\n\n## Usage\n\nTinyExpr defines only four functions:\n\n```C\n    double te_interp(const char *expression, int *error);\n    te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error);\n    double te_eval(const te_expr *expr);\n    void te_free(te_expr *expr);\n```\n\n## te_interp\n```C\n    double te_interp(const char *expression, int *error);\n```\n\n`te_interp()` takes an expression and immediately returns the result of it. If there\nis a parse error, `te_interp()` returns NaN.\n\nIf the `error` pointer argument is not 0, then `te_interp()` will set `*error` to the position\nof the parse error on failure, and set `*error` to 0 on success.\n\n**example usage:**\n\n```C\n    int error;\n\n    double a = te_interp(\"(5+5)\", 0); /* Returns 10. */\n    double b = te_interp(\"(5+5)\", \u0026error); /* Returns 10, error is set to 0. */\n    double c = te_interp(\"(5+5\", \u0026error); /* Returns NaN, error is set to 4. */\n```\n\n## te_compile, te_eval, te_free\n```C\n    te_expr *te_compile(const char *expression, const te_variable *lookup, int lookup_len, int *error);\n    double te_eval(const te_expr *n);\n    void te_free(te_expr *n);\n```\n\nGive `te_compile()` an expression with unbound variables and a list of\nvariable names and pointers. `te_compile()` will return a `te_expr*` which can\nbe evaluated later using `te_eval()`. On failure, `te_compile()` will return 0\nand optionally set the passed in `*error` to the location of the parse error.\n\nYou may also compile expressions without variables by passing `te_compile()`'s second\nand third arguments as 0.\n\nGive `te_eval()` a `te_expr*` from `te_compile()`. `te_eval()` will evaluate the expression\nusing the current variable values.\n\nAfter you're finished, make sure to call `te_free()`.\n\n**example usage:**\n\n```C\n    double x, y;\n    /* Store variable names and pointers. */\n    te_variable vars[] = {{\"x\", \u0026x}, {\"y\", \u0026y}};\n\n    int err;\n    /* Compile the expression with variables. */\n    te_expr *expr = te_compile(\"sqrt(x^2+y^2)\", vars, 2, \u0026err);\n\n    if (expr) {\n        x = 3; y = 4;\n        const double h1 = te_eval(expr); /* Returns 5. */\n\n        x = 5; y = 12;\n        const double h2 = te_eval(expr); /* Returns 13. */\n\n        te_free(expr);\n    } else {\n        printf(\"Parse error at %d\\n\", err);\n    }\n\n```\n\n## Longer Example\n\nHere is a complete example that will evaluate an expression passed in from the command\nline. It also does error checking and binds the variables `x` and `y` to *3* and *4*, respectively.\n\n```C\n    #include \"tinyexpr.h\"\n    #include \u003cstdio.h\u003e\n\n    int main(int argc, char *argv[])\n    {\n        if (argc \u003c 2) {\n            printf(\"Usage: example2 \\\"expression\\\"\\n\");\n            return 0;\n        }\n\n        const char *expression = argv[1];\n        printf(\"Evaluating:\\n\\t%s\\n\", expression);\n\n        /* This shows an example where the variables\n         * x and y are bound at eval-time. */\n        double x, y;\n        te_variable vars[] = {{\"x\", \u0026x}, {\"y\", \u0026y}};\n\n        /* This will compile the expression and check for errors. */\n        int err;\n        te_expr *n = te_compile(expression, vars, 2, \u0026err);\n\n        if (n) {\n            /* The variables can be changed here, and eval can be called as many\n             * times as you like. This is fairly efficient because the parsing has\n             * already been done. */\n            x = 3; y = 4;\n            const double r = te_eval(n); printf(\"Result:\\n\\t%f\\n\", r);\n            te_free(n);\n        } else {\n            /* Show the user where the error is at. */\n            printf(\"\\t%*s^\\nError near here\", err-1, \"\");\n        }\n\n        return 0;\n    }\n```\n\n\nThis produces the output:\n\n    $ example2 \"sqrt(x^2+y2)\"\n        Evaluating:\n                sqrt(x^2+y2)\n                          ^\n        Error near here\n\n\n    $ example2 \"sqrt(x^2+y^2)\"\n        Evaluating:\n                sqrt(x^2+y^2)\n        Result:\n                5.000000\n\n\n## Binding to Custom Functions\n\nTinyExpr can also call to custom functions implemented in C. Here is a short example:\n\n```C\ndouble my_sum(double a, double b) {\n    /* Example C function that adds two numbers together. */\n    return a + b;\n}\n\nte_variable vars[] = {\n    {\"mysum\", my_sum, TE_FUNCTION2} /* TE_FUNCTION2 used because my_sum takes two arguments. */\n};\n\nte_expr *n = te_compile(\"mysum(5, 6)\", vars, 1, 0);\n\n```\n\n\n## How it works\n\n`te_compile()` uses a simple recursive descent parser to compile your\nexpression into a syntax tree. For example, the expression `\"sin x + 1/4\"`\nparses as:\n\n![example syntax tree](doc/e1.png?raw=true)\n\n`te_compile()` also automatically prunes constant branches. In this example,\nthe compiled expression returned by `te_compile()` would become:\n\n![example syntax tree](doc/e2.png?raw=true)\n\n`te_eval()` will automatically load in any variables by their pointer, and then evaluate\nand return the result of the expression.\n\n`te_free()` should always be called when you're done with the compiled expression.\n\n\n## Speed\n\n\nTinyExpr is pretty fast compared to C when the expression is short, when the\nexpression does hard calculations (e.g. exponentiation), and when some of the\nwork can be simplified by `te_compile()`. TinyExpr is slow compared to C when the\nexpression is long and involves only basic arithmetic.\n\nHere is some example performance numbers taken from the included\n**benchmark.c** program:\n\n| Expression | te_eval time | native C time | slowdown  |\n| :------------- |-------------:| -----:|----:|\n| sqrt(a^1.5+a^2.5) | 15,641 ms | 14,478 ms | 8% slower |\n| a+5 | 765 ms | 563 ms | 36% slower |\n| a+(5*2) | 765 ms | 563 ms | 36% slower |\n| (a+5)*2 | 1422 ms | 563 ms | 153% slower |\n| (1/(a+1)+2/(a+2)+3/(a+3)) | 5,516 ms | 1,266 ms | 336% slower |\n\n\n\n## Grammar\n\nTinyExpr parses the following grammar:\n\n    \u003clist\u003e      =    \u003cexpr\u003e {\",\" \u003cexpr\u003e}\n    \u003cexpr\u003e      =    \u003cterm\u003e {(\"+\" | \"-\") \u003cterm\u003e}\n    \u003cterm\u003e      =    \u003cfactor\u003e {(\"*\" | \"/\" | \"%\") \u003cfactor\u003e}\n    \u003cfactor\u003e    =    \u003cpower\u003e {\"^\" \u003cpower\u003e}\n    \u003cpower\u003e     =    {(\"-\" | \"+\")} \u003cbase\u003e\n    \u003cbase\u003e      =    \u003cconstant\u003e\n                   | \u003cvariable\u003e\n                   | \u003cfunction-0\u003e {\"(\" \")\"}\n                   | \u003cfunction-1\u003e \u003cpower\u003e\n                   | \u003cfunction-X\u003e \"(\" \u003cexpr\u003e {\",\" \u003cexpr\u003e} \")\"\n                   | \"(\" \u003clist\u003e \")\"\n\nIn addition, whitespace between tokens is ignored.\n\nValid variable names consist of a letter followed by any combination of:\nletters, the digits *0* through *9*, and underscore. Constants can be integers\nor floating-point numbers, and can be in decimal, hexadecimal (e.g., *0x57CEF7*),\nor scientific notation (e.g., *1e3* for *1000*).\nA leading zero is not required (e.g., *.5* for *0.5*).\n\n\n## Functions supported\n\nTinyExpr supports addition (+), subtraction/negation (-), multiplication (\\*),\ndivision (/), exponentiation (^) and modulus (%) with the normal operator\nprecedence (the one exception being that exponentiation is evaluated\nleft-to-right, but this can be changed - see below).\n\nThe following C math functions are also supported:\n\n- 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\n\nThe following functions are also built-in and provided by TinyExpr:\n\n- fac (factorials e.g. `fac 5` == 120)\n- ncr (combinations e.g. `ncr(6,2)` == 15)\n- npr (permutations e.g. `npr(6,2)` == 30)\n\nAlso, the following constants are available:\n\n- `pi`, `e`\n\n\n## Compile-time options\n\n\nBy default, TinyExpr does exponentiation from left to right. For example:\n\n`a^b^c == (a^b)^c` and `-a^b == (-a)^b`\n\nThis is by design. It's the way that spreadsheets do it (e.g. Excel, Google Sheets).\n\n\nIf you would rather have exponentiation work from right to left, you need to\ndefine `TE_POW_FROM_RIGHT` when compiling `tinyexpr.c`. There is a\ncommented-out define near the top of that file. With this option enabled, the\nbehaviour is:\n\n`a^b^c == a^(b^c)` and `-a^b == -(a^b)`\n\nThat will match how many scripting languages do it (e.g. Python, Ruby).\n\nAlso, if you'd like `log` to default to the natural log instead of `log10`,\nthen you can define `TE_NAT_LOG`.\n\n## Hints\n\n- All functions/types start with the letters *te*.\n\n- To allow constant optimization, surround constant expressions in parentheses.\n  For example \"x+(1+5)\" will evaluate the \"(1+5)\" expression at compile time and\n  compile the entire expression as \"x+6\", saving a runtime calculation. The\n  parentheses are important, because TinyExpr will not change the order of\n  evaluation. If you instead compiled \"x+1+5\" TinyExpr will insist that \"1\" is\n  added to \"x\" first, and \"5\" is added the result second.\n\n","funding_links":[],"categories":["Math","Utilities","Maths","C","公用事业","进程间通信","Utilities ##"],"sub_categories":["YAML","数学","Vim ###"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeplea%2Ftinyexpr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodeplea%2Ftinyexpr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeplea%2Ftinyexpr/lists"}