[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
java: demonstrate push parsers
From: |
Akim Demaille |
Subject: |
java: demonstrate push parsers |
Date: |
Sat, 2 May 2020 09:43:20 +0200 |
Hi Dennis, hi Paolo,
I am not a Java programmer, so I'd like to have your acknowledgement on a
change in the patch below: the Location inner class of the parser was not a
static class, and I don't see why. It certainly makes it easier for a push
parser that it is static, but maybe I'm missing something. Also, I do not see
if that change can have impact on (realistic) user code.
I also relaxed the constraints over Lexer in the case of purely-push parsers:
there's no reason to ask for yylex, getLVal and get(Start|End)Pos.
Thanks in advance!
commit 34a85e670b11fe21813e00d89ecbd761ab2d5caf
Author: Akim Demaille <address@hidden>
Date: Sat May 2 09:01:34 2020 +0200
java: demonstrate push parsers
* data/skeletons/lalr1.java (Location): Make it a static class.
(Lexer.yylex, Lexer.getLVal, Lexer.getStartPos, Lexer.getEndPos):
These are not needed in push parsers.
* examples/java/calc/Calc.y: Demonstrate push parsers in the Java.
* doc/bison.texi: Push parsers have been supported for a long time,
remove incorrect statements stating the opposite.
diff --git a/NEWS b/NEWS
index 389448e1..05185c75 100644
--- a/NEWS
+++ b/NEWS
@@ -216,8 +216,8 @@ GNU Bison NEWS
*** Examples
- There are now two examples in examples/java: a very simple calculator, and
- one that tracks locations to provide accurate error messages.
+ There are now examples/java: a very simple calculator, and a more complete
+ one (push-parser, location tracking, and debug traces).
The lexcalc example (a simple example in C based on Flex and Bison) now
also demonstrates location tracking.
diff --git a/TODO b/TODO
index e2200fe1..31f890e8 100644
--- a/TODO
+++ b/TODO
@@ -25,9 +25,6 @@ should be updated to not use YYERRCODE. Returning an undef
token is good
enough.
** Java
-*** Examples
-Have an example with a push parser. Use autocompletion in that case.
-
*** calc.at
Stop hard-coding "Calc". Adjust local.at (look for FIXME).
diff --git a/data/skeletons/lalr1.java b/data/skeletons/lalr1.java
index 8536359b..1baa497d 100644
--- a/data/skeletons/lalr1.java
+++ b/data/skeletons/lalr1.java
@@ -121,7 +121,7 @@ import java.text.MessageFormat;
* Locations represent a part of the input through the beginning
* and ending positions.
*/
- public class ]b4_location_type[ {
+ public static class ]b4_location_type[ {
/**
* The first, inclusive, position in the range.
*/
@@ -182,8 +182,7 @@ import java.text.MessageFormat;
]b4_token_enums[
/** Deprecated, use ]b4_symbol(0, id)[ instead. */
public static final int EOF = ]b4_symbol(0, id)[;
-
-]b4_locations_if([[
+]b4_pull_if([b4_locations_if([[
/**
* Method to retrieve the beginning position of the last scanned token.
* @@return the position at which the last scanned token starts.
@@ -209,7 +208,7 @@ import java.text.MessageFormat;
* @@return the token identifier corresponding to the next token.
*/
int yylex()]b4_maybe_throws([b4_lex_throws])[;
-
+]])[
/**
* Emit an error]b4_locations_if([ referring to the given location])[in a
user-defined way.
*
@@ -832,7 +831,7 @@ b4_dollar_popdef[]dnl
this.push_parse_initialized = true;
}
-]b4_locations_if([
+]b4_locations_if([[
/**
* Push parse given input from an external lexer.
*
@@ -842,11 +841,10 @@ b4_dollar_popdef[]dnl
*
* @@return <tt>YYACCEPT, YYABORT, YYPUSH_MORE</tt>
*/
- public int push_parse(int yylextoken, b4_yystype yylexval, b4_position_type
yylexpos)b4_maybe_throws([b4_list2([b4_lex_throws], [b4_throws])])
- {
- return push_parse(yylextoken, yylexval, new b4_location_type (yylexpos));
+ public int push_parse(int yylextoken, ]b4_yystype[ yylexval,
]b4_position_type[ yylexpos)]b4_maybe_throws([b4_list2([b4_lex_throws],
[b4_throws])])[ {
+ return push_parse(yylextoken, yylexval, new
]b4_location_type[(yylexpos));
}
-])[]])[
+]])])[
]b4_both_if([[
/**
@@ -857,21 +855,18 @@ b4_dollar_popdef[]dnl
* @@return <tt>true</tt> if the parsing succeeds. Note that this does not
* imply that there were no syntax errors.
*/
- public boolean parse()]b4_maybe_throws([b4_list2([b4_lex_throws],
[b4_throws])])[
- {
- if (yylexer == null)
- throw new NullPointerException("Null Lexer");
- int status;
- do {
- int token = yylexer.yylex();
- ]b4_yystype[ lval = yylexer.getLVal();
-]b4_locations_if([dnl
- b4_location_type yyloc = new b4_location_type (yylexer.getStartPos (),
- yylexer.getEndPos
());])[]b4_locations_if([[
- status = push_parse(token,lval,yyloc);]], [[
- status = push_parse(token,lval);]])[
- } while (status == YYPUSH_MORE);
- return (status == YYACCEPT);
+ public boolean parse()]b4_maybe_throws([b4_list2([b4_lex_throws],
[b4_throws])])[ {
+ if (yylexer == null)
+ throw new NullPointerException("Null Lexer");
+ int status;
+ do {
+ int token = yylexer.yylex();
+ ]b4_yystype[ lval = yylexer.getLVal();]b4_locations_if([[
+ ]b4_location_type[ yyloc = new
]b4_location_type[(yylexer.getStartPos(), yylexer.getEndPos());
+ status = push_parse(token, lval, yyloc);]], [[
+ status = push_parse(token, lval);]])[
+ } while (status == YYPUSH_MORE);
+ return status == YYACCEPT;
}
]])[
diff --git a/doc/bison.texi b/doc/bison.texi
index 32d41924..734ca088 100644
--- a/doc/bison.texi
+++ b/doc/bison.texi
@@ -13336,9 +13336,9 @@ changed using @code{%define api.location.type
@{@var{class-name}@}}.
@end deftypemethod
@deftypemethod {Lexer} {int} yylex ()
-Return the next token. Its type is the return value, its semantic
-value and location are saved and returned by the their methods in the
-interface.
+Return the next token. Its type is the return value, its semantic value and
+location are saved and returned by the their methods in the interface. Not
+needed for push-only parsers.
Use @samp{%define lex_throws} to specify any uncaught exceptions.
Default is @code{java.io.IOException}.
@@ -13348,7 +13348,7 @@ Default is @code{java.io.IOException}.
@deftypemethodx {Lexer} {Position} getEndPos ()
Return respectively the first position of the last token that @code{yylex}
returned, and the first position beyond it. These methods are not needed
-unless location tracking is active.
+unless location tracking and pull parsing are active.
They should return new objects for each call, to avoid that all the symbol
share the same Position boundaries.
@@ -13358,7 +13358,8 @@ The return type can be changed using @code{%define
api.position.type
@end deftypemethod
@deftypemethod {Lexer} {Object} getLVal ()
-Return the semantic value of the last token that yylex returned.
+Return the semantic value of the last token that yylex returned. Not needed
+for push-only parsers.
The return type can be changed using @samp{%define api.value.type
@{@var{class-name}@}}.
diff --git a/examples/java/README.md b/examples/java/README.md
index 4be92c80..25b7f27c 100644
--- a/examples/java/README.md
+++ b/examples/java/README.md
@@ -9,7 +9,7 @@ afterwards.
The usual calculator, a very simple version.
## calc/Calc.y
-The calculator, but with location tracking and debug traces.
+The calculator, but with location tracking, debug traces, and a push parser.
<!---
diff --git a/examples/java/calc/Calc.y b/examples/java/calc/Calc.y
index 5a5d2048..4bb07b5f 100644
--- a/examples/java/calc/Calc.y
+++ b/examples/java/calc/Calc.y
@@ -2,6 +2,7 @@
%define api.parser.class {Calc}
%define api.parser.public
+%define api.push-pull push
%define parse.error custom
%define parse.trace
@@ -20,12 +21,19 @@
%code {
public static void main(String[] args) throws IOException {
- CalcLexer l = new CalcLexer(System.in);
- Calc p = new Calc(l);
+ CalcLexer scanner = new CalcLexer(System.in);
+ Calc parser = new Calc(scanner);
for (String arg : args)
if (arg.equals("-p"))
- p.setDebugLevel(1);
- if (!p.parse())
+ parser.setDebugLevel(1);
+ int status;
+ do {
+ int token = scanner.getToken();
+ Object lval = scanner.getValue();
+ Calc.Location yyloc = scanner.getLocation();
+ status = parser.push_parse(token, lval, yyloc);
+ } while (status == Calc.YYPUSH_MORE);
+ if (status != Calc.YYACCEPT)
System.exit(1);
}
@@ -105,12 +113,12 @@ class CalcLexer implements Calc.Lexer {
Position start = new Position(1, 0);
Position end = new Position(1, 0);
- public Position getStartPos() {
- return new Position(start);
- }
-
- public Position getEndPos() {
- return new Position(end);
+ /**
+ * The location of the last token read.
+ * Implemented with getStartPos and getEndPos in pull parsers.
+ */
+ public Calc.Location getLocation() {
+ return new Calc.Location(new Position(start), new Position(end));
}
/**
@@ -150,11 +158,17 @@ class CalcLexer implements Calc.Lexer {
Integer yylval;
- public Object getLVal() {
+ /**
+ * The value of the last token read. Called getLVal in pull parsers
+ */
+ public Object getValue() {
return yylval;
}
- public int yylex() throws IOException {
+ /**
+ * Fetch the next token. Called yylex in pull parsers.
+ */
+ public int getToken() throws IOException {
start.set(reader.getPosition());
int ttype = st.nextToken();
end.set(reader.getPosition());
@@ -170,7 +184,7 @@ class CalcLexer implements Calc.Lexer {
end.set(reader.getPreviousPosition());
return NUM;
case ' ': case '\t':
- return yylex();
+ return getToken();
case '!':
return BANG;
case '+':
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- java: demonstrate push parsers,
Akim Demaille <=