/src/muparser/src/muParserInt.cpp
Line | Count | Source |
1 | | /* |
2 | | |
3 | | _____ __ _____________ _______ ______ ___________ |
4 | | / \| | \____ \__ \\_ __ \/ ___// __ \_ __ \ |
5 | | | Y Y \ | / |_> > __ \| | \/\___ \\ ___/| | \/ |
6 | | |__|_| /____/| __(____ /__| /____ >\___ >__| |
7 | | \/ |__| \/ \/ \/ |
8 | | Copyright (C) 2026 Ingo Berg |
9 | | |
10 | | Redistribution and use in source and binary forms, with or without modification, are permitted |
11 | | provided that the following conditions are met: |
12 | | |
13 | | * Redistributions of source code must retain the above copyright notice, this list of |
14 | | conditions and the following disclaimer. |
15 | | * Redistributions in binary form must reproduce the above copyright notice, this list of |
16 | | conditions and the following disclaimer in the documentation and/or other materials provided |
17 | | with the distribution. |
18 | | |
19 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR |
20 | | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
21 | | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR |
22 | | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
25 | | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
26 | | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | | */ |
28 | | |
29 | | #include "muParserInt.h" |
30 | | |
31 | | #include <cmath> |
32 | | #include <algorithm> |
33 | | #include <numeric> |
34 | | |
35 | | using namespace std; |
36 | | |
37 | | /** \file |
38 | | \brief Implementation of a parser using integer value. |
39 | | */ |
40 | | |
41 | | /** \brief Namespace for mathematical applications. */ |
42 | | namespace mu |
43 | | { |
44 | 210 | value_type ParserInt::Abs(value_type v) { return (value_type)Round(fabs((double)v)); } |
45 | 881 | value_type ParserInt::Sign(value_type v) { return (Round(v) < 0) ? -1 : (Round(v) > 0) ? 1 : 0; } |
46 | 1.09k | value_type ParserInt::Ite(value_type v1, value_type v2, value_type v3) { return (Round(v1) == 1) ? Round(v2) : Round(v3); } |
47 | 24.0k | value_type ParserInt::Add(value_type v1, value_type v2) { return Round(v1) + Round(v2); } |
48 | 69.4k | value_type ParserInt::Sub(value_type v1, value_type v2) { return Round(v1) - Round(v2); } |
49 | 25.2k | value_type ParserInt::Mul(value_type v1, value_type v2) { return Round(v1) * Round(v2); } |
50 | | |
51 | | value_type ParserInt::Div(value_type v1, value_type v2) |
52 | 4.42k | { |
53 | 4.42k | int divisor = Round(v2); |
54 | 4.42k | if (divisor == 0) |
55 | 60 | throw ParserError(ecDIV_BY_ZERO); |
56 | | |
57 | 4.36k | int dividend = Round(v1); |
58 | 4.36k | if (dividend == INT_MIN && divisor == -1) |
59 | 2 | throw ParserError(ecDOMAIN_ERROR); |
60 | | |
61 | 4.36k | return dividend / divisor; |
62 | 4.36k | } |
63 | | |
64 | | value_type ParserInt::Mod(value_type v1, value_type v2) |
65 | 1.26k | { |
66 | 1.26k | int divisor = Round(v2); |
67 | 1.26k | if (divisor == 0) |
68 | 15 | throw ParserError(ecDIV_BY_ZERO); |
69 | | |
70 | 1.25k | int dividend = Round(v1); |
71 | 1.25k | if (dividend == INT_MIN && divisor == -1) |
72 | 1 | throw ParserError(ecDOMAIN_ERROR); |
73 | | |
74 | 1.25k | return dividend % divisor; |
75 | 1.25k | } |
76 | | |
77 | | value_type ParserInt::Shr(value_type v1, value_type v2) |
78 | 428 | { |
79 | 428 | int shift = Round(v2); |
80 | 428 | if (shift < 0 || shift >= (int)(sizeof(int) * 8)) |
81 | 79 | throw ParserError(ecDOMAIN_ERROR); |
82 | | |
83 | 349 | return (int)((unsigned)Round(v1) >> shift); |
84 | 428 | } |
85 | | |
86 | | value_type ParserInt::Shl(value_type v1, value_type v2) |
87 | 547 | { |
88 | 547 | int shift = Round(v2); |
89 | 547 | if (shift < 0 || shift >= (int)(sizeof(int) * 8)) |
90 | 70 | throw ParserError(ecDOMAIN_ERROR); |
91 | | |
92 | 477 | return (int)((unsigned)Round(v1) << shift); |
93 | 547 | } |
94 | | |
95 | 1.97k | value_type ParserInt::BitAnd(value_type v1, value_type v2) { return Round(v1) & Round(v2); } |
96 | 1.44k | value_type ParserInt::BitOr(value_type v1, value_type v2) { return Round(v1) | Round(v2); } |
97 | 4.72k | value_type ParserInt::And(value_type v1, value_type v2) { return Round(v1) && Round(v2); } |
98 | 3.40k | value_type ParserInt::Or(value_type v1, value_type v2) { return Round(v1) || Round(v2); } |
99 | 5.57k | value_type ParserInt::Less(value_type v1, value_type v2) { return Round(v1) < Round(v2); } |
100 | 1.59k | value_type ParserInt::Greater(value_type v1, value_type v2) { return Round(v1) > Round(v2); } |
101 | 1.10k | value_type ParserInt::LessEq(value_type v1, value_type v2) { return Round(v1) <= Round(v2); } |
102 | 492 | value_type ParserInt::GreaterEq(value_type v1, value_type v2) { return Round(v1) >= Round(v2); } |
103 | 326 | value_type ParserInt::Equal(value_type v1, value_type v2) { return Round(v1) == Round(v2); } |
104 | 1.48k | value_type ParserInt::NotEqual(value_type v1, value_type v2) { return Round(v1) != Round(v2); } |
105 | 1.40k | value_type ParserInt::Not(value_type v) { return !Round(v); } |
106 | | |
107 | | value_type ParserInt::Pow(value_type v1, value_type v2) |
108 | 620k | { |
109 | 620k | return std::pow((double)Round(v1), (double)Round(v2)); |
110 | 620k | } |
111 | | |
112 | | |
113 | | value_type ParserInt::UnaryMinus(value_type v) |
114 | 5.48k | { |
115 | 5.48k | return -Round(v); |
116 | 5.48k | } |
117 | | |
118 | | |
119 | | value_type ParserInt::Sum(const value_type* a_afArg, int a_iArgc) |
120 | 2.95k | { |
121 | 2.95k | if (!a_iArgc) |
122 | 0 | throw ParserError(_T("too few arguments for function sum.")); |
123 | | |
124 | 2.95k | value_type fRes = 0; |
125 | 42.3k | for (int i = 0; i < a_iArgc; ++i) |
126 | 39.4k | fRes += a_afArg[i]; |
127 | | |
128 | 2.95k | return fRes; |
129 | 2.95k | } |
130 | | |
131 | | |
132 | | value_type ParserInt::Min(const value_type* a_afArg, int a_iArgc) |
133 | 1.64k | { |
134 | 1.64k | if (!a_iArgc) |
135 | 0 | throw ParserError(_T("too few arguments for function min.")); |
136 | | |
137 | 1.64k | value_type fRes = a_afArg[0]; |
138 | 50.0k | for (int i = 0; i < a_iArgc; ++i) |
139 | 48.4k | fRes = std::min(fRes, a_afArg[i]); |
140 | | |
141 | 1.64k | return fRes; |
142 | 1.64k | } |
143 | | |
144 | | |
145 | | value_type ParserInt::Max(const value_type* a_afArg, int a_iArgc) |
146 | 2.28k | { |
147 | 2.28k | if (!a_iArgc) |
148 | 0 | throw ParserError(_T("too few arguments for function min.")); |
149 | | |
150 | 2.28k | value_type fRes = a_afArg[0]; |
151 | 173k | for (int i = 0; i < a_iArgc; ++i) |
152 | 171k | fRes = std::max(fRes, a_afArg[i]); |
153 | | |
154 | 2.28k | return fRes; |
155 | 2.28k | } |
156 | | |
157 | | |
158 | | int ParserInt::IsVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal) |
159 | 324k | { |
160 | 324k | string_type buf(a_szExpr); |
161 | 324k | std::size_t pos = buf.find_first_not_of(_T("0123456789")); |
162 | | |
163 | 324k | if (pos == std::string::npos) |
164 | 0 | pos = buf.length(); |
165 | | |
166 | 324k | if (pos == 0) |
167 | 184k | return 0; |
168 | | |
169 | 139k | stringstream_type stream(buf.substr(0, pos)); |
170 | 139k | int iVal(0); |
171 | | |
172 | 139k | stream >> iVal; |
173 | 139k | if (stream.fail()) |
174 | 1.93k | return 0; |
175 | | |
176 | 137k | stringstream_type::pos_type iEnd = stream.tellg(); // Position after reading |
177 | 137k | if (stream.fail()) |
178 | 137k | iEnd = stream.str().length(); |
179 | | |
180 | 137k | if (iEnd == (stringstream_type::pos_type) - 1) |
181 | 0 | return 0; |
182 | | |
183 | 137k | *a_iPos += (int)iEnd; |
184 | 137k | *a_fVal = (value_type)iVal; |
185 | 137k | return 1; |
186 | 137k | } |
187 | | |
188 | | |
189 | | /** \brief Check a given position in the expression for the presence of |
190 | | a hex value. |
191 | | \param a_szExpr Pointer to the expression string |
192 | | \param [in/out] a_iPos Pointer to an integer value holding the current parsing |
193 | | position in the expression. |
194 | | \param [out] a_fVal Pointer to the position where the detected value shall be stored. |
195 | | |
196 | | Hey values must be prefixed with "0x" in order to be detected properly. |
197 | | */ |
198 | | int ParserInt::IsHexVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal) |
199 | 324k | { |
200 | 324k | if (a_szExpr[1] == 0 || (a_szExpr[0] != '0' || a_szExpr[1] != 'x')) |
201 | 324k | return 0; |
202 | | |
203 | 507 | unsigned iVal(0); |
204 | | |
205 | | // New code based on streams for UNICODE compliance: |
206 | 507 | stringstream_type::pos_type nPos(0); |
207 | 507 | stringstream_type ss(a_szExpr + 2); |
208 | 507 | ss >> std::hex >> iVal; |
209 | 507 | nPos = ss.tellg(); |
210 | | |
211 | 507 | if (nPos == (stringstream_type::pos_type)0) |
212 | 0 | return 0; |
213 | | |
214 | 507 | *a_iPos += (int)(2 + nPos); |
215 | 507 | *a_fVal = (value_type)iVal; |
216 | 507 | return 1; |
217 | 507 | } |
218 | | |
219 | | |
220 | | int ParserInt::IsBinVal(const char_type* a_szExpr, int* a_iPos, value_type* a_fVal) |
221 | 324k | { |
222 | 324k | if (a_szExpr[0] != '#') |
223 | 323k | return 0; |
224 | | |
225 | 684 | unsigned iVal(0), |
226 | 684 | iBits(sizeof(iVal) * 8), |
227 | 684 | i(0); |
228 | | |
229 | 2.80k | for (i = 0; (a_szExpr[i + 1] == '0' || a_szExpr[i + 1] == '1') && i < iBits; ++i) |
230 | 2.11k | iVal |= (int)(a_szExpr[i + 1] == '1') << ((iBits - 1) - i); |
231 | | |
232 | 684 | if (i == 0) |
233 | 339 | return 0; |
234 | | |
235 | 345 | if (i == iBits) |
236 | 4 | throw exception_type(_T("Binary to integer conversion error (overflow).")); |
237 | | |
238 | 341 | *a_fVal = (unsigned)(iVal >> (iBits - i)); |
239 | 341 | *a_iPos += i + 1; |
240 | | |
241 | 341 | return 1; |
242 | 345 | } |
243 | | |
244 | | |
245 | | /** \brief Constructor. |
246 | | |
247 | | Call ParserBase class constructor and trigger Function, Operator and Constant initialization. |
248 | | */ |
249 | | ParserInt::ParserInt() |
250 | 2.79k | :ParserBase() |
251 | 2.79k | { |
252 | 2.79k | AddValIdent(IsVal); // lowest priority |
253 | 2.79k | AddValIdent(IsBinVal); |
254 | 2.79k | AddValIdent(IsHexVal); // highest priority |
255 | | |
256 | 2.79k | InitCharSets(); |
257 | 2.79k | InitFun(); |
258 | 2.79k | InitOprt(); |
259 | 2.79k | } |
260 | | |
261 | | |
262 | | void ParserInt::InitConst() |
263 | 0 | { |
264 | 0 | } |
265 | | |
266 | | |
267 | | void ParserInt::InitCharSets() |
268 | 2.79k | { |
269 | 2.79k | DefineNameChars(_T("0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")); |
270 | 2.79k | DefineOprtChars(_T("+-*^/?<>=!%&|~'_")); |
271 | 2.79k | DefineInfixOprtChars(_T("/+-*^?<>=!%&|~'_")); |
272 | 2.79k | } |
273 | | |
274 | | |
275 | | /** \brief Initialize the default functions. */ |
276 | | void ParserInt::InitFun() |
277 | 2.79k | { |
278 | 2.79k | DefineFun(_T("sign"), Sign); |
279 | 2.79k | DefineFun(_T("abs"), Abs); |
280 | 2.79k | DefineFun(_T("if"), Ite); |
281 | 2.79k | DefineFun(_T("sum"), Sum); |
282 | 2.79k | DefineFun(_T("min"), Min); |
283 | 2.79k | DefineFun(_T("max"), Max); |
284 | 2.79k | } |
285 | | |
286 | | |
287 | | /** \brief Initialize operators. */ |
288 | | void ParserInt::InitOprt() |
289 | 2.79k | { |
290 | | // disable all built in operators, not all of them useful for integer numbers |
291 | | // (they don't do rounding of values) |
292 | 2.79k | EnableBuiltInOprt(false); |
293 | | |
294 | | // Disable all built in operators, they won't work with integer numbers |
295 | | // since they are designed for floating point numbers |
296 | 2.79k | DefineInfixOprt(_T("-"), UnaryMinus); |
297 | 2.79k | DefineInfixOprt(_T("!"), Not); |
298 | | |
299 | 2.79k | DefineOprt(_T("&"), BitAnd, prBAND); |
300 | 2.79k | DefineOprt(_T("|"), BitOr, prBOR); |
301 | | |
302 | 2.79k | DefineOprt(_T("&&"), And, prLAND); |
303 | 2.79k | DefineOprt(_T("||"), Or, prLOR); |
304 | | |
305 | 2.79k | DefineOprt(_T("<"), Less, prCMP); |
306 | 2.79k | DefineOprt(_T(">"), Greater, prCMP); |
307 | 2.79k | DefineOprt(_T("<="), LessEq, prCMP); |
308 | 2.79k | DefineOprt(_T(">="), GreaterEq, prCMP); |
309 | 2.79k | DefineOprt(_T("=="), Equal, prCMP); |
310 | 2.79k | DefineOprt(_T("!="), NotEqual, prCMP); |
311 | | |
312 | 2.79k | DefineOprt(_T("+"), Add, prADD_SUB); |
313 | 2.79k | DefineOprt(_T("-"), Sub, prADD_SUB); |
314 | | |
315 | 2.79k | DefineOprt(_T("*"), Mul, prMUL_DIV); |
316 | 2.79k | DefineOprt(_T("/"), Div, prMUL_DIV); |
317 | 2.79k | DefineOprt(_T("%"), Mod, prMUL_DIV); |
318 | | |
319 | 2.79k | DefineOprt(_T("^"), Pow, prPOW, oaRIGHT); |
320 | 2.79k | DefineOprt(_T(">>"), Shr, prMUL_DIV + 1); |
321 | 2.79k | DefineOprt(_T("<<"), Shl, prMUL_DIV + 1); |
322 | 2.79k | } |
323 | | |
324 | | } // namespace mu |