1 /** @file parse_binop_rhs.cpp
3 * Code to deal with binary operators. */
6 * GiNaC Copyright (C) 1999-2024 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 /// unary_expr: [+-] expression
118 ex parser::parse_unary_expr()
120 // Parse a binary expression with the priority of exponentiation
121 // or higher. Ignore the overall sign, because parse_primary()
122 // handles it for us.
123 get_next_tok(); // Skip [+-]
124 ex lhs = parse_primary();
125 ex e = parse_binop_rhs(get_tok_prec('^'), lhs);
129 extern const numeric* _num_1_p;
131 static ex make_minus_expr(const exvector& args)
134 rest_args.reserve(args.size() - 1);
135 std::copy(args.begin() + 1, args.end(), std::back_inserter(rest_args));
136 ex rest_base = dynallocate<add>(rest_args);
137 ex rest = dynallocate<mul>(rest_base, *_num_1_p);
138 ex ret = dynallocate<add>(args[0], rest);
142 static ex make_divide_expr(const exvector& args)
145 rest_args.reserve(args.size() - 1);
146 std::copy(args.begin() + 1, args.end(), std::back_inserter(rest_args));
147 ex rest_base = dynallocate<mul>(rest_args);
148 ex rest = pow(rest_base, *_num_1_p);
149 return dynallocate<mul>(args[0], rest);
152 static ex make_power_expr(const exvector& args)
154 size_t n = args.size();
155 ex p = pow(args[n - 2], args[n - 1]);
156 for (size_t i = n - 2; i > 0; i--) {
157 p = pow(args[i - 1], p);
162 static ex make_binop_expr(const int binop, const exvector& args)
166 return dynallocate<add>(args);
168 return make_minus_expr(args);
170 return dynallocate<mul>(args);
172 return make_divide_expr(args);
174 return make_power_expr(args);
176 throw std::invalid_argument(
177 std::string(__func__)
178 + ": invalid binary operation: "
183 static inline bool is_binop(const int c)
197 /// Get the precedence of the pending binary operator.
198 static int get_tok_prec(const int c)
211 // means 'this is not a binary operator'