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.

167 lines
4.2 KiB

  1. //
  2. // Lol Engine - Sandbox program
  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. #if HAVE_CONFIG_H
  13. # include "config.h"
  14. #endif
  15. #include <lol/engine.h>
  16. #include "pegtl.hh"
  17. namespace lol { namespace parser = pegtl; }
  18. #include "axe.h"
  19. namespace lol { using namespace axe; }
  20. using namespace lol;
  21. //
  22. // Parser tools for a simple calculator grammar with + - * /
  23. //
  24. struct calculator
  25. {
  26. void push(double d) { stack.Push(d); }
  27. void pop() { printf("%f\n", stack.Pop()); }
  28. void mul() { auto x = stack.Pop(); stack.Push(stack.Pop() * x); }
  29. void div() { auto x = stack.Pop(); stack.Push(stack.Pop() / x); }
  30. void add() { auto x = stack.Pop(); stack.Push(stack.Pop() + x); }
  31. void sub() { auto x = stack.Pop(); stack.Push(stack.Pop() - x); }
  32. array<double> stack;
  33. };
  34. static void parse_pegtl(std::string const &str);
  35. static void parse_axe(std::string const &str);
  36. int main()
  37. {
  38. std::string const str("42+2*(1-1+2+3-4*5)");
  39. parse_axe(str);
  40. parse_pegtl(str);
  41. return EXIT_SUCCESS;
  42. }
  43. //
  44. // PegTL -- a PEG parser
  45. //
  46. namespace pegtl_parser
  47. {
  48. using namespace lol::parser;
  49. #define ACTION(name, code) \
  50. struct name : action_base<name> { \
  51. static void apply(std::string const &ctx, calculator &c) { \
  52. code \
  53. } \
  54. };
  55. ACTION( do_number, c.push(atof(ctx.c_str())); )
  56. ACTION( do_op,
  57. switch (ctx[0])
  58. {
  59. case '*': c.mul(); break;
  60. case '/': c.div(); break;
  61. case '+': c.add(); break;
  62. case '-': c.sub(); break;
  63. } )
  64. ACTION( do_success, c.pop(); )
  65. #undef ACTION
  66. // number <- <digit> +
  67. struct number : ifapply<plus<digit>, do_number> {};
  68. // term <- number | "(" expr ")"
  69. struct term : sor<number,
  70. seq<one<'('>, struct expr, one<')'>>> {};
  71. // factor <- term ( "*" term | "/" term ) *
  72. struct factor : seq<term,
  73. star<ifapply<sor<seq<one<'*'>, term>,
  74. seq<one<'/'>, term>>, do_op>>> {};
  75. // expr <- factor ( "+" factor | "-" factor ) *
  76. struct expr : seq<factor,
  77. star<ifapply<sor<seq<one<'+'>, factor>,
  78. seq<one<'-'>, factor>>, do_op>>> {};
  79. // stmt <- expr <end>
  80. struct stmt : ifapply<seq<expr, eof>, do_success> {};
  81. };
  82. static void parse_pegtl(std::string const & str)
  83. {
  84. calculator c;
  85. pegtl::basic_parse_string<pegtl_parser::stmt>(str, c);
  86. }
  87. //
  88. // AXE -- a recursive descent parser (needs right-recursion)
  89. //
  90. template<typename IT>
  91. static void parse_axe_helper(IT i1, IT i2)
  92. {
  93. calculator c;
  94. double d;
  95. #define ACTION(code) e_ref([&](...) { code })
  96. r_rule<IT> number, term, factor, factor_tail, expr, expr_tail, stmt;
  97. // number ::= <double>
  98. number = r_double(d) >> ACTION( c.push(d); );
  99. // term ::= number | ( expr )
  100. term = number
  101. | '(' & expr & ')';
  102. // factor ::= term factor_tail
  103. // factor_tail ::= * term factor_tail
  104. // | / term factor_tail
  105. // | ɛ
  106. factor_tail = '*' & term >> ACTION( c.mul(); ) & factor_tail
  107. | '/' & term >> ACTION( c.div(); ) & factor_tail
  108. | r_empty();
  109. factor = term & factor_tail;
  110. // expr ::= factor expr_tail
  111. // expr_tail ::= + factor expr_tail
  112. // | - factor expr_tail
  113. // | ɛ
  114. expr_tail = '+' & factor >> ACTION( c.add(); ) & expr_tail
  115. | '-' & factor >> ACTION( c.sub(); ) & expr_tail
  116. | r_empty();
  117. expr = factor & expr_tail;
  118. // stmt ::= expr <end>
  119. // | <fail>
  120. stmt = expr & r_end() >> ACTION( c.pop(); )
  121. | r_fail([](...) { printf("malformed expression\n"); });
  122. #undef ACTION
  123. // Evaluate expression
  124. stmt(i1, i2);
  125. }
  126. static void parse_axe(std::string const &str)
  127. {
  128. return parse_axe_helper(str.begin(), str.end());
  129. }