From 6b5e4b38b5fff236dce186ec191390d92d227a47 Mon Sep 17 00:00:00 2001 From: Aaron Taylor Date: Wed, 31 Jul 2019 14:36:37 -0700 Subject: [PATCH] Fixes to `vvi` related to pushing the most negative number to the stack. --- tests/6001_push_intmin.pvvs | 22 ++++++++++++++++++++++ tests/vv_test.py | 1 + vv_interpreter.c | 16 ++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 tests/6001_push_intmin.pvvs diff --git a/tests/6001_push_intmin.pvvs b/tests/6001_push_intmin.pvvs new file mode 100644 index 0000000..6452d78 --- /dev/null +++ b/tests/6001_push_intmin.pvvs @@ -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 diff --git a/tests/vv_test.py b/tests/vv_test.py index 9345239..c0853ef 100755 --- a/tests/vv_test.py +++ b/tests/vv_test.py @@ -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: diff --git a/vv_interpreter.c b/vv_interpreter.c index 6dde3e8..5ec36eb 100644 --- a/vv_interpreter.c +++ b/vv_interpreter.c @@ -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': -- 2.20.1