16 /// Make a sum or a product.
17 static ex make_binop_expr(const int binop, const exvector& args);
18 /// Check if the token is a binary operator.
19 static inline bool is_binop(const int c);
20 /// Get the precedence of the pending binary operator.
21 static int get_tok_prec(const int c);
23 /// binoprhs: ([+*/^-] primary)*
24 ex parser::parse_binop_rhs(int expr_prec, ex& lhs)
28 int binop = -1, orig_binop = -1;
29 bool need_sign_flip = false;
31 // check if this is a binop
32 if (!is_binop(token)) {
34 return make_binop_expr(orig_binop, args);
39 // Okay, we know this is a binop.
45 // If this is a binop that binds at least as tightly as
46 // the current binop, consume it, otherwise we are done.
47 int tok_prec = get_tok_prec(token);
48 if (tok_prec < expr_prec) {
50 return make_binop_expr(orig_binop, args);
55 get_next_tok(); // eat binop
57 // Parse the primary expression after the binary operator.
58 ex rhs = parse_primary();
60 // If binop binds less tightly with rhs than the operator after
61 // rhs, let the pending operator take rhs as its lhs.
62 int next_prec = get_tok_prec(token);
63 if (tok_prec < next_prec)
64 rhs = parse_binop_rhs(tok_prec + 1, rhs);
66 // previous operator was '+', and current one is '-'
73 // Minimize the number of eval() and ctor calls. This is
74 // crucial for a reasonable performance. If the next operator
75 // is compatible with the pending one (or the same) don't create
76 // the expression and continue collecting operands instead.
79 else if (binop == '+' && token == '-') {
80 need_sign_flip = token != orig_binop;
82 } else if (binop == '-' && token == '+') {
83 need_sign_flip = token != orig_binop;
87 bug("binop has " << args.size() << " arguments, expected >= 2");
88 lhs = make_binop_expr(orig_binop, args);
95 extern numeric* _num_1_p;
97 static ex make_minus_expr(const exvector& args)
100 rest_args.reserve(args.size() - 1);
101 std::copy(args.begin() + 1, args.end(), std::back_inserter(rest_args));
102 ex rest_base = (new add(rest_args))->setflag(status_flags::dynallocated);
103 ex rest = (new mul(rest_base, *_num_1_p))->setflag(status_flags::dynallocated);
104 ex ret = (new add(args[0], rest))->setflag(status_flags::dynallocated);
108 static ex make_divide_expr(const exvector& args)
111 rest_args.reserve(args.size() - 1);
112 std::copy(args.begin() + 1, args.end(), std::back_inserter(rest_args));
113 ex rest_base = (new mul(rest_args))->setflag(status_flags::dynallocated);
114 ex rest = pow(rest_base, *_num_1_p);
115 return (new mul(args[0], rest))->setflag(status_flags::dynallocated);
118 static ex make_binop_expr(const int binop, const exvector& args)
122 return (new add(args))->setflag(status_flags::dynallocated);
124 return make_minus_expr(args);
126 return (new mul(args))->setflag(status_flags::dynallocated);
128 return make_divide_expr(args);
130 if (args.size() != 2)
131 throw std::invalid_argument(
132 std::string(__func__)
133 + ": power should have exactly 2 operands");
134 return pow(args[0], args[1]);
136 throw std::invalid_argument(
137 std::string(__func__)
138 + ": invalid binary operation: "
143 static inline bool is_binop(const int c)
157 /// Get the precedence of the pending binary operator.
158 static int get_tok_prec(const int c)
171 // means 'this is not a binary operator'