1 # Checking the C++ Features. -*- Autotest -*- 2 3 # Copyright (C) 2004-2005, 2007, 2009-2012 Free Software Foundation, 4 # Inc. 5 6 # This program is free software: you can redistribute it and/or modify 7 # it under the terms of the GNU General Public License as published by 8 # the Free Software Foundation, either version 3 of the License, or 9 # (at your option) any later version. 10 # 11 # This program is distributed in the hope that it will be useful, 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 # GNU General Public License for more details. 15 # 16 # You should have received a copy of the GNU General Public License 17 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19 AT_BANNER([[C++ Features.]]) 20 21 22 ## ----------------------- ## 23 ## Doxygen Documentation. ## 24 ## ----------------------- ## 25 26 m4_define([AT_CHECK_DOXYGEN], 27 [m4_case([$1], 28 [Public], [m4_pushdef([AT_DOXYGEN_PRIVATE], [NO])], 29 [Private], [m4_pushdef([AT_DOXYGEN_PRIVATE], [YES])], 30 [m4_fatal([invalid argument: $1])]) 31 AT_SETUP([Doxygen $1 Documentation]) 32 33 AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) 34 AT_DATA([input.yy], 35 [[%skeleton "lalr1.cc" 36 %locations 37 %debug 38 %defines 39 %% 40 exp:; 41 %% 42 ]AT_YYERROR_DEFINE[ 43 ]]) 44 45 AT_BISON_CHECK([-o input.cc input.yy], 0) 46 47 AT_DATA([Doxyfile], 48 [# The PROJECT_NAME tag is a single word (or a sequence of words 49 # surrounded by quotes) that should identify the project. 50 PROJECT_NAME = "Bison C++ Parser" 51 52 # The QUIET tag can be used to turn on/off the messages that are 53 # generated by doxygen. Possible values are YES and NO. If left blank 54 # NO is used. 55 QUIET = YES 56 57 # The WARNINGS tag can be used to turn on/off the warning messages 58 # that are generated by doxygen. Possible values are YES and NO. If 59 # left blank NO is used. 60 WARNINGS = YES 61 # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate 62 # warnings for undocumented members. If EXTRACT_ALL is set to YES then 63 # this flag will automatically be disabled. 64 WARN_IF_UNDOCUMENTED = YES 65 # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings 66 # for potential errors in the documentation, such as not documenting 67 # some parameters in a documented function, or documenting parameters 68 # that don't exist or using markup commands wrongly. 69 WARN_IF_DOC_ERROR = YES 70 # The WARN_FORMAT tag determines the format of the warning messages 71 # that doxygen can produce. The string should contain the $file, 72 # $line, and $text tags, which will be replaced by the file and line 73 # number from which the warning originated and the warning text. 74 WARN_FORMAT = "$file:$line: $text" 75 76 # If the EXTRACT_ALL tag is set to YES doxygen will assume all 77 # entities in documentation are documented, even if no documentation 78 # was available. Private class members and static file members will 79 # be hidden unless the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set 80 # to YES 81 EXTRACT_ALL = YES 82 83 # If the EXTRACT_PRIVATE tag is set to YES all private members of a 84 # class will be included in the documentation. 85 EXTRACT_PRIVATE = AT_DOXYGEN_PRIVATE 86 87 # If the EXTRACT_STATIC tag is set to YES all static members of a file 88 # will be included in the documentation. 89 EXTRACT_STATIC = AT_DOXYGEN_PRIVATE 90 ]) 91 92 AT_CHECK([doxygen --version || exit 77], 0, ignore) 93 AT_CHECK([doxygen], 0, [], [ignore]) 94 95 AT_BISON_OPTION_POPDEFS 96 AT_CLEANUP 97 98 m4_popdef([AT_DOXYGEN_PRIVATE]) 99 ])# AT_CHECK_DOXYGEN 100 101 AT_CHECK_DOXYGEN([Public]) 102 AT_CHECK_DOXYGEN([Private]) 103 104 ## ------------ ## 105 ## Namespaces. ## 106 ## ------------ ## 107 108 # AT_CHECK_NAMESPACE(NAMESPACE-DECL, [COMPILE-ERROR]) 109 # --------------------------------------------------- 110 # See if Bison can handle %define namespace "NAMESPACE-DECL". If COMPILE-ERROR 111 # is specified, then Bison should accept the input, but compilation will fail, 112 # so don't check compilation. 113 m4_define([AT_CHECK_NAMESPACE], 114 [ 115 116 AT_DATA_GRAMMAR([[input.y]], 117 [[%language "C++" 118 %defines 119 %define namespace "]$1[" 120 %union { int i; } 121 %define global_tokens_and_yystype 122 123 %code { 124 // YYSTYPE contains a namespace reference. 125 int yylex (YYSTYPE *lval) { 126 lval->i = 3; 127 return 0; 128 } 129 } 130 131 %% 132 133 start: ; 134 135 %% 136 137 void 138 ]$1[::parser::error (const ]$1[::parser::location_type &loc, 139 const std::string &msg) 140 { 141 std::cerr << "At " << loc << ": " << msg << std::endl; 142 } 143 144 int 145 main (void) 146 { 147 ]$1[::parser p; 148 return p.parse (); 149 } 150 ]]) 151 152 AT_BISON_CHECK([[-o input.cc input.y]]) 153 154 m4_if([$#], [1], 155 [AT_COMPILE_CXX([[input]], [[input.cc]]) 156 AT_PARSER_CHECK([[./input]])]) 157 158 ]) 159 160 AT_SETUP([[Relative namespace references]]) 161 AT_CHECK_NAMESPACE([[foo]]) 162 AT_CHECK_NAMESPACE([[foo::bar]]) 163 AT_CHECK_NAMESPACE([[foo::bar::baz]]) 164 AT_CLEANUP 165 166 AT_SETUP([[Absolute namespace references]]) 167 AT_CHECK_NAMESPACE([[::foo]]) 168 AT_CHECK_NAMESPACE([[::foo::bar]]) 169 AT_CHECK_NAMESPACE([[::foo::bar::baz]]) 170 AT_CHECK_NAMESPACE([[ ::foo]]) 171 AT_CHECK_NAMESPACE([[ ::foo::bar]]) 172 AT_CHECK_NAMESPACE([[ ::foo::bar::baz]]) 173 AT_CLEANUP 174 175 AT_SETUP([[Syntactically invalid namespace references]]) 176 AT_CHECK_NAMESPACE([[:foo:bar]], [[-]]) 177 AT_CHECK_NAMESPACE([[foo: :bar]], [[-]]) 178 # This one is interesting because `[3]' is encoded as `@<:@3@:>@', which 179 # contains single occurrences of `:'. 180 AT_CHECK_NAMESPACE([[foo[3]::bar::baz]], [[-]]) 181 AT_CHECK_NAMESPACE([[foo::bar,baz]], [[-]]) 182 AT_CHECK_NAMESPACE([[foo::bar::(baz]], [[-]]) 183 AT_CLEANUP 184 185 186 ## ------------------ ## 187 ## Exception safety. ## 188 ## ------------------ ## 189 190 AT_SETUP([[Exception safety]]) 191 192 AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc"]) 193 194 AT_DATA_GRAMMAR([[input.yy]], 195 [[%skeleton "lalr1.cc" 196 %defines // FIXME: Mandated in 2.6. 197 %debug 198 %error-verbose 199 200 %code requires 201 { 202 #include <cassert> 203 #include <cstdlib> // size_t and getenv. 204 #include <iostream> 205 #include <list> 206 207 bool debug = false; 208 209 /// A class that counts its number of instances. 210 struct Object 211 { 212 typedef std::list<const Object*> objects; 213 static objects instances; 214 char val; 215 216 static bool 217 empty () 218 { 219 return instances.empty(); 220 } 221 222 static void 223 log (Object const *o, const std::string& msg) 224 { 225 if (debug) 226 { 227 if (o) 228 std::cerr << o << "->"; 229 std::cerr << msg << " {"; 230 const char* sep = " "; 231 for (objects::const_iterator i = instances.begin(), 232 i_end = instances.end(); 233 i != i_end; 234 ++i) 235 { 236 std::cerr << sep << *i; 237 sep = ", "; 238 } 239 std::cerr << " }" << std::endl; 240 } 241 } 242 243 Object (char v) 244 : val (v) 245 { 246 instances.push_back(this); 247 log (this, "Object::Object"); 248 } 249 250 ~Object () 251 { 252 instances.remove(this); 253 log (this, "Object::~Object"); 254 } 255 }; 256 } 257 258 %code 259 { 260 #include <cassert> 261 #include <cstring> // strchr 262 #include <stdexcept> 263 int yylex (yy::parser::semantic_type *); 264 Object::objects Object::instances; 265 static char const *input; 266 } 267 268 %union 269 { 270 Object *obj; 271 } 272 273 %initial-action 274 { 275 if (strchr (input, 'i')) 276 throw std::runtime_error ("initial-action"); 277 } 278 279 %destructor { delete $$; } <obj>; 280 %printer 281 { 282 yyo << $$ << " '" << $$->val << '\''; 283 if ($$->val == 'p') 284 throw std::runtime_error ("printer"); 285 } <obj>; 286 287 %token <obj> 'a' 'E' 'e' 'p' 'R' 's' 'T' 288 %type <obj> list item 289 290 %% 291 292 start: list { delete $1; }; 293 294 list: 295 item { $$ = $1; } 296 | item list { $$ = $1; delete $2; } // Right recursion to load the stack. 297 ; 298 299 item: 300 'a' { $$ = $1; } 301 | 'e' { YYUSE ($$); YYUSE($1); error (location_type(), "syntax error"); } 302 // Not just 'E', otherwise we reduce when 'E' is the lookahead, and 303 // then the stack is emptied, defeating the point of the test. 304 | 'E' 'a' { YYUSE($1); $$ = $2; } 305 | 'R' { $$ = YY_NULL; delete $1; YYERROR; } 306 | 'p' { $$ = $1; } 307 | 's' { $$ = $1; throw std::runtime_error ("reduction"); } 308 | 'T' { $$ = YY_NULL; delete $1; YYABORT; } 309 | error { $$ = YY_NULL; yyerrok; } 310 ; 311 %% 312 313 int 314 yylex (yy::parser::semantic_type *lvalp) 315 { 316 // 'a': no error. 317 // 'e': user action calls error. 318 // 'E': syntax error, with yyerror that throws. 319 // 'i': initial action throws. 320 // 'l': yylex throws. 321 // 'R': call YYERROR in the action 322 // 's': reduction throws. 323 // 'T': call YYABORT in the action 324 switch (int res = *input++) 325 { 326 case 'l': 327 throw std::runtime_error ("yylex"); 328 default: 329 lvalp->obj = new Object (res); 330 // Fall through. 331 case 0: 332 return res; 333 } 334 } 335 336 /* A C++ error reporting function. */ 337 void 338 yy::parser::error (const location_type& l, const std::string& m) 339 { 340 YYUSE (l); 341 throw std::runtime_error (m); 342 } 343 344 int 345 main (int argc, const char *argv[]) 346 { 347 switch (argc) 348 { 349 case 2: 350 input = argv[1]; 351 break; 352 case 3: 353 assert (!strcmp (argv[1], "--debug")); 354 debug = 1; 355 input = argv[2]; 356 break; 357 default: 358 abort (); 359 } 360 361 yy::parser parser; 362 debug |= !!getenv ("YYDEBUG"); 363 parser.set_debug_level (debug); 364 int res = 2; 365 try 366 { 367 res = parser.parse (); 368 } 369 catch (const std::exception& e) 370 { 371 std::cerr << "exception caught: " << e.what () << std::endl; 372 } 373 catch (...) 374 { 375 std::cerr << "unknown exception caught" << std::endl; 376 } 377 Object::log (YY_NULL, "end"); 378 assert (Object::empty()); 379 return res; 380 } 381 ]]) 382 AT_BISON_CHECK([[-o input.cc --report=all input.yy]]) 383 AT_COMPILE_CXX([[input]]) 384 385 AT_PARSER_CHECK([[./input aaaas]], [[2]], [[]], 386 [[exception caught: reduction 387 ]]) 388 389 AT_PARSER_CHECK([[./input aaaal]], [[2]], [[]], 390 [[exception caught: yylex 391 ]]) 392 393 AT_PARSER_CHECK([[./input i]], [[2]], [[]], 394 [[exception caught: initial-action 395 ]]) 396 397 AT_PARSER_CHECK([[./input aaaap]]) 398 399 AT_PARSER_CHECK([[./input --debug aaaap]], [[2]], [[]], [[stderr]]) 400 AT_CHECK([[grep '^exception caught: printer$' stderr]], [], [ignore]) 401 402 AT_PARSER_CHECK([[./input aaaae]], [[2]], [[]], 403 [[exception caught: syntax error 404 ]]) 405 406 AT_PARSER_CHECK([[./input aaaaE]], [[2]], [[]], 407 [[exception caught: syntax error, unexpected $end, expecting 'a' 408 ]]) 409 410 AT_PARSER_CHECK([[./input aaaaT]], [[1]]) 411 412 # There is error-recovery, so exit success. 413 AT_PARSER_CHECK([[./input aaaaR]], [[0]]) 414 415 AT_BISON_OPTION_POPDEFS 416 417 AT_CLEANUP 418