1# Checking Push Parsing.                            -*- Autotest -*-
2
3# Copyright (C) 2007, 2009-2015, 2018-2021 Free Software Foundation,
4# Inc.
5
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
19AT_BANNER([[Push Parsing Tests]])
20
21## -------------------------------- ##
22## Memory Leak for Early Deletion.  ##
23## -------------------------------- ##
24
25AT_SETUP([[Memory Leak for Early Deletion]])
26
27# Requires Valgrind.
28AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
29AT_DATA_GRAMMAR([[input.y]],
30[[
31%{
32  #include <assert.h>
33  #include <stdio.h>
34  #define YYINITDEPTH 1
35]AT_YYERROR_DECLARE[
36%}
37
38%define api.pure
39%define api.push-pull push
40
41%%
42
43start: 'a' 'b' 'c' ;
44
45%%
46
47]AT_YYERROR_DEFINE[
48
49int
50main (void)
51{
52  yypstate *ps;
53
54  /* Make sure we don't try to free ps->yyss in this case.  */
55  ps = yypstate_new ();
56  yypstate_delete (ps);
57
58  /* yypstate_delete used to leak ps->yyss if the stack was reallocated but the
59     parse did not return on success, syntax error, or memory exhaustion.  */
60  ps = yypstate_new ();
61  assert (yypush_parse (ps, 'a', YY_NULLPTR) == YYPUSH_MORE);
62  yypstate_delete (ps);
63
64  ps = yypstate_new ();
65  assert (yypush_parse (ps, 'a', YY_NULLPTR) == YYPUSH_MORE);
66  assert (yypush_parse (ps, 'b', YY_NULLPTR) == YYPUSH_MORE);
67  yypstate_delete (ps);
68
69  return 0;
70}
71]])
72AT_BISON_OPTION_POPDEFS
73
74AT_BISON_CHECK([[-o input.c input.y]])
75AT_COMPILE([[input]])
76AT_PARSER_CHECK([[input]])
77
78AT_CLEANUP
79
80## --------------------------- ##
81## Multiple impure instances.  ##
82## --------------------------- ##
83
84AT_SETUP([[Multiple impure instances]])
85
86m4_pushdef([AT_MULTIPLE_IMPURE_INSTANCES_CHECK], [
87AT_BISON_OPTION_PUSHDEFS([%define api.push-pull $1])
88AT_DATA_GRAMMAR([[input.y]],
89[[
90%{
91  #include <assert.h>
92  #include <stdio.h>
93]AT_YYERROR_DECLARE[
94]m4_if([$1], [[both]], [AT_YYLEX_DECLARE([])])[
95%}
96
97%define api.push-pull ]$1[
98
99%%
100
101start: ;
102
103%%
104]AT_YYERROR_DEFINE[
105]m4_if([$1], [[both]], [AT_YYLEX_DEFINE])[
106
107int
108main (void)
109{
110  int i;
111  for (i = 0; i < 2; ++i)
112    {
113      yypstate *ps = yypstate_new ();
114      assert (ps);
115      assert (yypstate_new () == YY_NULLPTR);
116      ]m4_if([$1], [[both]], [[assert (yyparse () == 2)]])[;
117      yychar = 0;
118      assert (yypush_parse (ps) == 0);
119      assert (yypstate_new () == YY_NULLPTR);
120      ]m4_if([$1], [[both]], [[assert (yyparse () == 2)]])[;
121      yypstate_delete (ps);
122    }
123
124  return 0;
125}
126]])
127
128AT_BISON_CHECK([[-o input.c input.y]])
129AT_COMPILE([[input]])
130AT_PARSER_CHECK([[input]])
131AT_BISON_OPTION_POPDEFS
132])
133
134AT_MULTIPLE_IMPURE_INSTANCES_CHECK([[both]])
135AT_MULTIPLE_IMPURE_INSTANCES_CHECK([[push]])
136
137m4_popdef([AT_MULTIPLE_IMPURE_INSTANCES_CHECK])
138
139AT_CLEANUP
140
141## ----------------------- ##
142## Unsupported Skeletons.  ##
143## ----------------------- ##
144
145AT_SETUP([[Unsupported Skeletons]])
146
147AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
148AT_DATA([[input.y]],
149[[%glr-parser
150%define api.push-pull push
151%%
152start: ;
153]])
154AT_BISON_OPTION_POPDEFS
155
156AT_BISON_CHECK([[input.y]], [[1]], [],
157[[input.y:2.1-26: error: %define variable 'api.push-pull' is not used
158]])
159
160AT_CLEANUP
161
162
163## -------------- ##
164## Pstate reuse.  ##
165## -------------- ##
166
167AT_SETUP([[Pstate reuse]])
168
169# Make sure that when a single pstate is used for multiple successive
170# parses, no state from a previous run leaks into the following one.
171#
172# See https://lists.gnu.org/r/bug-bison/2021-03/msg00000.html.
173
174AT_BISON_OPTION_PUSHDEFS([%define api.push-pull push])
175AT_DATA_GRAMMAR([[input.y]],
176[[%code top {
177  #include <stdlib.h>
178  #include <string.h>
179
180  static char *string_concat (char *a, char *b);
181  ]AT_YYERROR_DECLARE[
182}
183
184%define parse.trace
185%define api.pure full
186%define api.push-pull push
187%expect 0
188
189%union {
190  char *sval;
191};
192%destructor { free ($$); } <sval>
193%printer { fprintf (yyo, "%s", $$); } <sval>
194
195%token <sval> RAW
196%token EOL
197
198%type <sval> text
199
200%%
201
202line
203  : text EOL  { printf ("text: %s\n", $1); free ($1); YYACCEPT; };
204
205text
206  : RAW       { $$ = $1; }
207  | text RAW  { $$ = string_concat ($1, $2); }
208  ;
209
210%%
211]AT_YYERROR_DEFINE[
212
213static char *
214string_concat (char *a, char *b)
215{
216  size_t la = strlen (a);
217  size_t lb = strlen (b);
218  char *res = YY_CAST (char *, malloc (la + lb + 1));
219  strcpy (res, a);
220  strcpy (res + la, b);
221  free (a);
222  free (b);
223  return res;
224}
225
226static int
227push (yypstate *ps, yytoken_kind_t kind, const char *str)
228{
229  YYSTYPE lval;
230  lval.sval = str ? strdup (str) :  YY_NULLPTR;
231  switch (yypush_parse (ps, kind, &lval))
232    {
233    case 0:
234      return 0;
235    case YYPUSH_MORE:
236      // parsing incomplete, but valid; parser not reset
237      return 0;
238    case 1:
239      // YYABORT or syntax invalid; parser is reset
240      fprintf (stderr, "invalid input, but no error was thrown\n");
241      return 1;
242    case 2:
243      // memory exhaustion; parser is reset
244      fprintf (stderr, "memory exhaustion during yypush_parse\n");
245      return 1;
246    }
247  return 1;
248}
249
250int
251main (void)
252{
253  yydebug = !!getenv ("YYDEBUG");
254  yypstate *ps = yypstate_new ();
255
256#define PUSH(Kind, Val)                         \
257  do {                                          \
258    if (push (ps, Kind, Val))                   \
259      return 1;                                 \
260  } while (0)
261
262  PUSH (RAW, "te");
263  PUSH (RAW, "xt");
264  PUSH (EOL,  YY_NULLPTR);
265
266  PUSH (RAW, "te");
267  PUSH (RAW, "xt");
268  PUSH (EOL,  YY_NULLPTR);
269
270  yypstate_delete (ps);
271
272  return 0;
273}
274]])
275
276AT_FULL_COMPILE([input])
277AT_CHECK([./input], 0,
278[[text: text
279text: text
280]])
281
282AT_BISON_OPTION_POPDEFS
283AT_CLEANUP
284