LCOV - code coverage report
Current view: top level - src - tinyexpr.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 345 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 29 0

            Line data    Source code
       1              : // SPDX-License-Identifier: Zlib
       2              : /*
       3              :  * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
       4              :  *
       5              :  * Copyright (c) 2015-2020 Lewis Van Winkle
       6              :  *
       7              :  * http://CodePlea.com
       8              :  *
       9              :  * This software is provided 'as-is', without any express or implied
      10              :  * warranty. In no event will the authors be held liable for any damages
      11              :  * arising from the use of this software.
      12              :  *
      13              :  * Permission is granted to anyone to use this software for any purpose,
      14              :  * including commercial applications, and to alter it and redistribute it
      15              :  * freely, subject to the following restrictions:
      16              :  *
      17              :  * 1. The origin of this software must not be misrepresented; you must not
      18              :  * claim that you wrote the original software. If you use this software
      19              :  * in a product, an acknowledgement in the product documentation would be
      20              :  * appreciated but is not required.
      21              :  * 2. Altered source versions must be plainly marked as such, and must not be
      22              :  * misrepresented as being the original software.
      23              :  * 3. This notice may not be removed or altered from any source distribution.
      24              :  */
      25              : 
      26              : /* COMPILE TIME OPTIONS */
      27              : 
      28              : /* Exponentiation associativity:
      29              : For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing.
      30              : For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/
      31              : /* #define TE_POW_FROM_RIGHT */
      32              : 
      33              : /* Logarithms
      34              : For log = base 10 log do nothing
      35              : For log = natural log uncomment the next line. */
      36              : /* #define TE_NAT_LOG */
      37              : 
      38              : #include "tinyexpr.h"
      39              : #include <ctype.h>
      40              : #include <limits.h>
      41              : #include <math.h>
      42              : #include <stdio.h>
      43              : #include <stdlib.h>
      44              : #include <string.h>
      45              : 
      46              : #ifndef NAN
      47              : #define NAN (0.0 / 0.0)
      48              : #endif
      49              : 
      50              : #ifndef INFINITY
      51              : #define INFINITY (1.0 / 0.0)
      52              : #endif
      53              : 
      54              : typedef double (*te_fun2)(double, double);
      55              : 
      56              : enum {
      57              :    TOK_NULL = TE_CLOSURE7 + 1,
      58              :    TOK_ERROR,
      59              :    TOK_END,
      60              :    TOK_SEP,
      61              :    TOK_OPEN,
      62              :    TOK_CLOSE,
      63              :    TOK_NUMBER,
      64              :    TOK_VARIABLE,
      65              :    TOK_INFIX
      66              : };
      67              : 
      68              : enum { TE_CONSTANT = 1 };
      69              : 
      70              : typedef struct state {
      71              :    const char *start;
      72              :    const char *next;
      73              :    int type;
      74              :    union {
      75              :       double value;
      76              :       const double *bound;
      77              :       const void *function;
      78              :    };
      79              :    void *context;
      80              : 
      81              :    const te_variable *lookup;
      82              :    int lookup_len;
      83              : } state;
      84              : 
      85              : #define TYPE_MASK(TYPE) ((TYPE) &0x0000001F)
      86              : 
      87              : #define IS_PURE(TYPE) (((TYPE) &TE_FLAG_PURE) != 0)
      88              : #define IS_FUNCTION(TYPE) (((TYPE) &TE_FUNCTION0) != 0)
      89              : #define IS_CLOSURE(TYPE) (((TYPE) &TE_CLOSURE0) != 0)
      90              : #define ARITY(TYPE) (((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) &0x00000007) : 0)
      91              : #define NEW_EXPR(type, ...) new_expr((type), (const te_expr *[]){__VA_ARGS__})
      92              : 
      93            0 : static te_expr *new_expr(const int type, const te_expr *parameters[]) {
      94            0 :    const int arity = ARITY(type);
      95            0 :    const int psize = sizeof(void *) * arity;
      96            0 :    const int size = (sizeof(te_expr) /* - sizeof(void *) */) + psize + (IS_CLOSURE(type) ? sizeof(void *) : 0);
      97            0 :    te_expr *ret = malloc(size);
      98            0 :    memset(ret, 0, size);
      99            0 :    if (arity && parameters) {
     100            0 :       memcpy(ret->parameters, parameters, psize);
     101              :    }
     102            0 :    ret->type = type;
     103            0 :    ret->bound = 0;
     104            0 :    return ret;
     105              : }
     106              : 
     107            0 : void te_free_parameters(te_expr *n) {
     108            0 :    if (!n)
     109            0 :       return;
     110            0 :    switch (TYPE_MASK(n->type)) {
     111            0 :       case TE_FUNCTION7:
     112            0 :       case TE_CLOSURE7: te_free(n->parameters[6]); /* Falls through. */
     113            0 :       case TE_FUNCTION6:
     114            0 :       case TE_CLOSURE6: te_free(n->parameters[5]); /* Falls through. */
     115            0 :       case TE_FUNCTION5:
     116            0 :       case TE_CLOSURE5: te_free(n->parameters[4]); /* Falls through. */
     117            0 :       case TE_FUNCTION4:
     118            0 :       case TE_CLOSURE4: te_free(n->parameters[3]); /* Falls through. */
     119            0 :       case TE_FUNCTION3:
     120            0 :       case TE_CLOSURE3: te_free(n->parameters[2]); /* Falls through. */
     121            0 :       case TE_FUNCTION2:
     122            0 :       case TE_CLOSURE2: te_free(n->parameters[1]); /* Falls through. */
     123            0 :       case TE_FUNCTION1:
     124            0 :       case TE_CLOSURE1: te_free(n->parameters[0]);
     125              :    }
     126              : }
     127              : 
     128            0 : void te_free(te_expr *n) {
     129            0 :    if (!n)
     130            0 :       return;
     131            0 :    te_free_parameters(n);
     132            0 :    free(n);
     133              : }
     134              : 
     135            0 : static double pi(void) { return 3.14159265358979323846; }
     136            0 : static double e(void) { return 2.71828182845904523536; }
     137            0 : static double fac(double a) { /* simplest version of fac */
     138            0 :    if (a < 0.0)
     139            0 :       return NAN;
     140            0 :    if (a > UINT_MAX)
     141            0 :       return INFINITY;
     142            0 :    unsigned int ua = (unsigned int) (a);
     143            0 :    unsigned long int result = 1, i;
     144            0 :    for (i = 1; i <= ua; i++) {
     145            0 :       if (i > ULONG_MAX / result)
     146            0 :          return INFINITY;
     147            0 :       result *= i;
     148              :    }
     149            0 :    return (double) result;
     150              : }
     151            0 : static double ncr(double n, double r) {
     152            0 :    if (n < 0.0 || r < 0.0 || n < r)
     153            0 :       return NAN;
     154            0 :    if (n > UINT_MAX || r > UINT_MAX)
     155            0 :       return INFINITY;
     156            0 :    unsigned long int un = (unsigned int) (n), ur = (unsigned int) (r), i;
     157            0 :    unsigned long int result = 1;
     158            0 :    if (ur > un / 2)
     159            0 :       ur = un - ur;
     160            0 :    for (i = 1; i <= ur; i++) {
     161            0 :       if (result > ULONG_MAX / (un - ur + i))
     162            0 :          return INFINITY;
     163            0 :       result *= un - ur + i;
     164            0 :       result /= i;
     165              :    }
     166            0 :    return result;
     167              : }
     168            0 : static double npr(double n, double r) { return ncr(n, r) * fac(r); }
     169              : 
     170              : #ifdef _MSC_VER
     171              : #pragma function(ceil)
     172              : #pragma function(floor)
     173              : #endif
     174              : 
     175              : static const te_variable functions[] = {
     176              :    /* must be in alphabetical order */
     177              :    {"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     178              :    {"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     179              :    {"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     180              :    {"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     181              :    {"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE, 0},
     182              :    {"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     183              :    {"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     184              :    {"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     185              :    {"e", e, TE_FUNCTION0 | TE_FLAG_PURE, 0},
     186              :    {"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     187              :    {"fac", fac, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     188              :    {"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     189              :    {"ln", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     190              : #ifdef TE_NAT_LOG
     191              :    {"log", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     192              : #else
     193              :    {"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     194              : #endif
     195              :    {"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     196              :    {"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
     197              :    {"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
     198              :    {"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0},
     199              :    {"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0},
     200              :    {"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     201              :    {"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     202              :    {"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     203              :    {"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     204              :    {"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
     205              :    {0, 0, 0, 0}};
     206              : 
     207            0 : static const te_variable *find_builtin(const char *name, int len) {
     208            0 :    int imin = 0;
     209            0 :    int imax = sizeof(functions) / sizeof(te_variable) - 2;
     210              : 
     211              :    /*Binary search.*/
     212            0 :    while (imax >= imin) {
     213            0 :       const int i = (imin + ((imax - imin) / 2));
     214            0 :       int c = strncmp(name, functions[i].name, len);
     215            0 :       if (!c)
     216            0 :          c = '\0' - functions[i].name[len];
     217            0 :       if (c == 0) {
     218            0 :          return functions + i;
     219            0 :       } else if (c > 0) {
     220            0 :          imin = i + 1;
     221              :       } else {
     222            0 :          imax = i - 1;
     223              :       }
     224              :    }
     225              : 
     226            0 :    return 0;
     227              : }
     228              : 
     229            0 : static const te_variable *find_lookup(const state *s, const char *name, int len) {
     230              :    int iters;
     231              :    const te_variable *var;
     232            0 :    if (!s->lookup)
     233            0 :       return 0;
     234              : 
     235            0 :    for (var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) {
     236            0 :       if (strncmp(name, var->name, len) == 0 && var->name[len] == '\0') {
     237            0 :          return var;
     238              :       }
     239              :    }
     240            0 :    return 0;
     241              : }
     242              : 
     243            0 : static double add(double a, double b) { return a + b; }
     244            0 : static double sub(double a, double b) { return a - b; }
     245            0 : static double mul(double a, double b) { return a * b; }
     246            0 : static double divide(double a, double b) { return a / b; }
     247            0 : static double negate(double a) { return -a; }
     248            0 : static double comma(double a, double b) {
     249              :    (void) a;
     250            0 :    return b;
     251              : }
     252              : 
     253            0 : void next_token(state *s) {
     254            0 :    s->type = TOK_NULL;
     255              : 
     256              :    do {
     257              : 
     258            0 :       if (!*s->next) {
     259            0 :          s->type = TOK_END;
     260            0 :          return;
     261              :       }
     262              : 
     263              :       /* Try reading a number. */
     264            0 :       if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
     265            0 :          s->value = strtod(s->next, (char **) &s->next);
     266            0 :          s->type = TOK_NUMBER;
     267              :       } else {
     268              :          /* Look for a variable or builtin function call. */
     269            0 :          if (isalpha(s->next[0])) {
     270              :             const char *start;
     271            0 :             start = s->next;
     272            0 :             while (isalpha(s->next[0]) || isdigit(s->next[0]) || (s->next[0] == '_'))
     273            0 :                s->next++;
     274              : 
     275            0 :             const te_variable *var = find_lookup(s, start, s->next - start);
     276            0 :             if (!var)
     277            0 :                var = find_builtin(start, s->next - start);
     278              : 
     279            0 :             if (!var) {
     280            0 :                s->type = TOK_ERROR;
     281              :             } else {
     282            0 :                switch (TYPE_MASK(var->type)) {
     283            0 :                   case TE_VARIABLE:
     284            0 :                      s->type = TOK_VARIABLE;
     285            0 :                      s->bound = var->address;
     286            0 :                      break;
     287              : 
     288            0 :                   case TE_CLOSURE0:
     289              :                   case TE_CLOSURE1:
     290              :                   case TE_CLOSURE2:
     291              :                   case TE_CLOSURE3: /* Falls through. */
     292              :                   case TE_CLOSURE4:
     293              :                   case TE_CLOSURE5:
     294              :                   case TE_CLOSURE6:
     295              :                   case TE_CLOSURE7:             /* Falls through. */
     296            0 :                      s->context = var->context; /* Falls through. */
     297              : 
     298            0 :                   case TE_FUNCTION0:
     299              :                   case TE_FUNCTION1:
     300              :                   case TE_FUNCTION2:
     301              :                   case TE_FUNCTION3: /* Falls through. */
     302              :                   case TE_FUNCTION4:
     303              :                   case TE_FUNCTION5:
     304              :                   case TE_FUNCTION6:
     305              :                   case TE_FUNCTION7: /* Falls through. */
     306            0 :                      s->type = var->type;
     307            0 :                      s->function = var->address;
     308            0 :                      break;
     309              :                }
     310              :             }
     311              : 
     312              :          } else {
     313              :             /* Look for an operator or special character. */
     314            0 :             switch (s->next++[0]) {
     315            0 :                case '+':
     316            0 :                   s->type = TOK_INFIX;
     317            0 :                   s->function = add;
     318            0 :                   break;
     319            0 :                case '-':
     320            0 :                   s->type = TOK_INFIX;
     321            0 :                   s->function = sub;
     322            0 :                   break;
     323            0 :                case '*':
     324            0 :                   s->type = TOK_INFIX;
     325            0 :                   s->function = mul;
     326            0 :                   break;
     327            0 :                case '/':
     328            0 :                   s->type = TOK_INFIX;
     329            0 :                   s->function = divide;
     330            0 :                   break;
     331            0 :                case '^':
     332            0 :                   s->type = TOK_INFIX;
     333            0 :                   s->function = pow;
     334            0 :                   break;
     335            0 :                case '%':
     336            0 :                   s->type = TOK_INFIX;
     337            0 :                   s->function = fmod;
     338            0 :                   break;
     339            0 :                case '(': s->type = TOK_OPEN; break;
     340            0 :                case ')': s->type = TOK_CLOSE; break;
     341            0 :                case ',': s->type = TOK_SEP; break;
     342            0 :                case ' ':
     343              :                case '\t':
     344              :                case '\n':
     345            0 :                case '\r': break;
     346            0 :                default: s->type = TOK_ERROR; break;
     347              :             }
     348              :          }
     349              :       }
     350            0 :    } while (s->type == TOK_NULL);
     351              : }
     352              : 
     353              : static te_expr *list(state *s);
     354              : static te_expr *expr(state *s);
     355              : static te_expr *power(state *s);
     356              : 
     357            0 : static te_expr *base(state *s) {
     358              :    /* <base>      =    <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
     359              :    te_expr *ret;
     360              :    int arity;
     361              : 
     362            0 :    switch (TYPE_MASK(s->type)) {
     363            0 :       case TOK_NUMBER:
     364            0 :          ret = new_expr(TE_CONSTANT, 0);
     365            0 :          ret->value = s->value;
     366            0 :          next_token(s);
     367            0 :          break;
     368              : 
     369            0 :       case TOK_VARIABLE:
     370            0 :          ret = new_expr(TE_VARIABLE, 0);
     371            0 :          ret->bound = s->bound;
     372            0 :          next_token(s);
     373            0 :          break;
     374              : 
     375            0 :       case TE_FUNCTION0:
     376              :       case TE_CLOSURE0:
     377            0 :          ret = new_expr(s->type, 0);
     378            0 :          ret->function = s->function;
     379            0 :          if (IS_CLOSURE(s->type))
     380            0 :             ret->parameters[0] = s->context;
     381            0 :          next_token(s);
     382            0 :          if (s->type == TOK_OPEN) {
     383            0 :             next_token(s);
     384            0 :             if (s->type != TOK_CLOSE) {
     385            0 :                s->type = TOK_ERROR;
     386              :             } else {
     387            0 :                next_token(s);
     388              :             }
     389              :          }
     390            0 :          break;
     391              : 
     392            0 :       case TE_FUNCTION1:
     393              :       case TE_CLOSURE1:
     394            0 :          ret = new_expr(s->type, 0);
     395            0 :          ret->function = s->function;
     396            0 :          if (IS_CLOSURE(s->type))
     397            0 :             ret->parameters[1] = s->context;
     398            0 :          next_token(s);
     399            0 :          ret->parameters[0] = power(s);
     400            0 :          break;
     401              : 
     402            0 :       case TE_FUNCTION2:
     403              :       case TE_FUNCTION3:
     404              :       case TE_FUNCTION4:
     405              :       case TE_FUNCTION5:
     406              :       case TE_FUNCTION6:
     407              :       case TE_FUNCTION7:
     408              :       case TE_CLOSURE2:
     409              :       case TE_CLOSURE3:
     410              :       case TE_CLOSURE4:
     411              :       case TE_CLOSURE5:
     412              :       case TE_CLOSURE6:
     413              :       case TE_CLOSURE7:
     414            0 :          arity = ARITY(s->type);
     415              : 
     416            0 :          ret = new_expr(s->type, 0);
     417            0 :          ret->function = s->function;
     418            0 :          if (IS_CLOSURE(s->type))
     419            0 :             ret->parameters[arity] = s->context;
     420            0 :          next_token(s);
     421              : 
     422            0 :          if (s->type != TOK_OPEN) {
     423            0 :             s->type = TOK_ERROR;
     424              :          } else {
     425              :             int i;
     426            0 :             for (i = 0; i < arity; i++) {
     427            0 :                next_token(s);
     428            0 :                ret->parameters[i] = expr(s);
     429            0 :                if (s->type != TOK_SEP) {
     430            0 :                   break;
     431              :                }
     432              :             }
     433            0 :             if (s->type != TOK_CLOSE || i != arity - 1) {
     434            0 :                s->type = TOK_ERROR;
     435              :             } else {
     436            0 :                next_token(s);
     437              :             }
     438              :          }
     439              : 
     440            0 :          break;
     441              : 
     442            0 :       case TOK_OPEN:
     443            0 :          next_token(s);
     444            0 :          ret = list(s);
     445            0 :          if (s->type != TOK_CLOSE) {
     446            0 :             s->type = TOK_ERROR;
     447              :          } else {
     448            0 :             next_token(s);
     449              :          }
     450            0 :          break;
     451              : 
     452            0 :       default:
     453            0 :          ret = new_expr(0, 0);
     454            0 :          s->type = TOK_ERROR;
     455            0 :          ret->value = NAN;
     456            0 :          break;
     457              :    }
     458              : 
     459            0 :    return ret;
     460              : }
     461              : 
     462            0 : static te_expr *power(state *s) {
     463              :    /* <power>     =    {("-" | "+")} <base> */
     464            0 :    int sign = 1;
     465            0 :    while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
     466            0 :       if (s->function == sub)
     467            0 :          sign = -sign;
     468            0 :       next_token(s);
     469              :    }
     470              : 
     471              :    te_expr *ret;
     472              : 
     473            0 :    if (sign == 1) {
     474            0 :       ret = base(s);
     475              :    } else {
     476            0 :       ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
     477            0 :       ret->function = negate;
     478              :    }
     479              : 
     480            0 :    return ret;
     481              : }
     482              : 
     483              : #ifdef TE_POW_FROM_RIGHT
     484              : static te_expr *factor(state *s) {
     485              :    /* <factor>    =    <power> {"^" <power>} */
     486              :    te_expr *ret = power(s);
     487              : 
     488              :    int neg = 0;
     489              : 
     490              :    if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) {
     491              :       te_expr *se = ret->parameters[0];
     492              :       free(ret);
     493              :       ret = se;
     494              :       neg = 1;
     495              :    }
     496              : 
     497              :    te_expr *insertion = 0;
     498              : 
     499              :    while (s->type == TOK_INFIX && (s->function == pow)) {
     500              :       te_fun2 t = s->function;
     501              :       next_token(s);
     502              : 
     503              :       if (insertion) {
     504              :          /* Make exponentiation go right-to-left. */
     505              :          te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s));
     506              :          insert->function = t;
     507              :          insertion->parameters[1] = insert;
     508              :          insertion = insert;
     509              :       } else {
     510              :          ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
     511              :          ret->function = t;
     512              :          insertion = ret;
     513              :       }
     514              :    }
     515              : 
     516              :    if (neg) {
     517              :       ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret);
     518              :       ret->function = negate;
     519              :    }
     520              : 
     521              :    return ret;
     522              : }
     523              : #else
     524            0 : static te_expr *factor(state *s) {
     525              :    /* <factor>    =    <power> {"^" <power>} */
     526            0 :    te_expr *ret = power(s);
     527              : 
     528            0 :    while (s->type == TOK_INFIX && (s->function == pow)) {
     529            0 :       te_fun2 t = s->function;
     530            0 :       next_token(s);
     531            0 :       ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
     532            0 :       ret->function = t;
     533              :    }
     534              : 
     535            0 :    return ret;
     536              : }
     537              : #endif
     538              : 
     539            0 : static te_expr *term(state *s) {
     540              :    /* <term>      =    <factor> {("*" | "/" | "%") <factor>} */
     541            0 :    te_expr *ret = factor(s);
     542              : 
     543            0 :    while (s->type == TOK_INFIX && (s->function == mul || s->function == divide || s->function == fmod)) {
     544            0 :       te_fun2 t = s->function;
     545            0 :       next_token(s);
     546            0 :       ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s));
     547            0 :       ret->function = t;
     548              :    }
     549              : 
     550            0 :    return ret;
     551              : }
     552              : 
     553            0 : static te_expr *expr(state *s) {
     554              :    /* <expr>      =    <term> {("+" | "-") <term>} */
     555            0 :    te_expr *ret = term(s);
     556              : 
     557            0 :    while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
     558            0 :       te_fun2 t = s->function;
     559            0 :       next_token(s);
     560            0 :       ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s));
     561            0 :       ret->function = t;
     562              :    }
     563              : 
     564            0 :    return ret;
     565              : }
     566              : 
     567            0 : static te_expr *list(state *s) {
     568              :    /* <list>      =    <expr> {"," <expr>} */
     569            0 :    te_expr *ret = expr(s);
     570              : 
     571            0 :    while (s->type == TOK_SEP) {
     572            0 :       next_token(s);
     573            0 :       ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s));
     574            0 :       ret->function = comma;
     575              :    }
     576              : 
     577            0 :    return ret;
     578              : }
     579              : 
     580              : #define TE_FUN(...) ((double (*)(__VA_ARGS__)) n->function)
     581              : #define M(e) te_eval(n->parameters[e])
     582              : 
     583            0 : double te_eval(const te_expr *n) {
     584            0 :    if (!n)
     585            0 :       return NAN;
     586              : 
     587            0 :    switch (TYPE_MASK(n->type)) {
     588            0 :       case TE_CONSTANT: return n->value;
     589            0 :       case TE_VARIABLE: return *n->bound;
     590              : 
     591            0 :       case TE_FUNCTION0:
     592              :       case TE_FUNCTION1:
     593              :       case TE_FUNCTION2:
     594              :       case TE_FUNCTION3:
     595              :       case TE_FUNCTION4:
     596              :       case TE_FUNCTION5:
     597              :       case TE_FUNCTION6:
     598              :       case TE_FUNCTION7:
     599            0 :          switch (ARITY(n->type)) {
     600            0 :             case 0: return TE_FUN(void)();
     601            0 :             case 1: return TE_FUN(double)(M(0));
     602            0 :             case 2: return TE_FUN(double, double)(M(0), M(1));
     603            0 :             case 3: return TE_FUN(double, double, double)(M(0), M(1), M(2));
     604            0 :             case 4: return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3));
     605            0 :             case 5: return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4));
     606            0 :             case 6: return TE_FUN(double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5));
     607            0 :             case 7: return TE_FUN(double, double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5), M(6));
     608            0 :             default: return NAN;
     609              :          }
     610              : 
     611            0 :       case TE_CLOSURE0:
     612              :       case TE_CLOSURE1:
     613              :       case TE_CLOSURE2:
     614              :       case TE_CLOSURE3:
     615              :       case TE_CLOSURE4:
     616              :       case TE_CLOSURE5:
     617              :       case TE_CLOSURE6:
     618              :       case TE_CLOSURE7:
     619            0 :          switch (ARITY(n->type)) {
     620            0 :             case 0: return TE_FUN(void *)(n->parameters[0]);
     621            0 :             case 1: return TE_FUN(void *, double)(n->parameters[1], M(0));
     622            0 :             case 2: return TE_FUN(void *, double, double)(n->parameters[2], M(0), M(1));
     623            0 :             case 3: return TE_FUN(void *, double, double, double)(n->parameters[3], M(0), M(1), M(2));
     624            0 :             case 4: return TE_FUN(void *, double, double, double, double)(n->parameters[4], M(0), M(1), M(2), M(3));
     625            0 :             case 5: return TE_FUN(void *, double, double, double, double, double)(n->parameters[5], M(0), M(1), M(2), M(3), M(4));
     626            0 :             case 6: return TE_FUN(void *, double, double, double, double, double, double)(n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5));
     627            0 :             case 7: return TE_FUN(void *, double, double, double, double, double, double, double)(n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6));
     628            0 :             default: return NAN;
     629              :          }
     630              : 
     631            0 :       default: return NAN;
     632              :    }
     633              : }
     634              : 
     635              : #undef TE_FUN
     636              : #undef M
     637              : 
     638            0 : static void optimize(te_expr *n) {
     639              :    /* Evaluates as much as possible. */
     640            0 :    if (n->type == TE_CONSTANT)
     641            0 :       return;
     642            0 :    if (n->type == TE_VARIABLE)
     643            0 :       return;
     644              : 
     645              :    /* Only optimize out functions flagged as pure. */
     646            0 :    if (IS_PURE(n->type)) {
     647            0 :       const int arity = ARITY(n->type);
     648            0 :       int known = 1;
     649              :       int i;
     650            0 :       for (i = 0; i < arity; ++i) {
     651            0 :          optimize(n->parameters[i]);
     652            0 :          if (((te_expr *) (n->parameters[i]))->type != TE_CONSTANT) {
     653            0 :             known = 0;
     654              :          }
     655              :       }
     656            0 :       if (known) {
     657            0 :          const double value = te_eval(n);
     658            0 :          te_free_parameters(n);
     659            0 :          n->type = TE_CONSTANT;
     660            0 :          n->value = value;
     661              :       }
     662              :    }
     663              : }
     664              : 
     665            0 : te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) {
     666              :    state s;
     667            0 :    s.start = s.next = expression;
     668            0 :    s.lookup = variables;
     669            0 :    s.lookup_len = var_count;
     670              : 
     671            0 :    next_token(&s);
     672            0 :    te_expr *root = list(&s);
     673              : 
     674            0 :    if (s.type != TOK_END) {
     675            0 :       te_free(root);
     676            0 :       if (error) {
     677            0 :          *error = (s.next - s.start);
     678            0 :          if (*error == 0)
     679            0 :             *error = 1;
     680              :       }
     681            0 :       return 0;
     682              :    } else {
     683            0 :       optimize(root);
     684            0 :       if (error)
     685            0 :          *error = 0;
     686            0 :       return root;
     687              :    }
     688              : }
     689              : 
     690            0 : double te_interp(const char *expression, int *error) {
     691            0 :    te_expr *n = te_compile(expression, 0, 0, error);
     692              :    double ret;
     693            0 :    if (n) {
     694            0 :       ret = te_eval(n);
     695            0 :       te_free(n);
     696              :    } else {
     697            0 :       ret = NAN;
     698              :    }
     699            0 :    return ret;
     700              : }
     701              : 
     702            0 : static void pn(const te_expr *n, int depth) {
     703              :    int i, arity;
     704            0 :    printf("%*s", depth, "");
     705              : 
     706            0 :    switch (TYPE_MASK(n->type)) {
     707            0 :       case TE_CONSTANT: printf("%f\n", n->value); break;
     708            0 :       case TE_VARIABLE: printf("bound %p\n", n->bound); break;
     709              : 
     710            0 :       case TE_FUNCTION0:
     711              :       case TE_FUNCTION1:
     712              :       case TE_FUNCTION2:
     713              :       case TE_FUNCTION3:
     714              :       case TE_FUNCTION4:
     715              :       case TE_FUNCTION5:
     716              :       case TE_FUNCTION6:
     717              :       case TE_FUNCTION7:
     718              :       case TE_CLOSURE0:
     719              :       case TE_CLOSURE1:
     720              :       case TE_CLOSURE2:
     721              :       case TE_CLOSURE3:
     722              :       case TE_CLOSURE4:
     723              :       case TE_CLOSURE5:
     724              :       case TE_CLOSURE6:
     725              :       case TE_CLOSURE7:
     726            0 :          arity = ARITY(n->type);
     727            0 :          printf("f%d", arity);
     728            0 :          for (i = 0; i < arity; i++) {
     729            0 :             printf(" %p", n->parameters[i]);
     730              :          }
     731            0 :          printf("\n");
     732            0 :          for (i = 0; i < arity; i++) {
     733            0 :             pn(n->parameters[i], depth + 1);
     734              :          }
     735            0 :          break;
     736              :    }
     737            0 : }
     738              : 
     739            0 : void te_print(const te_expr *n) {
     740            0 :    pn(n, 0);
     741            0 : }
        

Generated by: LCOV version 2.0-1