mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 04:13:03 +00:00
Bench the use of Boost.Variants.
* etc/bench.pl.in ($cxx, &variant_grammar, &bench_variant_parser): New. (&compile): Be ready to compile C++ parsers. (&bench_push_parser): Move debug information to the outermost level. * THANKS: Add Michiel De Wilde.
This commit is contained in:
10
ChangeLog
10
ChangeLog
@@ -1,3 +1,13 @@
|
|||||||
|
2008-11-03 Akim Demaille <demaille@gostai.com>
|
||||||
|
|
||||||
|
Bench the use of Boost.Variants.
|
||||||
|
* etc/bench.pl.in ($cxx, &variant_grammar, &bench_variant_parser):
|
||||||
|
New.
|
||||||
|
(&compile): Be ready to compile C++ parsers.
|
||||||
|
(&bench_push_parser): Move debug information to the outermost
|
||||||
|
level.
|
||||||
|
* THANKS: Add Michiel De Wilde.
|
||||||
|
|
||||||
2008-11-03 Akim Demaille <demaille@gostai.com>
|
2008-11-03 Akim Demaille <demaille@gostai.com>
|
||||||
|
|
||||||
bench.pl: Pass directives as a list instead of as a string.
|
bench.pl: Pass directives as a list instead of as a string.
|
||||||
|
|||||||
195
etc/bench.pl.in
195
etc/bench.pl.in
@@ -32,6 +32,7 @@ use Benchmark qw (:all);
|
|||||||
|
|
||||||
my $bison = $ENV{'BISON'} || '@abs_top_builddir@/tests/bison';
|
my $bison = $ENV{'BISON'} || '@abs_top_builddir@/tests/bison';
|
||||||
my $cc = $ENV{'CC'} || 'gcc';
|
my $cc = $ENV{'CC'} || 'gcc';
|
||||||
|
my $cxx = $ENV{'CXX'} || 'g++';
|
||||||
|
|
||||||
##################################################################
|
##################################################################
|
||||||
|
|
||||||
@@ -43,13 +44,21 @@ my $cc = $ENV{'CC'} || 'gcc';
|
|||||||
|
|
||||||
Format the list of directives for Bison for bench named C<$bench>.
|
Format the list of directives for Bison for bench named C<$bench>.
|
||||||
|
|
||||||
|
The special fake C<%variant> directive requests the use of
|
||||||
|
Boost.Variants instead of a regular union. So don't pass it, it is
|
||||||
|
not a valid directive.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub directives($@)
|
sub directives($@)
|
||||||
{
|
{
|
||||||
my ($bench, @directives) = @_;
|
my ($bench, @directives) = @_;
|
||||||
my $res = "/* Directives for bench `$bench'. */\n";
|
my $res = "/* Directives for bench `$bench'. */\n";
|
||||||
$res .= join ("\n", @directives);
|
for my $d (@directives)
|
||||||
|
{
|
||||||
|
$res .= $d . "\n"
|
||||||
|
unless $d eq '%variant';
|
||||||
|
}
|
||||||
$res .= "/* End of directives for bench `$bench'. */\n";
|
$res .= "/* End of directives for bench `$bench'. */\n";
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
@@ -193,9 +202,9 @@ sub calc_input ($$)
|
|||||||
##################################################################
|
##################################################################
|
||||||
=item C<calc_grammar ($base, $max, @directives)>
|
=item C<calc_grammar ($base, $max, @directives)>
|
||||||
|
|
||||||
Generate a Bison file C<$base.y> that for a calculator parser in C.
|
Generate a Bison file C<$base.y> for a calculator parser in C. Pass
|
||||||
Pass the additional Bison C<@directives>. C<$max> is ignored, but
|
the additional Bison C<@directives>. C<$max> is ignored, but left to
|
||||||
left to have the same interface as C<triangular_grammar>.
|
have the same interface as C<triangular_grammar>.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
@@ -401,18 +410,168 @@ EOF
|
|||||||
|
|
||||||
##################################################################
|
##################################################################
|
||||||
|
|
||||||
|
=item C<variant_grammar ($base, $max, @directives)>
|
||||||
|
|
||||||
|
Generate a Bison file C<$base.y> that uses, or not, the Boost.Variants
|
||||||
|
depending on the C<@directives>.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub variant_grammar ($$$)
|
||||||
|
{
|
||||||
|
my ($base, $max, @directives) = @_;
|
||||||
|
my $directives = directives ($base, @directives);
|
||||||
|
my $variant = grep { '%variant' } @directives;
|
||||||
|
|
||||||
|
my $out = new IO::File ">$base.y"
|
||||||
|
or die;
|
||||||
|
print $out <<EOF;
|
||||||
|
%debug
|
||||||
|
%language "C++"
|
||||||
|
%defines
|
||||||
|
|
||||||
|
%code requires // code for the .hh file
|
||||||
|
{
|
||||||
|
#include <string>
|
||||||
|
}
|
||||||
|
|
||||||
|
%code // code for the .cc file
|
||||||
|
{
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
// Prototype of the yylex function providing subsequent tokens.
|
||||||
|
static yy::parser::token_type yylex(yy::parser::semantic_type* yylval);
|
||||||
|
|
||||||
|
#define STAGE_MAX $max
|
||||||
|
#define USE_VARIANTS $variant
|
||||||
|
#if USE_VARIANTS
|
||||||
|
# define IF_VARIANTS(True, False) True
|
||||||
|
#else
|
||||||
|
# define IF_VARIANTS(True, False) False
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if ($variant)
|
||||||
|
{
|
||||||
|
print $out <<'EOF';
|
||||||
|
%code variant {int,std::string}
|
||||||
|
%token <std::string> TEXT
|
||||||
|
%token <int> NUMBER
|
||||||
|
%printer { std::cerr << "Number: " << $$; } <int>
|
||||||
|
%printer { std::cerr << "Text: " << $$; } <std::string>
|
||||||
|
%token END_OF_FILE 0
|
||||||
|
%type <std::string> text result
|
||||||
|
|
||||||
|
%%
|
||||||
|
result:
|
||||||
|
text { /* Throw away the result. */ }
|
||||||
|
;
|
||||||
|
|
||||||
|
text:
|
||||||
|
/* nothing */ { /* This will generate an empty string */ }
|
||||||
|
| text TEXT { std::swap($$,$1); $$.append($2); }
|
||||||
|
| text NUMBER {
|
||||||
|
std::swap($$,$1);
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << ' ' << $2;
|
||||||
|
$$.append(ss.str());
|
||||||
|
}
|
||||||
|
;
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
# Not using Boost variants.
|
||||||
|
print $out <<'EOF';
|
||||||
|
%union {int ival; std::string* sval;}
|
||||||
|
%token <sval> TEXT
|
||||||
|
%token <ival> NUMBER
|
||||||
|
%printer { std::cerr << "Number: " << $$; } <ival>
|
||||||
|
%printer { std::cerr << "Text: " << *$$; } <sval>
|
||||||
|
%token END_OF_FILE 0
|
||||||
|
%type <sval> text result
|
||||||
|
|
||||||
|
%%
|
||||||
|
result:
|
||||||
|
text { delete $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
text:
|
||||||
|
/* nothing */ { $$ = new std::string; }
|
||||||
|
| text TEXT { $$->append(*$2); delete $2; }
|
||||||
|
| text NUMBER {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << ' ' << $2;
|
||||||
|
$$->append(ss.str());
|
||||||
|
}
|
||||||
|
;
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
print $out <<'EOF';
|
||||||
|
%%
|
||||||
|
static
|
||||||
|
yy::parser::token_type
|
||||||
|
yylex(yy::parser::semantic_type* yylval)
|
||||||
|
{
|
||||||
|
static int stage = -1;
|
||||||
|
++stage;
|
||||||
|
if (stage == STAGE_MAX)
|
||||||
|
return yy::parser::token::END_OF_FILE;
|
||||||
|
else if (stage % 2)
|
||||||
|
{
|
||||||
|
IF_VARIANTS(*yylval, yylval->ival) = stage;
|
||||||
|
return yy::parser::token::NUMBER;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IF_VARIANTS(*yylval =, yylval->sval = new) std::string("A string.");
|
||||||
|
return yy::parser::token::TEXT;
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mandatory error function
|
||||||
|
void
|
||||||
|
yy::parser::error(const yy::parser::location_type& yylloc,
|
||||||
|
const std::string& message)
|
||||||
|
{
|
||||||
|
std::cerr << yylloc << ": " << message << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
yy::parser p;
|
||||||
|
p.set_debug_level(!!getenv("YYDEBUG"));
|
||||||
|
p.parse();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
##################################################################
|
||||||
|
|
||||||
=item C<compile ($base)>
|
=item C<compile ($base)>
|
||||||
|
|
||||||
Compile C<$base.y> to an executable C<$base> using the C compiler.
|
Compile C<$base.y> to an executable C, Using the C or C++ compiler
|
||||||
|
depending on the %language specification in C<$base.y>.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub compile ($)
|
sub compile ($)
|
||||||
{
|
{
|
||||||
my ($base) = @_;
|
my ($base) = @_;
|
||||||
|
my $language = `sed -ne '/%language "\\(.*\\)"/{s//\\1/;p;q;}' $base.y`;
|
||||||
|
chomp $language;
|
||||||
|
|
||||||
|
my $compiler = $language eq 'C++' ? $cxx : $cc;
|
||||||
|
|
||||||
system ("$bison $base.y -o $base.c") == 0
|
system ("$bison $base.y -o $base.c") == 0
|
||||||
or die;
|
or die;
|
||||||
system ("$cc -o $base $base.c") == 0
|
system ("$compiler -o $base -O3 -I /opt/local/include $base.c") == 0
|
||||||
or die;
|
or die;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,7 +621,6 @@ interfaces.
|
|||||||
|
|
||||||
sub bench_push_parser ()
|
sub bench_push_parser ()
|
||||||
{
|
{
|
||||||
print STDERR "Using $bison, $cc.\n";
|
|
||||||
calc_input ('calc', 200);
|
calc_input ('calc', 200);
|
||||||
bench_grammar
|
bench_grammar
|
||||||
('calc',
|
('calc',
|
||||||
@@ -475,7 +633,28 @@ sub bench_push_parser ()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_push_parser();
|
=item C<bench_variant_parser ()>
|
||||||
|
|
||||||
|
Bench the C++ lalr1.cc parser using Boost.Variants or %union.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
sub bench_variant_parser ()
|
||||||
|
{
|
||||||
|
bench_grammar
|
||||||
|
('variant',
|
||||||
|
(
|
||||||
|
"union" => [],
|
||||||
|
"variant" => ['%variant'],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
|
||||||
|
print STDERR "Using bison=$bison, cc=$cc, cxx=$cxx.\n";
|
||||||
|
# bench_push_parser();
|
||||||
|
bench_variant_parser();
|
||||||
|
|
||||||
### Setup "GNU" style for perl-mode and cperl-mode.
|
### Setup "GNU" style for perl-mode and cperl-mode.
|
||||||
## Local Variables:
|
## Local Variables:
|
||||||
|
|||||||
Reference in New Issue
Block a user