yacc: use the most appropriate integral type for state numbers

Currently we properly use the "best" integral type for tables,
including those storing state numbers.  However the variables for
state numbers used in yyparse (and its dependencies such as
yy_stack_print) still use int16_t invariably.  As a consequence, very
large models overflow these variables.

Let's use the "best" type for these variables too.  It turns out that
we can still use 16 bits for twice larger automata: stick to unsigned
types.

However using 'unsigned' when 16 bits are not enough is troublesome
and generates tons of warnings about signedness issues.  Instead,
let's use 'int'.

Reported by Tom Kramer.
https://lists.gnu.org/archive/html/bug-bison/2019-09/msg00018.html

* data/skeletons/yacc.c (b4_state_num_type): New.
(yy_state_num): Be computed from YYNSTATES.
* tests/linear: New.
* tests/torture.at (State number type): New.
Use it.
This commit is contained in:
Akim Demaille
2019-09-28 13:48:35 +02:00
parent 871c02b327
commit 2ca6b71967
5 changed files with 160 additions and 25 deletions

94
tests/linear Executable file
View File

@@ -0,0 +1,94 @@
#! /usr/bin/env ruby
# Build a grammar whose LALR(1) parser has a given number of states.
# Useful to test edge cases (e.g., 256 and 257 states, etc.).
class Linear
def initialize(states)
@states = states - 4
@cols = Math.sqrt(@states).to_i
@lines = @states / @cols
@rest = @states % @cols
@n = @lines * (@cols - 1) + (@rest == 0 ? 1 : @rest == 1 ? 2 : @rest)
end
def nterms
last = @lines + ([0, 1].include?(@rest) ? 0 : 1)
(0...last).map { |i| "t#{i}" }.join(' ')
end
def rules
res = (0...@lines).map { |i| "t#{i}:#{' N' * (@cols - 1)}" }.join("\n")
case @rest
when 0
res += ' N'
when 1
res += ' N N'
else
res += "\nt#{@lines}:#{" N" * @rest}"
end
res
end
def to_s
puts <<~EOF
// states: #{@states}
// cols: #{@cols}
// lines: #{@lines}
// rest: #{@rest}
// n: #{@n}
%code {
#include <stdio.h>
#include <stdlib.h>
static int yylex (void);
static void yyerror (const char *msg);
}
%debug
%define api.value.type union
%define parse.lac full
%define parse.error verbose
%printer { fprintf (yyo, "%ld", $$); } <long>
%token <long> N
%%
exp: #{nterms}
#{rules}
%%
static
int yylex (void)
{
static long count = 0;
if (count++ < #{@n})
{
yylval.N = count;
return N;
}
else
return 0;
}
static
void yyerror (const char *msg)
{
fprintf (stderr, "%s\\n", msg);
}
int
main (void)
{
yydebug = !!getenv ("YYDEBUG");
return yyparse ();
}
EOF
end
end
puts Linear.new(ARGV[0].to_i).to_s