mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
tests: style: reorder the calculator test macros
* tests/local.at (AT_TOKEN_TRANSLATE_IF): New, moved from... * tests/calc.at: here. Instead of sorting per feature (main, yylex, calc.y) and then by language, do the converse, so that C bits are together, etc.
This commit is contained in:
800
tests/calc.at
800
tests/calc.at
@@ -19,16 +19,42 @@
|
|||||||
## Compile the grammar described in the documentation. ##
|
## 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_CALC_MAIN. #
|
# AT_DATA_CALC. #
|
||||||
# -------------- #
|
# -------------- #
|
||||||
|
|
||||||
m4_pushdef([AT_CALC_MAIN], [AT_LANG_DISPATCH([$0], $@)])
|
|
||||||
|
|
||||||
# Whether token translation is supported.
|
# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES])
|
||||||
m4_pushdef([AT_TOKEN_TRANSLATE_IF],
|
# -----------------------------------------------
|
||||||
[AT_ERROR_CUSTOM_IF([$1], [AT_ERROR_DETAILED_IF([$1], [$2])])])
|
# 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)],
|
m4_define([AT_CALC_MAIN(c)],
|
||||||
[[#include <assert.h>
|
[[#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -95,44 +121,8 @@ main (int argc, const char **argv)
|
|||||||
}
|
}
|
||||||
]])
|
]])
|
||||||
|
|
||||||
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], $@)])
|
|
||||||
|
|
||||||
|
|
||||||
|
# AT_CALC_YYLEX(c).
|
||||||
m4_define([AT_CALC_YYLEX(c)],
|
m4_define([AT_CALC_YYLEX(c)],
|
||||||
[[#include <ctype.h>
|
[[#include <ctype.h>
|
||||||
|
|
||||||
@@ -234,7 +224,266 @@ read_integer (]AT_YYLEX_FORMALS[)
|
|||||||
}
|
}
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exercise %union. */
|
||||||
|
%union
|
||||||
|
{
|
||||||
|
semantic_value ival;
|
||||||
|
};
|
||||||
|
%printer { ]AT_CXX_IF([[yyo << $$]],
|
||||||
|
[[fprintf (yyo, "%d", $$)]])[; } <ival>;
|
||||||
|
|
||||||
|
%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;], [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_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)],
|
m4_define([AT_CALC_YYLEX(d)],
|
||||||
[[import std.range.primitives;
|
[[import std.range.primitives;
|
||||||
@@ -360,6 +609,114 @@ class CalcLexer(R) : Lexer
|
|||||||
}
|
}
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
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 CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[
|
||||||
|
%token <ival> NUM "number"
|
||||||
|
%type <ival> exp
|
||||||
|
|
||||||
|
%token PLUS "+"
|
||||||
|
MINUS "-"
|
||||||
|
STAR "*"
|
||||||
|
SLASH "/"
|
||||||
|
LPAR "("
|
||||||
|
RPAR ")"
|
||||||
|
EQUAL "="
|
||||||
|
POW "^"
|
||||||
|
NOT "!"
|
||||||
|
EOL "\n"
|
||||||
|
|
||||||
|
%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;], [USE ($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_YYERROR_DEFINE[
|
||||||
|
]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)],
|
m4_define([AT_CALC_YYLEX(java)],
|
||||||
[AT_LEXPARAM_IF([[%code lexer {]],
|
[AT_LEXPARAM_IF([[%code lexer {]],
|
||||||
@@ -427,357 +784,6 @@ m4_define([AT_CALC_YYLEX(java)],
|
|||||||
};
|
};
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
|
||||||
# -------------- #
|
|
||||||
# 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], $@)])
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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, "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)
|
|
||||||
|
|
||||||
|
|
||||||
m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)])
|
|
||||||
|
|
||||||
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 CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[
|
|
||||||
%token <ival> NUM "number"
|
|
||||||
%type <ival> exp
|
|
||||||
|
|
||||||
%token PLUS "+"
|
|
||||||
MINUS "-"
|
|
||||||
STAR "*"
|
|
||||||
SLASH "/"
|
|
||||||
LPAR "("
|
|
||||||
RPAR ")"
|
|
||||||
EQUAL "="
|
|
||||||
POW "^"
|
|
||||||
NOT "!"
|
|
||||||
EOL "\n"
|
|
||||||
|
|
||||||
%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;], [AT_D_IF([], [USE ($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; ]AT_D_IF([], [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_YYERROR_DEFINE[
|
|
||||||
]AT_CALC_YYLEX
|
|
||||||
AT_CALC_MAIN])
|
|
||||||
])# _AT_DATA_CALC_Y(d)
|
|
||||||
|
|
||||||
m4_define([_AT_DATA_CALC_Y(java)],
|
m4_define([_AT_DATA_CALC_Y(java)],
|
||||||
[AT_DATA_GRAMMAR([Calc.y],
|
[AT_DATA_GRAMMAR([Calc.y],
|
||||||
[[/* Infix notation calculator--calc */
|
[[/* Infix notation calculator--calc */
|
||||||
@@ -868,6 +874,12 @@ exp:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## ------------------ ##
|
||||||
|
## Calculator tests. ##
|
||||||
|
## ------------------ ##
|
||||||
|
|
||||||
|
|
||||||
# AT_DATA_CALC_Y([BISON-OPTIONS])
|
# AT_DATA_CALC_Y([BISON-OPTIONS])
|
||||||
# -------------------------------
|
# -------------------------------
|
||||||
# Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or
|
# Produce 'calc.y' and, if %header was specified, 'calc-lex.c' or
|
||||||
@@ -877,7 +889,6 @@ m4_define([AT_DATA_CALC_Y],
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# _AT_CHECK_CALC(BISON-OPTIONS, INPUT, [STDOUT], [NUM-STDERR-LINES])
|
# _AT_CHECK_CALC(BISON-OPTIONS, INPUT, [STDOUT], [NUM-STDERR-LINES])
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Run 'calc' on INPUT and expect no STDOUT nor STDERR.
|
# Run 'calc' on INPUT and expect no STDOUT nor STDERR.
|
||||||
@@ -1404,6 +1415,5 @@ AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error custom %locati
|
|||||||
AT_CHECK_CALC_LALR1_JAVA([%define parse.trace %define parse.error verbose %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_MAIN])
|
||||||
m4_popdef([AT_CALC_YYLEX])
|
m4_popdef([AT_CALC_YYLEX])
|
||||||
|
|||||||
@@ -340,6 +340,10 @@ m4_pushdef([AT_PURE_LEX_IF],
|
|||||||
[AT_PURE_IF([$1],
|
[AT_PURE_IF([$1],
|
||||||
[AT_CXX_IF([$1], [$2])])])
|
[AT_CXX_IF([$1], [$2])])])
|
||||||
|
|
||||||
|
# Whether token translation is supported.
|
||||||
|
m4_pushdef([AT_TOKEN_TRANSLATE_IF],
|
||||||
|
[AT_ERROR_CUSTOM_IF([$1], [AT_ERROR_DETAILED_IF([$1], [$2])])])
|
||||||
|
|
||||||
m4_pushdef([AT_YYSTYPE],
|
m4_pushdef([AT_YYSTYPE],
|
||||||
[AT_CXX_IF([AT_NAMESPACE[::parser::semantic_type]],
|
[AT_CXX_IF([AT_NAMESPACE[::parser::semantic_type]],
|
||||||
[AT_API_PREFIX[STYPE]])])
|
[AT_API_PREFIX[STYPE]])])
|
||||||
@@ -409,6 +413,7 @@ m4_popdef([AT_YYLTYPE])
|
|||||||
m4_popdef([AT_YYSTYPE])
|
m4_popdef([AT_YYSTYPE])
|
||||||
m4_popdef([AT_VAL])
|
m4_popdef([AT_VAL])
|
||||||
m4_popdef([AT_LOC])
|
m4_popdef([AT_LOC])
|
||||||
|
m4_popdef([AT_TOKEN_TRANSLATE_IF])
|
||||||
m4_popdef([AT_PURE_LEX_IF])
|
m4_popdef([AT_PURE_LEX_IF])
|
||||||
m4_popdef([AT_YYERROR_SEES_LOC_IF])
|
m4_popdef([AT_YYERROR_SEES_LOC_IF])
|
||||||
m4_popdef([AT_YYERROR_ARG_LOC_IF])
|
m4_popdef([AT_YYERROR_ARG_LOC_IF])
|
||||||
|
|||||||
Reference in New Issue
Block a user