glr2.cc: custom error messages
[bison.git] / tests / calc.at
blob5e463042e45b63d949610e26d587990d0430b8ec
1 # Simple calculator.                         -*- Autotest -*-
3 # Copyright (C) 2000-2015, 2018-2021 Free Software Foundation, Inc.
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.
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.
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 ## ---------------------------------------------------- ##
19 ## Compile the grammar described in the documentation.  ##
20 ## ---------------------------------------------------- ##
23 m4_pushdef([AT_CALC_MAIN],  [AT_LANG_DISPATCH([$0], $@)])
24 m4_pushdef([AT_CALC_YYLEX], [AT_LANG_DISPATCH([$0], $@)])
26 # -------------- #
27 # AT_DATA_CALC.  #
28 # -------------- #
31 # _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES])
32 # -----------------------------------------------
33 # Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or
34 # 'calc-lex.cc'.
36 # Don't call this macro directly, because it contains some occurrences
37 # of '$1' etc. which will be interpreted by m4.  So you should call it
38 # with $1, $2, and $3 as arguments, which is what AT_DATA_CALC_Y does.
40 # When %header is not passed, generate a single self-contained file.
41 # Otherwise, generate three: calc.y with the parser, calc-lex.c with
42 # the scanner, and calc-main.c with "main()".  This is in order to
43 # stress the use of the generated parser header.  To avoid code
44 # duplication, AT_CALC_YYLEX and AT_CALC_MAIN contain the body of these
45 # two later files.
46 m4_pushdef([_AT_DATA_CALC_Y],
47 [m4_if([$1$2$3], $[1]$[2]$[3], [],
48        [m4_fatal([$0: Invalid arguments: $@])])dnl
49 AT_LANG_DISPATCH([$0], $@)])
53 ## ----------- ##
54 ## Calc in C.  ##
55 ## ----------- ##
57 # AT_CALC_MAIN(c).
58 m4_define([AT_CALC_MAIN(c)],
59 [[#include <assert.h>
60 #include <stdlib.h> /* exit */
61 #include <string.h> /* strcmp */
62 #include <unistd.h>
64 ]AT_CXX_IF([[
65 namespace
67   /* A C++ ]AT_NAME_PREFIX[parse that simulates the C signature.  */
68   int
69   ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([semantic_value *result, int *count, int *nerrs]))[
70   {
71     ]AT_NAME_PREFIX[::parser parser]AT_PARAM_IF([ (result, count, nerrs)])[;
72   #if ]AT_API_PREFIX[DEBUG
73     parser.set_debug_level (1);
74   #endif
75     return parser.parse ();
76   }
78 ]])[
80 /* Value of the last computation.  */
81 semantic_value global_result = 0;
82 /* Total number of computations.  */
83 int global_count = 0;
84 /* Total number of errors.  */
85 int global_nerrs = 0;
87 #ifndef EX_NOINPUT
88 # define EX_NOINPUT 66
89 #endif
91 static FILE *
92 open_file (const char *file)
94   FILE *res = (file && *file && strcmp (file, "-")) ? fopen (file, "r") : stdin;
95   if (!res)
96     {
97       perror (file);
98       exit (EX_NOINPUT);
99     }
100   return res;
103 /* A C main function.  */
105 main (int argc, const char **argv)
106 {]AT_PARAM_IF([[
107   semantic_value result = 0;
108   int count = 0;
109   int nerrs = 0;]])[
110   int status = 0;
112   /* This used to be alarm (10), but that isn't enough time for a July
113      1995 vintage DEC Alphastation 200 4/100 system, according to
114      Nelson H. F. Beebe.  100 seconds was enough for regular users,
115      but the Hydra build farm, which is heavily loaded needs more.  */
117   alarm (200);
119 ]AT_CXX_IF([], [AT_DEBUG_IF([  ]AT_NAME_PREFIX[debug = 1;])])[
121   {
122     int i;
123     for (i = 1; i < argc; ++i)
124       {
125 ]AT_MULTISTART_IF([[
126         if (!strcmp (argv[i], "--exp") && i+1 < argc)
127           {
128             input = open_file (argv[i+1]);
129             ignore_eol = 1;
130             ]AT_NAME_PREFIX[parse_exp_t res = ]AT_NAME_PREFIX[parse_exp ();
131             printf ("exp => %d (status: %d, errors: %d)\n",
132                     res.yystatus == 0 ? res.yyvalue : 0, res.yystatus, res.yynerrs);
133             status = res.yystatus;
134             ++i;
135           }
136         else if (!strcmp (argv[i], "--num") && i+1 < argc)
137           {
138             input = open_file (argv[i+1]);
139             ignore_eol = 1;
140             ]AT_NAME_PREFIX[parse_NUM_t res = ]AT_NAME_PREFIX[parse_NUM ();
141             printf ("NUM => %d (status: %d, errors: %d)\n",
142                     res.yystatus == 0 ? res.yyvalue : 0, res.yystatus, res.yynerrs);
143             status = res.yystatus;
144             ++i;
145           }
146         else]])[
147           {
148             input = open_file (argv[i]);
149             status = ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([[&result, &count, &nerrs]])[);
150           }
151         if (input != stdin && fclose (input))
152           perror ("fclose");
153       }
154   }
155 ]AT_PARAM_IF([[
156   assert (global_result == result); (void) result;
157   assert (global_count  == count);  (void) count;
158   assert (global_nerrs  == nerrs);  (void) nerrs;
159   printf ("final: %d %d %d\n", global_result, global_count, global_nerrs);]])[
160   return status;
165 # AT_CALC_YYLEX(c).
166 m4_define([AT_CALC_YYLEX(c)],
167 [[#include <ctype.h>
169 ]AT_YYLEX_DECLARE_EXTERN[
171 ]AT_LOCATION_IF([
172 static AT_YYLTYPE last_yylloc;
174 static int
175 get_char (]AT_YYLEX_FORMALS[)
177   int res = getc (input);
178   ]AT_USE_LEX_ARGS[;
179 ]AT_LOCATION_IF([
180   last_yylloc = AT_LOC;
181   if (res == '\n')
182     {
183       AT_LOC_LAST_LINE++;
184       AT_LOC_LAST_COLUMN = 1;
185     }
186   else
187     AT_LOC_LAST_COLUMN++;
189   return res;
192 static void
193 unget_char (]AT_YYLEX_PRE_FORMALS[ int c)
195   ]AT_USE_LEX_ARGS[;
196 ]AT_LOCATION_IF([
197   /* Wrong when C == '\n'. */
198   AT_LOC = last_yylloc;
200   ungetc (c, input);
203 static int
204 read_integer (]AT_YYLEX_FORMALS[)
206   int c = get_char (]AT_YYLEX_ARGS[);
207   int res = 0;
209   ]AT_USE_LEX_ARGS[;
210   while (isdigit (c))
211     {
212       res = 10 * res + (c - '0');
213       c = get_char (]AT_YYLEX_ARGS[);
214     }
216   unget_char (]AT_YYLEX_PRE_ARGS[ c);
218   return res;
222 /*---------------------------------------------------------------.
223 | Lexical analyzer returns an integer on the stack and the token |
224 | NUM, or the ASCII character read if not a number.  Skips all   |
225 | blanks and tabs, returns 0 for EOF.                            |
226 `---------------------------------------------------------------*/
228 ]AT_YYLEX_PROTOTYPE[
230   int c;
231   /* Skip white spaces.  */
232   do
233     {
234 ]AT_LOCATION_IF([
235       AT_LOC_FIRST_COLUMN = AT_LOC_LAST_COLUMN;
236       AT_LOC_FIRST_LINE   = AT_LOC_LAST_LINE;
238     }
239   while ((c = get_char (]AT_YYLEX_ARGS[)) == ' '
240          || c == '\t'
241          || (ignore_eol && c == '\n'));
243   /* Process numbers.   */
244   if (isdigit (c))
245     {
246       unget_char (]AT_YYLEX_PRE_ARGS[ c);
247       ]AT_VAL[.]AT_VALUE_UNION_IF([NUM], [ival])[ = read_integer (]AT_YYLEX_ARGS[);
248       return ]AT_TOKEN([NUM])[;
249     }
251   /* Return end-of-file.  */
252   if (c == EOF)
253     return ]AT_TOKEN([CALC_EOF])[;
255   /* An explicit error raised by the scanner. */
256   if (c == '#')
257     {]AT_LOCATION_IF([
258       fprintf (stderr, "%d.%d: ",
259                AT_LOC_FIRST_LINE, AT_LOC_FIRST_COLUMN);])[
260       fputs ("syntax error: invalid character: '#'\n", stderr);
261       return ]AT_TOKEN(AT_API_PREFIX[][error])[;
262     }
264   /* Return single chars. */
265   return c;
270 m4_define([_AT_DATA_CALC_Y(c)],
271 [AT_DATA_GRAMMAR([calc.y.tmp],
272 [[/* Infix notation calculator--calc */
273 ]$4[
274 %code requires
276 ]AT_LOCATION_TYPE_SPAN_IF([[
277   typedef struct
278   {
279     int l;
280     int c;
281   } Point;
283   typedef struct
284   {
285     Point first;
286     Point last;
287   } Span;
289 # define YYLLOC_DEFAULT(Current, Rhs, N)                                \
290   do                                                                    \
291     if (N)                                                              \
292       {                                                                 \
293         (Current).first = YYRHSLOC (Rhs, 1).first;                      \
294         (Current).last  = YYRHSLOC (Rhs, N).last;                       \
295       }                                                                 \
296     else                                                                \
297       {                                                                 \
298         (Current).first = (Current).last = YYRHSLOC (Rhs, 0).last;      \
299       }                                                                 \
300   while (0)
302 ]AT_C_IF(
303 [[#include <stdio.h>
304 void location_print (FILE *o, Span s);
305 #define LOCATION_PRINT location_print
306 ]])[
308 ]])[
309   /* Exercise pre-prologue dependency to %union.  */
310   typedef int semantic_value;
313 ]AT_VALUE_UNION_IF([],
314 [[/* Exercise %union. */
315 %union
317   semantic_value ival;
318 };]])[
319 %printer { ]AT_CXX_IF([[yyo << $$]],
320                       [[fprintf (yyo, "%d", $$)]])[; } <]AT_VALUE_UNION_IF([int], [ival])[>;
322 %code provides
324   #include <stdio.h>
325   /* The input.  */
326   extern FILE *input;
327   /* Whether \n is a blank.  */
328   extern int ignore_eol;
329   extern semantic_value global_result;
330   extern int global_count;
331   extern int global_nerrs;
334 %code
336   #include <assert.h>
337   #include <string.h>
338   #define USE(Var)
340   FILE *input;
341   int ignore_eol = 0;
342   static int power (int base, int exponent);
344   ]AT_YYERROR_DECLARE[
345   ]AT_YYLEX_DECLARE_EXTERN[
347   ]AT_TOKEN_TRANSLATE_IF([[
348 #define N_
349     static
350     const char *
351     _ (const char *cp)
352     {
353       if (strcmp (cp, "end of input") == 0)
354         return "end of file";
355       else if (strcmp (cp, "number") == 0)
356         return "nombre";
357       else
358         return cp;
359     }
360   ]])[
363 ]AT_LOCATION_TYPE_SPAN_IF([[
364 %initial-action
366   @$.first.l = @$.first.c = 1;
367   @$.last = @$.first;
368 }]])[
370 /* Bison Declarations */
371 %token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
372 %token <]AT_VALUE_UNION_IF([int], [ival])[> NUM   "number"
373 %type  <]AT_VALUE_UNION_IF([int], [ival])[> exp
375 %nonassoc '='   /* comparison          */
376 %left '-' '+'
377 %left '*' '/'
378 %precedence NEG /* negation--unary minus */
379 %right '^'      /* exponentiation        */
381 /* Grammar follows */
383 input:
384   line
385 | input line         { ]AT_PARAM_IF([++*count; ++global_count;])[ }
388 line:
389   '\n'
390 | exp '\n'           { ]AT_PARAM_IF([*result = global_result = $1;], [USE ($1);])[ }
393 exp:
394   NUM
395 | exp '=' exp
396   {
397     if ($1 != $3)]AT_LANG_CASE(
398       [c], [[
399       {
400         char buf[1024];
401         snprintf (buf, sizeof buf, "error: %d != %d", $1, $3);]AT_YYERROR_ARG_LOC_IF([[
402         yyerror (&@$, ]AT_PARAM_IF([result, count, nerrs, ])[buf);]], [[
403         {
404           YYLTYPE old_yylloc = yylloc;
405           yylloc = @$;
406           yyerror (]AT_PARAM_IF([result, count, nerrs, ])[buf);
407           yylloc = old_yylloc;
408         }
409         ]])[
410       }]],
411       [c++], [[
412       {
413         char buf[1024];
414         snprintf (buf, sizeof buf, "error: %d != %d", $1, $3);
415         ]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@$, ]])[buf);
416       }]])[
417     $$ = $1;
418   }
419 | exp '+' exp        { $$ = $1 + $3; }
420 | exp '-' exp        { $$ = $1 - $3; }
421 | exp '*' exp        { $$ = $1 * $3; }
422 | exp '/' exp
423   {
424     if ($3 == 0)]AT_LANG_CASE(
425       [c], [[
426       {]AT_YYERROR_ARG_LOC_IF([[
427         yyerror (&@3, ]AT_PARAM_IF([result, count, nerrs, ])["error: null divisor");]], [[
428         {
429           YYLTYPE old_yylloc = yylloc;
430           yylloc = @3;
431           yyerr][or (]AT_PARAM_IF([result, count, nerrs, ])["error: null divisor");
432           yylloc = old_yylloc;
433         }
434         ]])[
435       }]],
436       [c++], [[
437       {
438         ]AT_GLR_IF([[yyparser.]])[err][or (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
439       }]])[
440     else
441       $$ = $1 / $3;
442   }
443 | '-' exp  %prec NEG { $$ = -$2; }
444 | exp '^' exp        { $$ = power ($1, $3); }
445 | '(' exp ')'        { $$ = $2; }
446 | '(' error ')'      { $$ = 1111; yyerrok; }
447 | '-' error          { $$ = 0; YYERROR; }
448 | '!' '!'            { $$ = 0; YYERROR; }
449 | '!' '+'            { $$ = 0; YYACCEPT; }
450 | '!' '-'            { $$ = 0; YYABORT; }]AT_C_IF([[
451 | '!' '*'            { $$ = 0; YYNOMEM; }]])[
456 power (int base, int exponent)
458   int res = 1;
459   assert (0 <= exponent);
460   for (/* Niente */; exponent; --exponent)
461     res *= base;
462   return res;
465 ]AT_LOCATION_TYPE_SPAN_IF([AT_CXX_IF([[
466 #include <iostream>
467 namespace
469   std::ostream&
470   operator<< (std::ostream& o, const Span& s)
471   {
472     o << s.first.l << '.' << s.first.c;
473     if (s.first.l != s.last.l)
474       o << '-' << s.last.l << '.' << s.last.c - 1;
475     else if (s.first.c != s.last.c - 1)
476       o << '-' << s.last.c - 1;
477     return o;
478   }
480 ]], [[
481 void
482 location_print (FILE *o, Span s)
484   fprintf (o, "%d.%d", s.first.l, s.first.c);
485   if (s.first.l != s.last.l)
486     fprintf (o, "-%d.%d", s.last.l, s.last.c - 1);
487   else if (s.first.c != s.last.c - 1)
488     fprintf (o, "-%d", s.last.c - 1);
490 ]])])[
491 ]AT_YYERROR_DEFINE[
492 ]AT_HEADER_IF([],
493 [AT_CALC_YYLEX
494 AT_CALC_MAIN])])
496 # Remove the generated prototypes.
497 AT_CHECK(
498   [AT_YACC_IF([[
499     if "$POSIXLY_CORRECT_IS_EXPORTED"; then
500       sed -e '/\/\* !POSIX \*\//d' calc.y.tmp >calc.y
501     else
502       mv calc.y.tmp calc.y
503     fi
504   ]],
505   [[mv calc.y.tmp calc.y]])
508 AT_HEADER_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT],
509 [[#include "calc.]AT_LANG_HDR["
511 ]AT_CALC_YYLEX])
512 AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT],
513 [[#include "calc.]AT_LANG_HDR["
515 ]AT_CALC_MAIN])
517 ])# _AT_DATA_CALC_Y(c)
521 ## ------------- ##
522 ## Calc in C++.  ##
523 ## ------------- ##
525 m4_copy([AT_CALC_MAIN(c)], [AT_CALC_MAIN(c++)])
526 m4_copy([AT_CALC_YYLEX(c)], [AT_CALC_YYLEX(c++)])
527 m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)])
530 ## ----------- ##
531 ## Calc in D.  ##
532 ## ----------- ##
534 # AT_YYLEX_RETURN_VAL
535 # -------------------
536 # Produce the return value for yylex().
537 m4_define([AT_YYLEX_RETURN_VAL],
538 [return dnl
539 AT_TOKEN_CTOR_IF(
540   [[Symbol.]AT_TOKEN_PREFIX[$1](m4_ifval([$2], [$2])[]AT_LOCATION_IF([m4_ifval([$2], [, ])[location]])[);]],
541   [[Symbol(TokenKind.]AT_TOKEN_PREFIX[$1]m4_ifval([$2], [, $2])[]AT_LOCATION_IF([[, location]])[);]])]
544 # AT_CALC_MAIN(d).
545 m4_define([AT_CALC_MAIN(d)],
546 [[int main (string[] args)
547 {]AT_PARAM_IF([[
548   semantic_value result = 0;
549   int count = 0;]])[
551   File input = args.length == 2 ? File (args[1], "r") : stdin;
552   auto l = calcLexer (input);
553   auto p = new YYParser (l);]AT_DEBUG_IF([[
554   p.setDebugLevel (1);]])[
555   return !p.parse();
559 m4_define([AT_CALC_YYLEX(d)],
560 [[import std.range.primitives;
561 import std.stdio;
563 auto calcLexer(R)(R range)
564 if (isInputRange!R && is (ElementType!R : dchar))
566   return new CalcLexer!R(range);
569 auto calcLexer (File f)
571   import std.algorithm : map, joiner;
572   import std.utf : byDchar;
574   return f.byChunk(1024)        // avoid making a syscall roundtrip per char
575           .map!(chunk => cast(char[]) chunk) // because byChunk returns ubyte[]
576           .joiner               // combine chunks into a single virtual range of char
577           .calcLexer;           // forward to other overload
580 class CalcLexer(R) : Lexer
581 if (isInputRange!R && is (ElementType!R : dchar))
583   R input;
585   this(R r) { input = r; }
587   ]AT_YYERROR_DEFINE[
588 ]AT_LOCATION_IF([[
589   Location location;
590 ]])[
591   int parseInt ()
592   {
593     auto res = 0;
594     import std.uni : isNumber;
595     while (input.front.isNumber)
596     {
597       res = res * 10 + (input.front - '0');]AT_LOCATION_IF([[
598       location.end.column += 1;]])[
599       input.popFront;
600     }
601     return res;
602   }
604   Symbol yylex ()
605   {]AT_LOCATION_IF([[
606     location.step();]])[
608     import std.uni : isWhite, isNumber;
610     // Skip initial spaces
611     while (!input.empty && input.front != '\n' && isWhite (input.front))
612     {
613       input.popFront;]AT_LOCATION_IF([[
614       location.end.column += 1;]])[
615     }]AT_LOCATION_IF([[
616     location.step();]])[
618     // EOF.
619     if (input.empty)
620       ]AT_YYLEX_RETURN_VAL([EOF])[
621     // Numbers.
622     if (input.front.isNumber)
623       ]AT_YYLEX_RETURN_VAL([NUM], [parseInt])[
625     // Individual characters
626     auto c = input.front;]AT_LOCATION_IF([[
627     if (c == '\n')
628     {
629       location.end.line += 1;
630       location.end.column = 1;
631     }
632     else
633       location.end.column += 1;]])[
634     input.popFront;
636     // An explicit error raised by the scanner. */
637     if (c == '#')
638     {
639       stderr.writeln (]AT_LOCATION_IF([location, ": ", ])["syntax error: invalid character: '#'");
640       ]AT_YYLEX_RETURN_VAL([YYerror])[
641     }
643     switch (c)
644     {
645       case '+':  ]AT_YYLEX_RETURN_VAL([PLUS])[
646       case '-':  ]AT_YYLEX_RETURN_VAL([MINUS])[
647       case '*':  ]AT_YYLEX_RETURN_VAL([STAR])[
648       case '/':  ]AT_YYLEX_RETURN_VAL([SLASH])[
649       case '(':  ]AT_YYLEX_RETURN_VAL([LPAR])[
650       case ')':  ]AT_YYLEX_RETURN_VAL([RPAR])[
651       case '\n': ]AT_YYLEX_RETURN_VAL([EOL])[
652       case '=':  ]AT_YYLEX_RETURN_VAL([EQUAL])[
653       case '^':  ]AT_YYLEX_RETURN_VAL([POW])[
654       case '!':  ]AT_YYLEX_RETURN_VAL([NOT])[
655       default:   ]AT_YYLEX_RETURN_VAL([YYUNDEF])[
656     }
657   }
661 m4_define([_AT_DATA_CALC_Y(d)],
662 [AT_DATA_GRAMMAR([calc.y],
663 [[/* Infix notation calculator--calc */
664 ]$4[
665 %code imports {
666   alias semantic_value = int;
668 /* Exercise %union. */
669 ]AT_UNION_IF([[]], [[%union
671   semantic_value ival;
672 };]])[
673 %printer { yyo.write($$); } <]AT_UNION_IF([[int]], [[ival]])[>;
675 %code {
676 ]AT_TOKEN_TRANSLATE_IF([[
677   static string _(string s)
678   {
679     switch (s)
680     {
681       case "end of input":
682         return "end of file";
683       case "number":
684         return "nombre";
685       default:
686         return s;
687     }
688   }
689 ]])[
692 /* Bison Declarations */
693 %token EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
694 %token <]AT_UNION_IF([[int]], [[ival]])[> NUM   "number"
695 %type  <]AT_UNION_IF([[int]], [[ival]])[> exp
697 %token EQUAL  "="
698        MINUS  "-"
699        PLUS   "+"
700        STAR   "*"
701        SLASH  "/"
702        POW    "^"
703        EOL    "'\\n'"
704        LPAR   "("
705        RPAR   ")"
706        NOT    "!"
708 %nonassoc "="   /* comparison          */
709 %left "-" "+"
710 %left "*" "/"
711 %precedence NEG /* negation--unary minus */
712 %right "^"      /* exponentiation        */
714 /* Grammar follows */
716 input:
717   line
718 | input line         { ]AT_PARAM_IF([++*count; ++global_count;])[ }
721 line:
722   EOL
723 | exp EOL            { ]AT_PARAM_IF([*result = global_result = $1;])[ }
726 exp:
727   NUM
728 | exp "=" exp
729   {
730     if ($1 != $3)
731       yyerror (]AT_LOCATION_IF([[@$, ]])[format ("error: %d != %d", $1, $3));
732     $$ = $1;
733   }
734 | exp "+" exp        { $$ = $1 + $3; }
735 | exp "-" exp        { $$ = $1 - $3; }
736 | exp "*" exp        { $$ = $1 * $3; }
737 | exp "/" exp
738   {
739     if ($3 == 0)
740       yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
741     else
742       $$ = $1 / $3;
743   }
744 | "-" exp  %prec NEG { $$ = -$2; }
745 | exp "^" exp        { $$ = power ($1, $3); }
746 | "(" exp ")"        { $$ = $2; }
747 | "(" error ")"      { $$ = 1111; yyerrok(); }
748 | "-" error          { $$ = 0; return YYERROR; }
749 | "!" "!"            { $$ = 0; return YYERROR; }
750 | "!" "+"            { $$ = 0; return YYACCEPT; }
751 | "!" "-"            { $$ = 0; return YYABORT; }
756 power (int base, int exponent)
758   int res = 1;
759   assert (0 <= exponent);
760   for (/* Niente */; exponent; --exponent)
761     res *= base;
762   return res;
765 ]AT_CALC_YYLEX[
766 ]AT_CALC_MAIN])
767 ])# _AT_DATA_CALC_Y(d)
771 ## -------------- ##
772 ## Calc in Java.  ##
773 ## -------------- ##
775 m4_define([AT_CALC_MAIN(java)],
776 [[public static void main (String[] args) throws IOException
777   {]AT_LEXPARAM_IF([[
778     Calc p = new Calc (System.in);]], [[
779     CalcLexer l = new CalcLexer (System.in);
780     Calc p = new Calc (l);]])AT_DEBUG_IF([[
781     p.setDebugLevel (1);]])[
782     boolean success = p.parse ();
783     if (!success)
784       System.exit (1);
785   }
788 m4_define([AT_CALC_YYLEX(java)],
789 [AT_LEXPARAM_IF([[%code lexer {]],
790                 [[%code epilogue { class CalcLexer implements Calc.Lexer {]])[
791   StreamTokenizer st;]AT_LOCATION_IF([[
792   PositionReader reader;]])[
794   public ]AT_LEXPARAM_IF([[YYLexer]], [[CalcLexer]])[ (InputStream is)
795   {]AT_LOCATION_IF([[
796     reader = new PositionReader (new InputStreamReader (is));
797     st = new StreamTokenizer (reader);]], [[
798     st = new StreamTokenizer (new InputStreamReader (is));]])[
799     st.resetSyntax ();
800     st.eolIsSignificant (true);
801     st.wordChars ('0', '9');
802   }
804 ]AT_LOCATION_IF([[
805   Position start = new Position (1, 0);
806   Position end = new Position (1, 0);
808   public Position getStartPos () {
809     return new Position (start);
810   }
812   public Position getEndPos () {
813     return new Position (end);
814   }
816 ]])[
817   ]AT_YYERROR_DEFINE[
819   Integer yylval;
821   public Object getLVal () {
822     return yylval;
823   }
825   public int yylex() throws IOException {;]AT_LOCATION_IF([[
826     start.set(reader.getPosition());]])[
827     int tkind = st.nextToken();]AT_LOCATION_IF([[
828     end.set(reader.getPosition());]])[
829     switch (tkind)
830       {
831       case StreamTokenizer.TT_EOF:
832         return CALC_EOF;
833       case StreamTokenizer.TT_EOL:;]AT_LOCATION_IF([[
834         end.line += 1;
835         end.column = 0;]])[
836         return (int) '\n';
837       case StreamTokenizer.TT_WORD:
838         yylval = Integer.parseInt(st.sval);]AT_LOCATION_IF([[
839         end.set(reader.getPreviousPosition());]])[
840         return NUM;
841       case ' ': case '\t':
842         return yylex();
843       case '#':
844         System.err.println(]AT_LOCATION_IF([[start + ": " + ]])["syntax error: invalid character: '#'");
845         return YYerror;
846       default:
847         return tkind;
848       }
849   }
850 ]AT_LEXPARAM_IF([], [[}]])[
854 m4_define([_AT_DATA_CALC_Y(java)],
855 [AT_DATA_GRAMMAR([Calc.y],
856 [[/* Infix notation calculator--calc */
857 %define api.prefix {Calc}
858 %define api.parser.class {Calc}
859 %define public
861 ]$4[
863 %code imports {]AT_LOCATION_IF([[
864   import java.io.BufferedReader;]])[
865   import java.io.IOException;
866   import java.io.InputStream;
867   import java.io.InputStreamReader;
868   import java.io.Reader;
869   import java.io.StreamTokenizer;
872 %code {
873   ]AT_CALC_MAIN[
875   ]AT_TOKEN_TRANSLATE_IF([[
876     static String i18n(String s)
877     {
878       if (s.equals ("end of input"))
879         return "end of file";
880       else if (s.equals ("number"))
881         return "nombre";
882       else
883         return s;
884     }
885   ]])[
888 /* Bison Declarations */
889 %token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
890 %token <Integer> NUM "number"
891 %type  <Integer> exp
893 %nonassoc '='       /* comparison            */
894 %left '-' '+'
895 %left '*' '/'
896 %precedence NEG     /* negation--unary minus */
897 %right '^'          /* exponentiation        */
899 /* Grammar follows */
901 input:
902   line
903 | input line
906 line:
907   '\n'
908 | exp '\n'
911 exp:
912   NUM
913 | exp '=' exp
914   {
915     if ($1.intValue () != $3.intValue ())
916       yyerror (]AT_LOCATION_IF([[@$, ]])["error: " + $1 + " != " + $3);
917   }
918 | exp '+' exp        { $$ = $1 + $3; }
919 | exp '-' exp        { $$ = $1 - $3; }
920 | exp '*' exp        { $$ = $1 * $3; }
921 | exp '/' exp
922   {
923     if ($3.intValue () == 0)
924       yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
925     else
926       $$ = $1 / $3;
927   }
928 | '-' exp  %prec NEG { $$ = -$2; }
929 | exp '^' exp        { $$ = (int) Math.pow ($1, $3); }
930 | '(' exp ')'        { $$ = $2; }
931 | '(' error ')'      { $$ = 1111; }
932 | '-' error          { $$ = 0; return YYERROR; }
933 | '!' '!'            { $$ = 0; return YYERROR; }
934 | '!' '+'            { $$ = 0; return YYACCEPT; }
935 | '!' '-'            { $$ = 0; return YYABORT; }
937 ]AT_CALC_YYLEX[
938 ]AT_LOCATION_IF([[
940 ]AT_JAVA_POSITION_DEFINE])[
942 ])# _AT_DATA_JAVA_CALC_Y
947 ## ------------------ ##
948 ## Calculator tests.  ##
949 ## ------------------ ##
952 # AT_DATA_CALC_Y([BISON-OPTIONS])
953 # -------------------------------
954 # Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or
955 # 'calc-lex.cc'.
956 m4_define([AT_DATA_CALC_Y],
957 [_AT_DATA_CALC_Y($[1], $[2], $[3], [$1])
961 # _AT_CHECK_CALC(CALC-OPTIONS, INPUT, [STDOUT], [NUM-STDERR-LINES])
962 # -----------------------------------------------------------------
963 # Run 'calc' on INPUT and expect no STDOUT nor STDERR.
965 # If BISON-OPTIONS contains '%debug' but not '%glr-parser', then
966 # NUM-STDERR-LINES is the number of expected lines on stderr.
967 # Currently this is ignored, though, since the output format is fluctuating.
969 # We don't count GLR's traces yet, since its traces are somewhat
970 # different from LALR's.  Likewise for D.
972 # The push traces are the same, except for "Return for a new token", don't
973 # count them.
974 m4_define([_AT_CHECK_CALC],
975 [AT_DATA([[input]],
978 echo "input:"
979 sed -e 's/^/  | /' <input
980 AT_JAVA_IF(
981   [AT_JAVA_PARSER_CHECK([Calc $1 < input], 0, [m4_ifvaln(m4_quote($3), [$3])], [stderr])],
982   [AT_PARSER_CHECK([calc $1 input],        0, [m4_ifvaln(m4_quote($3), [$3])], [stderr])])
983 AT_LANG_MATCH([c\|c++\|java],
984   [AT_GLR_IF([],
985     [AT_CHECK([$EGREP -c -v 'Return for a new token:|LAC:' stderr],
986               [ignore],
987               [m4_n([AT_DEBUG_IF([$4], [0])])])])])
991 # _AT_CHECK_CALC_ERROR($1 = BISON-OPTIONS, $2 = EXIT-STATUS, $3 = INPUT,
992 #                      $4 = [STDOUT],
993 #                      $5 = [NUM-STDERR-LINES],
994 #                      $6 = [CUSTOM-ERROR-MESSAGE])
995 #                      $7 = [CALC-OPTIONS])
996 # ----------------------------------------------------------------------
997 # Run 'calc' on INPUT, and expect a 'syntax error' message.
999 # If INPUT starts with a slash, it is used as absolute input file name,
1000 # otherwise as contents.
1002 # NUM-STDERR-LINES is the number of expected lines on stderr.
1003 # If BISON-OPTIONS contains '%debug' but not '%glr', then NUM-STDERR-LINES
1004 # is the number of expected lines on stderr.
1006 # CUSTOM-ERROR-MESSAGE is the expected error message when parse.error
1007 # is 'custom' and locations are enabled.  Other expected formats are
1008 # computed from it.
1009 m4_define([_AT_CHECK_CALC_ERROR],
1010 [m4_bmatch([$3], [^/],
1011   [AT_JAVA_IF(
1012     [AT_JAVA_PARSER_CHECK([Calc $7 < $3], $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])],
1013     [AT_PARSER_CHECK([calc $7 $3],        $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])])],
1014   [AT_DATA([[input]],
1015 [[$3
1017   echo "input:"
1018   sed -e 's/^/  | /' <input
1019   AT_JAVA_IF(
1020     [AT_JAVA_PARSER_CHECK([Calc $7 < input], $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])],
1021     [AT_PARSER_CHECK([calc $7 input],        $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])])
1024 # Normalize the observed and expected error messages, depending upon the
1025 # options.
1026 # 1. Remove the traces from observed.
1027 sed '
1028 / \$[[0-9$]]* = /d
1029 /^Cleanup:/d
1030 /^Discarding/d
1031 /^Entering/d
1032 /^Error:/d
1033 /^LAC:/d
1034 /^Next/d
1035 /^Now/d
1036 /^Reading/d
1037 /^Reducing/d
1038 /^Return/d
1039 /^Shifting/d
1040 /^Stack/d
1041 /^Starting/d
1042 /^state/d
1043 /^yydestructor:/d
1044 ' stderr >at-stderr
1045 mv at-stderr stderr
1047 # 2. Create the reference error message.
1048 AT_DATA([[expout]],
1049 [m4_n([$6])])
1051 # 3. If locations are not used, remove them.
1052 AT_YYERROR_SEES_LOC_IF([],
1053 [[sed 's/^[-0-9.]*: //' expout >at-expout
1054 mv at-expout expout]])
1056 # 4. If parse.error is not custom, turn the expected message to
1057 # the traditional one.
1058 AT_ERROR_CUSTOM_IF([], [
1059 AT_PERL_REQUIRE([[-pi -e 'use strict;
1060   s{syntax error on token \[(.*?)\] \(expected: (.*)\)}
1061   {
1062     my $unexp = $][1;
1063     my @exps = $][2 =~ /\[(.*?)\]/g;]AT_D_IF([[
1064     # In the case of D, there are no single quotes around the symbols.
1065     $unexp =~ s/'"'(.)'"'/$][1/g;
1066     s/'"'(.)'"'/$][1/g for @exps;]])[
1067     ($][#exps && $][#exps < 4)
1068     ? "syntax error, unexpected $unexp, expecting @{[join(\" or \", @exps)]}"
1069     : "syntax error, unexpected $unexp";
1070   }eg
1071 ' expout]])
1074 # 5. If parse.error is simple, strip the', unexpected....' part.
1075 AT_ERROR_SIMPLE_IF(
1076 [[sed 's/syntax error, .*$/syntax error/' expout >at-expout
1077 mv at-expout expout]])
1079 # 6. Actually check.
1080 AT_CHECK([cat stderr], 0, [expout])
1084 # AT_CHECK_SPACES([FILES])
1085 # ------------------------
1086 # Make sure we did not introduce bad spaces.  Checked here because all
1087 # the skeletons are (or should be) exercised here.
1088 m4_define([AT_CHECK_SPACES],
1089 [AT_PERL_CHECK([-ne '
1090   chomp;
1091   print "$ARGV:$.: {$_}\n"
1092     if (# No starting/ending empty lines.
1093         (eof || $. == 1) && /^\s*$/
1094         # No trailing space.
1095         || /\s$/
1096         # No tabs.
1097         || /\t/
1098         )' $1
1103 # AT_CHECK_JAVA_GREP(FILE, [LINE], [COUNT=1])
1104 # -------------------------------------------
1105 # Check that FILE contains exactly COUNT lines matching ^LINE$
1106 # with grep.  Unquoted so that COUNT can be a shell expression.
1107 m4_define([AT_CHECK_JAVA_GREP],
1108 [AT_CHECK_UNQUOTED([grep -c '^$2$' $1], [ignore], [m4_default([$3], [1])
1109 ])])
1112 # AT_CHECK_CALC([BISON-OPTIONS], [COMPILER-OPTIONS])
1113 # --------------------------------------------------
1114 # Start a testing chunk which compiles 'calc' grammar with
1115 # BISON-OPTIONS, and performs several tests over the parser.
1116 m4_define([AT_CHECK_CALC],
1117 [m4_ifval([$3], [m4_fatal([$0: expected at most two arguments])])
1119 # We use integers to avoid dependencies upon the precision of doubles.
1120 AT_SETUP([Calculator $1 $2])
1122 AT_BISON_OPTION_PUSHDEFS([$1])
1124 AT_DATA_CALC_Y([$1])
1125 AT_FULL_COMPILE(AT_JAVA_IF([[Calc]], [[calc]]), AT_HEADER_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated])
1127 AT_YACC_C_IF(
1128   [# No direct calls to malloc/free.
1129   AT_CHECK([[$EGREP '(malloc|free) *\(' calc.[ch] | $EGREP -v 'INFRINGES ON USER NAME SPACE']],
1130            [1])])
1132 AT_PUSH_IF([AT_JAVA_IF(
1133  [# Verify that this is a push parser.
1134   AT_CHECK_JAVA_GREP([[Calc.java]],
1135                      [[.*public void push_parse_initialize ().*]])])])
1137 AT_CHECK_SPACES([AT_JAVA_IF([Calc], [calc]).AT_LANG_EXT AT_HEADER_IF([AT_JAVA_IF([Calc], [calc]).AT_LANG_HDR])])
1139 # Test the precedences.
1140 # The Java traces do not show the clean up sequence at the end,
1141 # since it does not support %destructor.
1142 _AT_CHECK_CALC([],
1143 [[1 + 2 * 3 = 7
1144 1 + 2 * -3 = -5
1146 -1^2 = -1
1147 (-1)^2 = 1
1149 ---1 = -1
1151 1 - 2 - 3 = -4
1152 1 - (2 - 3) = 2
1154 2^2^3 = 256
1155 (2^2)^3 = 64]],
1156 [AT_PARAM_IF([final: 64 12 0])],
1157                [AT_JAVA_IF([1014], [1017])])
1159 # Some syntax errors.
1160 _AT_CHECK_CALC_ERROR([$1], [1], [1 2],
1161                      [AT_PARAM_IF([final: 0 0 1])],
1162                      [15],
1163                      [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]])
1164 _AT_CHECK_CALC_ERROR([$1], [1], [1//2],
1165                      [AT_PARAM_IF([final: 0 0 1])],
1166                      [20],
1167                      [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token ['/'] (expected: [number] ['-'] ['('] ['!'])]])
1168 _AT_CHECK_CALC_ERROR([$1], [1], [error],
1169                      [AT_PARAM_IF([final: 0 0 1])],
1170                      [5],
1171                      [AT_JAVA_IF([1.1-1.2], [1.1])[: syntax error on token [invalid token] (expected: [number] ['-'] ['\n'] ['('] ['!'])]])
1172 _AT_CHECK_CALC_ERROR([$1], [1], [1 = 2 = 3],
1173                      [AT_PARAM_IF([final: 0 0 1])],
1174                      [30],
1175                      [AT_LAC_IF(
1176                        [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]],
1177                        [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'])]])])
1178 _AT_CHECK_CALC_ERROR([$1], [1],
1179                      [
1180 +1],
1181                      [AT_PARAM_IF([final: 0 0 1])],
1182                      [20],
1183                      [AT_JAVA_IF([2.1-2.2], [2.1])[: syntax error on token ['+'] (expected: ]AT_TOKEN_TRANSLATE_IF([[[end of file]]], [[[end of input]]])[ [number] ['-'] ['\n'] ['('] ['!'])]])
1184 # Exercise error messages with EOF: work on an empty file.
1185 _AT_CHECK_CALC_ERROR([$1], [1], [/dev/null],
1186                      [AT_PARAM_IF([final: 0 0 1])],
1187                      [4],
1188                      [[1.1: syntax error on token ]AT_TOKEN_TRANSLATE_IF([[[end of file]]], [[[end of input]]])[ (expected: [number] ['-'] ['\n'] ['('] ['!'])]])
1190 # Exercise the error token: without it, we die at the first error,
1191 # hence be sure to
1193 # - have several errors which exercise different shift/discardings
1194 #   - (): nothing to pop, nothing to discard
1195 #   - (1 + 1 + 1 +): a lot to pop, nothing to discard
1196 #   - (* * *): nothing to pop, a lot to discard
1197 #   - (1 + 2 * *): some to pop and discard
1199 # - test the action associated to 'error'
1201 # - check the lookahead that triggers an error is not discarded
1202 #   when we enter error recovery.  Below, the lookahead causing the
1203 #   first error is ")", which is needed to recover from the error and
1204 #   produce the "0" that triggers the "0 != 1" error.
1206 _AT_CHECK_CALC_ERROR([$1], [0],
1207                      [() + (1 + 1 + 1 +) + (* * *) + (1 * 2 * *) = 1],
1208                      [AT_PARAM_IF([final: 4444 0 5])],
1209                      [250],
1210 [AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!'])
1211 ]AT_JAVA_IF([1.18-1.19], [1.18])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!'])
1212 ]AT_JAVA_IF([1.23-1.24], [1.23])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1213 ]AT_JAVA_IF([1.41-1.42], [1.41])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1214 ]AT_JAVA_IF([1.1-1.47], [1.1-46])[: error: 4444 != 1]])
1216 # The same, but this time exercising explicitly triggered syntax errors.
1217 # POSIX says the lookahead causing the error should not be discarded.
1218 _AT_CHECK_CALC_ERROR([$1], [0], [(!!) + (1 2) = 1],
1219                      [AT_PARAM_IF([final: 2222 0 2])],
1220                      [102],
1221 [AT_JAVA_IF([1.11-1.12], [1.11])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')'])
1222 ]AT_JAVA_IF([1.1-1.17], [1.1-16])[: error: 2222 != 1]])
1224 _AT_CHECK_CALC_ERROR([$1], [0], [(- *) + (1 2) = 1],
1225                      [AT_PARAM_IF([final: 2222 0 3])],
1226                      [113],
1227 [AT_JAVA_IF([1.4-1.5], [1.4])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1228 ]AT_JAVA_IF([1.12-1.13], [1.12])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')'])
1229 ]AT_JAVA_IF([1.1-1.18], [1.1-17])[: error: 2222 != 1]])
1231 # Check that yyerrok works properly: second error is not reported,
1232 # third and fourth are.  Parse status is successful.
1233 _AT_CHECK_CALC_ERROR([$1], [0], [(* *) + (*) + (*)],
1234                      [AT_PARAM_IF([final: 3333 0 3])],
1235                      [113],
1236 [AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1237 ]AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1238 ]AT_JAVA_IF([1.16-1.17], [1.16])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])]])
1241 # Special actions.
1242 # ----------------
1243 # !+ => YYACCEPT, !- => YYABORT, !! => YYERROR, !* => YYNOMEM.
1245 # YYACCEPT.
1246 # Java lacks the traces at the end for cleaning the stack
1247 # -Stack now 0 8 20
1248 # -Cleanup: popping token '+' (1.1: )
1249 # -Cleanup: popping nterm exp (1.1: 7)
1250 _AT_CHECK_CALC([], [1 + 2 * 3 + !+ ++],
1251                [AT_PARAM_IF([final: 0 0 0])],
1252                [AT_JAVA_IF([77], [80])])
1253 # YYABORT.
1254 _AT_CHECK_CALC_ERROR([$1], [1], [1 + 2 * 3 + !- ++],
1255                      [AT_PARAM_IF([final: 0 0 0])],
1256                      [102])
1257 AT_C_IF(
1258 [# YYNOMEM.
1259 _AT_CHECK_CALC_ERROR([$1], [2], [1 + 2 * 3 + !* ++],
1260                      [AT_PARAM_IF([final: 0 0 1])],
1261                      [102],
1262                      [1.14: memory exhausted])])
1265 # YYerror.
1266 # --------
1267 # Check that returning YYerror from the scanner properly enters
1268 # error-recovery without issuing a second error message.
1270 _AT_CHECK_CALC_ERROR([$1], [0], [(#) + (#) = 2222],
1271                      [AT_PARAM_IF([final: 2222 0 0])],
1272                      [102],
1273 [[1.2: syntax error: invalid character: '#'
1274 1.8: syntax error: invalid character: '#']])
1276 _AT_CHECK_CALC_ERROR([$1], [0], [(1 + #) = 1111],
1277                      [AT_PARAM_IF([final: 1111 0 0])],
1278                      [102],
1279 [[1.6: syntax error: invalid character: '#']])
1281 _AT_CHECK_CALC_ERROR([$1], [0], [(# + 1) = 1111],
1282                      [AT_PARAM_IF([final: 1111 0 0])],
1283                      [102],
1284 [[1.2: syntax error: invalid character: '#']])
1286 _AT_CHECK_CALC_ERROR([$1], [0], [(1 + # + 1) = 1111],
1287                      [AT_PARAM_IF([final: 1111 0 0])],
1288                      [102],
1289 [[1.6: syntax error: invalid character: '#']])
1291 _AT_CHECK_CALC_ERROR([$1], [0], [(1 + 1) / (1 - 1)],
1292                      [AT_PARAM_IF([final: 2 0 1])],
1293                      [102],
1294 [AT_JAVA_IF([1.11-1.18], [1.11-17])[: error: null divisor]])
1296 # Multiple start symbols.
1297 AT_MULTISTART_IF([
1298 _AT_CHECK_CALC([--num], [[123]],
1299                [[NUM => 123 (status: 0, errors: 0)]],
1300                [AT_JAVA_IF([1014], [1017])])
1301 _AT_CHECK_CALC_ERROR([$1], [1], [1 + 2 * 3],
1302                      [NUM => 0 (status: 1, errors: 1)],
1303                      [102],
1304                      [[1.3: syntax error, unexpected '+', expecting end of file]],
1305                      [--num])
1307 _AT_CHECK_CALC([--exp], [[1 + 2 * 3]],
1308                [[exp => 7 (status: 0, errors: 0)]],
1309                [AT_JAVA_IF([1014], [1017])])
1313 AT_BISON_OPTION_POPDEFS
1315 AT_CLEANUP
1316 ])# AT_CHECK_CALC
1321 # ----------------- #
1322 # LALR Calculator.  #
1323 # ----------------- #
1325 AT_BANNER([[LALR(1) Calculator.]])
1327 # AT_CHECK_CALC_LALR([BISON-OPTIONS])
1328 # -----------------------------------
1329 # Start a testing chunk which compiles 'calc' grammar with
1330 # BISON-OPTIONS, and performs several tests over the parser.
1331 m4_define([AT_CHECK_CALC_LALR],
1332 [AT_CHECK_CALC($@)])
1334 AT_CHECK_CALC_LALR([%define parse.trace])
1336 AT_CHECK_CALC_LALR([%header])
1337 AT_CHECK_CALC_LALR([%debug %locations])
1338 AT_CHECK_CALC_LALR([%locations %define api.location.type {Span}])
1340 AT_CHECK_CALC_LALR([%name-prefix "calc"])
1341 AT_CHECK_CALC_LALR([%verbose])
1342 AT_CHECK_CALC_LALR([%yacc])
1343 AT_CHECK_CALC_LALR([%define parse.error detailed])
1344 AT_CHECK_CALC_LALR([%define parse.error verbose])
1346 AT_CHECK_CALC_LALR([%define api.pure full %locations])
1347 AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %locations])
1348 AT_CHECK_CALC_LALR([%define parse.error detailed %locations])
1350 AT_CHECK_CALC_LALR([%define parse.error detailed %locations %header %define api.prefix {calc} %verbose %yacc])
1351 AT_CHECK_CALC_LALR([%define parse.error detailed %locations %header %name-prefix "calc" %define api.token.prefix {TOK_} %verbose %yacc])
1353 AT_CHECK_CALC_LALR([%debug])
1354 AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %header %name-prefix "calc" %verbose %yacc])
1355 AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc])
1357 AT_CHECK_CALC_LALR([%define api.pure full %define parse.error detailed %debug %locations %header %name-prefix "calc" %verbose %yacc])
1358 AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc])
1360 AT_CHECK_CALC_LALR([%define api.pure %define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1362 AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1363 AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error verbose %debug %locations %header %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1364 AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error verbose %debug %locations %defines %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1366 # parse.error custom.
1367 AT_CHECK_CALC_LALR([%define parse.error custom])
1368 AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc}])
1369 AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1370 AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs} %define api.push-pull both %define api.pure full])
1371 AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs} %define api.push-pull both %define api.pure full %define parse.lac full])
1373 # multistart.
1374 AT_CHECK_CALC_LALR([%start input exp NUM %define api.value.type union])
1375 AT_CHECK_CALC_LALR([%start input exp NUM %define api.value.type union %locations %define parse.error detailed])
1378 # ---------------- #
1379 # GLR Calculator.  #
1380 # ---------------- #
1382 AT_BANNER([[GLR Calculator.]])
1384 m4_define([AT_CHECK_CALC_GLR],
1385 [AT_CHECK_CALC([%glr-parser] $@)])
1387 AT_CHECK_CALC_GLR()
1389 AT_CHECK_CALC_GLR([%header])
1390 AT_CHECK_CALC_GLR([%locations])
1391 AT_CHECK_CALC_GLR([%locations %define api.location.type {Span}])
1392 AT_CHECK_CALC_GLR([%name-prefix "calc"])
1393 AT_CHECK_CALC_GLR([%define api.prefix {calc}])
1394 AT_CHECK_CALC_GLR([%verbose])
1395 AT_CHECK_CALC_GLR([%define parse.error verbose])
1397 AT_CHECK_CALC_GLR([%define api.pure %locations])
1398 AT_CHECK_CALC_GLR([%define parse.error verbose %locations])
1400 AT_CHECK_CALC_GLR([%define parse.error custom %locations %header %name-prefix "calc" %verbose])
1401 AT_CHECK_CALC_GLR([%define parse.error custom %locations %header %name-prefix "calc" %verbose %define api.pure])
1402 AT_CHECK_CALC_GLR([%define parse.error detailed %locations %header %name-prefix "calc" %verbose])
1403 AT_CHECK_CALC_GLR([%define parse.error verbose %locations %header %name-prefix "calc" %verbose])
1405 AT_CHECK_CALC_GLR([%define parse.error custom %locations %header %name-prefix "calc" %verbose])
1407 AT_CHECK_CALC_GLR([%debug])
1408 AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose])
1409 AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %header %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose])
1411 AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose])
1413 AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1414 AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %header %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1416 AT_CHECK_CALC_GLR([%no-lines %define api.pure %define parse.error verbose %debug %locations %header %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1419 # ---------------------- #
1420 # LALR1 C++ Calculator.  #
1421 # ---------------------- #
1423 AT_BANNER([[LALR(1) C++ Calculator.]])
1425 # First let's try using %skeleton
1426 AT_CHECK_CALC([%skeleton "lalr1.cc" %header])
1428 m4_define([AT_CHECK_CALC_LALR1_CC],
1429 [AT_CHECK_CALC([%language "C++" $1], [$2])])
1431 AT_CHECK_CALC_LALR1_CC([])
1432 AT_CHECK_CALC_LALR1_CC([%locations])
1433 AT_CHECK_CALC_LALR1_CC([%locations], [$NO_EXCEPTIONS_CXXFLAGS])
1434 AT_CHECK_CALC_LALR1_CC([%locations %define api.location.type {Span}])
1435 AT_CHECK_CALC_LALR1_CC([%header %locations %define parse.error verbose %name-prefix "calc" %verbose])
1437 AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %define api.prefix {calc} %verbose])
1438 AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %name-prefix "calc" %verbose])
1440 AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose])
1441 AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose])
1443 AT_CHECK_CALC_LALR1_CC([%header %locations %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1445 AT_CHECK_CALC_LALR1_CC([%define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1446 AT_CHECK_CALC_LALR1_CC([%header %locations %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1448 AT_CHECK_CALC_LALR1_CC([%header %locations %define api.location.file none])
1449 AT_CHECK_CALC_LALR1_CC([%header %locations %define api.location.file "my-location.hh"])
1451 AT_CHECK_CALC_LALR1_CC([%no-lines %header %locations %define api.location.file "my-location.hh"])
1453 AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error verbose])
1454 AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed])
1455 AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed %define parse.trace])
1457 AT_CHECK_CALC_LALR1_CC([%define parse.error custom])
1458 AT_CHECK_CALC_LALR1_CC([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1459 AT_CHECK_CALC_LALR1_CC([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs} %define parse.lac full])
1461 # -------------------- #
1462 # GLR C++ Calculator.  #
1463 # -------------------- #
1465 AT_BANNER([[GLR C++ Calculator.]])
1467 # Again, we try also using %skeleton.
1468 AT_CHECK_CALC([%skeleton "glr.cc"])
1469 AT_CHECK_CALC([%skeleton "glr2.cc"])
1471 m4_define([AT_CHECK_CALC_GLR_CC],
1472 [AT_CHECK_CALC([%language "C++" %glr-parser] $@) # glr.cc
1473 AT_CHECK_CALC([%skeleton "glr2.cc"] $@)
1476 AT_CHECK_CALC_GLR_CC([])
1477 AT_CHECK_CALC_GLR_CC([%locations])
1478 AT_CHECK_CALC_GLR_CC([%locations %define api.location.type {Span}])
1479 AT_CHECK_CALC_GLR_CC([%header %define parse.error verbose %name-prefix "calc" %verbose])
1480 AT_CHECK_CALC_GLR_CC([%define parse.error verbose %define api.prefix {calc} %verbose])
1482 AT_CHECK_CALC_GLR_CC([%debug])
1484 # parse.error.
1485 AT_CHECK_CALC_GLR_CC([%define parse.error detailed %debug %name-prefix "calc" %verbose])
1486 AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %verbose])
1487 AT_CHECK_CALC([%skeleton "glr2.cc" %define parse.error custom %debug %name-prefix "calc" %verbose]) # Only glr2.cc.
1489 AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %define api.token.prefix {TOK_} %verbose])
1491 AT_CHECK_CALC_GLR_CC([%locations %header %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1492 AT_CHECK_CALC_GLR_CC([%locations %header %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1494 AT_CHECK_CALC_GLR_CC([%no-lines %locations %header %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1497 # -------------------- #
1498 # LALR1 D Calculator.  #
1499 # -------------------- #
1501 AT_BANNER([[LALR(1) D Calculator.]])
1503 # First let's try using %skeleton
1504 AT_CHECK_CALC([%skeleton "lalr1.d"])
1506 m4_define([AT_CHECK_CALC_LALR1_D],
1507 [AT_CHECK_CALC([%language "D" $1], [$2])])
1509 AT_CHECK_CALC_LALR1_D([])
1510 AT_CHECK_CALC_LALR1_D([%locations])
1511 #AT_CHECK_CALC_LALR1_D([%locations %define api.location.type {Span}])
1512 AT_CHECK_CALC_LALR1_D([%define parse.error detailed %define api.prefix {calc} %verbose])
1514 AT_CHECK_CALC_LALR1_D([%debug])
1516 AT_CHECK_CALC_LALR1_D([%define parse.error custom])
1517 AT_CHECK_CALC_LALR1_D([%locations %define parse.error custom])
1518 AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed])
1519 AT_CHECK_CALC_LALR1_D([%locations %define parse.error simple])
1520 AT_CHECK_CALC_LALR1_D([%define parse.error detailed %debug %verbose])
1521 AT_CHECK_CALC_LALR1_D([%define parse.error detailed %debug %define api.symbol.prefix {SYMB_} %define api.token.prefix {TOK_} %verbose])
1523 AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error detailed])
1524 AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error custom])
1525 AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error detailed %define parse.trace])
1527 #AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1528 #AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1530 AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error custom %define api.value.type union])
1531 AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error detailed])
1532 AT_CHECK_CALC_LALR1_D([%define api.push-pull both])
1533 AT_CHECK_CALC_LALR1_D([%define parse.trace %define parse.error custom %locations %define api.push-pull both %define parse.lac full])
1535 # ----------------------- #
1536 # LALR1 Java Calculator.  #
1537 # ----------------------- #
1539 AT_BANNER([[LALR(1) Java Calculator.]])
1541 m4_define([AT_CHECK_CALC_LALR1_JAVA],
1542 [AT_CHECK_CALC([%language "Java" $1], [$2])])
1544 AT_CHECK_CALC_LALR1_JAVA
1545 AT_CHECK_CALC_LALR1_JAVA([%define parse.error custom])
1546 AT_CHECK_CALC_LALR1_JAVA([%define parse.error detailed])
1547 AT_CHECK_CALC_LALR1_JAVA([%define parse.error verbose])
1548 AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error custom])
1549 AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error detailed])
1550 AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error verbose])
1551 AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose])
1552 AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is}])
1554 AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both])
1555 AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both %define parse.error detailed %locations])
1556 AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %lex-param {InputStream is} %define api.push-pull both])
1557 AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is} %define api.push-pull both])
1559 # parse.lac.
1560 AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %define parse.lac full])
1561 AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %define api.push-pull both %define parse.lac full])
1564 m4_popdef([AT_CALC_MAIN])
1565 m4_popdef([AT_CALC_YYLEX])