OLD | NEW |
(Empty) | |
| 1 # Checking GLR Parsing. -*- Autotest -*- |
| 2 # Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software |
| 3 # Foundation, Inc. |
| 4 |
| 5 # This program is free software: you can redistribute it and/or modify |
| 6 # it under the terms of the GNU General Public License as published by |
| 7 # the Free Software Foundation, either version 3 of the License, or |
| 8 # (at your option) any later version. |
| 9 # |
| 10 # This program is distributed in the hope that it will be useful, |
| 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 # GNU General Public License for more details. |
| 14 # |
| 15 # You should have received a copy of the GNU General Public License |
| 16 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 |
| 18 AT_BANNER([[C++ Type Syntax (GLR).]]) |
| 19 |
| 20 # _AT_TEST_GLR_CXXTYPES(DECL, RESOLVE1, RESOLVE2) |
| 21 # ----------------------------------------------- |
| 22 # Store into types.y the calc program, with DECL inserted as a declaration, |
| 23 # and with RESOLVE1 and RESOLVE2 as annotations on the conflicted rule for |
| 24 # stmt. Then compile the result. |
| 25 m4_define([_AT_TEST_GLR_CXXTYPES], |
| 26 [ |
| 27 AT_BISON_OPTION_PUSHDEFS([$1]) |
| 28 |
| 29 AT_DATA_GRAMMAR([types.y], |
| 30 [[/* Simplified C++ Type and Expression Grammar. */ |
| 31 |
| 32 $1 |
| 33 |
| 34 %{ |
| 35 #include <stdio.h> |
| 36 union Node { |
| 37 struct { |
| 38 int isNterm; |
| 39 int parents; |
| 40 } nodeInfo; |
| 41 struct { |
| 42 int isNterm; /* 1 */ |
| 43 int parents; |
| 44 char const *form; |
| 45 union Node *children[3]; |
| 46 } nterm; |
| 47 struct { |
| 48 int isNterm; /* 0 */ |
| 49 int parents; |
| 50 char *text; |
| 51 } term; |
| 52 }; |
| 53 typedef union Node Node; |
| 54 static Node *new_nterm (char const *, Node *, Node *, Node *); |
| 55 static Node *new_term (char *); |
| 56 static void free_node (Node *); |
| 57 static char *node_to_string (Node *); |
| 58 #define YYSTYPE Node * |
| 59 ]m4_bmatch([$2], [stmtMerge], |
| 60 [ static YYSTYPE stmtMerge (YYSTYPE x0, YYSTYPE x1);])[ |
| 61 #define YYINITDEPTH 10 |
| 62 #define YYSTACKEXPANDABLE 1 |
| 63 struct YYLTYPE; |
| 64 #if YYPURE |
| 65 # if YYLSP_NEEDED |
| 66 # define LEX_PARAMETERS YYSTYPE *lvalp, struct YYLTYPE *llocp |
| 67 # define ERROR_PARAMETERS struct YYLTYPE *llocp, char const *s |
| 68 # else |
| 69 # define LEX_PARAMETERS YYSTYPE *lvalp |
| 70 # endif |
| 71 #endif |
| 72 #ifndef LEX_PARAMETERS |
| 73 # define LEX_PARAMETERS void |
| 74 #endif |
| 75 #ifndef ERROR_PARAMETERS |
| 76 # define ERROR_PARAMETERS char const *s |
| 77 #endif |
| 78 int yylex (LEX_PARAMETERS); |
| 79 void yyerror (ERROR_PARAMETERS); |
| 80 %} |
| 81 |
| 82 %token TYPENAME ID |
| 83 |
| 84 %right '=' |
| 85 %left '+' |
| 86 |
| 87 %glr-parser |
| 88 |
| 89 %destructor { free_node ($$); } stmt expr decl declarator TYPENAME ID |
| 90 |
| 91 %% |
| 92 |
| 93 prog : |
| 94 | prog stmt { |
| 95 char *output;]AT_LOCATION_IF([ |
| 96 printf ("%d.%d-%d.%d: ", |
| 97 @2.first_line, @2.first_column, |
| 98 @2.last_line, @2.last_column);])[ |
| 99 output = node_to_string (]$[2); |
| 100 printf ("%s\n", output); |
| 101 free (output); |
| 102 free_node (]$[2); |
| 103 } |
| 104 ; |
| 105 |
| 106 stmt : expr ';' $2 { $$ = ]$[1; } |
| 107 | decl $3 |
| 108 | error ';' { $$ = new_nterm ("<error>", 0, 0, 0); } |
| 109 | '@' { YYACCEPT; } |
| 110 ; |
| 111 |
| 112 expr : ID |
| 113 | TYPENAME '(' expr ')' |
| 114 { $$ = new_nterm ("<cast>(%s,%s)", ]$[3, ]$[1, 0); } |
| 115 | expr '+' expr { $$ = new_nterm ("+(%s,%s)", ]$[1, ]$[3, 0); } |
| 116 | expr '=' expr { $$ = new_nterm ("=(%s,%s)", ]$[1, ]$[3, 0); } |
| 117 ; |
| 118 |
| 119 decl : TYPENAME declarator ';' |
| 120 { $$ = new_nterm ("<declare>(%s,%s)", ]$[1, ]$[2, 0); } |
| 121 | TYPENAME declarator '=' expr ';' |
| 122 { $$ = new_nterm ("<init-declare>(%s,%s,%s)", ]$[1, |
| 123 ]$[2, ]$[4); } |
| 124 ; |
| 125 |
| 126 declarator : ID |
| 127 | '(' declarator ')' { $$ = ]$[2; } |
| 128 ; |
| 129 |
| 130 %% |
| 131 |
| 132 #include <ctype.h> |
| 133 #include <stdlib.h> |
| 134 #include <string.h> |
| 135 #include <stdarg.h> |
| 136 |
| 137 int |
| 138 main (int argc, char **argv) |
| 139 { |
| 140 if (argc != 2) |
| 141 abort (); |
| 142 if (!freopen (argv[1], "r", stdin)) |
| 143 return 3; |
| 144 return yyparse (); |
| 145 } |
| 146 |
| 147 int |
| 148 yylex (LEX_PARAMETERS) |
| 149 { |
| 150 char buffer[256]; |
| 151 int c; |
| 152 unsigned int i; |
| 153 static int lineNum = 1; |
| 154 static int colNum = 0; |
| 155 |
| 156 #if YYPURE |
| 157 # undef yylloc |
| 158 # define yylloc (*llocp) |
| 159 # undef yylval |
| 160 # define yylval (*lvalp) |
| 161 #endif |
| 162 |
| 163 while (1) |
| 164 { |
| 165 if (feof (stdin)) |
| 166 abort (); |
| 167 c = getchar (); |
| 168 switch (c) |
| 169 { |
| 170 case EOF: |
| 171 return 0; |
| 172 case '\t': |
| 173 colNum = (colNum + 7) & ~7; |
| 174 break; |
| 175 case ' ': case '\f': |
| 176 colNum += 1; |
| 177 break; |
| 178 case '\n': |
| 179 lineNum += 1; |
| 180 colNum = 0; |
| 181 break; |
| 182 default: |
| 183 { |
| 184 int tok; |
| 185 #if YYLSP_NEEDED |
| 186 yylloc.first_line = yylloc.last_line = lineNum; |
| 187 yylloc.first_column = colNum; |
| 188 #endif |
| 189 if (isalpha (c)) |
| 190 { |
| 191 i = 0; |
| 192 |
| 193 do |
| 194 { |
| 195 buffer[i++] = c; |
| 196 colNum += 1; |
| 197 if (i == sizeof buffer - 1) |
| 198 abort (); |
| 199 c = getchar (); |
| 200 } |
| 201 while (isalnum (c) || c == '_'); |
| 202 |
| 203 ungetc (c, stdin); |
| 204 buffer[i++] = 0; |
| 205 tok = isupper ((unsigned char) buffer[0]) ? TYPENAME : ID; |
| 206 yylval = new_term (strcpy ((char *) malloc (i), buffer)); |
| 207 } |
| 208 else |
| 209 { |
| 210 colNum += 1; |
| 211 tok = c; |
| 212 yylval = 0; |
| 213 } |
| 214 #if YYLSP_NEEDED |
| 215 yylloc.last_column = colNum-1; |
| 216 #endif |
| 217 return tok; |
| 218 } |
| 219 } |
| 220 } |
| 221 } |
| 222 |
| 223 void |
| 224 yyerror (ERROR_PARAMETERS) |
| 225 { |
| 226 #if YYPURE && YYLSP_NEEDED |
| 227 /* Pacify GCC by using llocp. */ |
| 228 if (! llocp) |
| 229 abort (); |
| 230 #endif |
| 231 fprintf (stderr, "%s\n", s); |
| 232 } |
| 233 |
| 234 static Node * |
| 235 new_nterm (char const *form, Node *child0, Node *child1, Node *child2) |
| 236 { |
| 237 Node *node = (Node *) malloc (sizeof (Node)); |
| 238 node->nterm.isNterm = 1; |
| 239 node->nterm.parents = 0; |
| 240 node->nterm.form = form; |
| 241 node->nterm.children[0] = child0; |
| 242 if (child0) |
| 243 child0->nodeInfo.parents += 1; |
| 244 node->nterm.children[1] = child1; |
| 245 if (child1) |
| 246 child1->nodeInfo.parents += 1; |
| 247 node->nterm.children[2] = child2; |
| 248 if (child2) |
| 249 child2->nodeInfo.parents += 1; |
| 250 return node; |
| 251 } |
| 252 |
| 253 static Node * |
| 254 new_term (char *text) |
| 255 { |
| 256 Node *node = (Node *) malloc (sizeof (Node)); |
| 257 node->term.isNterm = 0; |
| 258 node->term.parents = 0; |
| 259 node->term.text = text; |
| 260 return node; |
| 261 } |
| 262 |
| 263 static void |
| 264 free_node (Node *node) |
| 265 { |
| 266 if (!node) |
| 267 return; |
| 268 node->nodeInfo.parents -= 1; |
| 269 /* Free only if 0 (last parent) or -1 (no parents). */ |
| 270 if (node->nodeInfo.parents > 0) |
| 271 return; |
| 272 if (node->nodeInfo.isNterm == 1) |
| 273 { |
| 274 free_node (node->nterm.children[0]); |
| 275 free_node (node->nterm.children[1]); |
| 276 free_node (node->nterm.children[2]); |
| 277 } |
| 278 else |
| 279 free (node->term.text); |
| 280 free (node); |
| 281 } |
| 282 |
| 283 static char * |
| 284 node_to_string (Node *node) |
| 285 { |
| 286 char *child0; |
| 287 char *child1; |
| 288 char *child2; |
| 289 char *buffer; |
| 290 if (!node) |
| 291 { |
| 292 buffer = (char *) malloc (1); |
| 293 buffer[0] = 0; |
| 294 } |
| 295 else if (node->nodeInfo.isNterm == 1) |
| 296 { |
| 297 child0 = node_to_string (node->nterm.children[0]); |
| 298 child1 = node_to_string (node->nterm.children[1]); |
| 299 child2 = node_to_string (node->nterm.children[2]); |
| 300 buffer = (char *) malloc (strlen (node->nterm.form) + strlen (child0) |
| 301 + strlen (child1) + strlen (child2) + 1); |
| 302 sprintf (buffer, node->nterm.form, child0, child1, child2); |
| 303 free (child0); |
| 304 free (child1); |
| 305 free (child2); |
| 306 } |
| 307 else |
| 308 buffer = strdup (node->term.text); |
| 309 return buffer; |
| 310 } |
| 311 |
| 312 ]] |
| 313 m4_bmatch([$2], [stmtMerge], |
| 314 [[static YYSTYPE |
| 315 stmtMerge (YYSTYPE x0, YYSTYPE x1) |
| 316 { |
| 317 return new_nterm ("<OR>(%s,%s)", x0, x1, 0); |
| 318 } |
| 319 ]]) |
| 320 ) |
| 321 |
| 322 AT_DATA([test-input], |
| 323 [[ |
| 324 |
| 325 z + q; |
| 326 |
| 327 T x; |
| 328 |
| 329 T x = y; |
| 330 |
| 331 x = y; |
| 332 |
| 333 T (x) + y; |
| 334 |
| 335 T (x); |
| 336 |
| 337 T (y) = z + q; |
| 338 |
| 339 T (y y) = z + q; |
| 340 |
| 341 z + q; |
| 342 |
| 343 @ |
| 344 |
| 345 This is total garbage, but it should be ignored. |
| 346 ]]) |
| 347 |
| 348 AT_BISON_CHECK([-o types.c types.y], 0, [], ignore) |
| 349 AT_COMPILE([types]) |
| 350 AT_BISON_OPTION_POPDEFS |
| 351 ]) |
| 352 |
| 353 m4_define([_AT_RESOLVED_GLR_OUTPUT], |
| 354 [[[+(z,q) |
| 355 <declare>(T,x) |
| 356 <init-declare>(T,x,y) |
| 357 =(x,y) |
| 358 +(<cast>(x,T),y) |
| 359 <declare>(T,x) |
| 360 <init-declare>(T,y,+(z,q)) |
| 361 <error> |
| 362 +(z,q) |
| 363 ]]]) |
| 364 |
| 365 m4_define([_AT_RESOLVED_GLR_OUTPUT_WITH_LOC], |
| 366 [[[3.0-3.5: +(z,q) |
| 367 5.0-5.3: <declare>(T,x) |
| 368 7.0-7.7: <init-declare>(T,x,y) |
| 369 9.0-9.5: =(x,y) |
| 370 11.0-11.9: +(<cast>(x,T),y) |
| 371 13.0-13.5: <declare>(T,x) |
| 372 15.0-15.13: <init-declare>(T,y,+(z,q)) |
| 373 17.0-17.15: <error> |
| 374 19.0-19.5: +(z,q) |
| 375 ]]]) |
| 376 |
| 377 m4_define([_AT_AMBIG_GLR_OUTPUT], |
| 378 [[[+(z,q) |
| 379 <declare>(T,x) |
| 380 <init-declare>(T,x,y) |
| 381 =(x,y) |
| 382 +(<cast>(x,T),y) |
| 383 <OR>(<declare>(T,x),<cast>(x,T)) |
| 384 <OR>(<init-declare>(T,y,+(z,q)),=(<cast>(y,T),+(z,q))) |
| 385 <error> |
| 386 +(z,q) |
| 387 ]]]) |
| 388 |
| 389 m4_define([_AT_AMBIG_GLR_OUTPUT_WITH_LOC], |
| 390 [[[3.0-3.5: +(z,q) |
| 391 5.0-5.3: <declare>(T,x) |
| 392 7.0-7.7: <init-declare>(T,x,y) |
| 393 9.0-9.5: =(x,y) |
| 394 11.0-11.9: +(<cast>(x,T),y) |
| 395 13.0-13.5: <OR>(<declare>(T,x),<cast>(x,T)) |
| 396 15.0-15.13: <OR>(<init-declare>(T,y,+(z,q)),=(<cast>(y,T),+(z,q))) |
| 397 17.0-17.15: <error> |
| 398 19.0-19.5: +(z,q) |
| 399 ]]]) |
| 400 |
| 401 m4_define([_AT_GLR_STDERR], |
| 402 [[[syntax error |
| 403 ]]]) |
| 404 |
| 405 m4_define([_AT_VERBOSE_GLR_STDERR], |
| 406 [[[syntax error, unexpected ID, expecting '=' or '+' or ')' |
| 407 ]]]) |
| 408 |
| 409 ## ---------------------------------------------------- ## |
| 410 ## Compile the grammar described in the documentation. ## |
| 411 ## ---------------------------------------------------- ## |
| 412 |
| 413 AT_SETUP([GLR: Resolve ambiguity, impure, no locations]) |
| 414 _AT_TEST_GLR_CXXTYPES([], |
| 415 [%dprec 1], [%dprec 2]) |
| 416 AT_PARSER_CHECK([[./types test-input]], 0, |
| 417 _AT_RESOLVED_GLR_OUTPUT, _AT_GLR_STDERR) |
| 418 AT_CLEANUP |
| 419 |
| 420 AT_SETUP([GLR: Resolve ambiguity, impure, locations]) |
| 421 _AT_TEST_GLR_CXXTYPES([%locations],[%dprec 1],[%dprec 2]) |
| 422 AT_PARSER_CHECK([[./types test-input]], 0, |
| 423 _AT_RESOLVED_GLR_OUTPUT_WITH_LOC, _AT_GLR_STDERR) |
| 424 AT_CLEANUP |
| 425 |
| 426 AT_SETUP([GLR: Resolve ambiguity, pure, no locations]) |
| 427 _AT_TEST_GLR_CXXTYPES([%define api.pure], |
| 428 [%dprec 1], [%dprec 2]) |
| 429 AT_PARSER_CHECK([[./types test-input]], 0, |
| 430 _AT_RESOLVED_GLR_OUTPUT, _AT_GLR_STDERR) |
| 431 AT_CLEANUP |
| 432 |
| 433 AT_SETUP([GLR: Resolve ambiguity, pure, locations]) |
| 434 _AT_TEST_GLR_CXXTYPES([%define api.pure %locations], |
| 435 [%dprec 1], [%dprec 2]) |
| 436 AT_PARSER_CHECK([[./types test-input]], 0, |
| 437 _AT_RESOLVED_GLR_OUTPUT_WITH_LOC, _AT_GLR_STDERR) |
| 438 AT_CLEANUP |
| 439 |
| 440 AT_SETUP([GLR: Merge conflicting parses, impure, no locations]) |
| 441 _AT_TEST_GLR_CXXTYPES([], |
| 442 [%merge <stmtMerge>], [%merge <stmtMerge>]) |
| 443 AT_PARSER_CHECK([[./types test-input]], 0, |
| 444 _AT_AMBIG_GLR_OUTPUT, _AT_GLR_STDERR) |
| 445 AT_CLEANUP |
| 446 |
| 447 AT_SETUP([GLR: Merge conflicting parses, impure, locations]) |
| 448 _AT_TEST_GLR_CXXTYPES([%locations], |
| 449 [%merge <stmtMerge>], [%merge <stmtMerge>]) |
| 450 AT_PARSER_CHECK([[./types test-input]], 0, |
| 451 _AT_AMBIG_GLR_OUTPUT_WITH_LOC, _AT_GLR_STDERR) |
| 452 AT_CLEANUP |
| 453 |
| 454 AT_SETUP([GLR: Merge conflicting parses, pure, no locations]) |
| 455 _AT_TEST_GLR_CXXTYPES([%define api.pure], |
| 456 [%merge <stmtMerge>], [%merge <stmtMerge>]) |
| 457 AT_PARSER_CHECK([[./types test-input]], 0, |
| 458 _AT_AMBIG_GLR_OUTPUT, _AT_GLR_STDERR) |
| 459 AT_CLEANUP |
| 460 AT_SETUP([GLR: Merge conflicting parses, pure, locations]) |
| 461 _AT_TEST_GLR_CXXTYPES([%define api.pure %locations], |
| 462 [%merge <stmtMerge>],[%merge <stmtMerge>]) |
| 463 AT_PARSER_CHECK([[./types test-input]], 0, |
| 464 _AT_AMBIG_GLR_OUTPUT_WITH_LOC, _AT_GLR_STDERR) |
| 465 AT_CLEANUP |
| 466 |
| 467 AT_SETUP([GLR: Verbose messages, resolve ambiguity, impure, no locations]) |
| 468 _AT_TEST_GLR_CXXTYPES([%error-verbose], |
| 469 [%merge <stmtMerge>], [%merge <stmtMerge>]) |
| 470 AT_PARSER_CHECK([[./types test-input]], 0, |
| 471 _AT_AMBIG_GLR_OUTPUT, _AT_VERBOSE_GLR_STDERR) |
| 472 AT_CLEANUP |
OLD | NEW |