Coverage Report

Created: 2026-08-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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