java: add push-parser support

* data/lalr1.java: Capture the declarations as m4 macros to avoid
duplication.  When push parsing, the declarations occur at the class
instance level rather than within the parse() function.

Change the way that the parser state is initialized.  For
push-parsing, the parse state declarations are moved to
"push_parse_initialize()", which is called on the first invocation of
"push_parse()". The %initial-action code is also inserted after the
invocation of "push_parse_initialize()".

The body of the parse loop is modified to return values at appropriate
points when doing push parsing.  In order to make push parsing work,
it is necessary to divide YYNEWSTATE into two states: YYNEWSTATE and
YYGETTOKEN. On the first call to push_parse(), the state is
YYNEWSTATE. On all later entries, the state is set to YYGETTOKEN. The
YYNEWSTATE switch arm falls through into YYGETTOKEN. YYGETTOKEN
indicates that a new token is potentially needed.  Normally, with a
pull parser, this new token would be obtained by calling "yylex()". In
the push parser, the value YYMORE is returned to the caller. On the
next call to push_parse(), the parser will return to the YYGETTOKEN
state and continue operation.

* tests/javapush.at: New test file for java push parsing.
* tests/testsuite.at: Use it.
* tests/local.mk: Adjust.
* doc/bison.texi (Java Push Parser Interface): New.

Signed-off-by: Akim Demaille <akim@lrde.epita.fr>
This commit is contained in:
Dennis Heimbigner
2013-06-13 10:08:19 +02:00
committed by Akim Demaille
parent 0fcc2e9a74
commit aa94def12d
6 changed files with 1141 additions and 53 deletions

View File

@@ -366,6 +366,7 @@ Java Parsers
* Java Parser Interface:: Instantiating and running the parser
* Java Scanner Interface:: Specifying the scanner for the parser
* Java Action Features:: Special features for use in actions
* Java Push Parser Interface:: Instantiating and running the a push parser
* Java Differences:: Differences between C/C++ and Java Grammars
* Java Declarations Summary:: List of Bison declarations used with Java
@@ -11500,6 +11501,7 @@ main (int argc, char *argv[])
* Java Parser Interface:: Instantiating and running the parser
* Java Scanner Interface:: Specifying the scanner for the parser
* Java Action Features:: Special features for use in actions
* Java Push Parser Interface:: Instantiating and running the a push parser
* Java Differences:: Differences between C/C++ and Java Grammars
* Java Declarations Summary:: List of Bison declarations used with Java
@end menu
@@ -11811,7 +11813,6 @@ The return type can be changed using @samp{%define api.value.type
@{@var{class-name}@}}.
@end deftypemethod
@node Java Action Features
@subsection Special Features for Use in Java Actions
@@ -11890,6 +11891,73 @@ instance in use. The @code{Location} and @code{Position} parameters are
available only if location tracking is active.
@end deftypefn
@node Java Push Parser Interface
@subsection Java Push Parser Interface
@c - define push_parse
@findex %define api.push-pull
(The current push parsing interface is experimental and may evolve. More
user feedback will help to stabilize it.)
Normally, Bison generates a pull parser for Java.
The following Bison declaration says that you want the parser to be a push
parser (@pxref{%define Summary,,api.push-pull}):
@example
%define api.push-pull push
@end example
Most of the discussion about the Java pull Parser Interface, (@pxref{Java
Parser Interface}) applies to the push parser interface as well.
When generating a push parser, the method @code{push_parse} is created with
the following signature (depending on if locations are enabled).
@deftypemethod {YYParser} {void} push_parse ({int} @var{token}, {Object} @var{yylval})
@deftypemethodx {YYParser} {void} push_parse ({int} @var{token}, {Object} @var{yylval}, {Location} @var{yyloc})
@deftypemethodx {YYParser} {void} push_parse ({int} @var{token}, {Object} @var{yylval}, {Position} @var{yypos})
@end deftypemethod
The primary difference with respect to a pull parser is that the parser
method @code{push_parse} is invoked repeatedly to parse each token. This
function is available if either the "%define api.push-pull push" or "%define
api.push-pull both" declaration is used (@pxref{%define
Summary,,api.push-pull}). The @code{Location} and @code{Position}
parameters are available only if location tracking is active.
The value returned by the @code{push_parse} method is one of the following
four constants: @code{YYABORT}, @code{YYACCEPT}, @code{YYERROR}, or
@code{YYMORE}. This new value, @code{YYMORE}, may be returned if more input
is required to finish parsing the grammar.
If api.push-pull is declared as @code{both}, then the generated parser class
will also implement the @code{parse} method. This method's body is a loop
that repeatedly invokes the scanner and then passes the values obtained from
the scanner to the @code{push_parse} method.
There is one additional complication. Technically, the push parser does not
need to know about the scanner (i.e. an object implementing the
@code{YYParser.Lexer} interface), but it does need access to the
@code{yyerror} method. Currently, the @code{yyerror} method is defined in
the @code{YYParser.Lexer} interface. Hence, an implementation of that
interface is still required in order to provide an implementation of
@code{yyerror}. The current approach (and subject to change) is to require
the @code{YYParser} constructor to be given an object implementing the
@code{YYParser.Lexer} interface. This object need only implement the
@code{yyerror} method; the other methods can be stubbed since they will
never be invoked. The simplest way to do this is to add a trivial scanner
implementation to your grammar file using whatever implementation of
@code{yyerror} is desired. The following code sample shows a simple way to
accomplish this.
@example
%code lexer
@{
public Object getLVal () @{return null;@}
public int yylex () @{return 0;@}
public void yyerror (String s) @{System.err.println(s);@}
@}
@end example
@node Java Differences
@subsection Differences between C/C++ and Java Grammars