From 8405b70c057cf1e117e81a77114b055d7c9b59f1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 29 Jan 2007 10:54:42 +0000 Subject: [PATCH] 2007-01-29 Paolo Bonzini * NEWS: Mention java. * TODO: Remove things that are done. * bootstrap.conf: Add javacomp-script and javaexec-script. * configure.ac: Invoke gt_JAVACOMP and gt_JAVAEXEC. * data/Makefile.am: Add new files. * data/java-skel.m4: New. * data/java.m4: New. * data/lalr1.java: New. * doc/bison.texinfo: Put "A Complete C++ Example" under C++ Parsers. Add Java Parsers. Put C++ Parsers and Java Parsers under Other Languages. * src/getargs.c (valid_languages): Add Java. * src/getargs.h (struct bison_language): Update size of string fields. * tests/Makefile.am: Add java.at. * tests/atlocal.in: Add CONF_JAVA and CONF_JAVAC. * tests/java.at: New. * tests/testsuite.at: Include it. --- ChangeLog | 24 ++ NEWS | 3 + TODO | 27 -- bootstrap.conf | 7 +- build-aux/.cvsignore | 2 + configure.ac | 3 + data/Makefile.am | 3 +- data/java-skel.m4 | 28 ++ data/java.m4 | 268 +++++++++++++ data/lalr1.java | 880 +++++++++++++++++++++++++++++++++++++++++++ doc/bison.texinfo | 385 +++++++++++++++++-- m4/.cvsignore | 2 + src/getargs.c | 3 +- src/getargs.h | 13 +- tests/Makefile.am | 1 + tests/atlocal.in | 6 + tests/input.at | 2 + tests/java.at | 415 ++++++++++++++++++++ tests/testsuite.at | 3 + 19 files changed, 2012 insertions(+), 63 deletions(-) create mode 100644 data/java-skel.m4 create mode 100644 data/java.m4 create mode 100644 data/lalr1.java create mode 100644 tests/java.at diff --git a/ChangeLog b/ChangeLog index cd74bed8..475df516 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2007-01-29 Paolo Bonzini + + * NEWS: Mention java. + * TODO: Remove things that are done. + * bootstrap.conf: Add javacomp-script and javaexec-script. + * configure.ac: Invoke gt_JAVACOMP and gt_JAVAEXEC. + + * data/Makefile.am: Add new files. + * data/java-skel.m4: New. + * data/java.m4: New. + * data/lalr1.java: New. + + * doc/bison.texinfo: Put "A Complete C++ Example" under + C++ Parsers. Add Java Parsers. Put C++ Parsers and Java Parsers + under Other Languages. + + * src/getargs.c (valid_languages): Add Java. + * src/getargs.h (struct bison_language): Update size of string fields. + + * tests/Makefile.am: Add java.at. + * tests/atlocal.in: Add CONF_JAVA and CONF_JAVAC. + * tests/java.at: New. + * tests/testsuite.at: Include it. + 2007-01-28 Joel E. Denny Clean up. diff --git a/NEWS b/NEWS index 7d35ebf5..68fb66f0 100644 --- a/NEWS +++ b/NEWS @@ -92,6 +92,9 @@ Changes in version 2.3a+ (????-??-??): Changes in version 2.3a, 2006-09-13: +* Bison now supports generating Java parsers. Grammars written for + the Java language should include the `%language "Java"' directive. + * Instead of %union, you can define and use your own union type YYSTYPE if your grammar contains at least one tag. Your YYSTYPE need not be a macro; it can be a typedef. diff --git a/TODO b/TODO index 7d6f20ea..94bd12c8 100644 --- a/TODO +++ b/TODO @@ -14,13 +14,6 @@ find something clean (not like YYLSP_NEEDED...). * Installation -** Disable installation of yacc. - -Add an option to 'configure' that allows people to install Bison -without installing the yacc wrapper script or the rarely-used little -yacc library required by Posix. This is for people who prefer some -other implementation of yacc. - * Documentation Before releasing, make sure the documentation ("Understanding your parser") refers to the current `output' format. @@ -154,23 +147,6 @@ Are there any Texinfo standards for bibliography? * Java, Fortran, etc. -** Java - -There are a couple of proposed outputs: - -- BYACC/J - which is based on Byacc. - - -- Bison Java - which is based on Bison. - - -Sebastien Serrurier (serrur_s@epita.fr) is working on this: he is -expected to contact the authors, design the output, and implement it -into Bison. - - * Coding system independence Paul notes: @@ -231,9 +207,6 @@ It is unfortunate that there is a total order for precedence. It makes it impossible to have modular precedence information. We should move to partial orders (sounds like series/parallel orders to me). -This will be possible with a Bison parser for the grammar, as it will -make it much easier to extend the grammar. - ** Correlation b/w precedence and associativity Also, I fail to understand why we have to assign the same associativity to operators with the same precedence. For instance, diff --git a/bootstrap.conf b/bootstrap.conf index f4fe8d5b..478e71f9 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -21,9 +21,10 @@ # gnulib modules used by this package. gnulib_modules=' argmatch config-h configmake dirname error extensions fopen-safer - getopt gettext hash inttypes malloc mbswidth obstack quote - quotearg stdbool stpcpy strerror strtoul strverscmp unistd - unistd-safer unlocked-io verify xalloc xalloc-die xstrndup + getopt gettext hash inttypes javacomp-script javaexec-script malloc + mbswidth obstack quote quotearg stdbool stpcpy strerror strtoul + strverscmp unistd unistd-safer unlocked-io verify xalloc xalloc-die + xstrndup ' # Any gnulib files needed that are not in modules. diff --git a/build-aux/.cvsignore b/build-aux/.cvsignore index 971508e4..f7724115 100644 --- a/build-aux/.cvsignore +++ b/build-aux/.cvsignore @@ -6,6 +6,8 @@ config.rpath config.sub depcomp install-sh +javacomp.sh.in +javaexec.sh.in mdate-sh missing mkinstalldirs diff --git a/configure.ac b/configure.ac index 56a69b60..9e609d56 100644 --- a/configure.ac +++ b/configure.ac @@ -136,6 +136,9 @@ AC_SUBST([O0CFLAGS]) O0CXXFLAGS=`echo $CXXFLAGS | sed 's/-O[[0-9]] *//'` AC_SUBST([O0CXXFLAGS]) +gt_JAVACOMP([1.3], [1.3]) +gt_JAVAEXEC + AC_CONFIG_FILES([Makefile build-aux/Makefile po/Makefile.in diff --git a/data/Makefile.am b/data/Makefile.am index 69574343..9f526edc 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -17,7 +17,8 @@ dist_pkgdata_DATA = README bison.m4 \ c-skel.m4 c.m4 yacc.c glr.c push.c \ - c++-skel.m4 c++.m4 location.cc lalr1.cc glr.cc + c++-skel.m4 c++.m4 location.cc lalr1.cc glr.cc \ + java-skel.m4 java.m4 lalr1.java m4sugardir = $(pkgdatadir)/m4sugar dist_m4sugar_DATA = m4sugar/m4sugar.m4 diff --git a/data/java-skel.m4 b/data/java-skel.m4 new file mode 100644 index 00000000..f00981a4 --- /dev/null +++ b/data/java-skel.m4 @@ -0,0 +1,28 @@ + -*- Autoconf -*- + +# Java skeleton dispatching for Bison. +# Copyright (C) 2007 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +b4_glr_if( [b4_complain([%%glr-parser not supported for Java])]) +b4_nondeterministic_if([b4_complain([%%nondeterministic-parser not supported for Java])]) +b4_push_if( [b4_complain([%%push-parser is not supported for Java])]) + +m4_define_default([b4_used_skeleton], [b4_pkgdatadir/[lalr1.java]]) +m4_define_default([b4_skeleton], ["b4_basename(b4_used_skeleton)"]) + +m4_include(b4_used_skeleton) diff --git a/data/java.m4 b/data/java.m4 new file mode 100644 index 00000000..47b6008a --- /dev/null +++ b/data/java.m4 @@ -0,0 +1,268 @@ + -*- Autoconf -*- + +# Java language support for Bison + +# Copyright (C) 2007 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + + +# b4_comment(TEXT) +# ---------------- +m4_define([b4_comment], [/* m4_bpatsubst([$1], [ +], [ + ]) */]) + + +# b4_flag_value(BOOLEAN-FLAG) +# --------------------------- +m4_define([b4_flag_value], [b4_flag_if([$1], [true], [false])]) + + +# b4_public_if(TRUE, FALSE) +# ------------------------- +b4_percent_define_default([public], 0) +m4_define([b4_public_if], +[b4_percent_define_flag_if([public], [$1], [$2])]) + +# b4_single_class_if(TRUE, FALSE) +# ------------------------------- +b4_percent_define_default([single_class], 0) +m4_define([b4_single_class_if], +[b4_percent_define_flag_if([single_class], [$1], [$2])]) + + +# b4_abstract_if(TRUE, FALSE) +# --------------------------- +m4_define([b4_abstract_if], +[b4_pure_if([$2], [b4_single_class_if([$2], [$1])])]) + + +# b4_identification +# ----------------- +m4_define([b4_identification], +[/** Always true, identifies Bison output. */ + public static final boolean bison = true; + + /** Version number for the Bison executable that generated this parser. */ + public static final String bisonVersion = "b4_version"; + + /** Name of the skeleton that generated this parser. */ + public static final String bisonSkeleton = b4_skeleton; +]) + + +## ------------ ## +## Data types. ## +## ------------ ## + +# b4_int_type(MIN, MAX) +# --------------------- +# Return the smallest int type able to handle numbers ranging from +# MIN to MAX (included). +m4_define([b4_int_type], +[m4_if(b4_ints_in($@, [-128], [127]), [1], [byte], + b4_ints_in($@, [-32768], [32767]), [1], [short], + [int])]) + +# b4_int_type_for(NAME) +# --------------------- +# Return the smallest int type able to handle numbers ranging from +# `NAME_min' to `NAME_max' (included). +m4_define([b4_int_type_for], +[b4_int_type($1_min, $1_max)]) + +# b4_null +# ------- +m4_define([b4_null], [null]) + + +## ------------------------- ## +## Assigning token numbers. ## +## ------------------------- ## + +# b4_token_enum(TOKEN-NAME, TOKEN-NUMBER) +# --------------------------------------- +# Output the definition of this token as an enum. +m4_define([b4_token_enum], +[ /** Token number, to be returned by the scanner. */ + public static final int $1 = $2; +]) + + +# b4_token_enums(LIST-OF-PAIRS-TOKEN-NAME-TOKEN-NUMBER) +# ----------------------------------------------------- +# Output the definition of the tokens (if there are) as enums. +m4_define([b4_token_enums], +[m4_if([$@], [[]], [], +[/* Tokens. */ +m4_map([b4_token_enum], [$@])]) +]) + +# b4-case(ID, CODE) +# ----------------- +# We need to fool Java's stupid unreachable code detection. +m4_define([b4_case], [ case $1: + if (yyn == $1) + $2; + break; + ]) + + +## ---------------- ## +## Default values. ## +## ---------------- ## + +m4_define([b4_union_name], [b4_percent_define_get([[union_name]])]) +b4_percent_define_default([[union_name]], [[Object]])]) + +m4_define_default([[b4_prefix]], [[YY]])]) +b4_percent_define_default([[parser_class_name]], [b4_prefix[]Parser])]) +m4_define([b4_parser_class_name], [b4_percent_define_get([[parser_class_name]])]) + +b4_percent_define_default([[lex_throws]], [[java.io.IOException]])]) +m4_define([b4_lex_throws], [b4_percent_define_get([[lex_throws]])]) + +b4_percent_define_default([[throws]], [b4_lex_throws])]) +m4_define([b4_throws], [b4_percent_define_get([[throws]])]) + +b4_percent_define_default([[location_type]], [Location])]) +m4_define([b4_location_type], [b4_percent_define_get([[location_type]])]) + +b4_percent_define_default([[position_type]], [Position])]) +m4_define([b4_position_type], [b4_percent_define_get([[position_type]])]) + + +## ----------------- ## +## Semantic Values. ## +## ----------------- ## + + +# b4_lhs_value([TYPE]) +# -------------------- +# Expansion of $$. +m4_define([b4_lhs_value], [yyval]) + + +# b4_rhs_value(RULE-LENGTH, NUM, [TYPE]) +# -------------------------------------- +# Expansion of $NUM, where the current rule has RULE-LENGTH +# symbols on RHS. +# +# In this simple implementation, %token and %type have class names +# between the angle brackets. +m4_define([b4_rhs_value], +[(m4_ifval([$3], [($3)])[](yystack.valueAt ($1-($2))))]) + +# b4_lhs_location() +# ----------------- +# Expansion of @$. +m4_define([b4_lhs_location], +[(yyloc)]) + + +# b4_rhs_location(RULE-LENGTH, NUM) +# --------------------------------- +# Expansion of @NUM, where the current rule has RULE-LENGTH symbols +# on RHS. +m4_define([b4_rhs_location], +[yystack.locationAt ($1-($2))]) + + +# b4_lex_param +# b4_parse_param +# -------------- +# If defined, b4_lex_param arrives double quoted, but below we prefer +# it to be single quoted. Same for b4_parse_param. + +# TODO: should be in bison.m4 +m4_define_default([b4_lex_param], [[]])) +m4_define([b4_lex_param], b4_lex_param)) +m4_define([b4_parse_param], b4_parse_param)) + +# b4_lex_param_decl +# ------------------- +# Extra formal arguments of the constructor. +m4_define([b4_lex_param_decl], +[m4_ifset([b4_lex_param], + [b4_remove_comma([$1], + [m4_map([b4_lex_param_decl_1], [b4_lex_param])])], + [$1])]) + +m4_define([b4_lex_param_decl_1], [, $1]) +m4_define([b4_remove_comma], [m4_ifval([$1], [$1, ], [])m4_cdr([m4_cdr($@)])]) + + + +# b4_lex_param_call +# ------------------- +# Extra initialisations of the constructor. +m4_define([b4_lex_param_call], + [m4_ifset([b4_lex_param], + [b4_remove_comma([$1], + [b4_lex_param_calls(b4_lex_param)])], + [$1])]) +m4_define([b4_lex_param_calls], + [m4_map([b4_lex_param_call_1], [$@])]) +m4_define([b4_lex_param_call_1], [, $2]) + + + +# b4_parse_param_decl +# ------------------- +# Extra formal arguments of the constructor. +m4_define([b4_parse_param_decl], +[m4_ifset([b4_parse_param], + [b4_remove_comma([$1], + [m4_map([b4_parse_param_decl_1], + [b4_parse_param])])], + [$1])]) + +m4_define([b4_parse_param_decl_1], [, $1]) + + + +# b4_parse_param_cons +# ------------------- +# Extra initialisations of the constructor. +m4_define([b4_parse_param_cons], + [m4_ifset([b4_parse_param], + [b4_constructor_calls(b4_parse_param)])]) +m4_define([b4_constructor_calls], + [m4_map([b4_constructor_call], [$@])]) +m4_define([b4_constructor_call], + [this.$2 = $2; + ]) + +# b4_parse_param_vars +# ------------------- +# Extra instance variables. +m4_define([b4_parse_param_vars], + [m4_ifset([b4_parse_param], + [ + /* User arguments. */ +b4_var_decls(b4_parse_param)])]) +m4_define([b4_var_decls], + [m4_map_sep([b4_var_decl], [ +], [$@])]) +m4_define([b4_var_decl], + [ protected final $1;]) + +# b4_maybe_throws(THROWS) +# ----------------------- +# Expand to either an empty string or "throws THROWS". +m4_define([b4_maybe_throws], + [m4_ifval([$1], [throws $1])]) diff --git a/data/lalr1.java b/data/lalr1.java new file mode 100644 index 00000000..7c1add69 --- /dev/null +++ b/data/lalr1.java @@ -0,0 +1,880 @@ +# Java skeleton for Bison -*- autoconf -*- + +# Copyright (C) 2007 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +m4_include(b4_pkgdatadir/[java.m4]) + +b4_defines_if([b4_fatal([%s: %%defines does not make sense in Java], [b4_skeleton])]) +m4_ifval(m4_defn([b4_symbol_destructors]), + [b4_fatal([%s: %%destructor does not make sense in Java], [b4_skeleton])], + []) + +m4_divert_push(0)dnl +@output(b4_parser_file_name@) +b4_copyright([Skeleton implementation for Bison LALR(1) parsers in Java], + [2007]) + +b4_percent_define_ifdef([package], [package b4_percent_define_get([package]); +])[/* First part of user declarations. */ +]b4_pre_prologue +b4_percent_code_get([[imports]]) +[/** + * A Bison parser, automatically generated from @ofile@. + * + * @@author LALR (1) parser skeleton written by Paolo Bonzini. + */ +]b4_public_if([public ])b4_abstract_if([abstract ])[class ]b4_parser_class_name[ +{ + ]b4_identification[ + + /** True if verbose error messages are enabled. */ + public boolean errorVerbose = ]b4_flag_value([error_verbose]); + +b4_locations_if([[ + /** + * A class defining a pair of positions. Positions, defined by the + * ]b4_position_type[ class, denote a point in the input. + * Locations represent a part of the input through the beginning + * and ending positions. */ + public class ]b4_location_type[ { + /** The first, inclusive, position in the range. */ + public ]b4_position_type[ begin; + + /** The first position beyond the range. */ + public ]b4_position_type[ end; + + /** + * Create a ]b4_location_type[ denoting an empty range located at + * a given point. + * @@param loc The position at which the range is anchored. */ + public ]b4_location_type[ (]b4_position_type[ loc) { + this.begin = this.end = loc; + } + + /** + * Create a ]b4_location_type[ from the endpoints of the range. + * @@param begin The first position included in the range. + * @@param begin The first position beyond the range. */ + public ]b4_location_type[ (]b4_position_type[ begin, ]b4_position_type[ end) { + this.begin = begin; + this.end = end; + } + + /** + * Print a representation of the location. For this to be correct, + * ]b4_position_type[ should override the equals + * method. */ + public String toString () { + if (begin.equals (end)) + return begin.toString (); + else + return begin.toString () + "-" + end.toString (); + } + } + +]]) + +[ /** Token returned by the scanner to signal the end of its input. */ + public static final int EOF = 0;] + +b4_token_enums(b4_tokens) + + b4_locations_if([[ + private ]b4_location_type[ yylloc (Stack rhs, int n) + { + if (n > 0) + return new ]b4_location_type[ (rhs.locationAt (1).begin, rhs.locationAt (n).end); + else + return new ]b4_location_type[ (rhs.locationAt (0).end); + }]]) + + b4_pure_if([[/** + * Communication interface between the scanner and the Bison-generated + * parser ]b4_parser_class_name[. + */ + public interface Lexer { + ]b4_locations_if([[/** + * Method to retrieve the beginning position of the last scanned token. + * @@return the position at which the last scanned token starts. */ + ]b4_position_type[ getStartPos (); + + /** + * Method to retrieve the ending position of the last scanned token. + * @@return the first position beyond the last scanned token. */ + ]b4_position_type[ getEndPos ();]])[ + + /** + * Method to retrieve the semantic value of the last scanned token. + * @@return the semantic value of the last scanned token. */ + ]b4_union_name[ getLVal ();]], [[ + + /** + * A place where the scanner can store the beginning position of the + * last scanned token. */ + ]b4_locations_if([b4_position_type[ yystartpos;]])[ + + /** + * A place where the scanner can store the ending position of the last + * scanned token, i.e. the first position beyond the last scanned token. */ + ]b4_locations_if([b4_position_type[ yyendpos;]])[ + + /** + * A place where the scanner can store the semantic value of the + * last scanned token. */ + protected ]b4_union_name[ yylval;]]) + + b4_single_class_if([], [[/** + * Entry point for the scanner. Returns the token identifier corresponding + * to the next token and ]b4_pure_if([prepares to return], [stores])[ + * the semantic value]b4_locations_if([ and beginning/ending positions])[ + * of the token. + * @@return the token identifier corresponding to the next token. */ + abstract int yylex (]b4_lex_param_decl) b4_maybe_throws([b4_lex_throws])[; + + /** + * Entry point for error reporting. Emits an error + * ]b4_locations_if([ referring to the given location])[in a user-defined + * way. + * + * ]b4_locations_if([loc], [[The location of the element to which the + * error message is related]])[ + * @@param s The string for the error message. */ + abstract void yyerror (]b4_locations_if([b4_location_type[ loc, ]])[String s);]]) + b4_pure_if([} + + /** The object doing lexical analysis for us. */ + private Lexer yylex;]) + b4_parse_param_vars[ + + /** + * Instantiates the Bison-generated parser. ]b4_pure_if([ + * @@param yylex The scanner that will supply tokens to the parser.])[ + */ + public ]b4_parser_class_name[ (]b4_parse_param_decl([b4_pure_if([Lexer yylex])])[) { + ]b4_pure_if(this.yylex = yylex;) + b4_parse_param_cons[ + } + + private java.io.PrintStream debugStream = System.err; + + /** + * Return the PrintStream on which the debugging output is + * printed. + */ + public final java.io.PrintStream getDebugStream () { return debugStream; } + + /** + * Set the PrintStream on which the debug output is printed. + * @@param s The stream that is used for debugging output. + */ + public final void setDebugStream(java.io.PrintStream s) { debugStream = s; } + + private int yydebug = 0; + + /** + * Answer the verbosity of the debugging output; 0 means that all kinds of + * output from the parser are suppressed. + */ + public final int getDebugLevel() { return yydebug; } + + /** + * Set the verbosity of the debugging output; 0 means that all kinds of + * output from the parser are suppressed. + * @@param level The verbosity level for debugging output. + */ + public final void setDebugLevel(int level) { yydebug = level; } + + ]b4_pure_if([[ + private final int yylex (]b4_lex_param_decl) b4_maybe_throws([b4_lex_throws]) [{ + return yylex.yylex (]b4_lex_param_call[); + } + protected final void yyerror (]b4_locations_if([b4_location_type[ loc, ]])[String s) { + yylex.yyerror (]b4_locations_if([loc, ])[s); + }]]) + b4_locations_if([ + protected final void yyerror (String s) { + yyerror ((Location)null, s); + } + protected final void yyerror (]b4_position_type[ loc, String s) { + yyerror (new ]b4_location_type[ (loc), s); + }]) + + [protected final void yycdebug (String s) { + if (yydebug > 0) + debugStream.println (s); + } + + private final class Stack { + private int[] stateStack = new int[16]; + ]b4_locations_if([[private ]b4_location_type[[] locStack = new ]b4_location_type[[16];]])[ + private ]b4_union_name[[] valueStack = new ]b4_union_name[[16]; + + private int size = 16; + private int height = -1; + + public final void push (int state, ]b4_union_name[ value]dnl + b4_locations_if([, ]b4_location_type[ loc])[) { + height++; + if (size == height) + { + int[] newStateStack = new int[size * 2]; + System.arraycopy (stateStack, 0, newStateStack, 0, height); + stateStack = newStateStack; + ]b4_locations_if([[ + ]b4_location_type[[] newLocStack = new ]b4_location_type[[size * 2]; + System.arraycopy (locStack, 0, newLocStack, 0, height); + locStack = newLocStack;]]) + + b4_union_name[[] newValueStack = new ]b4_union_name[[size * 2]; + System.arraycopy (valueStack, 0, newValueStack, 0, height); + valueStack = newValueStack; + + size *= 2; + } + + stateStack[height] = state; + ]b4_locations_if([[locStack[height] = loc;]])[ + valueStack[height] = value; + } + + public final void pop () { + height--; + } + + public final void pop (int num) { + // Avoid memory leaks... garbage collection is a white lie! + if (num > 0) { + java.util.Arrays.fill (valueStack, height - num + 1, height, null); + ]b4_locations_if([[java.util.Arrays.fill (locStack, height - num + 1, height, null);]])[ + } + height -= num; + } + + public final int stateAt (int i) { + return stateStack[height - i]; + } + + ]b4_locations_if([[public final ]b4_location_type[ locationAt (int i) { + return locStack[height - i]; + } + + ]])[public final ]b4_union_name[ valueAt (int i) { + return valueStack[height - i]; + } + + // Print the state stack on the debug stream. + private void print (java.io.PrintStream out) + { + out.print ("Stack now"); + + for (int i = 0; i < height; i++) + { + out.print (' '); + out.print (stateStack[i]); + } + out.println (); + } + } + + /** + * Returned by a Bison action in order to stop the parsing process and + * return success (true). */ + public static final int YYACCEPT = 0; + + /** + * Returned by a Bison action in order to stop the parsing process and + * return failure (false). */ + public static final int YYABORT = 1; + + /** + * Returned by a Bison action in order to start error recovery without + * printing an error message. */ + public static final int YYERROR = 2; + + /** + * Returned by a Bison action in order to print an error message and start + * error recovery. */ + public static final int YYFAIL = 3; + + private static final int YYNEWSTATE = 4; + private static final int YYDEFAULT = 5; + private static final int YYREDUCE = 6; + private static final int YYERRLAB1 = 7; + private static final int YYRETURN = 8; + + private int yyerrstatus_ = 0; + + /** + * Return whether error recovery is being done. In this state, the parser + * reads token until it reaches a known state, and then restarts normal + * operation. */ + public final boolean yyrecovering () + { + return yyerrstatus_ == 0; + } + + private int yyaction (int yyn, Stack yystack, int yylen) + { + ]b4_union_name[ yyval; + ]b4_locations_if([b4_location_type[ yyloc = yylloc (yystack, yylen);]])[ + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. Otherwise, use the top of the stack. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. */ + if (yylen > 0) + yyval = yystack.valueAt (yylen - 1); + else + yyval = yystack.valueAt (0); + + yy_reduce_print (yyn, yystack); + + switch (yyn) + { + ]b4_user_actions[ + default: break; + } + + yy_symbol_print ("-> $$ =", yyr1_[yyn], yyval]b4_locations_if([, yyloc])[); + + yystack.pop (yylen); + yylen = 0; + + /* Shift the result of the reduction. */ + yyn = yyr1_[yyn]; + int yystate = yypgoto_[yyn - yyntokens_] + yystack.stateAt (0); + if (0 <= yystate && yystate <= yylast_ + && yycheck_[yystate] == yystack.stateAt (0)) + yystate = yytable_[yystate]; + else + yystate = yydefgoto_[yyn - yyntokens_]; + + yystack.push (yystate, yyval]b4_locations_if([, yyloc])[); + return YYNEWSTATE; + } + + /* Return YYSTR after stripping away unnecessary quotes and + backslashes, so that it's suitable for yyerror. The heuristic is + that double-quoting is unnecessary unless the string contains an + apostrophe, a comma, or backslash (other than backslash-backslash). + YYSTR is taken from yytname. */ + private final String yytnamerr_ (String yystr) + { + if (yystr.charAt (0) == '"') + { + StringBuffer yyr = new StringBuffer (); + strip_quotes: for (int i = 1; i < yystr.length (); i++) + switch (yystr.charAt (i)) + { + case '\'': + case ',': + break strip_quotes; + + case '\\': + if (yystr.charAt(++i) != '\\') + break strip_quotes; + /* Fall through. */ + default: + yyr.append (yystr.charAt (i)); + break; + + case '"': + return yyr.toString (); + } + } + else if (yystr.equals ("$end")) + return "end of input"; + + return yystr; + } + + /*--------------------------------. + | Print this symbol on YYOUTPUT. | + `--------------------------------*/ + + private void yy_symbol_print (String s, int yytype, + ]b4_union_name[ yyvaluep]dnl + b4_locations_if([, Object yylocationp])[) + { + if (yydebug > 0) + yycdebug (s + (yytype < yyntokens_ ? " token " : " nterm ") + + yytname_[yytype] + " ("]b4_locations_if([ + + yylocationp + ": "])[ + + (yyvaluep == null ? "(null)" : yyvaluep) + ")"); + } + + /** + * Parse input from the scanner that was specified at object construction + * time. Return whether the end of the input was reached successfully. + * + * @@return true if the parsing succeeds. Note that this does not + * imply that there were no syntax errors. + */ + public boolean parse () ]b4_maybe_throws([b4_throws])[ + { + /// Lookahead and lookahead in internal form. + int yychar = yyempty_; + int yytoken = 0; + + /* State. */ + int yyn = 0; + int yylen = 0; + int yystate = 0; + + Stack yystack = new Stack (); + + /* Error handling. */ + int yynerrs_ = 0; + ]b4_locations_if([/// The location where the error started. + ]b4_location_type[ yyerrloc = null; + + /// ]b4_location_type[ of the lookahead. + ]b4_location_type[ yylloc = new ]b4_location_type[ (null, null); + + /// @@$. + ]b4_location_type[ yyloc;]) + + /// Semantic value of the lookahead. + b4_union_name[ yylval = null; + + int yyresult; + + yycdebug ("Starting parse\n"); + yyerrstatus_ = 0; + +]m4_ifdef([b4_initial_action], [ +m4_pushdef([b4_at_dollar], [yylloc])dnl +m4_pushdef([b4_dollar_dollar], [yylval])dnl + /* User initialization code. */ + b4_user_initial_action +m4_popdef([b4_dollar_dollar])dnl +m4_popdef([b4_at_dollar])])dnl + + [ /* Initialize the stack. */ + yystack.push (yystate, yylval]b4_locations_if([, yylloc])[); + + int label = YYNEWSTATE; + for (;;) + switch (label) + { + /* New state. Unlike in the C/C++ skeletons, the state is already + pushed when we come here. */ + case YYNEWSTATE: + yycdebug ("Entering state " + yystate + "\n"); + if (yydebug > 0) + yystack.print (debugStream); + + /* Accept? */ + if (yystate == yyfinal_) + return true; + + /* Take a decision. First try without lookahead. */ + yyn = yypact_[yystate]; + if (yyn == yypact_ninf_) + { + label = YYDEFAULT; + break; + } + + /* Read a lookahead token. */ + if (yychar == yyempty_) + { + yycdebug ("Reading a token: "); + yychar = yylex (]b4_lex_param_call[);] + b4_locations_if([ + b4_pure_if([yylloc = new ]b4_location_type[(yylex.getStartPos (), + yylex.getEndPos ());], + [yylloc = new ]b4_location_type[(this.yystartpos, + this.yyendpos);]);]) + b4_pure_if([yylval = yylex.getLVal ()], [yylval = this.yylval]);[ + } + + /* Convert token to internal form. */ + if (yychar <= EOF) + { + yychar = yytoken = EOF; + yycdebug ("Now at end of input.\n"); + } + else + { + yytoken = yytranslate_ (yychar); + yy_symbol_print ("Next token is", yytoken, + yylval]b4_locations_if([, yylloc])[); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yytoken) + label = YYDEFAULT; + + /* <= 0 means reduce or error. */ + else if ((yyn = yytable_[yyn]) <= 0) + { + if (yyn == 0 || yyn == yytable_ninf_) + label = YYFAIL; + else + { + yyn = -yyn; + label = YYREDUCE; + } + } + + else + { + /* Shift the lookahead token. */ + yy_symbol_print ("Shifting", yytoken, + yylval]b4_locations_if([, yylloc])[); + + /* Discard the token being shifted. */ + yychar = yyempty_; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus_ > 0) + --yyerrstatus_; + + yystate = yyn; + yystack.push (yystate, yylval]b4_locations_if([, yylloc])[); + label = YYNEWSTATE; + } + break; + + /*-----------------------------------------------------------. + | yydefault -- do the default action for the current state. | + `-----------------------------------------------------------*/ + case YYDEFAULT: + yyn = yydefact_[yystate]; + if (yyn == 0) + label = YYFAIL; + else + label = YYREDUCE; + break; + + /*-----------------------------. + | yyreduce -- Do a reduction. | + `-----------------------------*/ + case YYREDUCE: + yylen = yyr2_[yyn]; + label = yyaction (yyn, yystack, yylen); + yystate = yystack.stateAt (0); + break; + + /*------------------------------------. + | yyerrlab -- here on detecting error | + `------------------------------------*/ + case YYFAIL: + /* If not already recovering from an error, report this error. */ + if (yyerrstatus_ == 0) + { + ++yynerrs_; + yyerror (]b4_locations_if([yylloc, ])[yysyntax_error (yystate, yytoken)); + } + + ]b4_locations_if([yyerrloc = yylloc;])[ + if (yyerrstatus_ == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= EOF) + { + /* Return failure if at end of input. */ + if (yychar == EOF) + return false; + } + else + yychar = yyempty_; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + label = YYERRLAB1; + break; + + /*---------------------------------------------------. + | errorlab -- error raised explicitly by YYERROR. | + `---------------------------------------------------*/ + case YYERROR: + + ]b4_locations_if([yyerrloc = yystack.locationAt (yylen - 1);])[ + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + yystack.pop (yylen); + yylen = 0; + yystate = yystack.stateAt (0); + label = YYERRLAB1; + break; + + /*-------------------------------------------------------------. + | yyerrlab1 -- common code for both syntax error and YYERROR. | + `-------------------------------------------------------------*/ + case YYERRLAB1: + yyerrstatus_ = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact_[yystate]; + if (yyn != yypact_ninf_) + { + yyn += yyterror_; + if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == yyterror_) + { + yyn = yytable_[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yystack.height == 1) + return false; + + ]b4_locations_if([yyerrloc = yystack.locationAt (0);])[ + yystack.pop (); + yystate = yystack.stateAt (0); + if (yydebug > 0) + yystack.print (debugStream); + } + + ]b4_locations_if([ + /* Muck with the stack to setup for yylloc. */ + yystack.push (0, null, yylloc); + yystack.push (0, null, yyerrloc); + yyloc = yylloc (yystack, 2); + yystack.pop (2);])[ + + /* Shift the error token. */ + yy_symbol_print ("Shifting", yystos_[yyn], + yylval]b4_locations_if([, yyloc])[); + + yystate = yyn; + yystack.push (yyn, yylval]b4_locations_if([, yyloc])[); + label = YYNEWSTATE; + break; + + /* Accept. */ + case YYACCEPT: + return true; + + /* Abort. */ + case YYABORT: + return false; + } + } + + // Generate an error message. + private String yysyntax_error (int yystate, int tok) + { + if (errorVerbose) + { + int yyn = yypact_[yystate]; + if (yypact_ninf_ < yyn && yyn <= yylast_) + { + StringBuffer res; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = yylast_ - yyn + 1; + int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_; + int count = 0; + for (int x = yyxbegin; x < yyxend; ++x) + if (yycheck_[x + yyn] == x && x != yyterror_) + ++count; + + // FIXME: This method of building the message is not compatible + // with internationalization. + res = new StringBuffer ("syntax error, unexpected "); + res.append (yytnamerr_ (yytname_[tok])); + if (count < 5) + { + count = 0; + for (int x = yyxbegin; x < yyxend; ++x) + if (yycheck_[x + yyn] == x && x != yyterror_) + { + res.append (count++ == 0 ? ", expecting " : " or "); + res.append (yytnamerr_ (yytname_[x])); + } + } + return res.toString (); + } + } + + return "syntax error"; + } + + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ + private static final ]b4_int_type_for([b4_pact])[ yypact_ninf_ = ]b4_pact_ninf[; + private static final ]b4_int_type_for([b4_pact])[ yypact_[] = + { + ]b4_pact[ + }; + + /* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ + private static final ]b4_int_type_for([b4_defact])[ yydefact_[] = + { + ]b4_defact[ + }; + + /* YYPGOTO[NTERM-NUM]. */ + private static final ]b4_int_type_for([b4_pgoto])[ yypgoto_[] = + { + ]b4_pgoto[ + }; + + /* YYDEFGOTO[NTERM-NUM]. */ + private static final ]b4_int_type_for([b4_defgoto])[ + yydefgoto_[] = + { + ]b4_defgoto[ + }; + + /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. */ + private static final ]b4_int_type_for([b4_table])[ yytable_ninf_ = ]b4_table_ninf[; + private static final ]b4_int_type_for([b4_table])[ + yytable_[] = + { + ]b4_table[ + }; + + /* YYCHECK. */ + private static final ]b4_int_type_for([b4_check])[ + yycheck_[] = + { + ]b4_check[ + }; + + /* STOS_[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ + private static final ]b4_int_type_for([b4_stos])[ + yystos_[] = + { + ]b4_stos[ + }; + + /* TOKEN_NUMBER_[YYLEX-NUM] -- Internal symbol number corresponding + to YYLEX-NUM. */ + private static final ]b4_int_type_for([b4_toknum])[ + yytoken_number_[] = + { + ]b4_toknum[ + }; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ + private static final ]b4_int_type_for([b4_r1])[ + yyr1_[] = + { + ]b4_r1[ + }; + + /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ + private static final ]b4_int_type_for([b4_r2])[ + yyr2_[] = + { + ]b4_r2[ + }; + + /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at \a yyntokens_, nonterminals. */ + private static final String yytname_[] = + { + ]b4_tname[ + }; + + /* YYRHS -- A `-1'-separated list of the rules' RHS. */ + private static final ]b4_int_type_for([b4_rhs])[ yyrhs_[] = + { + ]b4_rhs[ + }; + + /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ + private static final ]b4_int_type_for([b4_prhs])[ yyprhs_[] = + { + ]b4_prhs[ + }; + + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ + private static final ]b4_int_type_for([b4_rline])[ yyrline_[] = + { + ]b4_rline[ + }; + + // Report on the debug stream that the rule yyrule is going to be reduced. + private void yy_reduce_print (int yyrule, Stack yystack) + { + if (yydebug == 0) + return; + + int yylno = yyrline_[yyrule]; + int yynrhs = yyr2_[yyrule]; + /* Print the symbols being reduced, and their result. */ + yycdebug ("Reducing stack by rule " + (yyrule - 1) + + " (line " + yylno + "), "); + + /* The symbols being reduced. */ + for (int yyi = 0; yyi < yynrhs; yyi++) + yy_symbol_print (" $" + (yyi + 1) + " =", + yyrhs_[yyprhs_[yyrule] + yyi], + ]b4_rhs_value(yynrhs, yyi + 1)b4_locations_if([, + b4_rhs_location(yynrhs, yyi + 1)])[); + } + + /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ + private static final ]b4_int_type_for([b4_translate])[ yytranslate_table_[] = + { + ]b4_translate[ + }; + + private static final ]b4_int_type_for([b4_translate])[ yytranslate_ (int t) + { + if (t >= 0 && t <= yyuser_token_number_max_) + return yytranslate_table_[t]; + else + return yyundef_token_; + } + + private static final int yylast_ = ]b4_last[; + private static final int yynnts_ = ]b4_nterms_number[; + private static final int yyempty_ = -2; + private static final int yyfinal_ = ]b4_final_state_number[; + private static final int yyterror_ = 1; + private static final int yyerrcode_ = 256; + private static final int yyntokens_ = ]b4_tokens_number[; + + private static final int yyuser_token_number_max_ = ]b4_user_token_number_max[; + private static final int yyundef_token_ = ]b4_undef_token_number[; + +]/* User implementation code. */ +b4_percent_code_get[]dnl + +} + +b4_epilogue +m4_divert_pop(0)dnl diff --git a/doc/bison.texinfo b/doc/bison.texinfo index 38888287..28bbc8c2 100644 --- a/doc/bison.texinfo +++ b/doc/bison.texinfo @@ -104,7 +104,7 @@ Reference sections: messy for Bison to handle straightforwardly. * Debugging:: Understanding or debugging Bison parsers. * Invocation:: How to run Bison (to produce the parser source file). -* C++ Language Interface:: Creating C++ parser objects. +* Other Languages:: Creating C++ and Java parsers. * FAQ:: Frequently Asked Questions * Table of Symbols:: All the keywords of the Bison language are explained. * Glossary:: Basic concepts are explained. @@ -285,10 +285,10 @@ Invoking Bison * Option Cross Key:: Alphabetical list of long options. * Yacc Library:: Yacc-compatible @code{yylex} and @code{main}. -C++ Language Interface +Parsers Written In Other Languages * C++ Parsers:: The interface to generate C++ parser classes -* A Complete C++ Example:: Demonstrating their use +* Java Parsers:: The interface to generate Java parser classes C++ Parsers @@ -297,6 +297,7 @@ C++ Parsers * C++ Location Values:: The position and location classes * C++ Parser Interface:: Instantiating and running the parser * C++ Scanner Interface:: Exchanges between yylex and parse +* A Complete C++ Example:: Demonstrating their use A Complete C++ Example @@ -306,6 +307,15 @@ A Complete C++ Example * Calc++ Scanner:: A pure C++ Flex scanner * Calc++ Top Level:: Conducting the band +Java Parsers + +* Java Bison Interface:: Asking for Java parser generation +* Java Semantic Values:: %type and %token vs. Java +* Java Location Values:: The position and location classes +* Java Parser Interface:: Instantiating and running the parser +* Java Scanner Interface:: Java scanners, and pure parsers +* Java Differences:: Differences between C/C++ and Java Grammars + Frequently Asked Questions * Memory Exhausted:: Breaking the Stack Limits @@ -2694,7 +2704,7 @@ As an alternative, Bison provides a %code directive with an explicit qualifier field, which identifies the purpose of the code and thus the location(s) where Bison should generate it. For C/C++, the qualifier can be omitted for the default location, or it can be -@code{requires}, @code{provides}, or @code{top}. +one of @code{requires}, @code{provides}, @code{top}. @xref{Decl Summary,,%code}. Look again at the example of the previous section: @@ -4572,18 +4582,19 @@ directives: @deffn {Directive} %code @{@var{code}@} @findex %code This is the unqualified form of the @code{%code} directive. -It inserts @var{code} verbatim at the default location in the output. -That default location is determined by the selected target language and/or -parser skeleton. +It inserts @var{code} verbatim at a language-dependent default location in the +output@footnote{The default location is actually skeleton-dependent; + writers of non-standard skeletons however should choose the default location + consistently with the behavior of the standard Bison skeletons.}. @cindex Prologue -For the current C/C++ skeletons, the default location is the parser source code +For C/C++, the default location is the parser source code file after the usual contents of the parser header file. Thus, @code{%code} replaces the traditional Yacc prologue, @code{%@{@var{code}%@}}, for most purposes. For a detailed discussion, see @ref{Prologue Alternatives}. -@comment For Java, the default location is inside the parser class. +For Java, the default location is inside the parser class. (Like all the Yacc prologue alternatives, this directive is experimental. More user feedback will help to determine whether it should become a permanent @@ -4651,7 +4662,7 @@ For example: @item Location(s): Near the top of the parser source code file. @end itemize -@ignore + @item imports @findex %code imports @@ -4663,7 +4674,6 @@ For example: @item Location(s): The parser Java file after any Java package directive and before any class definitions. @end itemize -@end ignore @end itemize (Like all the Yacc prologue alternatives, this directive is experimental. @@ -7578,12 +7588,12 @@ int yyparse (void); @c ================================================= C++ Bison -@node C++ Language Interface -@chapter C++ Language Interface +@node Other Languages +@chapter Parsers Written In Other Languages @menu * C++ Parsers:: The interface to generate C++ parser classes -* A Complete C++ Example:: Demonstrating their use +* Java Parsers:: The interface to generate Java parser classes @end menu @node C++ Parsers @@ -7595,6 +7605,7 @@ int yyparse (void); * C++ Location Values:: The position and location classes * C++ Parser Interface:: Instantiating and running the parser * C++ Scanner Interface:: Exchanges between yylex and parse +* A Complete C++ Example:: Demonstrating their use @end menu @node C++ Bison Interface @@ -7803,7 +7814,7 @@ value and location being @var{yylval} and @var{yylloc}. Invocations of @node A Complete C++ Example -@section A Complete C++ Example +@subsection A Complete C++ Example This section demonstrates the use of a C++ parser with a simple but complete example. This example should be available on your system, @@ -7823,7 +7834,7 @@ actually easier to interface with. @end menu @node Calc++ --- C++ Calculator -@subsection Calc++ --- C++ Calculator +@subsubsection Calc++ --- C++ Calculator Of course the grammar is dedicated to arithmetics, a single expression, possibly preceded by variable assignments. An @@ -7838,7 +7849,7 @@ seven * seven @end example @node Calc++ Parsing Driver -@subsection Calc++ Parsing Driver +@subsubsection Calc++ Parsing Driver @c - An env @c - A place to store error messages @c - A place for the result @@ -7987,7 +7998,7 @@ calcxx_driver::error (const std::string& m) @end example @node Calc++ Parser -@subsection Calc++ Parser +@subsubsection Calc++ Parser The parser definition file @file{calc++-parser.yy} starts by asking for the C++ LALR(1) skeleton, the creation of the parser header file, and @@ -8157,7 +8168,7 @@ yy::calcxx_parser::error (const yy::calcxx_parser::location_type& l, @end example @node Calc++ Scanner -@subsection Calc++ Scanner +@subsubsection Calc++ Scanner The Flex scanner first includes the driver declaration, then the parser's to get the set of defined tokens. @@ -8283,7 +8294,7 @@ calcxx_driver::scan_end () @end example @node Calc++ Top Level -@subsection Calc++ Top Level +@subsubsection Calc++ Top Level The top level file, @file{calc++.cc}, poses no problem. @@ -8306,6 +8317,321 @@ main (int argc, char *argv[]) @} @end example +@node Java Parsers +@section Java Parsers + +@menu +* Java Bison Interface:: Asking for Java parser generation +* Java Semantic Values:: %type and %token vs. Java +* Java Location Values:: The position and location classes +* Java Parser Interface:: Instantiating and running the parser +* Java Scanner Interface:: Java scanners, and pure parsers +* Java Differences:: Differences between C/C++ and Java Grammars +@end menu + +@node Java Bison Interface +@subsection Java Bison Interface +@c - %language "Java" +@c - initial action + +The Java parser skeletons are selected using a language directive, +@samp{%language "Java"}, or the synonymous command-line option +@option{--language=java}. + +When run, @command{bison} will create several entities whose name +starts with @samp{YY}. Use the @samp{%name-prefix} directive to +change the prefix, see @ref{Decl Summary}; classes can be placed +in an arbitrary Java package using a @samp{%define package} section. + +The parser class defines an inner class, @code{Location}, that is used +for location tracking. If the parser is pure, it also defines an +inner interface, @code{Lexer}; see~@ref{Java Scanner Interface} for the +meaning of pure parsers when the Java language is chosen. Other than +these inner class/interface, and the members described in~@ref{Java +Parser Interface}, all the other members and fields are preceded +with a @code{yy} prefix to avoid clashes with user code. + +No header file can be generated for Java parsers; you must not pass +@option{-d}/@option{--defines} to @command{bison}, nor use the +@samp{%defines} directive. + +By default, the @samp{YYParser} class has package visibility. A +declaration @samp{%define "public"} will change to public visibility. +Remember that, according to the Java language specification, the name +of the @file{.java} file should match the name of the class in this +case. + +All these files are documented using Javadoc. + +@node Java Semantic Values +@subsection Java Semantic Values +@c - No %union, specify type in %type/%token. +@c - YYSTYPE +@c - Printer and destructor + +There is no @code{%union} directive in Java parsers. Instead, the +semantic values' types (class names) should be specified in the +@code{%type} or @code{%token} directive: + +@example +%type expr assignment_expr term factor +%type number +@end example + +By default, the semantic stack is declared to have @code{Object} members, +which means that the class types you specify can be of any class. +To improve the type safety of the parser, you can declare the common +superclass of all the semantic values using the @samp{%define} directive. +For example, after the following declaration: + +@example +%define "union_name" "ASTNode" +@end example + +@noindent +any @code{%type} or @code{%token} specifying a semantic type which +is not a subclass of ASTNode, will cause a compile-time error. + +Types used in the directives may be qualified with a package name. +Primitive data types are accepted for Java version 1.5 or later. Note +that in this case the autoboxing feature of Java 1.5 will be used. + +Java parsers do not support @code{%destructor}, since the language +adopts garbage collection. The parser will try to hold references +to semantic values for as little time as needed. + +Java parsers do not support @code{%printer}, as @code{toString()} +can be used to print the semantic values. This however may change +(in a backwards-compatible way) in future versions of Bison. + + +@node Java Location Values +@subsection Java Location Values +@c - %locations +@c - class Position +@c - class Location + +When the directive @code{%locations} is used, the Java parser +supports location tracking, see @ref{Locations, , Locations Overview}. +An auxiliary user-defined class defines a @dfn{position}, a single point +in a file; Bison itself defines a class representing a @dfn{location}, +a range composed of a pair of positions (possibly spanning several +files). The location class is an inner class of the parser; the name +is @code{Location} by default, may also be renamed using @code{%define +"location_type" "@var{class-name}}. + +The location class treats the position as a completely opaque value. +By default, the class name is @code{Position}, but this can be changed +with @code{%define "position_type" "@var{class-name}"}. + + +@deftypemethod {Location} {Position} begin +@deftypemethodx {Location} {Position} end +The first, inclusive, position of the range, and the first beyond. +@end deftypemethod + +@deftypemethod {Location} {void} toString () +Prints the range represented by the location. For this to work +properly, the position class should override the @code{equals} and +@code{toString} methods appropriately. +@end deftypemethod + + +@node Java Parser Interface +@subsection Java Parser Interface +@c - define parser_class_name +@c - Ctor +@c - parse, error, set_debug_level, debug_level, set_debug_stream, +@c debug_stream. +@c - Reporting errors + +The output file defines the parser class in the package optionally +indicated in the @code{%define package} section. The class name defaults +to @code{YYParser}. The @code{YY} prefix may be changed using +@samp{%name-prefix}; alternatively, you can use @samp{%define +"parser_class_name" "@var{name}"} to give a custom name to the class. +The interface of this class is detailed below. It can be extended using +the @code{%parse-param} directive; each occurrence of the directive will +add a field to the parser class, and an argument to its constructor. + +@deftypemethod {YYParser} {} YYParser (@var{type1} @var{arg1}, ...) +Build a new parser object. There are no arguments by default, unless +@samp{%parse-param @{@var{type1} @var{arg1}@}} was used. +@end deftypemethod + +@deftypemethod {YYParser} {boolean} parse () +Run the syntactic analysis, and return @code{true} on success, +@code{false} otherwise. +@end deftypemethod + +@deftypemethod {YYParser} {boolean} yyrecovering () +During the syntactic analysis, return @code{true} if recovering +from a syntax error. @xref{Error Recovery}. +@end deftypemethod + +@deftypemethod {YYParser} {java.io.PrintStream} getDebugStream () +@deftypemethodx {YYParser} {void} setDebugStream (java.io.printStream @var{o}) +Get or set the stream used for tracing the parsing. It defaults to +@code{System.err}. +@end deftypemethod + +@deftypemethod {YYParser} {int} getDebugLevel () +@deftypemethodx {YYParser} {void} setDebugLevel (int @var{l}) +Get or set the tracing level. Currently its value is either 0, no trace, +or nonzero, full tracing. +@end deftypemethod + +@deftypemethod {YYParser} {void} error (Location @var{l}, String @var{m}) +The definition for this member function must be supplied by the user +in the same way as the scanner interface (@pxref{Java Scanner +Interface}); the parser uses it to report a parser error occurring at +@var{l}, described by @var{m}. +@end deftypemethod + + +@node Java Scanner Interface +@subsection Java Scanner Interface +@c - prefix for yylex. +@c - Pure interface to yylex +@c - %lex-param + +There are two possible ways to interface a Bison-generated Java parser +with a scanner. + +@cindex pure parser, in Java +Contrary to C parsers, Java parsers do not use global variables; the +state of the parser is always local to an instance of the parser class. +Therefore, all Java parsers are ``pure'' in the C sense. The +@code{%pure-parser} directive can still be used in Java, and it +will control whether the lexer resides in a separate class than the +Bison-generated parser (therefore, Bison generates a class that is +``purely'' a parser), or in the same class. The interface to the scanner +is similar, though the two cases present a slightly different naming. + +For the @code{%pure-parser} case, the scanner implements an interface +called @code{Lexer} and defined within the parser class (e.g., +@code{YYParser.Lexer}. The constructor of the parser object accepts +an object implementing the interface. The interface specifies +the following methods. + +@deftypemethod {Lexer} {void} error (Location @var{l}, String @var{m}) +As explained in @pxref{Java Parser Interface}, this method is defined +by the user to emit an error message. The first parameter is not used +unless location tracking is active. Its type can be changed using +@samp{%define "location_type" "@var{class-name}".} +@end deftypemethod + +@deftypemethod {Lexer} {int} yylex (@var{type1} @var{arg1}, ...) +Return the next token. Its type is the return value, its semantic +value and location are saved and returned by the ther methods in the +interface. Invocations of @samp{%lex-param @{@var{type1} +@var{arg1}@}} yield additional arguments. +@end deftypemethod + +@deftypemethod {Lexer} {Position} getStartPos () +@deftypemethodx {Lexer} {Position} getEndPos () +Return respectively the first position of the last token that yylex +returned, and the first position beyond it. These methods are not +needed unless location tracking is active. + +The return type can be changed using @samp{%define "position_type" +"@var{class-name}".} +@end deftypemethod + +@deftypemethod {Lexer} {Object} getLVal () +Return respectively the first position of the last token that yylex +returned, and the first position beyond it. + +The return type can be changed using @samp{%define "union_name" +"@var{class-name}".} +@end deftypemethod + + +If @code{%pure-parser} is not specified, the lexer interface +resides in the same class (@code{YYParser}) as the Bison-generated +parser. The fields and methods that are provided to +this end are as follows. + +@deftypemethod {YYParser} {void} error (Location @var{l}, String @var{m}) +As explained in @pxref{Java Parser Interface}, this method is defined +by the user to emit an error message. The first parameter is not used +unless location tracking is active. Its type can be changed using +@samp{%define "location_type" "@var{class-name}".} +@end deftypemethod + +@deftypemethod {YYParser} {int} yylex (@var{type1} @var{arg1}, ...) +Return the next token. Its type is the return value, its semantic +value and location are saved into @code{yylval}, @code{yystartpos}, +@code{yyendpos}. Invocations of @samp{%lex-param @{@var{type1} +@var{arg1}@}} yield additional arguments. +@end deftypemethod + +@deftypecv {Field} {YYParser} Position yystartpos +@deftypecvx {Field} {YYParser} Position yyendpos +Contain respectively the first position of the last token that yylex +returned, and the first position beyond it. These methods are not +needed unless location tracking is active. + +The field's type can be changed using @samp{%define "position_type" +"@var{class-name}".} +@end deftypecv + +@deftypecv {Field} {YYParser} Object yylval +Return respectively the first position of the last token that yylex +returned, and the first position beyond it. + +The field's type can be changed using @samp{%define "union_name" +"@var{class-name}".} +@end deftypecv + +By default the class generated for a non-pure Java parser is abstract, +and the methods @code{yylex} and @code{yyerror} shall be placed in a +subclass (possibly defined in the additional code section). It is +also possible, using the @code{%define "single_class"} declaration, to +define the scanner in the same class as the parser; when this +declaration is present, the class is not declared as abstract. +In order to place the declarations for the scanner inside the +parser class, you should use @code{%code} sections. + +@node Java Differences +@subsection Differences between C/C++ and Java Grammars + +The different structure of the Java language forces several differences +between C/C++ grammars, and grammars designed for Java parsers. This +section summarizes this differences. + +@itemize +@item +Since Java lacks a preprocessor, the @code{YYERROR}, @code{YYACCEPT}, +@code{YYABORT} symbols (@pxref{Table of Symbols}) cannot obviously be +macros. Instead, they should be preceded in an action with +@code{return}. The actual definition of these symbols should be +opaque to the Bison grammar, and it might change in the future. The +only meaningful operation that you can do, is to return them. + +Note that of these three symbols, only @code{YYACCEPT} and +@code{YYABORT} will cause a return from the @code{yyparse} +method@footnote{Java parsers include the actions in a separate +method than @code{yyparse} in order to have an intuitive syntax that +corresponds to these C macros.}. + +@item +The prolog declarations have a different meaning than in C/C++ code. +@table @code +@item %code +@code{%code imports} blocks are placed at the beginning of the Java +source code. They may include copyright notices. For a @code{package} +declarations, it is suggested to use @code{%define package} instead. + +@code{%code} blocks are placed inside the parser class. If @code{%define +single_class} is being used, the definitions of @code{yylex} and +@code{yyerror} should be placed here. Subroutines for the parser actions +may be included in this kind of block. + +Other @code{%code} blocks are not supported in Java parsers. +@end table +@end itemize + @c ================================================= FAQ @node FAQ @@ -8326,7 +8652,7 @@ are addressed. * I can't build Bison:: Troubleshooting * Where can I find help?:: Troubleshouting * Bug Reports:: Troublereporting -* Other Languages:: Parsers in Java and others +* More Languages:: Parsers in C++, Java, and so on * Beta Testing:: Experimenting development versions * Mailing Lists:: Meeting other Bison users @end menu @@ -8649,15 +8975,15 @@ send a bug report just because you can not provide a fix. Send bug reports to @email{bug-bison@@gnu.org}. -@node Other Languages -@section Other Languages +@node More Languages +@section More Languages @display -Will Bison ever have C++ support? How about Java or @var{insert your +Will Bison ever have C++ and Java support? How about @var{insert your favorite language here}? @end display -C++ support is there now, and is documented. We'd love to add other +C++ and Java support is there now, and is documented. We'd love to add other languages; contributions are welcome. @node Beta Testing @@ -8977,12 +9303,18 @@ Macro to pretend that an unrecoverable syntax error has occurred, by making @code{yyparse} return 1 immediately. The error reporting function @code{yyerror} is not called. @xref{Parser Function, ,The Parser Function @code{yyparse}}. + +For Java parsers, this functionality is invoked using @code{return YYABORT;} +instead. @end deffn @deffn {Macro} YYACCEPT Macro to pretend that a complete utterance of the language has been read, by making @code{yyparse} return 0 immediately. @xref{Parser Function, ,The Parser Function @code{yyparse}}. + +For Java parsers, this functionality is invoked using @code{return YYACCEPT;} +instead. @end deffn @deffn {Macro} YYBACKUP @@ -9023,6 +9355,9 @@ Macro to pretend that a syntax error has just been detected: call @code{yyerror} and then perform normal error recovery if possible (@pxref{Error Recovery}), or (if recovery is impossible) make @code{yyparse} return 1. @xref{Error Recovery}. + +For Java parsers, this functionality is invoked using @code{return YYERROR;} +instead. @end deffn @deffn {Function} yyerror diff --git a/m4/.cvsignore b/m4/.cvsignore index dea96420..ba11f3e6 100644 --- a/m4/.cvsignore +++ b/m4/.cvsignore @@ -19,6 +19,8 @@ inline.m4 inttypes-h.m4 inttypes-pri.m4 inttypes.m4 +javacomp.m4 +javaexec.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 diff --git a/src/getargs.c b/src/getargs.c index dbd5b6dd..0938c698 100644 --- a/src/getargs.c +++ b/src/getargs.c @@ -1,7 +1,7 @@ /* Parse command line arguments for Bison. Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002, 2003, 2004, - 2005, 2006 Free Software Foundation, Inc. + 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of Bison, the GNU Compiler Compiler. @@ -70,6 +70,7 @@ int warnings_flag = warnings_none; static struct bison_language const valid_languages[] = { { "c", "c-skel.m4", ".c", ".h", true }, { "c++", "c++-skel.m4", ".cc", ".hh", true }, + { "java", "java-skel.m4", ".java", ".java", false }, { "", "", "", "", false } }; diff --git a/src/getargs.h b/src/getargs.h index 1e61931d..886f2004 100644 --- a/src/getargs.h +++ b/src/getargs.h @@ -1,6 +1,7 @@ /* Parse command line arguments for bison. - Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + + Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of Bison, the GNU Compiler Compiler. @@ -75,10 +76,10 @@ extern bool nondeterministic_parser; /* --language. */ struct bison_language { - char language[sizeof "c++"]; - char skeleton[sizeof "c++-skel.m4"]; - char src_extension[sizeof ".cc"]; - char header_extension[sizeof ".hh"]; + char language[sizeof "Java"]; + char skeleton[sizeof "java-skel.m4"]; + char src_extension[sizeof ".java"]; + char header_extension[sizeof ".java"]; bool add_tab; }; diff --git a/tests/Makefile.am b/tests/Makefile.am index 35fdf3ba..64999869 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -52,6 +52,7 @@ TESTSUITE_AT = \ calc.at \ torture.at existing.at regression.at \ c++.at \ + java.at \ cxx-type.at glr-regression.at TESTSUITE = $(srcdir)/testsuite diff --git a/tests/atlocal.in b/tests/atlocal.in index d4d1b231..9b429094 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -30,3 +30,9 @@ LDFLAGS='@LDFLAGS@' # Are special libraries needed? LIBS='@LIBS@ @INTLLIBS@' + +# Empty if no javac was found +CONF_JAVAC='@CONF_JAVAC@' + +# Empty if no Java VM was found +CONF_JAVA='@CONF_JAVA@' diff --git a/tests/input.at b/tests/input.at index 12561892..f24f489c 100644 --- a/tests/input.at +++ b/tests/input.at @@ -714,6 +714,7 @@ AT_DATA([input-c.y], [[%code q {} %code bad {} %code bad {} +%code format {} %% start: ; ]]) @@ -721,6 +722,7 @@ AT_CHECK([[bison input-c.y]], [0], [], [[input-c.y:1.7: warning: %code qualifier `q' is not used input-c.y:2.7-9: warning: %code qualifier `bad' is not used input-c.y:3.7-9: warning: %code qualifier `bad' is not used +input-c.y:4.7-12: warning: %code qualifier `format' is not used ]]) AT_DATA([input-c-glr.y], diff --git a/tests/java.at b/tests/java.at new file mode 100644 index 00000000..6d991c1b --- /dev/null +++ b/tests/java.at @@ -0,0 +1,415 @@ +# Simple calculator. -*- Autotest -*- + +# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 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 2, 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +AT_BANNER([[Java Calculator.]]) + + +# ------------------------- # +# Helping Autotest macros. # +# ------------------------- # + + +# _AT_DATA_JAVA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES], [BISON-EPILOGUE]) +# ---------------------------------------------------------------------- +# Produce `calc.y'. 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_JAVA_CALC_Y does. +m4_define([_AT_DATA_JAVA_CALC_Y], +[m4_if([$1$2$3], $[1]$[2]$[3], [], + [m4_fatal([$0: Invalid arguments: $@])])dnl +AT_DATA([Calc.y], +[[/* Infix notation calculator--calc */ +%language "Java" +%name-prefix "Calc"] +%define parser_class_name "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; +} + +/* Bison Declarations */ +%token NUM "number" +%type exp + +%nonassoc '=' /* comparison */ +%left '-' '+' +%left '*' '/' +%left NEG /* negation--unary minus */ +%right '^' /* exponentiation */ + +/* Grammar follows */ +%% +input: + line +| input line +; + +line: + '\n' +| exp '\n' +| error '\n' +; + +exp: + NUM { $$ = $1; } +| exp '=' exp + { + if ($1.intValue () != $3.intValue ()) + yyerror ("calc: error: " + $1 + " != " + $3); + } +| exp '+' exp { $$ = new Integer ($1.intValue () + $3.intValue ()); } +| exp '-' exp { $$ = new Integer ($1.intValue () - $3.intValue ()); } +| exp '*' exp { $$ = new Integer ($1.intValue () * $3.intValue ()); } +| exp '/' exp { $$ = new Integer ($1.intValue () / $3.intValue ()); } +| '-' exp %prec NEG { $$ = new Integer (-$2.intValue ()); } +| exp '^' exp { $$ = new Integer ((int) + Math.pow ($1.intValue (), + $3.intValue ())); } +| '(' exp ')' { $$ = $2; } +| '(' error ')' { $$ = new Integer (1111); } +| '!' { $$ = new Integer (0); return YYERROR; } +| '-' error { $$ = new Integer (0); return YYERROR; } +; +%% + + class Position { + public int line; + + public Position () + { + line = 0; + } + + public Position (int l) + { + line = l; + } + + public long getHashCode () + { + return line; + } + + public boolean equals (Position l) + { + return l.line == line; + } + + public String toString () + { + return Integer.toString (line); + } + + public int lineno () + { + return line; + } + } + +]$5 +]) +])# _AT_DATA_JAVA_CALC_Y + + +# AT_DATA_CALC_Y([BISON-OPTIONS], [BISON-EPILOGUE]) +# ------------------------------------------------- +# Produce `calc.y'. +m4_define([AT_DATA_JAVA_CALC_Y], +[_AT_DATA_JAVA_CALC_Y($[1], $[2], $[3], [$1], [$2]) +]) + + + +# AT_JAVA_COMPILE(SOURCE) +# ----------------------- +# Compile SOURCES into Java class files. Skip the test if java or javac is +# not installed. +m4_define([AT_JAVA_COMPILE], +[AT_CHECK([test -n "$CONF_JAVA$CONF_JAVAC" || exit 77]) +AT_CHECK([$SHELL ../../../javacomp.sh $1], + 0, [ignore], [ignore])]) + + +# AT_JAVA_PARSER_CHECK(COMMAND, EXIT-STATUS, EXPOUT, EXPERR, [PRE]) +# ----------------------------------------------------------------- +m4_define([AT_JAVA_PARSER_CHECK], +[AT_CHECK([$5 $SHELL ../../../javaexec.sh $1], [$2], [$3], [$4])]) + + +# _AT_CHECK_JAVA_CALC_ERROR(BISON-OPTIONS, INPUT, +# [VERBOSE-AND-LOCATED-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. +# +# The VERBOSE-AND-LOCATED-ERROR-MESSAGE is stripped of locations +# and expected tokens if necessary, and compared with the output. +m4_define([_AT_CHECK_JAVA_CALC_ERROR], +[m4_bmatch([$2], [^/], + [AT_JAVA_PARSER_CHECK([Calc < $2], 0, [], [stderr])], + [AT_DATA([[input]], +[[$2 +]]) +AT_JAVA_PARSER_CHECK([Calc < input], 0, [], [stderr])]) + +# Normalize the observed and expected error messages, depending upon the +# options. +# 1. Create the reference error message. +AT_DATA([[expout]], +[$3 +]) +# 2. If locations are not used, remove them. +AT_YYERROR_SEES_LOC_IF([], +[[sed 's/^[-0-9.]*: //' expout >at-expout +mv at-expout expout]]) +# 3. If error-verbose is not used, strip the`, unexpected....' part. +m4_bmatch([$1], [%error-verbose], [], +[[sed 's/syntax error, .*$/syntax error/' expout >at-expout +mv at-expout expout]]) +# 4. Check +AT_CHECK([cat stderr], 0, [expout]) +]) + +# _AT_CHECK_JAVA_CALC([BISON-DIRECTIVES], [BISON-CODE], [BISON-EPILOGUE]) +# ----------------------------------------------------------------------- +# Start a testing chunk which compiles `calc' grammar with +# BISON-DIRECTIVES, and performs several tests over the parser. +m4_define([_AT_CHECK_JAVA_CALC], +[# We use integers to avoid dependencies upon the precision of doubles. +AT_SETUP([Calculator $1]) + +AT_BISON_OPTION_PUSHDEFS([$1]) + +AT_DATA_JAVA_CALC_Y([$1 +%code { +$2 +}], [$3]) + +AT_CHECK([bison -o Calc.java Calc.y]) +AT_JAVA_COMPILE([Calc.java]) + +# Test the priorities. +AT_DATA([[input]], +[[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 +]]) +AT_JAVA_PARSER_CHECK([Calc < input], 0, [], [stderr]) + + +# Some syntax errors. +_AT_CHECK_JAVA_CALC_ERROR([$1], [0 0], + [1: syntax error, unexpected number]) +_AT_CHECK_JAVA_CALC_ERROR([$1], [1//2], + [1: syntax error, unexpected '/', expecting number or '-' or '(' or '!']) +_AT_CHECK_JAVA_CALC_ERROR([$1], [error], + [1: syntax error, unexpected $undefined]) +_AT_CHECK_JAVA_CALC_ERROR([$1], [1 = 2 = 3], + [1: syntax error, unexpected '=']) +_AT_CHECK_JAVA_CALC_ERROR([$1], [ ++1], + [2: syntax error, unexpected '+']) +# Exercise error messages with EOF: work on an empty file. +_AT_CHECK_JAVA_CALC_ERROR([$1], [/dev/null], + [1: syntax error, unexpected end of input]) + +# 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_JAVA_CALC_ERROR([$1], + [() + (1 + 1 + 1 +) + (* * *) + (1 * 2 * *) = 1], +[1: syntax error, unexpected ')', expecting number or '-' or '(' or '!' +1: syntax error, unexpected ')', expecting number or '-' or '(' or '!' +1: syntax error, unexpected '*', expecting number or '-' or '(' or '!' +1: syntax error, unexpected '*', expecting number or '-' or '(' or '!' +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_JAVA_CALC_ERROR([$1], [(!) + (0 0) = 1], +[1: syntax error, unexpected number +calc: error: 2222 != 1]) +_AT_CHECK_JAVA_CALC_ERROR([$1], [(- *) + (0 0) = 1], +[1: syntax error, unexpected '*', expecting number or '-' or '(' or '!' +1: syntax error, unexpected number +calc: error: 2222 != 1]) +AT_BISON_OPTION_POPDEFS + +AT_CLEANUP +])# _AT_CHECK_JAVA_CALC + + +# AT_CHECK_JAVA_CALC([BISON-DIRECTIVES], [BISON-EPILOGUE]) +# -------------------------------------------------------- +# Start a testing chunk which compiles `calc' grammar with +# BISON-DIRECTIVES, and performs several tests over the parser. +# Run the test with and without %error-verbose. +m4_define([AT_CHECK_JAVA_CALC], +[_AT_CHECK_JAVA_CALC([$1], [$2], [$3]) +_AT_CHECK_JAVA_CALC([%error-verbose $1], [$2], [$3]) +])# AT_CHECK_JAVA_CALC + + +# ------------------------ # +# Simple LALR Calculator. # +# ------------------------ # + +dnl AT_CHECK_JAVA_CALC([], []) + +AT_CHECK_JAVA_CALC([%define single_class %locations], [[ + StreamTokenizer st; + + public Calc (InputStream is) + { + Reader r = new InputStreamReader (is); + st = new StreamTokenizer(r); + st.resetSyntax (); + st.eolIsSignificant (true); + st.whitespaceChars (9, 9); + st.whitespaceChars (32, 32); + st.wordChars (48, 57); + + yyendpos = new Position (1); + } + + public int yylex () throws IOException { + int ttype = st.nextToken (); + yystartpos = yyendpos; + if (ttype == st.TT_EOF) + return EOF; + + else if (ttype == st.TT_EOL) + { + yyendpos = new Position (yyendpos.lineno () + 1); + return (int) '\n'; + } + + else if (ttype == st.TT_WORD) + { + yylval = new Integer (st.sval); + return NUM; + } + + else + return st.ttype; + } + + public void yyerror (Location l, String s) + { + if (l == null) + System.err.println (s); + else + System.err.println (l.begin + ": " + s); + } + + public static void main (String args[]) throws IOException + { + new Calc (System.in).parse (); + } +]]) + +AT_CHECK_JAVA_CALC([%pure-parser], [[ + public static void main (String args[]) throws IOException + { + CalcLexer l = new CalcLexer (System.in); + Calc p = new Calc (l); + p.parse (); + } +]], [[ +class CalcLexer implements Calc.Lexer { + Integer yylval; + + StreamTokenizer st; + + public Object getLVal () + { + return yylval; + } + + public CalcLexer (InputStream is) + { + Reader r = new InputStreamReader (is); + st = new StreamTokenizer(r); + st.resetSyntax (); + st.eolIsSignificant (true); + st.whitespaceChars (9, 9); + st.whitespaceChars (32, 32); + st.wordChars (48, 57); + } + + public int yylex () throws IOException { + int ttype = st.nextToken (); + if (ttype == st.TT_EOF) + return Calc.EOF; + + else if (ttype == st.TT_EOL) + return (int) '\n'; + + else if (ttype == st.TT_WORD) + { + yylval = new Integer (st.sval); + return Calc.NUM; + } + + else + return st.ttype; + } + + + public void yyerror (String s) + { + System.err.println (s); + } +} +]]) + +dnl AT_CHECK_JAVA_CALC([%pure-parser %locations], []) diff --git a/tests/testsuite.at b/tests/testsuite.at index d00c3c9e..569acfb8 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -71,6 +71,9 @@ m4_include([regression.at]) # Some C++ specific tests. m4_include([c++.at]) +# And some Java specific tests. +m4_include([java.at]) + # GLR tests: # C++ types, simplified m4_include([cxx-type.at]) -- 2.45.2