]> git.saurik.com Git - bison.git/blame - tests/c++.at
lalr1.cc: also handle syntax_error when calling yylex.
[bison.git] / tests / c++.at
CommitLineData
e019c247 1# Checking the output filenames. -*- Autotest -*-
7d424de1 2
34136e65 3# Copyright (C) 2004-2005, 2007-2012 Free Software Foundation, Inc.
e019c247 4
f16b0819 5# This program is free software: you can redistribute it and/or modify
e019c247 6# it under the terms of the GNU General Public License as published by
f16b0819
PE
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
e019c247
AD
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.
f16b0819 14#
e019c247 15# You should have received a copy of the GNU General Public License
f16b0819 16# along with this program. If not, see <http://www.gnu.org/licenses/>.
e019c247
AD
17
18AT_BANNER([[C++ Features.]])
19
20
76307410
AD
21## ---------- ##
22## Variants. ##
23## ---------- ##
24
25# AT_CHECK_VARIANTS([DIRECTIVES])
26# -------------------------------
27# Check the support of variants in C++, with the additional DIRECTIVES.
28m4_define([AT_CHECK_VARIANTS],
29[AT_SETUP([Variants $1])
30
31# Store strings and integers in a list of strings.
68c989de 32AT_DATA_GRAMMAR([list.yy],
76307410
AD
33[[%debug
34%skeleton "lalr1.cc"
35%defines
36%define variant
dddec537 37%locations
e5eb92e7
AD
38]m4_bpatsubst([$1], [\\n], [
39])[
76307410
AD
40
41%code requires // code for the .hh file
42{
43#include <list>
44#include <string>
45typedef std::list<std::string> strings_type;
46}
47
48%code // code for the .cc file
49{
76307410 50#include <iostream>
76307410
AD
51#include <sstream>
52
cb823b6f 53 static
dddec537
AD
54#if defined USE_LEX_SYMBOL
55 yy::parser::symbol_type yylex ();
56#else
57 yy::parser::token_type yylex (yy::parser::semantic_type* yylval,
58 yy::parser::location_type* yylloc);
59#endif
76307410 60
dddec537 61 // Printing a list of strings (for %printer).
76307410
AD
62 // Koening look up will look into std, since that's an std::list.
63 namespace std
64 {
65 std::ostream&
66 operator<<(std::ostream& o, const strings_type& s)
67 {
f5da8149
AD
68 o << '(';
69 for (strings_type::const_iterator i = s.begin(); i != s.end (); ++i)
70 {
71 if (i != s.begin ())
72 o << ", ";
73 o << *i;
74 }
75 return o << ')';
76307410
AD
76 }
77 }
78
79 // Conversion to string.
80 template <typename T>
81 inline
82 std::string
83 string_cast (const T& t)
84 {
85 std::ostringstream o;
86 o << t;
87 return o.str();
88 }
89}
90
f5da8149 91%token <::std::string> TEXT;
76307410 92%token <int> NUMBER;
76307410
AD
93%token END_OF_FILE 0;
94
f5da8149 95%type <::std::string> item;
cb823b6f
AD
96// Using the template type to exercize its parsing.
97// Starting with :: to ensure we don't output "<::" which starts by the
98// digraph for the left square bracket.
99%type <::std::list<std::string>> list result;
76307410 100
cb823b6f
AD
101%printer { debug_stream() << $][$; }
102 <int> <::std::string> <::std::list<::std::string>>;
76307410
AD
103%%
104
105result:
f5da8149 106 list { std::cout << $][1 << std::endl; }
76307410
AD
107;
108
109list:
cb823b6f
AD
110 /* nothing */ { /* Generates an empty string list */ }
111| list item { std::swap($][$,$][1); $$.push_back($][2); }
c4dc4c46 112| list error { std::swap($][$,$][1); }
76307410
AD
113;
114
115item:
cb823b6f 116 TEXT { std::swap($][$,$][1); }
c4dc4c46 117| NUMBER { if ($][1 == 3) YYERROR; else $][$ = string_cast($][1); }
76307410
AD
118;
119%%
120
dddec537 121#define STAGE_MAX 5
76307410 122static
dddec537
AD
123#if defined USE_LEX_SYMBOL
124yy::parser::symbol_type yylex()
125#else
126yy::parser::token_type yylex(yy::parser::semantic_type* yylval,
127 yy::parser::location_type* yylloc)
128#endif
76307410 129{
dddec537
AD
130 typedef yy::parser::token token;
131 typedef yy::parser::location_type location_type;
132 static int stage = -1;
133 ++stage;
134 if (stage == STAGE_MAX)
135 {
136#if defined USE_LEX_SYMBOL
137 return yy::parser::make_END_OF_FILE (location_type ());
e5eb92e7 138#else
dddec537
AD
139 *yylloc = location_type ();
140 return token::END_OF_FILE;
e5eb92e7 141#endif
dddec537
AD
142 }
143 else if (stage % 2)
144 {
145#if defined USE_LEX_SYMBOL
146 return yy::parser::make_NUMBER (stage, location_type ());
e5eb92e7 147#else
dddec537
AD
148# if defined ONE_STAGE_BUILD
149 yylval->build(stage);
150# else
76307410 151 yylval->build<int>() = stage;
dddec537
AD
152# endif
153 *yylloc = location_type ();
154 return token::NUMBER;
e5eb92e7 155#endif
dddec537
AD
156 }
157 else
158 {
159#if defined USE_LEX_SYMBOL
160 return yy::parser::make_TEXT (string_cast (stage), location_type ());
161#else
162# if defined ONE_STAGE_BUILD
163 yylval->build (string_cast (stage));
164# else
165 yylval->build<std::string>() = string_cast (stage);
166# endif
167 *yylloc = location_type ();
168 return token::TEXT;
169#endif
170 }
171 abort();
76307410
AD
172}
173
76307410 174void
dddec537 175yy::parser::error(const yy::parser::location_type&,
cb823b6f 176 const std::string& message)
76307410 177{
2ea7730c 178 std::cerr << message << std::endl;
76307410
AD
179}
180
e5eb92e7 181int
d73e55e0 182main (void)
76307410
AD
183{
184 yy::parser p;
185 p.set_debug_level(!!getenv("YYDEBUG"));
186 return p.parse();
187}
188]])
189
e5eb92e7 190AT_BISON_CHECK([-o list.cc list.yy])
76307410
AD
191AT_COMPILE_CXX([list])
192AT_CHECK([./list], 0,
f5da8149 193 [(0, 1, 2, 4)
76307410
AD
194])
195
196AT_CLEANUP
197])
198
199AT_CHECK_VARIANTS([])
0c90a1f5
AD
200AT_CHECK_VARIANTS([%define parse.assert])
201AT_CHECK_VARIANTS([[%define parse.assert %code {\n#define ONE_STAGE_BUILD\n}]])
202AT_CHECK_VARIANTS([[%define parse.assert %define lex_symbol %code {\n#define USE_LEX_SYMBOL\n}]])
4c6622c2 203AT_CHECK_VARIANTS([[%define parse.assert %define lex_symbol %code {\n#define USE_LEX_SYMBOL\n} %define api.tokens.prefix "TOK_"]])
76307410
AD
204
205
e019c247
AD
206## ----------------------- ##
207## Doxygen Documentation. ##
208## ----------------------- ##
209
210m4_define([AT_CHECK_DOXYGEN],
211[m4_case([$1],
212 [Public], [m4_pushdef([AT_DOXYGEN_PRIVATE], [NO])],
213 [Private], [m4_pushdef([AT_DOXYGEN_PRIVATE], [YES])],
e9690142 214 [m4_fatal([invalid argument: $1])])
e019c247
AD
215AT_SETUP([Doxygen $1 Documentation])
216
217AT_DATA([input.yy],
218[[%skeleton "lalr1.cc"
219%locations
220%debug
221%defines
222%%
223exp:;
224%%
225yy::parser::error (const location& l, const std::string& m)
226{
227 std::cerr << l << s << std::endl;
228}
229]])
230
da730230 231AT_BISON_CHECK([-o input.cc input.yy], 0)
e019c247
AD
232
233AT_DATA([Doxyfile],
234[# The PROJECT_NAME tag is a single word (or a sequence of words
235# surrounded by quotes) that should identify the project.
236PROJECT_NAME = "Bison C++ Parser"
237
238# The QUIET tag can be used to turn on/off the messages that are
239# generated by doxygen. Possible values are YES and NO. If left blank
240# NO is used.
241QUIET = YES
242
243# The WARNINGS tag can be used to turn on/off the warning messages
244# that are generated by doxygen. Possible values are YES and NO. If
245# left blank NO is used.
246WARNINGS = YES
247# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate
248# warnings for undocumented members. If EXTRACT_ALL is set to YES then
249# this flag will automatically be disabled.
250WARN_IF_UNDOCUMENTED = YES
251# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings
252# for potential errors in the documentation, such as not documenting
253# some parameters in a documented function, or documenting parameters
254# that don't exist or using markup commands wrongly.
255WARN_IF_DOC_ERROR = YES
256# The WARN_FORMAT tag determines the format of the warning messages
257# that doxygen can produce. The string should contain the $file,
258# $line, and $text tags, which will be replaced by the file and line
259# number from which the warning originated and the warning text.
260WARN_FORMAT = "$file:$line: $text"
261
262# If the EXTRACT_ALL tag is set to YES doxygen will assume all
263# entities in documentation are documented, even if no documentation
264# was available. Private class members and static file members will
265# be hidden unless the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set
266# to YES
267EXTRACT_ALL = YES
268
269# If the EXTRACT_PRIVATE tag is set to YES all private members of a
270# class will be included in the documentation.
271EXTRACT_PRIVATE = AT_DOXYGEN_PRIVATE
272
273# If the EXTRACT_STATIC tag is set to YES all static members of a file
274# will be included in the documentation.
275EXTRACT_STATIC = AT_DOXYGEN_PRIVATE
276])
277
278AT_CHECK([doxygen --version || exit 77], 0, ignore)
279AT_CHECK([doxygen], 0, [], [ignore])
280
281AT_CLEANUP
282
283m4_popdef([AT_DOXYGEN_PRIVATE])
284])# AT_CHECK_DOXYGEN
285
286AT_CHECK_DOXYGEN([Public])
287AT_CHECK_DOXYGEN([Private])
793fbca5 288
76307410 289
793fbca5
JD
290## ------------ ##
291## Namespaces. ##
292## ------------ ##
293
294# AT_CHECK_NAMESPACE(NAMESPACE-DECL, [COMPILE-ERROR])
295# ---------------------------------------------------
296# See if Bison can handle %define namespace "NAMESPACE-DECL". If COMPILE-ERROR
297# is specified, then Bison should accept the input, but compilation will fail,
298# so don't check compilation.
299m4_define([AT_CHECK_NAMESPACE],
300[
301
302AT_DATA_GRAMMAR([[input.y]],
303[[%language "C++"
304%defines
67501061 305%define api.namespace "]$1["
793fbca5
JD
306%union { int i; }
307%define global_tokens_and_yystype
2ea7730c 308%locations
793fbca5
JD
309
310%code {
311 // YYSTYPE contains a namespace reference.
d73e55e0 312 int yylex (YYSTYPE *lval, const ]$1[::parser::location_type*) {
793fbca5
JD
313 lval->i = 3;
314 return 0;
315 }
316}
317
318%%
319
320start: ;
321
322%%
323
324void
325]$1[::parser::error (const ]$1[::parser::location_type &loc,
326 const std::string &msg)
327{
328 std::cerr << "At " << loc << ": " << msg << std::endl;
329}
330
331int
332main (void)
333{
334 ]$1[::parser p;
335 return p.parse ();
336}
337]])
338
da730230 339AT_BISON_CHECK([[-o input.cc input.y]])
793fbca5
JD
340
341m4_if([$#], [1],
342[AT_COMPILE_CXX([[input]], [[input.cc]])
343AT_PARSER_CHECK([[./input]])])
344
345])
346
347AT_SETUP([[Relative namespace references]])
348AT_CHECK_NAMESPACE([[foo]])
349AT_CHECK_NAMESPACE([[foo::bar]])
350AT_CHECK_NAMESPACE([[foo::bar::baz]])
351AT_CLEANUP
352
353AT_SETUP([[Absolute namespace references]])
354AT_CHECK_NAMESPACE([[::foo]])
355AT_CHECK_NAMESPACE([[::foo::bar]])
356AT_CHECK_NAMESPACE([[::foo::bar::baz]])
357AT_CHECK_NAMESPACE([[ ::foo]])
358AT_CHECK_NAMESPACE([[ ::foo::bar]])
359AT_CHECK_NAMESPACE([[ ::foo::bar::baz]])
360AT_CLEANUP
361
362AT_SETUP([[Syntactically invalid namespace references]])
363AT_CHECK_NAMESPACE([[:foo:bar]], [[-]])
364AT_CHECK_NAMESPACE([[foo: :bar]], [[-]])
365# This one is interesting because `[3]' is encoded as `@<:@3@:>@', which
366# contains single occurrences of `:'.
367AT_CHECK_NAMESPACE([[foo[3]::bar::baz]], [[-]])
368AT_CHECK_NAMESPACE([[foo::bar,baz]], [[-]])
cb823b6f 369AT_CHECK_NAMESPACE([[foo::bar::(baz /* Pacify Emacs ) */]], [[-]])
793fbca5 370AT_CLEANUP
d59beda0
JD
371
372
373## -------------------------------------- ##
374## Syntax error discarding no lookahead. ##
375## -------------------------------------- ##
376
377# After a syntax error, lalr1.cc used to not check whether there
378# actually is a lookahead before discarding the lookahead. As a result,
379# it mistakenly invoked the destructor for the previous lookahead.
380
381AT_SETUP([[Syntax error discarding no lookahead]])
382
383AT_DATA_GRAMMAR([[input.yy]],
384[[%skeleton "lalr1.cc"
385
386%code {
387 #include <string>
a8c5aaa5 388 int yylex (yy::parser::semantic_type *);
d59beda0
JD
389 #define USE(Args)
390}
391
392%defines
d59beda0
JD
393%define parse.error verbose
394
395%nonassoc 'a' ;
396
397%destructor {
398 std::cerr << "Discarding 'a'." << std::endl;
399} 'a'
400
401%%
402
403start: error-reduce consistent-error 'a' { USE ($3); };
404
405error-reduce:
406 'a' 'a' consistent-error 'a' { USE (($1, $2, $4)); }
407| 'a' error { std::cerr << "Reducing 'a'." << std::endl; USE ($1); }
408;
409
410consistent-error:
411 'a'
412| /*empty*/ %prec 'a'
413;
414
5335b65a
JD
415// Provide another context in which all rules are useful so that this
416// test case looks a little more realistic.
417start: 'b' consistent-error ;
418
d59beda0
JD
419%%
420
421int
a8c5aaa5 422yylex (yy::parser::semantic_type *)
d59beda0
JD
423{
424 static char const *input = "aa";
425 return *input++;
426}
427
428void
a8c5aaa5 429yy::parser::error (const std::string &m)
d59beda0
JD
430{
431 std::cerr << m << std::endl;
432}
433
434int
435main (void)
436{
437 yy::parser parser;
438 return parser.parse ();
439}
440]])
5335b65a 441AT_BISON_CHECK([[-o input.cc input.yy]])
d59beda0
JD
442AT_COMPILE_CXX([[input]])
443# This used to print "Discarding 'a'." again at the end.
444AT_PARSER_CHECK([[./input]], [[1]], [[]],
445[[syntax error
446Discarding 'a'.
447Reducing 'a'.
448]])
449
450AT_CLEANUP
199a2d6d
AD
451
452
453## --------------------------- ##
454## Syntax error as exception. ##
455## --------------------------- ##
456
457AT_SETUP([[Syntax error as exception]])
458
459AT_DATA_GRAMMAR([[input.yy]],
460[[%skeleton "lalr1.cc"
461
462%code
463{
464 int yylex (yy::parser::semantic_type *);
465}
466
467%defines
468%define variant
469%define parse.error verbose
470%define parse.trace
471%%
472
473start:
474 thing
475| start thing
476;
477
478thing:
479 error { std::cerr << "caught error" << std::endl; }
480| item
481;
482
483item:
484 'a'
485| 's'
486 {
487 throw yy::parser::syntax_error("invalid expression");
488 }
489
490%%
491
492int
493yylex (yy::parser::semantic_type *)
494{
a6552c5d
AD
495 // 's': syntax error, 'l': lexical error.
496 static char const *input = "asal";
199a2d6d
AD
497 switch (int res = *input++)
498 {
a6552c5d
AD
499 case 'l':
500 throw yy::parser::syntax_error("invalid character");
199a2d6d
AD
501 default:
502 return res;
503 }
504}
505
506void
507yy::parser::error (const std::string &m)
508{
509 std::cerr << "error: " << m << std::endl;
510}
511
512int
513main ()
514{
515 yy::parser parser;
516 parser.set_debug_level(!!getenv("YYDEBUG"));
517 return parser.parse ();
518}
519]])
520AT_BISON_CHECK([[-o input.cc input.yy]])
521AT_COMPILE_CXX([[input]])
522
523AT_PARSER_CHECK([[./input]], [[0]], [[]],
524[[error: invalid expression
525caught error
a6552c5d
AD
526error: invalid character
527caught error
199a2d6d
AD
528]])
529
530AT_CLEANUP