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.
 
 
 

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