X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/595284e9d0277517bac8f3fc7bcdd529d97aa6f9..f6df83b4e80b2a53c08b5dc654e247076a3b9b03:/tests/c%20%20.at/bison.git/blobdiff_plain/595284e9d0277517bac8f3fc7bcdd529d97aa6f9..f6df83b4e80b2a53c08b5dc654e247076a3b9b03:/tests/c++.at diff --git a/tests/c++.at b/tests/c++.at index 288ff865..a5d41a98 100644 --- a/tests/c++.at +++ b/tests/c++.at @@ -1,4 +1,4 @@ -# Checking the output filenames. -*- Autotest -*- +# Checking the C++ Features. -*- Autotest -*- # Copyright (C) 2004-2005, 2007-2012 Free Software Foundation, Inc. @@ -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. @@ -118,68 +119,51 @@ item: ; %% -#define STAGE_MAX 5 -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 -{ -#ifndef USE_LEX_SYMBOL - typedef yy::parser::token token; -#endif - 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 ()); +#ifdef TWO_STAGE_BUILD +# define BUILD(Type, Value) build () = Value #else -# if defined ONE_STAGE_BUILD - yylval->build (stage); -# else - yylval->build() = stage; -# endif - *yylloc = location_type (); - return token::NUMBER; +# define BUILD(Type, Value) build (Value) #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 () { @@ -190,19 +174,24 @@ main () ]]) 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]) ## ----------------------- ## @@ -216,6 +205,7 @@ m4_define([AT_CHECK_DOXYGEN], [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 @@ -224,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) @@ -280,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]) @@ -468,7 +456,7 @@ AT_DATA_GRAMMAR([[input.yy]], } %defines -%define variant +%define api.value.type variant %define parse.error verbose %define parse.trace %% @@ -531,3 +519,279 @@ 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