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. ##
|
||||
## ---------------------------------------------------- ##
|
||||
|
||||
|
||||
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.
|
||||
m4_pushdef([AT_TOKEN_TRANSLATE_IF],
|
||||
[AT_ERROR_CUSTOM_IF([$1], [AT_ERROR_DETAILED_IF([$1], [$2])])])
|
||||
# _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 <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)],
|
||||
[[#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_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;
|
||||
@@ -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)],
|
||||
[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)],
|
||||
[AT_DATA_GRAMMAR([Calc.y],
|
||||
[[/* Infix notation calculator--calc */
|
||||
@@ -868,6 +874,12 @@ exp:
|
||||
|
||||
|
||||
|
||||
|
||||
## ------------------ ##
|
||||
## Calculator tests. ##
|
||||
## ------------------ ##
|
||||
|
||||
|
||||
# AT_DATA_CALC_Y([BISON-OPTIONS])
|
||||
# -------------------------------
|
||||
# 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])
|
||||
# ------------------------------------------------------------------
|
||||
# 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])
|
||||
|
||||
|
||||
m4_popdef([AT_TOKEN_TRANSLATE_IF])
|
||||
m4_popdef([AT_CALC_MAIN])
|
||||
m4_popdef([AT_CALC_YYLEX])
|
||||
|
||||
@@ -340,6 +340,10 @@ m4_pushdef([AT_PURE_LEX_IF],
|
||||
[AT_PURE_IF([$1],
|
||||
[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],
|
||||
[AT_CXX_IF([AT_NAMESPACE[::parser::semantic_type]],
|
||||
[AT_API_PREFIX[STYPE]])])
|
||||
@@ -409,6 +413,7 @@ m4_popdef([AT_YYLTYPE])
|
||||
m4_popdef([AT_YYSTYPE])
|
||||
m4_popdef([AT_VAL])
|
||||
m4_popdef([AT_LOC])
|
||||
m4_popdef([AT_TOKEN_TRANSLATE_IF])
|
||||
m4_popdef([AT_PURE_LEX_IF])
|
||||
m4_popdef([AT_YYERROR_SEES_LOC_IF])
|
||||
m4_popdef([AT_YYERROR_ARG_LOC_IF])
|
||||
|
||||
Reference in New Issue
Block a user