mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
* data/skeletons/lalr1.cc: added support here * tests/calc.at: added test cases * tests/local.at: added yyreport_syntax_error implementation for C++ test cases
1228 lines
38 KiB
Plaintext
1228 lines
38 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. ##
|
|
## ---------------------------------------------------- ##
|
|
|
|
# -------------- #
|
|
# AT_CALC_MAIN. #
|
|
# -------------- #
|
|
|
|
m4_pushdef([AT_CALC_MAIN], [AT_LANG_DISPATCH([$0], $@)])
|
|
|
|
# Whether token translation is supported.
|
|
m4_pushdef([AT_TOKEN_TRANSLATE_IF],
|
|
[AT_ERROR_CUSTOM_IF([$1], [AT_ERROR_DETAILED_IF([$1], [$2])])])
|
|
|
|
m4_define([AT_CALC_MAIN(c)],
|
|
[[#include <assert.h>
|
|
#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;
|
|
|
|
/* 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;
|
|
|
|
/* 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);
|
|
|
|
if (argc == 2)
|
|
input = fopen (argv[1], "r");
|
|
else
|
|
input = stdin;
|
|
|
|
if (!input)
|
|
{
|
|
perror (argv[1]);
|
|
return 3;
|
|
}
|
|
|
|
]AT_CXX_IF([], [AT_DEBUG_IF([ ]AT_NAME_PREFIX[debug = 1;])])[
|
|
status = ]AT_NAME_PREFIX[parse (]AT_PARAM_IF([[&result, &count, &nerrs]])[);
|
|
if (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;
|
|
}
|
|
]])
|
|
|
|
m4_copy([AT_CALC_MAIN(c)], [AT_CALC_MAIN(c++)])
|
|
|
|
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_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);
|
|
}
|
|
]])
|
|
|
|
|
|
# --------------- #
|
|
# AT_CALC_YYLEX. #
|
|
# --------------- #
|
|
|
|
m4_pushdef([AT_CALC_YYLEX], [AT_LANG_DISPATCH([$0], $@)])
|
|
|
|
|
|
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');
|
|
|
|
/* Process numbers. */
|
|
if (isdigit (c))
|
|
{
|
|
unget_char (]AT_YYLEX_PRE_ARGS[ c);
|
|
]AT_VAL[.ival = read_integer (]AT_YYLEX_ARGS[);
|
|
return ]AT_TOKEN_PREFIX[NUM;
|
|
}
|
|
|
|
/* Return end-of-file. */
|
|
if (c == EOF)
|
|
return ]AT_TOKEN_PREFIX[CALC_EOF;
|
|
|
|
/* Return single chars. */
|
|
return c;
|
|
}
|
|
]])
|
|
|
|
m4_copy([AT_CALC_YYLEX(c)], [AT_CALC_YYLEX(c++)])
|
|
|
|
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;
|
|
}
|
|
|
|
int 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;]])[
|
|
}
|
|
|
|
// Handle EOF.
|
|
if (input.empty)
|
|
return YYTokenType.EOF;
|
|
|
|
// Numbers.
|
|
if (input.front.isNumber)
|
|
{
|
|
semanticVal_.ival = parseInt;
|
|
return YYTokenType.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;
|
|
return c;
|
|
}
|
|
}
|
|
]])
|
|
|
|
|
|
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 ttype = st.nextToken ();]AT_LOCATION_IF([[
|
|
end.set (reader.getPosition ());]])[
|
|
switch (ttype)
|
|
{
|
|
case StreamTokenizer.TT_EOF:
|
|
return EOF;
|
|
case StreamTokenizer.TT_EOL:;]AT_LOCATION_IF([[
|
|
end.line += 1;
|
|
end.column = 0;]])[
|
|
return (int) '\n';
|
|
case StreamTokenizer.TT_WORD:
|
|
yylval = new Integer (st.sval);]AT_LOCATION_IF([[
|
|
end.set (reader.getPreviousPosition ());]])[
|
|
return NUM;
|
|
case ' ': case '\t':
|
|
return yylex ();
|
|
default:
|
|
return ttype;
|
|
}
|
|
}
|
|
]AT_LEXPARAM_IF([], [[}]])[
|
|
};
|
|
]])
|
|
|
|
|
|
# -------------- #
|
|
# AT_DATA_CALC. #
|
|
# -------------- #
|
|
|
|
|
|
# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES])
|
|
# -----------------------------------------------
|
|
# Produce 'calc.y' and, if %defines 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 %defines 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], $@)])
|
|
|
|
m4_define([_AT_DATA_CALC_Y(c)],
|
|
[AT_DATA_GRAMMAR([calc.y],
|
|
[[/* Infix notation calculator--calc */
|
|
]$4[
|
|
]AT_CXX_IF([%define global_tokens_and_yystype])[
|
|
]AT_LANG_MATCH(
|
|
[d], [[
|
|
%code imports {
|
|
alias semantic_value = int;
|
|
}
|
|
]],
|
|
[c\|c++], [[
|
|
%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;
|
|
}
|
|
]])[
|
|
|
|
/* Exercise %union. */
|
|
%union
|
|
{
|
|
semantic_value ival;
|
|
};
|
|
%printer { ]AT_CXX_IF([[yyo << $$]],
|
|
[[fprintf (yyo, "%d", $$)]])[; } <ival>;
|
|
|
|
]AT_LANG_MATCH([c\|c++], [[
|
|
%code provides
|
|
{
|
|
#include <stdio.h>
|
|
/* The input. */
|
|
extern FILE *input;
|
|
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;
|
|
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 input")], ["end of input"])[
|
|
%token <ival> NUM "number"
|
|
%type <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;], [AT_D_IF([], [USE ($1);])])[ }
|
|
;
|
|
|
|
exp:
|
|
NUM
|
|
| exp '=' exp
|
|
{
|
|
if ($1 != $3)]AT_LANG_CASE(
|
|
[c], [[
|
|
{
|
|
char buf[1024];
|
|
snprintf (buf, sizeof buf, "calc: 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, "calc: error: %d != %d", $1, $3);
|
|
]AT_GLR_IF([[yyparser.]])[error (]AT_LOCATION_IF([[@$, ]])[buf);
|
|
}]],
|
|
[d], [[
|
|
yyerror (]AT_LOCATION_IF([[@$, ]])[format ("calc: error: %d != %d", $1, $3));]])[
|
|
$$ = $1;
|
|
}
|
|
| exp '+' exp { $$ = $1 + $3; }
|
|
| exp '-' exp { $$ = $1 - $3; }
|
|
| exp '*' exp { $$ = $1 * $3; }
|
|
| exp '/' exp { $$ = $1 / $3; }
|
|
| '-' exp %prec NEG { $$ = -$2; }
|
|
| exp '^' exp { $$ = power ($1, $3); }
|
|
| '(' exp ')' { $$ = $2; }
|
|
| '(' error ')' { $$ = 1111; ]AT_D_IF([], [yyerrok;])[ }
|
|
| '!' { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; }
|
|
| '-' error { $$ = 0; ]AT_D_IF([return YYERROR], [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_DEFINES_IF([],
|
|
[AT_CALC_YYLEX
|
|
AT_CALC_MAIN])])
|
|
|
|
AT_DEFINES_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
|
|
|
|
|
|
m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)])
|
|
m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(d)])
|
|
|
|
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 _ (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 input")], ["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([[@$, ]])["calc: error: " + $1 + " != " + $3);
|
|
}
|
|
| exp '+' exp { $$ = $1 + $3; }
|
|
| exp '-' exp { $$ = $1 - $3; }
|
|
| exp '*' exp { $$ = $1 * $3; }
|
|
| exp '/' exp { $$ = $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
|
|
|
|
|
|
|
|
# AT_DATA_CALC_Y([BISON-OPTIONS])
|
|
# -------------------------------
|
|
# Produce 'calc.y' and, if %defines 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(BISON-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 < input], 0, [AT_PARAM_IF([m4_n([$3])])], [stderr])],
|
|
[AT_PARSER_CHECK([calc input], 0, [AT_PARAM_IF([m4_n([$3])])], [stderr])])
|
|
AT_LANG_MATCH([c\|c++\|java],
|
|
[AT_GLR_IF([],
|
|
[AT_CHECK([grep -v 'Return for a new token:' stderr | wc -l],
|
|
[0],
|
|
[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])
|
|
# ----------------------------------------------------------------------
|
|
# 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 < $3], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])],
|
|
[AT_PARSER_CHECK([calc $3], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])])],
|
|
[AT_DATA([[input]],
|
|
[[$3
|
|
]])
|
|
AT_JAVA_IF(
|
|
[AT_JAVA_PARSER_CHECK([Calc < input], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])],
|
|
[AT_PARSER_CHECK([calc input], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])])
|
|
])
|
|
|
|
# Normalize the observed and expected error messages, depending upon the
|
|
# options.
|
|
# 1. Remove the traces from observed.
|
|
sed '/^Starting/d
|
|
/^Entering/d
|
|
/^Stack/d
|
|
/^Reading/d
|
|
/^Reducing/d
|
|
/^Return/d
|
|
/^Shifting/d
|
|
/^state/d
|
|
/^Cleanup:/d
|
|
/^Error:/d
|
|
/^Next/d
|
|
/^Now/d
|
|
/^Discarding/d
|
|
/ \$[[0-9$]]* = /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;
|
|
($][#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) exercized 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_DEFINES_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated])
|
|
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_DEFINES_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],
|
|
[[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]],
|
|
[[final: 64 12 0]],
|
|
[AT_JAVA_IF([1014], [1017])])
|
|
|
|
# Some syntax errors.
|
|
_AT_CHECK_CALC_ERROR([$1], [1], [1 2],
|
|
[[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],
|
|
[[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],
|
|
[[final: 0 0 1]],
|
|
[5],
|
|
[AT_JAVA_IF([1.1-1.2], [1.1])[: syntax error on token [$undefined] (expected: [number] ['-'] ['\n'] ['('] ['!'])]])
|
|
_AT_CHECK_CALC_ERROR([$1], [1], [1 = 2 = 3],
|
|
[[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],
|
|
[[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],
|
|
[[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],
|
|
[[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])[: calc: 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],
|
|
[[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])[: calc: error: 2222 != 1]])
|
|
|
|
_AT_CHECK_CALC_ERROR([$1], [0], [(- *) + (1 2) = 1],
|
|
[[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])[: calc: 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], [(* *) + (*) + (*)],
|
|
[[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] ['-'] ['('] ['!'])]])
|
|
|
|
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([%defines])
|
|
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 %defines %define api.prefix {calc} %verbose %yacc])
|
|
AT_CHECK_CALC_LALR([%define parse.error detailed %locations %defines %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 %defines %name-prefix "calc" %verbose %yacc])
|
|
AT_CHECK_CALC_LALR([%define parse.error detailed %debug %locations %defines %define api.prefix {calc} %verbose %yacc])
|
|
|
|
AT_CHECK_CALC_LALR([%define api.pure full %define parse.error detailed %debug %locations %defines %name-prefix "calc" %verbose %yacc])
|
|
AT_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])
|
|
|
|
AT_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}])
|
|
|
|
AT_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}])
|
|
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}])
|
|
|
|
|
|
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])
|
|
|
|
# ---------------- #
|
|
# 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([%defines])
|
|
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 %defines %name-prefix "calc" %verbose])
|
|
AT_CHECK_CALC_GLR([%define parse.error detailed %locations %defines %name-prefix "calc" %verbose])
|
|
AT_CHECK_CALC_GLR([%define parse.error verbose %locations %defines %name-prefix "calc" %verbose])
|
|
|
|
AT_CHECK_CALC_GLR([%debug])
|
|
AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose])
|
|
AT_CHECK_CALC_GLR([%define parse.error verbose %debug %locations %defines %define api.prefix {calc} %define api.token.prefix {TOK_} %verbose])
|
|
|
|
AT_CHECK_CALC_GLR([%define api.pure %define parse.error verbose %debug %locations %defines %name-prefix "calc" %verbose])
|
|
|
|
AT_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}])
|
|
AT_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}])
|
|
|
|
AT_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}])
|
|
|
|
|
|
# ---------------------- #
|
|
# LALR1 C++ Calculator. #
|
|
# ---------------------- #
|
|
|
|
AT_BANNER([[LALR(1) C++ Calculator.]])
|
|
|
|
# First let's try using %skeleton
|
|
AT_CHECK_CALC([%skeleton "lalr1.cc" %defines])
|
|
|
|
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([%defines %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([%defines %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([%defines %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([%defines %locations %define api.location.file none])
|
|
AT_CHECK_CALC_LALR1_CC([%defines %locations %define api.location.file "my-location.hh"])
|
|
|
|
AT_CHECK_CALC_LALR1_CC([%no-lines %defines %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([%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"])
|
|
|
|
m4_define([AT_CHECK_CALC_GLR_CC],
|
|
[AT_CHECK_CALC([%language "C++" %glr-parser] $@)])
|
|
|
|
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([%defines %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 %defines %define parse.error verbose %debug %name-prefix "calc" %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
|
|
AT_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}])
|
|
|
|
AT_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}])
|
|
|
|
|
|
# -------------------- #
|
|
# 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 verbose %debug %verbose])
|
|
#AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %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])
|
|
|
|
|
|
m4_popdef([AT_TOKEN_TRANSLATE_IF])
|
|
m4_popdef([AT_CALC_MAIN])
|
|
m4_popdef([AT_CALC_YYLEX])
|