1 /** @file parse_binop_rhs.cpp
3 * Code to deal with binary operators. */
6 * GiNaC Copyright (C) 1999-2015 Johannes Gutenberg University Mainz, Germany
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "operators.h"
38 /// Make a sum or a product.
39 static ex make_binop_expr(const int binop, const exvector& args);
40 /// Check if the token is a binary operator.
41 static inline bool is_binop(const int c);
42 /// Get the precedence of the pending binary operator.
43 static int get_tok_prec(const int c);
45 /// binoprhs: ([+*/^-] primary)*
46 ex parser::parse_binop_rhs(int expr_prec, ex& lhs)
50 int binop = -1, orig_binop = -1;
51 bool need_sign_flip = false;
53 // check if this is a binop
54 if (!is_binop(token)) {
56 return make_binop_expr(orig_binop, args);
61 // Okay, we know this is a binop.
67 // If this is a binop that binds at least as tightly as
68 // the current binop, consume it, otherwise we are done.
69 int tok_prec = get_tok_prec(token);
70 if (tok_prec < expr_prec) {
72 return make_binop_expr(orig_binop, args);
77 get_next_tok(); // eat binop
79 // Parse the primary expression after the binary operator.
80 ex rhs = parse_primary();
82 // If binop binds less tightly with rhs than the operator after
83 // rhs, let the pending operator take rhs as its lhs.
84 int next_prec = get_tok_prec(token);
85 if (tok_prec < next_prec)
86 rhs = parse_binop_rhs(tok_prec + 1, rhs);
88 // previous operator was '+', and current one is '-'
95 // Minimize the number of eval() and ctor calls. This is
96 // crucial for a reasonable performance. If the next operator
97 // is compatible with the pending one (or the same) don't create
98 // the expression and continue collecting operands instead.
101 else if (binop == '+' && token == '-') {
102 need_sign_flip = token != orig_binop;
104 } else if (binop == '-' && token == '+') {
105 need_sign_flip = token != orig_binop;
108 if (args.size() <= 1)
109 bug("binop has " << args.size() << " arguments, expected >= 2");
110 lhs = make_binop_expr(orig_binop, args);
117 extern const numeric* _num_1_p;
119 static ex make_minus_expr(const exvector& args)
122 rest_args.reserve(args.size() - 1);
123 std::copy(args.begin() + 1, args.end(), std::back_inserter(rest_args));
124 ex rest_base = (new add(rest_args))->setflag(status_flags::dynallocated);
125 ex rest = (new mul(rest_base, *_num_1_p))->setflag(status_flags::dynallocated);
126 ex ret = (new add(args[0], rest))->setflag(status_flags::dynallocated);
130 static ex make_divide_expr(const exvector& args)
133 rest_args.reserve(args.size() - 1);
134 std::copy(args.begin() + 1, args.end(), std::back_inserter(rest_args));
135 ex rest_base = (new mul(rest_args))->setflag(status_flags::dynallocated);
136 ex rest = pow(rest_base, *_num_1_p);
137 return (new mul(args[0], rest))->setflag(status_flags::dynallocated);
140 static ex make_binop_expr(const int binop, const exvector& args)
144 return (new add(args))->setflag(status_flags::dynallocated);
146 return make_minus_expr(args);
148 return (new mul(args))->setflag(status_flags::dynallocated);
150 return make_divide_expr(args);
152 if (args.size() != 2)
153 throw std::invalid_argument(
154 std::string(__func__)
155 + ": power should have exactly 2 operands");
156 return pow(args[0], args[1]);
158 throw std::invalid_argument(
159 std::string(__func__)
160 + ": invalid binary operation: "
165 static inline bool is_binop(const int c)
179 /// Get the precedence of the pending binary operator.
180 static int get_tok_prec(const int c)
193 // means 'this is not a binary operator'