blob: 18a4f90a2bac7247f41157790d63e4b49a3b7926 [file] [log] [blame]
#! /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.).
# Copyright (C) 2020-2021 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Written by Akim Demaille.
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