X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/6e0977873a3d12eeff4f31c85ff8925830c00cf7..22b081deb7ab1d0ec7a279e5213fa7fdc2c85207:/etc/bench.pl.in diff --git a/etc/bench.pl.in b/etc/bench.pl.in index 0679046c..5d83fc7b 100755 --- a/etc/bench.pl.in +++ b/etc/bench.pl.in @@ -1,6 +1,6 @@ #! /usr/bin/perl -w -# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# Copyright (C) 2006, 2008-2012 Free Software Foundation, Inc. # # This file is part of Bison, the GNU Compiler Compiler. # @@ -30,11 +30,15 @@ bench.pl - bench marks for Bison parsers. Specify the set of benches to run. The following grammar defines the I: - I ::= I | I -- Alternation - | I & I -- Concatenation - | [ I ] -- Optional - | ( I ) -- Parentheses - | I + directives ::= + directives | directives -- Alternation + | directives & directives -- Concatenation + | [ directives> ] -- Optional + | ( directives> ) -- Parentheses + | #d NAME[=VALUE] -- %code { #define NAME [VALUE] } + | %d NAME[=VALUE] -- %define NAME ["VALUE"] + | %s skeleton -- %skeleton "skeleton" + | directive Parentheses only group to override precedence. For instance: @@ -53,11 +57,6 @@ request. =over 4 -=item I - -Test F with three stacks against F which -uses a single one. - =item I Test the push parser vs. the pull interface. Use the C parser. @@ -247,7 +246,6 @@ sub generate_grammar_triangular ($$@) or die; print $out < #include @@ -286,8 +284,8 @@ for my $size (1 .. $max) { use Text::Wrap; print $out wrap ("| ", " ", - (map { "\"$_\"" } (1 .. $size)), - " END \n"), + (map { "\"$_\"" } (1 .. $size)), + " END \n"), " { \$\$ = $size; }\n"; }; print $out ";\n"; @@ -319,7 +317,9 @@ yyerror (const char *msg) int main (void) { +#if YYDEBUG yydebug = !!getenv ("YYDEBUG"); +#endif return yyparse (); } EOF @@ -371,8 +371,8 @@ sub generate_grammar_calc ($$@) or die; print $out < #include - #include #include #include @@ -411,7 +411,7 @@ static int yylex (void); %token NUM "number" %type exp -%nonassoc '=' /* comparison */ +%nonassoc '=' /* comparison */ %left '-' '+' %left '*' '/' %left NEG /* negation--unary minus */ @@ -528,9 +528,8 @@ yylex (void) static int power (int base, int exponent) { + assert (0 <= exponent); int res = 1; - if (exponent < 0) - exit (3); for (/* Niente */; exponent; --exponent) res *= base; return res; @@ -544,6 +543,10 @@ main (int argc, const char **argv) int count = 0; int status; +#if YYDEBUG + yydebug = !!getenv ("YYDEBUG"); +#endif + input = fopen ("calc.input", "r"); if (!input) { @@ -576,11 +579,13 @@ sub generate_grammar_list ($$@) my ($base, $max, @directive) = @_; my $directives = directives ($base, @directive); my $variant = grep { /%define "?variant"?/ } @directive; + my $lex_symbol = grep { /%define "?lex_symbol"?/ } @directive; my $out = new IO::File ">$base.y" or die; print $out < #include -// Prototype of the yylex function providing subsequent tokens. -static yy::parser::token_type yylex(yy::parser::semantic_type* yylval); - #define STAGE_MAX ($max * 10) // max = $max +#define USE_LEX_SYMBOL $lex_symbol #define USE_VARIANTS $variant -#if USE_VARIANTS -# define IF_VARIANTS(True, False) True -#else -# define IF_VARIANTS(True, False) False -#endif -#ifdef ONE_STAGE_BUILD -# define IF_ONE_STAGE_BUILD(True, False) True + // Prototype of the yylex function providing subsequent tokens. + static +#if USE_LEX_SYMBOL + yy::parser::symbol_type yylex(); #else -# define IF_ONE_STAGE_BUILD(True, False) False + yy::parser::token_type yylex(yy::parser::semantic_type* yylval, + yy::parser::location_type* yylloc); #endif + + // Conversion to string. + template + inline + std::string + string_cast (const T& t) + { + std::ostringstream o; + o << t; + return o.str (); + } } + +%token END_OF_FILE 0 EOF if ($variant) @@ -621,23 +635,17 @@ EOF %token NUMBER %printer { std::cerr << "Number: " << $$; } %printer { std::cerr << "Text: " << $$; } -%token END_OF_FILE 0 %type text result %% result: - text { /* Throw away the 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()); - } + /* nothing */ { /* This will generate an empty string */ } +| text TEXT { std::swap ($$, $2); } +| text NUMBER { $$ = string_cast($2); } ; EOF } @@ -650,71 +658,86 @@ EOF %token NUMBER %printer { std::cerr << "Number: " << $$; } %printer { std::cerr << "Text: " << *$$; } -%token END_OF_FILE 0 %type text result %% result: - text { delete $1; } + text { delete $1; } ; text: - /* nothing */ { $$ = new std::string; } -| text TEXT { $$->append(*$2); delete $2; } -| text NUMBER { - std::ostringstream ss; - ss << ' ' << $2; - $$->append(ss.str()); - } + /* nothing */ { $$ = new std::string; } +| text TEXT { delete $1; $$ = $2; } +| text NUMBER { delete $1; $$ = new std::string (string_cast ($2)); } ; EOF } print $out <<'EOF'; %% +# + static -yy::parser::token_type -yylex(yy::parser::semantic_type* yylval) +#if USE_LEX_SYMBOL +yy::parser::symbol_type yylex() +#else +yy::parser::token_type yylex(yy::parser::semantic_type* yylval, + yy::parser::location_type* yylloc) +#endif { + typedef yy::parser::location_type location_type; + typedef yy::parser::token token; static int stage = -1; ++stage; if (stage == STAGE_MAX) - return yy::parser::token::END_OF_FILE; + { +#if USE_LEX_SYMBOL + return yy::parser::make_END_OF_FILE (location_type ()); +#else + *yylloc = location_type (); + return token::END_OF_FILE; +#endif + } else if (stage % 2) { -#if USE_VARIANTS -# ifdef ONE_STAGE_BUILD +#if USE_LEX_SYMBOL + return yy::parser::make_NUMBER (stage, location_type ()); +#else +# if defined ONE_STAGE_BUILD yylval->build(stage); -# else +# elif USE_VARIANTS yylval->build() = stage; -# endif -#else +# else yylval->ival = stage; +# endif + *yylloc = location_type (); + return token::NUMBER; #endif - return yy::parser::token::NUMBER; } else { -#if USE_VARIANTS -# ifdef ONE_STAGE_BUILD +#if USE_LEX_SYMBOL + return yy::parser::make_TEXT ("A string.", location_type ()); +#else +# if defined ONE_STAGE_BUILD yylval->build(std::string("A string.")); -# else +# elif USE_VARIANTS yylval->build() = std::string("A string."); -# endif -#else +# else yylval->sval = new std::string("A string."); +# endif + *yylloc = location_type (); + return token::TEXT; #endif - return yy::parser::token::TEXT; } abort(); } // Mandatory error function void -yy::parser::error(const yy::parser::location_type& yylloc, - const std::string& message) +yy::parser::error(const yy::parser::location_type& loc, const std::string& msg) { - std::cerr << yylloc << ": " << message << std::endl; + std::cerr << loc << ": " << msg << std::endl; } int main(int argc, char *argv[]) @@ -869,10 +892,10 @@ interfaces. sub bench_push_parser () { bench ('calc', - ( - '[', '%define api.pure', ']', - '&', - '[', '%define api.push_pull "both"', ']' + qw( + [ %d api.pure ] + & + [ %d api.push-pull=both ] )); } @@ -880,40 +903,21 @@ sub bench_push_parser () =item C -Bench the C++ lalr1.cc parser using Boost.Variants or %union. +Bench the C++ lalr1.cc parser using variants or %union. =cut sub bench_variant_parser () { bench ('list', - ('%skeleton "lalr1.cc"', - '&', - '[', '%debug', ']', - '&', - '[', '%define variant', - '&', - '[', "%code {\n#define VARIANT_DESTROY\n}", ']', - '&', - '[', "%code {\n#define ONE_STAGE_BUILD\n}", ']', - ']' - )); -} - -###################################################################### - -=item C - -Bench the C++ lalr1.cc parser using Boost.Variants or %union. - -=cut - -sub bench_fusion_parser () -{ - bench ('list', - ('%skeleton "lalr1-split.cc"', - '|', - '%skeleton "lalr1.cc"')); + qw( + [ + %d variant + & + [ #d ONE_STAGE_BUILD | %d lex_symbol ] + ] + ) + ); } ############################################################################ @@ -931,29 +935,42 @@ sub help ($) ###################################################################### +# The end of the directives to parse. +my $eod = "end of directives"; # The list of tokens parsed by the following functions. my @token; +# eat ($EXPECTED) +# --------------- +# Check that the current token is $EXPECTED, and move to the next. +sub eat ($) +{ + my ($expected) = @_; + die "expected $expected, unexpected: $token[0] (@token)\n" + unless $token[0] eq $expected; + shift @token; +} + # Parse directive specifications: # expr: term (| term)* # term: fact (& fact)* # fact: ( expr ) | [ expr ] | dirs +# dirs: %s SKELETON | #d NAME[=VALUE] | %d NAME[=VALUE] | directive sub parse (@) { - @token = @_; + @token = (@_, $eod); verbose 3, "Parsing: @token\n"; my @res = parse_expr (); - die "expected end of directives, unexpected: @token" - if defined $token[0]; + eat ($eod); return @res; } sub parse_expr () { my @res = parse_term (); - while (defined $token[0] && $token[0] eq '|') + while ($token[0] eq '|') { - shift @token; + eat ('|'); # Alternation. push @res, parse_term (); } @@ -963,9 +980,9 @@ sub parse_expr () sub parse_term () { my @res = parse_fact (); - while (defined $token[0] && $token[0] eq '&') + while ($token[0] eq '&') { - shift @token; + eat ('&'); # Cartesian product. my @lhs = @res; @res = (); @@ -973,7 +990,7 @@ sub parse_term () { for my $lhs (@lhs) { - push @res, "$lhs\n$rhs"; + push @res, $lhs . ($lhs && $rhs ? "\n" : "") . $rhs; } } } @@ -988,18 +1005,47 @@ sub parse_fact () if ($token[0] eq '(') { - shift @token; + eat ('('); @res = parse_expr (); - die "unexpected $token[0], expected )" - unless $token[0] eq ')'; - shift @token; + eat (')'); } elsif ($token[0] eq '[') { - shift @token; + eat ('['); @res = (parse_expr (), ''); - die "unexpected $token[0], expected ]" - unless $token[0] eq ']'; + eat (']'); + } + else + { + @res = parse_dirs (); + } + return @res; +} + +sub parse_dirs () +{ + my @res; + die "unexpected end of expression" + unless defined $token[0]; + + if ($token[0] eq '#d') + { + eat ('#d'); + $token[0] =~ s/(.*?)=(.*)/$1 $2/; + @res = ("%code {\n#define $token[0]\n}"); + shift @token; + } + elsif ($token[0] eq '%d') + { + shift @token; + $token[0] =~ s/(.*?)=(.*)/$1 "$2"/; + @res = ("%define $token[0]"); + shift @token; + } + elsif ($token[0] eq '%s') + { + shift @token; + @res = ("%skeleton \"$token[0]\""); shift @token; } else @@ -1007,6 +1053,7 @@ sub parse_fact () @res = $token[0]; shift @token; } + return @res; } @@ -1035,14 +1082,17 @@ sub getopt () getopt; # Create the directory we work in. +mkdir "benches" or die "cannot create benches" + unless -d "benches"; my $count = 1; ++$count - while -d "bench-$count"; -my $dir = "bench-$count"; + while -d "benches/$count"; +my $dir = "benches/$count"; mkdir $dir or die "cannot create $dir"; chdir $dir or die "cannot chdir $dir"; + # The following message is tailored to please Emacs' compilation-mode. verbose 1, "Entering directory `$dir'\n"; verbose 1, "Using bison=$bison.\n"; @@ -1055,7 +1105,6 @@ verbose 2, "Grammar: $grammar\n"; # Support -b: predefined benches. my %bench = ( - "fusion" => \&bench_fusion_parser, "push" => \&bench_push_parser, "variant" => \&bench_variant_parser, );