Changeset View
Changeset View
Standalone View
Standalone View
libs/global/kis_numparser.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * Copyright (c) 2016 Laurent Valentin Jospin <laurent.valentin@famillejospin.ch> | ||||
3 | * | ||||
4 | * This program is free software; you can redistribute it and/or modify | ||||
5 | * it under the terms of the GNU General Public License as published by | ||||
6 | * the Free Software Foundation; either version 2 of the License, or | ||||
7 | * (at your option) any later version. | ||||
8 | * | ||||
9 | * This program is distributed in the hope that it will be useful, | ||||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
12 | * GNU General Public License for more details. | ||||
13 | * | ||||
14 | * You should have received a copy of the GNU General Public License | ||||
15 | * along with this program; if not, write to the Free Software | ||||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
17 | */ | ||||
18 | | ||||
19 | #include "kis_numparser.h" | ||||
20 | | ||||
21 | //#include <QtMath> | ||||
22 | #include <qmath.h> | ||||
23 | #include <QVector> | ||||
24 | #include <QRegExp> | ||||
25 | #include <QStringList> | ||||
26 | #include <QVariant> | ||||
27 | | ||||
28 | using namespace std; | ||||
29 | | ||||
30 | const QVector<char> opLevel1 = {'+', '-'}; | ||||
31 | const QVector<char> opLevel2 = {'*', '/'}; | ||||
32 | | ||||
33 | const QStringList supportedFuncs = {"", "cos", "sin", "tan", "acos", "asin", "atan", "exp", "ln", "log10", "abs"}; | ||||
34 | | ||||
35 | const QRegExp funcExpr("(-)?([a-zA-Z]*)?\\((.+)\\)"); | ||||
36 | const QRegExp numberExpr("(-)?([0-9]+\\.?[0-9]*(e[0-9]*)?)"); | ||||
37 | | ||||
38 | const QRegExp funcExprInteger("(-)?\\((.+)\\)"); | ||||
39 | const QRegExp integerExpr("(-)?([0-9]+)"); | ||||
40 | | ||||
41 | //double functions | ||||
42 | double treatFuncs(QString const& expr, bool & noProblem); | ||||
43 | double treatLevel1(QString const& expr, bool & noProblem); | ||||
44 | double treatLevel2(QString const& expr, bool & noProblem); | ||||
45 | double treatLevel3(QString const& expr, bool & noProblem); | ||||
46 | | ||||
47 | //int functions | ||||
48 | int treatLevel1Int(QString const& expr, bool & noProblem); | ||||
49 | int treatLevel2Int(QString const& expr, bool & noProblem); | ||||
50 | int treatFuncsInt(QString const& expr, bool & noProblem); | ||||
51 | | ||||
52 | namespace KisNumericParser { | ||||
53 | | ||||
54 | /*! | ||||
55 | * \param expr the expression to parse | ||||
56 | * \param noProblem if provided, the value pointed to will be se to true is no problem appeared, false otherwise. | ||||
57 | * \return the numerical value the expression eval to (or 0 in case of error). | ||||
58 | */ | ||||
59 | double parseSimpleMathExpr(const QString &expr, bool *noProblem) | ||||
60 | { | ||||
61 | | ||||
62 | bool ok = true; //intermediate variable to pass by reference to the sublevel parser (if no pointer is provided). | ||||
63 | | ||||
64 | //then go down each 3 levels of operation priority. | ||||
65 | if (noProblem != nullptr) { | ||||
66 | return treatLevel1(expr, *noProblem); | ||||
67 | } | ||||
68 | | ||||
69 | return treatLevel1(expr, ok); | ||||
70 | | ||||
71 | } | ||||
72 | | ||||
73 | /*! | ||||
74 | * \param expr the expression to parse | ||||
75 | * \param noProblem if provided, the value pointed to will be se to true is no problem appeared, false otherwise. | ||||
76 | * \return the numerical value the expression eval to (or 0 in case of error). | ||||
77 | */ | ||||
78 | int parseIntegerMathExpr(QString const& expr, bool* noProblem) | ||||
79 | { | ||||
80 | | ||||
81 | bool ok = true; //intermediate variable to pass by reference to the sublevel parser (if no pointer is provided). | ||||
82 | | ||||
83 | if (noProblem != nullptr) { | ||||
84 | return treatLevel1Int(expr, *noProblem); | ||||
85 | } | ||||
86 | | ||||
87 | return treatLevel1Int(expr, ok); | ||||
88 | | ||||
89 | } | ||||
90 | | ||||
91 | } //namespace KisNumericParser. | ||||
92 | | ||||
93 | | ||||
94 | //intermediate functions | ||||
95 | | ||||
96 | /*! | ||||
97 | * \brief cutLevel1 cut an expression into many subparts using the level1 operations (+-) outside of parenthesis as separator. Return some results by reference. | ||||
98 | * \param expr The expression to cut. | ||||
99 | * \param readyToTreat A reference to a string list to hold the subparts. | ||||
100 | * \param op A list of operations stored as char ('+' and '-') and returned by reference. | ||||
101 | * \param noProblem A reference to a bool, set to true if there was no problem, false otherwise. | ||||
102 | * | ||||
103 | * The function won't cut the expression if the + or - operation is nested within parenthesis. The subexpression in the parenthesis will be treated recursivly later on. | ||||
104 | */ | ||||
105 | inline void cutLevel1(QString const& expr, QStringList & readyToTreat, QVector<char> & op, bool & noProblem) | ||||
106 | { | ||||
107 | | ||||
108 | readyToTreat.clear(); | ||||
109 | op.clear(); | ||||
110 | | ||||
111 | int subCount = 0; | ||||
112 | int lastPos = 0; | ||||
113 | | ||||
114 | bool lastMetIsNumber = false; | ||||
115 | | ||||
116 | for(int i = 0; i < expr.size(); i++){ | ||||
117 | | ||||
118 | if (expr.at(i) == '(') { | ||||
119 | subCount++; | ||||
120 | } | ||||
121 | | ||||
122 | if (expr.at(i) == ')') { | ||||
123 | subCount--; | ||||
124 | } | ||||
125 | | ||||
126 | if (subCount < 0) { | ||||
127 | noProblem = false; | ||||
128 | return; | ||||
129 | } | ||||
130 | | ||||
131 | if( (expr.at(i) == '+' || expr.at(i) == '-') && | ||||
132 | subCount == 0) { | ||||
133 | | ||||
134 | if (expr.at(i) == '-' && | ||||
135 | i < expr.size()-1) { | ||||
136 | | ||||
137 | bool cond = !expr.at(i+1).isSpace(); | ||||
138 | | ||||
139 | if (cond && !lastMetIsNumber) { | ||||
140 | continue; | ||||
141 | } | ||||
142 | | ||||
143 | } | ||||
144 | | ||||
145 | readyToTreat.push_back(expr.mid(lastPos, i-lastPos).trimmed()); | ||||
146 | lastPos = i+1; | ||||
147 | op.push_back(expr.at(i).toLatin1()); | ||||
148 | | ||||
149 | } | ||||
150 | | ||||
151 | if (expr.at(i).isDigit()) { | ||||
152 | lastMetIsNumber = true; | ||||
153 | } else if (expr.at(i) != '.' && | ||||
154 | !expr.at(i).isSpace()) { | ||||
155 | lastMetIsNumber = false; | ||||
156 | } | ||||
157 | } | ||||
158 | | ||||
159 | readyToTreat.push_back(expr.mid(lastPos).trimmed()); | ||||
160 | | ||||
161 | } | ||||
162 | | ||||
163 | /*! | ||||
164 | * \brief cutLeve2 cut an expression into many subparts using the level2 operations (* and /) outside of parenthesis as separator. Return some results by reference. | ||||
165 | * \param expr The expression to cut. | ||||
166 | * \param readyToTreat A reference to a string list to hold the subparts. | ||||
167 | * \param op A list of operations stored as char ('*' and '/') and returned by reference. | ||||
168 | * \param noProblem A reference to a bool, set to true if there was no problem, false otherwise. | ||||
169 | * | ||||
170 | * The function won't cut the expression if the * or / operation is nested within parenthesis. The subexpression in the parenthesis will be treated recursivly later on. | ||||
171 | */ | ||||
172 | inline void cutLevel2(QString const& expr, QStringList & readyToTreat, QVector<char> & op, bool & noProblem) | ||||
173 | { | ||||
174 | | ||||
175 | readyToTreat.clear(); | ||||
176 | op.clear(); | ||||
177 | | ||||
178 | int subCount = 0; | ||||
179 | int lastPos = 0; | ||||
180 | | ||||
181 | for (int i = 0; i < expr.size(); i++) { | ||||
182 | | ||||
183 | if (expr.at(i) == '(') { | ||||
184 | subCount++; | ||||
185 | } | ||||
186 | | ||||
187 | if (expr.at(i) == ')') { | ||||
188 | subCount--; | ||||
189 | } | ||||
190 | | ||||
191 | if (subCount < 0) { | ||||
192 | noProblem = false; | ||||
193 | return; | ||||
194 | } | ||||
195 | | ||||
196 | if ( (expr.at(i) == '*' || expr.at(i) == '/') && | ||||
197 | subCount == 0) { | ||||
198 | | ||||
199 | readyToTreat.push_back(expr.mid(lastPos, i-lastPos).trimmed()); | ||||
200 | lastPos = i+1; | ||||
201 | op.push_back(expr.at(i).toLatin1()); | ||||
202 | | ||||
203 | } | ||||
204 | } | ||||
205 | | ||||
206 | readyToTreat.push_back(expr.mid(lastPos).trimmed()); | ||||
207 | } | ||||
208 | | ||||
209 | /*! | ||||
210 | * \brief treatLevel1 treat an expression at the first level of recursion. | ||||
211 | * \param expr The expression to treat. | ||||
212 | * \param noProblem A reference to a bool set to true if no problem happened, false otherwise. | ||||
213 | * \return The value of the parsed expression or subexpression or 0 in case of error. | ||||
214 | */ | ||||
215 | double treatLevel1(const QString &expr, bool & noProblem) | ||||
216 | { | ||||
217 | | ||||
218 | noProblem = true; | ||||
219 | | ||||
220 | QStringList readyToTreat; | ||||
221 | QVector<char> op; | ||||
222 | | ||||
223 | cutLevel1(expr, readyToTreat, op, noProblem); | ||||
224 | if (!noProblem) { | ||||
225 | return 0.0; | ||||
226 | } | ||||
227 | | ||||
228 | if (readyToTreat.contains("")) { | ||||
229 | noProblem = false; | ||||
230 | return 0.0; | ||||
231 | } | ||||
232 | | ||||
233 | if (op.size() != readyToTreat.size()-1) { | ||||
234 | noProblem = false; | ||||
235 | return 0.0; | ||||
236 | } | ||||
237 | | ||||
238 | double result = 0.0; | ||||
239 | | ||||
240 | for (int i = 0; i < readyToTreat.size(); i++) { | ||||
241 | | ||||
242 | if (i == 0) { | ||||
243 | result += treatLevel2(readyToTreat[i], noProblem); | ||||
244 | } else { | ||||
245 | if (op[i-1] == '+') { | ||||
246 | result += treatLevel2(readyToTreat[i], noProblem); | ||||
247 | } else if (op[i-1] == '-') { | ||||
248 | result -= treatLevel2(readyToTreat[i], noProblem); | ||||
249 | } | ||||
250 | } | ||||
251 | | ||||
252 | if (noProblem == false) { | ||||
253 | return 0.0; | ||||
254 | } | ||||
255 | } | ||||
256 | | ||||
257 | return result; | ||||
258 | | ||||
259 | } | ||||
260 | | ||||
261 | /*! | ||||
262 | * \brief treatLevel2 treat a subexpression at the second level of recursion. | ||||
263 | * \param expr The subexpression to treat. | ||||
264 | * \param noProblem A reference to a bool set to true if no problem happened, false otherwise. | ||||
265 | * \return The value of the parsed subexpression or 0 in case of error. | ||||
266 | * | ||||
267 | * The expression should not contain first level operations not nested in parenthesis. | ||||
268 | */ | ||||
269 | double treatLevel2(QString const& expr, bool & noProblem) | ||||
270 | { | ||||
271 | | ||||
272 | noProblem = true; | ||||
273 | | ||||
274 | QStringList readyToTreat; | ||||
275 | QVector<char> op; | ||||
276 | | ||||
277 | cutLevel2(expr, readyToTreat, op, noProblem); | ||||
278 | if (!noProblem) { | ||||
279 | return 0.0; | ||||
280 | } | ||||
281 | | ||||
282 | if (readyToTreat.contains("")) { | ||||
283 | noProblem = false; | ||||
284 | return 0.0; | ||||
285 | } | ||||
286 | | ||||
287 | if (op.size() != readyToTreat.size()-1) { | ||||
288 | noProblem = false; | ||||
289 | return 0.0; | ||||
290 | } | ||||
291 | | ||||
292 | double result = 0.0; | ||||
293 | | ||||
294 | for (int i = 0; i < readyToTreat.size(); i++) { | ||||
295 | | ||||
296 | if (i == 0) { | ||||
297 | result += treatLevel3(readyToTreat[i], noProblem); | ||||
298 | } else { | ||||
299 | if (op[i-1] == '*') { | ||||
300 | result *= treatLevel3(readyToTreat[i], noProblem); | ||||
301 | } else if(op[i-1] == '/') { | ||||
302 | //may become infinity or NAN. | ||||
303 | result /= treatLevel3(readyToTreat[i], noProblem); | ||||
304 | } | ||||
305 | } | ||||
306 | | ||||
307 | if (noProblem == false) { | ||||
308 | return 0.0; | ||||
309 | } | ||||
310 | } | ||||
311 | | ||||
312 | return result; | ||||
313 | } | ||||
314 | | ||||
315 | /*! | ||||
316 | * \brief treatLevel3 treat a subexpression at the third level of recursion. | ||||
317 | * \param expr The subexpression to treat. | ||||
318 | * \param noProblem A reference to a bool set to true if no problem happened, false otherwise. | ||||
319 | * \return The value of the parsed subexpression or 0 in case of error. | ||||
320 | * | ||||
321 | * The expression should not contain first or second level operations not nested in parenthesis. | ||||
322 | */ | ||||
323 | double treatLevel3(const QString &expr, bool & noProblem) | ||||
324 | { | ||||
325 | | ||||
326 | noProblem = true; | ||||
327 | | ||||
328 | int indexPower = -1; | ||||
329 | int indexCount = 0; | ||||
330 | int subLevels = 0; | ||||
331 | | ||||
332 | for (int i = 0; i < expr.size(); i++) { | ||||
333 | if (expr.at(i) == '(') { | ||||
334 | subLevels++; | ||||
335 | } else if(expr.at(i) == ')') { | ||||
336 | subLevels--; | ||||
337 | if (subLevels < 0) { | ||||
338 | noProblem = false; | ||||
339 | return 0.0; | ||||
340 | } | ||||
341 | } else if (expr.at(i) == '^') { | ||||
342 | if (subLevels == 0) { | ||||
343 | indexPower = i; | ||||
344 | indexCount++; | ||||
345 | } | ||||
346 | } | ||||
347 | } | ||||
348 | | ||||
349 | if (indexCount > 1) { | ||||
350 | noProblem = false; | ||||
351 | return 0.0; | ||||
352 | } | ||||
353 | | ||||
354 | if (indexPower > -1) { | ||||
355 | | ||||
356 | QStringList subExprs = expr.split('^'); | ||||
357 | | ||||
358 | bool noProb1 = true; | ||||
359 | bool noProb2 = true; | ||||
360 | | ||||
361 | double base = treatFuncs(subExprs[0], noProb1); | ||||
362 | double power = treatFuncs(subExprs[1], noProb2); | ||||
363 | | ||||
364 | return qPow(base, power); | ||||
365 | | ||||
366 | } else { | ||||
367 | return treatFuncs(expr, noProblem); | ||||
368 | } | ||||
369 | | ||||
370 | noProblem = false; | ||||
371 | return 0.0; | ||||
372 | | ||||
373 | } | ||||
374 | | ||||
375 | /*! | ||||
376 | * \brief treatFuncs treat the last level of recursion: parenthesis and functions. | ||||
377 | * \param expr The expression to parse. | ||||
378 | * \param noProblem A reference to a bool set to true if no problem happened, false otherwise. | ||||
379 | * \return The value of the parsed subexpression or 0 in case of error. | ||||
380 | * | ||||
381 | * The expression should not contain operators not nested anymore. The subexpressions within parenthesis will be treated by recalling the level 1 function. | ||||
382 | */ | ||||
383 | double treatFuncs(QString const& expr, bool & noProblem) | ||||
384 | { | ||||
385 | | ||||
386 | noProblem = true; | ||||
387 | | ||||
388 | QRegExp funcExp = funcExpr; //copy the expression in the current execution stack, to avoid errors for example when multiple thread call this function. | ||||
389 | QRegExp numExp = numberExpr; | ||||
390 | | ||||
391 | if (funcExp.exactMatch(expr.trimmed())) { | ||||
392 | | ||||
393 | int sign = funcExp.capturedTexts()[1].isEmpty() ? 1 : -1; | ||||
394 | QString func = funcExp.capturedTexts()[2].toLower(); | ||||
395 | QString subExpr = funcExp.capturedTexts()[3]; | ||||
396 | | ||||
397 | double val = treatLevel1(subExpr, noProblem); | ||||
398 | | ||||
399 | if (!noProblem) { | ||||
400 | return 0.0; | ||||
401 | } | ||||
402 | | ||||
403 | if (func.isEmpty()) { | ||||
404 | return sign*val; | ||||
405 | } | ||||
406 | | ||||
407 | if (!supportedFuncs.contains(func)) { | ||||
408 | noProblem = false; | ||||
409 | return 0.0; | ||||
410 | } | ||||
411 | | ||||
412 | //trigonometry is done in degree | ||||
413 | if (func == "cos") { | ||||
414 | val = qCos(val/180*qAcos(-1)); | ||||
415 | } else if (func == "sin") { | ||||
416 | val = qSin(val/180*qAcos(-1)); | ||||
417 | } else if (func == "tan") { | ||||
418 | val = qTan(val/180*qAcos(-1)); | ||||
419 | } else if(func == "acos") { | ||||
420 | val = qAcos(val)*180/qAcos(-1); | ||||
421 | } else if (func == "asin") { | ||||
422 | val = qAsin(val)*180/qAcos(-1); | ||||
423 | } else if (func == "atan") { | ||||
424 | val = qAtan(val)*180/qAcos(-1); | ||||
425 | } else if (func == "exp") { | ||||
426 | val = qExp(val); | ||||
427 | } else if (func == "ln") { | ||||
428 | val = qLn(val); | ||||
429 | } else if (func == "log10") { | ||||
430 | val = qLn(val)/qLn(10.0); | ||||
431 | } else if (func == "abs") { | ||||
432 | val = qAbs(val); | ||||
433 | } | ||||
434 | | ||||
435 | return sign*val; | ||||
436 | } else if(numExp.exactMatch(expr.trimmed())) { | ||||
437 | return expr.toDouble(&noProblem); | ||||
438 | } | ||||
439 | | ||||
440 | noProblem = false; | ||||
441 | return 0.0; | ||||
442 | | ||||
443 | } | ||||
444 | | ||||
445 | //int functions | ||||
446 | /*! | ||||
447 | * \brief treatLevel1 treat an expression at the first level of recursion. | ||||
448 | * \param expr The expression to treat. | ||||
449 | * \param noProblem A reference to a bool set to true if no problem happened, false otherwise. | ||||
450 | * \return The value of the parsed expression or subexpression or 0 in case of error. | ||||
451 | */ | ||||
452 | int treatLevel1Int(QString const& expr, bool & noProblem) | ||||
453 | { | ||||
454 | | ||||
455 | noProblem = true; | ||||
456 | | ||||
457 | QStringList readyToTreat; | ||||
458 | QVector<char> op; | ||||
459 | | ||||
460 | cutLevel1(expr, readyToTreat, op, noProblem); | ||||
461 | if (!noProblem) { | ||||
462 | return 0.0; | ||||
463 | } | ||||
464 | | ||||
465 | if (readyToTreat.contains("")) { | ||||
466 | noProblem = false; | ||||
467 | return 0; | ||||
468 | } | ||||
469 | | ||||
470 | if (op.size() != readyToTreat.size()-1) { | ||||
471 | noProblem = false; | ||||
472 | return 0; | ||||
473 | } | ||||
474 | | ||||
475 | int result = 0; | ||||
476 | | ||||
477 | for (int i = 0; i < readyToTreat.size(); i++) { | ||||
478 | | ||||
479 | if (i == 0) { | ||||
480 | result += treatLevel2Int(readyToTreat[i], noProblem); | ||||
481 | } else { | ||||
482 | if (op[i-1] == '+') { | ||||
483 | result += treatLevel2Int(readyToTreat[i], noProblem); | ||||
484 | } else if(op[i-1] == '-') { | ||||
485 | result -= treatLevel2Int(readyToTreat[i], noProblem); | ||||
486 | } | ||||
487 | } | ||||
488 | | ||||
489 | if (noProblem == false) { | ||||
490 | return 0; | ||||
491 | } | ||||
492 | } | ||||
493 | | ||||
494 | return result; | ||||
495 | | ||||
496 | } | ||||
497 | | ||||
498 | /*! | ||||
499 | * \brief treatLevel2 treat a subexpression at the second level of recursion. | ||||
500 | * \param expr The subexpression to treat. | ||||
501 | * \param noProblem A reference to a bool set to true if no problem happened, false otherwise. | ||||
502 | * \return The value of the parsed subexpression or 0 in case of error. | ||||
503 | * | ||||
504 | * The expression should not contain first level operations not nested in parenthesis. | ||||
505 | */ | ||||
506 | int treatLevel2Int(const QString &expr, bool &noProblem) | ||||
507 | { | ||||
508 | | ||||
509 | noProblem = true; | ||||
510 | | ||||
511 | QStringList readyToTreat; | ||||
512 | QVector<char> op; | ||||
513 | | ||||
514 | cutLevel2(expr, readyToTreat, op, noProblem); | ||||
515 | if (!noProblem) { | ||||
516 | return 0.0; | ||||
517 | } | ||||
518 | | ||||
519 | if (readyToTreat.contains("")) { | ||||
520 | noProblem = false; | ||||
521 | return 0; | ||||
522 | } | ||||
523 | | ||||
524 | if (op.size() != readyToTreat.size()-1) { | ||||
525 | noProblem = false; | ||||
526 | return 0; | ||||
527 | } | ||||
528 | | ||||
529 | int result = 0; | ||||
530 | | ||||
531 | for (int i = 0; i < readyToTreat.size(); i++) { | ||||
532 | | ||||
533 | if (i == 0) { | ||||
534 | result += treatFuncsInt(readyToTreat[i], noProblem); | ||||
535 | } else { | ||||
536 | if (op[i-1] == '*') { | ||||
537 | result *= treatFuncsInt(readyToTreat[i], noProblem); | ||||
538 | } else if(op[i-1] == '/') { | ||||
539 | int value = treatFuncsInt(readyToTreat[i], noProblem); | ||||
540 | | ||||
541 | //int int airthmetic it's impossible to divide by 0. | ||||
542 | if (value == 0) { | ||||
543 | noProblem = false; | ||||
544 | return 0; | ||||
545 | } | ||||
546 | | ||||
547 | result /= value; | ||||
548 | } | ||||
549 | } | ||||
550 | | ||||
551 | if (noProblem == false) { | ||||
552 | return 0; | ||||
553 | } | ||||
554 | } | ||||
555 | | ||||
556 | return result; | ||||
557 | | ||||
558 | } | ||||
559 | | ||||
560 | /*! | ||||
561 | * \brief treatFuncs treat the last level of recursion: parenthesis | ||||
562 | * \param expr The expression to parse. | ||||
563 | * \param noProblem A reference to a bool set to true if no problem happened, false otherwise. | ||||
564 | * \return The value of the parsed subexpression or 0 in case of error. | ||||
565 | * | ||||
566 | * The expression should not contain operators not nested anymore. The subexpressions within parenthesis will be treated by recalling the level 1 function. | ||||
567 | */ | ||||
568 | int treatFuncsInt(QString const& expr, bool & noProblem) | ||||
569 | { | ||||
570 | | ||||
571 | noProblem = true; | ||||
572 | | ||||
573 | QRegExp funcExpInteger = funcExprInteger; | ||||
574 | QRegExp integerExp = integerExpr; | ||||
575 | QRegExp numberExp = numberExpr; | ||||
576 | | ||||
577 | if (funcExpInteger.exactMatch(expr.trimmed())) { | ||||
578 | | ||||
579 | int sign = funcExpInteger.capturedTexts()[1].isEmpty() ? 1 : -1; | ||||
580 | QString subExpr = funcExpInteger.capturedTexts()[2]; | ||||
581 | | ||||
582 | int val = treatLevel1Int(subExpr, noProblem); | ||||
583 | | ||||
584 | if (!noProblem) { | ||||
585 | return 0; | ||||
586 | } | ||||
587 | | ||||
588 | return sign*val; | ||||
589 | | ||||
590 | } else if(integerExp.exactMatch(expr.trimmed())) { | ||||
591 | return QVariant(expr).toInt(&noProblem); | ||||
592 | } else if(numberExp.exactMatch(expr.trimmed())) { | ||||
593 | double value = qFloor( QVariant(expr).toDouble(&noProblem)); | ||||
594 | return (value > 0.0) ? value: value + 1; | ||||
595 | } | ||||
596 | | ||||
597 | noProblem = false; | ||||
598 | return 0; | ||||
599 | | ||||
600 | } |