Advertisement
Guest User

0001-tinyexpr.patch

a guest
Dec 27th, 2016
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.31 KB | None | 0 0
  1. From 28b99b14c792ac16b1fe64aab476bf20de58bcf6 Mon Sep 17 00:00:00 2001
  2. From: Dmitriy Dyomin <dmitrodem@gmail.com>
  3. Date: Thu, 22 Dec 2016 02:24:24 +0300
  4. Subject: [PATCH] tinyexpr
  5.  
  6. ---
  7. common/CMakeLists.txt | 1 +
  8. common/base_units.cpp | 56 +----
  9. common/tinyexpr.c | 615 ++++++++++++++++++++++++++++++++++++++++++++++++++
  10. include/tinyexpr.h | 86 +++++++
  11. 4 files changed, 708 insertions(+), 50 deletions(-)
  12. create mode 100644 common/tinyexpr.c
  13. create mode 100644 include/tinyexpr.h
  14.  
  15. diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
  16. index da08d2b..7dd6c14 100644
  17. --- a/common/CMakeLists.txt
  18. +++ b/common/CMakeLists.txt
  19. @@ -265,6 +265,7 @@ set( COMMON_SRCS
  20. wx_status_popup.cpp
  21. xnode.cpp
  22. zoom.cpp
  23. + tinyexpr.c
  24. )
  25.  
  26. if( TRUE OR NOT USE_KIWAY_DLLS )
  27. diff --git a/common/base_units.cpp b/common/base_units.cpp
  28. index bd03bcf..7a1330d 100644
  29. --- a/common/base_units.cpp
  30. +++ b/common/base_units.cpp
  31. @@ -39,7 +39,7 @@
  32. #include <class_title_block.h>
  33. #include <common.h>
  34. #include <base_units.h>
  35. -
  36. +#include <tinyexpr.h>
  37.  
  38. #if defined( PCBNEW ) || defined( CVPCB ) || defined( EESCHEMA ) || defined( GERBVIEW ) || defined( PL_EDITOR )
  39. #define IU_TO_MM( x ) ( x / IU_PER_MM )
  40. @@ -301,7 +301,8 @@ double From_User_Unit( EDA_UNITS_T aUnit, double aValue )
  41. double DoubleValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue )
  42. {
  43. double value;
  44. - double dtmp = 0;
  45. + int error;
  46. + double te_value;
  47.  
  48. // Acquire the 'right' decimal point separator
  49. const struct lconv* lc = localeconv();
  50. @@ -312,54 +313,9 @@ double DoubleValueFromString( EDA_UNITS_T aUnits, const wxString& aTextValue )
  51. // Convert the period in decimal point
  52. buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
  53.  
  54. - // Find the end of the numeric part
  55. - unsigned brk_point = 0;
  56. -
  57. - while( brk_point < buf.Len() )
  58. - {
  59. - wxChar ch = buf[brk_point];
  60. -
  61. - if( !( (ch >= '0' && ch <='9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
  62. - {
  63. - break;
  64. - }
  65. -
  66. - ++brk_point;
  67. - }
  68. -
  69. - // Extract the numeric part
  70. - buf.Left( brk_point );
  71. -
  72. - buf.ToDouble( &dtmp );
  73. -
  74. - // Check the optional unit designator (2 ch significant)
  75. - wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
  76. -
  77. - if( aUnits == INCHES || aUnits == MILLIMETRES )
  78. - {
  79. - if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
  80. - {
  81. - aUnits = INCHES;
  82. - }
  83. - else if( unit == wxT( "mm" ) )
  84. - {
  85. - aUnits = MILLIMETRES;
  86. - }
  87. - else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // Mils or thous
  88. - {
  89. - aUnits = INCHES;
  90. - dtmp /= 1000;
  91. - }
  92. - }
  93. - else if( aUnits == DEGREES )
  94. - {
  95. - if( unit == wxT( "ra" ) ) // Radians
  96. - {
  97. - dtmp *= 180.0f / M_PI;
  98. - }
  99. - }
  100. -
  101. - value = From_User_Unit( aUnits, dtmp );
  102. + te_value = te_interp((const char *) buf.mb_str(), &error);
  103. + wxCHECK_MSG(error == 0, NAN, wxT("Failed to parse expression"));
  104. + value = From_User_Unit( aUnits, te_value );
  105.  
  106. return value;
  107. }
  108. diff --git a/common/tinyexpr.c b/common/tinyexpr.c
  109. new file mode 100644
  110. index 0000000..6c3cb7a
  111. --- /dev/null
  112. +++ b/common/tinyexpr.c
  113. @@ -0,0 +1,615 @@
  114. +/*
  115. + * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
  116. + *
  117. + * Copyright (c) 2015, 2016 Lewis Van Winkle
  118. + *
  119. + * http://CodePlea.com
  120. + *
  121. + * This software is provided 'as-is', without any express or implied
  122. + * warranty. In no event will the authors be held liable for any damages
  123. + * arising from the use of this software.
  124. + *
  125. + * Permission is granted to anyone to use this software for any purpose,
  126. + * including commercial applications, and to alter it and redistribute it
  127. + * freely, subject to the following restrictions:
  128. + *
  129. + * 1. The origin of this software must not be misrepresented; you must not
  130. + * claim that you wrote the original software. If you use this software
  131. + * in a product, an acknowledgement in the product documentation would be
  132. + * appreciated but is not required.
  133. + * 2. Altered source versions must be plainly marked as such, and must not be
  134. + * misrepresented as being the original software.
  135. + * 3. This notice may not be removed or altered from any source distribution.
  136. + */
  137. +
  138. +/* COMPILE TIME OPTIONS */
  139. +
  140. +/* Exponentiation associativity:
  141. +For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing.
  142. +For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/
  143. +/* #define TE_POW_FROM_RIGHT */
  144. +
  145. +/* Logarithms
  146. +For log = base 10 log do nothing
  147. +For log = natural log uncomment the next line. */
  148. +/* #define TE_NAT_LOG */
  149. +
  150. +#include "tinyexpr.h"
  151. +#include <stdlib.h>
  152. +#include <math.h>
  153. +#include <string.h>
  154. +#include <stdio.h>
  155. +
  156. +#ifndef NAN
  157. +#define NAN (0.0/0.0)
  158. +#endif
  159. +
  160. +typedef double (*te_fun2)(double, double);
  161. +
  162. +enum {
  163. + TOK_NULL = TE_CLOSURE7+1, TOK_ERROR, TOK_END, TOK_SEP,
  164. + TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_VARIABLE, TOK_INFIX
  165. +};
  166. +
  167. +
  168. +enum {TE_CONSTANT = 1};
  169. +
  170. +
  171. +typedef struct state {
  172. + const char *start;
  173. + const char *next;
  174. + int type;
  175. + union {double value; const double *bound; const void *function;};
  176. + void *context;
  177. +
  178. + const te_variable *lookup;
  179. + int lookup_len;
  180. +} state;
  181. +
  182. +
  183. +#define TYPE_MASK(TYPE) ((TYPE)&0x0000001F)
  184. +
  185. +#define IS_PURE(TYPE) (((TYPE) & TE_FLAG_PURE) != 0)
  186. +#define IS_FUNCTION(TYPE) (((TYPE) & TE_FUNCTION0) != 0)
  187. +#define IS_CLOSURE(TYPE) (((TYPE) & TE_CLOSURE0) != 0)
  188. +#define ARITY(TYPE) ( ((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) & 0x00000007) : 0 )
  189. +#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__})
  190. +
  191. +static te_expr *new_expr(const int type, const te_expr *parameters[]) {
  192. + const int arity = ARITY(type);
  193. + const int psize = sizeof(void*) * arity;
  194. + const int size = (sizeof(te_expr) - sizeof(void*)) + psize + (IS_CLOSURE(type) ? sizeof(void*) : 0);
  195. + te_expr *ret = malloc(size);
  196. + memset(ret, 0, size);
  197. + if (arity && parameters) {
  198. + memcpy(ret->parameters, parameters, psize);
  199. + }
  200. + ret->type = type;
  201. + ret->bound = 0;
  202. + return ret;
  203. +}
  204. +
  205. +
  206. +void te_free_parameters(te_expr *n) {
  207. + if (!n) return;
  208. + switch (TYPE_MASK(n->type)) {
  209. + case TE_FUNCTION7: case TE_CLOSURE7: te_free(n->parameters[6]);
  210. + case TE_FUNCTION6: case TE_CLOSURE6: te_free(n->parameters[5]);
  211. + case TE_FUNCTION5: case TE_CLOSURE5: te_free(n->parameters[4]);
  212. + case TE_FUNCTION4: case TE_CLOSURE4: te_free(n->parameters[3]);
  213. + case TE_FUNCTION3: case TE_CLOSURE3: te_free(n->parameters[2]);
  214. + case TE_FUNCTION2: case TE_CLOSURE2: te_free(n->parameters[1]);
  215. + case TE_FUNCTION1: case TE_CLOSURE1: te_free(n->parameters[0]);
  216. + }
  217. +}
  218. +
  219. +
  220. +void te_free(te_expr *n) {
  221. + if (!n) return;
  222. + te_free_parameters(n);
  223. + free(n);
  224. +}
  225. +
  226. +
  227. +static double pi() {return 3.14159265358979323846;}
  228. +static double e() {return 2.71828182845904523536;}
  229. +
  230. +static const te_variable functions[] = {
  231. + /* must be in alphabetical order */
  232. + {"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE},
  233. + {"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE},
  234. + {"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE},
  235. + {"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE},
  236. + {"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE},
  237. + {"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE},
  238. + {"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE},
  239. + {"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE},
  240. + {"e", e, TE_FUNCTION0 | TE_FLAG_PURE},
  241. + {"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE},
  242. + {"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE},
  243. + {"ln", log, TE_FUNCTION1 | TE_FLAG_PURE},
  244. +#ifdef TE_NAT_LOG
  245. + {"log", log, TE_FUNCTION1 | TE_FLAG_PURE},
  246. +#else
  247. + {"log", log10, TE_FUNCTION1 | TE_FLAG_PURE},
  248. +#endif
  249. + {"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE},
  250. + {"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE},
  251. + {"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE},
  252. + {"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE},
  253. + {"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE},
  254. + {"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE},
  255. + {"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE},
  256. + {"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE},
  257. + {0}
  258. +};
  259. +
  260. +static const te_variable *find_builtin(const char *name, int len) {
  261. + int imin = 0;
  262. + int imax = sizeof(functions) / sizeof(te_variable) - 2;
  263. +
  264. + /*Binary search.*/
  265. + while (imax >= imin) {
  266. + const int i = (imin + ((imax-imin)/2));
  267. + int c = strncmp(name, functions[i].name, len);
  268. + if (!c) c = '\0' - functions[i].name[len];
  269. + if (c == 0) {
  270. + return functions + i;
  271. + } else if (c > 0) {
  272. + imin = i + 1;
  273. + } else {
  274. + imax = i - 1;
  275. + }
  276. + }
  277. +
  278. + return 0;
  279. +}
  280. +
  281. +static const te_variable *find_lookup(const state *s, const char *name, int len) {
  282. + int iters;
  283. + const te_variable *var;
  284. + if (!s->lookup) return 0;
  285. +
  286. + for (var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) {
  287. + if (strncmp(name, var->name, len) == 0 && var->name[len] == '\0') {
  288. + return var;
  289. + }
  290. + }
  291. + return 0;
  292. +}
  293. +
  294. +
  295. +
  296. +static double add(double a, double b) {return a + b;}
  297. +static double sub(double a, double b) {return a - b;}
  298. +static double mul(double a, double b) {return a * b;}
  299. +static double divide(double a, double b) {return a / b;}
  300. +static double negate(double a) {return -a;}
  301. +static double comma(double a, double b) {return b;}
  302. +
  303. +
  304. +void next_token(state *s) {
  305. + s->type = TOK_NULL;
  306. +
  307. + do {
  308. +
  309. + if (!*s->next){
  310. + s->type = TOK_END;
  311. + return;
  312. + }
  313. +
  314. + /* Try reading a number. */
  315. + if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
  316. + s->value = strtod(s->next, (char**)&s->next);
  317. + s->type = TOK_NUMBER;
  318. + } else {
  319. + /* Look for a variable or builtin function call. */
  320. + if (s->next[0] >= 'a' && s->next[0] <= 'z') {
  321. + const char *start;
  322. + start = s->next;
  323. + while ((s->next[0] >= 'a' && s->next[0] <= 'z') || (s->next[0] >= '0' && s->next[0] <= '9') || (s->next[0] == '_')) s->next++;
  324. +
  325. + const te_variable *var = find_lookup(s, start, s->next - start);
  326. + if (!var) var = find_builtin(start, s->next - start);
  327. +
  328. + if (!var) {
  329. + s->type = TOK_ERROR;
  330. + } else {
  331. + switch(TYPE_MASK(var->type))
  332. + {
  333. + case TE_VARIABLE:
  334. + s->type = TOK_VARIABLE;
  335. + s->bound = var->address;
  336. + break;
  337. +
  338. + case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
  339. + case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
  340. + s->context = var->context;
  341. +
  342. + case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
  343. + case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
  344. + s->type = var->type;
  345. + s->function = var->address;
  346. + break;
  347. + }
  348. + }
  349. +
  350. + } else {
  351. + /* Look for an operator or special character. */
  352. + switch (s->next++[0]) {
  353. + case '+': s->type = TOK_INFIX; s->function = add; break;
  354. + case '-': s->type = TOK_INFIX; s->function = sub; break;
  355. + case '*': s->type = TOK_INFIX; s->function = mul; break;
  356. + case '/': s->type = TOK_INFIX; s->function = divide; break;
  357. + case '^': s->type = TOK_INFIX; s->function = pow; break;
  358. + case '%': s->type = TOK_INFIX; s->function = fmod; break;
  359. + case '(': s->type = TOK_OPEN; break;
  360. + case ')': s->type = TOK_CLOSE; break;
  361. + case ',': s->type = TOK_SEP; break;
  362. + case ' ': case '\t': case '\n': case '\r': break;
  363. + default: s->type = TOK_ERROR; break;
  364. + }
  365. + }
  366. + }
  367. + } while (s->type == TOK_NULL);
  368. +}
  369. +
  370. +
  371. +static te_expr *list(state *s);
  372. +static te_expr *expr(state *s);
  373. +static te_expr *power(state *s);
  374. +
  375. +static te_expr *base(state *s) {
  376. + /* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
  377. + te_expr *ret;
  378. + int arity;
  379. +
  380. + switch (TYPE_MASK(s->type)) {
  381. + case TOK_NUMBER:
  382. + ret = new_expr(TE_CONSTANT, 0);
  383. + ret->value = s->value;
  384. + next_token(s);
  385. + break;
  386. +
  387. + case TOK_VARIABLE:
  388. + ret = new_expr(TE_VARIABLE, 0);
  389. + ret->bound = s->bound;
  390. + next_token(s);
  391. + break;
  392. +
  393. + case TE_FUNCTION0:
  394. + case TE_CLOSURE0:
  395. + ret = new_expr(s->type, 0);
  396. + ret->function = s->function;
  397. + if (IS_CLOSURE(s->type)) ret->parameters[0] = s->context;
  398. + next_token(s);
  399. + if (s->type == TOK_OPEN) {
  400. + next_token(s);
  401. + if (s->type != TOK_CLOSE) {
  402. + s->type = TOK_ERROR;
  403. + } else {
  404. + next_token(s);
  405. + }
  406. + }
  407. + break;
  408. +
  409. + case TE_FUNCTION1:
  410. + case TE_CLOSURE1:
  411. + ret = new_expr(s->type, 0);
  412. + ret->function = s->function;
  413. + if (IS_CLOSURE(s->type)) ret->parameters[1] = s->context;
  414. + next_token(s);
  415. + ret->parameters[0] = power(s);
  416. + break;
  417. +
  418. + case TE_FUNCTION2: case TE_FUNCTION3: case TE_FUNCTION4:
  419. + case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
  420. + case TE_CLOSURE2: case TE_CLOSURE3: case TE_CLOSURE4:
  421. + case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
  422. + arity = ARITY(s->type);
  423. +
  424. + ret = new_expr(s->type, 0);
  425. + ret->function = s->function;
  426. + if (IS_CLOSURE(s->type)) ret->parameters[arity] = s->context;
  427. + next_token(s);
  428. +
  429. + if (s->type != TOK_OPEN) {
  430. + s->type = TOK_ERROR;
  431. + } else {
  432. + int i;
  433. + for(i = 0; i < arity; i++) {
  434. + next_token(s);
  435. + ret->parameters[i] = expr(s);
  436. + if(s->type != TOK_SEP) {
  437. + break;
  438. + }
  439. + }
  440. + if(s->type != TOK_CLOSE || i != arity - 1) {
  441. + s->type = TOK_ERROR;
  442. + } else {
  443. + next_token(s);
  444. + }
  445. + }
  446. +
  447. + break;
  448. +
  449. + case TOK_OPEN:
  450. + next_token(s);
  451. + ret = list(s);
  452. + if (s->type != TOK_CLOSE) {
  453. + s->type = TOK_ERROR;
  454. + } else {
  455. + next_token(s);
  456. + }
  457. + break;
  458. +
  459. + default:
  460. + ret = new_expr(0, 0);
  461. + s->type = TOK_ERROR;
  462. + ret->value = NAN;
  463. + break;
  464. + }
  465. +
  466. + return ret;
  467. +}
  468. +
  469. +
  470. +static te_expr *power(state *s) {
  471. + /* <power> = {("-" | "+")} <base> */
  472. + int sign = 1;
  473. + while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
  474. + if (s->function == sub) sign = -sign;
  475. + next_token(s);
  476. + }
  477. +
  478. + te_expr *ret;
  479. +
  480. + if (sign == 1) {
  481. + ret = base(s);
  482. + } else {
  483. + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s));
  484. + ret->function = negate;
  485. + }
  486. +
  487. + return ret;
  488. +}
  489. +
  490. +#ifdef TE_POW_FROM_RIGHT
  491. +static te_expr *factor(state *s) {
  492. + /* <factor> = <power> {"^" <power>} */
  493. + te_expr *ret = power(s);
  494. +
  495. + int neg = 0;
  496. + te_expr *insertion = 0;
  497. +
  498. + if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) {
  499. + te_expr *se = ret->parameters[0];
  500. + free(ret);
  501. + ret = se;
  502. + neg = 1;
  503. + }
  504. +
  505. + while (s->type == TOK_INFIX && (s->function == pow)) {
  506. + te_fun2 t = s->function;
  507. + next_token(s);
  508. +
  509. + if (insertion) {
  510. + /* Make exponentiation go right-to-left. */
  511. + te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s));
  512. + insert->function = t;
  513. + insertion->parameters[1] = insert;
  514. + insertion = insert;
  515. + } else {
  516. + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
  517. + ret->function = t;
  518. + insertion = ret;
  519. + }
  520. + }
  521. +
  522. + if (neg) {
  523. + ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret);
  524. + ret->function = negate;
  525. + }
  526. +
  527. + return ret;
  528. +}
  529. +#else
  530. +static te_expr *factor(state *s) {
  531. + /* <factor> = <power> {"^" <power>} */
  532. + te_expr *ret = power(s);
  533. +
  534. + while (s->type == TOK_INFIX && (s->function == pow)) {
  535. + te_fun2 t = s->function;
  536. + next_token(s);
  537. + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s));
  538. + ret->function = t;
  539. + }
  540. +
  541. + return ret;
  542. +}
  543. +#endif
  544. +
  545. +
  546. +
  547. +static te_expr *term(state *s) {
  548. + /* <term> = <factor> {("*" | "/" | "%") <factor>} */
  549. + te_expr *ret = factor(s);
  550. +
  551. + while (s->type == TOK_INFIX && (s->function == mul || s->function == divide || s->function == fmod)) {
  552. + te_fun2 t = s->function;
  553. + next_token(s);
  554. + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s));
  555. + ret->function = t;
  556. + }
  557. +
  558. + return ret;
  559. +}
  560. +
  561. +
  562. +static te_expr *expr(state *s) {
  563. + /* <expr> = <term> {("+" | "-") <term>} */
  564. + te_expr *ret = term(s);
  565. +
  566. + while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
  567. + te_fun2 t = s->function;
  568. + next_token(s);
  569. + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s));
  570. + ret->function = t;
  571. + }
  572. +
  573. + return ret;
  574. +}
  575. +
  576. +
  577. +static te_expr *list(state *s) {
  578. + /* <list> = <expr> {"," <expr>} */
  579. + te_expr *ret = expr(s);
  580. +
  581. + while (s->type == TOK_SEP) {
  582. + next_token(s);
  583. + ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s));
  584. + ret->function = comma;
  585. + }
  586. +
  587. + return ret;
  588. +}
  589. +
  590. +
  591. +#define TE_FUN(...) ((double(*)(__VA_ARGS__))n->function)
  592. +#define M(e) te_eval(n->parameters[e])
  593. +
  594. +
  595. +double te_eval(const te_expr *n) {
  596. + if (!n) return NAN;
  597. +
  598. + switch(TYPE_MASK(n->type)) {
  599. + case TE_CONSTANT: return n->value;
  600. + case TE_VARIABLE: return *n->bound;
  601. +
  602. + case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
  603. + case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
  604. + switch(ARITY(n->type)) {
  605. + case 0: return TE_FUN(void)();
  606. + case 1: return TE_FUN(double)(M(0));
  607. + case 2: return TE_FUN(double, double)(M(0), M(1));
  608. + case 3: return TE_FUN(double, double, double)(M(0), M(1), M(2));
  609. + case 4: return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3));
  610. + case 5: return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4));
  611. + case 6: return TE_FUN(double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5));
  612. + 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));
  613. + default: return NAN;
  614. + }
  615. +
  616. + case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
  617. + case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
  618. + switch(ARITY(n->type)) {
  619. + case 0: return TE_FUN(void*)(n->parameters[0]);
  620. + case 1: return TE_FUN(void*, double)(n->parameters[1], M(0));
  621. + case 2: return TE_FUN(void*, double, double)(n->parameters[2], M(0), M(1));
  622. + case 3: return TE_FUN(void*, double, double, double)(n->parameters[3], M(0), M(1), M(2));
  623. + case 4: return TE_FUN(void*, double, double, double, double)(n->parameters[4], M(0), M(1), M(2), M(3));
  624. + case 5: return TE_FUN(void*, double, double, double, double, double)(n->parameters[5], M(0), M(1), M(2), M(3), M(4));
  625. + 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));
  626. + 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));
  627. + default: return NAN;
  628. + }
  629. +
  630. + default: return NAN;
  631. + }
  632. +
  633. +}
  634. +
  635. +#undef TE_FUN
  636. +#undef M
  637. +
  638. +static void optimize(te_expr *n) {
  639. + /* Evaluates as much as possible. */
  640. + if (n->type == TE_CONSTANT) return;
  641. + if (n->type == TE_VARIABLE) return;
  642. +
  643. + /* Only optimize out functions flagged as pure. */
  644. + if (IS_PURE(n->type)) {
  645. + const int arity = ARITY(n->type);
  646. + int known = 1;
  647. + int i;
  648. + for (i = 0; i < arity; ++i) {
  649. + optimize(n->parameters[i]);
  650. + if (((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) {
  651. + known = 0;
  652. + }
  653. + }
  654. + if (known) {
  655. + const double value = te_eval(n);
  656. + te_free_parameters(n);
  657. + n->type = TE_CONSTANT;
  658. + n->value = value;
  659. + }
  660. + }
  661. +}
  662. +
  663. +
  664. +te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) {
  665. + state s;
  666. + s.start = s.next = expression;
  667. + s.lookup = variables;
  668. + s.lookup_len = var_count;
  669. +
  670. + next_token(&s);
  671. + te_expr *root = list(&s);
  672. +
  673. + if (s.type != TOK_END) {
  674. + te_free(root);
  675. + if (error) {
  676. + *error = (s.next - s.start);
  677. + if (*error == 0) *error = 1;
  678. + }
  679. + return 0;
  680. + } else {
  681. + optimize(root);
  682. + if (error) *error = 0;
  683. + return root;
  684. + }
  685. +}
  686. +
  687. +
  688. +double te_interp(const char *expression, int *error) {
  689. + te_expr *n = te_compile(expression, 0, 0, error);
  690. + double ret;
  691. + if (n) {
  692. + ret = te_eval(n);
  693. + te_free(n);
  694. + } else {
  695. + ret = NAN;
  696. + }
  697. + return ret;
  698. +}
  699. +
  700. +static void pn (const te_expr *n, int depth) {
  701. + int i, arity;
  702. + printf("%*s", depth, "");
  703. +
  704. + switch(TYPE_MASK(n->type)) {
  705. + case TE_CONSTANT: printf("%f\n", n->value); break;
  706. + case TE_VARIABLE: printf("bound %p\n", n->bound); break;
  707. +
  708. + case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
  709. + case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
  710. + case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
  711. + case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
  712. + arity = ARITY(n->type);
  713. + printf("f%d", arity);
  714. + for(i = 0; i < arity; i++) {
  715. + printf(" %p", n->parameters[i]);
  716. + }
  717. + printf("\n");
  718. + for(i = 0; i < arity; i++) {
  719. + pn(n->parameters[i], depth + 1);
  720. + }
  721. + break;
  722. + }
  723. +}
  724. +
  725. +
  726. +void te_print(const te_expr *n) {
  727. + pn(n, 0);
  728. +}
  729. diff --git a/include/tinyexpr.h b/include/tinyexpr.h
  730. new file mode 100644
  731. index 0000000..5d0dc0c
  732. --- /dev/null
  733. +++ b/include/tinyexpr.h
  734. @@ -0,0 +1,86 @@
  735. +/*
  736. + * TINYEXPR - Tiny recursive descent parser and evaluation engine in C
  737. + *
  738. + * Copyright (c) 2015, 2016 Lewis Van Winkle
  739. + *
  740. + * http://CodePlea.com
  741. + *
  742. + * This software is provided 'as-is', without any express or implied
  743. + * warranty. In no event will the authors be held liable for any damages
  744. + * arising from the use of this software.
  745. + *
  746. + * Permission is granted to anyone to use this software for any purpose,
  747. + * including commercial applications, and to alter it and redistribute it
  748. + * freely, subject to the following restrictions:
  749. + *
  750. + * 1. The origin of this software must not be misrepresented; you must not
  751. + * claim that you wrote the original software. If you use this software
  752. + * in a product, an acknowledgement in the product documentation would be
  753. + * appreciated but is not required.
  754. + * 2. Altered source versions must be plainly marked as such, and must not be
  755. + * misrepresented as being the original software.
  756. + * 3. This notice may not be removed or altered from any source distribution.
  757. + */
  758. +
  759. +#ifndef __TINYEXPR_H__
  760. +#define __TINYEXPR_H__
  761. +
  762. +
  763. +#ifdef __cplusplus
  764. +extern "C" {
  765. +#endif
  766. +
  767. +
  768. +
  769. +typedef struct te_expr {
  770. + int type;
  771. + union {double value; const double *bound; const void *function;};
  772. + void *parameters[1];
  773. +} te_expr;
  774. +
  775. +
  776. +enum {
  777. + TE_VARIABLE = 0,
  778. +
  779. + TE_FUNCTION0 = 8, TE_FUNCTION1, TE_FUNCTION2, TE_FUNCTION3,
  780. + TE_FUNCTION4, TE_FUNCTION5, TE_FUNCTION6, TE_FUNCTION7,
  781. +
  782. + TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3,
  783. + TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7,
  784. +
  785. + TE_FLAG_PURE = 32
  786. +};
  787. +
  788. +typedef struct te_variable {
  789. + const char *name;
  790. + const void *address;
  791. + int type;
  792. + void *context;
  793. +} te_variable;
  794. +
  795. +
  796. +
  797. +/* Parses the input expression, evaluates it, and frees it. */
  798. +/* Returns NaN on error. */
  799. +double te_interp(const char *expression, int *error);
  800. +
  801. +/* Parses the input expression and binds variables. */
  802. +/* Returns NULL on error. */
  803. +te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error);
  804. +
  805. +/* Evaluates the expression. */
  806. +double te_eval(const te_expr *n);
  807. +
  808. +/* Prints debugging information on the syntax tree. */
  809. +void te_print(const te_expr *n);
  810. +
  811. +/* Frees the expression. */
  812. +/* This is safe to call on NULL pointers. */
  813. +void te_free(te_expr *n);
  814. +
  815. +
  816. +#ifdef __cplusplus
  817. +}
  818. +#endif
  819. +
  820. +#endif /*__TINYEXPR_H__*/
  821. --
  822. 2.10.2
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement