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", $$)]])[; } ; -]AT_D_IF([], [[ +]AT_LANG_MATCH([c\|c++], [[ %code provides { #include @@ -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 NUM "number" %type 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 NUM "number" +%type 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 # -----------------------