Implement MathSignal
[pulseview.git] / pv / exprtk.hpp
1 /*
2  ******************************************************************
3  *           C++ Mathematical Expression Toolkit Library          *
4  *                                                                *
5  * Author: Arash Partow (1999-2020)                               *
6  * URL: http://www.partow.net/programming/exprtk/index.html       *
7  *                                                                *
8  * Copyright notice:                                              *
9  * Free use of the C++ Mathematical Expression Toolkit Library is *
10  * permitted under the guidelines and in accordance with the most *
11  * current version of the MIT License.                            *
12  * http://www.opensource.org/licenses/MIT                         *
13  *                                                                *
14  * Example expressions:                                           *
15  * (00) (y + x / y) * (x - y / x)                                 *
16  * (01) (x^2 / sin(2 * pi / y)) - x / 2                           *
17  * (02) sqrt(1 - (x^2))                                           *
18  * (03) 1 - sin(2 * x) + cos(pi / y)                              *
19  * (04) a * exp(2 * t) + c                                        *
20  * (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z)        *
21  * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x          *
22  * (07) z := x + sin(2 * pi / y)                                  *
23  * (08) u := 2 * (pi * z) / (w := x + cos(y / pi))                *
24  * (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1)            *
25  * (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0)     *
26  * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1)  *
27  * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)]                  *
28  *                                                                *
29  ******************************************************************
30 */
31
32
33 #ifndef INCLUDE_EXPRTK_HPP
34 #define INCLUDE_EXPRTK_HPP
35
36
37 #include <algorithm>
38 #include <cctype>
39 #include <cmath>
40 #include <complex>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
44 #include <deque>
45 #include <exception>
46 #include <functional>
47 #include <iterator>
48 #include <limits>
49 #include <list>
50 #include <map>
51 #include <set>
52 #include <stack>
53 #include <stdexcept>
54 #include <string>
55 #include <utility>
56 #include <vector>
57
58
59 namespace exprtk
60 {
61    #ifdef exprtk_enable_debugging
62      #define exprtk_debug(params) printf params
63    #else
64      #define exprtk_debug(params) (void)0
65    #endif
66
67    #define exprtk_error_location             \
68    "exprtk.hpp:" + details::to_str(__LINE__) \
69
70    #if defined(__GNUC__) && (__GNUC__  >= 7)
71
72       #define exprtk_disable_fallthrough_begin                      \
73       _Pragma ("GCC diagnostic push")                               \
74       _Pragma ("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \
75
76       #define exprtk_disable_fallthrough_end                        \
77       _Pragma ("GCC diagnostic pop")                                \
78
79    #else
80       #define exprtk_disable_fallthrough_begin (void)0;
81       #define exprtk_disable_fallthrough_end   (void)0;
82    #endif
83
84    namespace details
85    {
86       typedef unsigned char            uchar_t;
87       typedef char                      char_t;
88       typedef uchar_t*               uchar_ptr;
89       typedef char_t*                 char_ptr;
90       typedef uchar_t const*        uchar_cptr;
91       typedef char_t const*          char_cptr;
92       typedef unsigned long long int _uint64_t;
93       typedef long long int           _int64_t;
94
95       inline bool is_whitespace(const char_t c)
96       {
97          return (' '  == c) || ('\n' == c) ||
98                 ('\r' == c) || ('\t' == c) ||
99                 ('\b' == c) || ('\v' == c) ||
100                 ('\f' == c) ;
101       }
102
103       inline bool is_operator_char(const char_t c)
104       {
105          return ('+' == c) || ('-' == c) ||
106                 ('*' == c) || ('/' == c) ||
107                 ('^' == c) || ('<' == c) ||
108                 ('>' == c) || ('=' == c) ||
109                 (',' == c) || ('!' == c) ||
110                 ('(' == c) || (')' == c) ||
111                 ('[' == c) || (']' == c) ||
112                 ('{' == c) || ('}' == c) ||
113                 ('%' == c) || (':' == c) ||
114                 ('?' == c) || ('&' == c) ||
115                 ('|' == c) || (';' == c) ;
116       }
117
118       inline bool is_letter(const char_t c)
119       {
120          return (('a' <= c) && (c <= 'z')) ||
121                 (('A' <= c) && (c <= 'Z')) ;
122       }
123
124       inline bool is_digit(const char_t c)
125       {
126          return ('0' <= c) && (c <= '9');
127       }
128
129       inline bool is_letter_or_digit(const char_t c)
130       {
131          return is_letter(c) || is_digit(c);
132       }
133
134       inline bool is_left_bracket(const char_t c)
135       {
136          return ('(' == c) || ('[' == c) || ('{' == c);
137       }
138
139       inline bool is_right_bracket(const char_t c)
140       {
141          return (')' == c) || (']' == c) || ('}' == c);
142       }
143
144       inline bool is_bracket(const char_t c)
145       {
146          return is_left_bracket(c) || is_right_bracket(c);
147       }
148
149       inline bool is_sign(const char_t c)
150       {
151          return ('+' == c) || ('-' == c);
152       }
153
154       inline bool is_invalid(const char_t c)
155       {
156          return !is_whitespace   (c) &&
157                 !is_operator_char(c) &&
158                 !is_letter       (c) &&
159                 !is_digit        (c) &&
160                 ('.'  != c)          &&
161                 ('_'  != c)          &&
162                 ('$'  != c)          &&
163                 ('~'  != c)          &&
164                 ('\'' != c);
165       }
166
167       #ifndef exprtk_disable_caseinsensitivity
168       inline void case_normalise(std::string& s)
169       {
170          for (std::size_t i = 0; i < s.size(); ++i)
171          {
172             s[i] = static_cast<std::string::value_type>(std::tolower(s[i]));
173          }
174       }
175
176       inline bool imatch(const char_t c1, const char_t c2)
177       {
178          return std::tolower(c1) == std::tolower(c2);
179       }
180
181       inline bool imatch(const std::string& s1, const std::string& s2)
182       {
183          if (s1.size() == s2.size())
184          {
185             for (std::size_t i = 0; i < s1.size(); ++i)
186             {
187                if (std::tolower(s1[i]) != std::tolower(s2[i]))
188                {
189                   return false;
190                }
191             }
192
193             return true;
194          }
195
196          return false;
197       }
198
199       struct ilesscompare
200       {
201          inline bool operator() (const std::string& s1, const std::string& s2) const
202          {
203             const std::size_t length = std::min(s1.size(),s2.size());
204
205             for (std::size_t i = 0; i < length;  ++i)
206             {
207                const char_t c1 = static_cast<char>(std::tolower(s1[i]));
208                const char_t c2 = static_cast<char>(std::tolower(s2[i]));
209
210                if (c1 > c2)
211                   return false;
212                else if (c1 < c2)
213                   return true;
214             }
215
216             return s1.size() < s2.size();
217          }
218       };
219
220       #else
221       inline void case_normalise(std::string&)
222       {}
223
224       inline bool imatch(const char_t c1, const char_t c2)
225       {
226          return c1 == c2;
227       }
228
229       inline bool imatch(const std::string& s1, const std::string& s2)
230       {
231          return s1 == s2;
232       }
233
234       struct ilesscompare
235       {
236          inline bool operator() (const std::string& s1, const std::string& s2) const
237          {
238             return s1 < s2;
239          }
240       };
241       #endif
242
243       inline bool is_valid_sf_symbol(const std::string& symbol)
244       {
245          // Special function: $f12 or $F34
246          return (4 == symbol.size())  &&
247                 ('$' == symbol[0])    &&
248                 imatch('f',symbol[1]) &&
249                 is_digit(symbol[2])   &&
250                 is_digit(symbol[3]);
251       }
252
253       inline const char_t& front(const std::string& s)
254       {
255          return s[0];
256       }
257
258       inline const char_t& back(const std::string& s)
259       {
260          return s[s.size() - 1];
261       }
262
263       inline std::string to_str(int i)
264       {
265          if (0 == i)
266             return std::string("0");
267
268          std::string result;
269
270          if (i < 0)
271          {
272             for ( ; i; i /= 10)
273             {
274                result += '0' + char(-(i % 10));
275             }
276
277             result += '-';
278          }
279          else
280          {
281             for ( ; i; i /= 10)
282             {
283                result += '0' + char(i % 10);
284             }
285          }
286
287          std::reverse(result.begin(), result.end());
288
289          return result;
290       }
291
292       inline std::string to_str(std::size_t i)
293       {
294          return to_str(static_cast<int>(i));
295       }
296
297       inline bool is_hex_digit(const std::string::value_type digit)
298       {
299          return (('0' <= digit) && (digit <= '9')) ||
300                 (('A' <= digit) && (digit <= 'F')) ||
301                 (('a' <= digit) && (digit <= 'f')) ;
302       }
303
304       inline uchar_t hex_to_bin(uchar_t h)
305       {
306          if (('0' <= h) && (h <= '9'))
307             return (h - '0');
308          else
309             return static_cast<unsigned char>(std::toupper(h) - 'A');
310       }
311
312       template <typename Iterator>
313       inline void parse_hex(Iterator& itr, Iterator end, std::string::value_type& result)
314       {
315          if (
316               (end !=  (itr    )) &&
317               (end !=  (itr + 1)) &&
318               (end !=  (itr + 2)) &&
319               (end !=  (itr + 3)) &&
320               ('0' == *(itr    )) &&
321               (
322                 ('x' == *(itr + 1)) ||
323                 ('X' == *(itr + 1))
324               ) &&
325               (is_hex_digit(*(itr + 2))) &&
326               (is_hex_digit(*(itr + 3)))
327             )
328          {
329             result = hex_to_bin(static_cast<uchar_t>(*(itr + 2))) << 4 |
330                      hex_to_bin(static_cast<uchar_t>(*(itr + 3))) ;
331             itr += 3;
332          }
333          else
334             result = '\0';
335       }
336
337       inline void cleanup_escapes(std::string& s)
338       {
339          typedef std::string::iterator str_itr_t;
340
341          str_itr_t itr1 = s.begin();
342          str_itr_t itr2 = s.begin();
343          str_itr_t end  = s.end  ();
344
345          std::size_t removal_count  = 0;
346
347          while (end != itr1)
348          {
349             if ('\\' == (*itr1))
350             {
351                ++removal_count;
352
353                if (end == ++itr1)
354                   break;
355                else if ('\\' != (*itr1))
356                {
357                   switch (*itr1)
358                   {
359                      case 'n' : (*itr1) = '\n'; break;
360                      case 'r' : (*itr1) = '\r'; break;
361                      case 't' : (*itr1) = '\t'; break;
362                      case '0' : parse_hex(itr1, end, (*itr1));
363                                 removal_count += 3;
364                                 break;
365                   }
366
367                   continue;
368                }
369             }
370
371             if (itr1 != itr2)
372             {
373                (*itr2) = (*itr1);
374             }
375
376             ++itr1;
377             ++itr2;
378          }
379
380          s.resize(s.size() - removal_count);
381       }
382
383       class build_string
384       {
385       public:
386
387          build_string(const std::size_t& initial_size = 64)
388          {
389             data_.reserve(initial_size);
390          }
391
392          inline build_string& operator << (const std::string& s)
393          {
394             data_ += s;
395             return (*this);
396          }
397
398          inline build_string& operator << (char_cptr s)
399          {
400             data_ += std::string(s);
401             return (*this);
402          }
403
404          inline operator std::string () const
405          {
406             return data_;
407          }
408
409          inline std::string as_string() const
410          {
411             return data_;
412          }
413
414       private:
415
416          std::string data_;
417       };
418
419       static const std::string reserved_words[] =
420                                   {
421                                     "break",  "case",  "continue",  "default",  "false",  "for",
422                                     "if", "else", "ilike",  "in", "like", "and",  "nand", "nor",
423                                     "not",  "null",  "or",   "repeat", "return",  "shl",  "shr",
424                                     "swap", "switch", "true",  "until", "var",  "while", "xnor",
425                                     "xor", "&", "|"
426                                   };
427
428       static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string);
429
430       static const std::string reserved_symbols[] =
431                                   {
432                                     "abs",  "acos",  "acosh",  "and",  "asin",  "asinh", "atan",
433                                     "atanh", "atan2", "avg",  "break", "case", "ceil",  "clamp",
434                                     "continue",   "cos",   "cosh",   "cot",   "csc",  "default",
435                                     "deg2grad",  "deg2rad",   "equal",  "erf",   "erfc",  "exp",
436                                     "expm1",  "false",   "floor",  "for",   "frac",  "grad2deg",
437                                     "hypot", "iclamp", "if",  "else", "ilike", "in",  "inrange",
438                                     "like",  "log",  "log10", "log2",  "logn",  "log1p", "mand",
439                                     "max", "min",  "mod", "mor",  "mul", "ncdf",  "nand", "nor",
440                                     "not",   "not_equal",   "null",   "or",   "pow",  "rad2deg",
441                                     "repeat", "return", "root", "round", "roundn", "sec", "sgn",
442                                     "shl", "shr", "sin", "sinc", "sinh", "sqrt",  "sum", "swap",
443                                     "switch", "tan",  "tanh", "true",  "trunc", "until",  "var",
444                                     "while", "xnor", "xor", "&", "|"
445                                   };
446
447       static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string);
448
449       static const std::string base_function_list[] =
450                                   {
451                                     "abs", "acos",  "acosh", "asin",  "asinh", "atan",  "atanh",
452                                     "atan2",  "avg",  "ceil",  "clamp",  "cos",  "cosh",  "cot",
453                                     "csc",  "equal",  "erf",  "erfc",  "exp",  "expm1", "floor",
454                                     "frac", "hypot", "iclamp",  "like", "log", "log10",  "log2",
455                                     "logn", "log1p", "mand", "max", "min", "mod", "mor",  "mul",
456                                     "ncdf",  "pow",  "root",  "round",  "roundn",  "sec", "sgn",
457                                     "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh",
458                                     "trunc",  "not_equal",  "inrange",  "deg2grad",   "deg2rad",
459                                     "rad2deg", "grad2deg"
460                                   };
461
462       static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string);
463
464       static const std::string logic_ops_list[] =
465                                   {
466                                     "and", "nand", "nor", "not", "or",  "xnor", "xor", "&", "|"
467                                   };
468
469       static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string);
470
471       static const std::string cntrl_struct_list[] =
472                                   {
473                                      "if", "switch", "for", "while", "repeat", "return"
474                                   };
475
476       static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string);
477
478       static const std::string arithmetic_ops_list[] =
479                                   {
480                                     "+", "-", "*", "/", "%", "^"
481                                   };
482
483       static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string);
484
485       static const std::string assignment_ops_list[] =
486                                   {
487                                     ":=", "+=", "-=",
488                                     "*=", "/=", "%="
489                                   };
490
491       static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string);
492
493       static const std::string inequality_ops_list[] =
494                                   {
495                                      "<",  "<=", "==",
496                                      "=",  "!=", "<>",
497                                     ">=",  ">"
498                                   };
499
500       static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string);
501
502       inline bool is_reserved_word(const std::string& symbol)
503       {
504          for (std::size_t i = 0; i < reserved_words_size; ++i)
505          {
506             if (imatch(symbol, reserved_words[i]))
507             {
508                return true;
509             }
510          }
511
512          return false;
513       }
514
515       inline bool is_reserved_symbol(const std::string& symbol)
516       {
517          for (std::size_t i = 0; i < reserved_symbols_size; ++i)
518          {
519             if (imatch(symbol, reserved_symbols[i]))
520             {
521                return true;
522             }
523          }
524
525          return false;
526       }
527
528       inline bool is_base_function(const std::string& function_name)
529       {
530          for (std::size_t i = 0; i < base_function_list_size; ++i)
531          {
532             if (imatch(function_name, base_function_list[i]))
533             {
534                return true;
535             }
536          }
537
538          return false;
539       }
540
541       inline bool is_control_struct(const std::string& cntrl_strct)
542       {
543          for (std::size_t i = 0; i < cntrl_struct_list_size; ++i)
544          {
545             if (imatch(cntrl_strct, cntrl_struct_list[i]))
546             {
547                return true;
548             }
549          }
550
551          return false;
552       }
553
554       inline bool is_logic_opr(const std::string& lgc_opr)
555       {
556          for (std::size_t i = 0; i < logic_ops_list_size; ++i)
557          {
558             if (imatch(lgc_opr, logic_ops_list[i]))
559             {
560                return true;
561             }
562          }
563
564          return false;
565       }
566
567       struct cs_match
568       {
569          static inline bool cmp(const char_t c0, const char_t c1)
570          {
571             return (c0 == c1);
572          }
573       };
574
575       struct cis_match
576       {
577          static inline bool cmp(const char_t c0, const char_t c1)
578          {
579             return (std::tolower(c0) == std::tolower(c1));
580          }
581       };
582
583       template <typename Iterator, typename Compare>
584       inline bool match_impl(const Iterator pattern_begin,
585                              const Iterator pattern_end  ,
586                              const Iterator data_begin   ,
587                              const Iterator data_end     ,
588                              const typename std::iterator_traits<Iterator>::value_type& zero_or_more,
589                              const typename std::iterator_traits<Iterator>::value_type& zero_or_one )
590       {
591          const Iterator null_itr(0);
592
593          Iterator d_itr    = data_begin;
594          Iterator p_itr    = pattern_begin;
595          Iterator tb_p_itr = null_itr;
596          Iterator tb_d_itr = null_itr;
597
598          while (d_itr != data_end)
599          {
600             if (zero_or_more == *p_itr)
601             {
602                while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
603                {
604                   ++p_itr;
605                }
606
607                if (pattern_end == p_itr)
608                   return true;
609
610                const typename std::iterator_traits<Iterator>::value_type c = *(p_itr);
611
612                while ((data_end != d_itr) && !Compare::cmp(c,*d_itr))
613                {
614                   ++d_itr;
615                }
616
617                tb_p_itr = p_itr;
618                tb_d_itr = d_itr;
619
620                continue;
621             }
622             else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr))
623             {
624                if (null_itr == tb_d_itr)
625                   return false;
626
627                d_itr = tb_d_itr++;
628                p_itr = tb_p_itr;
629
630                continue;
631             }
632
633             ++p_itr;
634             ++d_itr;
635          }
636
637          while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr)))
638          {
639             ++p_itr;
640          }
641
642          return (pattern_end == p_itr);
643       }
644
645       inline bool wc_match(const std::string& wild_card,
646                            const std::string& str)
647       {
648          return match_impl<char_cptr,cs_match>(wild_card.data(),
649                                                wild_card.data() + wild_card.size(),
650                                                str.data(),
651                                                str.data() + str.size(),
652                                                '*',
653                                                '?');
654       }
655
656       inline bool wc_imatch(const std::string& wild_card,
657                             const std::string& str)
658       {
659          return match_impl<char_cptr,cis_match>(wild_card.data(),
660                                                 wild_card.data() + wild_card.size(),
661                                                 str.data(),
662                                                 str.data() + str.size(),
663                                                 '*',
664                                                 '?');
665       }
666
667       inline bool sequence_match(const std::string& pattern,
668                                  const std::string& str,
669                                  std::size_t&       diff_index,
670                                  char_t&            diff_value)
671       {
672          if (str.empty())
673          {
674             return ("Z" == pattern);
675          }
676          else if ('*' == pattern[0])
677             return false;
678
679          typedef std::string::const_iterator itr_t;
680
681          itr_t p_itr = pattern.begin();
682          itr_t s_itr = str    .begin();
683
684          itr_t p_end = pattern.end();
685          itr_t s_end = str    .end();
686
687          while ((s_end != s_itr) && (p_end != p_itr))
688          {
689             if ('*' == (*p_itr))
690             {
691                const char_t target = static_cast<char>(std::toupper(*(p_itr - 1)));
692
693                if ('*' == target)
694                {
695                   diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr));
696                   diff_value = static_cast<char>(std::toupper(*p_itr));
697
698                   return false;
699                }
700                else
701                   ++p_itr;
702
703                while (s_itr != s_end)
704                {
705                   if (target != std::toupper(*s_itr))
706                      break;
707                   else
708                      ++s_itr;
709                }
710
711                continue;
712             }
713             else if (
714                       ('?' != *p_itr) &&
715                       std::toupper(*p_itr) != std::toupper(*s_itr)
716                     )
717             {
718                diff_index = static_cast<std::size_t>(std::distance(str.begin(),s_itr));
719                diff_value = static_cast<char>(std::toupper(*p_itr));
720
721                return false;
722             }
723
724             ++p_itr;
725             ++s_itr;
726          }
727
728          return (
729                   (s_end == s_itr) &&
730                   (
731                     (p_end ==  p_itr) ||
732                     ('*'   == *p_itr)
733                   )
734                 );
735       }
736
737       static const double pow10[] = {
738                                       1.0,
739                                       1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004,
740                                       1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008,
741                                       1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012,
742                                       1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016
743                                     };
744
745       static const std::size_t pow10_size = sizeof(pow10) / sizeof(double);
746
747       namespace numeric
748       {
749          namespace constant
750          {
751             static const double e       =  2.71828182845904523536028747135266249775724709369996;
752             static const double pi      =  3.14159265358979323846264338327950288419716939937510;
753             static const double pi_2    =  1.57079632679489661923132169163975144209858469968755;
754             static const double pi_4    =  0.78539816339744830961566084581987572104929234984378;
755             static const double pi_180  =  0.01745329251994329576923690768488612713442871888542;
756             static const double _1_pi   =  0.31830988618379067153776752674502872406891929148091;
757             static const double _2_pi   =  0.63661977236758134307553505349005744813783858296183;
758             static const double _180_pi = 57.29577951308232087679815481410517033240547246656443;
759             static const double log2    =  0.69314718055994530941723212145817656807550013436026;
760             static const double sqrt2   =  1.41421356237309504880168872420969807856967187537695;
761          }
762
763          namespace details
764          {
765             struct unknown_type_tag { unknown_type_tag() {} };
766             struct real_type_tag    { real_type_tag   () {} };
767             struct complex_type_tag { complex_type_tag() {} };
768             struct int_type_tag     { int_type_tag    () {} };
769
770             template <typename T>
771             struct number_type
772             {
773                typedef unknown_type_tag type;
774                number_type() {}
775             };
776
777             #define exprtk_register_real_type_tag(T)             \
778             template<> struct number_type<T>                     \
779             { typedef real_type_tag type; number_type() {} };    \
780
781             #define exprtk_register_complex_type_tag(T)          \
782             template<> struct number_type<std::complex<T> >      \
783             { typedef complex_type_tag type; number_type() {} }; \
784
785             #define exprtk_register_int_type_tag(T)              \
786             template<> struct number_type<T>                     \
787             { typedef int_type_tag type; number_type() {} };     \
788
789             exprtk_register_real_type_tag(double     )
790             exprtk_register_real_type_tag(long double)
791             exprtk_register_real_type_tag(float      )
792
793             exprtk_register_complex_type_tag(double     )
794             exprtk_register_complex_type_tag(long double)
795             exprtk_register_complex_type_tag(float      )
796
797             exprtk_register_int_type_tag(short         )
798             exprtk_register_int_type_tag(int           )
799             exprtk_register_int_type_tag(_int64_t      )
800             exprtk_register_int_type_tag(unsigned short)
801             exprtk_register_int_type_tag(unsigned int  )
802             exprtk_register_int_type_tag(_uint64_t     )
803
804             #undef exprtk_register_real_type_tag
805             #undef exprtk_register_int_type_tag
806
807             template <typename T>
808             struct epsilon_type
809             {
810                static inline T value()
811                {
812                   const T epsilon = T(0.0000000001);
813                   return epsilon;
814                }
815             };
816
817             template <>
818             struct epsilon_type <float>
819             {
820                static inline float value()
821                {
822                   const float epsilon = float(0.000001f);
823                   return epsilon;
824                }
825             };
826
827             template <>
828             struct epsilon_type <long double>
829             {
830                static inline long double value()
831                {
832                   const long double epsilon = (long double)(0.000000000001);
833                   return epsilon;
834                }
835             };
836
837             template <typename T>
838             inline bool is_nan_impl(const T v, real_type_tag)
839             {
840                return std::not_equal_to<T>()(v,v);
841             }
842
843             template <typename T>
844             inline int to_int32_impl(const T v, real_type_tag)
845             {
846                return static_cast<int>(v);
847             }
848
849             template <typename T>
850             inline _int64_t to_int64_impl(const T v, real_type_tag)
851             {
852                return static_cast<_int64_t>(v);
853             }
854
855             template <typename T>
856             inline bool is_true_impl(const T v)
857             {
858                return std::not_equal_to<T>()(T(0),v);
859             }
860
861             template <typename T>
862             inline bool is_false_impl(const T v)
863             {
864                return std::equal_to<T>()(T(0),v);
865             }
866
867             template <typename T>
868             inline T abs_impl(const T v, real_type_tag)
869             {
870                return ((v < T(0)) ? -v : v);
871             }
872
873             template <typename T>
874             inline T min_impl(const T v0, const T v1, real_type_tag)
875             {
876                return std::min<T>(v0,v1);
877             }
878
879             template <typename T>
880             inline T max_impl(const T v0, const T v1, real_type_tag)
881             {
882                return std::max<T>(v0,v1);
883             }
884
885             template <typename T>
886             inline T equal_impl(const T v0, const T v1, real_type_tag)
887             {
888                const T epsilon = epsilon_type<T>::value();
889                return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0);
890             }
891
892             inline float equal_impl(const float v0, const float v1, real_type_tag)
893             {
894                const float epsilon = epsilon_type<float>::value();
895                return (abs_impl(v0 - v1,real_type_tag()) <= (std::max(1.0f,std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? 1.0f : 0.0f;
896             }
897
898             template <typename T>
899             inline T equal_impl(const T v0, const T v1, int_type_tag)
900             {
901                return (v0 == v1) ? 1 : 0;
902             }
903
904             template <typename T>
905             inline T expm1_impl(const T v, real_type_tag)
906             {
907                // return std::expm1<T>(v);
908                if (abs_impl(v,real_type_tag()) < T(0.00001))
909                   return v + (T(0.5) * v * v);
910                else
911                   return std::exp(v) - T(1);
912             }
913
914             template <typename T>
915             inline T expm1_impl(const T v, int_type_tag)
916             {
917                return T(std::exp<double>(v)) - T(1);
918             }
919
920             template <typename T>
921             inline T nequal_impl(const T v0, const T v1, real_type_tag)
922             {
923                typedef real_type_tag rtg;
924                const T epsilon = epsilon_type<T>::value();
925                return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0);
926             }
927
928             inline float nequal_impl(const float v0, const float v1, real_type_tag)
929             {
930                typedef real_type_tag rtg;
931                const float epsilon = epsilon_type<float>::value();
932                return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f;
933             }
934
935             template <typename T>
936             inline T nequal_impl(const T v0, const T v1, int_type_tag)
937             {
938                return (v0 != v1) ? 1 : 0;
939             }
940
941             template <typename T>
942             inline T modulus_impl(const T v0, const T v1, real_type_tag)
943             {
944                return std::fmod(v0,v1);
945             }
946
947             template <typename T>
948             inline T modulus_impl(const T v0, const T v1, int_type_tag)
949             {
950                return v0 % v1;
951             }
952
953             template <typename T>
954             inline T pow_impl(const T v0, const T v1, real_type_tag)
955             {
956                return std::pow(v0,v1);
957             }
958
959             template <typename T>
960             inline T pow_impl(const T v0, const T v1, int_type_tag)
961             {
962                return std::pow(static_cast<double>(v0),static_cast<double>(v1));
963             }
964
965             template <typename T>
966             inline T logn_impl(const T v0, const T v1, real_type_tag)
967             {
968                return std::log(v0) / std::log(v1);
969             }
970
971             template <typename T>
972             inline T logn_impl(const T v0, const T v1, int_type_tag)
973             {
974                return static_cast<T>(logn_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag()));
975             }
976
977             template <typename T>
978             inline T log1p_impl(const T v, real_type_tag)
979             {
980                if (v > T(-1))
981                {
982                   if (abs_impl(v,real_type_tag()) > T(0.0001))
983                   {
984                      return std::log(T(1) + v);
985                   }
986                   else
987                      return (T(-0.5) * v + T(1)) * v;
988                }
989                else
990                   return std::numeric_limits<T>::quiet_NaN();
991             }
992
993             template <typename T>
994             inline T log1p_impl(const T v, int_type_tag)
995             {
996                if (v > T(-1))
997                {
998                   return std::log(T(1) + v);
999                }
1000                else
1001                   return std::numeric_limits<T>::quiet_NaN();
1002             }
1003
1004             template <typename T>
1005             inline T root_impl(const T v0, const T v1, real_type_tag)
1006             {
1007                if (v1 < T(0))
1008                   return std::numeric_limits<T>::quiet_NaN();
1009
1010                const std::size_t n = static_cast<std::size_t>(v1);
1011
1012                if ((v0 < T(0)) && (0 == (n % 2)))
1013                   return std::numeric_limits<T>::quiet_NaN();
1014
1015                return std::pow(v0, T(1) / n);
1016             }
1017
1018             template <typename T>
1019             inline T root_impl(const T v0, const T v1, int_type_tag)
1020             {
1021                return root_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag());
1022             }
1023
1024             template <typename T>
1025             inline T round_impl(const T v, real_type_tag)
1026             {
1027                return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5)));
1028             }
1029
1030             template <typename T>
1031             inline T roundn_impl(const T v0, const T v1, real_type_tag)
1032             {
1033                const int index = std::max<int>(0, std::min<int>(pow10_size - 1, (int)std::floor(v1)));
1034                const T p10 = T(pow10[index]);
1035
1036                if (v0 < T(0))
1037                   return T(std::ceil ((v0 * p10) - T(0.5)) / p10);
1038                else
1039                   return T(std::floor((v0 * p10) + T(0.5)) / p10);
1040             }
1041
1042             template <typename T>
1043             inline T roundn_impl(const T v0, const T, int_type_tag)
1044             {
1045                return v0;
1046             }
1047
1048             template <typename T>
1049             inline T hypot_impl(const T v0, const T v1, real_type_tag)
1050             {
1051                return std::sqrt((v0 * v0) + (v1 * v1));
1052             }
1053
1054             template <typename T>
1055             inline T hypot_impl(const T v0, const T v1, int_type_tag)
1056             {
1057                return static_cast<T>(std::sqrt(static_cast<double>((v0 * v0) + (v1 * v1))));
1058             }
1059
1060             template <typename T>
1061             inline T atan2_impl(const T v0, const T v1, real_type_tag)
1062             {
1063                return std::atan2(v0,v1);
1064             }
1065
1066             template <typename T>
1067             inline T atan2_impl(const T, const T, int_type_tag)
1068             {
1069                return 0;
1070             }
1071
1072             template <typename T>
1073             inline T shr_impl(const T v0, const T v1, real_type_tag)
1074             {
1075                return v0 * (T(1) / std::pow(T(2),static_cast<T>(static_cast<int>(v1))));
1076             }
1077
1078             template <typename T>
1079             inline T shr_impl(const T v0, const T v1, int_type_tag)
1080             {
1081                return v0 >> v1;
1082             }
1083
1084             template <typename T>
1085             inline T shl_impl(const T v0, const T v1, real_type_tag)
1086             {
1087                return v0 * std::pow(T(2),static_cast<T>(static_cast<int>(v1)));
1088             }
1089
1090             template <typename T>
1091             inline T shl_impl(const T v0, const T v1, int_type_tag)
1092             {
1093                return v0 << v1;
1094             }
1095
1096             template <typename T>
1097             inline T sgn_impl(const T v, real_type_tag)
1098             {
1099                     if (v > T(0)) return T(+1);
1100                else if (v < T(0)) return T(-1);
1101                else               return T( 0);
1102             }
1103
1104             template <typename T>
1105             inline T sgn_impl(const T v, int_type_tag)
1106             {
1107                     if (v > T(0)) return T(+1);
1108                else if (v < T(0)) return T(-1);
1109                else               return T( 0);
1110             }
1111
1112             template <typename T>
1113             inline T and_impl(const T v0, const T v1, real_type_tag)
1114             {
1115                return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0);
1116             }
1117
1118             template <typename T>
1119             inline T and_impl(const T v0, const T v1, int_type_tag)
1120             {
1121                return v0 && v1;
1122             }
1123
1124             template <typename T>
1125             inline T nand_impl(const T v0, const T v1, real_type_tag)
1126             {
1127                return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0);
1128             }
1129
1130             template <typename T>
1131             inline T nand_impl(const T v0, const T v1, int_type_tag)
1132             {
1133                return !(v0 && v1);
1134             }
1135
1136             template <typename T>
1137             inline T or_impl(const T v0, const T v1, real_type_tag)
1138             {
1139                return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0);
1140             }
1141
1142             template <typename T>
1143             inline T or_impl(const T v0, const T v1, int_type_tag)
1144             {
1145                return (v0 || v1);
1146             }
1147
1148             template <typename T>
1149             inline T nor_impl(const T v0, const T v1, real_type_tag)
1150             {
1151                return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0);
1152             }
1153
1154             template <typename T>
1155             inline T nor_impl(const T v0, const T v1, int_type_tag)
1156             {
1157                return !(v0 || v1);
1158             }
1159
1160             template <typename T>
1161             inline T xor_impl(const T v0, const T v1, real_type_tag)
1162             {
1163                return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0);
1164             }
1165
1166             template <typename T>
1167             inline T xor_impl(const T v0, const T v1, int_type_tag)
1168             {
1169                return v0 ^ v1;
1170             }
1171
1172             template <typename T>
1173             inline T xnor_impl(const T v0, const T v1, real_type_tag)
1174             {
1175                const bool v0_true = is_true_impl(v0);
1176                const bool v1_true = is_true_impl(v1);
1177
1178                if ((v0_true &&  v1_true) || (!v0_true && !v1_true))
1179                   return T(1);
1180                else
1181                   return T(0);
1182             }
1183
1184             template <typename T>
1185             inline T xnor_impl(const T v0, const T v1, int_type_tag)
1186             {
1187                const bool v0_true = is_true_impl(v0);
1188                const bool v1_true = is_true_impl(v1);
1189
1190                if ((v0_true &&  v1_true) || (!v0_true && !v1_true))
1191                   return T(1);
1192                else
1193                   return T(0);
1194             }
1195
1196             #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER)
1197             #define exprtk_define_erf(TT,impl)           \
1198             inline TT erf_impl(TT v) { return impl(v); } \
1199
1200             exprtk_define_erf(      float,::erff)
1201             exprtk_define_erf(     double,::erf )
1202             exprtk_define_erf(long double,::erfl)
1203             #undef exprtk_define_erf
1204             #endif
1205
1206             template <typename T>
1207             inline T erf_impl(T v, real_type_tag)
1208             {
1209                #if defined(_MSC_VER) && (_MSC_VER < 1900)
1210                // Credits: Abramowitz & Stegun Equations 7.1.25-28
1211                static const T c[] = {
1212                                       T( 1.26551223), T(1.00002368),
1213                                       T( 0.37409196), T(0.09678418),
1214                                       T(-0.18628806), T(0.27886807),
1215                                       T(-1.13520398), T(1.48851587),
1216                                       T(-0.82215223), T(0.17087277)
1217                                     };
1218
1219                const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag()));
1220
1221                T result = T(1) - t * std::exp((-v * v) -
1222                                       c[0] + t * (c[1] + t *
1223                                      (c[2] + t * (c[3] + t *
1224                                      (c[4] + t * (c[5] + t *
1225                                      (c[6] + t * (c[7] + t *
1226                                      (c[8] + t * (c[9]))))))))));
1227
1228                return (v >= T(0)) ? result : -result;
1229                #else
1230                return erf_impl(v);
1231                #endif
1232             }
1233
1234             template <typename T>
1235             inline T erf_impl(T v, int_type_tag)
1236             {
1237                return erf_impl(static_cast<double>(v),real_type_tag());
1238             }
1239
1240             #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER)
1241             #define exprtk_define_erfc(TT,impl)           \
1242             inline TT erfc_impl(TT v) { return impl(v); } \
1243
1244             exprtk_define_erfc(      float,::erfcf)
1245             exprtk_define_erfc(     double,::erfc )
1246             exprtk_define_erfc(long double,::erfcl)
1247             #undef exprtk_define_erfc
1248             #endif
1249
1250             template <typename T>
1251             inline T erfc_impl(T v, real_type_tag)
1252             {
1253                #if defined(_MSC_VER) && (_MSC_VER < 1900)
1254                return T(1) - erf_impl(v,real_type_tag());
1255                #else
1256                return erfc_impl(v);
1257                #endif
1258             }
1259
1260             template <typename T>
1261             inline T erfc_impl(T v, int_type_tag)
1262             {
1263                return erfc_impl(static_cast<double>(v),real_type_tag());
1264             }
1265
1266             template <typename T>
1267             inline T ncdf_impl(T v, real_type_tag)
1268             {
1269                T cnd = T(0.5) * (T(1) + erf_impl(
1270                                            abs_impl(v,real_type_tag()) /
1271                                            T(numeric::constant::sqrt2),real_type_tag()));
1272                return  (v < T(0)) ? (T(1) - cnd) : cnd;
1273             }
1274
1275             template <typename T>
1276             inline T ncdf_impl(T v, int_type_tag)
1277             {
1278                return ncdf_impl(static_cast<double>(v),real_type_tag());
1279             }
1280
1281             template <typename T>
1282             inline T sinc_impl(T v, real_type_tag)
1283             {
1284                if (std::abs(v) >= std::numeric_limits<T>::epsilon())
1285                    return(std::sin(v) / v);
1286                else
1287                   return T(1);
1288             }
1289
1290             template <typename T>
1291             inline T sinc_impl(T v, int_type_tag)
1292             {
1293                return sinc_impl(static_cast<double>(v),real_type_tag());
1294             }
1295
1296             template <typename T> inline T  acos_impl(const T v, real_type_tag) { return std::acos (v); }
1297             template <typename T> inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); }
1298             template <typename T> inline T  asin_impl(const T v, real_type_tag) { return std::asin (v); }
1299             template <typename T> inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); }
1300             template <typename T> inline T  atan_impl(const T v, real_type_tag) { return std::atan (v); }
1301             template <typename T> inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); }
1302             template <typename T> inline T  ceil_impl(const T v, real_type_tag) { return std::ceil (v); }
1303             template <typename T> inline T   cos_impl(const T v, real_type_tag) { return std::cos  (v); }
1304             template <typename T> inline T  cosh_impl(const T v, real_type_tag) { return std::cosh (v); }
1305             template <typename T> inline T   exp_impl(const T v, real_type_tag) { return std::exp  (v); }
1306             template <typename T> inline T floor_impl(const T v, real_type_tag) { return std::floor(v); }
1307             template <typename T> inline T   log_impl(const T v, real_type_tag) { return std::log  (v); }
1308             template <typename T> inline T log10_impl(const T v, real_type_tag) { return std::log10(v); }
1309             template <typename T> inline T  log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); }
1310             template <typename T> inline T   neg_impl(const T v, real_type_tag) { return -v;            }
1311             template <typename T> inline T   pos_impl(const T v, real_type_tag) { return +v;            }
1312             template <typename T> inline T   sin_impl(const T v, real_type_tag) { return std::sin  (v); }
1313             template <typename T> inline T  sinh_impl(const T v, real_type_tag) { return std::sinh (v); }
1314             template <typename T> inline T  sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); }
1315             template <typename T> inline T   tan_impl(const T v, real_type_tag) { return std::tan  (v); }
1316             template <typename T> inline T  tanh_impl(const T v, real_type_tag) { return std::tanh (v); }
1317             template <typename T> inline T   cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); }
1318             template <typename T> inline T   sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); }
1319             template <typename T> inline T   csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); }
1320             template <typename T> inline T   r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); }
1321             template <typename T> inline T   d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180));  }
1322             template <typename T> inline T   d2g_impl(const T v, real_type_tag) { return (v * T(20.0/9.0)); }
1323             template <typename T> inline T   g2d_impl(const T v, real_type_tag) { return (v * T(9.0/20.0)); }
1324             template <typename T> inline T  notl_impl(const T v, real_type_tag) { return (std::not_equal_to<T>()(T(0),v) ? T(0) : T(1)); }
1325             template <typename T> inline T  frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); }
1326             template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v));    }
1327
1328             template <typename T> inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); }
1329             template <typename T> inline T const_e_impl (real_type_tag) { return T(numeric::constant::e);  }
1330
1331             template <typename T> inline T   abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); }
1332             template <typename T> inline T   exp_impl(const T v, int_type_tag) { return std::exp  (v); }
1333             template <typename T> inline T   log_impl(const T v, int_type_tag) { return std::log  (v); }
1334             template <typename T> inline T log10_impl(const T v, int_type_tag) { return std::log10(v); }
1335             template <typename T> inline T  log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); }
1336             template <typename T> inline T   neg_impl(const T v, int_type_tag) { return -v;            }
1337             template <typename T> inline T   pos_impl(const T v, int_type_tag) { return +v;            }
1338             template <typename T> inline T  ceil_impl(const T v, int_type_tag) { return v;             }
1339             template <typename T> inline T floor_impl(const T v, int_type_tag) { return v;             }
1340             template <typename T> inline T round_impl(const T v, int_type_tag) { return v;             }
1341             template <typename T> inline T  notl_impl(const T v, int_type_tag) { return !v;            }
1342             template <typename T> inline T  sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); }
1343             template <typename T> inline T  frac_impl(const T  , int_type_tag) { return T(0);          }
1344             template <typename T> inline T trunc_impl(const T v, int_type_tag) { return v;             }
1345             template <typename T> inline T  acos_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1346             template <typename T> inline T acosh_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1347             template <typename T> inline T  asin_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1348             template <typename T> inline T asinh_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1349             template <typename T> inline T  atan_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1350             template <typename T> inline T atanh_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1351             template <typename T> inline T   cos_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1352             template <typename T> inline T  cosh_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1353             template <typename T> inline T   sin_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1354             template <typename T> inline T  sinh_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1355             template <typename T> inline T   tan_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1356             template <typename T> inline T  tanh_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1357             template <typename T> inline T   cot_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1358             template <typename T> inline T   sec_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1359             template <typename T> inline T   csc_impl(const T  , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
1360
1361             template <typename T>
1362             inline bool is_integer_impl(const T& v, real_type_tag)
1363             {
1364                return std::equal_to<T>()(T(0),std::fmod(v,T(1)));
1365             }
1366
1367             template <typename T>
1368             inline bool is_integer_impl(const T&, int_type_tag)
1369             {
1370                return true;
1371             }
1372          }
1373
1374          template <typename Type>
1375          struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; };
1376
1377          template<> struct numeric_info<int>         { enum { length = 10, size = 16, bound_length = 9}; };
1378          template<> struct numeric_info<float>       { enum { min_exp =  -38, max_exp =  +38}; };
1379          template<> struct numeric_info<double>      { enum { min_exp = -308, max_exp = +308}; };
1380          template<> struct numeric_info<long double> { enum { min_exp = -308, max_exp = +308}; };
1381
1382          template <typename T>
1383          inline int to_int32(const T v)
1384          {
1385             const typename details::number_type<T>::type num_type;
1386             return to_int32_impl(v, num_type);
1387          }
1388
1389          template <typename T>
1390          inline _int64_t to_int64(const T v)
1391          {
1392             const typename details::number_type<T>::type num_type;
1393             return to_int64_impl(v, num_type);
1394          }
1395
1396          template <typename T>
1397          inline bool is_nan(const T v)
1398          {
1399             const typename details::number_type<T>::type num_type;
1400             return is_nan_impl(v, num_type);
1401          }
1402
1403          template <typename T>
1404          inline T min(const T v0, const T v1)
1405          {
1406             const typename details::number_type<T>::type num_type;
1407             return min_impl(v0, v1, num_type);
1408          }
1409
1410          template <typename T>
1411          inline T max(const T v0, const T v1)
1412          {
1413             const typename details::number_type<T>::type num_type;
1414             return max_impl(v0, v1, num_type);
1415          }
1416
1417          template <typename T>
1418          inline T equal(const T v0, const T v1)
1419          {
1420             const typename details::number_type<T>::type num_type;
1421             return equal_impl(v0, v1, num_type);
1422          }
1423
1424          template <typename T>
1425          inline T nequal(const T v0, const T v1)
1426          {
1427             const typename details::number_type<T>::type num_type;
1428             return nequal_impl(v0, v1, num_type);
1429          }
1430
1431          template <typename T>
1432          inline T modulus(const T v0, const T v1)
1433          {
1434             const typename details::number_type<T>::type num_type;
1435             return modulus_impl(v0, v1, num_type);
1436          }
1437
1438          template <typename T>
1439          inline T pow(const T v0, const T v1)
1440          {
1441             const typename details::number_type<T>::type num_type;
1442             return pow_impl(v0, v1, num_type);
1443          }
1444
1445          template <typename T>
1446          inline T logn(const T v0, const T v1)
1447          {
1448             const typename details::number_type<T>::type num_type;
1449             return logn_impl(v0, v1, num_type);
1450          }
1451
1452          template <typename T>
1453          inline T root(const T v0, const T v1)
1454          {
1455             const typename details::number_type<T>::type num_type;
1456             return root_impl(v0, v1, num_type);
1457          }
1458
1459          template <typename T>
1460          inline T roundn(const T v0, const T v1)
1461          {
1462             const typename details::number_type<T>::type num_type;
1463             return roundn_impl(v0, v1, num_type);
1464          }
1465
1466          template <typename T>
1467          inline T hypot(const T v0, const T v1)
1468          {
1469             const typename details::number_type<T>::type num_type;
1470             return hypot_impl(v0, v1, num_type);
1471          }
1472
1473          template <typename T>
1474          inline T atan2(const T v0, const T v1)
1475          {
1476             const typename details::number_type<T>::type num_type;
1477             return atan2_impl(v0, v1, num_type);
1478          }
1479
1480          template <typename T>
1481          inline T shr(const T v0, const T v1)
1482          {
1483             const typename details::number_type<T>::type num_type;
1484             return shr_impl(v0, v1, num_type);
1485          }
1486
1487          template <typename T>
1488          inline T shl(const T v0, const T v1)
1489          {
1490             const typename details::number_type<T>::type num_type;
1491             return shl_impl(v0, v1, num_type);
1492          }
1493
1494          template <typename T>
1495          inline T and_opr(const T v0, const T v1)
1496          {
1497             const typename details::number_type<T>::type num_type;
1498             return and_impl(v0, v1, num_type);
1499          }
1500
1501          template <typename T>
1502          inline T nand_opr(const T v0, const T v1)
1503          {
1504             const typename details::number_type<T>::type num_type;
1505             return nand_impl(v0, v1, num_type);
1506          }
1507
1508          template <typename T>
1509          inline T or_opr(const T v0, const T v1)
1510          {
1511             const typename details::number_type<T>::type num_type;
1512             return or_impl(v0, v1, num_type);
1513          }
1514
1515          template <typename T>
1516          inline T nor_opr(const T v0, const T v1)
1517          {
1518             const typename details::number_type<T>::type num_type;
1519             return nor_impl(v0, v1, num_type);
1520          }
1521
1522          template <typename T>
1523          inline T xor_opr(const T v0, const T v1)
1524          {
1525             const typename details::number_type<T>::type num_type;
1526             return xor_impl(v0, v1, num_type);
1527          }
1528
1529          template <typename T>
1530          inline T xnor_opr(const T v0, const T v1)
1531          {
1532             const typename details::number_type<T>::type num_type;
1533             return xnor_impl(v0, v1, num_type);
1534          }
1535
1536          template <typename T>
1537          inline bool is_integer(const T v)
1538          {
1539             const typename details::number_type<T>::type num_type;
1540             return is_integer_impl(v, num_type);
1541          }
1542
1543          template <typename T, unsigned int N>
1544          struct fast_exp
1545          {
1546             static inline T result(T v)
1547             {
1548                unsigned int k = N;
1549                T l = T(1);
1550
1551                while (k)
1552                {
1553                   if (k & 1)
1554                   {
1555                      l *= v;
1556                      --k;
1557                   }
1558
1559                   v *= v;
1560                   k >>= 1;
1561                }
1562
1563                return l;
1564             }
1565          };
1566
1567          template <typename T> struct fast_exp<T,10> { static inline T result(T v) { T v_5 = fast_exp<T,5>::result(v); return v_5 * v_5; } };
1568          template <typename T> struct fast_exp<T, 9> { static inline T result(T v) { return fast_exp<T,8>::result(v) * v; } };
1569          template <typename T> struct fast_exp<T, 8> { static inline T result(T v) { T v_4 = fast_exp<T,4>::result(v); return v_4 * v_4; } };
1570          template <typename T> struct fast_exp<T, 7> { static inline T result(T v) { return fast_exp<T,6>::result(v) * v; } };
1571          template <typename T> struct fast_exp<T, 6> { static inline T result(T v) { T v_3 = fast_exp<T,3>::result(v); return v_3 * v_3; } };
1572          template <typename T> struct fast_exp<T, 5> { static inline T result(T v) { return fast_exp<T,4>::result(v) * v; } };
1573          template <typename T> struct fast_exp<T, 4> { static inline T result(T v) { T v_2 = v * v; return v_2 * v_2; } };
1574          template <typename T> struct fast_exp<T, 3> { static inline T result(T v) { return v * v * v; } };
1575          template <typename T> struct fast_exp<T, 2> { static inline T result(T v) { return v * v;     } };
1576          template <typename T> struct fast_exp<T, 1> { static inline T result(T v) { return v;         } };
1577          template <typename T> struct fast_exp<T, 0> { static inline T result(T  ) { return T(1);      } };
1578
1579          #define exprtk_define_unary_function(FunctionName)        \
1580          template <typename T>                                     \
1581          inline T FunctionName (const T v)                         \
1582          {                                                         \
1583             const typename details::number_type<T>::type num_type; \
1584             return  FunctionName##_impl(v,num_type);               \
1585          }                                                         \
1586
1587          exprtk_define_unary_function(abs  )
1588          exprtk_define_unary_function(acos )
1589          exprtk_define_unary_function(acosh)
1590          exprtk_define_unary_function(asin )
1591          exprtk_define_unary_function(asinh)
1592          exprtk_define_unary_function(atan )
1593          exprtk_define_unary_function(atanh)
1594          exprtk_define_unary_function(ceil )
1595          exprtk_define_unary_function(cos  )
1596          exprtk_define_unary_function(cosh )
1597          exprtk_define_unary_function(exp  )
1598          exprtk_define_unary_function(expm1)
1599          exprtk_define_unary_function(floor)
1600          exprtk_define_unary_function(log  )
1601          exprtk_define_unary_function(log10)
1602          exprtk_define_unary_function(log2 )
1603          exprtk_define_unary_function(log1p)
1604          exprtk_define_unary_function(neg  )
1605          exprtk_define_unary_function(pos  )
1606          exprtk_define_unary_function(round)
1607          exprtk_define_unary_function(sin  )
1608          exprtk_define_unary_function(sinc )
1609          exprtk_define_unary_function(sinh )
1610          exprtk_define_unary_function(sqrt )
1611          exprtk_define_unary_function(tan  )
1612          exprtk_define_unary_function(tanh )
1613          exprtk_define_unary_function(cot  )
1614          exprtk_define_unary_function(sec  )
1615          exprtk_define_unary_function(csc  )
1616          exprtk_define_unary_function(r2d  )
1617          exprtk_define_unary_function(d2r  )
1618          exprtk_define_unary_function(d2g  )
1619          exprtk_define_unary_function(g2d  )
1620          exprtk_define_unary_function(notl )
1621          exprtk_define_unary_function(sgn  )
1622          exprtk_define_unary_function(erf  )
1623          exprtk_define_unary_function(erfc )
1624          exprtk_define_unary_function(ncdf )
1625          exprtk_define_unary_function(frac )
1626          exprtk_define_unary_function(trunc)
1627          #undef exprtk_define_unary_function
1628       }
1629
1630       template <typename T>
1631       inline T compute_pow10(T d, const int exponent)
1632       {
1633          static const double fract10[] =
1634          {
1635            0.0,
1636            1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010,
1637            1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020,
1638            1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030,
1639            1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040,
1640            1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050,
1641            1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060,
1642            1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070,
1643            1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080,
1644            1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090,
1645            1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100,
1646            1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110,
1647            1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120,
1648            1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130,
1649            1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140,
1650            1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150,
1651            1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160,
1652            1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170,
1653            1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180,
1654            1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190,
1655            1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200,
1656            1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210,
1657            1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220,
1658            1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230,
1659            1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240,
1660            1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250,
1661            1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260,
1662            1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270,
1663            1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280,
1664            1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290,
1665            1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300,
1666            1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308
1667          };
1668
1669          static const int fract10_size = static_cast<int>(sizeof(fract10) / sizeof(double));
1670
1671          const int e = std::abs(exponent);
1672
1673          if (exponent >= std::numeric_limits<T>::min_exponent10)
1674          {
1675             if (e < fract10_size)
1676             {
1677                if (exponent > 0)
1678                   return T(d * fract10[e]);
1679                else
1680                   return T(d / fract10[e]);
1681             }
1682             else
1683                return T(d * std::pow(10.0, 10.0 * exponent));
1684          }
1685          else
1686          {
1687                      d /= T(fract10[           -std::numeric_limits<T>::min_exponent10]);
1688             return T(d /    fract10[-exponent + std::numeric_limits<T>::min_exponent10]);
1689          }
1690       }
1691
1692       template <typename Iterator, typename T>
1693       inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result)
1694       {
1695          if (itr == end)
1696             return false;
1697
1698          const bool negative = ('-' == (*itr));
1699
1700          if (negative || ('+' == (*itr)))
1701          {
1702             if (end == ++itr)
1703                return false;
1704          }
1705
1706          static const uchar_t zero = static_cast<uchar_t>('0');
1707
1708          while ((end != itr) && (zero == (*itr))) ++itr;
1709
1710          bool return_result = true;
1711          unsigned int digit = 0;
1712          const std::size_t length  = static_cast<std::size_t>(std::distance(itr,end));
1713
1714          if (length <= 4)
1715          {
1716             exprtk_disable_fallthrough_begin
1717             switch (length)
1718             {
1719                #ifdef exprtk_use_lut
1720
1721                #define exprtk_process_digit                          \
1722                if ((digit = details::digit_table[(int)*itr++]) < 10) \
1723                   result = result * 10 + (digit);                    \
1724                else                                                  \
1725                {                                                     \
1726                   return_result = false;                             \
1727                   break;                                             \
1728                }                                                     \
1729
1730                #else
1731
1732                #define exprtk_process_digit         \
1733                if ((digit = (*itr++ - zero)) < 10)  \
1734                   result = result * T(10) + digit;  \
1735                else                                 \
1736                {                                    \
1737                   return_result = false;            \
1738                   break;                            \
1739                }                                    \
1740
1741                #endif
1742
1743                case  4 : exprtk_process_digit
1744                case  3 : exprtk_process_digit
1745                case  2 : exprtk_process_digit
1746                case  1 : if ((digit = (*itr - zero))>= 10) { digit = 0; return_result = false; }
1747
1748                #undef exprtk_process_digit
1749             }
1750             exprtk_disable_fallthrough_end
1751          }
1752          else
1753             return_result = false;
1754
1755          if (length && return_result)
1756          {
1757             result = result * 10 + static_cast<T>(digit);
1758             ++itr;
1759          }
1760
1761          result = negative ? -result : result;
1762          return return_result;
1763       }
1764
1765       template <typename Iterator, typename T>
1766       static inline bool parse_nan(Iterator& itr, const Iterator end, T& t)
1767       {
1768          typedef typename std::iterator_traits<Iterator>::value_type type;
1769
1770          static const std::size_t nan_length = 3;
1771
1772          if (std::distance(itr,end) != static_cast<int>(nan_length))
1773             return false;
1774
1775          if (static_cast<type>('n') == (*itr))
1776          {
1777             if (
1778                  (static_cast<type>('a') != *(itr + 1)) ||
1779                  (static_cast<type>('n') != *(itr + 2))
1780                )
1781             {
1782                return false;
1783             }
1784          }
1785          else if (
1786                    (static_cast<type>('A') != *(itr + 1)) ||
1787                    (static_cast<type>('N') != *(itr + 2))
1788                  )
1789          {
1790             return false;
1791          }
1792
1793          t = std::numeric_limits<T>::quiet_NaN();
1794
1795          return true;
1796       }
1797
1798       template <typename Iterator, typename T>
1799       static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative)
1800       {
1801          static const char_t inf_uc[] = "INFINITY";
1802          static const char_t inf_lc[] = "infinity";
1803          static const std::size_t inf_length = 8;
1804
1805          const std::size_t length = static_cast<std::size_t>(std::distance(itr,end));
1806
1807          if ((3 != length) && (inf_length != length))
1808             return false;
1809
1810          char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc;
1811
1812          while (end != itr)
1813          {
1814             if (*inf_itr == static_cast<char>(*itr))
1815             {
1816                ++itr;
1817                ++inf_itr;
1818                continue;
1819             }
1820             else
1821                return false;
1822          }
1823
1824          if (negative)
1825             t = -std::numeric_limits<T>::infinity();
1826          else
1827             t =  std::numeric_limits<T>::infinity();
1828
1829          return true;
1830       }
1831
1832       template <typename Iterator, typename T>
1833       inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag)
1834       {
1835          if (end == itr_external) return false;
1836
1837          Iterator itr = itr_external;
1838
1839          T d = T(0);
1840
1841          const bool negative = ('-' == (*itr));
1842
1843          if (negative || '+' == (*itr))
1844          {
1845             if (end == ++itr)
1846                return false;
1847          }
1848
1849          bool instate = false;
1850
1851          static const char_t zero = static_cast<uchar_t>('0');
1852
1853          #define parse_digit_1(d)          \
1854          if ((digit = (*itr - zero)) < 10) \
1855             { d = d * T(10) + digit; }     \
1856          else                              \
1857             { break; }                     \
1858          if (end == ++itr) break;          \
1859
1860          #define parse_digit_2(d)          \
1861          if ((digit = (*itr - zero)) < 10) \
1862             { d = d * T(10) + digit; }     \
1863          else { break; }                   \
1864             ++itr;                         \
1865
1866          if ('.' != (*itr))
1867          {
1868             const Iterator curr = itr;
1869
1870             while ((end != itr) && (zero == (*itr))) ++itr;
1871
1872             unsigned int digit;
1873
1874             while (end != itr)
1875             {
1876                // Note: For 'physical' superscalar architectures it
1877                // is advised that the following loop be: 4xPD1 and 1xPD2
1878                #ifdef exprtk_enable_superscalar
1879                parse_digit_1(d)
1880                parse_digit_1(d)
1881                #endif
1882                parse_digit_1(d)
1883                parse_digit_1(d)
1884                parse_digit_2(d)
1885             }
1886
1887             if (curr != itr) instate = true;
1888          }
1889
1890          int exponent = 0;
1891
1892          if (end != itr)
1893          {
1894             if ('.' == (*itr))
1895             {
1896                const Iterator curr = ++itr;
1897                unsigned int digit;
1898                T tmp_d = T(0);
1899
1900                while (end != itr)
1901                {
1902                   #ifdef exprtk_enable_superscalar
1903                   parse_digit_1(tmp_d)
1904                   parse_digit_1(tmp_d)
1905                   parse_digit_1(tmp_d)
1906                   #endif
1907                   parse_digit_1(tmp_d)
1908                   parse_digit_1(tmp_d)
1909                   parse_digit_2(tmp_d)
1910                }
1911
1912                if (curr != itr)
1913                {
1914                   instate = true;
1915                   d += compute_pow10(tmp_d,static_cast<int>(-std::distance(curr,itr)));
1916                }
1917
1918                #undef parse_digit_1
1919                #undef parse_digit_2
1920             }
1921
1922             if (end != itr)
1923             {
1924                typename std::iterator_traits<Iterator>::value_type c = (*itr);
1925
1926                if (('e' == c) || ('E' == c))
1927                {
1928                   int exp = 0;
1929
1930                   if (!details::string_to_type_converter_impl_ref(++itr, end, exp))
1931                   {
1932                      if (end == itr)
1933                         return false;
1934                      else
1935                         c = (*itr);
1936                   }
1937
1938                   exponent += exp;
1939                }
1940
1941                if (end != itr)
1942                {
1943                   if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c))
1944                      ++itr;
1945                   else if ('#' == c)
1946                   {
1947                      if (end == ++itr)
1948                         return false;
1949                      else if (('I' <= (*itr)) && ((*itr) <= 'n'))
1950                      {
1951                         if (('i' == (*itr)) || ('I' == (*itr)))
1952                         {
1953                            return parse_inf(itr, end, t, negative);
1954                         }
1955                         else if (('n' == (*itr)) || ('N' == (*itr)))
1956                         {
1957                            return parse_nan(itr, end, t);
1958                         }
1959                         else
1960                            return false;
1961                      }
1962                      else
1963                         return false;
1964                   }
1965                   else if (('I' <= (*itr)) && ((*itr) <= 'n'))
1966                   {
1967                      if (('i' == (*itr)) || ('I' == (*itr)))
1968                      {
1969                         return parse_inf(itr, end, t, negative);
1970                      }
1971                      else if (('n' == (*itr)) || ('N' == (*itr)))
1972                      {
1973                         return parse_nan(itr, end, t);
1974                      }
1975                      else
1976                         return false;
1977                   }
1978                   else
1979                      return false;
1980                }
1981             }
1982          }
1983
1984          if ((end != itr) || (!instate))
1985             return false;
1986          else if (exponent)
1987             d = compute_pow10(d,exponent);
1988
1989          t = static_cast<T>((negative) ? -d : d);
1990          return true;
1991       }
1992
1993       template <typename T>
1994       inline bool string_to_real(const std::string& s, T& t)
1995       {
1996          const typename numeric::details::number_type<T>::type num_type;
1997
1998          char_cptr begin = s.data();
1999          char_cptr end   = s.data() + s.size();
2000
2001          return string_to_real(begin, end, t, num_type);
2002       }
2003
2004       template <typename T>
2005       struct functor_t
2006       {
2007          /*
2008             Note: The following definitions for Type, may require tweaking
2009                   based on the compiler and target architecture. The benchmark
2010                   should provide enough information to make the right choice.
2011          */
2012          //typedef T Type;
2013          //typedef const T Type;
2014          typedef const T& Type;
2015          typedef       T& RefType;
2016          typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3);
2017          typedef T (*tfunc_t)(Type t0, Type t1, Type t2);
2018          typedef T (*bfunc_t)(Type t0, Type t1);
2019          typedef T (*ufunc_t)(Type t0);
2020       };
2021
2022    } // namespace details
2023
2024    namespace lexer
2025    {
2026       struct token
2027       {
2028          enum token_type
2029          {
2030             e_none        =   0, e_error       =   1, e_err_symbol  =   2,
2031             e_err_number  =   3, e_err_string  =   4, e_err_sfunc   =   5,
2032             e_eof         =   6, e_number      =   7, e_symbol      =   8,
2033             e_string      =   9, e_assign      =  10, e_addass      =  11,
2034             e_subass      =  12, e_mulass      =  13, e_divass      =  14,
2035             e_modass      =  15, e_shr         =  16, e_shl         =  17,
2036             e_lte         =  18, e_ne          =  19, e_gte         =  20,
2037             e_swap        =  21, e_lt          = '<', e_gt          = '>',
2038             e_eq          = '=', e_rbracket    = ')', e_lbracket    = '(',
2039             e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}',
2040             e_lcrlbracket = '{', e_comma       = ',', e_add         = '+',
2041             e_sub         = '-', e_div         = '/', e_mul         = '*',
2042             e_mod         = '%', e_pow         = '^', e_colon       = ':',
2043             e_ternary     = '?'
2044          };
2045
2046          token()
2047          : type(e_none),
2048            value(""),
2049            position(std::numeric_limits<std::size_t>::max())
2050          {}
2051
2052          void clear()
2053          {
2054             type     = e_none;
2055             value    = "";
2056             position = std::numeric_limits<std::size_t>::max();
2057          }
2058
2059          template <typename Iterator>
2060          inline token& set_operator(const token_type tt,
2061                                     const Iterator begin, const Iterator end,
2062                                     const Iterator base_begin = Iterator(0))
2063          {
2064             type = tt;
2065             value.assign(begin,end);
2066             if (base_begin)
2067                position = static_cast<std::size_t>(std::distance(base_begin,begin));
2068             return (*this);
2069          }
2070
2071          template <typename Iterator>
2072          inline token& set_symbol(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0))
2073          {
2074             type = e_symbol;
2075             value.assign(begin,end);
2076             if (base_begin)
2077                position = static_cast<std::size_t>(std::distance(base_begin,begin));
2078             return (*this);
2079          }
2080
2081          template <typename Iterator>
2082          inline token& set_numeric(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0))
2083          {
2084             type = e_number;
2085             value.assign(begin,end);
2086             if (base_begin)
2087                position = static_cast<std::size_t>(std::distance(base_begin,begin));
2088             return (*this);
2089          }
2090
2091          template <typename Iterator>
2092          inline token& set_string(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0))
2093          {
2094             type = e_string;
2095             value.assign(begin,end);
2096             if (base_begin)
2097                position = static_cast<std::size_t>(std::distance(base_begin,begin));
2098             return (*this);
2099          }
2100
2101          inline token& set_string(const std::string& s, const std::size_t p)
2102          {
2103             type     = e_string;
2104             value    = s;
2105             position = p;
2106             return (*this);
2107          }
2108
2109          template <typename Iterator>
2110          inline token& set_error(const token_type et,
2111                                  const Iterator begin, const Iterator end,
2112                                  const Iterator base_begin = Iterator(0))
2113          {
2114             if (
2115                  (e_error      == et) ||
2116                  (e_err_symbol == et) ||
2117                  (e_err_number == et) ||
2118                  (e_err_string == et) ||
2119                  (e_err_sfunc  == et)
2120                )
2121             {
2122                type = et;
2123             }
2124             else
2125                type = e_error;
2126
2127             value.assign(begin,end);
2128
2129             if (base_begin)
2130                position = static_cast<std::size_t>(std::distance(base_begin,begin));
2131
2132             return (*this);
2133          }
2134
2135          static inline std::string to_str(token_type t)
2136          {
2137             switch (t)
2138             {
2139                case e_none        : return "NONE";
2140                case e_error       : return "ERROR";
2141                case e_err_symbol  : return "ERROR_SYMBOL";
2142                case e_err_number  : return "ERROR_NUMBER";
2143                case e_err_string  : return "ERROR_STRING";
2144                case e_eof         : return "EOF";
2145                case e_number      : return "NUMBER";
2146                case e_symbol      : return "SYMBOL";
2147                case e_string      : return "STRING";
2148                case e_assign      : return ":=";
2149                case e_addass      : return "+=";
2150                case e_subass      : return "-=";
2151                case e_mulass      : return "*=";
2152                case e_divass      : return "/=";
2153                case e_modass      : return "%=";
2154                case e_shr         : return ">>";
2155                case e_shl         : return "<<";
2156                case e_lte         : return "<=";
2157                case e_ne          : return "!=";
2158                case e_gte         : return ">=";
2159                case e_lt          : return "<";
2160                case e_gt          : return ">";
2161                case e_eq          : return "=";
2162                case e_rbracket    : return ")";
2163                case e_lbracket    : return "(";
2164                case e_rsqrbracket : return "]";
2165                case e_lsqrbracket : return "[";
2166                case e_rcrlbracket : return "}";
2167                case e_lcrlbracket : return "{";
2168                case e_comma       : return ",";
2169                case e_add         : return "+";
2170                case e_sub         : return "-";
2171                case e_div         : return "/";
2172                case e_mul         : return "*";
2173                case e_mod         : return "%";
2174                case e_pow         : return "^";
2175                case e_colon       : return ":";
2176                case e_ternary     : return "?";
2177                case e_swap        : return "<=>";
2178                default            : return "UNKNOWN";
2179             }
2180          }
2181
2182          inline bool is_error() const
2183          {
2184             return (
2185                      (e_error      == type) ||
2186                      (e_err_symbol == type) ||
2187                      (e_err_number == type) ||
2188                      (e_err_string == type) ||
2189                      (e_err_sfunc  == type)
2190                    );
2191          }
2192
2193          token_type type;
2194          std::string value;
2195          std::size_t position;
2196       };
2197
2198       class generator
2199       {
2200       public:
2201
2202          typedef token token_t;
2203          typedef std::vector<token_t> token_list_t;
2204          typedef std::vector<token_t>::iterator token_list_itr_t;
2205          typedef details::char_t char_t;
2206
2207          generator()
2208          : base_itr_(0),
2209            s_itr_   (0),
2210            s_end_   (0)
2211          {
2212             clear();
2213          }
2214
2215          inline void clear()
2216          {
2217             base_itr_ = 0;
2218             s_itr_    = 0;
2219             s_end_    = 0;
2220             token_list_.clear();
2221             token_itr_ = token_list_.end();
2222             store_token_itr_ = token_list_.end();
2223          }
2224
2225          inline bool process(const std::string& str)
2226          {
2227             base_itr_ = str.data();
2228             s_itr_    = str.data();
2229             s_end_    = str.data() + str.size();
2230
2231             eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_);
2232             token_list_.clear();
2233
2234             while (!is_end(s_itr_))
2235             {
2236                scan_token();
2237
2238                if (!token_list_.empty() && token_list_.back().is_error())
2239                   return false;
2240             }
2241
2242             return true;
2243          }
2244
2245          inline bool empty() const
2246          {
2247             return token_list_.empty();
2248          }
2249
2250          inline std::size_t size() const
2251          {
2252             return token_list_.size();
2253          }
2254
2255          inline void begin()
2256          {
2257             token_itr_ = token_list_.begin();
2258             store_token_itr_ = token_list_.begin();
2259          }
2260
2261          inline void store()
2262          {
2263             store_token_itr_ = token_itr_;
2264          }
2265
2266          inline void restore()
2267          {
2268             token_itr_ = store_token_itr_;
2269          }
2270
2271          inline token_t& next_token()
2272          {
2273             if (token_list_.end() != token_itr_)
2274             {
2275                return *token_itr_++;
2276             }
2277             else
2278                return eof_token_;
2279          }
2280
2281          inline token_t& peek_next_token()
2282          {
2283             if (token_list_.end() != token_itr_)
2284             {
2285                return *token_itr_;
2286             }
2287             else
2288                return eof_token_;
2289          }
2290
2291          inline token_t& operator[](const std::size_t& index)
2292          {
2293             if (index < token_list_.size())
2294                return token_list_[index];
2295             else
2296                return eof_token_;
2297          }
2298
2299          inline token_t operator[](const std::size_t& index) const
2300          {
2301             if (index < token_list_.size())
2302                return token_list_[index];
2303             else
2304                return eof_token_;
2305          }
2306
2307          inline bool finished() const
2308          {
2309             return (token_list_.end() == token_itr_);
2310          }
2311
2312          inline void insert_front(token_t::token_type tk_type)
2313          {
2314             if (
2315                  !token_list_.empty() &&
2316                  (token_list_.end() != token_itr_)
2317                )
2318             {
2319                token_t t = *token_itr_;
2320
2321                t.type     = tk_type;
2322                token_itr_ = token_list_.insert(token_itr_,t);
2323             }
2324          }
2325
2326          inline std::string substr(const std::size_t& begin, const std::size_t& end)
2327          {
2328             const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_;
2329             const details::char_cptr end_itr   = ((base_itr_ +   end) < s_end_) ? (base_itr_ +   end) : s_end_;
2330
2331             return std::string(begin_itr,end_itr);
2332          }
2333
2334          inline std::string remaining() const
2335          {
2336             if (finished())
2337                return "";
2338             else if (token_list_.begin() != token_itr_)
2339                return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_);
2340             else
2341                return std::string(base_itr_ + token_itr_->position, s_end_);
2342          }
2343
2344       private:
2345
2346          inline bool is_end(details::char_cptr itr)
2347          {
2348             return (s_end_ == itr);
2349          }
2350
2351          inline bool is_comment_start(details::char_cptr itr)
2352          {
2353             #ifndef exprtk_disable_comments
2354             const char_t c0 = *(itr + 0);
2355             const char_t c1 = *(itr + 1);
2356
2357             if ('#' == c0)
2358                return true;
2359             else if (!is_end(itr + 1))
2360             {
2361                if (('/' == c0) && ('/' == c1)) return true;
2362                if (('/' == c0) && ('*' == c1)) return true;
2363             }
2364             #endif
2365             return false;
2366          }
2367
2368          inline void skip_whitespace()
2369          {
2370             while (!is_end(s_itr_) && details::is_whitespace(*s_itr_))
2371             {
2372                ++s_itr_;
2373             }
2374          }
2375
2376          inline void skip_comments()
2377          {
2378             #ifndef exprtk_disable_comments
2379             // The following comment styles are supported:
2380             // 1. // .... \n
2381             // 2. #  .... \n
2382             // 3. /* .... */
2383             struct test
2384             {
2385                static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr)
2386                {
2387                   mode = 0;
2388                        if ('#' == c0)    { mode = 1; incr = 1; }
2389                   else if ('/' == c0)
2390                   {
2391                           if ('/' == c1) { mode = 1; incr = 2; }
2392                      else if ('*' == c1) { mode = 2; incr = 2; }
2393                   }
2394                   return (0 != mode);
2395                }
2396
2397                static inline bool comment_end(const char_t c0, const char_t c1, int& mode)
2398                {
2399                   if (
2400                        ((1 == mode) && ('\n' == c0)) ||
2401                        ((2 == mode) && ( '*' == c0) && ('/' == c1))
2402                      )
2403                   {
2404                      mode = 0;
2405                      return true;
2406                   }
2407                   else
2408                      return false;
2409                }
2410             };
2411
2412             int mode      = 0;
2413             int increment = 0;
2414
2415             if (is_end(s_itr_))
2416                return;
2417             else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment))
2418                return;
2419
2420             details::char_cptr cmt_start = s_itr_;
2421
2422             s_itr_ += increment;
2423
2424             while (!is_end(s_itr_))
2425             {
2426                if ((1 == mode) && test::comment_end(*s_itr_, 0, mode))
2427                {
2428                   ++s_itr_;
2429                   return;
2430                }
2431
2432                if ((2 == mode))
2433                {
2434                   if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode))
2435                   {
2436                      s_itr_ += 2;
2437                      return;
2438                   }
2439                }
2440
2441                 ++s_itr_;
2442             }
2443
2444             if (2 == mode)
2445             {
2446                token_t t;
2447                t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_);
2448                token_list_.push_back(t);
2449             }
2450             #endif
2451          }
2452
2453          inline void scan_token()
2454          {
2455             if (details::is_whitespace(*s_itr_))
2456             {
2457                skip_whitespace();
2458                return;
2459             }
2460             else if (is_comment_start(s_itr_))
2461             {
2462                skip_comments();
2463                return;
2464             }
2465             else if (details::is_operator_char(*s_itr_))
2466             {
2467                scan_operator();
2468                return;
2469             }
2470             else if (details::is_letter(*s_itr_))
2471             {
2472                scan_symbol();
2473                return;
2474             }
2475             else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_)))
2476             {
2477                scan_number();
2478                return;
2479             }
2480             else if ('$' == (*s_itr_))
2481             {
2482                scan_special_function();
2483                return;
2484             }
2485             #ifndef exprtk_disable_string_capabilities
2486             else if ('\'' == (*s_itr_))
2487             {
2488                scan_string();
2489                return;
2490             }
2491             #endif
2492             else if ('~' == (*s_itr_))
2493             {
2494                token_t t;
2495                t.set_symbol(s_itr_, s_itr_ + 1, base_itr_);
2496                token_list_.push_back(t);
2497                ++s_itr_;
2498                return;
2499             }
2500             else
2501             {
2502                token_t t;
2503                t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_);
2504                token_list_.push_back(t);
2505                ++s_itr_;
2506             }
2507          }
2508
2509          inline void scan_operator()
2510          {
2511             token_t t;
2512
2513             const char_t c0 = s_itr_[0];
2514
2515             if (!is_end(s_itr_ + 1))
2516             {
2517                const char_t c1 = s_itr_[1];
2518
2519                if (!is_end(s_itr_ + 2))
2520                {
2521                   const char_t c2 = s_itr_[2];
2522
2523                   if ((c0 == '<') && (c1 == '=') && (c2 == '>'))
2524                   {
2525                      t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_);
2526                      token_list_.push_back(t);
2527                      s_itr_ += 3;
2528                      return;
2529                   }
2530                }
2531
2532                token_t::token_type ttype = token_t::e_none;
2533
2534                     if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte;
2535                else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte;
2536                else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne;
2537                else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne;
2538                else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq;
2539                else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign;
2540                else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl;
2541                else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr;
2542                else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass;
2543                else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass;
2544                else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass;
2545                else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass;
2546                else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass;
2547
2548                if (token_t::e_none != ttype)
2549                {
2550                   t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_);
2551                   token_list_.push_back(t);
2552                   s_itr_ += 2;
2553                   return;
2554                }
2555             }
2556
2557             if ('<' == c0)
2558                t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_);
2559             else if ('>' == c0)
2560                t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_);
2561             else if (';' == c0)
2562                t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_);
2563             else if ('&' == c0)
2564                t.set_symbol(s_itr_, s_itr_ + 1, base_itr_);
2565             else if ('|' == c0)
2566                t.set_symbol(s_itr_, s_itr_ + 1, base_itr_);
2567             else
2568                t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_);
2569
2570             token_list_.push_back(t);
2571             ++s_itr_;
2572          }
2573
2574          inline void scan_symbol()
2575          {
2576             details::char_cptr initial_itr = s_itr_;
2577
2578             while (!is_end(s_itr_))
2579             {
2580                if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_)))
2581                {
2582                   if ('.' != (*s_itr_))
2583                      break;
2584                   /*
2585                      Permit symbols that contain a 'dot'
2586                      Allowed   : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123
2587                      Disallowed: .abc, abc.<white-space>, abc.<eof>, abc.<operator +,-,*,/...>
2588                   */
2589                   if (
2590                        (s_itr_ != initial_itr)                     &&
2591                        !is_end(s_itr_ + 1)                         &&
2592                        !details::is_letter_or_digit(*(s_itr_ + 1)) &&
2593                        ('_' != (*(s_itr_ + 1)))
2594                      )
2595                      break;
2596                }
2597
2598                ++s_itr_;
2599             }
2600
2601             token_t t;
2602             t.set_symbol(initial_itr,s_itr_,base_itr_);
2603             token_list_.push_back(t);
2604          }
2605
2606          inline void scan_number()
2607          {
2608             /*
2609                Attempt to match a valid numeric value in one of the following formats:
2610                (01) 123456
2611                (02) 123456.
2612                (03) 123.456
2613                (04) 123.456e3
2614                (05) 123.456E3
2615                (06) 123.456e+3
2616                (07) 123.456E+3
2617                (08) 123.456e-3
2618                (09) 123.456E-3
2619                (00) .1234
2620                (11) .1234e3
2621                (12) .1234E+3
2622                (13) .1234e+3
2623                (14) .1234E-3
2624                (15) .1234e-3
2625             */
2626
2627             details::char_cptr initial_itr = s_itr_;
2628             bool dot_found                 = false;
2629             bool e_found                   = false;
2630             bool post_e_sign_found         = false;
2631             bool post_e_digit_found        = false;
2632             token_t t;
2633
2634             while (!is_end(s_itr_))
2635             {
2636                if ('.' == (*s_itr_))
2637                {
2638                   if (dot_found)
2639                   {
2640                      t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
2641                      token_list_.push_back(t);
2642                      return;
2643                   }
2644
2645                   dot_found = true;
2646                   ++s_itr_;
2647
2648                   continue;
2649                }
2650                else if ('e' == std::tolower(*s_itr_))
2651                {
2652                   const char_t& c = *(s_itr_ + 1);
2653
2654                   if (is_end(s_itr_ + 1))
2655                   {
2656                      t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
2657                      token_list_.push_back(t);
2658
2659                      return;
2660                   }
2661                   else if (
2662                             ('+' != c) &&
2663                             ('-' != c) &&
2664                             !details::is_digit(c)
2665                           )
2666                   {
2667                      t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
2668                      token_list_.push_back(t);
2669
2670                      return;
2671                   }
2672
2673                   e_found = true;
2674                   ++s_itr_;
2675
2676                   continue;
2677                }
2678                else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found)
2679                {
2680                   if (post_e_sign_found)
2681                   {
2682                      t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_);
2683                      token_list_.push_back(t);
2684
2685                      return;
2686                   }
2687
2688                   post_e_sign_found = true;
2689                   ++s_itr_;
2690
2691                   continue;
2692                }
2693                else if (e_found && details::is_digit(*s_itr_))
2694                {
2695                   post_e_digit_found = true;
2696                   ++s_itr_;
2697
2698                   continue;
2699                }
2700                else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_))
2701                   break;
2702                else
2703                   ++s_itr_;
2704             }
2705
2706             t.set_numeric(initial_itr, s_itr_, base_itr_);
2707             token_list_.push_back(t);
2708
2709             return;
2710          }
2711
2712          inline void scan_special_function()
2713          {
2714             details::char_cptr initial_itr = s_itr_;
2715             token_t t;
2716
2717             // $fdd(x,x,x) = at least 11 chars
2718             if (std::distance(s_itr_,s_end_) < 11)
2719             {
2720                t.set_error(token::e_err_sfunc, initial_itr, s_itr_, base_itr_);
2721                token_list_.push_back(t);
2722
2723                return;
2724             }
2725
2726             if (
2727                  !(('$' == *s_itr_)                       &&
2728                    (details::imatch  ('f',*(s_itr_ + 1))) &&
2729                    (details::is_digit(*(s_itr_ + 2)))     &&
2730                    (details::is_digit(*(s_itr_ + 3))))
2731                )
2732             {
2733                t.set_error(token::e_err_sfunc, initial_itr, s_itr_, base_itr_);
2734                token_list_.push_back(t);
2735
2736                return;
2737             }
2738
2739             s_itr_ += 4; // $fdd = 4chars
2740
2741             t.set_symbol(initial_itr, s_itr_, base_itr_);
2742             token_list_.push_back(t);
2743
2744             return;
2745          }
2746
2747          #ifndef exprtk_disable_string_capabilities
2748          inline void scan_string()
2749          {
2750             details::char_cptr initial_itr = s_itr_ + 1;
2751             token_t t;
2752
2753             if (std::distance(s_itr_,s_end_) < 2)
2754             {
2755                t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_);
2756                token_list_.push_back(t);
2757                return;
2758             }
2759
2760             ++s_itr_;
2761
2762             bool escaped_found = false;
2763             bool escaped = false;
2764
2765             while (!is_end(s_itr_))
2766             {
2767                if (!escaped && ('\\' == *s_itr_))
2768                {
2769                   escaped_found = true;
2770                   escaped = true;
2771                   ++s_itr_;
2772
2773                   continue;
2774                }
2775                else if (!escaped)
2776                {
2777                   if ('\'' == *s_itr_)
2778                      break;
2779                }
2780                else if (escaped)
2781                {
2782                   if (!is_end(s_itr_) && ('0' == *(s_itr_)))
2783                   {
2784                      /*
2785                         Note: The following 'awkward' conditional is
2786                               due to various broken msvc compilers.
2787                      */
2788                      #if defined(_MSC_VER) && (_MSC_VER == 1600)
2789                      const bool within_range = !is_end(s_itr_ + 2) &&
2790                                                !is_end(s_itr_ + 3) ;
2791                      #else
2792                      const bool within_range = !is_end(s_itr_ + 1) &&
2793                                                !is_end(s_itr_ + 2) &&
2794                                                !is_end(s_itr_ + 3) ;
2795                      #endif
2796
2797                      const bool x_seperator  = ('x' == *(s_itr_ + 1)) ||
2798                                                ('X' == *(s_itr_ + 1)) ;
2799
2800                      const bool both_digits  = details::is_hex_digit(*(s_itr_ + 2)) &&
2801                                                details::is_hex_digit(*(s_itr_ + 3)) ;
2802
2803                      if (!within_range || !x_seperator || !both_digits)
2804                      {
2805                         t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
2806                         token_list_.push_back(t);
2807
2808                         return;
2809                      }
2810                      else
2811                         s_itr_ += 3;
2812                   }
2813
2814                   escaped = false;
2815                }
2816
2817                ++s_itr_;
2818             }
2819
2820             if (is_end(s_itr_))
2821             {
2822                t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_);
2823                token_list_.push_back(t);
2824
2825                return;
2826             }
2827
2828             if (!escaped_found)
2829                t.set_string(initial_itr, s_itr_, base_itr_);
2830             else
2831             {
2832                std::string parsed_string(initial_itr,s_itr_);
2833
2834                details::cleanup_escapes(parsed_string);
2835
2836                t.set_string(
2837                     parsed_string,
2838                     static_cast<std::size_t>(std::distance(base_itr_,initial_itr)));
2839             }
2840
2841             token_list_.push_back(t);
2842             ++s_itr_;
2843
2844             return;
2845          }
2846          #endif
2847
2848       private:
2849
2850          token_list_t     token_list_;
2851          token_list_itr_t token_itr_;
2852          token_list_itr_t store_token_itr_;
2853          token_t eof_token_;
2854          details::char_cptr base_itr_;
2855          details::char_cptr s_itr_;
2856          details::char_cptr s_end_;
2857
2858          friend class token_scanner;
2859          friend class token_modifier;
2860          friend class token_inserter;
2861          friend class token_joiner;
2862       };
2863
2864       class helper_interface
2865       {
2866       public:
2867
2868          virtual void init()                     {              }
2869          virtual void reset()                    {              }
2870          virtual bool result()                   { return true; }
2871          virtual std::size_t process(generator&) { return 0;    }
2872          virtual ~helper_interface()             {              }
2873       };
2874
2875       class token_scanner : public helper_interface
2876       {
2877       public:
2878
2879          virtual ~token_scanner()
2880          {}
2881
2882          explicit token_scanner(const std::size_t& stride)
2883          : stride_(stride)
2884          {
2885             if (stride > 4)
2886             {
2887                throw std::invalid_argument("token_scanner() - Invalid stride value");
2888             }
2889          }
2890
2891          inline std::size_t process(generator& g)
2892          {
2893             if (g.token_list_.size() >= stride_)
2894             {
2895                for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
2896                {
2897                   token t;
2898
2899                   switch (stride_)
2900                   {
2901                      case 1 :
2902                               {
2903                                  const token& t0 = g.token_list_[i];
2904
2905                                  if (!operator()(t0))
2906                                  {
2907                                     return i;
2908                                  }
2909                               }
2910                               break;
2911
2912                      case 2 :
2913                               {
2914                                  const token& t0 = g.token_list_[i    ];
2915                                  const token& t1 = g.token_list_[i + 1];
2916
2917                                  if (!operator()(t0, t1))
2918                                  {
2919                                     return i;
2920                                  }
2921                               }
2922                               break;
2923
2924                      case 3 :
2925                               {
2926                                  const token& t0 = g.token_list_[i    ];
2927                                  const token& t1 = g.token_list_[i + 1];
2928                                  const token& t2 = g.token_list_[i + 2];
2929
2930                                  if (!operator()(t0, t1, t2))
2931                                  {
2932                                     return i;
2933                                  }
2934                               }
2935                               break;
2936
2937                      case 4 :
2938                               {
2939                                  const token& t0 = g.token_list_[i    ];
2940                                  const token& t1 = g.token_list_[i + 1];
2941                                  const token& t2 = g.token_list_[i + 2];
2942                                  const token& t3 = g.token_list_[i + 3];
2943
2944                                  if (!operator()(t0, t1, t2, t3))
2945                                  {
2946                                     return i;
2947                                  }
2948                               }
2949                               break;
2950                   }
2951                }
2952             }
2953
2954             return (g.token_list_.size() - stride_ + 1);
2955          }
2956
2957          virtual bool operator() (const token&)
2958          {
2959             return false;
2960          }
2961
2962          virtual bool operator() (const token&, const token&)
2963          {
2964             return false;
2965          }
2966
2967          virtual bool operator() (const token&, const token&, const token&)
2968          {
2969             return false;
2970          }
2971
2972          virtual bool operator() (const token&, const token&, const token&, const token&)
2973          {
2974             return false;
2975          }
2976
2977       private:
2978
2979          const std::size_t stride_;
2980       };
2981
2982       class token_modifier : public helper_interface
2983       {
2984       public:
2985
2986          inline std::size_t process(generator& g)
2987          {
2988             std::size_t changes = 0;
2989
2990             for (std::size_t i = 0; i < g.token_list_.size(); ++i)
2991             {
2992                if (modify(g.token_list_[i])) changes++;
2993             }
2994
2995             return changes;
2996          }
2997
2998          virtual bool modify(token& t) = 0;
2999       };
3000
3001       class token_inserter : public helper_interface
3002       {
3003       public:
3004
3005          explicit token_inserter(const std::size_t& stride)
3006          : stride_(stride)
3007          {
3008             if (stride > 5)
3009             {
3010                throw std::invalid_argument("token_inserter() - Invalid stride value");
3011             }
3012          }
3013
3014          inline std::size_t process(generator& g)
3015          {
3016             if (g.token_list_.empty())
3017                return 0;
3018             else if (g.token_list_.size() < stride_)
3019                return 0;
3020
3021             std::size_t changes = 0;
3022
3023             for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
3024             {
3025                int insert_index = -1;
3026                token t;
3027
3028                switch (stride_)
3029                {
3030                   case 1 : insert_index = insert(g.token_list_[i],t);
3031                            break;
3032
3033                   case 2 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], t);
3034                            break;
3035
3036                   case 3 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], t);
3037                            break;
3038
3039                   case 4 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], t);
3040                            break;
3041
3042                   case 5 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], g.token_list_[i + 4], t);
3043                            break;
3044                }
3045
3046                typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t;
3047
3048                if ((insert_index >= 0) && (insert_index <= (static_cast<int>(stride_) + 1)))
3049                {
3050                   g.token_list_.insert(
3051                      g.token_list_.begin() + static_cast<diff_t>(i + static_cast<std::size_t>(insert_index)), t);
3052
3053                   changes++;
3054                }
3055             }
3056
3057             return changes;
3058          }
3059
3060          #define token_inserter_empty_body \
3061          {                                 \
3062             return -1;                     \
3063          }                                 \
3064
3065          inline virtual int insert(const token&, token&)
3066          token_inserter_empty_body
3067
3068          inline virtual int insert(const token&, const token&, token&)
3069          token_inserter_empty_body
3070
3071          inline virtual int insert(const token&, const token&, const token&, token&)
3072          token_inserter_empty_body
3073
3074          inline virtual int insert(const token&, const token&, const token&, const token&, token&)
3075          token_inserter_empty_body
3076
3077          inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&)
3078          token_inserter_empty_body
3079
3080          #undef token_inserter_empty_body
3081
3082       private:
3083
3084          const std::size_t stride_;
3085       };
3086
3087       class token_joiner : public helper_interface
3088       {
3089       public:
3090
3091          explicit token_joiner(const std::size_t& stride)
3092          : stride_(stride)
3093          {}
3094
3095          inline std::size_t process(generator& g)
3096          {
3097             if (g.token_list_.empty())
3098                return 0;
3099
3100             switch (stride_)
3101             {
3102                case 2  : return process_stride_2(g);
3103                case 3  : return process_stride_3(g);
3104                default : return 0;
3105             }
3106          }
3107
3108          virtual bool join(const token&, const token&, token&)               { return false; }
3109          virtual bool join(const token&, const token&, const token&, token&) { return false; }
3110
3111       private:
3112
3113          inline std::size_t process_stride_2(generator& g)
3114          {
3115             typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t;
3116
3117             if (g.token_list_.size() < 2)
3118                return 0;
3119
3120             std::size_t changes = 0;
3121
3122             for (int i = 0;  i < static_cast<int>(g.token_list_.size() - 1); ++i)
3123             {
3124                token t;
3125
3126                while (join(g[i], g[i + 1], t))
3127                {
3128                   g.token_list_[i] = t;
3129
3130                   g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1));
3131
3132                   ++changes;
3133
3134                   if (static_cast<std::size_t>(i + 1) >= g.token_list_.size())
3135                      break;
3136                }
3137             }
3138
3139             return changes;
3140          }
3141
3142          inline std::size_t process_stride_3(generator& g)
3143          {
3144             typedef std::iterator_traits<generator::token_list_t::iterator>::difference_type diff_t;
3145
3146             if (g.token_list_.size() < 3)
3147                return 0;
3148
3149             std::size_t changes = 0;
3150
3151             for (int i = 0;  i < static_cast<int>(g.token_list_.size() - 2); ++i)
3152             {
3153                token t;
3154
3155                while (join(g[i], g[i + 1], g[i + 2], t))
3156                {
3157                   g.token_list_[i] = t;
3158
3159                   g.token_list_.erase(g.token_list_.begin() + static_cast<diff_t>(i + 1),
3160                                       g.token_list_.begin() + static_cast<diff_t>(i + 3));
3161                   ++changes;
3162
3163                   if (static_cast<std::size_t>(i + 2) >= g.token_list_.size())
3164                      break;
3165                }
3166             }
3167
3168             return changes;
3169          }
3170
3171          const std::size_t stride_;
3172       };
3173
3174       namespace helper
3175       {
3176
3177          inline void dump(lexer::generator& generator)
3178          {
3179             for (std::size_t i = 0; i < generator.size(); ++i)
3180             {
3181                lexer::token t = generator[i];
3182                printf("Token[%02d] @ %03d  %6s  -->  '%s'\n",
3183                       static_cast<int>(i),
3184                       static_cast<int>(t.position),
3185                       t.to_str(t.type).c_str(),
3186                       t.value.c_str());
3187             }
3188          }
3189
3190          class commutative_inserter : public lexer::token_inserter
3191          {
3192          public:
3193
3194             using lexer::token_inserter::insert;
3195
3196             commutative_inserter()
3197             : lexer::token_inserter(2)
3198             {}
3199
3200             inline void ignore_symbol(const std::string& symbol)
3201             {
3202                ignore_set_.insert(symbol);
3203             }
3204
3205             inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token)
3206             {
3207                bool match         = false;
3208                new_token.type     = lexer::token::e_mul;
3209                new_token.value    = "*";
3210                new_token.position = t1.position;
3211
3212                if (t0.type == lexer::token::e_symbol)
3213                {
3214                   if (ignore_set_.end() != ignore_set_.find(t0.value))
3215                   {
3216                      return -1;
3217                   }
3218                   else if (!t0.value.empty() && ('$' == t0.value[0]))
3219                   {
3220                      return -1;
3221                   }
3222                }
3223
3224                if (t1.type == lexer::token::e_symbol)
3225                {
3226                   if (ignore_set_.end() != ignore_set_.find(t1.value))
3227                   {
3228                      return -1;
3229                   }
3230                }
3231                     if ((t0.type == lexer::token::e_number     ) && (t1.type == lexer::token::e_symbol     )) match = true;
3232                else if ((t0.type == lexer::token::e_number     ) && (t1.type == lexer::token::e_lbracket   )) match = true;
3233                else if ((t0.type == lexer::token::e_number     ) && (t1.type == lexer::token::e_lcrlbracket)) match = true;
3234                else if ((t0.type == lexer::token::e_number     ) && (t1.type == lexer::token::e_lsqrbracket)) match = true;
3235                else if ((t0.type == lexer::token::e_symbol     ) && (t1.type == lexer::token::e_number     )) match = true;
3236                else if ((t0.type == lexer::token::e_rbracket   ) && (t1.type == lexer::token::e_number     )) match = true;
3237                else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number     )) match = true;
3238                else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number     )) match = true;
3239                else if ((t0.type == lexer::token::e_rbracket   ) && (t1.type == lexer::token::e_symbol     )) match = true;
3240                else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol     )) match = true;
3241                else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol     )) match = true;
3242                else if ((t0.type == lexer::token::e_symbol     ) && (t1.type == lexer::token::e_symbol     )) match = true;
3243
3244                return (match) ? 1 : -1;
3245             }
3246
3247          private:
3248
3249             std::set<std::string,details::ilesscompare> ignore_set_;
3250          };
3251
3252          class operator_joiner : public token_joiner
3253          {
3254          public:
3255
3256             explicit operator_joiner(const std::size_t& stride)
3257             : token_joiner(stride)
3258             {}
3259
3260             inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t)
3261             {
3262                // ': =' --> ':='
3263                if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq))
3264                {
3265                   t.type     = lexer::token::e_assign;
3266                   t.value    = ":=";
3267                   t.position = t0.position;
3268
3269                   return true;
3270                }
3271                // '+ =' --> '+='
3272                else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq))
3273                {
3274                   t.type     = lexer::token::e_addass;
3275