You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
11 KiB

  1. //
  2. // LolRemez — Remez algorithm implementation
  3. //
  4. // Copyright © 2005—2015 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // This program is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #pragma once
  13. //
  14. // Powerful arithmetic expression parser/evaluator
  15. //
  16. // Usage:
  17. // expression e;
  18. // e.parse(" 2*x^3 + 3 * sin(x - atan(x))");
  19. // auto y = e.eval("1.5");
  20. //
  21. #include "pegtl.hh"
  22. namespace grammar
  23. {
  24. using namespace pegtl;
  25. enum class op : uint8_t
  26. {
  27. /* Variables and constants */
  28. x,
  29. constant,
  30. /* Unary functions/operators */
  31. plus, minus, abs,
  32. sqrt, cbrt,
  33. exp, exp2, log, log2, log10,
  34. sin, cos, tan,
  35. asin, acos, atan,
  36. sinh, cosh, tanh,
  37. /* Binary functions/operators */
  38. add, sub, mul, div,
  39. atan2, pow,
  40. min, max,
  41. };
  42. // Map operation enums to pegl::string<> rules
  43. template<op OP> struct r_call_string {};
  44. template<> struct r_call_string<op::abs> : string<'a','b','s'> {};
  45. template<> struct r_call_string<op::sqrt> : string<'s','q','r','t'> {};
  46. template<> struct r_call_string<op::cbrt> : string<'c','b','r','t'> {};
  47. template<> struct r_call_string<op::exp> : string<'e','x','p'> {};
  48. template<> struct r_call_string<op::exp2> : string<'e','x','p','2'> {};
  49. template<> struct r_call_string<op::log> : string<'l','o','g'> {};
  50. template<> struct r_call_string<op::log2> : string<'l','o','g','2'> {};
  51. template<> struct r_call_string<op::log10> : string<'l','o','g','1','0'> {};
  52. template<> struct r_call_string<op::sin> : string<'s','i','n'> {};
  53. template<> struct r_call_string<op::cos> : string<'c','o','s'> {};
  54. template<> struct r_call_string<op::tan> : string<'t','a','n'> {};
  55. template<> struct r_call_string<op::asin> : string<'a','s','i','n'> {};
  56. template<> struct r_call_string<op::acos> : string<'a','c','o','s'> {};
  57. template<> struct r_call_string<op::atan> : string<'a','t','a','n'> {};
  58. template<> struct r_call_string<op::sinh> : string<'s','i','n','h'> {};
  59. template<> struct r_call_string<op::cosh> : string<'c','o','s','h'> {};
  60. template<> struct r_call_string<op::tanh> : string<'t','a','n','h'> {};
  61. template<> struct r_call_string<op::atan2> : string<'a','t','a','n','2'> {};
  62. template<> struct r_call_string<op::pow> : string<'p','o','w'> {};
  63. template<> struct r_call_string<op::min> : string<'m','i','n'> {};
  64. template<> struct r_call_string<op::max> : string<'m','a','x'> {};
  65. struct expression
  66. {
  67. /*
  68. * Parse arithmetic expression in x, e.g. 2*x+3
  69. */
  70. void parse(std::string const &str)
  71. {
  72. m_ops.empty();
  73. m_constants.empty();
  74. basic_parse_string<r_stmt>(str, this);
  75. }
  76. /*
  77. * Evaluate expression at x
  78. */
  79. lol::real eval(lol::real const &x) const
  80. {
  81. /* Use a stack */
  82. lol::array<lol::real> stack;
  83. for (int i = 0; i < m_ops.count(); ++i)
  84. {
  85. /* Rules that do not consume stack elements */
  86. if (m_ops[i].m1 == op::x)
  87. {
  88. stack.push(x);
  89. continue;
  90. }
  91. else if (m_ops[i].m1 == op::constant)
  92. {
  93. stack.push(m_constants[m_ops[i].m2]);
  94. continue;
  95. }
  96. /* All other rules consume at least the head of the stack */
  97. lol::real head = stack.pop();
  98. switch (m_ops[i].m1)
  99. {
  100. case op::plus: stack.push(head); break;
  101. case op::minus: stack.push(-head); break;
  102. case op::abs: stack.push(fabs(head)); break;
  103. case op::sqrt: stack.push(sqrt(head)); break;
  104. case op::cbrt: stack.push(cbrt(head)); break;
  105. case op::exp: stack.push(exp(head)); break;
  106. case op::exp2: stack.push(exp2(head)); break;
  107. case op::log: stack.push(log(head)); break;
  108. case op::log2: stack.push(log2(head)); break;
  109. case op::log10: stack.push(log10(head)); break;
  110. case op::sin: stack.push(sin(head)); break;
  111. case op::cos: stack.push(cos(head)); break;
  112. case op::tan: stack.push(tan(head)); break;
  113. case op::asin: stack.push(asin(head)); break;
  114. case op::acos: stack.push(acos(head)); break;
  115. case op::atan: stack.push(atan(head)); break;
  116. case op::sinh: stack.push(sinh(head)); break;
  117. case op::cosh: stack.push(cosh(head)); break;
  118. case op::tanh: stack.push(tanh(head)); break;
  119. case op::add: stack.push(stack.pop() + head); break;
  120. case op::sub: stack.push(stack.pop() - head); break;
  121. case op::mul: stack.push(stack.pop() * head); break;
  122. case op::div: stack.push(stack.pop() / head); break;
  123. case op::atan2: stack.push(atan2(stack.pop(), head)); break;
  124. case op::pow: stack.push(pow(stack.pop(), head)); break;
  125. case op::min: stack.push(min(stack.pop(), head)); break;
  126. case op::max: stack.push(max(stack.pop(), head)); break;
  127. case op::x:
  128. case op::constant:
  129. /* Already handled above */
  130. break;
  131. }
  132. }
  133. ASSERT(stack.count() == 1);
  134. return stack.pop();
  135. }
  136. private:
  137. lol::array<op, int> m_ops;
  138. lol::array<lol::real> m_constants;
  139. private:
  140. struct do_constant : action_base<do_constant>
  141. {
  142. static void apply(std::string const &ctx, expression *that)
  143. {
  144. /* FIXME: check if the constant is already in the list */
  145. that->m_ops.push(op::constant, that->m_constants.count());
  146. that->m_constants.push(lol::real(ctx.c_str()));
  147. }
  148. };
  149. template<op OP>
  150. struct do_op : action_base<do_op<OP>>
  151. {
  152. static void apply(std::string const &ctx, expression *that)
  153. {
  154. UNUSED(ctx);
  155. that->m_ops.push(OP, -1);
  156. }
  157. };
  158. struct r_expr;
  159. // r_ <- <blank> *
  160. struct _ : star<space> {};
  161. // r_call_unary <- <unary_op> "(" r_expr ")"
  162. template<op OP>
  163. struct r_call_unary : ifapply<seq<r_call_string<OP>,
  164. _,
  165. one<'('>,
  166. _,
  167. r_expr,
  168. _,
  169. one<')'>>,
  170. do_op<OP>> {};
  171. // r_call_binary <- <binary_op> "(" r_expr "," r_expr ")"
  172. template<op OP>
  173. struct r_call_binary : ifapply<seq<r_call_string<OP>,
  174. _,
  175. one<'('>,
  176. _,
  177. r_expr,
  178. _,
  179. one<','>,
  180. _,
  181. r_expr,
  182. _,
  183. one<')'>>,
  184. do_op<OP>> {};
  185. // r_constant <- <digit> + ( "." <digit> * ) ? ( [eE] [+-] ? <digit> + ) ?
  186. struct r_constant : ifapply<seq<plus<digit>,
  187. opt<seq<one<'.'>,
  188. star<digit>>>,
  189. opt<seq<one<'e', 'E'>,
  190. opt<one<'+', '-'>>,
  191. plus<digit>>>>,
  192. do_constant> {};
  193. // r_var <- "x"
  194. struct r_var : ifapply<one<'x'>, do_op<op::x>> {};
  195. // r_call <- r_call_unary / r_call_binary
  196. struct r_call : sor<r_call_unary<op::abs>,
  197. r_call_unary<op::sqrt>,
  198. r_call_unary<op::cbrt>,
  199. r_call_unary<op::exp>,
  200. r_call_unary<op::exp2>,
  201. r_call_unary<op::log>,
  202. r_call_unary<op::log2>,
  203. r_call_unary<op::log10>,
  204. r_call_unary<op::sin>,
  205. r_call_unary<op::cos>,
  206. r_call_unary<op::tan>,
  207. r_call_unary<op::asin>,
  208. r_call_unary<op::acos>,
  209. r_call_unary<op::atan>,
  210. r_call_unary<op::sinh>,
  211. r_call_unary<op::cosh>,
  212. r_call_unary<op::tanh>,
  213. r_call_binary<op::atan2>,
  214. r_call_binary<op::pow>,
  215. r_call_binary<op::min>,
  216. r_call_binary<op::max>> {};
  217. // r_parentheses <- "(" r_expr ")"
  218. struct r_parentheses : seq<one<'('>,
  219. _,
  220. r_expr,
  221. _,
  222. one<')'>> {};
  223. // r_terminal <- r_call / r_var / r_constant / r_parentheses
  224. struct r_terminal : sor<r_call,
  225. r_var,
  226. r_constant,
  227. r_parentheses> {};
  228. // r_signed <- "-" r_signed / "+" r_signed / r_terminal
  229. struct r_signed : sor<ifapply<seq<one<'-'>, _, r_signed>,
  230. do_op<op::minus>>,
  231. seq<one<'+'>, _, r_signed>,
  232. r_terminal> {};
  233. // r_exponent <- ( "^" / "**" ) r_signed
  234. struct r_exponent : ifapply<seq<_,
  235. sor<one<'^'>, string<'*', '*'>>,
  236. _,
  237. r_signed>, do_op<op::pow>> {};
  238. // r_factor <- r_signed ( r_exponent ) *
  239. struct r_factor : seq<r_signed,
  240. star<r_exponent>> {};
  241. // r_mul <- "*" r_factor
  242. // r_div <- "/" r_factor
  243. // r_term <- r_factor ( r_mul / r_div ) *
  244. struct r_mul : ifapply<seq<_, one<'*'>, _, r_factor>, do_op<op::mul>> {};
  245. struct r_div : ifapply<seq<_, one<'/'>, _, r_factor>, do_op<op::div>> {};
  246. struct r_term : seq<r_factor,
  247. star<sor<r_mul, r_div>>> {};
  248. // r_add <- "+" r_term
  249. // r_sub <- "-" r_term
  250. // r_expr <- r_term ( r_add / r_sub ) *
  251. struct r_add : ifapply<seq<_, one<'+'>, _, r_term>, do_op<op::add>> {};
  252. struct r_sub : ifapply<seq<_, one<'-'>, _, r_term>, do_op<op::sub>> {};
  253. struct r_expr : seq<r_term,
  254. star<sor<r_add, r_sub>>> {};
  255. // r_stmt <- r_expr <end>
  256. struct r_stmt : seq<_, r_expr, _, pegtl::eof> {};
  257. };
  258. } /* namespace grammar */
  259. using grammar::expression;