bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/3] try to match the columns in the ouput


From: Akim Demaille
Subject: [PATCH 2/3] try to match the columns in the ouput
Date: Sun, 30 Jun 2019 16:41:48 +0200

Now that compilers such as GCC 9 quote and underline the source code,
it is important for the generated code to (try to) be consistent with
the columns of the input file.

For instance on an incorrect input such as

    %define api.value.type {struct foo {}}
    %%
    exp: exp '+' exp { $$ = $1 + $3; }
       | '0'

Bison used to generate code that resulted in this error from GCC 9:

    foo.y:3:25: error: invalid operands to binary + (have 'YYSTYPE'
                       {aka 'struct foo'} and 'YYSTYPE' {aka 'struct foo'})
        3 | exp: exp '+' exp { $$ = $1 + $3; }
          |               ~~~~~~~~~ ^ ~~~~~~~~
          |                    |           |
          |                    |           YYSTYPE {aka struct foo}
          |                    YYSTYPE {aka struct foo}

Now, the error message is:

    foo.y:3:28: error: invalid operands to binary + (have 'YYSTYPE'
                       {aka 'struct foo'} and 'YYSTYPE' {aka 'struct foo'})
        3 | exp: exp '+' exp { $$ = $1 + $3; }
          |                            ^ ~~~~~
          |                                   |
          |                                   YYSTYPE {aka struct foo}

See https://lists.gnu.org/archive/html/bison-patches/2019-06/msg00012.html.
With help from Paul Eggert.

* data/skeletons/bison.m4 (b4_symbol_action): Output the code in
column 0, leave indentation matters to the C code.
* src/output.c (user_actions_output): Preserve the incoming
indentation in the output.
(prepare_symbol_definitions): Likewise for %printer/%destructor.
* src/scan-code.l (handle_action_dollar): After having output the
expansion of $n, start a new line and indent to match the incoming
column right after $n.
* tests/synclines.at (Output columns): New.
---
 NEWS                    | 31 ++++++++++++++
 data/skeletons/bison.m4 |  2 +-
 src/output.c            | 26 ++++++++----
 src/scan-code.l         |  6 +++
 tests/synclines.at      | 91 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 147 insertions(+), 9 deletions(-)

diff --git a/NEWS b/NEWS
index df884905..d2007c1e 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,37 @@ GNU Bison NEWS
   The Java backend no longer emits code and data for parser tracing if the
   %define variable parse.trace is not defined.
 
+*** Matching columns in the output
+
+  Newer compilers, such as GCC 9, quote to source files in the error
+  messages.  The generated parsers are now formatted to improve the quality
+  of these messages.  For instance on an incorrect input such as
+
+    %define api.value.type {struct foo {}}
+    %%
+    exp: exp '+' exp { $$ = $1 + $3; }
+       | '0'
+
+  Bison used to generate code that resulted in this error from GCC 9:
+
+    foo.y:3:25: error: invalid operands to binary + (have 'YYSTYPE'
+                       {aka 'struct foo'} and 'YYSTYPE' {aka 'struct foo'})
+        3 | exp: exp '+' exp { $$ = $1 + $3; }
+          |               ~~~~~~~~~ ^ ~~~~~~~~
+          |                    |           |
+          |                    |           YYSTYPE {aka struct foo}
+          |                    YYSTYPE {aka struct foo}
+
+  Now, the error message is:
+
+    foo.y:3:28: error: invalid operands to binary + (have 'YYSTYPE'
+                       {aka 'struct foo'} and 'YYSTYPE' {aka 'struct foo'})
+        3 | exp: exp '+' exp { $$ = $1 + $3; }
+          |                            ^ ~~~~~
+          |                                   |
+          |                                   YYSTYPE {aka struct foo}
+
+
 * Noteworthy changes in release 3.4.1 (2019-05-22) [stable]
 
 ** Bug fixes
diff --git a/data/skeletons/bison.m4 b/data/skeletons/bison.m4
index ff769410..2c01ac0f 100644
--- a/data/skeletons/bison.m4
+++ b/data/skeletons/bison.m4
@@ -449,7 +449,7 @@ m4_define([b4_symbol_action],
                    [(*yylocationp)])dnl
     _b4_symbol_case([$1])[]dnl
 b4_syncline([b4_symbol([$1], [$2_line])], [b4_symbol([$1], [$2_file])])dnl
-      b4_symbol([$1], [$2])
+b4_symbol([$1], [$2])
 b4_syncline([@oline@], [@ofile@])dnl
         break;
 
diff --git a/src/output.c b/src/output.c
index 1f519d0c..85528beb 100644
--- a/src/output.c
+++ b/src/output.c
@@ -359,9 +359,9 @@ symbol_numbers_output (FILE *out)
 }
 
 
-/*---------------------------------.
-| Output the user actions to OUT.  |
-`---------------------------------*/
+/*-------------------------------------------.
+| Output the user reduction actions to OUT.  |
+`-------------------------------------------*/
 
 static void
 user_actions_output (FILE *out)
@@ -370,11 +370,19 @@ user_actions_output (FILE *out)
   for (rule_number r = 0; r < nrules; ++r)
     if (rules[r].action)
       {
-        fprintf (out, "%s(%d, [b4_syncline(%d, ",
+        fprintf (out, "%s(%d, [",
                  rules[r].is_predicate ? "b4_predicate_case" : "b4_case",
-                 r + 1, rules[r].action_loc.start.line);
-        string_output (out, rules[r].action_loc.start.file);
-        fprintf (out, ")dnl\n[    %s]])\n\n", rules[r].action);
+                 r + 1);
+        if (!no_lines_flag)
+          {
+            fprintf (out, "b4_syncline(%d, ",
+                     rules[r].action_loc.start.line);
+            string_output (out, rules[r].action_loc.start.file);
+            fprintf (out, ")dnl\n");
+          }
+        fprintf (out, "[%*s%s]])\n\n",
+                 rules[r].action_loc.start.column - 1, "",
+                 rules[r].action);
       }
   fputs ("])\n\n", out);
 }
@@ -482,7 +490,9 @@ prepare_symbol_definitions (void)
               muscle_location_grow (key, p->location);
 
               SET_KEY (pname);
-              MUSCLE_INSERT_STRING_RAW (key, p->code);
+              obstack_printf (&muscle_obstack,
+                              "%*s%s", p->location.start.column - 1, "", 
p->code);
+              muscle_insert (key, obstack_finish0 (&muscle_obstack));
             }
         }
 #undef SET_KEY2
diff --git a/src/scan-code.l b/src/scan-code.l
index 07f1117a..414a28a7 100644
--- a/src/scan-code.l
+++ b/src/scan-code.l
@@ -698,6 +698,12 @@ handle_action_dollar (symbol_list *rule, char *text, const 
location *dollar_loc)
       }
       break;
     }
+  if (!no_lines_flag)
+    obstack_printf (&obstack_for_string,
+                    "\n]b4_syncline(%d, %s)dnl\n[%*s",
+                    dollar_loc->start.line,
+                    quotearg_style (c_quoting_style, dollar_loc->start.file),
+                    dollar_loc->end.column - 1, "");
 }
 
 
diff --git a/tests/synclines.at b/tests/synclines.at
index df9d8d66..f900ba44 100644
--- a/tests/synclines.at
+++ b/tests/synclines.at
@@ -497,3 +497,94 @@ AT_CLEANUP
 m4_map_args([AT_TEST], [yacc.c], [glr.c], [lalr1.cc], [glr.cc])
 
 m4_popdef([AT_TEST])
+
+
+
+## ---------------- ##
+## Output columns.  ##
+## ---------------- ##
+
+AT_SETUP([Output columns])
+
+# This test is fragile: its point is to check the compiler's error
+# message, but it seems too hard to do portability (even between
+# version of GCC).  So instead, let's just check the generated code
+# itself.
+
+AT_BISON_OPTION_PUSHDEFS
+AT_DATA([input.y],
+[[%{
+]AT_YYERROR_DECLARE_EXTERN[
+]AT_YYLEX_DECLARE_EXTERN[
+%}
+%define api.value.type union
+%type <int> '0' exp
+%destructor { /* --BEGIN */
+              destructor
+              /* --END   */ } <*>
+%printer { /* --BEGIN */
+           printer
+           /* --END   */ } <*>
+
+
+
+%left '+'
+%%
+exp: exp '+' exp {  /* --BEGIN */
+                    $$ = $1 + $3;
+                    /* --END */ }
+   | '0'
+]])
+
+AT_BISON_CHECK([-o input.c input.y])
+AT_CHECK([[sed -ne '/--BEGIN/,/--END/{' \
+    -e '/input.c/s/ [0-9]* / LINE /;' \
+    -e 'p;}' \
+    input.c]], 0,
+[[         { /* --BEGIN */
+           printer
+           /* --END   */ }
+         { /* --BEGIN */
+           printer
+           /* --END   */ }
+            { /* --BEGIN */
+              destructor
+              /* --END   */ }
+            { /* --BEGIN */
+              destructor
+              /* --END   */ }
+                 {  /* --BEGIN */
+                    (yyval.exp)
+#line 19 "input.y"
+                       = (yyvsp[-2].exp)
+#line 19 "input.y"
+                            + (yyvsp[0].exp)
+#line 19 "input.y"
+                                ;
+                    /* --END */ }
+]])
+
+AT_BISON_CHECK([--no-line -o input.c input.y])
+AT_CHECK([[sed -ne '/--BEGIN/,/--END/{' \
+    -e '/input.c/s/ [0-9]* / LINE /;' \
+    -e 'p;}' \
+    input.c]], 0,
+[[         { /* --BEGIN */
+           printer
+           /* --END   */ }
+         { /* --BEGIN */
+           printer
+           /* --END   */ }
+            { /* --BEGIN */
+              destructor
+              /* --END   */ }
+            { /* --BEGIN */
+              destructor
+              /* --END   */ }
+                 {  /* --BEGIN */
+                    (yyval.exp) = (yyvsp[-2].exp) + (yyvsp[0].exp);
+                    /* --END */ }
+]])
+
+AT_BISON_OPTION_POPDEFS
+AT_CLEANUP
-- 
2.22.0




reply via email to

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