// File: ArashPartow[P]exprtk-extras/exprtk_arithmetic_evaluator.cpp
// Function: void basic_arithmetic_parser_evaluator<double>()
void basic_arithmetic_parser_evaluator()
{
   typedef exprtk::symbol_table<T> symbol_table_t;
   typedef exprtk::expression<T>   expression_t;
   typedef exprtk::parser<T>       parser_t;

   const std::string arithmetic_parser_evaluator_program =
      " var curr_val := 0;                                "
      " var prev_val := 0;                                "
      " var result   := 0;                                "
      " var op       := '+';                              "
      "                                                   "
      " for (var i := 0; i < expression[]; i += 1)        "
      " {                                                 "
      "    var c := expression[i : i + 1];                "
      "                                                   "
      "    if (is_digit(c))                               "
      "    {                                              "
      "       curr_val := curr_val * 10 + to_num(c);      "
      "    };                                             "
      "                                                   "
      "    if (is_opr(c) or (i == expression[] - 1))      "
      "    {                                              "
      "       prev_val :=                                 "
      "          switch                                   "
      "          {                                        "
      "             case op == '+' :                      "
      "              ~{                                   "
      "                   result += prev_val;             "
      "                   curr_val;                       "
      "               };                                  "
      "                                                   "
      "             case op == '-' :                      "
      "              ~{                                   "
      "                  result += prev_val;              "
      "                  -curr_val;                       "
      "               };                                  "
      "                                                   "
      "             case op == '*' : prev_val * curr_val; "
      "             case op == '/' : prev_val / curr_val; "
      "          };                                       "
      "                                                   "
      "       curr_val := 0;                              "
      "       op       := c;                              "
      "    }                                              "
      " };                                                "
      "                                                   "
      " result += prev_val;                               "
      "                                                   "
      " println(result, ' = ', expression);               "
      "                                                   ";

   std::string arithmetic_expression;

   char_process<T,is_digit_func<T> >    isdigit;
   char_process<T,to_num_func<T> >      tonum;
   char_process<T,is_operator_func<T> > isopr;
   exprtk::rtl::io::println<T>          println;

   symbol_table_t symbol_table;
   symbol_table.add_stringvar("expression", arithmetic_expression);
   symbol_table.add_function ("println"   , println              );
   symbol_table.add_function ("is_digit"  , isdigit              );
   symbol_table.add_function ("is_opr"    , isopr                );
   symbol_table.add_function ("to_num"    , tonum                );

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(arithmetic_parser_evaluator_program, expression);

   /*
      Note: Expressions can be comprised of integers,
            basic arithmetic operators (+, -, *, /),
            and shall not contain parenthesises.
    */
   const std::vector<std::string> arithmetic_expressions =
   {
      "5 + 18 / 3",
      "4 + 3 * 15",
      "1 - 2 + 52 / 2 - 81 / 3",
   };

   for (const auto& expr : arithmetic_expressions)
   {
      arithmetic_expression = expr;
      expression.value();
   }
}

// Assembly:
subq $0xe98, %rsp            # imm = 0xE98
leaq 0xe77(%rsp), %rdi
movq %rdi, 0xb0(%rsp)
callq 0x111650
movq 0xb0(%rsp), %rdx
leaq 0x332cfa(%rip), %rsi    # 0x44b545
leaq 0xe78(%rsp), %rdi
callq 0x118760
jmp 0x11885a
leaq 0xe77(%rsp), %rdi
callq 0x111780
leaq 0xe40(%rsp), %rdi
callq 0x111270
leaq 0xdf8(%rsp), %rdi
callq 0x1195a0
jmp 0x118883
leaq 0xdb0(%rsp), %rdi
callq 0x119660
jmp 0x118892
leaq 0xd68(%rsp), %rdi
callq 0x119720
jmp 0x1188a1
leaq 0xcdf(%rsp), %rdi
movq %rdi, 0xa8(%rsp)
callq 0x111650
movq 0xa8(%rsp), %rdx
leaq 0x333545(%rip), %rsi    # 0x44be0a
leaq 0xce0(%rsp), %rdi
callq 0x118760
jmp 0x1188d4
leaq 0xd00(%rsp), %rdi
leaq 0xce0(%rsp), %rsi
callq 0x1197e0
jmp 0x1188eb
leaq 0xce0(%rsp), %rdi
callq 0x111798
leaq 0xcdf(%rsp), %rdi
callq 0x111780
leaq 0xcd0(%rsp), %rdi
movl $0x1, %esi
callq 0x1198f0
jmp 0x118919
leaq 0xcaf(%rsp), %rdi
movq %rdi, 0xa0(%rsp)
callq 0x111650
movq 0xa0(%rsp), %rdx
leaq 0x335d1f(%rip), %rsi    # 0x44e65c
leaq 0xcb0(%rsp), %rdi
callq 0x118760
jmp 0x11894c
leaq 0xcd0(%rsp), %rdi
leaq 0xcb0(%rsp), %rsi
leaq 0xe40(%rsp), %rdx
xorl %ecx, %ecx
callq 0x119930
jmp 0x11896d
leaq 0xcb0(%rsp), %rdi
callq 0x111798
leaq 0xcaf(%rsp), %rdi
callq 0x111780
leaq 0xc87(%rsp), %rdi
movq %rdi, 0x98(%rsp)
callq 0x111650
movq 0x98(%rsp), %rdx
leaq 0x333466(%rip), %rsi    # 0x44be11
leaq 0xc88(%rsp), %rdi
callq 0x118760
jmp 0x1189ba
leaq 0xcd0(%rsp), %rdi
leaq 0xc88(%rsp), %rsi
leaq 0xd00(%rsp), %rdx
callq 0x1199f0
jmp 0x1189d9
leaq 0xc88(%rsp), %rdi
callq 0x111798
leaq 0xc87(%rsp), %rdi
callq 0x111780
leaq 0xc5f(%rsp), %rdi
movq %rdi, 0x90(%rsp)
callq 0x111650
movq 0x90(%rsp), %rdx
leaq 0x333402(%rip), %rsi    # 0x44be19
leaq 0xc60(%rsp), %rdi
callq 0x118760
jmp 0x118a26
leaq 0xcd0(%rsp), %rdi
leaq 0xc60(%rsp), %rsi
leaq 0xdf8(%rsp), %rdx
callq 0x1199f0
jmp 0x118a45
leaq 0xc60(%rsp), %rdi
callq 0x111798
leaq 0xc5f(%rsp), %rdi
callq 0x111780
leaq 0xc37(%rsp), %rdi
movq %rdi, 0x88(%rsp)
callq 0x111650
movq 0x88(%rsp), %rdx
leaq 0x33339f(%rip), %rsi    # 0x44be22
leaq 0xc38(%rsp), %rdi
callq 0x118760
jmp 0x118a92
leaq 0xcd0(%rsp), %rdi
leaq 0xc38(%rsp), %rsi
leaq 0xd68(%rsp), %rdx
callq 0x1199f0
jmp 0x118ab1
leaq 0xc38(%rsp), %rdi
callq 0x111798
leaq 0xc37(%rsp), %rdi
callq 0x111780
leaq 0xc0f(%rsp), %rdi
movq %rdi, 0x80(%rsp)
callq 0x111650
movq 0x80(%rsp), %rdx
leaq 0x33333a(%rip), %rsi    # 0x44be29
leaq 0xc10(%rsp), %rdi
callq 0x118760
jmp 0x118afe
leaq 0xcd0(%rsp), %rdi
leaq 0xc10(%rsp), %rsi
leaq 0xdb0(%rsp), %rdx
callq 0x1199f0
jmp 0x118b1d
leaq 0xc10(%rsp), %rdi
callq 0x111798
leaq 0xc0f(%rsp), %rdi
callq 0x111780
leaq 0xbe8(%rsp), %rdi
callq 0x119bf0
jmp 0x118b46
leaq 0xbe8(%rsp), %rdi
leaq 0xcd0(%rsp), %rsi
callq 0x119ca0
jmp 0x118b5d
leaq 0x170(%rsp), %rdi
movl $0x7f, %esi
callq 0x119d50
jmp 0x118b71
leaq 0x2c0(%rsp), %rdi
leaq 0x170(%rsp), %rsi
callq 0x119e80
jmp 0x118b88
leaq 0x170(%rsp), %rdi
callq 0x11a6b0
leaq 0x2c0(%rsp), %rdi
leaq 0xe78(%rsp), %rsi
leaq 0xbe8(%rsp), %rdx
callq 0x11a720
jmp 0x118bb4
movb $0x1, 0xdc(%rsp)
leaq 0xe8(%rsp), %rax
movq %rax, 0x70(%rsp)
movq %rax, 0xe0(%rsp)
leaq 0xdf(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x111650
movq 0x70(%rsp), %rdi
movq 0x78(%rsp), %rdx
leaq 0x33323c(%rip), %rsi    # 0x44be30
callq 0x118760
jmp 0x118bfb
leaq 0x108(%rsp), %rax
movq %rax, 0x60(%rsp)
movq %rax, 0xe0(%rsp)
leaq 0xde(%rsp), %rdi
movq %rdi, 0x68(%rsp)
callq 0x111650
movq 0x60(%rsp), %rdi
movq 0x68(%rsp), %rdx
leaq 0x333208(%rip), %rsi    # 0x44be3b
callq 0x118760
jmp 0x118c3a
leaq 0x128(%rsp), %rax
movq %rax, 0x50(%rsp)
movq %rax, 0xe0(%rsp)
leaq 0xdd(%rsp), %rdi
movq %rdi, 0x58(%rsp)
callq 0x111650
movq 0x50(%rsp), %rdi
movq 0x58(%rsp), %rdx
leaq 0x3331d4(%rip), %rsi    # 0x44be46
callq 0x118760
jmp 0x118c79
movb $0x0, 0xdc(%rsp)
leaq 0xe8(%rsp), %rax
movq %rax, 0x148(%rsp)
movq $0x3, 0x150(%rsp)
leaq 0xdb(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x11afb0
movq 0x48(%rsp), %rcx
movq 0x148(%rsp), %rsi
movq 0x150(%rsp), %rdx
leaq 0x158(%rsp), %rdi
callq 0x11afc0
jmp 0x118cd3
leaq 0xdb(%rsp), %rdi
callq 0x11b050
leaq 0xe8(%rsp), %rax
movq %rax, 0x38(%rsp)
addq $0x60, %rax
movq %rax, 0x40(%rsp)
movq 0x40(%rsp), %rdi
addq $-0x20, %rdi
movq %rdi, 0x30(%rsp)
callq 0x111798
movq 0x38(%rsp), %rcx
movq 0x30(%rsp), %rax
cmpq %rcx, %rax
movq %rax, 0x40(%rsp)
jne 0x118cf6
leaq 0xdd(%rsp), %rdi
callq 0x111780
leaq 0xde(%rsp), %rdi
callq 0x111780
leaq 0xdf(%rsp), %rdi
callq 0x111780
leaq 0x158(%rsp), %rax
movq %rax, 0xd0(%rsp)
movq 0xd0(%rsp), %rdi
callq 0x11b060
movq %rax, 0xc8(%rsp)
movq 0xd0(%rsp), %rdi
callq 0x11b090
movq %rax, 0xc0(%rsp)
leaq 0xc8(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x11b0c0
testb $0x1, %al
jne 0x118d9c
jmp 0x1191e5
leaq 0xc8(%rsp), %rdi
callq 0x11b100
movq %rax, 0xb8(%rsp)
movq 0xb8(%rsp), %rsi
leaq 0xe40(%rsp), %rdi
callq 0x111720
jmp 0x118dc8
leaq 0xbe8(%rsp), %rdi
callq 0x11b110
jmp 0x118dd7
jmp 0x118dd9
leaq 0xc8(%rsp), %rdi
callq 0x11b130
jmp 0x118d7e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xe77(%rsp), %rdi
callq 0x111780
jmp 0x1192e4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x1192ca
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x1192bd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x1192b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x118e90
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xce0(%rsp), %rdi
callq 0x111798
leaq 0xcdf(%rsp), %rdi
callq 0x111780
jmp 0x1192a3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x119296
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x118ef2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xcb0(%rsp), %rdi
callq 0x111798
leaq 0xcaf(%rsp), %rdi
callq 0x111780
jmp 0x119289
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x118f3b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xc88(%rsp), %rdi
callq 0x111798
leaq 0xc87(%rsp), %rdi
callq 0x111780
jmp 0x119289
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x118f84
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xc60(%rsp), %rdi
callq 0x111798
leaq 0xc5f(%rsp), %rdi
callq 0x111780
jmp 0x119289
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x118fcd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xc38(%rsp), %rdi
callq 0x111798
leaq 0xc37(%rsp), %rdi
callq 0x111780
jmp 0x119289
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x119016
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xc10(%rsp), %rdi
callq 0x111798
leaq 0xc0f(%rsp), %rdi
callq 0x111780
jmp 0x119289
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x119289
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x11927c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0x170(%rsp), %rdi
callq 0x11a6b0
jmp 0x11927c
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x11926f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x11915b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x11914e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
jmp 0x119141
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0xdb(%rsp), %rdi
callq 0x11b050
leaq 0xe8(%rsp), %rax
movq %rax, 0x20(%rsp)
addq $0x60, %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rdi
addq $-0x20, %rdi
movq %rdi, 0x18(%rsp)
callq 0x111798
movq 0x20(%rsp), %rcx
movq 0x18(%rsp), %rax
cmpq %rcx, %rax
movq %rax, 0x28(%rsp)
jne 0x119118
jmp 0x119141
leaq 0xdd(%rsp), %rdi
callq 0x111780
leaq 0xde(%rsp), %rdi
callq 0x111780
leaq 0xdf(%rsp), %rdi
callq 0x111780
testb $0x1, 0xdc(%rsp)
jne 0x119174
jmp 0x1191ba
movq 0xe0(%rsp), %rax
leaq 0xe8(%rsp), %rcx
cmpq %rax, %rcx
movq %rax, 0x10(%rsp)
je 0x1191b8
movq 0x10(%rsp), %rdi
addq $-0x20, %rdi
movq %rdi, 0x8(%rsp)
callq 0x111798
movq 0x8(%rsp), %rax
leaq 0xe8(%rsp), %rcx
cmpq %rcx, %rax
movq %rax, 0x10(%rsp)
jne 0x11918e
jmp 0x1191ba
jmp 0x11926f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe68(%rsp)
movl %eax, 0xe64(%rsp)
leaq 0x158(%rsp), %rdi
callq 0x11b150
jmp 0x11926f
leaq 0x158(%rsp), %rdi
callq 0x11b150
leaq 0x2c0(%rsp), %rdi
callq 0x11b1b0
leaq 0xbe8(%rsp), %rdi
callq 0x11b3b0
leaq 0xcd0(%rsp), %rdi
callq 0x11b3f0
leaq 0xd00(%rsp), %rdi
callq 0x11b470
leaq 0xd68(%rsp), %rdi
callq 0x11b4a0
leaq 0xdb0(%rsp), %rdi
callq 0x11b4b0
leaq 0xdf8(%rsp), %rdi
callq 0x11b4c0
leaq 0xe40(%rsp), %rdi
callq 0x111798
leaq 0xe78(%rsp), %rdi
callq 0x111798
addq $0xe98, %rsp            # imm = 0xE98
retq
leaq 0x2c0(%rsp), %rdi
callq 0x11b1b0
leaq 0xbe8(%rsp), %rdi
callq 0x11b3b0
leaq 0xcd0(%rsp), %rdi
callq 0x11b3f0
leaq 0xd00(%rsp), %rdi
callq 0x11b470
leaq 0xd68(%rsp), %rdi
callq 0x11b4a0
leaq 0xdb0(%rsp), %rdi
callq 0x11b4b0
leaq 0xdf8(%rsp), %rdi
callq 0x11b4c0
leaq 0xe40(%rsp), %rdi
callq 0x111798
leaq 0xe78(%rsp), %rdi
callq 0x111798
movq 0xe68(%rsp), %rdi
callq 0x111450
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)