# Checking GLR Parsing: Regression Tests           -*- Autotest -*-

# Copyright (C) 2002-2003, 2005-2007, 2009-2015, 2018-2020 Free Software
# Foundation, Inc.

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

AT_BANNER([[GLR Regression Tests]])

# You might wonder what's the point of having names different for each
# test case.  When some endlessly loop, it is nice to see their "name"
# in ps.

# AT_YYPARSE_DEFINE
# -----------------
# Wrap the C++ parser in a C-like function interface.
m4_pushdef([AT_YYPARSE_DEFINE],
[AT_CXX_IF([[
static int
yyparse ()
{
  ]AT_NAMESPACE[::parser p;]AT_DEBUG_IF([[
  int debug = !!getenv ("YYDEBUG");
  p.set_debug_level (debug);]])[
  return p.parse ();
}
]])])


## ---------------------------- ##
## Badly Collapsed GLR States.  ##
## ---------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Badly Collapsed GLR States: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])

AT_DATA_GRAMMAR([glr-regr1.y],
[[/* Regression Test: Improper state compression */
/* Reported by Scott McPeak */

%define api.value.type {int}

%code {
#include <assert.h>

static ]AT_YYSTYPE[ exprMerge (]AT_YYSTYPE[ x0, ]AT_YYSTYPE[ x1);
]AT_YYERROR_DECLARE[
]AT_YYLEX_DECLARE[
}

%define parse.assert
%define parse.trace
%glr-parser
%expect 1
]$1[

/* -------- productions ------ */
%%

StartSymbol: E  { $$=0; }                   %merge <exprMerge>
           ;

E: E 'P' E { $$=1; printf("E -> E 'P' E\n"); }  %merge <exprMerge>
 | 'B'     { $$=2; printf("E -> 'B'\n"); }      %merge <exprMerge>
 ;



/* ---------- C code ----------- */
%%

static ]AT_YYSTYPE[ exprMerge (]AT_YYSTYPE[ x0, ]AT_YYSTYPE[ x1)
{
  (void) x0;
  (void) x1;
  printf ("<OR>\n");
  return 0;
}

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[

const char *input = YY_NULLPTR;

]AT_YYLEX_PROTOTYPE[
{
  ]AT_USE_LEX_ARGS[
  return *input++;
}

int
main (int argc, const char* argv[])
{
  assert (argc == 2); (void) argc;
  input = argv[1];
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  return yyparse ();
}
]])

AT_FULL_COMPILE([glr-regr1])
AT_PARSER_CHECK([[glr-regr1 BPBPB]], 0,
[[E -> 'B'
E -> 'B'
E -> E 'P' E
E -> 'B'
E -> E 'P' E
E -> 'B'
E -> E 'P' E
E -> E 'P' E
<OR>
]])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## -------------------------------------------------------------- ##
## Improper handling of embedded actions and $-N in GLR parsers.  ##
## -------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Improper handling of embedded actions and dollar(-N) in GLR parsers: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])

AT_DATA_GRAMMAR([glr-regr2a.y],
[[/* Regression Test: Improper handling of embedded actions and $-N  */
/* Reported by S. Eken */

%define api.value.type {char *}
%code {
  #include <ctype.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <assert.h>
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
}

%define parse.assert
%define parse.trace
%glr-parser
%expect 2
]$1[

%%

command:
    's' var 't'
       { printf ("Variable: '%s'\n", $][2); }
    'v' 'x' 'q'
       { free ($][2); }
  | 's' var_list 't' 'e'
       { printf ("Varlist: '%s'\n", $][2); free ($][2); }
  | 's' var 't' var_printer 'x'
       { free ($][2); }
  ;

var:
  'V'
     { $$ = $][1; }
  ;

var_list:
  var
    { $$ = $][1; }
  | var ',' var_list
    {
      char *s = YY_CAST (char *, realloc ($][1, strlen ($][1) + 1 + strlen ($][3) + 1));
      strcat (s, ",");
      strcat (s, $][3);
      free ($][3);
      $$ = s;
    }
  ;

var_printer: 'v'
   { printf ("Variable: '%s'\n", $-1); }

%%
]AT_YYERROR_DEFINE[
FILE *input;

]AT_YYLEX_PROTOTYPE[
{
  char buf[50];
  ]AT_USE_LEX_ARGS[
  assert (!feof (stdin));
  switch (fscanf (input, " %1[a-z,]", buf))
  {
  case 1:
    return buf[0];
  case EOF:
    return 0;
  default:
    if (fscanf (input, "%49s", buf) != 1)
      return 0;
    else
      {
        char *s;
        assert (strlen (buf) < sizeof buf - 1);
        s = YY_CAST (char *, malloc (strlen (buf) + 1));
        strcpy (s, buf);
        ]AT_VAL[ = s;
        return 'V';
      }
    break;
  }
}

]AT_YYPARSE_DEFINE[

int
main (int argc, char **argv)
{
  int res;
  input = stdin;
  if (argc == 2 && !(input = fopen (argv[1], "r")))
    return 3;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  res = yyparse ();
  if (argc == 2 && fclose (input))
    return 4;
  return res;
}
]])

AT_FULL_COMPILE([glr-regr2a],,,,[-rall])

AT_DATA([input1.txt],
[[s VARIABLE_1 t v x q
]])
AT_PARSER_CHECK([[glr-regr2a input1.txt]], 0,
[[Variable: 'VARIABLE_1'
]])

AT_DATA([input2.txt],
[[s VARIABLE_1 , ANOTHER_VARIABLE_2 t e
]])
AT_PARSER_CHECK([[glr-regr2a input2.txt]],
0,
[[Varlist: 'VARIABLE_1,ANOTHER_VARIABLE_2'
]])

AT_DATA([input3.txt],
[[s VARIABLE_3 t v x
]])
AT_PARSER_CHECK([[glr-regr2a input3.txt]], 0,
[[Variable: 'VARIABLE_3'
]])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])


## --------------------------------------------- ##
## Improper merging of GLR delayed action sets.  ##
## --------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Improper merging of GLR delayed action sets: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])

AT_DATA_GRAMMAR([glr-regr3.y],
[[/* Regression Test: Improper merging of GLR delayed action sets.  */
/* Reported by M. Rosien */

%code {
#include <stdarg.h>
#include <assert.h>

static int MergeRule (int x0, int x1);
]AT_YYERROR_DECLARE[
]AT_YYLEX_DECLARE[

#define RULE(x) (1 << (x))

}

%define parse.assert
%define parse.trace
%glr-parser
%expect 1
%expect-rr 2
]$1[

%token BAD_CHAR
%token P1 P2 T1 T2 T3 T4 O1 O2

%%

S : P1 T4 O2 NT6 P2  { printf ("Result: %x\n", $][4); }
;

NT1 : P1 T1 O1 T2 P2 { $$ = RULE(2); }  %merge<MergeRule>
;

NT2 : NT1             { $$ = RULE(3); } %merge<MergeRule>
    | P1 NT1 O1 T3 P2 { $$ = RULE(4); } %merge<MergeRule>
;

NT3 : T3              { $$ = RULE(5); } %merge<MergeRule>
    | P1 NT1 O1 T3 P2 { $$ = RULE(6); } %merge<MergeRule>
;

NT4 : NT3              { $$ = RULE(7); } %merge<MergeRule>
    | NT2              { $$ = RULE(8); } %merge<MergeRule>
    | P1 NT2 O1 NT3 P2 { $$ = RULE(9); } %merge<MergeRule>
;

NT5 : NT4              { $$ = RULE(10); } %merge<MergeRule>
;

NT6 : P1 NT1 O1 T3 P2  { $$ = RULE(11) | $][2; } %merge<MergeRule>
    | NT5              { $$ = RULE(12) | $][1; } %merge<MergeRule>
;

%%

static int
MergeRule (int x0, int x1)
{
  return x0 | x1;
}
]AT_YYERROR_DEFINE[

FILE *input = YY_NULLPTR;

int P[] = { ]AT_TOKEN([P1])[, ]AT_TOKEN([P2])[ };
int O[] = { ]AT_TOKEN([O1])[, ]AT_TOKEN([O2])[ };
int T[] = { ]AT_TOKEN([T1])[, ]AT_TOKEN([T2])[, ]AT_TOKEN([T3])[, ]AT_TOKEN([T4])[ };

]AT_YYLEX_PROTOTYPE[
{
  char inp[3];
  ]AT_USE_LEX_ARGS[
  assert (!feof (stdin));
  if (fscanf (input, "%2s", inp) == EOF)
    return 0;
  switch (inp[0])
    {
    case 'p': return P[inp[1] - '1'];
    case 't': return T[inp[1] - '1'];
    case 'o': return O[inp[1] - '1'];
    }
  return ]AT_TOKEN([BAD_CHAR])[;
}

]AT_YYPARSE_DEFINE[

int
main (int argc, char* argv[])
{
  int res;
  input = stdin;
  if (argc == 2 && !(input = fopen (argv[1], "r")))
    return 3;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  res = yyparse ();
  if (argc == 2 && fclose (input))
    return 4;
  return res;
}
]])

AT_FULL_COMPILE([glr-regr3],,,,[-rall])

AT_DATA([input.txt],
[[p1 t4 o2 p1 p1 t1 o1 t2 p2 o1 t3 p2 p2
]])
AT_PARSER_CHECK([[glr-regr3 input.txt]],
0,
[[Result: 1c04
]])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])


## ---------------------------------------------------------------------- ##
## Duplicate representation of merged trees.  See                         ##
## <http://lists.gnu.org/archive/html/help-bison/2005-07/msg00013.html>.  ##
## ---------------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Duplicate representation of merged trees: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])

AT_DATA_GRAMMAR([glr-regr4.y],
[[
%define parse.assert
%define parse.trace
%union { char *ptr; }
%type <ptr> S A A1 A2 B
%glr-parser
%expect-rr 2
]$1[

%code {
  #include <string.h>
  static char *merge (]AT_YYSTYPE[, ]AT_YYSTYPE[);
  static char *make_value (char const *, char const *);
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  static char *ptrs[100];
  static char **ptrs_next = ptrs;
}

%%

tree: S { printf ("%s\n", $][1); } ;

S:
  A   %merge<merge> { $$ = make_value ("S", $][1); }
  | B %merge<merge> { $$ = make_value ("S", $][1); }
  ;

A:
  A1   %merge<merge> { $$ = make_value ("A", $][1); }
  | A2 %merge<merge> { $$ = make_value ("A", $][1); }
  ;

A1: 'a' { $$ = make_value ("A1", "'a'"); } ;
A2: 'a' { $$ = make_value ("A2", "'a'"); } ;
B:  'a' { $$ = make_value ("B", "'a'");  } ;

%%
]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_DEFINE(["a"])[

int
main (void)
{
  int status = -1;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  status = yyparse ();
  while (ptrs_next != ptrs)
    free (*--ptrs_next);
  return status;
}

static char *
make_value (char const *parent, char const *child)
{
  char const format[] = "%s <- %s";
  char *value = *ptrs_next++ =
    YY_CAST (char *, malloc (strlen (parent) + strlen (child) + sizeof format));
  sprintf (value, format, parent, child);
  return value;
}

static char *
merge (]AT_YYSTYPE[ s1, ]AT_YYSTYPE[ s2)
{
  char const format[] = "merge{ %s and %s }";
  char *value = *ptrs_next++ =
    YY_CAST (char *, malloc (strlen (s1.ptr) + strlen (s2.ptr) + sizeof format));
  sprintf (value, format, s1.ptr, s2.ptr);
  return value;
}
]])

AT_FULL_COMPILE([glr-regr4],,,,[-rall])

AT_PARSER_CHECK([[glr-regr4]], 0,
[[merge{ S <- merge{ A <- A1 <- 'a' and A <- A2 <- 'a' } and S <- B <- 'a' }
]], [])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])


## ------------------------------------------------------------------------- ##
## User destructor for unresolved GLR semantic value.  See                   ##
## <http://lists.gnu.org/archive/html/bison-patches/2005-08/msg00016.html>.  ##
## ------------------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([User destructor for unresolved GLR semantic value: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr5.y],
[[
%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  enum { MAGIC_VALUE = -1057808125 }; /* originally chosen at random */
}

%define parse.assert
%define parse.trace
%glr-parser
%expect 0
%expect-rr 1
]$1[

%union { int value; }
%type <value> start

%destructor {
  if ($$ != MAGIC_VALUE)
    {
      fprintf (stderr, "Bad destructor call.\n");
      exit (EXIT_FAILURE);
    }
} start

%%

start:
   'a' { $$ = MAGIC_VALUE; }
   | 'a' { $$ = MAGIC_VALUE; }
   ;

%%
]AT_YYERROR_DEFINE[
]AT_YYLEX_DEFINE(["a"])[
]AT_MAIN_DEFINE[
]])

AT_FULL_COMPILE([glr-regr5],,,, [-rall])

AT_PARSER_CHECK([[glr-regr5]], 1, [],
[Ambiguity detected.
Option 1,
  start -> <Rule 1, tokens 1 .. 1>
    'a' <tokens 1 .. 1>

Option 2,
  start -> <Rule 2, tokens 1 .. 1>
    'a' <tokens 1 .. 1>

syntax is ambiguous
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------------------------- ##
## User destructor after an error during a split parse.  See                 ##
## <http://lists.gnu.org/archive/html/bison-patches/2005-08/msg00029.html>.  ##
## ------------------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([User destructor after an error during a split parse: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr6.y],
[[
%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
}

%define parse.assert
%define parse.trace
%glr-parser
%expect-rr 1
]$1[

%union { int value; }
%type <value> 'a'

%destructor {
  printf ("Destructor called.\n");
} 'a'

%%

start: 'a' | 'a' ;

%%
]AT_YYERROR_DEFINE[
]AT_YYLEX_DEFINE(["a"])[
]AT_MAIN_DEFINE[
]])

AT_FULL_COMPILE([glr-regr6],,,, [-rall])

AT_PARSER_CHECK([[glr-regr6]], 1,
[Destructor called.
],
[Ambiguity detected.
Option 1,
  start -> <Rule 1, tokens 1 .. 1>
    'a' <tokens 1 .. 1>

Option 2,
  start -> <Rule 2, tokens 1 .. 1>
    'a' <tokens 1 .. 1>

syntax is ambiguous
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------------------------- ##
## Duplicated user destructor for lookahead.  See                            ##
## <http://lists.gnu.org/archive/html/bison-patches/2005-08/msg00035.html>.  ##
## ------------------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Duplicated user destructor for lookahead: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])

AT_DATA_GRAMMAR([glr-regr7.y],
[[
%code requires {
  typedef struct count_node {
    int count;
    struct count_node *prev;
  } count_node;
}

%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  #define YYSTACKEXPANDABLE 0
  static count_node *tail;
}

%define parse.assert
%define parse.trace
%glr-parser
%expect-rr 2
]$1[

%union { count_node *node; }
%type <node> 'a'

%destructor {
  if ($$->count++)
    fprintf (stderr, "Destructor called on same value twice.\n");
} 'a'

%%

start:
    stack1 start
  | stack2 start
  | %empty
  ;
stack1: 'a' ;
stack2: 'a' ;

%%

]AT_YYLEX_PROTOTYPE[
{
  ]AT_USE_LEX_ARGS[
  ]AT_VAL[.node = YY_CAST (count_node*, malloc (sizeof *]AT_VAL[.node));
  if (!]AT_VAL[.node)
    {
      fprintf (stderr, "Test inconclusive.\n");
      exit (EXIT_FAILURE);
    }
  ]AT_VAL[.node->count = 0;
  ]AT_VAL[.node->prev = tail;
  tail = ]AT_VAL[.node;
  return 'a';
}

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[

int
main (void)
{
  int status;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  status = yyparse ();
  while (tail)
    {
      count_node *prev = tail->prev;
      free (tail);
      tail = prev;
    }
  return status;
}
]])

AT_FULL_COMPILE([glr-regr7],,,, [-rall])

AT_PARSER_CHECK([[glr-regr7]], 2, [],
[memory exhausted
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------------------------- ##
## Incorrect default location for empty right-hand sides.  Adapted from bug  ##
## report by Claudia Hermann.                                                ##
## See http://lists.gnu.org/archive/html/bug-bison/2005-10/msg00069.html and ##
## http://lists.gnu.org/archive/html/bug-bison/2005-10/msg00072.html         ##
## ------------------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Incorrectly initialized location for empty right-hand side in GLR: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser %locations $1])

AT_DATA_GRAMMAR([glr-regr8.y],
[[
%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
}

%define parse.assert
%define parse.trace
%glr-parser
%expect-rr 1
]$1[

%token T_CONSTANT
%token T_PORT
%token T_SIGNAL

%%


PortClause      : T_PORT InterfaceDeclaration T_PORT
                { printf("%d/%d - %d/%d - %d/%d\n",
                         @1.]AT_FIRST_COLUMN[, @1.]AT_LAST_COLUMN[,
                         @2.]AT_FIRST_COLUMN[, @2.]AT_LAST_COLUMN[,
                         @3.]AT_FIRST_COLUMN[, @3.]AT_LAST_COLUMN[); }
        ;

InterfaceDeclaration    : OptConstantWord       %dprec 1
        | OptSignalWord %dprec 2
        ;

OptConstantWord : %empty
        | T_CONSTANT
        ;

OptSignalWord   : %empty
                { printf("empty: %d/%d\n", @$.]AT_FIRST_COLUMN[, @$.]AT_LAST_COLUMN[); }
        | T_SIGNAL
        ;

%%

]AT_YYERROR_DEFINE[
static int lexIndex;

]AT_YYLEX_PROTOTYPE[
{
  ]AT_USE_LEX_ARGS[
  lexIndex += 1;
  switch (lexIndex)
    {
    default:
      abort ();
    case 1:
      ]AT_LOC_FIRST_COLUMN[ = 1;
      ]AT_LOC_LAST_COLUMN[ = 9;
      return ]AT_TOKEN([T_PORT])[;
    case 2:
      ]AT_LOC_FIRST_COLUMN[ = 13;
      ]AT_LOC_LAST_COLUMN[ = 17;
      return ]AT_TOKEN([T])[_PORT;
    case 3:
      return 0;
    }
}

]AT_MAIN_DEFINE[
]])

AT_FULL_COMPILE([glr-regr8],,,, [-rall])

AT_PARSER_CHECK([[glr-regr8]], 0,
[empty: 9/9
1/9 - 9/9 - 13/17
],
[])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------------------------- ##
## No users destructors if stack 0 deleted.  See                             ##
## <http://lists.gnu.org/archive/html/bison-patches/2005-09/msg00109.html>.  ##
## ------------------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([No users destructors if stack 0 deleted: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr9.y],
[[
%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
# define YYSTACKEXPANDABLE 0
  static int tokens = 0;
  static int destructors = 0;
# define USE(Var)
}

%define parse.assert
%define parse.trace
%glr-parser
%expect-rr 2
]$1[

%union { int dummy; }
%type <dummy> 'a'

%destructor {
  destructors += 1;
} 'a'

%%

start:
    ambig0 'a'   { destructors += 2; USE ($][2); }
  | ambig1 start { destructors += 1; }
  | ambig2 start { destructors += 1; }
  ;

ambig0: 'a' ;
ambig1: 'a' ;
ambig2: 'a' ;

%%

]AT_YYLEX_PROTOTYPE[
{
  ]AT_USE_LEX_ARGS[
  tokens += 1;
  return 'a';
}

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[

int
main (void)
{
  int status;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  status = yyparse ();
  if (tokens != destructors)
    {
      fprintf (stderr, "Tokens = %d, Destructors = %d\n", tokens, destructors);
      return 10;
    }
  return status;
}
]])

AT_FULL_COMPILE([glr-regr9],,,, [-rall])

# Exit 2: memory exhausted.
AT_PARSER_CHECK([[glr-regr9]], 2, [],
[memory exhausted
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------ ##
## Corrupted semantic options if user action cuts parse.  ##
## ------------------------------------------------------ ##

m4_pushdef([AT_TEST],
[AT_SETUP([Corrupted semantic options if user action cuts parse: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr10.y],
[[
%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  #define GARBAGE_SIZE 50
  static char garbage[GARBAGE_SIZE];
}

%define parse.assert
%define parse.trace
%glr-parser
%expect-rr 1
]$1[

%union { char *ptr; }
%type <ptr> start

%%

start:
    %dprec 2 { $$ = garbage; YYACCEPT; }
  | %dprec 1 { $$ = garbage; YYACCEPT; }
  ;

%%
]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_DEFINE[

int
main (void)
{
  int i;
  for (i = 0; i < GARBAGE_SIZE; i+=1)
    garbage[i] = 108;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  return yyparse ();
}
]])

AT_FULL_COMPILE([glr-regr10],,,, [-rall])

AT_PARSER_CHECK([[glr-regr10]], 0, [], [])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## --------------------------------------------------- ##
## Undesirable destructors if user action cuts parse.  ##
## --------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Undesirable destructors if user action cuts parse: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr11.y],
[[
%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  static int destructors = 0;
# define USE(val)
}

%define parse.assert
%define parse.trace
%glr-parser
%expect-rr 1
]$1[

%union { int dummy; }
%type <int> 'a'
%destructor { destructors += 1; } 'a'

%%

start:
    'a' %dprec 2 { USE ($][1); destructors += 1; YYACCEPT; }
  | 'a' %dprec 1 { USE ($][1); destructors += 1; YYACCEPT; }
  ;

%%

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_DEFINE(["a"])[

int
main (void)
{
  int status;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  status = yyparse ();
  if (destructors != 1)
    {
      fprintf (stderr, "Destructor calls: %d\n", destructors);
      return 1;
    }
  return status;
}
]])

AT_FULL_COMPILE([glr-regr11],,,, [-rall])

AT_PARSER_CHECK([[glr-regr11]], 0, [], [])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## -------------------------------------------------- ##
## Leaked semantic values if user action cuts parse.  ##
## -------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Leaked semantic values if user action cuts parse: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr12.y],
[[
%define parse.assert
%define parse.trace
%glr-parser
%expect 1
%expect-rr 1
]$1[

%union { int dummy; }
%token PARENT_RHS_AFTER
%type <dummy> parent_rhs_before merged PARENT_RHS_AFTER
%destructor { parent_rhs_before_value = 0; } parent_rhs_before
%destructor { merged_value = 0; } merged
%destructor { parent_rhs_after_value = 0; } PARENT_RHS_AFTER

%code {
# include <assert.h>
  static int merge (]AT_YYSTYPE[, ]AT_YYSTYPE[);
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  static int parent_rhs_before_value = 0;
  static int merged_value = 0;
  static int parent_rhs_after_value = 0;
# define USE(val)
}

%%

start:
  alt1 %dprec 1
  | alt2 %dprec 2
  ;

alt1:
  PARENT_RHS_AFTER {
    USE ($][1);
    parent_rhs_after_value = 0;
  }
  ;

alt2:
  parent_rhs_before merged PARENT_RHS_AFTER {
    USE (($][1, $][2, $][3));
    parent_rhs_before_value = 0;
    merged_value = 0;
    parent_rhs_after_value = 0;
  }
  ;

parent_rhs_before:
  {
    USE ($$);
    parent_rhs_before_value = 1;
  }
  ;

merged:
  %merge<merge> {
    USE ($$);
    merged_value = 1;
  }
  | cut %merge<merge> {
    USE ($$);
    merged_value = 1;
  }
  ;

cut: { YYACCEPT; } ;

%%

static int
merge (]AT_YYSTYPE[ s1, ]AT_YYSTYPE[ s2)
{
  /* Not invoked. */
  return s1.dummy + s2.dummy;
}

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_DEFINE([{ ]AT_TOKEN([PARENT_RHS_AFTER])[, 0 }],
 [if (res == ]AT_TOKEN([PARENT_RHS_AFTER])[)
    parent_rhs_after_value = 1;])[

int
main (void)
{
  int status;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  status = yyparse ();
  if (parent_rhs_before_value)
    {
      fprintf (stderr, "'parent_rhs_before' destructor not called.\n");
      status = 1;
    }
  if (merged_value)
    {
      fprintf (stderr, "'merged' destructor not called.\n");
      status = 1;
    }
  if (parent_rhs_after_value)
    {
      fprintf (stderr, "'PARENT_RHS_AFTER' destructor not called.\n");
      status = 1;
    }
  return status;
}
]])

AT_FULL_COMPILE([glr-regr12],,,, [-rall])

AT_PARSER_CHECK([[glr-regr12]], 0, [], [])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------------------------- ##
## Incorrect lookahead during deterministic GLR.  See                        ##
## <http://lists.gnu.org/archive/html/help-bison/2005-07/msg00017.html> and  ##
## <http://lists.gnu.org/archive/html/bison-patches/2006-01/msg00060.html>.  ##
## ------------------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Incorrect lookahead during deterministic GLR: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser %locations $1])
AT_DATA_GRAMMAR([glr-regr13.y],
[[
/* Tests:
     - Defaulted state with initial yychar: yychar == YYEMPTY.
     - Nondefaulted state: yychar != YYEMPTY.
     - Defaulted state after lookahead: yychar != YYEMPTY.
     - Defaulted state after shift: yychar == YYEMPTY.
     - User action changing the lookahead.  */

%code {
  #include <assert.h>
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  static void
  print_lookahead (int yychr, ]AT_YYSTYPE[ *yylvalp, ]AT_YYLTYPE[ *yyllocp,
                   char const *reduction);
  #define USE(value)
}

%define parse.assert
%define parse.trace
%locations
%glr-parser
]$1[

%union { char value; }
%type <value> 'a' 'b'

%%

start:
  defstate_init defstate_shift 'b' change_lookahead 'a' {
    USE ($][3);
    print_lookahead (yychar, &yylval, &yylloc, "start <- defstate_init defstate_shift 'b'");
  }
  ;
defstate_init:
  {
    print_lookahead (yychar, &yylval, &yylloc, "defstate_init <- empty string");
  }
  ;
defstate_shift:
  nondefstate defstate_look 'a' {
    USE ($][3);
    print_lookahead (yychar, &yylval, &yylloc, "defstate_shift <- nondefstate defstate_look 'a'");
  }
  ;
defstate_look:
  {
    print_lookahead (yychar, &yylval, &yylloc, "defstate_look <- empty string");
  }
  ;
nondefstate:
  {
    print_lookahead (yychar, &yylval, &yylloc, "nondefstate <- empty string");
  }
  | 'b' {
    USE ($][1);
    print_lookahead (yychar, &yylval, &yylloc, "nondefstate <- 'b'");
  }
  ;
change_lookahead:
  {
    yychar = 'a';
  }
  ;

%%

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_DEFINE(["ab"],
                 []AT_VAL[.value = YY_CAST (char, res + 'A' - 'a')])[

static void
print_lookahead (int yychr, ]AT_YYSTYPE[ *yylvalp, ]AT_YYLTYPE[ *yyllocp,
                 char const *reduction)
{
  printf ("%s:\n  yychar=", reduction);
  if (yychr == ]AT_TOKEN([YYEMPTY])[)
    printf ("YYEMPTY");
  else if (yychr == ]AT_TOKEN([YYEOF])[)
    printf ("YYEOF");
  else
    {
      printf ("'%c', yylval='", yychr);
      if (yylvalp->value > ' ')
        printf ("%c", yylvalp->value);
      printf ("', yylloc=(%d,%d),(%d,%d)",
              yyllocp->]AT_FIRST_LINE[, yyllocp->]AT_FIRST_COLUMN[,
              yyllocp->]AT_LAST_LINE[, yyllocp->]AT_LAST_COLUMN[);
    }
  printf ("\n");
}

int
main (void)
{
]AT_CXX_IF([], [[
  yychar = '#'; /* Not a token in the grammar.  */
  yylval.value = '!';
]])[
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  return yyparse ();
}
]])

AT_FULL_COMPILE([glr-regr13],,,, [-rall])

AT_PARSER_CHECK([[glr-regr13]], 0,
[defstate_init <- empty string:
  yychar=YYEMPTY
nondefstate <- empty string:
  yychar='a', yylval='A', yylloc=(1,1),(1,1)
defstate_look <- empty string:
  yychar='a', yylval='A', yylloc=(1,1),(1,1)
defstate_shift <- nondefstate defstate_look 'a':
  yychar=YYEMPTY
start <- defstate_init defstate_shift 'b':
  yychar=YYEMPTY
], [])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------- ##
## Incorrect lookahead during nondeterministic GLR.  ##
## ------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Incorrect lookahead during nondeterministic GLR: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser %locations $1])

AT_DATA_GRAMMAR([glr-regr14.y],
[[
/* Tests:
     - Conflicting actions (split-off parse, which copies lookahead need,
       which is necessarily yytrue) and nonconflicting actions (non-split-off
       parse) for nondefaulted state: yychar != YYEMPTY.
     - Merged deferred actions (lookahead need and RHS from different stack
       than the target state) and nonmerged deferred actions (same stack).
     - Defaulted state after lookahead: yychar != YYEMPTY.
     - Defaulted state after shift: yychar == YYEMPTY.
     - yychar != YYEMPTY but lookahead need is yyfalse (a previous stack has
       seen the lookahead but current stack has not).
     - Exceeding stack capacity (stack explosion), and thus reallocating
       lookahead need array.
   Note that it does not seem possible to see the initial yychar value during
   nondeterministic operation since:
     - In order to preserve the initial yychar, only defaulted states may be
       entered.
     - If only defaulted states are entered, there are no conflicts, so
       nondeterministic operation does not start.  */

%define parse.assert
%define parse.trace
%type <value> 'a' 'b' 'c' 'd' stack_explosion
%glr-parser
%expect 0
%expect-rr 5
]$1[
%locations

%union { char value; }

%code {
  #include <assert.h>
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  static void
  print_lookahead (int yychr, ]AT_YYSTYPE[ *yylvalp, ]AT_YYLTYPE[ *yyllocp,
                   char const *reduction);
  static char merge (]AT_YYSTYPE[, ]AT_YYSTYPE[);
  #define USE(value)
}

%%

start:
  merge 'c' stack_explosion {
    USE ($][2); USE ($][3);
    print_lookahead (yychar, &yylval, &yylloc, "start <- merge 'c' stack_explosion");
  }
  ;

/* When merging the 2 deferred actions, the lookahead needs are different.  */
merge:
  nonconflict1 'a' 'b' nonconflict2 %dprec 1 {
    USE ($][2); USE ($][3);
    print_lookahead (yychar, &yylval, &yylloc, "merge <- nonconflict1 'a' 'b' nonconflict2");
  }
  | conflict defstate_look 'a' nonconflict2 'b' defstate_shift %dprec 2 {
    USE ($][3); USE ($][5);
    print_lookahead (yychar, &yylval, &yylloc, "merge <- conflict defstate_look 'a' nonconflict2 'b'"
                      " defstate_shift");
  }
  ;

nonconflict1:
  {
    print_lookahead (yychar, &yylval, &yylloc, "nonconflict1 <- empty string");
  }
  ;
nonconflict2:
  {
    print_lookahead (yychar, &yylval, &yylloc, "nonconflict2 <- empty string");
  }
  | 'a' {
    USE ($][1);
    print_lookahead (yychar, &yylval, &yylloc, "nonconflict2 <- 'a'");
  }
  ;
conflict:
  {
    print_lookahead (yychar, &yylval, &yylloc, "conflict <- empty string");
  }
  ;
defstate_look:
  {
    print_lookahead (yychar, &yylval, &yylloc, "defstate_look <- empty string");
  }
  ;

/* yychar != YYEMPTY but lookahead need is yyfalse.  */
defstate_shift:
  {
    print_lookahead (yychar, &yylval, &yylloc, "defstate_shift <- empty string");
  }
  ;

stack_explosion:
  { $$ = '\0'; }
  | alt1 stack_explosion %merge<merge> { $$ = $][2; }
  | alt2 stack_explosion %merge<merge> { $$ = $][2; }
  | alt3 stack_explosion %merge<merge> { $$ = $][2; }
  ;
alt1:
  'd' no_look {
    USE ($][1);
    if (yychar != 'd' && yychar != ]AT_GLR2_CC_IF([yy::parser::token::])[YYEOF)
      {
        fprintf (stderr, "Incorrect lookahead during stack explosion.\n");
      }
  }
  ;
alt2:
  'd' no_look {
    USE ($][1);
    if (yychar != 'd' && yychar != ]AT_GLR2_CC_IF([yy::parser::token::])[YYEOF)
      {
        fprintf (stderr, "Incorrect lookahead during stack explosion.\n");
      }
  }
  ;
alt3:
  'd' no_look {
    USE ($][1);
    if (yychar != 'd' && yychar != ]AT_GLR2_CC_IF([yy::parser::token::])[YYEOF)
      {
        fprintf (stderr, "Incorrect lookahead during stack explosion.\n");
      }
  }
  ;
no_look:
  {
    if (yychar != ]AT_GLR2_CC_IF([yy::parser::token::])[YYEMPTY)
      {
        fprintf (stderr,
                 "Found lookahead where shouldn't during stack explosion.\n");
      }
  }
  ;

%%

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_PROTOTYPE[
{
  ]AT_USE_LEX_ARGS[
  static char const input[] = "abcdddd";
  static int toknum = 0;
  assert (toknum < YY_CAST (int, sizeof input));
  ]AT_LOC_FIRST_LINE[ = ]AT_LOC_LAST_LINE[ = 1;
  ]AT_LOC_FIRST_COLUMN[ = ]AT_LOC_LAST_COLUMN[ = toknum + 1;
  ]AT_VAL[.value = YY_CAST (char, input[toknum] + 'A' - 'a');
  return input[toknum++];
}

static char
merge (]AT_YYSTYPE[ s1, ]AT_YYSTYPE[ s2)
{
  return YY_CAST (char, s1.value + s2.value);
}

/* FIXME: Factor duplicate.  Possibly use yy_symbol_print. */
static void
print_lookahead (int yychr, ]AT_YYSTYPE[ *yylvalp, ]AT_YYLTYPE[ *yyllocp,
                 char const *reduction)
{
  printf ("%s:\n  yychar=", reduction);
  if (yychr == ]AT_TOKEN([YYEMPTY])[)
    printf ("YYEMPTY");
  else if (yychr == ]AT_TOKEN([YYEOF])[)
    printf ("YYEOF");
  else
    {
      printf ("'%c', yylval='", yychr);
      if (yylvalp->value > ' ')
        printf ("%c", yylvalp->value);
      printf ("', yylloc=(%d,%d),(%d,%d)",
              yyllocp->]AT_FIRST_LINE[, yyllocp->]AT_FIRST_COLUMN[,
              yyllocp->]AT_LAST_LINE[, yyllocp->]AT_LAST_COLUMN[);
    }
  printf ("\n");
}

int
main (void)
{
]AT_CXX_IF([], [[
  yychar = '#'; /* Not a token in the grammar.  */
  yylval.value = '!';
]])[
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  return yyparse ();
}
]])

AT_FULL_COMPILE([glr-regr14],,,, [-rall])

AT_PARSER_CHECK([[glr-regr14]], 0,
[conflict <- empty string:
  yychar='a', yylval='A', yylloc=(1,1),(1,1)
defstate_look <- empty string:
  yychar='a', yylval='A', yylloc=(1,1),(1,1)
nonconflict2 <- empty string:
  yychar='b', yylval='B', yylloc=(1,2),(1,2)
defstate_shift <- empty string:
  yychar=YYEMPTY
merge <- conflict defstate_look 'a' nonconflict2 'b' defstate_shift:
  yychar=YYEMPTY
start <- merge 'c' stack_explosion:
  yychar=YYEOF
], [])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------- ##
## Leaked semantic values when reporting ambiguity.  ##
## ------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Leaked semantic values when reporting ambiguity: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])

AT_DATA_GRAMMAR([glr-regr15.y],
[[
%define parse.assert
%define parse.trace
%glr-parser
%expect 0
%expect-rr 2
]$1[

%destructor { parent_rhs_before_value = 0; } parent_rhs_before

%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  static int parent_rhs_before_value = 0;
# define USE(val)
}

%%

start:
  alt1 %dprec 1
  | alt2 %dprec 2
  ;

/* This stack must be merged into the other stacks *last* (added at the
   beginning of the semantic options list) so that yyparse will choose to clean
   it up rather than the tree for which some semantic actions have been
   performed.  Thus, if yyreportAmbiguity longjmp's to yyparse, the values from
   those other trees are not cleaned up.  */
alt1: ;

alt2:
  parent_rhs_before ambiguity {
    USE ($][1);
    parent_rhs_before_value = 0;
  }
  ;

parent_rhs_before:
  {
    USE ($$);
    parent_rhs_before_value = 1;
  }
  ;

ambiguity: ambiguity1 | ambiguity2 ;
ambiguity1: ;
ambiguity2: ;

%%
]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_DEFINE[

int
main (void)
{
  int status;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  status = yyparse () != 1;
  if (parent_rhs_before_value)
    {
      fprintf (stderr, "'parent_rhs_before' destructor not called.\n");
      status = 1;
    }
  return status;
}
]])

AT_FULL_COMPILE([glr-regr15],,,, [-rall])

AT_PARSER_CHECK([[glr-regr15]], 0, [],
[Ambiguity detected.
Option 1,
  ambiguity -> <Rule 6, empty>
    ambiguity1 -> <Rule 8, empty>

Option 2,
  ambiguity -> <Rule 7, empty>
    ambiguity2 -> <Rule 9, empty>

syntax is ambiguous
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------------ ##
## Leaked lookahead after nondeterministic parse syntax error.  ##
## ------------------------------------------------------------ ##

m4_pushdef([AT_TEST],
[AT_SETUP([Leaked lookahead after nondeterministic parse syntax error: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr16.y],
[[
%define parse.assert
%define parse.trace
%glr-parser
%expect 0
%expect-rr 1
]$1[

%destructor { lookahead_value = 0; } 'b'

%code {
# include <assert.h>
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
  static int lookahead_value = 0;
# define USE(val)
}

%%

start: alt1 'a' | alt2 'a' ;
alt1: ;
alt2: ;

%%

]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[
]AT_YYLEX_DEFINE(["ab"],
  [if (res == 'b')
    lookahead_value = 1])[

int
main (void)
{
  int status;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  status = yyparse () != 1;
  if (lookahead_value)
    {
      fprintf (stderr, "Lookahead destructor not called.\n");
      status = 1;
    }
  return status;
}
]])

AT_FULL_COMPILE([glr-regr16],,,, [-rall])

AT_PARSER_CHECK([[glr-regr16]], 0, [],
[syntax error
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------- ##
## Uninitialized location when reporting ambiguity.  ##
## ------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Uninitialized location when reporting ambiguity: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser %locations $1])

AT_DATA_GRAMMAR([glr-regr17.y],
[[
%define parse.assert
%define parse.trace
%glr-parser
%expect 0
%expect-rr 3
]$1[
%locations
%define parse.error verbose

%union { int dummy; }

%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
}

%%

/* Tests the case of an empty RHS that has inherited the location of the
   previous nonterminal, which is unresolved.  That location is reported as the
   last position of the ambiguity.  */
start: ambig1 empty1 | ambig2 empty2 ;

/* Tests multiple levels of yyresolveLocations recursion.  */
ambig1: sub_ambig1 | sub_ambig2 ;
ambig2: sub_ambig1 | sub_ambig2 ;

/* Tests the case of a non-empty RHS as well as the case of an empty RHS that
   has inherited the initial location.  The empty RHS's location is reported as
   the first position in the ambiguity.  */
sub_ambig1: empty1 'a' 'b' ;
sub_ambig2: empty2 'a' 'b' ;
empty1: ;
empty2: ;

%%
# include <assert.h>

]AT_YYERROR_DEFINE[

]AT_YYLEX_PROTOTYPE[
{
  static char const input[] = "ab";
  static int toknum = 0;
  ]AT_USE_LEX_ARGS[
  assert (toknum < YY_CAST (int, sizeof input));
  lvalp->dummy = 0;
  ]AT_LOC_FIRST_LINE[ = ]AT_LOC_LAST_LINE[ = 2;
  ]AT_LOC_FIRST_COLUMN[ = toknum + 1;
  ]AT_LOC_LAST_COLUMN[ = ]AT_LOC_FIRST_COLUMN[ + 1;
  return input[toknum++];
}

]AT_MAIN_DEFINE[
]])

AT_FULL_COMPILE([glr-regr17],,,, [-rall])

AT_PARSER_CHECK([[glr-regr17]], 1, [],
[Ambiguity detected.
Option 1,
  start -> <Rule 1, tokens 1 .. 2>
    ambig1 -> <Rule 4, tokens 1 .. 2>
      sub_ambig2 -> <Rule 8, tokens 1 .. 2>
        empty2 -> <Rule 10, empty>
        'a' <tokens 1 .. 1>
        'b' <tokens 2 .. 2>
    empty1 -> <Rule 9, empty>

Option 2,
  start -> <Rule 2, tokens 1 .. 2>
    ambig2 -> <Rule 6, tokens 1 .. 2>
      sub_ambig2 -> <Rule 8, tokens 1 .. 2>
        empty2 -> <Rule 10, empty>
        'a' <tokens 1 .. 1>
        'b' <tokens 2 .. 2>
    empty2 -> <Rule 10, empty>

1.1-2.2: syntax is ambiguous
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c" %define api.pure])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------------------------------------------------- ##
## Missed %merge type warnings when LHS type is declared later.  ##
## ------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Missed %merge type warnings when LHS type is declared later: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([glr-regr18.y],
[[%define parse.assert
%define parse.trace
%glr-parser
]$1[

%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
}

%union {
  int type1;
  int type2;
  int type3;
}
]AT_CXX_IF([[
// In C++ we need one more line for the line numbers to match.
]])[
%%

sym1: sym2 %merge<merge> { $$ = $][1; } ;
sym2: sym3 %merge<merge> { $$ = $][1; } ;
sym3: %merge<merge> { $$ = 0; } ;

%type <type1> sym1;
%type <type2> sym2;
%type <type3> sym3;

%%
]AT_YYERROR_DEFINE[
]AT_YYLEX_DEFINE[
]AT_MAIN_DEFINE[
]])

AT_BISON_CHECK([[-o glr-regr18.c -rall -fcaret glr-regr18.y]], 1, [],
[[glr-regr18.y:30.18-24: error: result type clash on merge function 'merge': <type2> != <type1>
   30 | sym2: sym3 %merge<merge> { $$ = $][1; } ;
      |                  ^~~~~~~
glr-regr18.y:29.18-24: note: previous declaration
   29 | sym1: sym2 %merge<merge> { $$ = $][1; } ;
      |                  ^~~~~~~
glr-regr18.y:31.13-19: error: result type clash on merge function 'merge': <type3> != <type2>
   31 | sym3: %merge<merge> { $$ = 0; } ;
      |             ^~~~~~~
glr-regr18.y:30.18-24: note: previous declaration
   30 | sym2: sym3 %merge<merge> { $$ = $][1; } ;
      |                  ^~~~~~~
]])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ------------------- ##
## Ambiguity reports.  ##
## ------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Ambiguity reports: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser %debug $1])
AT_DATA_GRAMMAR([input.y],
[[%code {
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
}

%define parse.assert
%define parse.trace
%debug
%glr-parser
%expect 0
%expect-rr 1
]$1[
]AT_CXX_IF([[
// In C++ we need two more lines for the line numbers in the trace to match.
]])[
%%

start:
  'a' b 'c' d
| 'a' b 'c' d
;
b: 'b';
d: %empty;
%%
]AT_YYERROR_DEFINE[
]AT_YYLEX_DEFINE(["abc"])[
]AT_MAIN_DEFINE[
]])

AT_FULL_COMPILE([input])

AT_PARSER_CHECK([[input --debug]], 1, [],
[Starting parse
Entering state 0
Reading a token
Next token is token 'a' ()
Shifting token 'a' ()
Entering state 1
Reading a token
Next token is token 'b' ()
Shifting token 'b' ()
Entering state 3
Reducing stack 0 by rule 3 (line 30):
   $][1 = token 'b' ()
-> $][$ = nterm b ()
Entering state 4
Reading a token
Next token is token 'c' ()
Shifting token 'c' ()
Entering state 6
Reducing stack 0 by rule 4 (line 31):
-> $][$ = nterm d ()
Entering state 7
Reading a token
Now at end of input.
Stack 0 Entering state 7
Now at end of input.
Splitting off stack 1 from 0.
Reduced stack 1 by rule 2 (line 28); action deferred.  Now in state 2.
Stack 1 Entering state 2
Now at end of input.
Reduced stack 0 by rule 1 (line 27); action deferred.  Now in state 2.
Merging stack 0 into stack 1.
Stack 1 Entering state 2
Now at end of input.
Removing dead stacks.
Rename stack 1 -> 0.
On stack 0, shifting token "end of file" ()
Stack 0 now in state #5
Ambiguity detected.
Option 1,
  start -> <Rule 1, tokens 1 .. 3>
    'a' <tokens 1 .. 1>
    b <tokens 2 .. 2>
    'c' <tokens 3 .. 3>
    d <empty>

Option 2,
  start -> <Rule 2, tokens 1 .. 3>
    'a' <tokens 1 .. 1>
    b <tokens 2 .. 2>
    'c' <tokens 3 .. 3>
    d <empty>

syntax is ambiguous
Cleanup: popping token "end of file" ()
Cleanup: popping unresolved nterm start ()
Cleanup: popping nterm d ()
Cleanup: popping token 'c' ()
Cleanup: popping nterm b ()
Cleanup: popping token 'a' ()
])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])



## ----------------------------------------------------------------- ##
## Predicates.                                                       ##
##                                                                   ##
## http://lists.gnu.org/archive/html/bug-bison/2013-10/msg00004.html ##
## http://lists.gnu.org/archive/html/bug-bison/2018-05/msg00033.html ##
## ----------------------------------------------------------------- ##

m4_pushdef([AT_TEST],
[AT_SETUP([Predicates: $1])

AT_BISON_OPTION_PUSHDEFS([%glr-parser $1])
AT_DATA_GRAMMAR([input.y],
[[%define parse.assert
%define parse.trace
%glr-parser
%define parse.error verbose
%expect-rr 1
]$1[

%code
{
  #include <assert.h>
  #include <stdbool.h>
  bool new_syntax = false;
  const char *input = YY_NULLPTR;
  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE[
}
%%
widget:
  %? {new_syntax} 'w' id new_args  { printf("new"); }
| %?{!new_syntax} 'w' id old_args  { printf("old"); }
;
id: 'i';
new_args: 'n';
old_args: 'o';
%%
]AT_YYERROR_DEFINE[
]AT_YYPARSE_DEFINE[

]AT_YYLEX_PROTOTYPE[
{
  ]AT_USE_LEX_ARGS[
  return *input++;
}

int
main (int argc, const char* argv[])
{
  assert (argc == 2); (void) argc;
  // First char decides whether new, or old syntax.
  // Then the input.
  new_syntax = argv[1][0] == 'N';
  input = argv[1] + 1;
  if (getenv ("YYDEBUG"))
    yydebug = 1;
  return yyparse ();
}
]])

AT_FULL_COMPILE([input])
AT_PARSER_CHECK([[input Nwin]], [0], [new])
AT_PARSER_CHECK([[input Owin]], [1], [], [[syntax error, unexpected 'n', expecting 'o'
]])
AT_PARSER_CHECK([[input Owio]], [0], [old])
AT_PARSER_CHECK([[input Nwio]], [1], [], [[syntax error, unexpected 'o', expecting 'n'
]])

AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])

AT_TEST([%skeleton "glr.c"])
AT_TEST([%skeleton "glr.cc"])
AT_TEST([%skeleton "glr2.cc"])

m4_popdef([AT_TEST])


m4_popdef([AT_YYPARSE_DEFINE])
