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.
 
 
 

316 lines
10 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. // Parser tools for a simple calculator grammar with + - * /
  15. //
  16. #include "pegtl.hh"
  17. namespace grammar
  18. {
  19. using namespace pegtl;
  20. enum class op : uint8_t
  21. {
  22. /* Variables and constants */
  23. x,
  24. constant,
  25. /* Unary functions/operators */
  26. plus, minus,
  27. sqrt, cbrt,
  28. exp, exp2, log, log2, log10,
  29. sin, cos, tan,
  30. asin, acos, atan,
  31. sinh, cosh, tanh,
  32. /* Binary functions/operators */
  33. add, sub, mul, div,
  34. atan2, pow,
  35. min, max,
  36. };
  37. // Map operation enums to pegl::string<> rules
  38. template<op OP> struct r_call_string {};
  39. template<> struct r_call_string<op::sqrt> : string<'s','q','r','t'> {};
  40. template<> struct r_call_string<op::cbrt> : string<'c','b','r','t'> {};
  41. template<> struct r_call_string<op::exp> : string<'e','x','p'> {};
  42. template<> struct r_call_string<op::exp2> : string<'e','x','p','2'> {};
  43. template<> struct r_call_string<op::log> : string<'l','o','g'> {};
  44. template<> struct r_call_string<op::log2> : string<'l','o','g','2'> {};
  45. template<> struct r_call_string<op::log10> : string<'l','o','g','1','0'> {};
  46. template<> struct r_call_string<op::sin> : string<'s','i','n'> {};
  47. template<> struct r_call_string<op::cos> : string<'c','o','s'> {};
  48. template<> struct r_call_string<op::tan> : string<'t','a','n'> {};
  49. template<> struct r_call_string<op::asin> : string<'a','s','i','n'> {};
  50. template<> struct r_call_string<op::acos> : string<'a','c','o','s'> {};
  51. template<> struct r_call_string<op::atan> : string<'a','t','a','n'> {};
  52. template<> struct r_call_string<op::sinh> : string<'s','i','n','h'> {};
  53. template<> struct r_call_string<op::cosh> : string<'c','o','s','h'> {};
  54. template<> struct r_call_string<op::tanh> : string<'t','a','n','h'> {};
  55. template<> struct r_call_string<op::atan2> : string<'a','t','a','n','2'> {};
  56. template<> struct r_call_string<op::pow> : string<'p','o','w'> {};
  57. template<> struct r_call_string<op::min> : string<'m','i','n'> {};
  58. template<> struct r_call_string<op::max> : string<'m','a','x'> {};
  59. struct expression
  60. {
  61. /*
  62. * Parse arithmetic expression in x, e.g. 2*x+3
  63. */
  64. void parse(std::string const &str)
  65. {
  66. m_ops.Empty();
  67. m_constants.Empty();
  68. basic_parse_string<r_stmt>(str, this);
  69. }
  70. /*
  71. * Evaluate expression at x
  72. */
  73. lol::real eval(lol::real const &x)
  74. {
  75. lol::array<lol::real> stack;
  76. lol::real tmp;
  77. for (int i = 0; i < m_ops.Count(); ++i)
  78. {
  79. switch (m_ops[i].m1)
  80. {
  81. case op::plus:
  82. break;
  83. case op::minus:
  84. stack.Push(-stack.Pop());
  85. break;
  86. case op::sqrt:
  87. stack.Push(sqrt(stack.Pop()));
  88. break;
  89. case op::cbrt:
  90. stack.Push(cbrt(stack.Pop()));
  91. break;
  92. case op::exp:
  93. stack.Push(exp(stack.Pop()));
  94. break;
  95. case op::exp2:
  96. stack.Push(exp2(stack.Pop()));
  97. break;
  98. case op::log:
  99. stack.Push(log(stack.Pop()));
  100. break;
  101. case op::log2:
  102. stack.Push(log2(stack.Pop()));
  103. break;
  104. case op::log10:
  105. stack.Push(log10(stack.Pop()));
  106. break;
  107. case op::sin:
  108. stack.Push(sin(stack.Pop()));
  109. break;
  110. case op::cos:
  111. stack.Push(cos(stack.Pop()));
  112. break;
  113. case op::tan:
  114. stack.Push(tan(stack.Pop()));
  115. break;
  116. case op::asin:
  117. stack.Push(asin(stack.Pop()));
  118. break;
  119. case op::acos:
  120. stack.Push(acos(stack.Pop()));
  121. break;
  122. case op::atan:
  123. stack.Push(atan(stack.Pop()));
  124. break;
  125. case op::sinh:
  126. stack.Push(sinh(stack.Pop()));
  127. break;
  128. case op::cosh:
  129. stack.Push(cosh(stack.Pop()));
  130. break;
  131. case op::tanh:
  132. stack.Push(tanh(stack.Pop()));
  133. break;
  134. case op::add:
  135. tmp = stack.Pop();
  136. stack.Push(stack.Pop() + tmp);
  137. break;
  138. case op::sub:
  139. tmp = stack.Pop();
  140. stack.Push(stack.Pop() - tmp);
  141. break;
  142. case op::mul:
  143. tmp = stack.Pop();
  144. stack.Push(stack.Pop() * tmp);
  145. break;
  146. case op::div:
  147. tmp = stack.Pop();
  148. stack.Push(stack.Pop() / tmp);
  149. break;
  150. case op::atan2:
  151. tmp = stack.Pop();
  152. stack.Push(atan2(stack.Pop(), tmp));
  153. break;
  154. case op::pow:
  155. tmp = stack.Pop();
  156. stack.Push(pow(stack.Pop(), tmp));
  157. break;
  158. case op::min:
  159. tmp = stack.Pop();
  160. stack.Push(min(stack.Pop(), tmp));
  161. break;
  162. case op::max:
  163. tmp = stack.Pop();
  164. stack.Push(max(stack.Pop(), tmp));
  165. break;
  166. case op::x:
  167. stack.Push(x);
  168. break;
  169. case op::constant:
  170. stack.Push(m_constants[m_ops[i].m2]);
  171. break;
  172. }
  173. }
  174. return stack.Pop();
  175. }
  176. private:
  177. lol::array<op, int> m_ops;
  178. lol::array<lol::real> m_constants;
  179. private:
  180. struct do_constant : action_base<do_constant>
  181. {
  182. static void apply(std::string const &ctx, expression *that)
  183. {
  184. /* FIXME: check if the constant is already in the list */
  185. that->m_ops.Push(op::constant, that->m_constants.Count());
  186. that->m_constants.Push(lol::real(ctx.c_str()));
  187. }
  188. };
  189. template<op OP>
  190. struct do_op : action_base<do_op<OP>>
  191. {
  192. static void apply(std::string const &ctx, expression *that)
  193. {
  194. UNUSED(ctx);
  195. that->m_ops.Push(OP, -1);
  196. }
  197. };
  198. struct do_success : action_base<do_success>
  199. {
  200. static void apply(std::string const &ctx, expression *that)
  201. {
  202. UNUSED(ctx, that);
  203. }
  204. };
  205. struct r_expr;
  206. // Rule for unary function calls
  207. template<op OP>
  208. struct r_call_unary : ifapply<seq<r_call_string<OP>,
  209. one<'('>,
  210. r_expr,
  211. one<')'>>,
  212. do_op<OP>> {};
  213. // Rule for binary function calls
  214. template<op OP>
  215. struct r_call_binary : ifapply<seq<r_call_string<OP>,
  216. one<'('>,
  217. r_expr,
  218. one<','>,
  219. r_expr,
  220. one<')'>>,
  221. do_op<OP>> {};
  222. // r_constant <- <digit> +
  223. struct r_constant : ifapply<plus<digit>, do_constant> {};
  224. // r_var <- "x"
  225. struct r_var : ifapply<one<'x'>, do_op<op::x>> {};
  226. // r_call <- <unary_op> "(" r_expr ")"
  227. // / <binary_op> "(" r_expr "," r_expr ")"
  228. struct r_call : sor<r_call_unary<op::sqrt>,
  229. r_call_unary<op::cbrt>,
  230. r_call_unary<op::exp>,
  231. r_call_unary<op::exp2>,
  232. r_call_unary<op::log>,
  233. r_call_unary<op::log2>,
  234. r_call_unary<op::log10>,
  235. r_call_unary<op::sin>,
  236. r_call_unary<op::cos>,
  237. r_call_unary<op::tan>,
  238. r_call_unary<op::asin>,
  239. r_call_unary<op::acos>,
  240. r_call_unary<op::atan>,
  241. r_call_unary<op::sinh>,
  242. r_call_unary<op::cosh>,
  243. r_call_unary<op::tanh>,
  244. r_call_binary<op::atan2>,
  245. r_call_binary<op::pow>,
  246. r_call_binary<op::min>,
  247. r_call_binary<op::max>> {};
  248. // r_parentheses <- "(" r_expr ")"
  249. struct r_parentheses : seq<one<'('>, r_expr, one<')'>> {};
  250. // r_terminal <- r_call / r_var / r_constant / r_parentheses
  251. struct r_terminal : sor<r_call,
  252. r_var,
  253. r_constant,
  254. r_parentheses> {};
  255. // r_exponent <- ( "^" | "**" ) r_terminal
  256. // r_factor <- r_terminal ( r_exponent ) *
  257. struct r_exponent : ifapply<seq<sor<one<'^'>, string<'*', '*'>>,
  258. r_terminal>, do_op<op::pow>> {};
  259. struct r_factor : seq<r_terminal,
  260. star<r_exponent>> {};
  261. // r_mul <- "*" r_factor
  262. // r_div <- "/" r_factor
  263. // term <- r_factor ( r_mul / r_div ) *
  264. struct r_mul : ifapply<seq<one<'*'>, r_factor>, do_op<op::mul>> {};
  265. struct r_div : ifapply<seq<one<'/'>, r_factor>, do_op<op::div>> {};
  266. struct r_term : seq<r_factor,
  267. star<sor<r_mul, r_div>>> {};
  268. // add <- "+" r_term
  269. // sub <- "-" r_term
  270. // r_expr <- r_term ( add / sub ) *
  271. struct r_add : ifapply<seq<one<'+'>, r_term>, do_op<op::add>> {};
  272. struct r_sub : ifapply<seq<one<'-'>, r_term>, do_op<op::sub>> {};
  273. struct r_expr : seq<r_term,
  274. star<sor<r_add, r_sub>>> {};
  275. // stmt <- r_expr <end>
  276. struct r_stmt : ifapply<seq<r_expr, eof>, do_success> {};
  277. };
  278. } /* namespace grammar */
  279. using grammar::expression;