1 /*
2 * Copyright 2006-2012 Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 * John Scipione <jscipione@gmail.com>
8 * Ingo Weinhold <bonefish@cs.tu-berlin.de>
9 */
10
11 #include <ExpressionParser.h>
12
13 #include <ctype.h>
14 #include <math.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <strings.h>
18
19 #include <m_apm.h>
20
21
22 static const int32 kMaxDecimalPlaces = 32;
23
24
25 enum {
26 TOKEN_NONE = 0,
27 TOKEN_IDENTIFIER,
28 TOKEN_CONSTANT,
29
30 TOKEN_END_OF_LINE = '\n',
31
32 TOKEN_PLUS = '+',
33 TOKEN_MINUS = '-',
34
35 TOKEN_STAR = '*',
36 TOKEN_SLASH = '/',
37 TOKEN_MODULO = '%',
38
39 TOKEN_POWER = '^',
40 TOKEN_FACTORIAL = '!',
41
42 TOKEN_OPENING_BRACKET = '(',
43 TOKEN_CLOSING_BRACKET = ')',
44
45 TOKEN_AND = '&',
46 TOKEN_OR = '|',
47 TOKEN_NOT = '~'
48 };
49
50
51 struct ExpressionParser::Token {
TokenExpressionParser::Token52 Token()
53 : string(""),
54 type(TOKEN_NONE),
55 value(0),
56 position(0)
57 {
58 }
59
TokenExpressionParser::Token60 Token(const Token& other)
61 : string(other.string),
62 type(other.type),
63 value(other.value),
64 position(other.position)
65 {
66 }
67
TokenExpressionParser::Token68 Token(const char* string, int32 length, int32 position, int32 type)
69 : string(string, length),
70 type(type),
71 value(0),
72 position(position)
73 {
74 }
75
operator =ExpressionParser::Token76 Token& operator=(const Token& other)
77 {
78 string = other.string;
79 type = other.type;
80 value = other.value;
81 position = other.position;
82 return *this;
83 }
84
85 BString string;
86 int32 type;
87 MAPM value;
88
89 int32 position;
90 };
91
92
93 class ExpressionParser::Tokenizer {
94 public:
Tokenizer()95 Tokenizer()
96 : fString(""),
97 fCurrentChar(NULL),
98 fCurrentToken(),
99 fReuseToken(false),
100 fHexSupport(false),
101 fDecimalSeparator("."),
102 fGroupSeparator(",")
103 {
104 }
105
SetSupportHexInput(bool enabled)106 void SetSupportHexInput(bool enabled)
107 {
108 fHexSupport = enabled;
109 }
110
SetTo(const char * string)111 void SetTo(const char* string)
112 {
113 fString = string;
114 fCurrentChar = fString.String();
115 fCurrentToken = Token();
116 fReuseToken = false;
117 }
118
NextToken()119 const Token& NextToken()
120 {
121 if (fCurrentToken.type == TOKEN_END_OF_LINE)
122 return fCurrentToken;
123
124 if (fReuseToken) {
125 fReuseToken = false;
126 //printf("next token (recycled): '%s'\n", fCurrentToken.string.String());
127 return fCurrentToken;
128 }
129
130 while (*fCurrentChar != 0 && isspace(*fCurrentChar))
131 fCurrentChar++;
132
133 int32 decimalLen = fDecimalSeparator.Length();
134 int32 groupLen = fGroupSeparator.Length();
135
136 if (*fCurrentChar == 0 || decimalLen == 0)
137 return fCurrentToken = Token("", 0, _CurrentPos(), TOKEN_END_OF_LINE);
138
139 if (*fCurrentChar == fDecimalSeparator[0] || isdigit(*fCurrentChar)) {
140 if (fHexSupport && *fCurrentChar == '0' && fCurrentChar[1] == 'x')
141 return _ParseHexNumber();
142
143 BString temp;
144
145 const char* begin = fCurrentChar;
146
147 // optional digits before the comma
148 while (isdigit(*fCurrentChar) ||
149 (groupLen > 0 && *fCurrentChar == fGroupSeparator[0])) {
150 if (groupLen > 0 && *fCurrentChar == fGroupSeparator[0]) {
151 int i = 0;
152 while (i < groupLen && *fCurrentChar == fGroupSeparator[i]) {
153 fCurrentChar++;
154 i++;
155 }
156 } else {
157 temp << *fCurrentChar;
158 fCurrentChar++;
159 }
160 }
161
162 // optional post comma part
163 // (required if there are no digits before the comma)
164 if (*fCurrentChar == fDecimalSeparator[0]) {
165 int i = 0;
166 while (i < decimalLen && *fCurrentChar == fDecimalSeparator[i]) {
167 fCurrentChar++;
168 i++;
169 }
170
171 temp << '.';
172
173 // optional post comma digits
174 while (isdigit(*fCurrentChar)) {
175 temp << *fCurrentChar;
176 fCurrentChar++;
177 }
178 }
179
180 // optional exponent part
181 if (*fCurrentChar == 'E') {
182 temp << *fCurrentChar;
183 fCurrentChar++;
184
185 // optional exponent sign
186 if (*fCurrentChar == '+' || *fCurrentChar == '-') {
187 temp << *fCurrentChar;
188 fCurrentChar++;
189 }
190
191 // required exponent digits
192 if (!isdigit(*fCurrentChar)) {
193 throw ParseException("missing exponent in constant",
194 fCurrentChar - begin);
195 }
196
197 while (isdigit(*fCurrentChar)) {
198 temp << *fCurrentChar;
199 fCurrentChar++;
200 }
201 }
202
203 int32 length = fCurrentChar - begin;
204 BString test = temp;
205 test << "&_";
206 double value;
207 char t[2];
208 int32 matches = sscanf(test.String(), "%lf&%s", &value, t);
209 if (matches != 2) {
210 throw ParseException("error in constant",
211 _CurrentPos() - length);
212 }
213
214 fCurrentToken = Token(begin, length, _CurrentPos() - length,
215 TOKEN_CONSTANT);
216 fCurrentToken.value = temp.String();
217 } else if (isalpha(*fCurrentChar) && *fCurrentChar != 'x') {
218 const char* begin = fCurrentChar;
219 while (*fCurrentChar != 0 && (isalpha(*fCurrentChar)
220 || isdigit(*fCurrentChar))) {
221 fCurrentChar++;
222 }
223 int32 length = fCurrentChar - begin;
224 fCurrentToken = Token(begin, length, _CurrentPos() - length,
225 TOKEN_IDENTIFIER);
226 } else if (strncmp(fCurrentChar, "π", 2) == 0) {
227 fCurrentToken = Token(fCurrentChar, 2, _CurrentPos() - 1,
228 TOKEN_IDENTIFIER);
229 fCurrentChar += 2;
230 } else {
231 int32 type = TOKEN_NONE;
232
233 switch (*fCurrentChar) {
234 case TOKEN_PLUS:
235 case TOKEN_MINUS:
236 case TOKEN_STAR:
237 case TOKEN_SLASH:
238 case TOKEN_MODULO:
239 case TOKEN_POWER:
240 case TOKEN_FACTORIAL:
241 case TOKEN_OPENING_BRACKET:
242 case TOKEN_CLOSING_BRACKET:
243 case TOKEN_AND:
244 case TOKEN_OR:
245 case TOKEN_NOT:
246 case TOKEN_END_OF_LINE:
247 type = *fCurrentChar;
248 break;
249
250 case '\\':
251 case ':':
252 type = TOKEN_SLASH;
253 break;
254
255 case 'x':
256 if (!fHexSupport) {
257 type = TOKEN_STAR;
258 break;
259 }
260 // fall through
261
262 default:
263 throw ParseException("unexpected character", _CurrentPos());
264 }
265 fCurrentToken = Token(fCurrentChar, 1, _CurrentPos(), type);
266 fCurrentChar++;
267 }
268
269 //printf("next token: '%s'\n", fCurrentToken.string.String());
270 return fCurrentToken;
271 }
272
RewindToken()273 void RewindToken()
274 {
275 fReuseToken = true;
276 }
277
DecimalSeparator()278 BString DecimalSeparator()
279 {
280 return fDecimalSeparator;
281 }
282
GroupSeparator()283 BString GroupSeparator()
284 {
285 return fGroupSeparator;
286 }
287
SetSeparators(BString decimal,BString group)288 void SetSeparators(BString decimal, BString group)
289 {
290 fDecimalSeparator = decimal;
291 fGroupSeparator = group;
292 }
293
294 private:
_IsHexDigit(char c)295 static bool _IsHexDigit(char c)
296 {
297 return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
298 }
299
_ParseHexNumber()300 Token& _ParseHexNumber()
301 {
302 const char* begin = fCurrentChar;
303 fCurrentChar += 2;
304 // skip "0x"
305
306 if (!_IsHexDigit(*fCurrentChar))
307 throw ParseException("expected hex digit", _CurrentPos());
308
309 fCurrentChar++;
310 while (_IsHexDigit(*fCurrentChar))
311 fCurrentChar++;
312
313 int32 length = fCurrentChar - begin;
314 fCurrentToken = Token(begin, length, _CurrentPos() - length,
315 TOKEN_CONSTANT);
316
317 // MAPM has no conversion from long long, so we need to improvise.
318 uint64 value = strtoll(fCurrentToken.string.String(), NULL, 0);
319 if (value <= 0x7fffffff) {
320 fCurrentToken.value = (long)value;
321 } else {
322 fCurrentToken.value = (int)(value >> 60);
323 fCurrentToken.value *= 1 << 30;
324 fCurrentToken.value += (int)((value >> 30) & 0x3fffffff);
325 fCurrentToken.value *= 1 << 30;
326 fCurrentToken.value += (int)(value& 0x3fffffff);
327 }
328
329 return fCurrentToken;
330 }
331
_CurrentPos() const332 int32 _CurrentPos() const
333 {
334 return fCurrentChar - fString.String();
335 }
336
337 BString fString;
338 const char* fCurrentChar;
339 Token fCurrentToken;
340 bool fReuseToken;
341 bool fHexSupport;
342 BString fDecimalSeparator;
343 BString fGroupSeparator;
344 };
345
346
ExpressionParser()347 ExpressionParser::ExpressionParser()
348 : fTokenizer(new Tokenizer()),
349 fDegreeMode(false)
350 {
351 }
352
353
~ExpressionParser()354 ExpressionParser::~ExpressionParser()
355 {
356 delete fTokenizer;
357 }
358
359
360 bool
DegreeMode()361 ExpressionParser::DegreeMode()
362 {
363 return fDegreeMode;
364 }
365
366
367 void
SetDegreeMode(bool degrees)368 ExpressionParser::SetDegreeMode(bool degrees)
369 {
370 fDegreeMode = degrees;
371 }
372
373
374 void
SetSupportHexInput(bool enabled)375 ExpressionParser::SetSupportHexInput(bool enabled)
376 {
377 fTokenizer->SetSupportHexInput(enabled);
378 }
379
380
381 BString
Evaluate(const char * expressionString)382 ExpressionParser::Evaluate(const char* expressionString)
383 {
384 fTokenizer->SetTo(expressionString);
385
386 MAPM value = _ParseBinary();
387 Token token = fTokenizer->NextToken();
388 if (token.type != TOKEN_END_OF_LINE)
389 throw ParseException("parse error", token.position);
390
391 if (value == 0)
392 return BString("0");
393
394 char* buffer = value.toFixPtStringExp(kMaxDecimalPlaces,
395 '.', 0, 0);
396
397 if (buffer == NULL)
398 throw ParseException("out of memory", 0);
399
400 // remove surplus zeros
401 int32 lastChar = strlen(buffer) - 1;
402 if (strchr(buffer, '.')) {
403 while (buffer[lastChar] == '0')
404 lastChar--;
405
406 if (buffer[lastChar] == '.')
407 lastChar--;
408 }
409
410 BString result(buffer, lastChar + 1);
411 result.Replace(".", fTokenizer->DecimalSeparator(), 1);
412 free(buffer);
413 return result;
414 }
415
416
417 int64
EvaluateToInt64(const char * expressionString)418 ExpressionParser::EvaluateToInt64(const char* expressionString)
419 {
420 fTokenizer->SetTo(expressionString);
421
422 MAPM value = _ParseBinary();
423 Token token = fTokenizer->NextToken();
424 if (token.type != TOKEN_END_OF_LINE)
425 throw ParseException("parse error", token.position);
426
427 char buffer[128];
428 value.toIntegerString(buffer);
429
430 return strtoll(buffer, NULL, 0);
431 }
432
433
434 double
EvaluateToDouble(const char * expressionString)435 ExpressionParser::EvaluateToDouble(const char* expressionString)
436 {
437 fTokenizer->SetTo(expressionString);
438
439 MAPM value = _ParseBinary();
440 Token token = fTokenizer->NextToken();
441 if (token.type != TOKEN_END_OF_LINE)
442 throw ParseException("parse error", token.position);
443
444 char buffer[1024];
445 value.toString(buffer, sizeof(buffer) - 4);
446
447 return strtod(buffer, NULL);
448 }
449
450
451 MAPM
_ParseBinary()452 ExpressionParser::_ParseBinary()
453 {
454 return _ParseSum();
455 // binary operation appearantly not supported by m_apm library,
456 // should not be too hard to implement though....
457
458 // double value = _ParseSum();
459 //
460 // while (true) {
461 // Token token = fTokenizer->NextToken();
462 // switch (token.type) {
463 // case TOKEN_AND:
464 // value = (uint64)value & (uint64)_ParseSum();
465 // break;
466 // case TOKEN_OR:
467 // value = (uint64)value | (uint64)_ParseSum();
468 // break;
469 //
470 // default:
471 // fTokenizer->RewindToken();
472 // return value;
473 // }
474 // }
475 }
476
477
478 MAPM
_ParseSum()479 ExpressionParser::_ParseSum()
480 {
481 // TODO: check isnan()...
482 MAPM value = _ParseProduct();
483
484 while (true) {
485 Token token = fTokenizer->NextToken();
486 switch (token.type) {
487 case TOKEN_PLUS:
488 value = value + _ParseProduct();
489 break;
490 case TOKEN_MINUS:
491 value = value - _ParseProduct();
492 break;
493
494 default:
495 fTokenizer->RewindToken();
496 return _ParseFactorial(value);
497 }
498 }
499 }
500
501
502 MAPM
_ParseProduct()503 ExpressionParser::_ParseProduct()
504 {
505 // TODO: check isnan()...
506 MAPM value = _ParsePower();
507
508 while (true) {
509 Token token = fTokenizer->NextToken();
510 switch (token.type) {
511 case TOKEN_STAR:
512 value = value * _ParsePower();
513 break;
514 case TOKEN_SLASH: {
515 MAPM rhs = _ParsePower();
516 if (rhs == MAPM(0))
517 throw ParseException("division by zero", token.position);
518 value = value / rhs;
519 break;
520 }
521 case TOKEN_MODULO: {
522 MAPM rhs = _ParsePower();
523 if (rhs == MAPM(0))
524 throw ParseException("modulo by zero", token.position);
525 value = value % rhs;
526 break;
527 }
528
529 default:
530 fTokenizer->RewindToken();
531 return _ParseFactorial(value);
532 }
533 }
534 }
535
536
537 MAPM
_ParsePower()538 ExpressionParser::_ParsePower()
539 {
540 MAPM value = _ParseUnary();
541
542 while (true) {
543 Token token = fTokenizer->NextToken();
544 if (token.type != TOKEN_POWER) {
545 fTokenizer->RewindToken();
546 return _ParseFactorial(value);
547 }
548 value = value.pow(_ParseUnary());
549 }
550 }
551
552
553 MAPM
_ParseUnary()554 ExpressionParser::_ParseUnary()
555 {
556 Token token = fTokenizer->NextToken();
557 if (token.type == TOKEN_END_OF_LINE)
558 throw ParseException("unexpected end of expression", token.position);
559
560 switch (token.type) {
561 case TOKEN_PLUS:
562 return _ParseUnary();
563 case TOKEN_MINUS:
564 return -_ParseUnary();
565 // TODO: Implement !
566 // case TOKEN_NOT:
567 // return ~(uint64)_ParseUnary();
568
569 case TOKEN_IDENTIFIER:
570 return _ParseFunction(token);
571
572 default:
573 fTokenizer->RewindToken();
574 return _ParseAtom();
575 }
576
577 return MAPM(0);
578 }
579
580
581 struct Function {
582 const char* name;
583 int argumentCount;
584 void* function;
585 MAPM value;
586 };
587
588
589 void
_InitArguments(MAPM values[],int32 argumentCount)590 ExpressionParser::_InitArguments(MAPM values[], int32 argumentCount)
591 {
592 _EatToken(TOKEN_OPENING_BRACKET);
593
594 for (int32 i = 0; i < argumentCount; i++)
595 values[i] = _ParseBinary();
596
597 _EatToken(TOKEN_CLOSING_BRACKET);
598 }
599
600
601 MAPM
_ParseFunction(const Token & token)602 ExpressionParser::_ParseFunction(const Token& token)
603 {
604 if (token.string == "e")
605 return _ParseFactorial(MAPM(MM_E));
606 else if (token.string.ICompare("pi") == 0 || token.string == "π")
607 return _ParseFactorial(MAPM(MM_PI));
608
609 // hard coded cases for different count of arguments
610 // supports functions with 3 arguments at most
611
612 MAPM values[3];
613
614 if (strcasecmp("abs", token.string.String()) == 0) {
615 _InitArguments(values, 1);
616 return _ParseFactorial(values[0].abs());
617 } else if (strcasecmp("acos", token.string.String()) == 0) {
618 _InitArguments(values, 1);
619 if (fDegreeMode)
620 values[0] = values[0] * MM_PI / 180;
621
622 if (values[0] < -1 || values[0] > 1)
623 throw ParseException("out of domain", token.position);
624
625 return _ParseFactorial(values[0].acos());
626 } else if (strcasecmp("asin", token.string.String()) == 0) {
627 _InitArguments(values, 1);
628 if (fDegreeMode)
629 values[0] = values[0] * MM_PI / 180;
630
631 if (values[0] < -1 || values[0] > 1)
632 throw ParseException("out of domain", token.position);
633
634 return _ParseFactorial(values[0].asin());
635 } else if (strcasecmp("atan", token.string.String()) == 0) {
636 _InitArguments(values, 1);
637 if (fDegreeMode)
638 values[0] = values[0] * MM_PI / 180;
639
640 return _ParseFactorial(values[0].atan());
641 } else if (strcasecmp("atan2", token.string.String()) == 0) {
642 _InitArguments(values, 2);
643
644 if (fDegreeMode) {
645 values[0] = values[0] * MM_PI / 180;
646 values[1] = values[1] * MM_PI / 180;
647 }
648
649 return _ParseFactorial(values[0].atan2(values[1]));
650 } else if (strcasecmp("cbrt", token.string.String()) == 0) {
651 _InitArguments(values, 1);
652 return _ParseFactorial(values[0].cbrt());
653 } else if (strcasecmp("ceil", token.string.String()) == 0) {
654 _InitArguments(values, 1);
655 return _ParseFactorial(values[0].ceil());
656 } else if (strcasecmp("cos", token.string.String()) == 0) {
657 _InitArguments(values, 1);
658 if (fDegreeMode)
659 values[0] = values[0] * MM_PI / 180;
660
661 return _ParseFactorial(values[0].cos());
662 } else if (strcasecmp("cosh", token.string.String()) == 0) {
663 _InitArguments(values, 1);
664 // This function always uses radians
665 return _ParseFactorial(values[0].cosh());
666 } else if (strcasecmp("exp", token.string.String()) == 0) {
667 _InitArguments(values, 1);
668 return _ParseFactorial(values[0].exp());
669 } else if (strcasecmp("floor", token.string.String()) == 0) {
670 _InitArguments(values, 1);
671 return _ParseFactorial(values[0].floor());
672 } else if (strcasecmp("ln", token.string.String()) == 0) {
673 _InitArguments(values, 1);
674 if (values[0] <= 0)
675 throw ParseException("out of domain", token.position);
676
677 return _ParseFactorial(values[0].log());
678 } else if (strcasecmp("log", token.string.String()) == 0) {
679 _InitArguments(values, 1);
680 if (values[0] <= 0)
681 throw ParseException("out of domain", token.position);
682
683 return _ParseFactorial(values[0].log10());
684 } else if (strcasecmp("pow", token.string.String()) == 0) {
685 _InitArguments(values, 2);
686 return _ParseFactorial(values[0].pow(values[1]));
687 } else if (strcasecmp("sin", token.string.String()) == 0) {
688 _InitArguments(values, 1);
689 if (fDegreeMode)
690 values[0] = values[0] * MM_PI / 180;
691
692 return _ParseFactorial(values[0].sin());
693 } else if (strcasecmp("sinh", token.string.String()) == 0) {
694 _InitArguments(values, 1);
695 // This function always uses radians
696 return _ParseFactorial(values[0].sinh());
697 } else if (strcasecmp("sqrt", token.string.String()) == 0) {
698 _InitArguments(values, 1);
699 if (values[0] < 0)
700 throw ParseException("out of domain", token.position);
701
702 return _ParseFactorial(values[0].sqrt());
703 } else if (strcasecmp("tan", token.string.String()) == 0) {
704 _InitArguments(values, 1);
705 if (fDegreeMode)
706 values[0] = values[0] * MM_PI / 180;
707
708 MAPM divided_by_half_pi = values[0] / MM_HALF_PI;
709 if (divided_by_half_pi.is_integer() && divided_by_half_pi.is_odd())
710 throw ParseException("out of domain", token.position);
711
712 return _ParseFactorial(values[0].tan());
713 } else if (strcasecmp("tanh", token.string.String()) == 0) {
714 _InitArguments(values, 1);
715 // This function always uses radians
716 return _ParseFactorial(values[0].tanh());
717 }
718
719 throw ParseException("unknown identifier", token.position);
720 }
721
722
723 MAPM
_ParseAtom()724 ExpressionParser::_ParseAtom()
725 {
726 Token token = fTokenizer->NextToken();
727 if (token.type == TOKEN_END_OF_LINE)
728 throw ParseException("unexpected end of expression", token.position);
729
730 if (token.type == TOKEN_CONSTANT)
731 return _ParseFactorial(token.value);
732
733 fTokenizer->RewindToken();
734
735 _EatToken(TOKEN_OPENING_BRACKET);
736
737 MAPM value = _ParseBinary();
738
739 _EatToken(TOKEN_CLOSING_BRACKET);
740
741 return _ParseFactorial(value);
742 }
743
744
745 MAPM
_ParseFactorial(MAPM value)746 ExpressionParser::_ParseFactorial(MAPM value)
747 {
748 if (fTokenizer->NextToken().type == TOKEN_FACTORIAL) {
749 fTokenizer->RewindToken();
750 _EatToken(TOKEN_FACTORIAL);
751 if (value < 1000)
752 return value.factorial();
753 else {
754 // Use Stirling's approximation (9 term expansion)
755 // http://en.wikipedia.org/wiki/Stirling%27s_approximation
756 // http://www.wolframalpha.com/input/?i=stirling%27s+series
757 // all constants must fit in a signed long for MAPM
758 // (LONG_MAX = 2147483647)
759 return value.pow(value) / value.exp()
760 * (MAPM(2) * MAPM(MM_PI) * value).sqrt()
761 * (MAPM(1) + (MAPM(1) / (MAPM(12) * value))
762 + (MAPM(1) / (MAPM(288) * value.pow(2)))
763 - (MAPM(139) / (MAPM(51840) * value.pow(3)))
764 - (MAPM(571) / (MAPM(2488320) * value.pow(4)))
765 + (MAPM(163879) / (MAPM(209018880) * value.pow(5)))
766 // 2147483647 * 35 + 84869155 = 75246796800
767 + (MAPM(5246819) / ((MAPM(2147483647) * MAPM(35)
768 + MAPM(84869155)) * value.pow(6)))
769 // 2147483647 * 420 + 1018429860 = 902961561600
770 - (MAPM(534703531) / ((MAPM(2147483647) * MAPM(420)
771 + MAPM(1018429860)) * value.pow(7)))
772 // 2147483647 * 2 + 188163965 = 4483131259
773 // 2147483647 * 40366 + 985018798 = 86686309913600
774 - ((MAPM(2147483647) * MAPM(2) + MAPM(188163965))
775 / ((MAPM(2147483647) * MAPM(40366) + MAPM(985018798))
776 * value.pow(8)))
777 // 2147483647 * 201287 + 1380758682 = 432261921612371
778 // 2147483647 * 239771232 + 1145740896
779 // = 514904800886784000
780 + ((MAPM(2147483647) * MAPM(201287) + MAPM(1380758682))
781 / ((MAPM(2147483647) * MAPM(239771232)
782 + MAPM(1145740896))
783 * value.pow(9))));
784 }
785 }
786
787 fTokenizer->RewindToken();
788 return value;
789 }
790
791
792 void
_EatToken(int32 type)793 ExpressionParser::_EatToken(int32 type)
794 {
795 Token token = fTokenizer->NextToken();
796 if (token.type != type) {
797 BString expected;
798 switch (type) {
799 case TOKEN_IDENTIFIER:
800 expected = "an identifier";
801 break;
802
803 case TOKEN_CONSTANT:
804 expected = "a constant";
805 break;
806
807 case TOKEN_PLUS:
808 case TOKEN_MINUS:
809 case TOKEN_STAR:
810 case TOKEN_MODULO:
811 case TOKEN_POWER:
812 case TOKEN_FACTORIAL:
813 case TOKEN_OPENING_BRACKET:
814 case TOKEN_CLOSING_BRACKET:
815 case TOKEN_AND:
816 case TOKEN_OR:
817 case TOKEN_NOT:
818 expected << "'" << (char)type << "'";
819 break;
820
821 case TOKEN_SLASH:
822 expected = "'/', '\\', or ':'";
823 break;
824
825 case TOKEN_END_OF_LINE:
826 expected = "'\\n'";
827 break;
828 }
829 BString temp;
830 temp << "Expected " << expected.String() << " got '" << token.string << "'";
831 throw ParseException(temp.String(), token.position);
832 }
833 }
834
835
836 status_t
SetSeparators(BString decimal,BString group)837 ExpressionParser::SetSeparators(BString decimal, BString group)
838 {
839 if (decimal == group)
840 return B_ERROR;
841
842 fTokenizer->SetSeparators(decimal, group);
843
844 return B_OK;
845 }
846