Home | History | Annotate | Download | only in tests
      1 # Named references test.                           -*- Autotest -*-
      2 
      3 # Copyright (C) 2009-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 # FIXME: Duplication with calc.at.
     19 AT_BANNER([[Named references tests.]])
     20 
     21 AT_SETUP([Tutorial calculator])
     22 AT_BISON_OPTION_PUSHDEFS
     23 AT_DATA_GRAMMAR([test.y],
     24 [[
     25 %{
     26 #include <assert.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <ctype.h>
     31 typedef int semantic_value;
     32 FILE *input;
     33 static semantic_value global_result = 0;
     34 static int global_count = 0;
     35 static int power (int base, int exponent);
     36 ]AT_YYERROR_DECLARE[
     37 ]AT_YYLEX_DECLARE[
     38 %}
     39 
     40 %union
     41 {
     42   semantic_value ival;
     43 };
     44 
     45 %token CALC_EOF 0 "end of input"
     46 %token <ival> NUM "number"
     47 %type  <ival> exp
     48 
     49 %nonassoc '='   /* comparison	       */
     50 %left '-' '+'
     51 %left '*' '/'
     52 %left NEG       /* negation--unary minus */
     53 %right '^'      /* exponentiation        */
     54 
     55 %%
     56 input:
     57   line
     58 | input line         {}
     59 ;
     60 
     61 line:
     62   '\n'
     63 | exp '\n'           {}
     64 ;
     65 
     66 exp:
     67   NUM                { $$ = $NUM; }
     68 | exp[l] '=' exp[r]
     69   {
     70     if ($l != $r)
     71       fprintf (stderr, "calc: error: %d != %d\n", $l, $r);
     72     $$ = $l;
     73   }
     74 | exp[x] '+' { $<ival>$ = $x; } [l] exp[r]  { $$ = $<ival>l + $r;    }
     75 | exp[l] '-' exp[r]  { $$ = $l - $r;        }
     76 | exp[l] '*' exp[r]  { $$ = $l * $r;        }
     77 | exp[l] '/' exp[r]  { $$ = $l / $r;        }
     78 | '-' exp  %prec NEG { $$ = -$2;            }
     79 | exp[l] '^' exp[r]  { $$ = power ($l, $r); }
     80 | '(' exp[e] ')'     { $$ = $e;           }
     81 | '(' error ')'      { $$ = 1111; yyerrok;  }
     82 | '!'                { $$ = 0; YYERROR;     }
     83 | '-' error          { $$ = 0; YYERROR;     }
     84 ;
     85 %%
     86 ]AT_YYERROR_DEFINE[
     87 static int get_char (void)
     88 {
     89   int res = getc (input);
     90   return res;
     91 }
     92 
     93 static void unget_char (int c)
     94 {
     95   ungetc (c, input);
     96 }
     97 
     98 static int read_signed_integer (void)
     99 {
    100   int c = get_char ();
    101   int sign = 1;
    102   int n = 0;
    103   if (c == '-')
    104     {
    105       c = get_char ();
    106       sign = -1;
    107     }
    108   while (isdigit (c))
    109     {
    110       n = 10 * n + (c - '0');
    111       c = get_char ();
    112     }
    113   unget_char ( c);
    114   return sign * n;
    115 }
    116 
    117 static int
    118 yylex (void)
    119 {
    120   int c;
    121   /* Skip white space.  */
    122   while ((c = get_char ()) == ' ' || c == '\t') {}
    123 
    124   /* process numbers   */
    125   if (c == '.' || isdigit (c))
    126     {
    127       unget_char ( c);
    128       (yylval).ival = read_signed_integer ();
    129       return NUM;
    130     }
    131 
    132   /* Return end-of-file.  */
    133   if (c == EOF)
    134     return CALC_EOF;
    135 
    136   /* Return single chars. */
    137   return c;
    138 }
    139 
    140 static int power (int base, int exponent)
    141 {
    142   int res = 1;
    143   assert (0 <= exponent);
    144   for (/* Niente */; exponent; --exponent)
    145     res *= base;
    146   return res;
    147 }
    148 
    149 int main (int argc, const char **argv)
    150 {
    151   semantic_value result = 0;
    152   int count = 0;
    153   int status;
    154   if (argc == 2)
    155     input = fopen (argv[1], "r");
    156   else
    157     input = stdin;
    158   if (!input)
    159     {
    160       perror (argv[1]);
    161       return 3;
    162     }
    163   status = yyparse ();
    164   fclose (input);
    165   assert (global_result == result);
    166   assert (global_count == count);
    167   return status;
    168 }
    169 ]])
    170 
    171 AT_DATA([input.txt],
    172 [[
    173 1 + 2 * 3 = 7
    174 1 + 2 * -3 = -5
    175 -1^2 = -1
    176 (-1)^2 = 1
    177 ---1 = -1
    178 1 - 2 - 3 = -4
    179 1 - (2 - 3) = 2
    180 2^2^3 = 256
    181 (2^2)^3 = 64
    182 ]])
    183 
    184 AT_BISON_CHECK([-o test.c test.y])
    185 AT_COMPILE([[test]])
    186 AT_PARSER_CHECK([./test input.txt], 0, [], [stderr])
    187 AT_BISON_OPTION_POPDEFS
    188 AT_CLEANUP
    189 
    190 
    191 
    192 #######################################################################
    193 
    194 
    195 AT_SETUP([Undefined and ambiguous references])
    196 AT_BISON_OPTION_PUSHDEFS
    197 AT_DATA_GRAMMAR([test.y],
    198 [[
    199 %{
    200 static int power (int base, int exponent);
    201 ]AT_YYERROR_DECLARE[
    202 ]AT_YYLEX_DECLARE[
    203 %}
    204 
    205 %union
    206 {
    207   int ival;
    208 };
    209 
    210 %token CALC_EOF 0 "end of input"
    211 %token <ival> NUM "number"
    212 %type  <ival> exp
    213 
    214 %nonassoc '='   /* comparison	       */
    215 %left '-' '+'
    216 %left '*' '/'
    217 %left NEG       /* negation--unary minus */
    218 %right '^'      /* exponentiation        */
    219 
    220 %%
    221 input:
    222   line
    223 | input line         {}
    224 ;
    225 
    226 line:
    227   '\n'
    228 | exp '\n'           {}
    229 ;
    230 
    231 exp:
    232   NUM { $$ = $NUM; }
    233 | exp[l] '=' exp[r]
    234   {
    235     if ($l != $r)
    236       fprintf (stderr, "calc: error: %d != %d\n", $l, $r);
    237     $$ = $l;
    238   }
    239 | exp[x] '+' { $<ival>$ = $x; } [l] exp[r] { $$ = $<ival>lo9 + $r; }
    240 | exp[x] '-' { $<ival>$ = $x; } [l] exp[r] { $$ = $<ival>exp - $r; }
    241 | exp[x] '*' { $<ival>$ = $x; } [l] exp[r] { $$ = $l * $r; }
    242 | exp[l] '/' exp[r]  { $$ = $l / $r;        }
    243 | '-' exp  %prec NEG { $$ = -$2;            }
    244 | exp[l] '^' exp[r]  { $$ = power ($l, $r12); }
    245 | '(' exp ')'        { $$ = $expo;           }
    246 | '(' error ')'      { $$ = 1111; yyerrok;  }
    247 | '!'                { $$ = 0; YYERROR;     }
    248 | '-' error          { $$ = 0; YYERROR;     }
    249 ;
    250 %%
    251 ]])
    252 
    253 AT_BISON_CHECK([-o test.c test.y], 1, [],
    254 [[test.y:50.51-60: error: invalid reference: '$<ival>lo9'
    255 test.y:50.3-68:      symbol not found in production: lo9
    256 test.y:51.51-60: warning: misleading reference: '$<ival>exp'
    257 test.y:42.1-3:       refers to: $exp at $$
    258 test.y:51.7:         possibly meant: $x, hiding $exp at $1
    259 test.y:51.41:        possibly meant: $r, hiding $exp at $4
    260 test.y:52.51-52: error: $l of 'exp' has no declared type
    261 test.y:55.40-43: error: invalid reference: '$r12'
    262 test.y:55.3-47:      symbol not found in production: r12
    263 test.y:56.29-33: error: invalid reference: '$expo'
    264 test.y:56.3-46:      symbol not found in production: expo
    265 ]])
    266 AT_BISON_OPTION_POPDEFS
    267 AT_CLEANUP
    268 
    269 #######################################################################
    270 
    271 AT_SETUP([Misleading references])
    272 AT_DATA_GRAMMAR([test.y],
    273 [[
    274 %%
    275 start: foo foo.bar { $foo.bar; }
    276 foo: '1'
    277 foo.bar: '2'
    278 ]])
    279 AT_BISON_CHECK([-o test.c test.y], 0, [],
    280 [[test.y:11.22-29: warning: misleading reference: '$foo.bar'
    281 test.y:11.8-10:      refers to: $foo at $1
    282 test.y:11.12-18:     possibly meant: $[foo.bar] at $2
    283 ]])
    284 AT_CLEANUP
    285 
    286 #######################################################################
    287 
    288 AT_SETUP([Many kinds of errors])
    289 AT_DATA_GRAMMAR([test.y],
    290 [[
    291 %token IDENT
    292 %token NUMBER
    293 %token ASSIGNOP
    294 %token IF
    295 %token IF1
    296 %token THEN
    297 %token ELSE
    298 %token FI
    299 %token WHILE
    300 %token DO
    301 %token OD
    302 %start program
    303 %%
    304 if_stmt1: IF expr[cond] THEN stmt[then] ELSE stmt.list[else] FI
    305           { $if_stmt1 = new IfStmt($cond1, $then.f1, $else); };
    306 if_stmt2: IF expr[cond] THEN stmt[then] FI
    307           { $if_stmt2 = new IfStmt($cond, $stmt.field, 0); };
    308 if_stmt3: IF expr[cond] THEN stmt.list FI
    309           { $if_stmt3 = new IfStmt($cond, $stmt.list, 0); };
    310 if_stmt4: IF expr[cond] THEN stmt[xyz] ELSE stmt[xyz] FI
    311           { $if_stmt4 = new IfStmt($cond, $xyz, $cond); };
    312 if_stmt5: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    313           { $if_stmt5 = new IfStmt($cond, $stmt.list, $else); };
    314 if_stmt6: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    315           { $if_stmt6 = new IfStmt($cond, $stmt.list.field, $else); };
    316 if_stmt7: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    317           { $if_stmt7 = new IfStmt($cond, $[stmt.list].field, $else); };
    318 if_stmt8: IF expr[cond] THEN stmt.list[then.1] ELSE stmt.list[else] FI
    319           { $if_stmt8 = new IfStmt($cond, $then.1, $else); };
    320 if_stmt9: IF expr[cond] THEN stmt.list[then.1] ELSE stmt.list[else] FI
    321           { $if_stmt9 = new IfStmt($cond, $then.1.field, $else); };
    322 if_stmt10: IF expr[cond] THEN stmt[stmt.x] FI
    323           { $if_stmt10 = new IfStmt($cond, $stmt.x, 0); };
    324 if-stmt-a: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    325           { $if-stmt-a = new IfStmt($cond, $then, $else); };
    326 if-stmt-b: IF expr[cond] THEN if-stmt-a[then-a] ELSE stmt.list[else] FI
    327           { $[if-stmt-b] = new IfStmt($cond, $then-a.f, $else); };
    328 program: stmt.list;
    329 stmt.list:  stmt ';' stmt.list { $3->insert($stmt); $$ = $3; }
    330         |   stmt ';' { SL = new StmtList();  SL->insert($1); $$ = SL; }
    331         ;
    332 stmt:  assign_stmt { $$ = $1; }
    333     |  if_stmt { $$ = $1; }
    334     |  if_stmt1 { $$ = $1; }
    335     |  while_stmt { $$ = $1; }
    336     ;
    337 assign_stmt: IDENT ASSIGNOP expr
    338        { $$ = new AssignStmt(string($1),$3); };
    339 if_stmt: IF expr[cond] THEN stmt.list FI
    340        { $if_stmt = new IfStmt($cond, $[stmt.list], 0); };
    341 while_stmt[res]: WHILE expr DO stmt.list OD
    342        { $res = new WhileStmt($[expr], $[stmt.list]); };
    343 expr: expr '+' term   { $$ = new Plus($1,$3); }
    344     | expr '-' term   { $$ = new Minus($1,$3); }
    345     | term            { $$ = $1; }
    346     ;
    347 term: term '*' factor   { $$ = new Times($1,$3); }
    348     | factor            { $$ = $1; }
    349     ;
    350 factor:     '(' expr ')'  { $$ = $2; }
    351     |       NUMBER { $$ = new Number($1); }
    352     |       IDENT { $$ = new Ident(string($1)); }
    353     ;
    354 ]])
    355 AT_BISON_CHECK([-o test.c test.y], 1, [],
    356 [[test.y:24.36-41: error: invalid reference: '$cond1'
    357 test.y:23.11-24.62:  symbol not found in production: cond1
    358 test.y:26.43-53: error: invalid reference: '$stmt.field'
    359 test.y:25.11-26.60:  symbol not found in production: stmt
    360 test.y:25.35-38:     possibly meant: $then.field, hiding $stmt.field at $4
    361 test.y:28.43-52: error: invalid reference: '$stmt.list'
    362 test.y:27.11-28.59:  symbol not found in production: stmt
    363 test.y:27.30-38:     possibly meant: $[stmt.list] at $4
    364 test.y:30.43-46: error: ambiguous reference: '$xyz'
    365 test.y:29.35-37:     refers to: $xyz at $4
    366 test.y:29.50-52:     refers to: $xyz at $6
    367 test.y:32.43-52: error: invalid reference: '$stmt.list'
    368 test.y:31.11-32.63:  symbol not found in production: stmt
    369 test.y:31.40-43:     possibly meant: $then, hiding $[stmt.list] at $4
    370 test.y:31.61-64:     possibly meant: $else, hiding $[stmt.list] at $6
    371 test.y:34.43-58: error: invalid reference: '$stmt.list.field'
    372 test.y:33.11-34.69:  symbol not found in production: stmt
    373 test.y:33.40-43:     possibly meant: $then.field, hiding $[stmt.list].field at $4
    374 test.y:33.61-64:     possibly meant: $else.field, hiding $[stmt.list].field at $6
    375 test.y:36.43-54: error: invalid reference: '$[stmt.list]'
    376 test.y:35.11-36.71:  symbol not found in production: stmt.list
    377 test.y:35.40-43:     possibly meant: $then, hiding $[stmt.list] at $4
    378 test.y:35.61-64:     possibly meant: $else, hiding $[stmt.list] at $6
    379 test.y:38.43-49: error: invalid reference: '$then.1'
    380 test.y:37.11-38.60:  symbol not found in production: then
    381 test.y:37.40-45:     possibly meant: $[then.1] at $4
    382 test.y:40.43-55: error: invalid reference: '$then.1.field'
    383 test.y:39.11-40.66:  symbol not found in production: then
    384 test.y:39.40-45:     possibly meant: $[then.1].field at $4
    385 test.y:42.44-50: error: invalid reference: '$stmt.x'
    386 test.y:41.12-42.57:  symbol not found in production: stmt
    387 test.y:41.36-41:     possibly meant: $[stmt.x].x, hiding $stmt.x at $4
    388 test.y:41.36-41:     possibly meant: $[stmt.x] at $4
    389 test.y:44.13-22: error: invalid reference: '$if-stmt-a'
    390 test.y:43.12-44.59:  symbol not found in production: if
    391 test.y:43.1-9:       possibly meant: $[if-stmt-a] at $$
    392 test.y:46.46-54: error: invalid reference: '$then-a.f'
    393 test.y:45.12-46.65:  symbol not found in production: then
    394 test.y:45.41-46:     possibly meant: $[then-a].f at $4
    395 ]])
    396 
    397 AT_BISON_CHECK([-fcaret -o test.c test.y], 1, [],
    398 [[test.y:24.36-41: error: invalid reference: '$cond1'
    399            { $if_stmt1 = new IfStmt($cond1, $then.f1, $else); };
    400                                     ^^^^^^
    401 test.y:23.11-24.62:  symbol not found in production: cond1
    402  if_stmt1: IF expr[cond] THEN stmt[then] ELSE stmt.list[else] FI
    403            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    404 test.y:26.43-53: error: invalid reference: '$stmt.field'
    405            { $if_stmt2 = new IfStmt($cond, $stmt.field, 0); };
    406                                            ^^^^^^^^^^^
    407 test.y:25.11-26.60:  symbol not found in production: stmt
    408  if_stmt2: IF expr[cond] THEN stmt[then] FI
    409            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    410 test.y:25.35-38:     possibly meant: $then.field, hiding $stmt.field at $4
    411  if_stmt2: IF expr[cond] THEN stmt[then] FI
    412                                    ^^^^
    413 test.y:28.43-52: error: invalid reference: '$stmt.list'
    414            { $if_stmt3 = new IfStmt($cond, $stmt.list, 0); };
    415                                            ^^^^^^^^^^
    416 test.y:27.11-28.59:  symbol not found in production: stmt
    417  if_stmt3: IF expr[cond] THEN stmt.list FI
    418            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    419 test.y:27.30-38:     possibly meant: $[stmt.list] at $4
    420  if_stmt3: IF expr[cond] THEN stmt.list FI
    421                               ^^^^^^^^^
    422 test.y:30.43-46: error: ambiguous reference: '$xyz'
    423            { $if_stmt4 = new IfStmt($cond, $xyz, $cond); };
    424                                            ^^^^
    425 test.y:29.35-37:     refers to: $xyz at $4
    426  if_stmt4: IF expr[cond] THEN stmt[xyz] ELSE stmt[xyz] FI
    427                                    ^^^
    428 test.y:29.50-52:     refers to: $xyz at $6
    429  if_stmt4: IF expr[cond] THEN stmt[xyz] ELSE stmt[xyz] FI
    430                                                   ^^^
    431 test.y:32.43-52: error: invalid reference: '$stmt.list'
    432            { $if_stmt5 = new IfStmt($cond, $stmt.list, $else); };
    433                                            ^^^^^^^^^^
    434 test.y:31.11-32.63:  symbol not found in production: stmt
    435  if_stmt5: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    436            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    437 test.y:31.40-43:     possibly meant: $then, hiding $[stmt.list] at $4
    438  if_stmt5: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    439                                         ^^^^
    440 test.y:31.61-64:     possibly meant: $else, hiding $[stmt.list] at $6
    441  if_stmt5: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    442                                                              ^^^^
    443 test.y:34.43-58: error: invalid reference: '$stmt.list.field'
    444            { $if_stmt6 = new IfStmt($cond, $stmt.list.field, $else); };
    445                                            ^^^^^^^^^^^^^^^^
    446 test.y:33.11-34.69:  symbol not found in production: stmt
    447  if_stmt6: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    448            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    449 test.y:33.40-43:     possibly meant: $then.field, hiding $[stmt.list].field at $4
    450  if_stmt6: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    451                                         ^^^^
    452 test.y:33.61-64:     possibly meant: $else.field, hiding $[stmt.list].field at $6
    453  if_stmt6: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    454                                                              ^^^^
    455 test.y:36.43-54: error: invalid reference: '$[stmt.list]'
    456            { $if_stmt7 = new IfStmt($cond, $[stmt.list].field, $else); };
    457                                            ^^^^^^^^^^^^
    458 test.y:35.11-36.71:  symbol not found in production: stmt.list
    459  if_stmt7: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    460            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    461 test.y:35.40-43:     possibly meant: $then, hiding $[stmt.list] at $4
    462  if_stmt7: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    463                                         ^^^^
    464 test.y:35.61-64:     possibly meant: $else, hiding $[stmt.list] at $6
    465  if_stmt7: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    466                                                              ^^^^
    467 test.y:38.43-49: error: invalid reference: '$then.1'
    468            { $if_stmt8 = new IfStmt($cond, $then.1, $else); };
    469                                            ^^^^^^^
    470 test.y:37.11-38.60:  symbol not found in production: then
    471  if_stmt8: IF expr[cond] THEN stmt.list[then.1] ELSE stmt.list[else] FI
    472            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    473 test.y:37.40-45:     possibly meant: $[then.1] at $4
    474  if_stmt8: IF expr[cond] THEN stmt.list[then.1] ELSE stmt.list[else] FI
    475                                         ^^^^^^
    476 test.y:40.43-55: error: invalid reference: '$then.1.field'
    477            { $if_stmt9 = new IfStmt($cond, $then.1.field, $else); };
    478                                            ^^^^^^^^^^^^^
    479 test.y:39.11-40.66:  symbol not found in production: then
    480  if_stmt9: IF expr[cond] THEN stmt.list[then.1] ELSE stmt.list[else] FI
    481            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    482 test.y:39.40-45:     possibly meant: $[then.1].field at $4
    483  if_stmt9: IF expr[cond] THEN stmt.list[then.1] ELSE stmt.list[else] FI
    484                                         ^^^^^^
    485 test.y:42.44-50: error: invalid reference: '$stmt.x'
    486            { $if_stmt10 = new IfStmt($cond, $stmt.x, 0); };
    487                                             ^^^^^^^
    488 test.y:41.12-42.57:  symbol not found in production: stmt
    489  if_stmt10: IF expr[cond] THEN stmt[stmt.x] FI
    490             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    491 test.y:41.36-41:     possibly meant: $[stmt.x].x, hiding $stmt.x at $4
    492  if_stmt10: IF expr[cond] THEN stmt[stmt.x] FI
    493                                     ^^^^^^
    494 test.y:41.36-41:     possibly meant: $[stmt.x] at $4
    495  if_stmt10: IF expr[cond] THEN stmt[stmt.x] FI
    496                                     ^^^^^^
    497 test.y:44.13-22: error: invalid reference: '$if-stmt-a'
    498            { $if-stmt-a = new IfStmt($cond, $then, $else); };
    499              ^^^^^^^^^^
    500 test.y:43.12-44.59:  symbol not found in production: if
    501  if-stmt-a: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    502             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    503 test.y:43.1-9:       possibly meant: $[if-stmt-a] at $$
    504  if-stmt-a: IF expr[cond] THEN stmt.list[then] ELSE stmt.list[else] FI
    505  ^^^^^^^^^
    506 test.y:46.46-54: error: invalid reference: '$then-a.f'
    507            { $[if-stmt-b] = new IfStmt($cond, $then-a.f, $else); };
    508                                               ^^^^^^^^^
    509 test.y:45.12-46.65:  symbol not found in production: then
    510  if-stmt-b: IF expr[cond] THEN if-stmt-a[then-a] ELSE stmt.list[else] FI
    511             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    512 test.y:45.41-46:     possibly meant: $[then-a].f at $4
    513  if-stmt-b: IF expr[cond] THEN if-stmt-a[then-a] ELSE stmt.list[else] FI
    514                                          ^^^^^^
    515 ]])
    516 
    517 AT_CLEANUP
    518 
    519 #######################################################################
    520 
    521 AT_SETUP([Missing identifiers in brackets])
    522 AT_DATA_GRAMMAR([test.y],
    523 [[
    524 %%
    525 start: foo[] bar
    526   { s = $foo; }
    527 ]])
    528 AT_BISON_CHECK([-o test.c test.y], 1, [],
    529 [[test.y:11.12: error: an identifier expected
    530 ]])
    531 AT_CLEANUP
    532 
    533 #######################################################################
    534 
    535 AT_SETUP([Redundant words in brackets])
    536 AT_DATA_GRAMMAR([test.y],
    537 [[
    538 %%
    539 start: foo[ a d ] bar
    540   { s = $foo; }
    541 ]])
    542 AT_BISON_CHECK([-o test.c test.y], 1, [],
    543 [[test.y:11.15: error: unexpected identifier in bracketed name: 'd'
    544 ]])
    545 AT_CLEANUP
    546 
    547 #######################################################################
    548 
    549 AT_SETUP([Comments in brackets])
    550 AT_DATA_GRAMMAR([test.y],
    551 [[
    552 %%
    553 start: foo[/* comment */] bar
    554   { s = $foo; }
    555 ]])
    556 AT_BISON_CHECK([-o test.c test.y], 1, [],
    557 [[test.y:11.25: error: an identifier expected
    558 ]])
    559 AT_CLEANUP
    560 
    561 #######################################################################
    562 
    563 AT_SETUP([Stray symbols in brackets])
    564 AT_DATA_GRAMMAR([test.y],
    565 [[
    566 %%
    567 start: foo[ % /* aaa */ *&-.+\000\001\002\377 ] bar
    568   { s = $foo; }
    569 ]])
    570 AT_CHECK([[$PERL -pi -e 's/\\(\d{3})/chr(oct($1))/ge' test.y || exit 77]])
    571 AT_BISON_CHECK([-o test.c test.y], 1, [],
    572 [[test.y:11.13: error: invalid character in bracketed name: '%'
    573 test.y:11.25-27: error: invalid characters in bracketed name: '*&-'
    574 test.y:11.29-30: error: invalid characters in bracketed name: '+\0\001\002\377'
    575 ]])
    576 AT_CLEANUP
    577 
    578 #######################################################################
    579 
    580 AT_SETUP([Redundant words in LHS brackets])
    581 AT_DATA_GRAMMAR([test.y],
    582 [[
    583 %%
    584 start[a s]: foo;
    585 ]])
    586 AT_BISON_CHECK([-o test.c test.y], 1, [],
    587 [[test.y:11.9: error: unexpected identifier in bracketed name: 's'
    588 ]])
    589 AT_CLEANUP
    590 
    591 #######################################################################
    592 
    593 # Bison used to free twice the named ref for "a", since a single copy
    594 # was used in two rules.
    595 AT_SETUP([Factored LHS])
    596 AT_DATA_GRAMMAR([test.y],
    597 [[
    598 %%
    599 start[a]: "foo" | "bar";
    600 ]])
    601 AT_BISON_CHECK([-o test.c test.y])
    602 AT_CLEANUP
    603 
    604 #######################################################################
    605 
    606 AT_SETUP([Unresolved references])
    607 AT_DATA_GRAMMAR([test.y],
    608 [[
    609 %%
    610 stat:
    611   sym_a sym_b { func($sym.field); }
    612 | sym_a sym_b { func($<aa>sym.field); }
    613 | sym_a sym_b { func($[sym.field]); }
    614 | sym_a sym_b { func($<aa>[sym.field]); }
    615 | sym_a sym_b { func($sym); }
    616 | sym_a sym_b { func($<aa>sym); }
    617 | sym_a sym_b { func($[sym]); } sym_a sym_b { func($<aa>[sym]); }
    618 ;
    619 
    620 stat1:
    621   sym_a sym_b { func($sym-field); }
    622 | sym_a sym_b { func($<aa>sym-field); }
    623 | sym_a sym_b { func($[sym-field]); }
    624 | sym_a sym_b { func($<aa>[sym-field]); }
    625 | sym_a sym_b { func($sym); }
    626 | sym_a sym_b { func($<aa>sym); }
    627 | sym_a sym_b { func($[sym]); } sym_a sym_b { func($<aa>[sym]); }
    628 ;
    629 
    630 sym_a: 'a';
    631 sym_b: 'b';
    632 ]])
    633 AT_BISON_CHECK([-o test.c test.y], 1, [],
    634 [[test.y:12.22-31: error: invalid reference: '$sym.field'
    635 test.y:12.3-35:      symbol not found in production: sym
    636 test.y:13.22-35: error: invalid reference: '$<aa>sym.field'
    637 test.y:13.3-39:      symbol not found in production: sym
    638 test.y:14.22-33: error: invalid reference: '$[sym.field]'
    639 test.y:14.3-37:      symbol not found in production: sym.field
    640 test.y:15.22-37: error: invalid reference: '$<aa>[sym.field]'
    641 test.y:15.3-41:      symbol not found in production: sym.field
    642 test.y:16.22-25: error: invalid reference: '$sym'
    643 test.y:16.3-29:      symbol not found in production: sym
    644 test.y:17.22-29: error: invalid reference: '$<aa>sym'
    645 test.y:17.3-33:      symbol not found in production: sym
    646 test.y:18.22-27: error: invalid reference: '$[sym]'
    647 test.y:18.3-65:      symbol not found in production before $3: sym
    648 test.y:18.52-61: error: invalid reference: '$<aa>[sym]'
    649 test.y:18.3-65:      symbol not found in production: sym
    650 test.y:22.22-31: error: invalid reference: '$sym-field'
    651 test.y:22.3-35:      symbol not found in production: sym
    652 test.y:23.22-35: error: invalid reference: '$<aa>sym-field'
    653 test.y:23.3-39:      symbol not found in production: sym
    654 test.y:24.22-33: error: invalid reference: '$[sym-field]'
    655 test.y:24.3-37:      symbol not found in production: sym-field
    656 test.y:25.22-37: error: invalid reference: '$<aa>[sym-field]'
    657 test.y:25.3-41:      symbol not found in production: sym-field
    658 test.y:26.22-25: error: invalid reference: '$sym'
    659 test.y:26.3-29:      symbol not found in production: sym
    660 test.y:27.22-29: error: invalid reference: '$<aa>sym'
    661 test.y:27.3-33:      symbol not found in production: sym
    662 test.y:28.22-27: error: invalid reference: '$[sym]'
    663 test.y:28.3-65:      symbol not found in production before $3: sym
    664 test.y:28.52-61: error: invalid reference: '$<aa>[sym]'
    665 test.y:28.3-65:      symbol not found in production: sym
    666 ]])
    667 AT_CLEANUP
    668 
    669 #######################################################################
    670 
    671 AT_SETUP([[$ or @ followed by . or -]])
    672 AT_DATA([[test.y]],
    673 [[
    674 %%
    675 start:
    676   .field { $.field; }
    677 | 'a'    { @.field; }
    678 ;
    679 .field: ;
    680 ]])
    681 AT_BISON_CHECK([[test.y]], [[1]], [],
    682 [[test.y:4.12-18: error: invalid reference: '$.field'
    683 test.y:4.13:        syntax error after '$', expecting integer, letter, '_', '@<:@', or '$'
    684 test.y:4.3-8:       possibly meant: $[.field] at $1
    685 test.y:5.12-18: error: invalid reference: '@.field'
    686 test.y:5.13:        syntax error after '@', expecting integer, letter, '_', '@<:@', or '$'
    687 ]])
    688 AT_DATA([[test.y]],
    689 [[
    690 %%
    691 start:
    692   'a' { $-field; }
    693 | 'b' { @-field; }
    694 ;
    695 ]])
    696 AT_BISON_CHECK([[test.y]], [[0]], [],
    697 [[test.y:4.9: warning: stray '$'
    698 test.y:5.9: warning: stray '@'
    699 ]])
    700 AT_CLEANUP
    701