Fixes to `vvi` related to pushing the most negative number to the stack.
authorAaron Taylor <ataylor@subgeniuskitty.com>
Wed, 31 Jul 2019 21:36:37 +0000 (14:36 -0700)
committerAaron Taylor <ataylor@subgeniuskitty.com>
Wed, 31 Jul 2019 21:36:37 +0000 (14:36 -0700)
tests/6001_push_intmin.pvvs [new file with mode: 0644]
tests/vv_test.py
vv_interpreter.c

diff --git a/tests/6001_push_intmin.pvvs b/tests/6001_push_intmin.pvvs
new file mode 100644 (file)
index 0000000..6452d78
--- /dev/null
@@ -0,0 +1,22 @@
+@ This tests the interpreters ability to push the
+@ most negative number directly to the stack.
+
+@ Construct the number -(2^63) on the stack indirectly.
+SSTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTN  | -((2^63)-1)
+SSSTN                                                                | PUSH 1
+TSST                                                                 | SUBTRACT
+
+@ Now push -(2^63) directly onto the stack.
+SSTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSN | -(2^63)
+
+@ See if the interpreter thinks -((2^63)-1) - 1 == -(2^63)
+@ Print 1 for true and 0 for false.
+TSST   | SUBTRACT
+NTSTN  | BRZ > 1
+SSSSN  | PUSH 0
+TNST   | PUTDIGIT
+NNN    | DIE
+NSSVTN | Mark: 1
+SSSTN  | PUSH 1
+TNST   | PUTDIGIT
+NNN    | DIE
index 9345239..c0853ef 100755 (executable)
@@ -37,6 +37,7 @@ tests = [
         ['5002_io_output_digit', '', '2'],
         ['5003_io_input_character', 'A', 'A'],
         ['5004_io_input_digit', '1', '1'],
+        ['6001_push_intmin', '', '1'],
         ] 
 
 for test in tests:
index 6dde3e8..5ec36eb 100644 (file)
@@ -162,14 +162,26 @@ process_imp_stack(uint8_t * code, size_t * pc, int64_t ** sp)
 
                 /* Now, construct the number and push to TOS. */
                 /* I'm assuming the numbers are read MSb first. */
-                int64_t number = 0;
+                uint64_t number = 0; /* Unsigned to accomodate magnitude of most negative number. */
                 uint8_t temp;
                 while ((temp = next_code_byte(code,pc)) != '\n') {
                     if (temp == '\v') ws_die(pc, "non-binary digit in number");
                     number <<= 1;
                     if (temp == '\t') number++;
                 }
-                stack_push(sp, number*sign);
+                /* Without temporarily casting to something >64-bit, the most negative */
+                /* number will overflow when performing 'number*sign'. Instead, we     */
+                /* pick off the most negative number as a special case.                */
+                if (number == (1ULL << 63) && sign == -1) {
+                    /* C parses negative integer literals first as signed positive */
+                    /* integer literals, then applying a unary negation operator.  */
+                    /* Thus, the most negative value is unreachable directly.      */
+                    int64_t number_temp = -9223372036854775807LL; /* First store -((2^63)-1)  */
+                    number_temp--;                                /* Now turn it into -(2^63) */
+                    stack_push(sp, number_temp);
+                } else {
+                    stack_push(sp, number*sign);
+                }
             }
             break;
         case '\n':