Home | History | Annotate | Download | only in tests
      1 # Checking GLR Parsing.                         -*- Autotest -*-
      2 
      3 # Copyright (C) 2002-2012 Free Software 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 [AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
     27 
     28 AT_DATA_GRAMMAR([types.y],
     29 [[/* Simplified C++ Type and Expression Grammar.  */
     30 
     31 $1
     32 
     33 %code requires
     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   #define YYSTYPE Node *
     55 }
     56 
     57 %code
     58 {
     59   static Node *new_nterm (char const *, Node *, Node *, Node *);
     60   static Node *new_term (char *);
     61   static void free_node (Node *);
     62   static char *node_to_string (Node *);
     63 ]m4_bmatch([$2], [stmtMerge],
     64 [ static YYSTYPE stmtMerge (YYSTYPE x0, YYSTYPE x1);])[
     65   #define YYINITDEPTH 10
     66   #define YYSTACKEXPANDABLE 1
     67   ]AT_YYERROR_DECLARE[
     68   ]AT_YYLEX_DECLARE[
     69 }
     70 
     71 %token TYPENAME ID
     72 
     73 %right '='
     74 %left '+'
     75 
     76 %glr-parser
     77 
     78 %destructor { free_node ($$); } stmt expr decl declarator TYPENAME ID
     79 
     80 %%
     81 
     82 prog :
     83      | prog stmt   {
     84                         char *output;]AT_LOCATION_IF([
     85                         printf ("%d.%d-%d.%d: ",
     86                              @2.first_line, @2.first_column,
     87                              @2.last_line, @2.last_column);])[
     88                         output = node_to_string (]$[2);
     89                         printf ("%s\n", output);
     90                         free (output);
     91                         free_node (]$[2);
     92                    }
     93      ;
     94 
     95 stmt : expr ';'  $2     { $$ = ]$[1; }
     96      | decl      $3
     97      | error ';'        { $$ = new_nterm ("<error>", YY_NULL, YY_NULL, YY_NULL); }
     98      | '@'              { YYACCEPT; }
     99      ;
    100 
    101 expr : ID
    102      | TYPENAME '(' expr ')'
    103                         { $$ = new_nterm ("<cast>(%s,%s)", ]$[3, ]$[1, YY_NULL); }
    104      | expr '+' expr    { $$ = new_nterm ("+(%s,%s)", ]$[1, ]$[3, YY_NULL); }
    105      | expr '=' expr    { $$ = new_nterm ("=(%s,%s)", ]$[1, ]$[3, YY_NULL); }
    106      ;
    107 
    108 decl : TYPENAME declarator ';'
    109                         { $$ = new_nterm ("<declare>(%s,%s)", ]$[1, ]$[2, YY_NULL); }
    110      | TYPENAME declarator '=' expr ';'
    111                         { $$ = new_nterm ("<init-declare>(%s,%s,%s)", ]$[1,
    112                                           ]$[2, ]$[4); }
    113      ;
    114 
    115 declarator : ID
    116      | '(' declarator ')' { $$ = ]$[2; }
    117      ;
    118 
    119 %%
    120 
    121 #include <ctype.h>
    122 #include <stdlib.h>
    123 #include <string.h>
    124 #include <stdarg.h>
    125 #include <assert.h>
    126 
    127 int
    128 main (int argc, char **argv)
    129 {
    130   assert (argc == 2);
    131   if (!freopen (argv[1], "r", stdin))
    132     return 3;
    133   return yyparse ();
    134 }
    135 
    136 ]AT_YYERROR_DEFINE[
    137 
    138 ]AT_YYLEX_PROTOTYPE[
    139 {
    140   char buffer[256];
    141   int c;
    142   unsigned int i;
    143   static int lineNum = 1;
    144   static int colNum = 0;
    145 
    146 #if YYPURE
    147 # undef yylloc
    148 # define yylloc (*llocp)
    149 # undef yylval
    150 # define yylval (*lvalp)
    151 #endif
    152 
    153   while (1)
    154     {
    155       assert (!feof (stdin));
    156       c = getchar ();
    157       switch (c)
    158         {
    159         case EOF:
    160           return 0;
    161         case '\t':
    162           colNum = (colNum + 7) & ~7;
    163           break;
    164         case ' ': case '\f':
    165           colNum += 1;
    166           break;
    167         case '\n':
    168           lineNum += 1;
    169           colNum = 0;
    170           break;
    171         default:
    172           {
    173             int tok;]AT_LOCATION_IF([[
    174             yylloc.first_line = yylloc.last_line = lineNum;
    175             yylloc.first_column = colNum;]])[
    176             if (isalpha (c))
    177               {
    178                 i = 0;
    179 
    180                 do
    181                   {
    182                     buffer[i++] = c;
    183                     colNum += 1;
    184                     assert (i != sizeof buffer - 1);
    185                     c = getchar ();
    186                   }
    187                 while (isalnum (c) || c == '_');
    188 
    189                 ungetc (c, stdin);
    190                 buffer[i++] = 0;
    191                 tok = isupper ((unsigned char) buffer[0]) ? TYPENAME : ID;
    192                 yylval = new_term (strcpy ((char *) malloc (i), buffer));
    193               }
    194             else
    195               {
    196                 colNum += 1;
    197                 tok = c;
    198                 yylval = YY_NULL;
    199               }]AT_LOCATION_IF([[
    200             yylloc.last_column = colNum-1;]])[
    201             return tok;
    202           }
    203         }
    204     }
    205 }
    206 
    207 static Node *
    208 new_nterm (char const *form, Node *child0, Node *child1, Node *child2)
    209 {
    210   Node *node = (Node *) malloc (sizeof (Node));
    211   node->nterm.isNterm = 1;
    212   node->nterm.parents = 0;
    213   node->nterm.form = form;
    214   node->nterm.children[0] = child0;
    215   if (child0)
    216     child0->nodeInfo.parents += 1;
    217   node->nterm.children[1] = child1;
    218   if (child1)
    219     child1->nodeInfo.parents += 1;
    220   node->nterm.children[2] = child2;
    221   if (child2)
    222     child2->nodeInfo.parents += 1;
    223   return node;
    224 }
    225 
    226 static Node *
    227 new_term (char *text)
    228 {
    229   Node *node = (Node *) malloc (sizeof (Node));
    230   node->term.isNterm = 0;
    231   node->term.parents = 0;
    232   node->term.text = text;
    233   return node;
    234 }
    235 
    236 static void
    237 free_node (Node *node)
    238 {
    239   if (!node)
    240     return;
    241   node->nodeInfo.parents -= 1;
    242   /* Free only if 0 (last parent) or -1 (no parents).  */
    243   if (node->nodeInfo.parents > 0)
    244     return;
    245   if (node->nodeInfo.isNterm == 1)
    246     {
    247       free_node (node->nterm.children[0]);
    248       free_node (node->nterm.children[1]);
    249       free_node (node->nterm.children[2]);
    250     }
    251   else
    252     free (node->term.text);
    253   free (node);
    254 }
    255 
    256 static char *
    257 node_to_string (Node *node)
    258 {
    259   char *child0;
    260   char *child1;
    261   char *child2;
    262   char *buffer;
    263   if (!node)
    264     {
    265       buffer = (char *) malloc (1);
    266       buffer[0] = 0;
    267     }
    268   else if (node->nodeInfo.isNterm == 1)
    269     {
    270       child0 = node_to_string (node->nterm.children[0]);
    271       child1 = node_to_string (node->nterm.children[1]);
    272       child2 = node_to_string (node->nterm.children[2]);
    273       buffer = (char *) malloc (strlen (node->nterm.form) + strlen (child0)
    274                                 + strlen (child1) + strlen (child2) + 1);
    275       sprintf (buffer, node->nterm.form, child0, child1, child2);
    276       free (child0);
    277       free (child1);
    278       free (child2);
    279     }
    280   else
    281     buffer = strdup (node->term.text);
    282   return buffer;
    283 }
    284 
    285 ]]
    286 m4_bmatch([$2], [stmtMerge],
    287 [[static YYSTYPE
    288 stmtMerge (YYSTYPE x0, YYSTYPE x1)
    289 {
    290   return new_nterm ("<OR>(%s,%s)", x0, x1, YY_NULL);
    291 }
    292 ]])
    293 )
    294 
    295 AT_DATA([test-input],
    296 [[
    297 
    298 z + q;
    299 
    300 T x;
    301 
    302 T x = y;
    303 
    304 x = y;
    305 
    306 T (x) + y;
    307 
    308 T (x);
    309 
    310 T (y) = z + q;
    311 
    312 T (y y) = z + q;
    313 
    314 z + q;
    315 
    316 @
    317 
    318 This is total garbage, but it should be ignored.
    319 ]])
    320 
    321 AT_BISON_CHECK([-o types.c types.y], 0, [], ignore)
    322 AT_COMPILE([types])
    323 AT_BISON_OPTION_POPDEFS
    324 ])
    325 
    326 m4_define([_AT_RESOLVED_GLR_OUTPUT],
    327 [[+(z,q)
    328 <declare>(T,x)
    329 <init-declare>(T,x,y)
    330 =(x,y)
    331 +(<cast>(x,T),y)
    332 <declare>(T,x)
    333 <init-declare>(T,y,+(z,q))
    334 <error>
    335 +(z,q)
    336 ]])
    337 
    338 m4_define([_AT_RESOLVED_GLR_OUTPUT_WITH_LOC],
    339 [[3.0-3.5: +(z,q)
    340 5.0-5.3: <declare>(T,x)
    341 7.0-7.7: <init-declare>(T,x,y)
    342 9.0-9.5: =(x,y)
    343 11.0-11.9: +(<cast>(x,T),y)
    344 13.0-13.5: <declare>(T,x)
    345 15.0-15.13: <init-declare>(T,y,+(z,q))
    346 17.0-17.15: <error>
    347 19.0-19.5: +(z,q)
    348 ]])
    349 
    350 m4_define([_AT_AMBIG_GLR_OUTPUT],
    351 [[+(z,q)
    352 <declare>(T,x)
    353 <init-declare>(T,x,y)
    354 =(x,y)
    355 +(<cast>(x,T),y)
    356 <OR>(<declare>(T,x),<cast>(x,T))
    357 <OR>(<init-declare>(T,y,+(z,q)),=(<cast>(y,T),+(z,q)))
    358 <error>
    359 +(z,q)
    360 ]])
    361 
    362 m4_define([_AT_AMBIG_GLR_OUTPUT_WITH_LOC],
    363 [[3.0-3.5: +(z,q)
    364 5.0-5.3: <declare>(T,x)
    365 7.0-7.7: <init-declare>(T,x,y)
    366 9.0-9.5: =(x,y)
    367 11.0-11.9: +(<cast>(x,T),y)
    368 13.0-13.5: <OR>(<declare>(T,x),<cast>(x,T))
    369 15.0-15.13: <OR>(<init-declare>(T,y,+(z,q)),=(<cast>(y,T),+(z,q)))
    370 17.0-17.15: <error>
    371 19.0-19.5: +(z,q)
    372 ]])
    373 
    374 m4_define([_AT_GLR_STDERR],
    375 [[syntax error
    376 ]])
    377 
    378 m4_define([_AT_GLR_STDERR_WITH_LOC],
    379 [[17.5: syntax error
    380 ]])
    381 
    382 m4_define([_AT_VERBOSE_GLR_STDERR],
    383 [[syntax error, unexpected ID, expecting '=' or '+' or ')'
    384 ]])
    385 
    386 m4_define([_AT_VERBOSE_GLR_STDERR_WITH_LOC],
    387 [[17.5: syntax error, unexpected ID, expecting '=' or '+' or ')'
    388 ]])
    389 
    390 ## ---------------------------------------------------- ##
    391 ## Compile the grammar described in the documentation.  ##
    392 ## ---------------------------------------------------- ##
    393 
    394 AT_SETUP([GLR: Resolve ambiguity, impure, no locations])
    395 _AT_TEST_GLR_CXXTYPES([],
    396                       [%dprec 1], [%dprec 2])
    397 AT_PARSER_CHECK([[./types test-input]], 0,
    398                 [_AT_RESOLVED_GLR_OUTPUT], [_AT_GLR_STDERR])
    399 AT_CLEANUP
    400 
    401 AT_SETUP([GLR: Resolve ambiguity, impure, locations])
    402 _AT_TEST_GLR_CXXTYPES([%locations],[%dprec 1],[%dprec 2])
    403 AT_PARSER_CHECK([[./types test-input]], 0,
    404                 [_AT_RESOLVED_GLR_OUTPUT_WITH_LOC], [_AT_GLR_STDERR_WITH_LOC])
    405 AT_CLEANUP
    406 
    407 AT_SETUP([GLR: Resolve ambiguity, pure, no locations])
    408 _AT_TEST_GLR_CXXTYPES([%define api.pure],
    409                       [%dprec 1], [%dprec 2])
    410 AT_PARSER_CHECK([[./types test-input]], 0,
    411                 [_AT_RESOLVED_GLR_OUTPUT], [_AT_GLR_STDERR])
    412 AT_CLEANUP
    413 
    414 AT_SETUP([GLR: Resolve ambiguity, pure, locations])
    415 _AT_TEST_GLR_CXXTYPES([%define api.pure %locations],
    416                       [%dprec 1], [%dprec 2])
    417 AT_PARSER_CHECK([[./types test-input]], 0,
    418                 [_AT_RESOLVED_GLR_OUTPUT_WITH_LOC], [_AT_GLR_STDERR_WITH_LOC])
    419 AT_CLEANUP
    420 
    421 AT_SETUP([GLR: Merge conflicting parses, impure, no locations])
    422 _AT_TEST_GLR_CXXTYPES([],
    423                       [%merge <stmtMerge>], [%merge <stmtMerge>])
    424 AT_PARSER_CHECK([[./types test-input]], 0,
    425                 [_AT_AMBIG_GLR_OUTPUT], [_AT_GLR_STDERR])
    426 AT_CLEANUP
    427 
    428 AT_SETUP([GLR: Merge conflicting parses, impure, locations])
    429 _AT_TEST_GLR_CXXTYPES([%locations],
    430                       [%merge <stmtMerge>], [%merge <stmtMerge>])
    431 AT_PARSER_CHECK([[./types test-input]], 0,
    432                 [_AT_AMBIG_GLR_OUTPUT_WITH_LOC], [_AT_GLR_STDERR_WITH_LOC])
    433 AT_CLEANUP
    434 
    435 AT_SETUP([GLR: Merge conflicting parses, pure, no locations])
    436 _AT_TEST_GLR_CXXTYPES([%define api.pure],
    437                       [%merge <stmtMerge>], [%merge <stmtMerge>])
    438 AT_PARSER_CHECK([[./types test-input]], 0,
    439                 [_AT_AMBIG_GLR_OUTPUT], [_AT_GLR_STDERR])
    440 AT_CLEANUP
    441 AT_SETUP([GLR: Merge conflicting parses, pure, locations])
    442 _AT_TEST_GLR_CXXTYPES([%define api.pure %locations],
    443                       [%merge <stmtMerge>],[%merge <stmtMerge>])
    444 AT_PARSER_CHECK([[./types test-input]], 0,
    445                 [_AT_AMBIG_GLR_OUTPUT_WITH_LOC], [_AT_GLR_STDERR_WITH_LOC])
    446 AT_CLEANUP
    447 
    448 AT_SETUP([GLR: Verbose messages, resolve ambiguity, impure, no locations])
    449 _AT_TEST_GLR_CXXTYPES([%error-verbose],
    450                       [%merge <stmtMerge>], [%merge <stmtMerge>])
    451 AT_PARSER_CHECK([[./types test-input]], 0,
    452                 [_AT_AMBIG_GLR_OUTPUT], [_AT_VERBOSE_GLR_STDERR])
    453 AT_CLEANUP
    454