X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/575619af5e1f61a5f78fb3910bee424ead5fe5a6..f6df83b4e80b2a53c08b5dc654e247076a3b9b03:/tests/c%20%20.at/bison.git/blobdiff_plain/575619af5e1f61a5f78fb3910bee424ead5fe5a6..f6df83b4e80b2a53c08b5dc654e247076a3b9b03:/tests/c++.at diff --git a/tests/c++.at b/tests/c++.at index c2b9e462..a5d41a98 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -1,6 +1,6 @@ -# Checking the output filenames. -*- Autotest -*- +# Checking the C++ Features. -*- Autotest -*- -# Copyright (C) 2004-2005, 2007-2011 Free Software Foundation, Inc. +# Copyright (C) 2004-2005, 2007-2012 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 @@ -22,19 +22,19 @@ AT_BANNER([[C++ Features.]]) ## Variants. ## ## ---------- ## -# AT_CHECK_VARIANTS([DIRECTIVES]) -# ------------------------------- +# AT_TEST([DIRECTIVES]) +# --------------------- # Check the support of variants in C++, with the additional DIRECTIVES. -m4_define([AT_CHECK_VARIANTS], +m4_pushdef([AT_TEST], [AT_SETUP([Variants $1]) +AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc" $1]) # Store strings and integers in a list of strings. AT_DATA_GRAMMAR([list.yy], [[%debug %skeleton "lalr1.cc" %defines -%define variant -%locations +%define api.value.type variant ]m4_bpatsubst([$1], [\\n], [ ])[ @@ -47,16 +47,17 @@ typedef std::list strings_type; %code // code for the .cc file { +#include // abort, getenv #include #include - static -#if defined 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 + namespace yy + { + static]AT_TOKEN_CTOR_IF([[ + parser::symbol_type yylex ()]], [[ + parser::token_type yylex (parser::semantic_type* yylval]AT_LOCATION_IF([, + parser::location_type* yylloc])[)]])[; + } // Printing a list of strings (for %printer). // Koening look up will look into std, since that's an std::list. @@ -66,7 +67,7 @@ typedef std::list strings_type; operator<<(std::ostream& o, const strings_type& s) { o << '('; - for (strings_type::const_iterator i = s.begin(); i != s.end (); ++i) + for (strings_type::const_iterator i = s.begin (); i != s.end (); ++i) { if (i != s.begin ()) o << ", "; @@ -84,7 +85,7 @@ typedef std::list strings_type; { std::ostringstream o; o << t; - return o.str(); + return o.str (); } } @@ -98,8 +99,8 @@ typedef std::list strings_type; // digraph for the left square bracket. %type <::std::list> list result; -%printer { debug_stream() << $][$; } - <::std::string> <::std::list<::std::string>>; +%printer { yyo << $][$; } + <::std::string> <::std::list>; %% result: @@ -108,99 +109,89 @@ result: list: /* nothing */ { /* Generates an empty string list */ } -| list item { std::swap($][$,$][1); $$.push_back($][2); } -| list error { std::swap($][$,$][1); } +| list item { std::swap ($][$,$][1); $$.push_back ($][2); } +| list error { std::swap ($][$,$][1); } ; item: - TEXT { std::swap($][$,$][1); } -| NUMBER { if ($][1 == 3) YYERROR; else $][$ = string_cast($][1); } + TEXT { std::swap ($][$,$][1); } +| NUMBER { if ($][1 == 3) YYERROR; else $][$ = string_cast ($][1); } ; %% -#define STAGE_MAX 5 -static -#if defined USE_LEX_SYMBOL -yy::parser::symbol_type yylex() +#ifdef TWO_STAGE_BUILD +# define BUILD(Type, Value) build () = Value #else -yy::parser::token_type yylex(yy::parser::semantic_type* yylval, - yy::parser::location_type* yylloc) +# define BUILD(Type, Value) build (Value) #endif -{ - typedef yy::parser::token token; - typedef yy::parser::location_type location_type; - static int stage = -1; - ++stage; - if (stage == STAGE_MAX) - { -#if defined 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 defined USE_LEX_SYMBOL - return yy::parser::make_NUMBER (stage, location_type ()); -#else -# if defined ONE_STAGE_BUILD - yylval->build(stage); -# else - yylval->build() = stage; -# endif - *yylloc = location_type (); - return token::NUMBER; -#endif - } - else - { -#if defined USE_LEX_SYMBOL - return yy::parser::make_TEXT (string_cast (stage), location_type ()); -#else -# if defined ONE_STAGE_BUILD - yylval->build (string_cast (stage)); -# else - yylval->build() = string_cast (stage); -# endif - *yylloc = location_type (); - return token::TEXT; -#endif - } - abort(); -} -void -yy::parser::error(const yy::parser::location_type&, - const std::string& message) +#define STAGE_MAX 5 +namespace yy { - std::cerr << message << std::endl; + static]AT_TOKEN_CTOR_IF([[ + parser::symbol_type yylex ()]], [[ + parser::token_type yylex (parser::semantic_type* yylval]AT_LOCATION_IF([, + parser::location_type* yylloc])[)]])[ + {]AT_LOCATION_IF([ + typedef parser::location_type location;])[ + static int stage = -1; + ++stage; + if (stage == STAGE_MAX) + {]AT_TOKEN_CTOR_IF([[ + return parser::make_END_OF_FILE (]AT_LOCATION_IF([location ()])[);]], +[AT_LOCATION_IF([ + *yylloc = location ();])[ + return parser::token::END_OF_FILE;]])[ + } + else if (stage % 2) + {]AT_TOKEN_CTOR_IF([[ + return parser::make_NUMBER (stage]AT_LOCATION_IF([, location ()])[);]], +[[ + yylval->BUILD (int, stage);]AT_LOCATION_IF([ + *yylloc = location ();])[ + return parser::token::NUMBER;]])[ + } + else + {]AT_TOKEN_CTOR_IF([[ + return parser::make_TEXT (string_cast (stage)]AT_LOCATION_IF([, location ()])[);]], [[ + yylval->BUILD (std::string, string_cast (stage));]AT_LOCATION_IF([ + *yylloc = location ();])[ + return parser::token::TEXT;]])[ + } + abort (); + } } +]AT_YYERROR_DEFINE[ + int -main (void) +main () { yy::parser p; - p.set_debug_level(!!getenv("YYDEBUG")); - return p.parse(); + p.set_debug_level (!!getenv ("YYDEBUG")); + return p.parse (); } ]]) AT_BISON_CHECK([-o list.cc list.yy]) -AT_COMPILE_CXX([list]) -AT_CHECK([./list], 0, - [(0, 1, 2, 4) +AT_COMPILE_CXX([list], [$NO_STRICT_ALIAS_CXXFLAGS list.cc]) +AT_PARSER_CHECK([./list], 0, +[(0, 1, 2, 4) ]) +AT_BISON_OPTION_POPDEFS AT_CLEANUP ]) -AT_CHECK_VARIANTS([]) -AT_CHECK_VARIANTS([%define parse.assert]) -AT_CHECK_VARIANTS([[%define parse.assert %code {\n#define ONE_STAGE_BUILD\n}]]) -AT_CHECK_VARIANTS([[%define parse.assert %define lex_symbol %code {\n#define USE_LEX_SYMBOL\n}]]) -AT_CHECK_VARIANTS([[%define parse.assert %define lex_symbol %code {\n#define USE_LEX_SYMBOL\n} %define api.tokens.prefix "TOK_"]]) +AT_TEST([]) +AT_TEST([%define parse.assert]) +AT_TEST([%locations %define parse.assert]) +AT_TEST([[%define parse.assert %code {\n#define TWO_STAGE_BUILD\n}]]) +AT_TEST([[%define parse.assert %define api.token.constructor]]) +AT_TEST([[%define parse.assert %define api.token.constructor %define api.token.prefix "TOK_"]]) +AT_TEST([[%locations %define parse.assert %define api.token.constructor %define api.token.prefix "TOK_"]]) + +m4_popdef([AT_TEST]) ## ----------------------- ## @@ -211,9 +202,10 @@ m4_define([AT_CHECK_DOXYGEN], [m4_case([$1], [Public], [m4_pushdef([AT_DOXYGEN_PRIVATE], [NO])], [Private], [m4_pushdef([AT_DOXYGEN_PRIVATE], [YES])], - [m4_fatal([invalid argument: $1])]) + [m4_fatal([invalid argument: $1])]) AT_SETUP([Doxygen $1 Documentation]) +AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) AT_DATA([input.yy], [[%skeleton "lalr1.cc" %locations @@ -222,10 +214,7 @@ AT_DATA([input.yy], %% exp:; %% -yy::parser::error (const location& l, const std::string& m) -{ - std::cerr << l << s << std::endl; -} +]AT_YYERROR_DEFINE[ ]]) AT_BISON_CHECK([-o input.cc input.yy], 0) @@ -278,6 +267,7 @@ EXTRACT_STATIC = AT_DOXYGEN_PRIVATE AT_CHECK([doxygen --version || exit 77], 0, ignore) AT_CHECK([doxygen], 0, [], [ignore]) +AT_BISON_OPTION_POPDEFS AT_CLEANUP m4_popdef([AT_DOXYGEN_PRIVATE]) @@ -329,7 +319,7 @@ void } int -main (void) +main () { ]$1[::parser p; return p.parse (); @@ -385,12 +375,11 @@ AT_DATA_GRAMMAR([[input.yy]], %code { #include - int yylex (yy::parser::semantic_type *, yy::location *); + int yylex (yy::parser::semantic_type *); #define USE(Args) } %defines -%locations %define parse.error verbose %nonassoc 'a' ; @@ -420,20 +409,20 @@ start: 'b' consistent-error ; %% int -yylex (yy::parser::semantic_type *, yy::location *) +yylex (yy::parser::semantic_type *) { static char const *input = "aa"; return *input++; } void -yy::parser::error (const location_type &, const std::string &m) +yy::parser::error (const std::string &m) { std::cerr << m << std::endl; } int -main (void) +main () { yy::parser parser; return parser.parse (); @@ -449,3 +438,360 @@ Reducing 'a'. ]]) AT_CLEANUP + + +## --------------------------- ## +## Syntax error as exception. ## +## --------------------------- ## + +AT_SETUP([[Syntax error as exception]]) + +AT_DATA_GRAMMAR([[input.yy]], +[[%skeleton "lalr1.cc" + +%code +{ + #include + int yylex (yy::parser::semantic_type *); +} + +%defines +%define api.value.type variant +%define parse.error verbose +%define parse.trace +%% + +start: + thing +| start thing +; + +thing: + error { std::cerr << "caught error" << std::endl; } +| item +; + +item: + 'a' +| 's' + { + throw yy::parser::syntax_error ("invalid expression"); + } + +%% + +int +yylex (yy::parser::semantic_type *) +{ + // 's': syntax error, 'l': lexical error. + static char const *input = "asal"; + switch (int res = *input++) + { + case 'l': + throw yy::parser::syntax_error ("invalid character"); + default: + return res; + } +} + +void +yy::parser::error (const std::string &m) +{ + std::cerr << "error: " << m << std::endl; +} + +int +main () +{ + yy::parser parser; + parser.set_debug_level (!!getenv ("YYDEBUG")); + return parser.parse (); +} +]]) +AT_BISON_CHECK([[-o input.cc input.yy]]) +AT_COMPILE_CXX([[input]]) + +AT_PARSER_CHECK([[./input]], [[0]], [[]], +[[error: invalid expression +caught error +error: invalid character +caught error +]]) + +AT_CLEANUP + + +## ------------------ ## +## Exception safety. ## +## ------------------ ## + +AT_SETUP([[Exception safety]]) + +AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) + +AT_DATA_GRAMMAR([[input.yy]], +[[%skeleton "lalr1.cc" +%defines // FIXME: Mandated in 2.6. +%debug +%error-verbose + +%code requires +{ + #include + #include // size_t and getenv. + #include + #include + + bool debug = false; + + /// A class that counts its number of instances. + struct Object + { + typedef std::list objects; + static objects instances; + char val; + + static bool + empty () + { + return instances.empty(); + } + + static void + log (Object const *o, const std::string& msg) + { + if (debug) + { + if (o) + std::cerr << o << "->"; + std::cerr << msg << " {"; + const char* sep = " "; + for (objects::const_iterator i = instances.begin(), + i_end = instances.end(); + i != i_end; + ++i) + { + std::cerr << sep << *i; + sep = ", "; + } + std::cerr << " }" << std::endl; + } + } + + Object (char v) + : val (v) + { + instances.push_back(this); + log (this, "Object::Object"); + } + + ~Object () + { + instances.remove(this); + log (this, "Object::~Object"); + } + }; +} + +%code +{ + #include + #include // strchr + #include + int yylex (yy::parser::semantic_type *); + Object::objects Object::instances; + static char const *input; +} + +%union +{ + Object *obj; +} + +%initial-action +{ + if (strchr (input, 'i')) + throw std::runtime_error ("initial-action"); +} + +%destructor { delete $$; } ; +%printer +{ + yyo << $$ << " '" << $$->val << '\''; + if ($$->val == 'p') + throw std::runtime_error ("printer"); +} ; + +%token 'a' 'E' 'e' 'p' 'R' 's' 'T' +%type list item + +%% + +start: list { delete $1; }; + +list: + item { $$ = $1; } +| item list { $$ = $1; delete $2; } // Right recursion to load the stack. +; + +item: + 'a' { $$ = $1; } +| 'e' { YYUSE ($$); YYUSE($1); error ("syntax error"); } +// Not just 'E', otherwise we reduce when 'E' is the lookahead, and +// then the stack is emptied, defeating the point of the test. +| 'E' 'a' { YYUSE($1); $$ = $2; } +| 'R' { $$ = YY_NULL; delete $1; YYERROR; } +| 'p' { $$ = $1; } +| 's' { $$ = $1; throw std::runtime_error ("reduction"); } +| 'T' { $$ = YY_NULL; delete $1; YYABORT; } +| error { $$ = YY_NULL; yyerrok; } +; +%% + +int +yylex (yy::parser::semantic_type *lvalp) +{ + // 'a': no error. + // 'e': user action calls error. + // 'E': syntax error, with yyerror that throws. + // 'i': initial action throws. + // 'l': yylex throws. + // 'R': call YYERROR in the action + // 's': reduction throws. + // 'T': call YYABORT in the action + switch (int res = *input++) + { + case 'l': + throw std::runtime_error ("yylex"); + default: + lvalp->obj = new Object (res); + // Fall through. + case 0: + return res; + } +} + +/* A C++ error reporting function. */ +void +yy::parser::error (const std::string& m) +{ + throw std::runtime_error (m); +} + +int +main (int argc, const char *argv[]) +{ + switch (argc) + { + case 2: + input = argv[1]; + break; + case 3: + assert (std::string(argv[1]) == "--debug"); + debug = 1; + input = argv[2]; + break; + default: + abort (); + } + + yy::parser parser; + debug |= !!getenv ("YYDEBUG"); + parser.set_debug_level (debug); + int res = 2; + try + { + res = parser.parse (); + } + catch (const std::exception& e) + { + std::cerr << "exception caught: " << e.what () << std::endl; + } + catch (...) + { + std::cerr << "unknown exception caught" << std::endl; + } + Object::log (YY_NULL, "end"); + assert (Object::empty()); + return res; +} +]]) +AT_BISON_CHECK([[-o input.cc --report=all input.yy]]) +AT_COMPILE_CXX([[input]]) + +AT_PARSER_CHECK([[./input aaaas]], [[2]], [[]], +[[exception caught: reduction +]]) + +AT_PARSER_CHECK([[./input aaaal]], [[2]], [[]], +[[exception caught: yylex +]]) + +AT_PARSER_CHECK([[./input i]], [[2]], [[]], +[[exception caught: initial-action +]]) + +AT_PARSER_CHECK([[./input aaaap]]) + +AT_PARSER_CHECK([[./input --debug aaaap]], [[2]], [[]], [[stderr]]) +AT_CHECK([[grep '^exception caught: printer$' stderr]], [], [ignore]) + +AT_PARSER_CHECK([[./input aaaae]], [[2]], [[]], +[[exception caught: syntax error +]]) + +AT_PARSER_CHECK([[./input aaaaE]], [[2]], [[]], +[[exception caught: syntax error, unexpected $end, expecting 'a' +]]) + +AT_PARSER_CHECK([[./input aaaaT]], [[1]]) + +# There is error-recovery, so exit success. +AT_PARSER_CHECK([[./input aaaaR]], [[0]]) + +AT_BISON_OPTION_POPDEFS + +AT_CLEANUP + +## ------------------------------------ ## +## C++ GLR parser identifier shadowing ## +## ------------------------------------ ## + +AT_SETUP([[C++ GLR parser identifier shadowing]]) + +AT_DATA_GRAMMAR([input.yy], [ +%skeleton "glr.cc" + +%union +{ + int ival; +} + +%token ZERO; + +%code +{ + int yylex (yy::parser::semantic_type *yylval); +} + +%% +exp: ZERO + +%% + +int yylex (yy::parser::semantic_type *yylval) +{ + return yy::parser::token::ZERO; +} + +void yy::parser::error (std::string const& msg) +{} + +int main() +{} +]) + +AT_BISON_CHECK([[-o input.cc input.yy]]) +AT_COMPILE_CXX([[input]]) + +AT_CLEANUP