// File: ArashPartow[P]exprtk-extras/exprtk_magic_square.cpp
// Function: void magic_square<double>()
void magic_square()
{
   typedef exprtk::symbol_table<T>         symbol_table_t;
   typedef exprtk::expression<T>           expression_t;
   typedef exprtk::parser<T>               parser_t;
   typedef exprtk::function_compositor<T>  compositor_t;
   typedef typename compositor_t::function function_t;

   const T n = T(15);
   std::vector<T> square(static_cast<std::size_t>(n * n), T(0));

   exprtk::rtl::io::package<T> io_package;

   symbol_table_t symbol_table;
   symbol_table.add_constant("n", n);
   symbol_table.add_vector  ("square", square);
   symbol_table.add_function("print_digit",
                             [](T v) ->T
                             { printf(" %03d ",static_cast<int>(v)); return 0; });
   symbol_table.add_package (io_package);

   compositor_t compositor(symbol_table);

   compositor.load_variables(true);
   compositor.load_vectors  (true);

   compositor.add(
      function_t("get_square")
      .vars("col", "row")
      .expression
      ( " square[row * n + col]; " ));

   compositor.add(
      function_t("set_square")
      .vars("col", "row", "value")
      .expression
      ( " square[row * n + col] := value; " ));

   compositor.add(
      function_t("display_magic_square")
      .expression
      (
         " for (var row := 0; row < n; row += 1)    "
         " {                                        "
         "    for (var col := 0; col < n; col += 1) "
         "    {                                     "
         "       print_digit(get_square(col,row));  "
         "    };                                    "
         "                                          "
         "    println('');                          "
         " }                                        "
      ));

   const std::string magic_square_program =
      " var num := 1;                           "
      " var i   := 0;                           "
      " var j   := floor(n / 2);                "
      "                                         "
      " while (num <= (n * n))                  "
      " {                                       "
      "    set_square(i, j, num);               "
      "    num += 1;                            "
      "                                         "
      "    var i_next := (i - 1 + n) % n;       "
      "    var j_next := (j + 1) % n;           "
      "                                         "
      "    if (get_square(i_next, j_next) != 0) "
      "    {                                    "
      "       i := (i + 1) % n;                 "
      "    }                                    "
      "    else                                 "
      "    {                                    "
      "       i := i_next;                      "
      "       j := j_next;                      "
      "    }                                    "
      " };                                      "
      "                                         "
      " println('sum: ', n * (n^2 + 1) / 2);    "
      "                                         "
      " display_magic_square();                 ";

   expression_t expression;
   expression.register_symbol_table(symbol_table);

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

   expression.value();
}

// Assembly:
subq $0x1a48, %rsp           # imm = 0x1A48
movabsq $0x402e000000000000, %rax # imm = 0x402E000000000000
movq %rax, 0x1a40(%rsp)
movq $0x0, 0x1a20(%rsp)
leaq 0x1a1f(%rsp), %rdi
movq %rdi, 0xa0(%rsp)
callq 0x11c7f0
movq 0xa0(%rsp), %rcx
leaq 0x1a28(%rsp), %rdi
movl $0xe1, %esi
leaq 0x1a20(%rsp), %rdx
callq 0x11c800
jmp 0x11b88e
leaq 0x1a1f(%rsp), %rdi
callq 0x11c880
leaq 0x1938(%rsp), %rdi
callq 0x11c890
jmp 0x11b8aa
leaq 0x1930(%rsp), %rdi
movl $0x1, %esi
callq 0x11c9e0
jmp 0x11b8be
leaq 0x190f(%rsp), %rdi
movq %rdi, 0x98(%rsp)
callq 0x114660
movq 0x98(%rsp), %rdx
leaq 0x349b4e(%rip), %rsi    # 0x465430
leaq 0x1910(%rsp), %rdi
callq 0x11b770
jmp 0x11b8f1
leaq 0x1930(%rsp), %rdi
leaq 0x1910(%rsp), %rsi
leaq 0x1a40(%rsp), %rdx
callq 0x11ca20
jmp 0x11b910
leaq 0x1910(%rsp), %rdi
callq 0x1147a8
leaq 0x190f(%rsp), %rdi
callq 0x114790
leaq 0x18e7(%rsp), %rdi
movq %rdi, 0x90(%rsp)
callq 0x114660
movq 0x90(%rsp), %rdx
leaq 0x349c8a(%rip), %rsi    # 0x4655d8
leaq 0x18e8(%rsp), %rdi
callq 0x11b770
jmp 0x11b95d
leaq 0x1930(%rsp), %rdi
leaq 0x18e8(%rsp), %rsi
leaq 0x1a28(%rsp), %rdx
callq 0x11cb00
jmp 0x11b97c
leaq 0x18e8(%rsp), %rdi
callq 0x1147a8
leaq 0x18e7(%rsp), %rdi
callq 0x114790
leaq 0x18bf(%rsp), %rdi
movq %rdi, 0x88(%rsp)
callq 0x114660
movq 0x88(%rsp), %rdx
leaq 0x349bab(%rip), %rsi    # 0x465565
leaq 0x18c0(%rsp), %rdi
callq 0x11b770
jmp 0x11b9c9
leaq 0x18be(%rsp), %rdi
callq 0x11ccf0
movq %rax, %rdx
leaq 0x1930(%rsp), %rdi
leaq 0x18c0(%rsp), %rsi
callq 0x11cbc0
jmp 0x11b9f0
leaq 0x18c0(%rsp), %rdi
callq 0x1147a8
leaq 0x18bf(%rsp), %rdi
callq 0x114790
leaq 0x1930(%rsp), %rdi
leaq 0x1938(%rsp), %rsi
callq 0x11cd00
jmp 0x11ba21
leaq 0xed0(%rsp), %rdi
leaq 0x1930(%rsp), %rsi
callq 0x11cd30
jmp 0x11ba38
leaq 0xed0(%rsp), %rdi
movl $0x1, %esi
callq 0x11ced0
jmp 0x11ba4c
leaq 0xed0(%rsp), %rdi
movl $0x1, %esi
callq 0x11cf00
jmp 0x11ba60
leaq 0xe1f(%rsp), %rdi
movq %rdi, 0x80(%rsp)
callq 0x114660
movq 0x80(%rsp), %rdx
leaq 0x349aed(%rip), %rsi    # 0x465571
leaq 0xe20(%rsp), %rdi
callq 0x11b770
jmp 0x11ba93
leaq 0xe40(%rsp), %rdi
leaq 0xe20(%rsp), %rsi
callq 0x11cf80
jmp 0x11baaa
leaq 0xdf7(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x114660
movq 0x78(%rsp), %rdx
leaq 0x349ab4(%rip), %rsi    # 0x46557c
leaq 0xdf8(%rsp), %rdi
callq 0x11b770
jmp 0x11bad7
leaq 0xdcf(%rsp), %rdi
movq %rdi, 0x70(%rsp)
callq 0x114660
movq 0x70(%rsp), %rdx
leaq 0x349a8b(%rip), %rsi    # 0x465580
leaq 0xdd0(%rsp), %rdi
callq 0x11b770
jmp 0x11bb04
leaq 0xe40(%rsp), %rdi
leaq 0xdf8(%rsp), %rsi
leaq 0xdd0(%rsp), %rdx
callq 0x11d000
movq %rax, 0x68(%rsp)
jmp 0x11bb28
leaq 0xda7(%rsp), %rdi
movq %rdi, 0x60(%rsp)
callq 0x114660
movq 0x60(%rsp), %rdx
leaq 0x349a3e(%rip), %rsi    # 0x465584
leaq 0xda8(%rsp), %rdi
callq 0x11b770
jmp 0x11bb55
movq 0x68(%rsp), %rdi
leaq 0xda8(%rsp), %rsi
callq 0x11d050
movq %rax, 0x58(%rsp)
jmp 0x11bb6e
movq 0x58(%rsp), %rsi
leaq 0xed0(%rsp), %rdi
xorl %edx, %edx
callq 0x11cf30
jmp 0x11bb84
leaq 0xda8(%rsp), %rdi
callq 0x1147a8
leaq 0xda7(%rsp), %rdi
callq 0x114790
leaq 0xdd0(%rsp), %rdi
callq 0x1147a8
leaq 0xdcf(%rsp), %rdi
callq 0x114790
leaq 0xdf8(%rsp), %rdi
callq 0x1147a8
leaq 0xdf7(%rsp), %rdi
callq 0x114790
leaq 0xe40(%rsp), %rdi
callq 0x11d080
leaq 0xe20(%rsp), %rdi
callq 0x1147a8
leaq 0xe1f(%rsp), %rdi
callq 0x114790
leaq 0xcef(%rsp), %rdi
movq %rdi, 0x50(%rsp)
callq 0x114660
movq 0x50(%rsp), %rdx
leaq 0x349986(%rip), %rsi    # 0x46559d
leaq 0xcf0(%rsp), %rdi
callq 0x11b770
jmp 0x11bc26
leaq 0xd10(%rsp), %rdi
leaq 0xcf0(%rsp), %rsi
callq 0x11cf80
jmp 0x11bc3d
leaq 0xcc7(%rsp), %rdi
movq %rdi, 0x48(%rsp)
callq 0x114660
movq 0x48(%rsp), %rdx
leaq 0x349921(%rip), %rsi    # 0x46557c
leaq 0xcc8(%rsp), %rdi
callq 0x11b770
jmp 0x11bc6a
leaq 0xc9f(%rsp), %rdi
movq %rdi, 0x40(%rsp)
callq 0x114660
movq 0x40(%rsp), %rdx
leaq 0x3498f8(%rip), %rsi    # 0x465580
leaq 0xca0(%rsp), %rdi
callq 0x11b770
jmp 0x11bc97
leaq 0xc77(%rsp), %rdi
movq %rdi, 0x38(%rsp)
callq 0x114660
movq 0x38(%rsp), %rdx
leaq 0x34a0a1(%rip), %rsi    # 0x465d56
leaq 0xc78(%rsp), %rdi
callq 0x11b770
jmp 0x11bcc4
leaq 0xd10(%rsp), %rdi
leaq 0xcc8(%rsp), %rsi
leaq 0xca0(%rsp), %rdx
leaq 0xc78(%rsp), %rcx
callq 0x11d0c0
movq %rax, 0x30(%rsp)
jmp 0x11bcf0
leaq 0xc4f(%rsp), %rdi
movq %rdi, 0x28(%rsp)
callq 0x114660
movq 0x28(%rsp), %rdx
leaq 0x34989a(%rip), %rsi    # 0x4655a8
leaq 0xc50(%rsp), %rdi
callq 0x11b770
jmp 0x11bd1d
movq 0x30(%rsp), %rdi
leaq 0xc50(%rsp), %rsi
callq 0x11d050
movq %rax, 0x20(%rsp)
jmp 0x11bd36
movq 0x20(%rsp), %rsi
leaq 0xed0(%rsp), %rdi
xorl %edx, %edx
callq 0x11cf30
jmp 0x11bd4c
leaq 0xc50(%rsp), %rdi
callq 0x1147a8
leaq 0xc4f(%rsp), %rdi
callq 0x114790
leaq 0xc78(%rsp), %rdi
callq 0x1147a8
leaq 0xc77(%rsp), %rdi
callq 0x114790
leaq 0xca0(%rsp), %rdi
callq 0x1147a8
leaq 0xc9f(%rsp), %rdi
callq 0x114790
leaq 0xcc8(%rsp), %rdi
callq 0x1147a8
leaq 0xcc7(%rsp), %rdi
callq 0x114790
leaq 0xd10(%rsp), %rdi
callq 0x11d080
leaq 0xcf0(%rsp), %rdi
callq 0x1147a8
leaq 0xcef(%rsp), %rdi
callq 0x114790
leaq 0xb97(%rsp), %rdi
movq %rdi, 0x18(%rsp)
callq 0x114660
movq 0x18(%rsp), %rdx
leaq 0x3497d1(%rip), %rsi    # 0x4655ca
leaq 0xb98(%rsp), %rdi
callq 0x11b770
jmp 0x11be08
leaq 0xbb8(%rsp), %rdi
leaq 0xb98(%rsp), %rsi
callq 0x11cf80
jmp 0x11be1f
leaq 0xb6f(%rsp), %rdi
movq %rdi, 0x10(%rsp)
callq 0x114660
movq 0x10(%rsp), %rdx
leaq 0x3497a2(%rip), %rsi    # 0x4655df
leaq 0xb70(%rsp), %rdi
callq 0x11b770
jmp 0x11be4c
leaq 0xbb8(%rsp), %rdi
leaq 0xb70(%rsp), %rsi
callq 0x11d050
movq %rax, 0x8(%rsp)
jmp 0x11be68
movq 0x8(%rsp), %rsi
leaq 0xed0(%rsp), %rdi
xorl %edx, %edx
callq 0x11cf30
jmp 0x11be7e
leaq 0xb70(%rsp), %rdi
callq 0x1147a8
leaq 0xb6f(%rsp), %rdi
callq 0x114790
leaq 0xbb8(%rsp), %rdi
callq 0x11d080
leaq 0xb98(%rsp), %rdi
callq 0x1147a8
leaq 0xb97(%rsp), %rdi
callq 0x114790
leaq 0xb47(%rsp), %rdi
movq %rdi, (%rsp)
callq 0x114660
movq (%rsp), %rdx
leaq 0x34987f(%rip), %rsi    # 0x46575a
leaq 0xb48(%rsp), %rdi
callq 0x11b770
jmp 0x11beea
leaq 0xb47(%rsp), %rdi
callq 0x114790
leaq 0xb20(%rsp), %rdi
callq 0x11d120
jmp 0x11bf06
leaq 0xb20(%rsp), %rdi
leaq 0x1930(%rsp), %rsi
callq 0x11d1d0
jmp 0x11bf1d
leaq 0xa8(%rsp), %rdi
movl $0x7f, %esi
callq 0x11d280
jmp 0x11bf31
leaq 0x1f8(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x11d3b0
jmp 0x11bf48
leaq 0xa8(%rsp), %rdi
callq 0x11dbe0
leaq 0x1f8(%rsp), %rdi
leaq 0xb48(%rsp), %rsi
leaq 0xb20(%rsp), %rdx
callq 0x11dc50
jmp 0x11bf74
leaq 0xb20(%rsp), %rdi
callq 0x11e4e0
jmp 0x11bf83
leaq 0x1f8(%rsp), %rdi
callq 0x11e500
leaq 0xb20(%rsp), %rdi
callq 0x11e700
leaq 0xb48(%rsp), %rdi
callq 0x1147a8
leaq 0xed0(%rsp), %rdi
callq 0x11e740
leaq 0x1930(%rsp), %rdi
callq 0x11e7d0
leaq 0x1938(%rsp), %rdi
callq 0x11e850
leaq 0x1a28(%rsp), %rdi
callq 0x11e880
addq $0x1a48, %rsp           # imm = 0x1A48
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0x1a1f(%rsp), %rdi
callq 0x11c880
jmp 0x11c534
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c527
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c51a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c075
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0x1910(%rsp), %rdi
callq 0x1147a8
leaq 0x190f(%rsp), %rdi
callq 0x114790
jmp 0x11c50d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c0be
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0x18e8(%rsp), %rdi
callq 0x1147a8
leaq 0x18e7(%rsp), %rdi
callq 0x114790
jmp 0x11c50d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c107
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0x18c0(%rsp), %rdi
callq 0x1147a8
leaq 0x18bf(%rsp), %rdi
callq 0x114790
jmp 0x11c50d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c50d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c500
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c254
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c247
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c22d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c213
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c206
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c1f9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0xda8(%rsp), %rdi
callq 0x1147a8
leaq 0xda7(%rsp), %rdi
callq 0x114790
leaq 0xdd0(%rsp), %rdi
callq 0x1147a8
leaq 0xdcf(%rsp), %rdi
callq 0x114790
leaq 0xdf8(%rsp), %rdi
callq 0x1147a8
leaq 0xdf7(%rsp), %rdi
callq 0x114790
leaq 0xe40(%rsp), %rdi
callq 0x11d080
leaq 0xe20(%rsp), %rdi
callq 0x1147a8
leaq 0xe1f(%rsp), %rdi
callq 0x114790
jmp 0x11c500
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c3a2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c395
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c37b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c361
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c347
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c33a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c32d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0xc50(%rsp), %rdi
callq 0x1147a8
leaq 0xc4f(%rsp), %rdi
callq 0x114790
leaq 0xc78(%rsp), %rdi
callq 0x1147a8
leaq 0xc77(%rsp), %rdi
callq 0x114790
leaq 0xca0(%rsp), %rdi
callq 0x1147a8
leaq 0xc9f(%rsp), %rdi
callq 0x114790
leaq 0xcc8(%rsp), %rdi
callq 0x1147a8
leaq 0xcc7(%rsp), %rdi
callq 0x114790
leaq 0xd10(%rsp), %rdi
callq 0x11d080
leaq 0xcf0(%rsp), %rdi
callq 0x1147a8
leaq 0xcef(%rsp), %rdi
callq 0x114790
jmp 0x11c500
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c43e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c431
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c417
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0xb70(%rsp), %rdi
callq 0x1147a8
leaq 0xb6f(%rsp), %rdi
callq 0x114790
leaq 0xbb8(%rsp), %rdi
callq 0x11d080
leaq 0xb98(%rsp), %rdi
callq 0x1147a8
leaq 0xb97(%rsp), %rdi
callq 0x114790
jmp 0x11c500
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0xb47(%rsp), %rdi
callq 0x114790
jmp 0x11c500
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c4f3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
jmp 0x11c4e6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0xa8(%rsp), %rdi
callq 0x11dbe0
jmp 0x11c4e6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x1a10(%rsp)
movl %eax, 0x1a0c(%rsp)
leaq 0x1f8(%rsp), %rdi
callq 0x11e500
leaq 0xb20(%rsp), %rdi
callq 0x11e700
leaq 0xb48(%rsp), %rdi
callq 0x1147a8
leaq 0xed0(%rsp), %rdi
callq 0x11e740
leaq 0x1930(%rsp), %rdi
callq 0x11e7d0
leaq 0x1938(%rsp), %rdi
callq 0x11e850
leaq 0x1a28(%rsp), %rdi
callq 0x11e880
movq 0x1a10(%rsp), %rdi
callq 0x114450
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)