// File: ArashPartow[P]exprtk-extras/exprtk_truthtable_gen.cpp
// Function: void truth_table_generator<double>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&)
void truth_table_generator(const std::string& boolean_expression)
{
   typedef exprtk::symbol_table<T>    symbol_table_t;
   typedef exprtk::expression<T>      expression_t;
   typedef exprtk::parser<T>          parser_t;
   typedef exprtk::parser_error::type err_t;
   typedef typename parser_t::settings_store settings_t;

   symbol_table_t symbol_table;

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   static const std::size_t compile_options =
      settings_t::e_replacer            +
      settings_t::e_joiner              +
      settings_t::e_numeric_check       +
      settings_t::e_bracket_check       +
      settings_t::e_sequence_check      +
      settings_t::e_strength_reduction  +
      settings_t::e_disable_usr_on_rsrvd;

   parser_t parser(settings_t(compile_options)
                     .disable_all_base_functions    ()
                     .disable_all_control_structures());

   parser.enable_unknown_symbol_resolver();

   parser.dec().collect_variables() = true;
   parser.dec().collect_functions() = true;

   if (!parser.compile(boolean_expression,expression))
   {
      printf("Error: %s\tExpression: %s\n",
             parser.error().c_str(),
             boolean_expression.c_str());

      for (std::size_t i = 0; i < parser.error_count(); ++i)
      {
         err_t error = parser.get_error(i);

         printf("Error: %02d Position: %02d "
                "Type: [%s] "
                "Message: %s "
                "Expression: %s\n",
                static_cast<int>(i),
                static_cast<int>(error.token.position),
                exprtk::parser_error::to_str(error.mode).c_str(),
                error.diagnostic.c_str(),
                boolean_expression.c_str());

         exprtk::parser_error::update_error(error,boolean_expression);

         printf("Error[%02d] at line: %d column: %d\n",
                static_cast<int>(i),
                static_cast<int>(error.line_no),
                static_cast<int>(error.column_no));
      }

      return;
   }

   typedef typename parser_t::dependent_entity_collector::symbol_t dec_symbol_t;

   std::deque<dec_symbol_t> symbol_list;

   parser.dec().symbols(symbol_list);

   if (symbol_list.empty())
   {
      printf("Error: No variables found to build truth table.\n");
      return;
   }

   for (std::size_t i = 0; i < symbol_list.size(); ++i)
   {
      if (exprtk::details::imatch(symbol_list[i].first,"not"))
      {
         symbol_list.erase(symbol_list.begin() + i);

         if (i >= symbol_list.size())
            break;
      }

      if (parser_t::e_st_function == symbol_list[i].second)
      {
         printf("Error: call to function '%s' not allowed.\n",symbol_list[i].first.c_str());
         return;
      }
   }

   if (symbol_list.size() > 32)
   {
      printf("Error: no more than 32 unique variables allowed.\n");
      return;
   }

   unsigned int upper_bound = 1 << symbol_list.size();

   const int index_width = static_cast<int>(std::ceil(std::log10(upper_bound)));

   // Print truth table header
   printf(" #%s ",std::string(index_width - 1,' ').c_str());

   for (std::size_t i = 0; i < symbol_list.size(); ++i)
   {
      printf("| %s ",symbol_list[i].first.c_str());
   }

   printf("| %s \n",boolean_expression.c_str());

   for (std::size_t i = 0; i < upper_bound; ++i)
   {
      for (std::size_t j = 0; j < symbol_list.size(); ++j)
      {
         symbol_table.get_variable(symbol_list[j].first)->ref() = T((i & (1 << (symbol_list.size() - j - 1))) ? 0 : 1);
      }

      const std::size_t result = static_cast<std::size_t>(expression.value());

      printf(" %*d ", index_width, static_cast<int>(i));

      for (std::size_t j = 0; j < symbol_list.size(); ++j)
      {
         printf("| %d ",static_cast<int>(symbol_table.get_variable(symbol_list[j].first)->value()));
      }

      printf("| %d \n", static_cast<int>(result));
   }
}

// Assembly:
subq $0xe48, %rsp            # imm = 0xE48
movq %rdi, 0xe40(%rsp)
leaq 0xe38(%rsp), %rdi
movl $0x1, %esi
callq 0x119780
leaq 0xe18(%rsp), %rdi
callq 0x1197c0
jmp 0x118920
leaq 0xe18(%rsp), %rdi
leaq 0xe38(%rsp), %rsi
callq 0x119870
jmp 0x118937
leaq 0x390(%rsp), %rdi
movl $0x85f, %esi            # imm = 0x85F
callq 0x119920
jmp 0x11894b
leaq 0x390(%rsp), %rdi
callq 0x119a50
movq %rax, 0x138(%rsp)
jmp 0x118962
movq 0x138(%rsp), %rdi
callq 0x119ad0
movq %rax, 0x130(%rsp)
jmp 0x118979
movq 0x130(%rsp), %rsi
leaq 0x4e0(%rsp), %rdi
callq 0x119b50
jmp 0x118990
leaq 0x390(%rsp), %rdi
callq 0x11a380
xorl %eax, %eax
movl %eax, %esi
leaq 0x4e0(%rsp), %rdi
callq 0x11a3f0
jmp 0x1189b0
leaq 0x4e0(%rsp), %rdi
callq 0x11a440
movq %rax, 0x128(%rsp)
jmp 0x1189c7
movq 0x128(%rsp), %rdi
callq 0x11a460
movq %rax, 0x120(%rsp)
jmp 0x1189de
movq 0x120(%rsp), %rax
movb $0x1, (%rax)
leaq 0x4e0(%rsp), %rdi
callq 0x11a440
movq %rax, 0x118(%rsp)
jmp 0x118a00
movq 0x118(%rsp), %rdi
callq 0x11a470
movq %rax, 0x110(%rsp)
jmp 0x118a17
movq 0x110(%rsp), %rax
movb $0x1, (%rax)
movq 0xe40(%rsp), %rsi
leaq 0x4e0(%rsp), %rdi
leaq 0xe18(%rsp), %rdx
callq 0x11a480
movb %al, 0x10f(%rsp)
jmp 0x118a48
movb 0x10f(%rsp), %al
testb $0x1, %al
jne 0x118d1e
jmp 0x118a59
leaq 0x370(%rsp), %rdi
leaq 0x4e0(%rsp), %rsi
callq 0x11ad10
jmp 0x118a70
leaq 0x370(%rsp), %rdi
callq 0x1110f0
movq %rax, 0x100(%rsp)
movq 0xe40(%rsp), %rdi
callq 0x1110f0
movq 0x100(%rsp), %rsi
movq %rax, %rdx
leaq 0x335aec(%rip), %rdi    # 0x44e590
xorl %eax, %eax
callq 0x111080
jmp 0x118aad
leaq 0x370(%rsp), %rdi
callq 0x1117a8
movq $0x0, 0x368(%rsp)
movq 0x368(%rsp), %rax
movq %rax, 0xf0(%rsp)
leaq 0x4e0(%rsp), %rdi
callq 0x11add0
movq %rax, 0xf8(%rsp)
jmp 0x118aed
movq 0xf0(%rsp), %rax
movq 0xf8(%rsp), %rcx
cmpq %rcx, %rax
jae 0x118d0e
leaq 0x2c0(%rsp), %rdi
leaq 0x4e0(%rsp), %rsi
leaq 0x368(%rsp), %rdx
callq 0x11adf0
jmp 0x118b25
movl 0x368(%rsp), %eax
movl %eax, 0xe8(%rsp)
movl 0x2e8(%rsp), %eax
movl %eax, 0xec(%rsp)
movl 0x2f0(%rsp), %esi
leaq 0x2a0(%rsp), %rdi
callq 0x11aed0
jmp 0x118b57
leaq 0x2a0(%rsp), %rdi
callq 0x1110f0
movq %rax, 0xd8(%rsp)
leaq 0x2f8(%rsp), %rdi
callq 0x1110f0
movq %rax, 0xe0(%rsp)
movq 0xe40(%rsp), %rdi
callq 0x1110f0
movl 0xe8(%rsp), %esi
movl 0xec(%rsp), %edx
movq 0xd8(%rsp), %rcx
movq 0xe0(%rsp), %r8
movq %rax, %r9
leaq 0x3359f4(%rip), %rdi    # 0x44e5aa
xorl %eax, %eax
callq 0x111080
jmp 0x118bbf
leaq 0x2a0(%rsp), %rdi
callq 0x1117a8
movq 0xe40(%rsp), %rsi
leaq 0x2c0(%rsp), %rdi
callq 0x11b210
jmp 0x118be3
movl 0x368(%rsp), %esi
movl 0x358(%rsp), %edx
movl 0x360(%rsp), %ecx
leaq 0x3359ed(%rip), %rdi    # 0x44e5ec
xorl %eax, %eax
callq 0x111080
jmp 0x118c08
leaq 0x2c0(%rsp), %rdi
callq 0x11b3f0
movq 0x368(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x368(%rsp)
jmp 0x118ac6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
jmp 0x1194be
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
jmp 0x1194b1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
leaq 0x390(%rsp), %rdi
callq 0x11a380
jmp 0x1194b1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
jmp 0x1194a4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
leaq 0x370(%rsp), %rdi
callq 0x1117a8
jmp 0x1194a4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
jmp 0x118cfc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
leaq 0x2a0(%rsp), %rdi
callq 0x1117a8
leaq 0x2c0(%rsp), %rdi
callq 0x11b3f0
jmp 0x1194a4
movl $0x1, 0x29c(%rsp)
jmp 0x119468
leaq 0x248(%rsp), %rdi
callq 0x11b440
jmp 0x118d2d
leaq 0x4e0(%rsp), %rdi
callq 0x11a440
movq %rax, 0xd0(%rsp)
jmp 0x118d44
movq 0xd0(%rsp), %rdi
leaq 0x248(%rsp), %rsi
callq 0x11b450
jmp 0x118d5b
leaq 0x248(%rsp), %rdi
callq 0x11b5a0
testb $0x1, %al
jne 0x118d6e
jmp 0x118da7
leaq 0x33589b(%rip), %rdi    # 0x44e610
xorl %eax, %eax
callq 0x111080
jmp 0x118d7e
movl $0x1, 0x29c(%rsp)
jmp 0x11945b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
jmp 0x119497
movq $0x0, 0x240(%rsp)
movq 0x240(%rsp), %rax
movq %rax, 0xc8(%rsp)
leaq 0x248(%rsp), %rdi
callq 0x11b5c0
movq %rax, %rcx
movq 0xc8(%rsp), %rax
cmpq %rcx, %rax
jae 0x118ffc
movq 0x240(%rsp), %rsi
leaq 0x248(%rsp), %rdi
callq 0x11b6b0
movq %rax, 0xb8(%rsp)
leaq 0x21f(%rsp), %rdi
movq %rdi, 0xc0(%rsp)
callq 0x111670
movq 0xc0(%rsp), %rdx
leaq 0x3355b6(%rip), %rsi    # 0x44e3db
leaq 0x220(%rsp), %rdi
callq 0x118830
jmp 0x118e34
movq 0xb8(%rsp), %rdi
leaq 0x220(%rsp), %rsi
callq 0x11b5e0
movb %al, 0xb7(%rsp)
jmp 0x118e52
leaq 0x220(%rsp), %rdi
callq 0x1117a8
leaq 0x21f(%rsp), %rdi
callq 0x111790
movb 0xb7(%rsp), %al
testb $0x1, %al
jne 0x118e7c
jmp 0x118f7f
leaq 0x1b8(%rsp), %rdi
movq %rdi, 0x90(%rsp)
leaq 0x248(%rsp), %rsi
movq %rsi, 0xa0(%rsp)
callq 0x11b790
movq 0x90(%rsp), %rsi
movq 0x240(%rsp), %rdx
leaq 0x1d8(%rsp), %rdi
movq %rdi, 0x98(%rsp)
callq 0x11b740
movq 0x98(%rsp), %rsi
leaq 0x1f8(%rsp), %rdi
movq %rdi, 0xa8(%rsp)
callq 0x11b7c0
movq 0xa0(%rsp), %rsi
movq 0xa8(%rsp), %rdx
leaq 0x198(%rsp), %rdi
callq 0x11b6e0
jmp 0x118f02
movq 0x240(%rsp), %rax
movq %rax, 0x88(%rsp)
leaq 0x248(%rsp), %rdi
callq 0x11b5c0
movq %rax, %rcx
movq 0x88(%rsp), %rax
cmpq %rcx, %rax
jb 0x118f7d
jmp 0x118ffc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
jmp 0x118f6b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
leaq 0x220(%rsp), %rdi
callq 0x1117a8
leaq 0x21f(%rsp), %rdi
callq 0x111790
jmp 0x119497
jmp 0x118f7f
movq 0x240(%rsp), %rsi
leaq 0x248(%rsp), %rdi
callq 0x11b6b0
movq %rax, %rcx
movl $0x5, %eax
cmpl 0x20(%rcx), %eax
jne 0x118fe1
movq 0x240(%rsp), %rsi
leaq 0x248(%rsp), %rdi
callq 0x11b6b0
movq %rax, %rdi
callq 0x1110f0
movq %rax, %rsi
leaq 0x335679(%rip), %rdi    # 0x44e641
xorl %eax, %eax
callq 0x111080
jmp 0x118fd1
movl $0x1, 0x29c(%rsp)
jmp 0x11945b
jmp 0x118fe3
movq 0x240(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x240(%rsp)
jmp 0x118db3
leaq 0x248(%rsp), %rdi
callq 0x11b5c0
cmpq $0x20, %rax
jbe 0x11902f
leaq 0x335656(%rip), %rdi    # 0x44e66c
xorl %eax, %eax
callq 0x111080
jmp 0x11901f
movl $0x1, 0x29c(%rsp)
jmp 0x11945b
leaq 0x248(%rsp), %rdi
callq 0x11b5c0
movb %al, %cl
movl $0x1, %eax
shll %cl, %eax
movl %eax, 0x194(%rsp)
movl 0x194(%rsp), %edi
callq 0x11b810
movsd %xmm0, 0x80(%rsp)
jmp 0x119063
movsd 0x80(%rsp), %xmm0
callq 0x1116d0
cvttsd2si %xmm0, %eax
movl %eax, 0x190(%rsp)
movl 0x190(%rsp), %eax
decl %eax
cltq
movq %rax, 0x70(%rsp)
leaq 0x16f(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x111670
movq 0x70(%rsp), %rsi
movq 0x78(%rsp), %rcx
leaq 0x170(%rsp), %rdi
movl $0x20, %edx
callq 0x11b830
jmp 0x1190bc
leaq 0x170(%rsp), %rdi
callq 0x1110f0
movq %rax, %rsi
leaq 0x3355cb(%rip), %rdi    # 0x44e69e
xorl %eax, %eax
callq 0x111080
jmp 0x1190dc
leaq 0x170(%rsp), %rdi
callq 0x1117a8
leaq 0x16f(%rsp), %rdi
callq 0x111790
movq $0x0, 0x160(%rsp)
movq 0x160(%rsp), %rax
movq %rax, 0x68(%rsp)
leaq 0x248(%rsp), %rdi
callq 0x11b5c0
movq %rax, %rcx
movq 0x68(%rsp), %rax
cmpq %rcx, %rax
jae 0x1191be
movq 0x160(%rsp), %rsi
leaq 0x248(%rsp), %rdi
callq 0x11b6b0
movq %rax, %rdi
callq 0x1110f0
movq %rax, %rsi
leaq 0x335550(%rip), %rdi    # 0x44e6a4
xorl %eax, %eax
callq 0x111080
jmp 0x11915d
jmp 0x11915f
movq 0x160(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x160(%rsp)
jmp 0x119102
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
jmp 0x1191ac
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xe10(%rsp)
movl %eax, 0xe0c(%rsp)
leaq 0x170(%rsp), %rdi
callq 0x1117a8
leaq 0x16f(%rsp), %rdi
callq 0x111790
jmp 0x119497
movq 0xe40(%rsp), %rdi
callq 0x1110f0
movq %rax, %rsi
leaq 0x3354d5(%rip), %rdi    # 0x44e6aa
xorl %eax, %eax
callq 0x111080
jmp 0x1191de
movq $0x0, 0x158(%rsp)
movq 0x158(%rsp), %rax
movl 0x194(%rsp), %ecx
cmpq %rcx, %rax
jae 0x119450
movq $0x0, 0x150(%rsp)
movq 0x150(%rsp), %rax
movq %rax, 0x60(%rsp)
leaq 0x248(%rsp), %rdi
callq 0x11b5c0
movq %rax, %rcx
movq 0x60(%rsp), %rax
cmpq %rcx, %rax
jae 0x119313
movq 0x158(%rsp), %rax
movq %rax, 0x40(%rsp)
leaq 0x248(%rsp), %rdi
movq %rdi, 0x38(%rsp)
callq 0x11b5c0
movq %rax, %rdx
movq 0x40(%rsp), %rax
movq 0x150(%rsp), %rcx
movq %rcx, 0x48(%rsp)
notl %ecx
addl %edx, %ecx
movl $0x1, %edx
shll %cl, %edx
movl %edx, %ecx
movslq %ecx, %rcx
andq %rcx, %rax
testq %rax, %rax
movsd 0x32fd85(%rip), %xmm0   # 0x449010
xorps %xmm1, %xmm1
movsd %xmm1, 0x50(%rsp)
movsd %xmm0, 0x58(%rsp)
je 0x1192a8
movsd 0x50(%rsp), %xmm0
movsd %xmm0, 0x58(%rsp)
movq 0x48(%rsp), %rsi
movq 0x38(%rsp), %rdi
movsd 0x58(%rsp), %xmm0
movsd %xmm0, 0x28(%rsp)
callq 0x11b6b0
movq %rax, %rsi
leaq 0xe38(%rsp), %rdi
callq 0x11b8b0
movq %rax, 0x30(%rsp)
jmp 0x1192da
movq 0x30(%rsp), %rdi
callq 0x11b930
movq %rax, 0x20(%rsp)
jmp 0x1192eb
movq 0x20(%rsp), %rax
movsd 0x28(%rsp), %xmm0
movsd %xmm0, (%rax)
movq 0x150(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x150(%rsp)
jmp 0x11920e
leaq 0xe18(%rsp), %rdi
callq 0x11b940
movsd %xmm0, 0x18(%rsp)
jmp 0x119328
movsd 0x18(%rsp), %xmm0
movsd 0x32fcd2(%rip), %xmm2   # 0x449008
movaps %xmm0, %xmm1
subsd %xmm2, %xmm1
cvttsd2si %xmm1, %rcx
cvttsd2si %xmm0, %rax
movq %rax, %rdx
sarq $0x3f, %rdx
andq %rdx, %rcx
orq %rcx, %rax
movq %rax, 0x148(%rsp)
movl 0x190(%rsp), %esi
movl 0x158(%rsp), %edx
leaq 0x335340(%rip), %rdi    # 0x44e6b1
xorl %eax, %eax
callq 0x111080
jmp 0x11937a
movq $0x0, 0x140(%rsp)
movq 0x140(%rsp), %rax
movq %rax, 0x10(%rsp)
leaq 0x248(%rsp), %rdi
callq 0x11b5c0
movq %rax, %rcx
movq 0x10(%rsp), %rax
cmpq %rcx, %rax
jae 0x11941e
movq 0x140(%rsp), %rsi
leaq 0x248(%rsp), %rdi
callq 0x11b6b0
movq %rax, %rsi
leaq 0xe38(%rsp), %rdi
callq 0x11b8b0
movq %rax, 0x8(%rsp)
jmp 0x1193d9
movq 0x8(%rsp), %rdi
callq 0x11b960
movsd %xmm0, (%rsp)
jmp 0x1193ea
movsd (%rsp), %xmm0
cvttsd2si %xmm0, %esi
leaq 0x3352bd(%rip), %rdi    # 0x44e6b7
xorl %eax, %eax
callq 0x111080
jmp 0x119403
jmp 0x119405
movq 0x140(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x140(%rsp)
jmp 0x119386
movl 0x148(%rsp), %esi
leaq 0x335291(%rip), %rdi    # 0x44e6bd
xorl %eax, %eax
callq 0x111080
jmp 0x119435
jmp 0x119437
movq 0x158(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x158(%rsp)
jmp 0x1191ea
movl $0x0, 0x29c(%rsp)
leaq 0x248(%rsp), %rdi
callq 0x11b980
leaq 0x4e0(%rsp), %rdi
callq 0x11b9f0
leaq 0xe18(%rsp), %rdi
callq 0x11bbf0
leaq 0xe38(%rsp), %rdi
callq 0x11bc30
addq $0xe48, %rsp            # imm = 0xE48
retq
leaq 0x248(%rsp), %rdi
callq 0x11b980
leaq 0x4e0(%rsp), %rdi
callq 0x11b9f0
leaq 0xe18(%rsp), %rdi
callq 0x11bbf0
leaq 0xe38(%rsp), %rdi
callq 0x11bc30
movq 0xe10(%rsp), %rdi
callq 0x111470
nopl (%rax,%rax)