summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkim Demaille <akim.demaille@gmail.com>2020-02-02 07:50:50 +0100
committerAkim Demaille <akim.demaille@gmail.com>2020-02-02 11:33:16 +0100
commitfe14fb1c4026b96907efb77fc242a007558b08de (patch)
tree4509d14c5331fae22368fc4d6163bddb3b3c57d2
parent88d1ab421a4730504aabd1e61e8380027ec96545 (diff)
downloadbison-fe14fb1c4026b96907efb77fc242a007558b08de.tar.gz
java: use the same calc tests as the other skeletons
* tests/local.at (AT_LANG_MATCH): New. (AT_YYERROR_DECLARE(java), AT_YYERROR_DECLARE_EXTERN(java)): New. * tests/calc.at: The grammar file for Java is quite different for the others, and continuing to assemble it from pieces makes the grammar file hard to understand. Let's also dispatch on the language to assemble it, and isolate Java from the others. Most of this comes from java.at.
-rw-r--r--data/skeletons/lalr1.java4
-rw-r--r--tests/calc.at273
-rw-r--r--tests/local.at9
3 files changed, 260 insertions, 26 deletions
diff --git a/data/skeletons/lalr1.java b/data/skeletons/lalr1.java
index de912383..e9da8cc5 100644
--- a/data/skeletons/lalr1.java
+++ b/data/skeletons/lalr1.java
@@ -565,7 +565,7 @@ m4_define([b4_define_state],[[
]b4_location_type[ yyloc;]])[
]b4_push_if([],[[
]b4_define_state[]b4_parse_trace_if([[
- yycdebug ("Starting parse\n");]])[
+ yycdebug ("Starting parse");]])[
yyerrstatus_ = 0;
yynerrs = 0;
@@ -599,7 +599,7 @@ b4_dollar_popdef[]dnl
/* New state. Unlike in the C/C++ skeletons, the state is already
pushed when we come here. */
case YYNEWSTATE:]b4_parse_trace_if([[
- yycdebug ("Entering state " + yystate + "\n");
+ yycdebug ("Entering state " + yystate);
if (0 < yydebug)
yystack.print (yyDebugStream);]])[
diff --git a/tests/calc.at b/tests/calc.at
index 2884275e..837a4d52 100644
--- a/tests/calc.at
+++ b/tests/calc.at
@@ -112,6 +112,19 @@ m4_define([AT_CALC_MAIN(d)],
]])
+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. #
@@ -318,6 +331,66 @@ class CalcLexer(R) : Lexer
]])
+m4_define([AT_CALC_YYLEX(java)],
+[AT_LEXPARAM_IF([[%code lexer {]],
+ [[%code epilogue { class CalcLexer implements Calc.Lexer {]])[
+ StreamTokenizer st;
+
+ public ]AT_LEXPARAM_IF([[YYLexer]], [[CalcLexer]])[ (InputStream is)
+ {
+ st = new StreamTokenizer (new InputStreamReader (is));
+ st.resetSyntax ();
+ st.eolIsSignificant (true);
+ st.whitespaceChars ('\t', '\t');
+ st.whitespaceChars (' ', ' ');
+ st.wordChars ('0', '9');
+ }
+
+]AT_LOCATION_IF([[
+ Position yypos = new Position (1, 0);
+
+ public Position getStartPos() {
+ return yypos;
+ }
+
+ public Position getEndPos() {
+ return yypos;
+ }
+]])[
+ ]AT_YYERROR_DEFINE[
+
+ Integer yylval;
+
+ public Object getLVal () {
+ return yylval;
+ }
+
+ public int yylex () throws IOException {
+ int ttype = st.nextToken ();]AT_LOCATION_IF([[
+ yypos = new Position (yypos.lineno (), yypos.token () + 1);]])[
+ if (ttype == st.TT_EOF)
+ return EOF;
+
+ else if (ttype == st.TT_EOL)
+ {]AT_LOCATION_IF([[
+ yypos = new Position (yypos.lineno () + 1, 0);]])[
+ return (int) '\n';
+ }
+
+ else if (ttype == st.TT_WORD)
+ {
+ yylval = new Integer (st.sval);
+ return NUM;
+ }
+
+ else
+ return st.ttype;
+ }
+]AT_LEXPARAM_IF([], [[}]])[
+};
+]])
+
+
# -------------- #
# AT_DATA_CALC. #
# -------------- #
@@ -338,19 +411,23 @@ class CalcLexer(R) : Lexer
# 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_define([_AT_DATA_CALC_Y],
+m4_pushdef([_AT_DATA_CALC_Y],
[m4_if([$1$2$3], $[1]$[2]$[3], [],
[m4_fatal([$0: Invalid arguments: $@])])dnl
+AT_LANG_DISPATCH([$0], $@)])
-AT_DATA_GRAMMAR([calc.y],
+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_D_IF([[
+]AT_LANG_MATCH(
+[d], [[
%code imports {
alias semantic_value = int;
}
-]], [[
+]],
+[c\|c++], [[
%code requires
{
]AT_LOCATION_TYPE_SPAN_IF([[
@@ -399,7 +476,7 @@ void location_print (FILE *o, Span s);
%printer { ]AT_CXX_IF([[yyo << $$]],
[[fprintf (yyo, "%d", $$)]])[; } <ival>;
-]AT_D_IF([], [[
+]AT_LANG_MATCH([c\|c++], [[
%code provides
{
#include <stdio.h>
@@ -448,7 +525,7 @@ void location_print (FILE *o, Span s);
}]])[
/* Bison Declarations */
-%token CALC_EOF 0 _("end of input")
+%token CALC_EOF 0 ]AT_TOKEN_TRANSLATE_IF([_("end of input")], ["end of input"])[
%token <ival> NUM "number"
%type <ival> exp
@@ -480,16 +557,16 @@ exp:
])[
$$ = $1;
}
-| exp '+' exp { $$ = $1 + $3; }
-| exp '-' exp { $$ = $1 - $3; }
-| exp '*' exp { $$ = $1 * $3; }
-| exp '/' exp { $$ = $1 / $3; }
-| '-' exp %prec NEG { $$ = -$2; }
+| 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])[; }
+| '(' exp ')' { $$ = $2; }
+| '(' error ')' { $$ = 1111; ]AT_D_IF([], [yyerrok;])[ }
+| '!' { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; }
+| '-' error { $$ = 0; ]AT_D_IF([return YYERROR], [YYERROR])[; }
;
%%
@@ -543,10 +620,137 @@ AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT],
]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 {
+ import java.io.StreamTokenizer;
+ import java.io.InputStream;
+ import java.io.InputStreamReader;
+ import java.io.Reader;
+ import java.io.IOException;
+}
+
+%code {
+]AT_CALC_MAIN[
+}
+
+/* Bison Declarations */
+%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_LEXPARAM_IF([[%code lexer {]],
+ [[%code epilogue { class CalcLexer implements Calc.Lexer {]])[
+ StreamTokenizer st;
+
+ public ]AT_LEXPARAM_IF([[YYLexer]], [[CalcLexer]])[ (InputStream is)
+ {
+ st = new StreamTokenizer (new InputStreamReader (is));
+ st.resetSyntax ();
+ st.eolIsSignificant (true);
+ st.whitespaceChars ('\t', '\t');
+ st.whitespaceChars (' ', ' ');
+ st.wordChars ('0', '9');
+ }
+
+]AT_LOCATION_IF([[
+ Position yypos = new Position (1, 0);
+
+ public Position getStartPos() {
+ return yypos;
+ }
+
+ public Position getEndPos() {
+ return yypos;
+ }
+]])[
+ ]AT_YYERROR_DEFINE[
+
+ Integer yylval;
+
+ public Object getLVal() {
+ return yylval;
+ }
+
+ public int yylex () throws IOException {
+ int ttype = st.nextToken ();]AT_LOCATION_IF([[
+ yypos = new Position (yypos.lineno (), yypos.token () + 1);]])[
+ if (ttype == st.TT_EOF)
+ return EOF;
+
+ else if (ttype == st.TT_EOL)
+ {]AT_LOCATION_IF([[
+ yypos = new Position (yypos.lineno () + 1, 0);]])[
+ return (int) '\n';
+ }
+
+ else if (ttype == st.TT_WORD)
+ {
+ yylval = new Integer (st.sval);
+ return NUM;
+ }
+
+ else
+ return st.ttype;
+ }
+]AT_LEXPARAM_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
@@ -571,8 +775,10 @@ m4_define([_AT_CHECK_CALC],
[AT_DATA([[input]],
[[$2
]])
-AT_PARSER_CHECK([calc input], 0, [AT_PARAM_IF([m4_n([$3])])], [stderr])
-AT_D_IF([],
+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++],
[AT_GLR_IF([],
[AT_CHECK([cat stderr | wc -l], [0], [m4_n([AT_DEBUG_IF([$4], [0])])])])])
])
@@ -597,11 +803,16 @@ AT_D_IF([],
# computed from it.
m4_define([_AT_CHECK_CALC_ERROR],
[m4_bmatch([$3], [^/],
- [AT_PARSER_CHECK([calc $3], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])],
- [AT_DATA([[input]],
+ [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_PARSER_CHECK([calc input], $2, [AT_PARAM_IF([m4_n([$4])])], [stderr])])
+ 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.
@@ -690,8 +901,8 @@ AT_SETUP([Calculator $1 $2])
AT_BISON_OPTION_PUSHDEFS([$1])
AT_DATA_CALC_Y([$1])
-AT_FULL_COMPILE([calc], AT_DEFINES_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated])
-AT_CHECK_SPACES([calc.AT_LANG_EXT AT_DEFINES_IF([calc.AT_LANG_HDR])])
+AT_FULL_COMPILE(AT_JAVA_IF([[Calc]], [[calc]]), AT_DEFINES_IF([[lex], [main]], [[], []]), [$2], [-Wno-deprecated])
+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.
_AT_CHECK_CALC([$1],
@@ -812,7 +1023,7 @@ AT_BANNER([[LALR(1) Calculator.]])
m4_define([AT_CHECK_CALC_LALR],
[AT_CHECK_CALC($@)])
-AT_CHECK_CALC_LALR()
+AT_CHECK_CALC_LALR([%define parse.trace])
AT_CHECK_CALC_LALR([%defines])
AT_CHECK_CALC_LALR([%locations])
@@ -980,6 +1191,20 @@ AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %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
+
+
+
m4_popdef([AT_TOKEN_TRANSLATE_IF])
m4_popdef([AT_CALC_MAIN])
m4_popdef([AT_CALC_YYLEX])
diff --git a/tests/local.at b/tests/local.at
index 20c7cd0d..307e341f 100644
--- a/tests/local.at
+++ b/tests/local.at
@@ -442,6 +442,12 @@ m4_define([AT_LANG_CASE],
[m4_case(AT_LANG, $@)])
+# AT_LANG_MATCH(LANG1, IF-LANG1, LANG2, IF-LANG2, ..., DEFAULT)
+# ------------------------------------------------------------
+m4_define([AT_LANG_MATCH],
+[m4_bmatch(AT_LANG, $@)])
+
+
# _AT_LANG_DISPATCH(LANG, MACRO, ARGS)
# ------------------------------------
# Call the specialization of MACRO for LANG with ARGS. Complain if
@@ -818,6 +824,9 @@ m4_define([AT_MAIN_DEFINE(d)],
# ------------------------------
m4_copy([AT_DATA], [AT_DATA_GRAMMAR(java)])
+# No need to declare, it's part of the class interface.
+m4_define([AT_YYERROR_DECLARE(java)], [])
+m4_define([AT_YYERROR_DECLARE_EXTERN(java)], [])
# AT_JAVA_POSITION_DEFINE
# -----------------------