# Simple calculator.                         -*- Autotest -*-

# Copyright (C) 2000-2015, 2018-2020 Free Software Foundation, Inc.

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

## ---------------------------------------------------- ##
## Compile the grammar described in the documentation.  ##
## ---------------------------------------------------- ##


m4_pushdef([AT_CALC_MAIN],  [AT_LANG_DISPATCH([$0], $@)])
m4_pushdef([AT_CALC_YYLEX], [AT_LANG_DISPATCH([$0], $@)])

# -------------- #
# AT_DATA_CALC.  #
# -------------- #


# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES])
# -----------------------------------------------
# Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or
# 'calc-lex.cc'.
#
# Don't call this macro directly, because it contains some occurrences
# of '$1' etc. which will be interpreted by m4.  So you should call it
# with $1, $2, and $3 as arguments, which is what AT_DATA_CALC_Y does.
#
# When %header is not passed, generate a single self-contained file.
# Otherwise, generate three: calc.y with the parser, calc-lex.c with
# the scanner, and calc-main.c with "main()".  This is in order to
# stress the use of the generated parser header.  To avoid code
# duplication, AT_CALC_YYLEX and AT_CALC_MAIN contain the body of these
# two later files.
m4_pushdef([_AT_DATA_CALC_Y],
[m4_if([$1$2$3], $[1]$[2]$[3], [],
       [m4_fatal([$0: Invalid arguments: $@])])dnl
AT_LANG_DISPATCH([$0], $@)])



## ----------- ##
## Calc in C.  ##
## ----------- ##

# AT_CALC_MAIN(c).
m4_define([AT_CALC_MAIN(c)],
[[#include <assert.h>
#include <stdlib.h> /* exit */
#include <string.h> /* strcmp */
#include <unistd.h>

]AT_CXX_IF([[
namespace
{
  /* A C++ ]AT_NAME_PREFIX[parse that simulates the C signature.  */
  int
  ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([semantic_value *result, int *count, int *nerrs]))[
  {
    ]AT_NAME_PREFIX[::parser parser]AT_PARAM_IF([ (result, count, nerrs)])[;
  #if ]AT_API_PREFIX[DEBUG
    parser.set_debug_level (1);
  #endif
    return parser.parse ();
  }
}
]])[

/* Value of the last computation.  */
semantic_value global_result = 0;
/* Total number of computations.  */
int global_count = 0;
/* Total number of errors.  */
int global_nerrs = 0;

#ifndef EX_NOINPUT
# define EX_NOINPUT 66
#endif

static FILE *
open_file (const char *file)
{
  FILE *res = (file && *file && strcmp (file, "-")) ? fopen (file, "r") : stdin;
  if (!res)
    {
      perror (file);
      exit (EX_NOINPUT);
    }
  return res;
}

/* A C main function.  */
int
main (int argc, const char **argv)
{]AT_PARAM_IF([[
  semantic_value result = 0;
  int count = 0;
  int nerrs = 0;]])[
  int status = 0;

  /* This used to be alarm (10), but that isn't enough time for a July
     1995 vintage DEC Alphastation 200 4/100 system, according to
     Nelson H. F. Beebe.  100 seconds was enough for regular users,
     but the Hydra build farm, which is heavily loaded needs more.  */

  alarm (200);

]AT_CXX_IF([], [AT_DEBUG_IF([  ]AT_NAME_PREFIX[debug = 1;])])[

  {
    int i;
    for (i = 1; i < argc; ++i)
      {
]AT_MULTISTART_IF([[
        if (!strcmp (argv[i], "--exp") && i+1 < argc)
          {
            input = open_file (argv[i+1]);
            ignore_eol = 1;
            ]AT_NAME_PREFIX[parse_exp_t res = ]AT_NAME_PREFIX[parse_exp ();
            printf ("exp => %d (status: %d, errors: %d)\n",
                    res.yystatus == 0 ? res.yyvalue : 0, res.yystatus, res.yynerrs);
            status = res.yystatus;
            ++i;
          }
        else if (!strcmp (argv[i], "--num") && i+1 < argc)
          {
            input = open_file (argv[i+1]);
            ignore_eol = 1;
            ]AT_NAME_PREFIX[parse_NUM_t res = ]AT_NAME_PREFIX[parse_NUM ();
            printf ("NUM => %d (status: %d, errors: %d)\n",
                    res.yystatus == 0 ? res.yyvalue : 0, res.yystatus, res.yynerrs);
            status = res.yystatus;
            ++i;
          }
        else]])[
          {
            input = open_file (argv[i]);
            status = ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([[&result, &count, &nerrs]])[);
          }
        if (input != stdin && fclose (input))
          perror ("fclose");
      }
  }
]AT_PARAM_IF([[
  assert (global_result == result); (void) result;
  assert (global_count  == count);  (void) count;
  assert (global_nerrs  == nerrs);  (void) nerrs;
  printf ("final: %d %d %d\n", global_result, global_count, global_nerrs);]])[
  return status;
}
]])


# AT_CALC_YYLEX(c).
m4_define([AT_CALC_YYLEX(c)],
[[#include <ctype.h>

]AT_YYLEX_DECLARE_EXTERN[

]AT_LOCATION_IF([
static AT_YYLTYPE last_yylloc;
])[
static int
get_char (]AT_YYLEX_FORMALS[)
{
  int res = getc (input);
  ]AT_USE_LEX_ARGS[;
]AT_LOCATION_IF([
  last_yylloc = AT_LOC;
  if (res == '\n')
    {
      AT_LOC_LAST_LINE++;
      AT_LOC_LAST_COLUMN = 1;
    }
  else
    AT_LOC_LAST_COLUMN++;
])[
  return res;
}

static void
unget_char (]AT_YYLEX_PRE_FORMALS[ int c)
{
  ]AT_USE_LEX_ARGS[;
]AT_LOCATION_IF([
  /* Wrong when C == '\n'. */
  AT_LOC = last_yylloc;
])[
  ungetc (c, input);
}

static int
read_integer (]AT_YYLEX_FORMALS[)
{
  int c = get_char (]AT_YYLEX_ARGS[);
  int res = 0;

  ]AT_USE_LEX_ARGS[;
  while (isdigit (c))
    {
      res = 10 * res + (c - '0');
      c = get_char (]AT_YYLEX_ARGS[);
    }

  unget_char (]AT_YYLEX_PRE_ARGS[ c);

  return res;
}


/*---------------------------------------------------------------.
| Lexical analyzer returns an integer on the stack and the token |
| NUM, or the ASCII character read if not a number.  Skips all   |
| blanks and tabs, returns 0 for EOF.                            |
`---------------------------------------------------------------*/

]AT_YYLEX_PROTOTYPE[
{
  int c;
  /* Skip white spaces.  */
  do
    {
]AT_LOCATION_IF([
      AT_LOC_FIRST_COLUMN = AT_LOC_LAST_COLUMN;
      AT_LOC_FIRST_LINE   = AT_LOC_LAST_LINE;
])[
    }
  while ((c = get_char (]AT_YYLEX_ARGS[)) == ' '
         || c == '\t'
         || (ignore_eol && c == '\n'));

  /* Process numbers.   */
  if (isdigit (c))
    {
      unget_char (]AT_YYLEX_PRE_ARGS[ c);
      ]AT_VAL[.]AT_VALUE_UNION_IF([NUM], [ival])[ = read_integer (]AT_YYLEX_ARGS[);
      return ]AT_TOKEN([NUM])[;
    }

  /* Return end-of-file.  */
  if (c == EOF)
    return ]AT_TOKEN([CALC_EOF])[;

  /* An explicit error raised by the scanner. */
  if (c == '#')
    {]AT_LOCATION_IF([
      fprintf (stderr, "%d.%d: ",
               AT_LOC_FIRST_LINE, AT_LOC_FIRST_COLUMN);])[
      fputs ("syntax error: invalid character: '#'\n", stderr);
      return ]AT_TOKEN(AT_API_PREFIX[][error])[;
    }

  /* Return single chars. */
  return c;
}
]])


m4_define([_AT_DATA_CALC_Y(c)],
[AT_DATA_GRAMMAR([calc.y],
[[/* Infix notation calculator--calc */
]$4[
%code requires
{
]AT_LOCATION_TYPE_SPAN_IF([[
  typedef struct
  {
    int l;
    int c;
  } Point;

  typedef struct
  {
    Point first;
    Point last;
  } Span;

# define YYLLOC_DEFAULT(Current, Rhs, N)                                \
  do                                                                    \
    if (N)                                                              \
      {                                                                 \
        (Current).first = YYRHSLOC (Rhs, 1).first;                      \
        (Current).last  = YYRHSLOC (Rhs, N).last;                       \
      }                                                                 \
    else                                                                \
      {                                                                 \
        (Current).first = (Current).last = YYRHSLOC (Rhs, 0).last;      \
      }                                                                 \
  while (0)

]AT_C_IF(
[[#include <stdio.h>
void location_print (FILE *o, Span s);
#define LOCATION_PRINT location_print
]])[

]])[
  /* Exercise pre-prologue dependency to %union.  */
  typedef int semantic_value;
}

]AT_VALUE_UNION_IF([],
[[/* Exercise %union. */
%union
{
  semantic_value ival;
};]])[
%printer { ]AT_CXX_IF([[yyo << $$]],
                      [[fprintf (yyo, "%d", $$)]])[; } <]AT_VALUE_UNION_IF([int], [ival])[>;

%code provides
{
  #include <stdio.h>
  /* The input.  */
  extern FILE *input;
  /* Whether \n is a blank.  */
  extern int ignore_eol;
  extern semantic_value global_result;
  extern int global_count;
  extern int global_nerrs;
}

%code
{
  #include <assert.h>
  #include <string.h>
  #define USE(Var)

  FILE *input;
  int ignore_eol = 0;
  static int power (int base, int exponent);

  ]AT_YYERROR_DECLARE[
  ]AT_YYLEX_DECLARE_EXTERN[

  ]AT_TOKEN_TRANSLATE_IF([[
#define N_
    static
    const char *
    _ (const char *cp)
    {
      if (strcmp (cp, "end of input") == 0)
        return "end of file";
      else if (strcmp (cp, "number") == 0)
        return "nombre";
      else
        return cp;
    }
  ]])[
}

]AT_LOCATION_TYPE_SPAN_IF([[
%initial-action
{
  @$.first.l = @$.first.c = 1;
  @$.last = @$.first;
}]])[

/* Bison Declarations */
%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
%token <]AT_VALUE_UNION_IF([int], [ival])[> NUM   "number"
%type  <]AT_VALUE_UNION_IF([int], [ival])[> exp

%nonassoc '='   /* comparison          */
%left '-' '+'
%left '*' '/'
%precedence NEG /* negation--unary minus */
%right '^'      /* exponentiation        */

/* Grammar follows */
%%
input:
  line
| input line         { ]AT_PARAM_IF([++*count; ++global_count;])[ }
;

line:
  '\n'
| exp '\n'           { ]AT_PARAM_IF([*result = global_result = $1;], [USE ($1);])[ }
;

exp:
  NUM
| exp '=' exp
  {
    if ($1 != $3)]AT_LANG_CASE(
      [c], [[
      {
        char buf[1024];
        snprintf (buf, sizeof buf, "error: %d != %d", $1, $3);]AT_YYERROR_ARG_LOC_IF([[
        yyerror (&@$, ]AT_PARAM_IF([result, count, nerrs, ])[buf);]], [[
        {
          YYLTYPE old_yylloc = yylloc;
          yylloc = @$;
          yyerror (]AT_PARAM_IF([result, count, nerrs, ])[buf);
          yylloc = old_yylloc;
        }
        ]])[
      }]],
      [c++], [[
      {
        char buf[1024];
        snprintf (buf, sizeof buf, "error: %d != %d", $1, $3);
        ]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@$, ]])[buf);
      }]])[
    $$ = $1;
  }
| exp '+' exp        { $$ = $1 + $3; }
| exp '-' exp        { $$ = $1 - $3; }
| exp '*' exp        { $$ = $1 * $3; }
| exp '/' exp
  {
    if ($3 == 0)]AT_LANG_CASE(
      [c], [[
      {]AT_YYERROR_ARG_LOC_IF([[
        yyerror (&@3, ]AT_PARAM_IF([result, count, nerrs, ])["error: null divisor");]], [[
        {
          YYLTYPE old_yylloc = yylloc;
          yylloc = @3;
          yyerr][or (]AT_PARAM_IF([result, count, nerrs, ])["error: null divisor");
          yylloc = old_yylloc;
        }
        ]])[
      }]],
      [c++], [[
      {
        ]AT_GLR_IF([[yyparser.]])[err][or (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
      }]])[
    else
      $$ = $1 / $3;
  }
| '-' exp  %prec NEG { $$ = -$2; }
| exp '^' exp        { $$ = power ($1, $3); }
| '(' exp ')'        { $$ = $2; }
| '(' error ')'      { $$ = 1111; yyerrok; }
| '!'                { $$ = 0; YYERROR; }
| '-' error          { $$ = 0; YYERROR; }
;
%%

int
power (int base, int exponent)
{
  int res = 1;
  assert (0 <= exponent);
  for (/* Niente */; exponent; --exponent)
    res *= base;
  return res;
}

]AT_LOCATION_TYPE_SPAN_IF([AT_CXX_IF([[
#include <iostream>
namespace
{
  std::ostream&
  operator<< (std::ostream& o, const Span& s)
  {
    o << s.first.l << '.' << s.first.c;
    if (s.first.l != s.last.l)
      o << '-' << s.last.l << '.' << s.last.c - 1;
    else if (s.first.c != s.last.c - 1)
      o << '-' << s.last.c - 1;
    return o;
  }
}
]], [[
void
location_print (FILE *o, Span s)
{
  fprintf (o, "%d.%d", s.first.l, s.first.c);
  if (s.first.l != s.last.l)
    fprintf (o, "-%d.%d", s.last.l, s.last.c - 1);
  else if (s.first.c != s.last.c - 1)
    fprintf (o, "-%d", s.last.c - 1);
}
]])])[
]AT_YYERROR_DEFINE[
]AT_HEADER_IF([],
[AT_CALC_YYLEX
AT_CALC_MAIN])])

AT_HEADER_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT],
[[#include "calc.]AT_LANG_HDR["

]AT_CALC_YYLEX])
AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT],
[[#include "calc.]AT_LANG_HDR["

]AT_CALC_MAIN])
])
])# _AT_DATA_CALC_Y(c)



## ------------- ##
## Calc in C++.  ##
## ------------- ##

m4_copy([AT_CALC_MAIN(c)], [AT_CALC_MAIN(c++)])
m4_copy([AT_CALC_YYLEX(c)], [AT_CALC_YYLEX(c++)])
m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)])


## ----------- ##
## Calc in D.  ##
## ----------- ##

# AT_CALC_MAIN(d).
m4_define([AT_CALC_MAIN(d)],
[[int main (string[] args)
{]AT_PARAM_IF([[
  semantic_value result = 0;
  int count = 0;]])[

  File input = args.length == 2 ? File (args[1], "r") : stdin;
  auto l = calcLexer (input);
  auto p = new YYParser (l);]AT_DEBUG_IF([[
  p.setDebugLevel (1);]])[
  return !p.parse ();
}
]])

m4_define([AT_CALC_YYLEX(d)],
[[import std.range.primitives;
import std.stdio;

auto calcLexer(R)(R range)
  if (isInputRange!R && is (ElementType!R : dchar))
{
  return new CalcLexer!R(range);
}

auto calcLexer (File f)
{
  import std.algorithm : map, joiner;
  import std.utf : byDchar;

  return f.byChunk(1024)        // avoid making a syscall roundtrip per char
          .map!(chunk => cast(char[]) chunk) // because byChunk returns ubyte[]
          .joiner               // combine chunks into a single virtual range of char
          .calcLexer;           // forward to other overload
}

class CalcLexer(R) : Lexer
  if (isInputRange!R && is (ElementType!R : dchar))
{
  R input;

  this(R r) {
    input = r;
  }

  ]AT_YYERROR_DEFINE[

  Value value_;]AT_LOCATION_IF([[
  Location location;
]])[
  int parseInt ()
  {
    auto res = 0;
    import std.uni : isNumber;
    while (input.front.isNumber)
      {
        res = res * 10 + (input.front - '0');]AT_LOCATION_IF([[
        location.end.column += 1;]])[
        input.popFront;
      }
    return res;
  }

  Symbol yylex ()
  {]AT_LOCATION_IF([[
    location.begin = location.end;]])[

    import std.uni : isWhite, isNumber;

    // Skip initial spaces
    while (!input.empty && input.front != '\n' && isWhite (input.front))
      {
        input.popFront;]AT_LOCATION_IF([[
        location.begin.column += 1;
        location.end.column += 1;]])[
      }

    // EOF.
    if (input.empty)
      return Symbol(TokenKind.]AT_TOKEN_PREFIX[EOF]AT_LOCATION_IF([[, location]])[);

    // Numbers.
    if (input.front.isNumber)
      {
        value_.ival = parseInt;
        return Symbol(TokenKind.]AT_TOKEN_PREFIX[NUM, value_.ival]AT_LOCATION_IF([[, location]])[);
      }

    // Individual characters
    auto c = input.front;]AT_LOCATION_IF([[
    if (c == '\n')
      {
        location.end.line += 1;
        location.end.column = 1;
      }
    else
      location.end.column += 1;]])[
    input.popFront;

    // An explicit error raised by the scanner. */
    if (c == '#')
      {
        stderr.writeln (]AT_LOCATION_IF([location, ": ", ])["syntax error: invalid character: '#'");
        return Symbol(TokenKind.]AT_TOKEN_PREFIX[YYerror]AT_LOCATION_IF([[, location]])[);
      }

    switch (c)
    {
      case '+':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[PLUS]AT_LOCATION_IF([[, location]])[);
      case '-':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[MINUS]AT_LOCATION_IF([[, location]])[);
      case '*':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[STAR]AT_LOCATION_IF([[, location]])[);
      case '/':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[SLASH]AT_LOCATION_IF([[, location]])[);
      case '(':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[LPAR]AT_LOCATION_IF([[, location]])[);
      case ')':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[RPAR]AT_LOCATION_IF([[, location]])[);
      case '\n': return Symbol(TokenKind.]AT_TOKEN_PREFIX[EOL]AT_LOCATION_IF([[, location]])[);
      case '=':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[EQUAL]AT_LOCATION_IF([[, location]])[);
      case '^':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[POW]AT_LOCATION_IF([[, location]])[);
      case '!':  return Symbol(TokenKind.]AT_TOKEN_PREFIX[NOT]AT_LOCATION_IF([[, location]])[);
      default:   return Symbol(TokenKind.]AT_TOKEN_PREFIX[YYUNDEF]AT_LOCATION_IF([[, location]])[);
    }
  }
}
]])

m4_define([_AT_DATA_CALC_Y(d)],
[AT_DATA_GRAMMAR([calc.y],
[[/* Infix notation calculator--calc */
]$4[
%code imports {
  alias semantic_value = int;
}
/* Exercise %union. */
%union
{
  semantic_value ival;
};
%printer { fprintf (yyo, "%d", $$); } <ival>;

/* Bison Declarations */
%token EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
%token <ival> NUM   "number"
%type  <ival> exp

%token EQUAL  "="
       MINUS  "-"
       PLUS   "+"
       STAR   "*"
       SLASH  "/"
       POW    "^"
       EOL    "\n"
       LPAR   "("
       RPAR   ")"
       NOT    "!"

%nonassoc "="   /* comparison          */
%left "-" "+"
%left "*" "/"
%precedence NEG /* negation--unary minus */
%right "^"      /* exponentiation        */

/* Grammar follows */
%%
input:
  line
| input line         { ]AT_PARAM_IF([++*count; ++global_count;])[ }
;

line:
  EOL
| exp EOL            { ]AT_PARAM_IF([*result = global_result = $1;])[ }
;

exp:
  NUM
| exp "=" exp
  {
    if ($1 != $3)
      yyerror (]AT_LOCATION_IF([[@$, ]])[format ("error: %d != %d", $1, $3));
    $$ = $1;
  }
| exp "+" exp        { $$ = $1 + $3; }
| exp "-" exp        { $$ = $1 - $3; }
| exp "*" exp        { $$ = $1 * $3; }
| exp "/" exp
  {
    if ($3 == 0)
      yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
    else
      $$ = $1 / $3;
  }
| "-" exp  %prec NEG { $$ = -$2; }
| exp "^" exp        { $$ = power ($1, $3); }
| "(" exp ")"        { $$ = $2; }
| "(" error ")"      { $$ = 1111; yyerrok(); }
| "!"                { $$ = 0; return YYERROR; }
| "-" error          { $$ = 0; return YYERROR; }
;
%%

int
power (int base, int exponent)
{
  int res = 1;
  assert (0 <= exponent);
  for (/* Niente */; exponent; --exponent)
    res *= base;
  return res;
}

]AT_CALC_YYLEX[
]AT_CALC_MAIN])
])# _AT_DATA_CALC_Y(d)



## -------------- ##
## Calc in Java.  ##
## -------------- ##

m4_define([AT_CALC_MAIN(java)],
[[public static void main (String[] args) throws IOException
  {]AT_LEXPARAM_IF([[
    Calc p = new Calc (System.in);]], [[
    CalcLexer l = new CalcLexer (System.in);
    Calc p = new Calc (l);]])AT_DEBUG_IF([[
    p.setDebugLevel (1);]])[
    boolean success = p.parse ();
    if (!success)
      System.exit (1);
  }
]])

m4_define([AT_CALC_YYLEX(java)],
[AT_LEXPARAM_IF([[%code lexer {]],
                [[%code epilogue { class CalcLexer implements Calc.Lexer {]])[
  StreamTokenizer st;]AT_LOCATION_IF([[
  PositionReader reader;]])[

  public ]AT_LEXPARAM_IF([[YYLexer]], [[CalcLexer]])[ (InputStream is)
  {]AT_LOCATION_IF([[
    reader = new PositionReader (new InputStreamReader (is));
    st = new StreamTokenizer (reader);]], [[
    st = new StreamTokenizer (new InputStreamReader (is));]])[
    st.resetSyntax ();
    st.eolIsSignificant (true);
    st.wordChars ('0', '9');
  }

]AT_LOCATION_IF([[
  Position start = new Position (1, 0);
  Position end = new Position (1, 0);

  public Position getStartPos () {
    return new Position (start);
  }

  public Position getEndPos () {
    return new Position (end);
  }

]])[
  ]AT_YYERROR_DEFINE[

  Integer yylval;

  public Object getLVal () {
    return yylval;
  }

  public int yylex() throws IOException {;]AT_LOCATION_IF([[
    start.set(reader.getPosition());]])[
    int tkind = st.nextToken();]AT_LOCATION_IF([[
    end.set(reader.getPosition());]])[
    switch (tkind)
      {
      case StreamTokenizer.TT_EOF:
        return CALC_EOF;
      case StreamTokenizer.TT_EOL:;]AT_LOCATION_IF([[
        end.line += 1;
        end.column = 0;]])[
        return (int) '\n';
      case StreamTokenizer.TT_WORD:
        yylval = Integer.parseInt(st.sval);]AT_LOCATION_IF([[
        end.set(reader.getPreviousPosition());]])[
        return NUM;
      case ' ': case '\t':
        return yylex();
      case '#':
        System.err.println(]AT_LOCATION_IF([[start + ": " + ]])["syntax error: invalid character: '#'");
        return YYerror;
      default:
        return tkind;
      }
  }
]AT_LEXPARAM_IF([], [[}]])[
};
]])

m4_define([_AT_DATA_CALC_Y(java)],
[AT_DATA_GRAMMAR([Calc.y],
[[/* Infix notation calculator--calc */
%define api.prefix {Calc}
%define api.parser.class {Calc}
%define public

]$4[

%code imports {]AT_LOCATION_IF([[
  import java.io.BufferedReader;]])[
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.Reader;
  import java.io.StreamTokenizer;
}

%code {
  ]AT_CALC_MAIN[

  ]AT_TOKEN_TRANSLATE_IF([[
    static String i18n(String s)
    {
      if (s.equals ("end of input"))
        return "end of file";
      else if (s.equals ("number"))
        return "nombre";
      else
        return s;
    }
  ]])[
}

/* Bison Declarations */
%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of file")], ["end of input"])[
%token <Integer> NUM "number"
%type  <Integer> exp

%nonassoc '='       /* comparison            */
%left '-' '+'
%left '*' '/'
%precedence NEG     /* negation--unary minus */
%right '^'          /* exponentiation        */

/* Grammar follows */
%%
input:
  line
| input line
;

line:
  '\n'
| exp '\n'
;

exp:
  NUM
| exp '=' exp
  {
    if ($1.intValue () != $3.intValue ())
      yyerror (]AT_LOCATION_IF([[@$, ]])["error: " + $1 + " != " + $3);
  }
| exp '+' exp        { $$ = $1 + $3; }
| exp '-' exp        { $$ = $1 - $3; }
| exp '*' exp        { $$ = $1 * $3; }
| exp '/' exp
  {
    if ($3.intValue () == 0)
      yyerror (]AT_LOCATION_IF([[@3, ]])["error: null divisor");
    else
      $$ = $1 / $3;
  }
| '-' exp  %prec NEG { $$ = -$2; }
| exp '^' exp        { $$ = (int) Math.pow ($1, $3); }
| '(' exp ')'        { $$ = $2; }
| '(' error ')'      { $$ = 1111; }
| '!'                { $$ = 0; return YYERROR; }
| '-' error          { $$ = 0; return YYERROR; }
;
]AT_CALC_YYLEX[
]AT_LOCATION_IF([[
%%
]AT_JAVA_POSITION_DEFINE])[
]])
])# _AT_DATA_JAVA_CALC_Y




## ------------------ ##
## Calculator tests.  ##
## ------------------ ##


# AT_DATA_CALC_Y([BISON-OPTIONS])
# -------------------------------
# Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or
# 'calc-lex.cc'.
m4_define([AT_DATA_CALC_Y],
[_AT_DATA_CALC_Y($[1], $[2], $[3], [$1])
])


# _AT_CHECK_CALC(CALC-OPTIONS, INPUT, [STDOUT], [NUM-STDERR-LINES])
# -----------------------------------------------------------------
# Run 'calc' on INPUT and expect no STDOUT nor STDERR.
#
# If BISON-OPTIONS contains '%debug' but not '%glr-parser', then
# NUM-STDERR-LINES is the number of expected lines on stderr.
# Currently this is ignored, though, since the output format is fluctuating.
#
# We don't count GLR's traces yet, since its traces are somewhat
# different from LALR's.  Likewise for D.
#
# The push traces are the same, except for "Return for a new token", don't
# count them.
m4_define([_AT_CHECK_CALC],
[AT_DATA([[input]],
[$2
])
AT_JAVA_IF(
  [AT_JAVA_PARSER_CHECK([Calc $1 < input], 0, [m4_ifvaln(m4_quote($3), [$3])], [stderr])],
  [AT_PARSER_CHECK([calc $1 input],        0, [m4_ifvaln(m4_quote($3), [$3])], [stderr])])
AT_LANG_MATCH([c\|c++\|java],
  [AT_GLR_IF([],
    [AT_CHECK([grep -c -v -E 'Return for a new token:|LAC:' stderr],
              [ignore],
              [m4_n([AT_DEBUG_IF([$4], [0])])])])])
])


# _AT_CHECK_CALC_ERROR($1 = BISON-OPTIONS, $2 = EXIT-STATUS, $3 = INPUT,
#                      $4 = [STDOUT],
#                      $5 = [NUM-STDERR-LINES],
#                      $6 = [CUSTOM-ERROR-MESSAGE])
#                      $7 = [CALC-OPTIONS])
# ----------------------------------------------------------------------
# Run 'calc' on INPUT, and expect a 'syntax error' message.
#
# If INPUT starts with a slash, it is used as absolute input file name,
# otherwise as contents.
#
# NUM-STDERR-LINES is the number of expected lines on stderr.
# If BISON-OPTIONS contains '%debug' but not '%glr', then NUM-STDERR-LINES
# is the number of expected lines on stderr.
#
# CUSTOM-ERROR-MESSAGE is the expected error message when parse.error
# is 'custom' and locations are enabled.  Other expected formats are
# computed from it.
m4_define([_AT_CHECK_CALC_ERROR],
[m4_bmatch([$3], [^/],
  [AT_JAVA_IF(
    [AT_JAVA_PARSER_CHECK([Calc $7 < $3], $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])],
    [AT_PARSER_CHECK([calc $7 $3],        $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])])],
  [AT_DATA([[input]],
[[$3
]])
  AT_JAVA_IF(
    [AT_JAVA_PARSER_CHECK([Calc $7 < input], $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])],
    [AT_PARSER_CHECK([calc $7 input],        $2, [m4_ifvaln(m4_quote($4), [$4])], [stderr])])
])

# Normalize the observed and expected error messages, depending upon the
# options.
# 1. Remove the traces from observed.
sed '
/ \$[[0-9$]]* = /d
/^Cleanup:/d
/^Discarding/d
/^Entering/d
/^Error:/d
/^LAC:/d
/^Next/d
/^Now/d
/^Reading/d
/^Reducing/d
/^Return/d
/^Shifting/d
/^Stack/d
/^Starting/d
/^state/d
/^yydestructor:/d
' stderr >at-stderr
mv at-stderr stderr

# 2. Create the reference error message.
AT_DATA([[expout]],
[$6
])

# 3. If locations are not used, remove them.
AT_YYERROR_SEES_LOC_IF([],
[[sed 's/^[-0-9.]*: //' expout >at-expout
mv at-expout expout]])

# 4. If parse.error is not custom, turn the expected message to
# the traditional one.
AT_ERROR_CUSTOM_IF([], [
AT_PERL_REQUIRE([[-pi -e 'use strict;
  s{syntax error on token \[(.*?)\] \(expected: (.*)\)}
  {
    my $unexp = $][1;
    my @exps = $][2 =~ /\[(.*?)\]/g;]AT_D_IF([[
    # In the case of D, there are no single quotes around the symbols.
    $unexp =~ s/'"'(.)'"'/$][1/g;
    s/'"'(.)'"'/$][1/g for @exps;]])[
    ($][#exps && $][#exps < 4)
    ? "syntax error, unexpected $unexp, expecting @{[join(\" or \", @exps)]}"
    : "syntax error, unexpected $unexp";
  }eg
' expout]])
])

# 5. If parse.error is simple, strip the', unexpected....' part.
AT_ERROR_SIMPLE_IF(
[[sed 's/syntax error, .*$/syntax error/' expout >at-expout
mv at-expout expout]])

# 6. Actually check.
AT_CHECK([cat stderr], 0, [expout])
])


# AT_CHECK_SPACES([FILES])
# ------------------------
# Make sure we did not introduce bad spaces.  Checked here because all
# the skeletons are (or should be) exercised here.
m4_define([AT_CHECK_SPACES],
[AT_PERL_CHECK([-ne '
  chomp;
  print "$ARGV:$.: {$_}\n"
    if (# No starting/ending empty lines.
        (eof || $. == 1) && /^\s*$/
        # No trailing space.
        || /\s$/
        # No tabs.
        || /\t/
        )' $1
])
])


# AT_CHECK_JAVA_GREP(FILE, [LINE], [COUNT=1])
# -------------------------------------------
# Check that FILE contains exactly COUNT lines matching ^LINE$
# with grep.  Unquoted so that COUNT can be a shell expression.
m4_define([AT_CHECK_JAVA_GREP],
[AT_CHECK_UNQUOTED([grep -c '^$2$' $1], [ignore], [m4_default([$3], [1])
])])


# AT_CHECK_CALC([BISON-OPTIONS], [COMPILER-OPTIONS])
# --------------------------------------------------
# Start a testing chunk which compiles 'calc' grammar with
# BISON-OPTIONS, and performs several tests over the parser.
m4_define([AT_CHECK_CALC],
[m4_ifval([$3], [m4_fatal([$0: expected at most two arguments])])

# We use integers to avoid dependencies upon the precision of doubles.
AT_SETUP([Calculator $1 $2])

AT_BISON_OPTION_PUSHDEFS([$1])

AT_DATA_CALC_Y([$1])
AT_FULL_COMPILE(AT_JAVA_IF([[Calc]], [[calc]]), AT_HEADER_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated])

AT_YACC_IF(
  [# No direct calls to malloc/free.
  AT_CHECK([[$EGREP '(malloc|free) *\(' calc.[ch] | $EGREP -v 'INFRINGES ON USER NAME SPACE']],
           [1])])

AT_PUSH_IF([AT_JAVA_IF(
 [# Verify that this is a push parser.
  AT_CHECK_JAVA_GREP([[Calc.java]],
                     [[.*public void push_parse_initialize ().*]])])])

AT_CHECK_SPACES([AT_JAVA_IF([Calc], [calc]).AT_LANG_EXT AT_HEADER_IF([AT_JAVA_IF([Calc], [calc]).AT_LANG_HDR])])

# Test the precedences.
# The Java traces do not show the clean up sequence at the end,
# since it does not support %destructor.
_AT_CHECK_CALC([],
[[1 + 2 * 3 = 7
1 + 2 * -3 = -5

-1^2 = -1
(-1)^2 = 1

---1 = -1

1 - 2 - 3 = -4
1 - (2 - 3) = 2

2^2^3 = 256
(2^2)^3 = 64]],
[AT_PARAM_IF([final: 64 12 0])],
               [AT_JAVA_IF([1014], [1017])])

# Some syntax errors.
_AT_CHECK_CALC_ERROR([$1], [1], [1 2],
                     [AT_PARAM_IF([final: 0 0 1])],
                     [15],
                     [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]])
_AT_CHECK_CALC_ERROR([$1], [1], [1//2],
                     [AT_PARAM_IF([final: 0 0 1])],
                     [20],
                     [AT_JAVA_IF([1.3-1.4], [1.3])[: syntax error on token ['/'] (expected: [number] ['-'] ['('] ['!'])]])
_AT_CHECK_CALC_ERROR([$1], [1], [error],
                     [AT_PARAM_IF([final: 0 0 1])],
                     [5],
                     [AT_JAVA_IF([1.1-1.2], [1.1])[: syntax error on token [invalid token] (expected: [number] ['-'] ['\n'] ['('] ['!'])]])
_AT_CHECK_CALC_ERROR([$1], [1], [1 = 2 = 3],
                     [AT_PARAM_IF([final: 0 0 1])],
                     [30],
                     [AT_LAC_IF(
                       [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'] ['\n'])]],
                       [AT_JAVA_IF([1.7-1.8], [1.7])[: syntax error on token ['='] (expected: ['-'] ['+'] ['*'] ['/'] ['^'])]])])
_AT_CHECK_CALC_ERROR([$1], [1],
                     [
+1],
                     [AT_PARAM_IF([final: 0 0 1])],
                     [20],
                     [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'] ['('] ['!'])]])
# Exercise error messages with EOF: work on an empty file.
_AT_CHECK_CALC_ERROR([$1], [1], [/dev/null],
                     [AT_PARAM_IF([final: 0 0 1])],
                     [4],
                     [[1.1: syntax error on token ]AT_TOKEN_TRANSLATE_IF([[[end of file]]], [[[end of input]]])[ (expected: [number] ['-'] ['\n'] ['('] ['!'])]])

# Exercise the error token: without it, we die at the first error,
# hence be sure to
#
# - have several errors which exercise different shift/discardings
#   - (): nothing to pop, nothing to discard
#   - (1 + 1 + 1 +): a lot to pop, nothing to discard
#   - (* * *): nothing to pop, a lot to discard
#   - (1 + 2 * *): some to pop and discard
#
# - test the action associated to 'error'
#
# - check the lookahead that triggers an error is not discarded
#   when we enter error recovery.  Below, the lookahead causing the
#   first error is ")", which is needed to recover from the error and
#   produce the "0" that triggers the "0 != 1" error.
#
_AT_CHECK_CALC_ERROR([$1], [0],
                     [() + (1 + 1 + 1 +) + (* * *) + (1 * 2 * *) = 1],
                     [AT_PARAM_IF([final: 4444 0 5])],
                     [250],
[AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!'])
]AT_JAVA_IF([1.18-1.19], [1.18])[: syntax error on token [')'] (expected: [number] ['-'] ['('] ['!'])
]AT_JAVA_IF([1.23-1.24], [1.23])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
]AT_JAVA_IF([1.41-1.42], [1.41])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
]AT_JAVA_IF([1.1-1.47], [1.1-46])[: error: 4444 != 1]])

# The same, but this time exercising explicitly triggered syntax errors.
# POSIX says the lookahead causing the error should not be discarded.
_AT_CHECK_CALC_ERROR([$1], [0], [(!) + (1 2) = 1],
                     [AT_PARAM_IF([final: 2222 0 2])],
                     [102],
[AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')'])
]AT_JAVA_IF([1.1-1.16], [1.1-15])[: error: 2222 != 1]])

_AT_CHECK_CALC_ERROR([$1], [0], [(- *) + (1 2) = 1],
                     [AT_PARAM_IF([final: 2222 0 3])],
                     [113],
[AT_JAVA_IF([1.4-1.5], [1.4])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
]AT_JAVA_IF([1.12-1.13], [1.12])[: syntax error on token [number] (expected: ['='] ['-'] ['+'] ['*'] ['/'] ['^'] [')'])
]AT_JAVA_IF([1.1-1.18], [1.1-17])[: error: 2222 != 1]])

# Check that yyerrok works properly: second error is not reported,
# third and fourth are.  Parse status is successful.
_AT_CHECK_CALC_ERROR([$1], [0], [(* *) + (*) + (*)],
                     [AT_PARAM_IF([final: 3333 0 3])],
                     [113],
[AT_JAVA_IF([1.2-1.3], [1.2])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
]AT_JAVA_IF([1.10-1.11], [1.10])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])
]AT_JAVA_IF([1.16-1.17], [1.16])[: syntax error on token ['*'] (expected: [number] ['-'] ['('] ['!'])]])


# YYerror.
# --------
# Check that returning YYerror from the scanner properly enters
# error-recovery without issuing a second error message.

_AT_CHECK_CALC_ERROR([$1], [0], [(#) + (#) = 2222],
                     [AT_PARAM_IF([final: 2222 0 0])],
                     [102],
[[1.2: syntax error: invalid character: '#'
1.8: syntax error: invalid character: '#']])

_AT_CHECK_CALC_ERROR([$1], [0], [(1 + #) = 1111],
                     [AT_PARAM_IF([final: 1111 0 0])],
                     [102],
[[1.6: syntax error: invalid character: '#']])

_AT_CHECK_CALC_ERROR([$1], [0], [(# + 1) = 1111],
                     [AT_PARAM_IF([final: 1111 0 0])],
                     [102],
[[1.2: syntax error: invalid character: '#']])

_AT_CHECK_CALC_ERROR([$1], [0], [(1 + # + 1) = 1111],
                     [AT_PARAM_IF([final: 1111 0 0])],
                     [102],
[[1.6: syntax error: invalid character: '#']])

_AT_CHECK_CALC_ERROR([$1], [0], [(1 + 1) / (1 - 1)],
                     [AT_PARAM_IF([final: 2 0 1])],
                     [102],
[AT_JAVA_IF([1.11-1.18], [1.11-17])[: error: null divisor]])

# Multiple start symbols.
AT_MULTISTART_IF([
_AT_CHECK_CALC([--num], [[123]],
               [[NUM => 123 (status: 0, errors: 0)]],
               [AT_JAVA_IF([1014], [1017])])
_AT_CHECK_CALC_ERROR([$1], [1], [1 + 2 * 3],
                     [NUM => 0 (status: 1, errors: 1)],
                     [102],
                     [[1.3: syntax error, unexpected '+', expecting end of file]],
                     [--num])

_AT_CHECK_CALC([--exp], [[1 + 2 * 3]],
               [[exp => 7 (status: 0, errors: 0)]],
               [AT_JAVA_IF([1014], [1017])])
])


AT_BISON_OPTION_POPDEFS

AT_CLEANUP
])# AT_CHECK_CALC




# ----------------- #
# LALR Calculator.  #
# ----------------- #

AT_BANNER([[LALR(1) Calculator.]])

# AT_CHECK_CALC_LALR([BISON-OPTIONS])
# -----------------------------------
# Start a testing chunk which compiles 'calc' grammar with
# BISON-OPTIONS, and performs several tests over the parser.
m4_define([AT_CHECK_CALC_LALR],
[AT_CHECK_CALC($@)])

AT_CHECK_CALC_LALR([%define parse.trace])

AT_CHECK_CALC_LALR([%header])
AT_CHECK_CALC_LALR([%debug %locations])
AT_CHECK_CALC_LALR([%locations %define api.location.type {Span}])

AT_CHECK_CALC_LALR([%name-prefix "calc"])
AT_CHECK_CALC_LALR([%verbose])
AT_CHECK_CALC_LALR([%yacc])
AT_CHECK_CALC_LALR([%define parse.error detailed])
AT_CHECK_CALC_LALR([%define parse.error verbose])

AT_CHECK_CALC_LALR([%define api.pure full %locations])
AT_CHECK_CALC_LALR([%define api.push-pull both %define api.pure full %locations])
AT_CHECK_CALC_LALR([%define parse.error detailed %locations])

AT_CHECK_CALC_LALR([%define parse.error detailed %locations %header %define api.prefix {calc} %verbose %yacc])
AT_CHECK_CALC_LALR([%define parse.error detailed %locations %header %name-prefix "calc" %define api.token.prefix {TOK_} %verbose %yacc])

AT_CHECK_CALC_LALR([%debug])
AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %header %name-prefix "calc" %verbose %yacc])
AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %header %define api.prefix {calc} %verbose %yacc])

AT_CHECK_CALC_LALR([%define api.pure full %define parse.error detailed %debug %locations %header %name-prefix "calc" %verbose %yacc])
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])

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}])

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}])
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}])
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}])

# parse.error custom.
AT_CHECK_CALC_LALR([%define parse.error custom])
AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc}])
AT_CHECK_CALC_LALR([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}])
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])
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])

# multistart.
AT_CHECK_CALC_LALR([%start input exp NUM %define api.value.type union])
AT_CHECK_CALC_LALR([%start input exp NUM %define api.value.type union %locations %define parse.error detailed])


# ---------------- #
# GLR Calculator.  #
# ---------------- #

AT_BANNER([[GLR Calculator.]])

m4_define([AT_CHECK_CALC_GLR],
[AT_CHECK_CALC([%glr-parser] $@)])

AT_CHECK_CALC_GLR()

AT_CHECK_CALC_GLR([%header])
AT_CHECK_CALC_GLR([%locations])
AT_CHECK_CALC_GLR([%locations %define api.location.type {Span}])
AT_CHECK_CALC_GLR([%name-prefix "calc"])
AT_CHECK_CALC_GLR([%define api.prefix {calc}])
AT_CHECK_CALC_GLR([%verbose])
AT_CHECK_CALC_GLR([%define parse.error verbose])

AT_CHECK_CALC_GLR([%define api.pure %locations])
AT_CHECK_CALC_GLR([%define parse.error verbose %locations])

AT_CHECK_CALC_GLR([%define parse.error custom %locations %header %name-prefix "calc" %verbose])
AT_CHECK_CALC_GLR([%define parse.error detailed %locations %header %name-prefix "calc" %verbose])
AT_CHECK_CALC_GLR([%define parse.error verbose %locations %header %name-prefix "calc" %verbose])

AT_CHECK_CALC_GLR([%debug])
AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose])
AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %header %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose])

AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %header %name-prefix "calc" %verbose])

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}])
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}])

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}])


# ---------------------- #
# LALR1 C++ Calculator.  #
# ---------------------- #

AT_BANNER([[LALR(1) C++ Calculator.]])

# First let's try using %skeleton
AT_CHECK_CALC([%skeleton "lalr1.cc" %header])

m4_define([AT_CHECK_CALC_LALR1_CC],
[AT_CHECK_CALC([%language "C++" $1], [$2])])

AT_CHECK_CALC_LALR1_CC([])
AT_CHECK_CALC_LALR1_CC([%locations])
AT_CHECK_CALC_LALR1_CC([%locations], [$NO_EXCEPTIONS_CXXFLAGS])
AT_CHECK_CALC_LALR1_CC([%locations %define api.location.type {Span}])
AT_CHECK_CALC_LALR1_CC([%header %locations %define parse.error verbose %name-prefix "calc" %verbose])

AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %define api.prefix {calc} %verbose])
AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %name-prefix "calc" %verbose])

AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose])
AT_CHECK_CALC_LALR1_CC([%locations %define parse.error verbose %debug %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose])

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}])

AT_CHECK_CALC_LALR1_CC([%define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
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}])

AT_CHECK_CALC_LALR1_CC([%header %locations %define api.location.file none])
AT_CHECK_CALC_LALR1_CC([%header %locations %define api.location.file "my-location.hh"])

AT_CHECK_CALC_LALR1_CC([%no-lines %header %locations %define api.location.file "my-location.hh"])

AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error verbose])
AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed])
AT_CHECK_CALC_LALR1_CC([%locations %define parse.lac full %define parse.error detailed %define parse.trace])

AT_CHECK_CALC_LALR1_CC([%define parse.error custom])
AT_CHECK_CALC_LALR1_CC([%define parse.error custom %locations %define api.prefix {calc} %parse-param {semantic_value *result}{int *count}{int *nerrs}])
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])

# -------------------- #
# GLR C++ Calculator.  #
# -------------------- #

AT_BANNER([[GLR C++ Calculator.]])

# Again, we try also using %skeleton.
AT_CHECK_CALC([%skeleton "glr.cc"])
AT_CHECK_CALC([%skeleton "glr2.cc"])

m4_define([AT_CHECK_CALC_GLR_CC],
[AT_CHECK_CALC([%language "C++" %glr-parser] $@) # glr.cc
AT_CHECK_CALC([%skeleton "glr2.cc"] $@)
])

AT_CHECK_CALC_GLR_CC([])
AT_CHECK_CALC_GLR_CC([%locations])
AT_CHECK_CALC_GLR_CC([%locations %define api.location.type {Span}])
AT_CHECK_CALC_GLR_CC([%header %define parse.error verbose %name-prefix "calc" %verbose])
AT_CHECK_CALC_GLR_CC([%define parse.error verbose %define api.prefix {calc} %verbose])

AT_CHECK_CALC_GLR_CC([%debug])

AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %verbose])
AT_CHECK_CALC_GLR_CC([%define parse.error verbose %debug %name-prefix "calc" %define api.token.prefix {TOK_} %verbose])

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}])
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}])

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}])


# -------------------- #
# LALR1 D Calculator.  #
# -------------------- #

AT_BANNER([[LALR(1) D Calculator.]])

# First let's try using %skeleton
AT_CHECK_CALC([%skeleton "lalr1.d"])

m4_define([AT_CHECK_CALC_LALR1_D],
[AT_CHECK_CALC([%language "D" $1], [$2])])

AT_CHECK_CALC_LALR1_D([])
AT_CHECK_CALC_LALR1_D([%locations])
#AT_CHECK_CALC_LALR1_D([%locations %define api.location.type {Span}])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %define api.prefix {calc} %verbose])

AT_CHECK_CALC_LALR1_D([%debug])

AT_CHECK_CALC_LALR1_D([%define parse.error custom])
AT_CHECK_CALC_LALR1_D([%locations %define parse.error custom])
AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed])
AT_CHECK_CALC_LALR1_D([%locations %define parse.error simple])
AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %verbose])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %define api.token.prefix {TOK_} %verbose])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %define api.symbol.prefix {SYMB_} %verbose])
AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %define api.symbol.prefix {SYMB_} %define api.token.prefix {TOK_} %verbose])

AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error verbose])
AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error custom])
AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error detailed %define parse.trace])

#AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose %debug %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
#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}])


# ----------------------- #
# LALR1 Java Calculator.  #
# ----------------------- #

AT_BANNER([[LALR(1) Java Calculator.]])

m4_define([AT_CHECK_CALC_LALR1_JAVA],
[AT_CHECK_CALC([%language "Java" $1], [$2])])

AT_CHECK_CALC_LALR1_JAVA
AT_CHECK_CALC_LALR1_JAVA([%define parse.error custom])
AT_CHECK_CALC_LALR1_JAVA([%define parse.error detailed])
AT_CHECK_CALC_LALR1_JAVA([%define parse.error verbose])
AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error custom])
AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error detailed])
AT_CHECK_CALC_LALR1_JAVA([%locations %define parse.error verbose])
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose])
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is}])

AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both])
AT_CHECK_CALC_LALR1_JAVA([%define api.push-pull both %define parse.error detailed %locations])
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %lex-param {InputStream is} %define api.push-pull both])
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %locations %lex-param {InputStream is} %define api.push-pull both])

# parse.lac.
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %define parse.lac full])
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locations %define api.push-pull both %define parse.lac full])


m4_popdef([AT_CALC_MAIN])
m4_popdef([AT_CALC_YYLEX])
