Files
bison/tests/calc.at
Adela Vais dc15b62a7c d: add the custom error message feature
Parser.Context class returns a const YYLocation, so Lexer's method
yyerror() needs to receive the location as a const parameter.

Internal error reporting flow is changed to be similar to that of
the other skeletons. Before, case YYERRLAB was calling yyerror()
with the result of yysyntax_error() as the string parameter. As the
custom error message lets the user decide if they want to use
yyerror() or not, this flow needed to be changed. Now, case YYERRLAB
calls yyreportSyntaxError(), that builds the error message using
yysyntaxErrorArguments(). Then yyreportSyntaxError() passes the
error message to the user defined syntax_error() in case of a custom
message, or to yyerror() otherwise.

In the tests in tests/calc.at, the order of the tokens needs to be
changed in order of precedence, so that the D program outputs the
expected tokens in the same order as the other parsers.

* data/skeletons/lalr1.d: Add the custom error message feature.
* doc/bison.texi: Document it.
* examples/d/calc/calc.y: Adjust.
* tests/calc.at, tests/local.at: Test it.
2020-11-07 17:03:23 +01:00

1499 lines
46 KiB
Plaintext

# 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;
static FILE *
open_file (const char *file)
{
FILE *res = (file && *file && strcmp (file, "-")) ? fopen (file, "r") : stdin;
if (!res)
{
perror (file);
exit (3);
}
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_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[NUM;
}
/* Return end-of-file. */
if (c == EOF)
return ]AT_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[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_CXX_IF([AT_NAMESPACE::parser::token::])[]AT_TOKEN_PREFIX[]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;
yyerror (]AT_PARAM_IF([result, count, nerrs, ])["error: null divisor");
yylloc = old_yylloc;
}
]])[
}]],
[c++], [[
{
]AT_GLR_IF([[yyparser.]])[error (]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[
YYSemanticType semanticVal_;]AT_LOCATION_IF([[
YYLocation location = new YYLocation;
public final @property YYPosition startPos()
{
return location.begin;
}
public final @property YYPosition endPos()
{
return location.end;
}
]])[
public final @property YYSemanticType semanticVal()
{
return semanticVal_;
}
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;
}
TokenKind 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 TokenKind.]AT_TOKEN_PREFIX[EOF;
// Numbers.
if (input.front.isNumber)
{
semanticVal_.ival = parseInt;
return TokenKind.]AT_TOKEN_PREFIX[NUM;
}
// 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 TokenKind.]AT_TOKEN_PREFIX[YYerror;
}
switch (c)
{
case '+': return TokenKind.]AT_TOKEN_PREFIX[PLUS;
case '-': return TokenKind.]AT_TOKEN_PREFIX[MINUS;
case '*': return TokenKind.]AT_TOKEN_PREFIX[STAR;
case '/': return TokenKind.]AT_TOKEN_PREFIX[SLASH;
case '(': return TokenKind.]AT_TOKEN_PREFIX[LPAR;
case ')': return TokenKind.]AT_TOKEN_PREFIX[RPAR;
case '\n': return TokenKind.]AT_TOKEN_PREFIX[EOL;
case '=': return TokenKind.]AT_TOKEN_PREFIX[EQUAL;
case '^': return TokenKind.]AT_TOKEN_PREFIX[POW;
case '!': return TokenKind.]AT_TOKEN_PREFIX[NOT;
default: return TokenKind.]AT_TOKEN_PREFIX[YYUNDEF;
}
}
}
]])
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.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])