Guest User

Untitled

a guest
May 25th, 2018
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.74 KB | None | 0 0
  1. // Example program
  2. #include <iostream>
  3. #include <string>
  4. #include <vector>
  5. #include <cctype>
  6. #include <cmath>
  7. #include <utility>
  8. #include <memory>
  9.  
  10. template <typename T>
  11. bool is_any_of(T str, std::vector<T> valid)
  12. {
  13. for (auto &v: valid)
  14. if (str == v)
  15. return true;
  16.  
  17. return false;
  18. }
  19.  
  20. bool is_number(std::string str)
  21. {
  22. if (!str.size())
  23. return false;
  24.  
  25. for (auto c: str)
  26. if (!isdigit(c) && c != '.')
  27. return false;
  28.  
  29. return true;
  30. }
  31.  
  32. std::vector<char> OP_AS_CHAR = {'+', '-', '*', '/', '^'};
  33. std::vector<std::string> OP_AS_STR = {"+", "-", "*", "/", "^"};
  34.  
  35. class Expr;
  36. class Literal;
  37. class Nud;
  38. class Op;
  39.  
  40. struct Source {
  41. std::string line, buffer;
  42. unsigned int cursor, start;
  43.  
  44. Source(std::string line)
  45. : line(line), cursor(0), start(0), buffer("")
  46. { };
  47.  
  48. void accept() { buffer.clear(); };
  49. std::string peek_next()
  50. {
  51. return (buffer = get_next());
  52. }
  53.  
  54. std::string get_next() {
  55. if (!buffer.empty()) {
  56. std::string tmp = buffer;
  57. buffer.clear();
  58. return tmp;
  59. }
  60.  
  61. while(cursor < line.size() && isspace(line[cursor]))
  62. cursor++;
  63.  
  64. if (cursor >= line.size())
  65. return "";
  66.  
  67. start = cursor;
  68. if (is_any_of(line[cursor], {OP_AS_CHAR}) || line[cursor] == '(' || line[cursor] == ')') {
  69. cursor++;
  70. } else if (isdigit(line[cursor])) {
  71. do {
  72. cursor++;
  73. } while(cursor < line.size() && (isdigit(line[cursor]) || line[cursor] == '.'));
  74. }
  75.  
  76. return std::string(line.begin() + start, line.begin() + cursor);
  77. };
  78. };
  79.  
  80. class IExpr {
  81. public:
  82. virtual float visit() = 0;
  83. };
  84.  
  85. class Literal: public IExpr {
  86. std::string lexeme;
  87.  
  88. public:
  89. Literal(std::string lexeme) {
  90. this->lexeme = lexeme;
  91. };
  92. ~Literal() { };
  93.  
  94. float visit() { return std::stod(lexeme); };
  95. };
  96.  
  97. class Nud: public IExpr {
  98. IExpr *expr;
  99.  
  100. public:
  101. Nud(IExpr *expr) : expr(expr) { };
  102. ~Nud() {
  103. if (expr) delete expr;
  104. };
  105. float visit() { return -expr->visit(); };
  106. };
  107.  
  108. class Op: public IExpr {
  109. IExpr *lval;
  110. std::string lexeme;
  111. IExpr *rval;
  112.  
  113. public:
  114. Op(IExpr *lval, std::string op, IExpr *rval) : lval(lval), rval(rval), lexeme(op) { };
  115. ~Op() {
  116. if (lval) delete lval;
  117. if (rval) delete rval;
  118. };
  119.  
  120. float visit() {
  121. float l = lval->visit();
  122. float r = rval->visit();
  123.  
  124. if (lexeme == "+") return (l + r);
  125. if (lexeme == "-") return (l - r);
  126. if (lexeme == "*") return (l * r);
  127. if (lexeme == "/") return (l / r);
  128. if (lexeme == "^") return pow(l, r);
  129. };
  130. bool parse(Source &src, int lbp);
  131. };
  132.  
  133. std::vector<std::pair<int, std::vector<std::string>>> OpPrec = {
  134. {0, {"+", "-"}},
  135. {0, {"*", "/"}},
  136. {1, {"^"}},
  137. };
  138.  
  139. std::pair<int, int> get_binding(std::string op)
  140. {
  141. int power = 0;
  142. for (auto &entry: OpPrec) {
  143. power++;
  144. if (is_any_of(op, entry.second))
  145. return {power, entry.first};
  146. }
  147.  
  148. return {-1, 0};
  149. }
  150.  
  151. IExpr *parse_expr(Source &src, int lbp);
  152. IExpr *parse_nud(Source &src);
  153.  
  154. IExpr *parse_nud(Source &src)
  155. {
  156. int neg = 0;
  157. std::unique_ptr<IExpr> nud;
  158. std::string token = src.get_next();
  159. if (token == "-") {
  160. neg = 1;
  161. token = src.get_next();
  162. }
  163.  
  164. if (token == "(") {
  165. nud = std::unique_ptr<IExpr>(parse_expr(src, 0));
  166. if (!nud)
  167. return NULL;
  168.  
  169. if (src.get_next() != ")") {
  170. std::cout << "Unbalanced parenthesis.\n";
  171. return NULL;
  172. }
  173. } else if (is_number(token)) {
  174. nud = std::unique_ptr<IExpr>(new Literal(token));
  175. }
  176.  
  177. if (neg)
  178. return new Nud(nud.release());
  179. else
  180. return nud.release();
  181. }
  182.  
  183. IExpr *parse_expr(Source &src, int lbp)
  184. {
  185. std::unique_ptr<IExpr> lval;
  186. IExpr *rval = NULL;
  187. std::string lookahead;
  188.  
  189. lval = std::unique_ptr<IExpr>(parse_nud(src));
  190. if (!lval)
  191. return NULL;
  192.  
  193. for (;;) {
  194. lookahead = src.peek_next();
  195.  
  196. if (is_any_of(lookahead, OP_AS_STR)) {
  197. auto bp = get_binding(lookahead);
  198.  
  199. if (bp.first + bp.second > lbp) {
  200. src.accept();
  201. rval = parse_expr(src, bp.first);
  202. if (!rval)
  203. return NULL;
  204.  
  205. lval = std::unique_ptr<IExpr>(new Op(lval.release(), lookahead, rval));
  206. }
  207. else {
  208. return lval.release();
  209. }
  210. } else {
  211. return lval.release();
  212. }
  213. }
  214.  
  215. return lval.release();
  216. }
  217.  
  218. #define M(c) {#c, c},
  219. std::vector<std::pair<std::string, float>> test_suite = {
  220. M(10)
  221. M(10 + 10)
  222. M(-(10) + 10)
  223. {"2+2*3^2", 2+2*pow(3,2)},
  224. {"2^2*2-2", pow(2,2)*2-2},
  225. M(2 - 2 / 3.0 + 3 * -(2+2))
  226. M(2*3/2-1+7+2/2+3+3-3-2/3.0)
  227. M(2*3/2)
  228. {"11 - (13 - 13) ^ 2 + 13 + 10 + 7 + 6", 47},
  229. {"(5+15) + 6 / 15 + 9 ^ 2 + 11 ^ 2 + 9", 231.4},
  230. {"8 + 10 ^ 2 + 5 * (12 - 10) * 6 / 7", 116.571428571},
  231. {"2^3^4 / 100", pow(2,pow(3,4)) / 100}
  232. };
  233. #undef M
  234.  
  235. int main(int argc, char *argv[])
  236. {
  237. for (auto p: test_suite)
  238. {
  239. Source src(p.first);
  240.  
  241. std::unique_ptr<IExpr> expr(parse_expr(src, 0));
  242. if (!expr) {
  243. std::cout << "parse failed for \"" << p.first << "\"." << std::endl;
  244. continue;
  245. }
  246.  
  247. float ret = expr->visit();
  248. std::cout << p.first << " = " << ret << " " << (ret == p.second ? "(ok)": "(failed)") << " => " << p.second << std::endl;
  249. }
  250. }
Add Comment
Please, Sign In to add comment