From a774839ca873d1082f79ba3c4eecc1e242a28ce1 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sun, 7 Mar 2021 08:19:36 +0100 Subject: [PATCH] tables: fix again the handling of useless tokens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The right-shift added in c22902e360e0fbbe9fd5657dcf107e03166da309 ("tables: fix handling for useless tokens") is incorrect. In particular, we need to reset the "new" bits. Reported by Balázs Scheidler. https://github.com/akimd/bison/issues/74 * src/tables.c (pos_set_set): Fix the right-shift. --- NEWS | 6 ++++++ src/tables.c | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 2ce2ad51..9598c0c2 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ GNU Bison NEWS * Noteworthy changes in release ?.? (????-??-??) [?] +** Bug fixes + +*** Fix Table Generation + + In some very rare conditions, when there are many useless tokens, it was + possible to generate incorrect parsers. * Noteworthy changes in release 3.7.5 (2021-01-24) [stable] diff --git a/src/tables.c b/src/tables.c index 6c8fc1cc..23a879ca 100644 --- a/src/tables.c +++ b/src/tables.c @@ -180,21 +180,26 @@ pos_set_set (int pos) int bitno = pos - pos_set_base; if (bitno < 0) { + // Need more room on the left. + // DELTA is positive. Run 'pos_set >> delta'. const int delta = pos_set_base - pos; const int old_size = bitset_size (pos_set); const int new_size = old_size + delta; bitset_resize (pos_set, new_size); - // Shift all the bits by DELTA. + // Right-shift all the bits by DELTA. Be sure to reset the new + // bits on the left. + // // FIXME: add bitset_assign, and bitset_shift? - for (int i = new_size - 1; delta <= i ; --i) - if (bitset_test (pos_set, i)) - bitset_set (pos_set, i + delta); + for (int i = new_size - 1; 0 <= i ; --i) + if (delta <= i && bitset_test (pos_set, i - delta)) + bitset_set (pos_set, i); else - bitset_reset (pos_set, i + delta); + bitset_reset (pos_set, i); pos_set_base = pos; bitno = 0; } else if (bitset_size (pos_set) <= bitno) + // Need more room on the right. bitset_resize (pos_set, bitno + 1); bitset_set (pos_set, bitno); }