bison-patches
[Top][All Lists]
Advanced

[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 '+':




reply via email to

[Prev in Thread] Current Thread [Next in Thread]