1# Simple calculator.                         -*- Autotest -*-
2
3# Copyright (C) 2000-2015, 2018-2021 Free Software Foundation, Inc.
4
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
18## ---------------------------------------------------- ##
19## Compile the grammar described in the documentation.  ##
20## ---------------------------------------------------- ##
21
22# -------------- #
23# AT_CALC_MAIN.  #
24# -------------- #
25
26m4_pushdef([AT_CALC_MAIN],   [AT_LANG_DISPATCH([$0], $@)])
27
28# Whether token translation is supported.
29m4_pushdef([AT_TOKEN_TRANSLATE_IF],
30[AT_ERROR_CUSTOM_IF([$1], [AT_ERROR_DETAILED_IF([$1], [$2])])])
31
32m4_define([AT_CALC_MAIN(c)],
33[[#include <assert.h>
34#include <unistd.h>
35
36]AT_CXX_IF([[
37namespace
38{
39  /* A C++ ]AT_NAME_PREFIX[parse that simulates the C signature.  */
40  int
41  ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([semantic_value *result, int *count, int *nerrs]))[
42  {
43    ]AT_NAME_PREFIX[::parser parser]AT_PARAM_IF([ (result, count, nerrs)])[;
44  #if ]AT_API_PREFIX[DEBUG
45    parser.set_debug_level (1);
46  #endif
47    return parser.parse ();
48  }
49}
50]])[
51
52/* Value of the last computation.  */
53semantic_value global_result = 0;
54/* Total number of computations.  */
55int global_count = 0;
56/* Total number of errors.  */
57int global_nerrs = 0;
58
59/* A C main function.  */
60int
61main (int argc, const char **argv)
62{]AT_PARAM_IF([[
63  semantic_value result = 0;
64  int count = 0;
65  int nerrs = 0;]])[
66  int status;
67
68  /* This used to be alarm (10), but that isn't enough time for a July
69     1995 vintage DEC Alphastation 200 4/100 system, according to
70     Nelson H. F. Beebe.  100 seconds was enough for regular users,
71     but the Hydra build farm, which is heavily loaded needs more.  */
72
73  alarm (200);
74
75  if (argc == 2)
76    input = fopen (argv[1], "r");
77  else
78    input = stdin;
79
80  if (!input)
81    {
82      perror (argv[1]);
83      return 3;
84    }
85
86]AT_CXX_IF([], [AT_DEBUG_IF([  ]AT_NAME_PREFIX[debug = 1;])])[
87  status = ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([[&result, &count, &nerrs]])[);
88  if (fclose (input))
89    perror ("fclose");]AT_PARAM_IF([[
90  assert (global_result == result); (void) result;
91  assert (global_count  == count);  (void) count;
92  assert (global_nerrs  == nerrs);  (void) nerrs;
93  printf ("final: %d %d %d\n", global_result, global_count, global_nerrs);]])[
94  return status;
95}
96]])
97
98m4_copy([AT_CALC_MAIN(c)], [AT_CALC_MAIN(c++)])
99
100m4_define([AT_CALC_MAIN(d)],
101[[int main (string[] args)
102{]AT_PARAM_IF([[
103  semantic_value result = 0;
104  int count = 0;]])[
105
106  File input = args.length == 2 ? File (args[1], "r") : stdin;
107  auto l = calcLexer (input);
108  auto p = new YYParser (l);]AT_DEBUG_IF([[
109  p.setDebugLevel (1);]])[
110  return !p.parse ();
111}
112]])
113
114
115m4_define([AT_CALC_MAIN(java)],
116[[public static void main (String[] args) throws IOException
117  {]AT_LEXPARAM_IF([[
118    Calc p = new Calc (System.in);]], [[
119    CalcLexer l = new CalcLexer (System.in);
120    Calc p = new Calc (l);]])AT_DEBUG_IF([[
121    p.setDebugLevel (1);]])[
122    boolean success = p.parse ();
123    if (!success)
124      System.exit (1);
125  }
126]])
127
128
129# --------------- #
130# AT_CALC_YYLEX.  #
131# --------------- #
132
133m4_pushdef([AT_CALC_YYLEX],   [AT_LANG_DISPATCH([$0], $@)])
134
135
136m4_define([AT_CALC_YYLEX(c)],
137[[#include <ctype.h>
138
139]AT_YYLEX_DECLARE_EXTERN[
140
141]AT_LOCATION_IF([
142static AT_YYLTYPE last_yylloc;
143])[
144static int
145get_char (]AT_YYLEX_FORMALS[)
146{
147  int res = getc (input);
148  ]AT_USE_LEX_ARGS[;
149]AT_LOCATION_IF([
150  last_yylloc = AT_LOC;
151  if (res == '\n')
152    {
153      AT_LOC_LAST_LINE++;
154      AT_LOC_LAST_COLUMN = 1;
155    }
156  else
157    AT_LOC_LAST_COLUMN++;
158])[
159  return res;
160}
161
162static void
163unget_char (]AT_YYLEX_PRE_FORMALS[ int c)
164{
165  ]AT_USE_LEX_ARGS[;
166]AT_LOCATION_IF([
167  /* Wrong when C == '\n'. */
168  AT_LOC = last_yylloc;
169])[
170  ungetc (c, input);
171}
172
173static int
174read_integer (]AT_YYLEX_FORMALS[)
175{
176  int c = get_char (]AT_YYLEX_ARGS[);
177  int res = 0;
178
179  ]AT_USE_LEX_ARGS[;
180  while (isdigit (c))
181    {
182      res = 10 * res + (c - '0');
183      c = get_char (]AT_YYLEX_ARGS[);
184    }
185
186  unget_char (]AT_YYLEX_PRE_ARGS[ c);
187
188  return res;
189}
190
191
192/*---------------------------------------------------------------.
193| Lexical analyzer returns an integer on the stack and the token |
194| NUM, or the ASCII character read if not a number.  Skips all   |
195| blanks and tabs, returns 0 for EOF.                            |
196`---------------------------------------------------------------*/
197
198]AT_YYLEX_PROTOTYPE[
199{
200  int c;
201  /* Skip white spaces.  */
202  do
203    {
204]AT_LOCATION_IF([
205      AT_LOC_FIRST_COLUMN = AT_LOC_LAST_COLUMN;
206      AT_LOC_FIRST_LINE   = AT_LOC_LAST_LINE;
207])[
208    }
209  while ((c = get_char (]AT_YYLEX_ARGS[)) == ' ' || c == '\t');
210
211  /* Process numbers.   */
212  if (isdigit (c))
213    {
214      unget_char (]AT_YYLEX_PRE_ARGS[ c);
215      ]AT_VAL[.ival = read_integer (]AT_YYLEX_ARGS[);
216      return ]AT_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[NUM;
217    }
218
219  /* Return end-of-file.  */
220  if (c == EOF)
221    return ]AT_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[CALC_EOF;
222
223  /* An explicit error raised by the scanner. */
224  if (c == '#')
225    {]AT_LOCATION_IF([
226      fprintf (stderr, "%d.%d: ",
227               AT_LOC_FIRST_LINE, AT_LOC_FIRST_COLUMN);])[
228      fputs ("syntax error: invalid character: '#'\n", stderr);
229      return ]AT_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[]AT_API_PREFIX[error;
230    }
231
232  /* Return single chars. */
233  return c;
234}
235]])
236
237m4_copy([AT_CALC_YYLEX(c)], [AT_CALC_YYLEX(c++)])
238
239m4_define([AT_CALC_YYLEX(d)],
240[[import std.range.primitives;
241import std.stdio;
242
243auto calcLexer(R)(R range)
244  if (isInputRange!R && is (ElementType!R : dchar))
245{
246  return new CalcLexer!R(range);
247}
248
249auto calcLexer (File f)
250{
251  import std.algorithm : map, joiner;
252  import std.utf : byDchar;
253
254  return f.byChunk(1024)        // avoid making a syscall roundtrip per char
255          .map!(chunk => cast(char[]) chunk) // because byChunk returns ubyte[]
256          .joiner               // combine chunks into a single virtual range of char
257          .calcLexer;           // forward to other overload
258}
259
260class CalcLexer(R) : Lexer
261  if (isInputRange!R && is (ElementType!R : dchar))
262{
263  R input;
264
265  this(R r) {
266    input = r;
267  }
268
269  ]AT_YYERROR_DEFINE[
270
271  YYSemanticType semanticVal_;]AT_LOCATION_IF([[
272  YYLocation location = new YYLocation;
273
274  public final @property YYPosition startPos()
275  {
276    return location.begin;
277  }
278
279  public final @property YYPosition endPos()
280  {
281    return location.end;
282  }
283]])[
284  public final @property YYSemanticType semanticVal()
285  {
286    return semanticVal_;
287  }
288
289  int parseInt ()
290  {
291    auto res = 0;
292    import std.uni : isNumber;
293    while (input.front.isNumber)
294      {
295        res = res * 10 + (input.front - '0');]AT_LOCATION_IF([[
296        location.end.column += 1;]])[
297        input.popFront;
298      }
299    return res;
300  }
301
302  int yylex ()
303  {]AT_LOCATION_IF([[
304    location.begin = location.end;]])[
305
306    import std.uni : isWhite, isNumber;
307
308    // Skip initial spaces
309    while (!input.empty && input.front != '\n' && isWhite (input.front))
310      {
311        input.popFront;]AT_LOCATION_IF([[
312        location.begin.column += 1;
313        location.end.column += 1;]])[
314      }
315
316    // EOF.
317    if (input.empty)
318      return TokenKind.CALC_EOF;
319
320    // Numbers.
321    if (input.front.isNumber)
322      {
323        semanticVal_.ival = parseInt;
324        return TokenKind.NUM;
325      }
326
327    // Individual characters
328    auto c = input.front;]AT_LOCATION_IF([[
329    if (c == '\n')
330      {
331        location.end.line += 1;
332        location.end.column = 1;
333      }
334    else
335      location.end.column += 1;]])[
336    input.popFront;
337
338    // An explicit error raised by the scanner. */
339    if (c == '#')
340      {
341        stderr.writeln (]AT_LOCATION_IF([location, ": ", ])["syntax error: invalid character: '#'");
342        return TokenKind.YYerror;
343      }
344
345    return c;
346  }
347}
348]])
349
350
351m4_define([AT_CALC_YYLEX(java)],
352[AT_LEXPARAM_IF([[%code lexer {]],
353                [[%code epilogue { class CalcLexer implements Calc.Lexer {]])[
354  StreamTokenizer st;]AT_LOCATION_IF([[
355  PositionReader reader;]])[
356
357  public ]AT_LEXPARAM_IF([[YYLexer]], [[CalcLexer]])[ (InputStream is)
358  {]AT_LOCATION_IF([[
359    reader = new PositionReader (new InputStreamReader (is));
360    st = new StreamTokenizer (reader);]], [[
361    st = new StreamTokenizer (new InputStreamReader (is));]])[
362    st.resetSyntax ();
363    st.eolIsSignificant (true);
364    st.wordChars ('0', '9');
365  }
366
367]AT_LOCATION_IF([[
368  Position start = new Position (1, 0);
369  Position end = new Position (1, 0);
370
371  public Position getStartPos () {
372    return new Position (start);
373  }
374
375  public Position getEndPos () {
376    return new Position (end);
377  }
378
379]])[
380  ]AT_YYERROR_DEFINE[
381
382  Integer yylval;
383
384  public Object getLVal () {
385    return yylval;
386  }
387
388  public int yylex () throws IOException {;]AT_LOCATION_IF([[
389    start.set (reader.getPosition ());]])[
390    int tkind = st.nextToken ();]AT_LOCATION_IF([[
391    end.set (reader.getPosition ());]])[
392    switch (tkind)
393      {
394      case StreamTokenizer.TT_EOF:
395        return CALC_EOF;
396      case StreamTokenizer.TT_EOL:;]AT_LOCATION_IF([[
397        end.line += 1;
398        end.column = 0;]])[
399        return (int) '\n';
400      case StreamTokenizer.TT_WORD:
401        yylval = new Integer (st.sval);]AT_LOCATION_IF([[
402        end.set (reader.getPreviousPosition ());]])[
403        return NUM;
404      case ' ': case '\t':
405        return yylex ();
406      case '#':
407        System.err.println(]AT_LOCATION_IF([[start + ": " + ]])["syntax error: invalid character: '#'");
408        return YYerror;
409      default:
410        return tkind;
411      }
412  }
413]AT_LEXPARAM_IF([], [[}]])[
414};
415]])
416
417
418# -------------- #
419# AT_DATA_CALC.  #
420# -------------- #
421
422
423# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES])
424# -----------------------------------------------
425# Produce 'calc.y' and, if %defines was specified, 'calc-lex.c' or
426# 'calc-lex.cc'.
427#
428# Don't call this macro directly, because it contains some occurrences
429# of '$1' etc. which will be interpreted by m4.  So you should call it
430# with $1, $2, and $3 as arguments, which is what AT_DATA_CALC_Y does.
431#
432# When %defines is not passed, generate a single self-contained file.
433# Otherwise, generate three: calc.y with the parser, calc-lex.c with
434# the scanner, and calc-main.c with "main()".  This is in order to
435# stress the use of the generated parser header.  To avoid code
436# duplication, AT_CALC_YYLEX and AT_CALC_MAIN contain the body of these
437# two later files.
438m4_pushdef([_AT_DATA_CALC_Y],
439[m4_if([$1$2$3], $[1]$[2]$[3], [],
440       [m4_fatal([$0: Invalid arguments: $@])])dnl
441AT_LANG_DISPATCH([$0], $@)])
442
443m4_define([_AT_DATA_CALC_Y(c)],
444[AT_DATA_GRAMMAR([calc.y],
445[[/* Infix notation calculator--calc */
446]$4[
447]AT_LANG_MATCH(
448[d], [[
449%code imports {
450  alias semantic_value = int;
451}
452]],
453[c\|c++], [[
454%code requires
455{
456]AT_LOCATION_TYPE_SPAN_IF([[
457  typedef struct
458  {
459    int l;
460    int c;
461  } Point;
462
463  typedef struct
464  {
465    Point first;
466    Point last;
467  } Span;
468
469# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
470  do                                                                    \
471    if (N)                                                              \
472      {                                                                 \
473        (Current).first = YYRHSLOC (Rhs, 1).first;                      \
474        (Current).last  = YYRHSLOC (Rhs, N).last;                       \
475      }                                                                 \
476    else                                                                \
477      {                                                                 \
478        (Current).first = (Current).last = YYRHSLOC (Rhs, 0).last;      \
479      }                                                                 \
480  while (0)
481
482]AT_C_IF(
483[[#include <stdio.h>
484void location_print (FILE *o, Span s);
485#define LOCATION_PRINT location_print
486]])[
487
488]])[
489  /* Exercise pre-prologue dependency to %union.  */
490  typedef int semantic_value;
491}
492]])[
493
494/* Exercise %union. */
495%union
496{
497  semantic_value ival;
498};
499%printer { ]AT_CXX_IF([[yyo << $$]],
500                      [[fprintf (yyo, "%d", $$)]])[; } <ival>;
501
502]AT_LANG_MATCH([c\|c++], [[
503%code provides
504{
505  #include <stdio.h>
506  /* The input.  */
507  extern FILE *input;
508  extern semantic_value global_result;
509  extern int global_count;
510  extern int global_nerrs;
511}
512
513%code
514{
515  #include <assert.h>
516  #include <string.h>
517  #define USE(Var)
518
519  FILE *input;
520  static int power (int base, int exponent);
521
522  ]AT_YYERROR_DECLARE[
523  ]AT_YYLEX_DECLARE_EXTERN[
524
525  ]AT_TOKEN_TRANSLATE_IF([[
526#define N_
527    static
528    const char *
529    _ (const char *cp)
530    {
531      if (strcmp (cp, "end of input") == 0)
532        return "end of file";
533      else if (strcmp (cp, "number") == 0)
534        return "nombre";
535      else
536        return cp;
537    }
538  ]])[
539}
540]])[
541
542]AT_LOCATION_TYPE_SPAN_IF([[
543%initial-action
544{
545  @$.first.l = @$.first.c = 1;
546  @$.last = @$.first;
547}]])[
548
549/* Bison Declarations */
550%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[
551%token <ival> NUM   "number"
552%type  <ival> exp
553
554%nonassoc '='   /* comparison          */
555%left '-' '+'
556%left '*' '/'
557%precedence NEG /* negation--unary minus */
558%right '^'      /* exponentiation        */
559
560/* Grammar follows */
561%%
562input:
563  line
564| input line         { ]AT_PARAM_IF([++*count; ++global_count;])[ }
565;
566
567line:
568  '\n'
569| exp '\n'           { ]AT_PARAM_IF([*result = global_result = $1;], [AT_D_IF([], [USE ($1);])])[ }
570;
571
572exp:
573  NUM
574| exp '=' exp
575  {
576    if ($1 != $3)]AT_LANG_CASE(
577      [c], [[
578      {
579        char buf[1024];
580        snprintf (buf, sizeof buf, "calc: error: %d != %d", $1, $3);]AT_YYERROR_ARG_LOC_IF([[
581        yyerror (&@$, ]AT_PARAM_IF([result, count, nerrs, ])[buf);]], [[
582        {
583          YYLTYPE old_yylloc = yylloc;
584          yylloc = @$;
585          yyerror (]AT_PARAM_IF([result, count, nerrs, ])[buf);
586          yylloc = old_yylloc;
587        }
588        ]])[
589      }]],
590      [c++], [[
591      {
592        char buf[1024];
593        snprintf (buf, sizeof buf, "calc: error: %d != %d", $1, $3);
594        ]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@$, ]])[buf);
595      }]],
596      [d], [[
597      yyerror (]AT_LOCATION_IF([[@$, ]])[format ("calc: error: %d != %d", $1, $3));]])[
598    $$ = $1;
599  }
600| exp '+' exp        { $$ = $1 + $3; }
601| exp '-' exp        { $$ = $1 - $3; }
602| exp '*' exp        { $$ = $1 * $3; }
603| exp '/' exp        { $$ = $1 / $3; }
604| '-' exp  %prec NEG { $$ = -$2; }
605| exp '^' exp        { $$ = power ($1, $3); }
606| '(' exp ')'        { $$ = $2; }
607| '(' error ')'      { $$ = 1111; ]AT_D_IF([], [yyerrok;])[ }
608| '!'                { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; }
609| '-' error          { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; }
610;
611%%
612
613int
614power (int base, int exponent)
615{
616  int res = 1;
617  assert (0 <= exponent);
618  for (/* Niente */; exponent; --exponent)
619    res *= base;
620  return res;
621}
622
623]AT_LOCATION_TYPE_SPAN_IF([AT_CXX_IF([[
624#include <iostream>
625namespace
626{
627  std::ostream&
628  operator<< (std::ostream& o, const Span& s)
629  {
630    o << s.first.l << '.' << s.first.c;
631    if (s.first.l != s.last.l)
632      o << '-' << s.last.l << '.' << s.last.c - 1;
633    else if (s.first.c != s.last.c - 1)
634      o << '-' << s.last.c - 1;
635    return o;
636  }
637}
638]], [[
639void
640location_print (FILE *o, Span s)
641{
642  fprintf (o, "%d.%d", s.first.l, s.first.c);
643  if (s.first.l != s.last.l)
644    fprintf (o, "-%d.%d", s.last.l, s.last.c - 1);
645  else if (s.first.c != s.last.c - 1)
646    fprintf (o, "-%d", s.last.c - 1);
647}
648]])])[
649]AT_YYERROR_DEFINE[
650]AT_DEFINES_IF([],
651[AT_CALC_YYLEX
652AT_CALC_MAIN])])
653
654AT_DEFINES_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT],
655[[#include "calc.]AT_LANG_HDR["
656
657]AT_CALC_YYLEX])
658AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT],
659[[#include "calc.]AT_LANG_HDR["
660
661]AT_CALC_MAIN])
662])
663])# _AT_DATA_CALC_Y
664
665
666m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)])
667m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(d)])
668
669m4_define([_AT_DATA_CALC_Y(java)],
670[AT_DATA_GRAMMAR([Calc.y],
671[[/* Infix notation calculator--calc */
672%define api.prefix {Calc}
673%define api.parser.class {Calc}
674%define public
675
676]$4[
677
678%code imports {]AT_LOCATION_IF([[
679  import java.io.BufferedReader;]])[
680  import java.io.IOException;
681  import java.io.InputStream;
682  import java.io.InputStreamReader;
683  import java.io.Reader;
684  import java.io.StreamTokenizer;
685}
686
687%code {
688  ]AT_CALC_MAIN[
689
690  ]AT_TOKEN_TRANSLATE_IF([[
691    static String i18n(String s)
692    {
693      if (s.equals ("end of input"))
694        return "end of file";
695      else if (s.equals ("number"))
696        return "nombre";
697      else
698        return s;
699    }
700  ]])[
701}
702
703/* Bison Declarations */
704%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[
705%token <Integer> NUM "number"
706%type  <Integer> exp
707
708%nonassoc '='       /* comparison            */
709%left '-' '+'
710%left '*' '/'
711%precedence NEG     /* negation--unary minus */
712%right '^'          /* exponentiation        */
713
714/* Grammar follows */
715%%
716input:
717  line
718| input line
719;
720
721line:
722  '\n'
723| exp '\n'
724;
725
726exp:
727  NUM
728| exp '=' exp
729  {
730    if ($1.intValue () != $3.intValue ())
731      yyerror (]AT_LOCATION_IF([[@$, ]])["calc: error: " + $1 + " != " + $3);
732  }
733| exp '+' exp        { $$ = $1 + $3; }
734| exp '-' exp        { $$ = $1 - $3; }
735| exp '*' exp        { $$ = $1 * $3; }
736| exp '/' exp        { $$ = $1 / $3; }
737| '-' exp  %prec NEG { $$ = -$2; }
738| exp '^' exp        { $$ = (int) Math.pow ($1, $3); }
739| '(' exp ')'        { $$ = $2; }
740| '(' error ')'      { $$ = 1111; }
741| '!'                { $$ = 0; return YYERROR; }
742| '-' error          { $$ = 0; return YYERROR; }
743;
744]AT_CALC_YYLEX[
745]AT_LOCATION_IF([[
746%%
747]AT_JAVA_POSITION_DEFINE])[
748]])
749])# _AT_DATA_JAVA_CALC_Y
750
751
752
753# AT_DATA_CALC_Y([BISON-OPTIONS])
754# -------------------------------
755# Produce 'calc.y' and, if %defines was specified, 'calc-lex.c' or
756# 'calc-lex.cc'.
757m4_define([AT_DATA_CALC_Y],
758[_AT_DATA_CALC_Y($[1], $[2], $[3], [$1])
759])
760
761
762
763# _AT_CHECK_CALC(BISON-OPTIONS, INPUT, [STDOUT], [NUM-STDERR-LINES])
764# ------------------------------------------------------------------
765# Run 'calc' on INPUT and expect no STDOUT nor STDERR.
766#
767# If BISON-OPTIONS contains '%debug' but not '%glr-parser', then
768# NUM-STDERR-LINES is the number of expected lines on stderr.
769# Currently this is ignored, though, since the output format is fluctuating.
770#
771# We don't count GLR's traces yet, since its traces are somewhat
772# different from LALR's.  Likewise for D.
773#
774# The push traces are the same, except for "Return for a new token", don't
775# count them.
776m4_define([_AT_CHECK_CALC],
777[AT_DATA([[input]],
778[$2
779])
780AT_JAVA_IF(
781  [AT_JAVA_PARSER_CHECK([Calc < input], 0, [AT_PARAM_IF([m4_n([$3])])], [stderr])],
782  [AT_PARSER_CHECK([calc input],        0, [AT_PARAM_IF([m4_n([$3])])], [stderr])])
783AT_LANG_MATCH([c\|c++\|java],
784  [AT_GLR_IF([],
785    [AT_CHECK([grep -c -v 'Return for a new token:' stderr],
786              [ignore],
787              [m4_n([AT_DEBUG_IF([$4], [0])])])])])
788])
789
790
791# _AT_CHECK_CALC_ERROR($1 = BISON-OPTIONS, $2 = EXIT-STATUS, $3 = INPUT,
792#                      $4 = [STDOUT],
793#                      $5 = [NUM-STDERR-LINES],
794#                      $6 = [CUSTOM-ERROR-MESSAGE])
795# ----------------------------------------------------------------------
796# Run 'calc' on INPUT, and expect a 'syntax error' message.
797#
798# If INPUT starts with a slash, it is used as absolute input file name,
799# otherwise as contents.
800#
801# NUM-STDERR-LINES is the number of expected lines on stderr.
802# If BISON-OPTIONS contains '%debug' but not '%glr', then NUM-STDERR-LINES
803# is the number of expected lines on stderr.
804#
805# CUSTOM-ERROR-MESSAGE is the expected error message when parse.error
806# is 'custom' and locations are enabled.  Other expected formats are
807# computed from it.
808m4_define([_AT_CHECK_CALC_ERROR],
809[m4_bmatch([$3], [^/],
810  [AT_JAVA_IF(
811    [AT_JAVA_PARSER_CHECK([Calc < $3], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])],
812    [AT_PARSER_CHECK([calc $3],        $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])])],
813  [AT_DATA([[input]],
814[[$3
815]])
816  AT_JAVA_IF(
817    [AT_JAVA_PARSER_CHECK([Calc < input], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])],
818    [AT_PARSER_CHECK([calc input],        $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])])
819])
820
821# Normalize the observed and expected error messages, depending upon the
822# options.
823# 1. Remove the traces from observed.
824sed '/^Starting/d
825/^Entering/d
826/^Stack/d
827/^Reading/d
828/^Reducing/d
829/^Return/d
830/^Shifting/d
831/^state/d
832/^Cleanup:/d
833/^Error:/d
834/^Next/d
835/^Now/d
836/^Discarding/d
837/ \$[[0-9$]]* = /d
838/^yydestructor:/d' stderr >at-stderr
839mv at-stderr stderr
840
841# 2. Create the reference error message.
842AT_DATA([[expout]],
843[$6
844])
845
846# 3. If locations are not used, remove them.
847AT_YYERROR_SEES_LOC_IF([],
848[[sed 's/^[-0-9.]*: //' expout >at-expout
849mv at-expout expout]])
850
851# 4. If parse.error is not custom, turn the expected message to
852# the traditional one.
853AT_ERROR_CUSTOM_IF([], [
854AT_PERL_REQUIRE([[-pi -e 'use strict;
855  s{syntax error on token \[(.*?)\] \(expected: (.*)\)}
856  {
857    my $unexp = $][1;
858    my @exps = $][2 =~ /\[(.*?)\]/g;
859    ($][#exps && $][#exps < 4)
860    ? "syntax error, unexpected $unexp, expecting @{[join(\" or \", @exps)]}"
861    : "syntax error, unexpected $unexp";
862  }eg
863' expout]])
864])
865
866# 5. If parse.error is simple, strip the', unexpected....' part.
867AT_ERROR_SIMPLE_IF(
868[[sed 's/syntax error, .*$/syntax error/' expout >at-expout
869mv at-expout expout]])
870
871# 6. Actually check.
872AT_CHECK([cat stderr], 0, [expout])
873])
874
875
876# AT_CHECK_SPACES([FILES])
877# ------------------------
878# Make sure we did not introduce bad spaces.  Checked here because all
879# the skeletons are (or should be) exercised here.
880m4_define([AT_CHECK_SPACES],
881[AT_PERL_CHECK([-ne '
882  chomp;
883  print "$ARGV:$.: {$_}\n"
884    if (# No starting/ending empty lines.
885        (eof || $. == 1) && /^\s*$/
886        # No trailing space.
887        || /\s$/
888        # No tabs.
889        || /\t/
890        )' $1
891])
892])
893
894
895# AT_CHECK_JAVA_GREP(FILE, [LINE], [COUNT=1])
896# -------------------------------------------
897# Check that FILE contains exactly COUNT lines matching ^LINE$
898# with grep.  Unquoted so that COUNT can be a shell expression.
899m4_define([AT_CHECK_JAVA_GREP],
900[AT_CHECK_UNQUOTED([grep -c '^$2$' $1], [ignore], [m4_default([$3], [1])
901])])
902
903
904# AT_CHECK_CALC([BISON-OPTIONS], [COMPILER-OPTIONS])
905# --------------------------------------------------
906# Start a testing chunk which compiles 'calc' grammar with
907# BISON-OPTIONS, and performs several tests over the parser.
908m4_define([AT_CHECK_CALC],
909[m4_ifval([$3], [m4_fatal([$0: expected at most two arguments])])
910
911# We use integers to avoid dependencies upon the precision of doubles.
912AT_SETUP([Calculator $1 $2])
913
914AT_BISON_OPTION_PUSHDEFS([$1])
915
916AT_DATA_CALC_Y([$1])
917AT_FULL_COMPILE(AT_JAVA_IF([[Calc]], [[calc]]), AT_DEFINES_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated])
918
919AT_YACC_IF(
920  [# No direct calls to malloc/free.
921  AT_CHECK([[$EGREP '(malloc|free) *\(' calc.[ch] | $EGREP -v 'INFRINGES ON USER NAME SPACE']],
922           [1])])
923
924AT_PUSH_IF([AT_JAVA_IF(
925 [# Verify that this is a push parser.
926  AT_CHECK_JAVA_GREP([[Calc.java]],
927                     [[.*public void push_parse_initialize ().*]])])])
928
929AT_CHECK_SPACES([AT_JAVA_IF([Calc], [calc]).AT_LANG_EXT AT_DEFINES_IF([AT_JAVA_IF([Calc], [calc]).AT_LANG_HDR])])
930
931# Test the precedences.
932# The Java traces do not show the clean up sequence at the end,
933# since it does not support %destructor.
934_AT_CHECK_CALC([$1],
935[[1 + 2 * 3 = 7
9361 + 2 * -3 = -5
937
938-1^2 = -1
939(-1)^2 = 1
940
941---1 = -1
942
9431 - 2 - 3 = -4
9441 - (2 - 3) = 2
945
9462^2^3 = 256
947(2^2)^3 = 64]],
948[[final: 64 12 0]],
949               [AT_JAVA_IF([1014], [1017])])
950
951# Some syntax errors.
952_AT_CHECK_CALC_ERROR([$1], [1], [1 2],
953                     [[final: 0 0 1]],
954                     [15],
955                     [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]])
956_AT_CHECK_CALC_ERROR([$1], [1], [1//2],
957                     [[final: 0 0 1]],
958                     [20],
959                     [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token ['/'] (expected: [number] ['-'] ['('] ['!'])]])
960_AT_CHECK_CALC_ERROR([$1], [1], [error],
961                     [[final: 0 0 1]],
962                     [5],
963                     [AT_JAVA_IF([1.1-1.2], [1.1])[: syntax error on token [invalid token] (expected: [number] ['-'] ['\n'] ['('] ['!'])]])
964_AT_CHECK_CALC_ERROR([$1], [1], [1 = 2 = 3],
965                     [[final: 0 0 1]],
966                     [30],
967                     [AT_LAC_IF(
968                       [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]],
969                       [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'])]])])
970_AT_CHECK_CALC_ERROR([$1], [1],
971                     [
972+1],
973                     [[final: 0 0 1]],
974                     [20],
975                     [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'] ['('] ['!'])]])
976# Exercise error messages with EOF: work on an empty file.
977_AT_CHECK_CALC_ERROR([$1], [1], [/dev/null],
978                     [[final: 0 0 1]],
979                     [4],
980                     [[1.1: syntax error on token ]AT_TOKEN_TRANSLATE_IF([[[end of file]]], [[[end of input]]])[ (expected: [number] ['-'] ['\n'] ['('] ['!'])]])
981
982# Exercise the error token: without it, we die at the first error,
983# hence be sure to
984#
985# - have several errors which exercise different shift/discardings
986#   - (): nothing to pop, nothing to discard
987#   - (1 + 1 + 1 +): a lot to pop, nothing to discard
988#   - (* * *): nothing to pop, a lot to discard
989#   - (1 + 2 * *): some to pop and discard
990#
991# - test the action associated to 'error'
992#
993# - check the lookahead that triggers an error is not discarded
994#   when we enter error recovery.  Below, the lookahead causing the
995#   first error is ")", which is needed to recover from the error and
996#   produce the "0" that triggers the "0 != 1" error.
997#
998_AT_CHECK_CALC_ERROR([$1], [0],
999                     [() + (1 + 1 + 1 +) + (* * *) + (1 * 2 * *) = 1],
1000                     [[final: 4444 0 5]],
1001                     [250],
1002[AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!'])
1003]AT_JAVA_IF([1.18-1.19], [1.18])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!'])
1004]AT_JAVA_IF([1.23-1.24], [1.23])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1005]AT_JAVA_IF([1.41-1.42], [1.41])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1006]AT_JAVA_IF([1.1-1.47], [1.1-46])[: calc: error: 4444 != 1]])
1007
1008# The same, but this time exercising explicitly triggered syntax errors.
1009# POSIX says the lookahead causing the error should not be discarded.
1010_AT_CHECK_CALC_ERROR([$1], [0], [(!) + (1 2) = 1],
1011                     [[final: 2222 0 2]],
1012                     [102],
1013[AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')'])
1014]AT_JAVA_IF([1.1-1.16], [1.1-15])[: calc: error: 2222 != 1]])
1015
1016_AT_CHECK_CALC_ERROR([$1], [0], [(- *) + (1 2) = 1],
1017                     [[final: 2222 0 3]],
1018                     [113],
1019[AT_JAVA_IF([1.4-1.5], [1.4])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1020]AT_JAVA_IF([1.12-1.13], [1.12])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')'])
1021]AT_JAVA_IF([1.1-1.18], [1.1-17])[: calc: error: 2222 != 1]])
1022
1023# Check that yyerrok works properly: second error is not reported,
1024# third and fourth are.  Parse status is successful.
1025_AT_CHECK_CALC_ERROR([$1], [0], [(* *) + (*) + (*)],
1026                     [[final: 3333 0 3]],
1027                     [113],
1028[AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1029]AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
1030]AT_JAVA_IF([1.16-1.17], [1.16])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])]])
1031
1032
1033# YYerror.
1034# --------
1035# Check that returning YYerror from the scanner properly enters
1036# error-recovery without issuing a second error message.
1037
1038_AT_CHECK_CALC_ERROR([$1], [0], [(#) + (#) = 2222],
1039                     [[final: 2222 0 0]],
1040                     [102],
1041[[1.2: syntax error: invalid character: '#'
10421.8: syntax error: invalid character: '#']])
1043
1044_AT_CHECK_CALC_ERROR([$1], [0], [(1 + #) = 1111],
1045                     [[final: 1111 0 0]],
1046                     [102],
1047[[1.6: syntax error: invalid character: '#']])
1048
1049_AT_CHECK_CALC_ERROR([$1], [0], [(# + 1) = 1111],
1050                     [[final: 1111 0 0]],
1051                     [102],
1052[[1.2: syntax error: invalid character: '#']])
1053
1054_AT_CHECK_CALC_ERROR([$1], [0], [(1 + # + 1) = 1111],
1055                     [[final: 1111 0 0]],
1056                     [102],
1057[[1.6: syntax error: invalid character: '#']])
1058
1059
1060
1061AT_BISON_OPTION_POPDEFS
1062
1063AT_CLEANUP
1064])# AT_CHECK_CALC
1065
1066
1067
1068
1069# ----------------- #
1070# LALR Calculator.  #
1071# ----------------- #
1072
1073AT_BANNER([[LALR(1) Calculator.]])
1074
1075# AT_CHECK_CALC_LALR([BISON-OPTIONS])
1076# -----------------------------------
1077# Start a testing chunk which compiles 'calc' grammar with
1078# BISON-OPTIONS, and performs several tests over the parser.
1079m4_define([AT_CHECK_CALC_LALR],
1080[AT_CHECK_CALC($@)])
1081
1082AT_CHECK_CALC_LALR([%define parse.trace])
1083
1084AT_CHECK_CALC_LALR([%defines])
1085AT_CHECK_CALC_LALR([%debug %locations])
1086AT_CHECK_CALC_LALR([%locations %define api.location.type {Span}])
1087
1088AT_CHECK_CALC_LALR([%name-prefix "calc"])
1089AT_CHECK_CALC_LALR([%verbose])
1090AT_CHECK_CALC_LALR([%yacc])
1091AT_CHECK_CALC_LALR([%define parse.error detailed])
1092AT_CHECK_CALC_LALR([%define parse.error verbose])
1093
1094AT_CHECK_CALC_LALR([%define api.pure full %locations])
1095AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %locations])
1096AT_CHECK_CALC_LALR([%define parse.error detailed %locations])
1097
1098AT_CHECK_CALC_LALR([%define parse.error detailed %locations %defines %define api.prefix {calc} %verbose %yacc])
1099AT_CHECK_CALC_LALR([%define parse.error detailed %locations %defines %name-prefix "calc" %define api.token.prefix {TOK_} %verbose %yacc])
1100
1101AT_CHECK_CALC_LALR([%debug])
1102AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %defines %name-prefix "calc" %verbose %yacc])
1103AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc])
1104
1105AT_CHECK_CALC_LALR([%define api.pure full %define parse.error detailed %debug %locations %defines %name-prefix "calc" %verbose %yacc])
1106AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc])
1107
1108AT_CHECK_CALC_LALR([%define api.pure %define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1109
1110AT_CHECK_CALC_LALR([%no-lines %define api.pure %define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1111AT_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}])
1112
1113
1114AT_CHECK_CALC_LALR([%define parse.error custom])
1115AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc}])
1116AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1117AT_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])
1118AT_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])
1119
1120# ---------------- #
1121# GLR Calculator.  #
1122# ---------------- #
1123
1124AT_BANNER([[GLR Calculator.]])
1125
1126m4_define([AT_CHECK_CALC_GLR],
1127[AT_CHECK_CALC([%glr-parser] $@)])
1128
1129AT_CHECK_CALC_GLR()
1130
1131AT_CHECK_CALC_GLR([%defines])
1132AT_CHECK_CALC_GLR([%locations])
1133AT_CHECK_CALC_GLR([%locations %define api.location.type {Span}])
1134AT_CHECK_CALC_GLR([%name-prefix "calc"])
1135AT_CHECK_CALC_GLR([%define api.prefix {calc}])
1136AT_CHECK_CALC_GLR([%verbose])
1137AT_CHECK_CALC_GLR([%define parse.error verbose])
1138
1139AT_CHECK_CALC_GLR([%define api.pure %locations])
1140AT_CHECK_CALC_GLR([%define parse.error verbose %locations])
1141
1142AT_CHECK_CALC_GLR([%define parse.error custom %locations %defines %name-prefix "calc" %verbose])
1143AT_CHECK_CALC_GLR([%define parse.error detailed %locations %defines %name-prefix "calc" %verbose])
1144AT_CHECK_CALC_GLR([%define parse.error verbose %locations %defines %name-prefix "calc" %verbose])
1145
1146AT_CHECK_CALC_GLR([%debug])
1147AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose])
1148AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %defines %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose])
1149
1150AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose])
1151
1152AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1153AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %defines %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1154
1155AT_CHECK_CALC_GLR([%no-lines %define api.pure %define parse.error verbose %debug %locations %defines %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1156
1157
1158# ---------------------- #
1159# LALR1 C++ Calculator.  #
1160# ---------------------- #
1161
1162AT_BANNER([[LALR(1) C++ Calculator.]])
1163
1164# First let's try using %skeleton
1165AT_CHECK_CALC([%skeleton "lalr1.cc" %defines])
1166
1167m4_define([AT_CHECK_CALC_LALR1_CC],
1168[AT_CHECK_CALC([%language "C++" $1], [$2])])
1169
1170AT_CHECK_CALC_LALR1_CC([])
1171AT_CHECK_CALC_LALR1_CC([%locations])
1172AT_CHECK_CALC_LALR1_CC([%locations], [$NO_EXCEPTIONS_CXXFLAGS])
1173AT_CHECK_CALC_LALR1_CC([%locations %define api.location.type {Span}])
1174AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose %name-prefix "calc" %verbose])
1175
1176AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %define api.prefix {calc} %verbose])
1177AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %name-prefix "calc" %verbose])
1178
1179AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose])
1180AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose])
1181
1182AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1183
1184AT_CHECK_CALC_LALR1_CC([%define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1185AT_CHECK_CALC_LALR1_CC([%defines %locations %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1186
1187AT_CHECK_CALC_LALR1_CC([%defines %locations %define api.location.file none])
1188AT_CHECK_CALC_LALR1_CC([%defines %locations %define api.location.file "my-location.hh"])
1189
1190AT_CHECK_CALC_LALR1_CC([%no-lines %defines %locations %define api.location.file "my-location.hh"])
1191
1192AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error verbose])
1193AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed])
1194
1195AT_CHECK_CALC_LALR1_CC([%define parse.error custom])
1196AT_CHECK_CALC_LALR1_CC([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1197AT_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])
1198
1199# -------------------- #
1200# GLR C++ Calculator.  #
1201# -------------------- #
1202
1203AT_BANNER([[GLR C++ Calculator.]])
1204
1205# Again, we try also using %skeleton.
1206AT_CHECK_CALC([%skeleton "glr.cc"])
1207
1208m4_define([AT_CHECK_CALC_GLR_CC],
1209[AT_CHECK_CALC([%language "C++" %glr-parser] $@)])
1210
1211AT_CHECK_CALC_GLR_CC([])
1212AT_CHECK_CALC_GLR_CC([%locations])
1213AT_CHECK_CALC_GLR_CC([%locations %define api.location.type {Span}])
1214AT_CHECK_CALC_GLR_CC([%defines %define parse.error verbose %name-prefix "calc" %verbose])
1215AT_CHECK_CALC_GLR_CC([%define parse.error verbose %define api.prefix {calc} %verbose])
1216
1217AT_CHECK_CALC_GLR_CC([%debug])
1218
1219AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %verbose])
1220AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %define api.token.prefix {TOK_} %verbose])
1221
1222AT_CHECK_CALC_GLR_CC([%locations %defines %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1223AT_CHECK_CALC_GLR_CC([%locations %defines %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1224
1225AT_CHECK_CALC_GLR_CC([%no-lines %locations %defines %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1226
1227
1228# -------------------- #
1229# LALR1 D Calculator.  #
1230# -------------------- #
1231
1232AT_BANNER([[LALR(1) D Calculator.]])
1233
1234# First let's try using %skeleton
1235AT_CHECK_CALC([%skeleton "lalr1.d"])
1236
1237m4_define([AT_CHECK_CALC_LALR1_D],
1238[AT_CHECK_CALC([%language "D" $1], [$2])])
1239
1240AT_CHECK_CALC_LALR1_D([])
1241AT_CHECK_CALC_LALR1_D([%locations])
1242#AT_CHECK_CALC_LALR1_D([%locations %define api.location.type {Span}])
1243AT_CHECK_CALC_LALR1_D([%define parse.error verbose %define api.prefix {calc} %verbose])
1244
1245AT_CHECK_CALC_LALR1_D([%debug])
1246
1247AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %verbose])
1248#AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %define api.token.prefix {TOK_} %verbose])
1249
1250#AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose %debug %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1251#AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
1252
1253
1254# ----------------------- #
1255# LALR1 Java Calculator.  #
1256# ----------------------- #
1257
1258AT_BANNER([[LALR(1) Java Calculator.]])
1259
1260m4_define([AT_CHECK_CALC_LALR1_JAVA],
1261[AT_CHECK_CALC([%language "Java" $1], [$2])])
1262
1263AT_CHECK_CALC_LALR1_JAVA
1264AT_CHECK_CALC_LALR1_JAVA([%define parse.error custom])
1265AT_CHECK_CALC_LALR1_JAVA([%define parse.error detailed])
1266AT_CHECK_CALC_LALR1_JAVA([%define parse.error verbose])
1267AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error custom])
1268AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error detailed])
1269AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error verbose])
1270AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose])
1271AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is}])
1272
1273AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both])
1274AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both %define parse.error detailed %locations])
1275AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %lex-param {InputStream is} %define api.push-pull both])
1276AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is} %define api.push-pull both])
1277
1278
1279m4_popdef([AT_TOKEN_TRANSLATE_IF])
1280m4_popdef([AT_CALC_MAIN])
1281m4_popdef([AT_CALC_YYLEX])
1282