--- /dev/null
+@ 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
['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:
/* 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':