bison-patches
[Top][All Lists]
Advanced

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

[PATCH] Add command line option to map file prefixes


From: Joshua Watt
Subject: [PATCH] Add command line option to map file prefixes
Date: Thu, 7 May 2020 11:25:46 -0500

Teaches bison about a new command line option, --file-prefix-map OLD=NEW
which causes it to replace and file path of OLD in the text of the
output file with NEW, mainly for header guards and comments. The primary
use of this is to make builds reproducible with different input paths,
and in particular the debugging information produced when the source
code is compiled. For example, a distro may know that the bison source
code will be located at "/usr/src/bison" and thus can generate bison
files that are reproducible with the following command:

 bison --output=/build/bison/parse.c -d -L C 
--file-prefix-map=/build/bison/=/usr/src/bison parse.y

Importantly, this will change the header guards from:

 #ifndef YY_BUILD_BISON_PARSE_H

to

 #ifndef YY_USR_SRC_BISON_PARSE_H

which is reproducible.

Signed-off-by: Joshua Watt <address@hidden>
---
 data/skeletons/glr.c       |  4 +-
 data/skeletons/glr.cc      |  4 +-
 data/skeletons/lalr1.cc    |  6 +--
 data/skeletons/location.cc |  2 +-
 data/skeletons/yacc.c      |  4 +-
 src/files.c                | 55 ++++++++++++++++++++++
 src/files.h                |  4 ++
 src/getargs.c              | 50 +++++++++++++-------
 src/output.c               |  2 +
 tests/c++.at               | 93 ++++++++++++++++++++++++++++++++++++++
 10 files changed, 197 insertions(+), 27 deletions(-)

diff --git a/data/skeletons/glr.c b/data/skeletons/glr.c
index c5074a3e..52f8d8ec 100644
--- a/data/skeletons/glr.c
+++ b/data/skeletons/glr.c
@@ -189,9 +189,9 @@ b4_glr_cc_if([],
 [b4_output_begin([b4_spec_header_file])
 b4_copyright([Skeleton interface for Bison GLR parsers in C],
              [2002-2015, 2018-2020])[
-]b4_cpp_guard_open([b4_spec_header_file])[
+]b4_cpp_guard_open([b4_spec_mapped_header_file])[
 ]b4_shared_declarations[
-]b4_cpp_guard_close([b4_spec_header_file])[
+]b4_cpp_guard_close([b4_spec_mapped_header_file])[
 ]b4_output_end[
 ]])])
 
diff --git a/data/skeletons/glr.cc b/data/skeletons/glr.cc
index 95053a2f..ceb0f81d 100644
--- a/data/skeletons/glr.cc
+++ b/data/skeletons/glr.cc
@@ -372,9 +372,9 @@ b4_copyright([Skeleton interface for Bison GLR parsers in 
C++],
 // C++ GLR parser skeleton written by Akim Demaille.
 
 ]b4_disclaimer[
-]b4_cpp_guard_open([b4_spec_header_file])[
+]b4_cpp_guard_open([b4_spec_mapped_header_file])[
 ]b4_shared_declarations[
-]b4_cpp_guard_close([b4_spec_header_file])[
+]b4_cpp_guard_close([b4_spec_mapped_header_file])[
 ]b4_output_end])
 
 # Let glr.c (and b4_shared_declarations) believe that the user
diff --git a/data/skeletons/lalr1.cc b/data/skeletons/lalr1.cc
index e6da4d81..3ce9e264 100644
--- a/data/skeletons/lalr1.cc
+++ b/data/skeletons/lalr1.cc
@@ -500,16 +500,16 @@ b4_defines_if(
 b4_copyright([Skeleton interface for Bison LALR(1) parsers in C++])
 [
 /**
- ** \file ]b4_spec_header_file[
+ ** \file ]b4_spec_mapped_header_file[
  ** Define the ]b4_namespace_ref[::parser class.
  */
 
 // C++ LALR(1) parser skeleton written by Akim Demaille.
 
 ]b4_disclaimer[
-]b4_cpp_guard_open([b4_spec_header_file])[
+]b4_cpp_guard_open([b4_spec_mapped_header_file])[
 ]b4_shared_declarations(hh)[
-]b4_cpp_guard_close([b4_spec_header_file])[
+]b4_cpp_guard_close([b4_spec_mapped_header_file])[
 ]b4_output_end[
 ]])
 
diff --git a/data/skeletons/location.cc b/data/skeletons/location.cc
index 34db4188..dff984e7 100644
--- a/data/skeletons/location.cc
+++ b/data/skeletons/location.cc
@@ -48,7 +48,7 @@ m4_ifdef([b4_location_file],
                                   ["b4_location_file"])])
  m4_define([b4_location_path],
            b4_percent_define_get([[api.location.include]],
-                                 ["b4_dir_prefix[]b4_location_file"]))
+                                 ["b4_mapped_dir_prefix[]b4_location_file"]))
  m4_define([b4_location_path],
            m4_substr(m4_defn([b4_location_path]), 1, 
m4_eval(m4_len(m4_defn([b4_location_path])) - 2)))
  ])
diff --git a/data/skeletons/yacc.c b/data/skeletons/yacc.c
index a790f6fa..b87c76b3 100644
--- a/data/skeletons/yacc.c
+++ b/data/skeletons/yacc.c
@@ -313,14 +313,14 @@ m4_define([b4_declare_yyparse],
 # Declaration that might either go into the header (if --defines)
 # or open coded in the parser body.
 m4_define([b4_shared_declarations],
-[b4_cpp_guard_open([b4_spec_header_file])[
+[b4_cpp_guard_open([b4_spec_mapped_header_file])[
 ]b4_declare_yydebug[
 ]b4_percent_code_get([[requires]])[
 ]b4_token_enums_defines[
 ]b4_declare_yylstype[
 ]b4_declare_yyparse[
 ]b4_percent_code_get([[provides]])[
-]b4_cpp_guard_close([b4_spec_header_file])[]dnl
+]b4_cpp_guard_close([b4_spec_mapped_header_file])[]dnl
 ])
 
 
diff --git a/src/files.c b/src/files.c
index 71c10e34..f685cdaa 100644
--- a/src/files.c
+++ b/src/files.c
@@ -52,6 +52,7 @@ char *spec_verbose_file = NULL;  /* for --verbose. */
 char *spec_graph_file = NULL;    /* for -g. */
 char *spec_xml_file = NULL;      /* for -x. */
 char *spec_header_file = NULL;  /* for --defines. */
+char *spec_mapped_header_file = NULL;
 char *parser_file_name;
 
 /* All computed output file names.  */
@@ -88,11 +89,19 @@ uniqstr grammar_file = NULL;
 char *all_but_ext;
 static char *all_but_tab_ext;
 char *dir_prefix;
+char *mapped_dir_prefix;
 
 /* C source file extension (the parser source).  */
 static char *src_extension = NULL;
 /* Header file extension (if option '`-d'' is specified).  */
 static char *header_extension = NULL;
+
+static struct prefix_map {
+  struct prefix_map *next;
+  char *oldprefix;
+  char *newprefix;
+} *prefix_maps;
+
 
 /*-----------------------------------------------------------------.
 | Return a newly allocated string composed of the concatenation of |
@@ -156,6 +165,40 @@ xfdopen (int fd, char const *mode)
   return res;
 }
 
+static char *
+map_file_name (char const *filename)
+{
+  struct prefix_map const *p;
+
+  if (!filename)
+    return NULL;
+
+  for (p = prefix_maps; p != NULL; p = p->next)
+    if (strncmp(p->oldprefix, filename, strlen(p->oldprefix)) == 0)
+      break;
+
+  if (!p)
+    return xstrdup (filename);
+
+  size_t oldprefix_len = strlen (p->oldprefix);
+  size_t newprefix_len = strlen (p->newprefix);
+  char *s = xmalloc (1 + newprefix_len + strlen (filename) - oldprefix_len);
+  strcpy (s, p->newprefix);
+  strcat (s, &filename[oldprefix_len]);
+
+  return s;
+}
+
+void
+add_prefix_map(char const* oldprefix, char const* newprefix)
+{
+  struct prefix_map *p = xmalloc(sizeof(*p));
+  p->oldprefix = xstrdup(oldprefix);
+  p->newprefix = xstrdup(newprefix);
+  p->next = prefix_maps;
+  prefix_maps = p;
+}
+
 /*------------------------------------------------------------------.
 | Compute ALL_BUT_EXT, ALL_BUT_TAB_EXT and output files extensions. |
 `------------------------------------------------------------------*/
@@ -360,6 +403,9 @@ compute_output_file_names (void)
       output_file_name_check (&spec_verbose_file, false);
     }
 
+  spec_mapped_header_file = map_file_name(spec_header_file);
+  mapped_dir_prefix = map_file_name(dir_prefix);
+
   free (all_but_tab_ext);
   free (src_extension);
   free (header_extension);
@@ -429,10 +475,19 @@ output_file_names_free (void)
   free (spec_graph_file);
   free (spec_xml_file);
   free (spec_header_file);
+  free (spec_mapped_header_file);
   free (parser_file_name);
   free (dir_prefix);
+  free (mapped_dir_prefix);
   for (int i = 0; i < generated_files_size; i++)
     free (generated_files[i].name);
   free (generated_files);
   free (relocate_buffer);
+
+  while (prefix_maps) {
+    struct prefix_map *p = prefix_maps;
+    prefix_maps = prefix_maps->next;
+    free(p->oldprefix);
+    free(p->newprefix);
+  }
 }
diff --git a/src/files.h b/src/files.h
index 00814ad0..379e6495 100644
--- a/src/files.h
+++ b/src/files.h
@@ -49,9 +49,11 @@ extern char *spec_xml_file;
 
 /* File name specified with --defines.  */
 extern char *spec_header_file;
+extern char *spec_mapped_header_file;
 
 /* Directory prefix of output file names.  */
 extern char *dir_prefix;
+extern char *mapped_dir_prefix;
 
 /* The file name as given on the command line.
    Not named "input_file" because Flex uses this name for an argument,
@@ -82,4 +84,6 @@ FILE *xfopen (const char *name, char const *mode);
 void xfclose (FILE *ptr);
 FILE *xfdopen (int fd, char const *mode);
 
+void add_prefix_map(char const* oldprefix, char const* newprefix);
+
 #endif /* !FILES_H_ */
diff --git a/src/getargs.c b/src/getargs.c
index 6f19a4ea..02ac5ce0 100644
--- a/src/getargs.c
+++ b/src/getargs.c
@@ -418,15 +418,17 @@ Tuning the Parser:\n\
        * won't assume that -d also takes an argument.  */
       fputs (_("\
 Output Files:\n\
-      --defines[=FILE]       also produce a header file\n\
-  -d                         likewise but cannot specify FILE (for POSIX 
Yacc)\n\
-  -r, --report=THINGS        also produce details on the automaton\n\
-      --report-file=FILE     write report to FILE\n\
-  -v, --verbose              same as '--report=state'\n\
-  -b, --file-prefix=PREFIX   specify a PREFIX for output files\n\
-  -o, --output=FILE          leave output to FILE\n\
-  -g, --graph[=FILE]         also output a graph of the automaton\n\
-  -x, --xml[=FILE]           also output an XML report of the automaton\n\
+      --defines[=FILE]          also produce a header file\n\
+  -d                            likewise but cannot specify FILE (for POSIX 
Yacc)\n\
+  -r, --report=THINGS           also produce details on the automaton\n\
+      --report-file=FILE        write report to FILE\n\
+  -v, --verbose                 same as '--report=state'\n\
+  -b, --file-prefix=PREFIX      specify a PREFIX for output files\n\
+  -o, --output=FILE             leave output to FILE\n\
+  -g, --graph[=FILE]            also output a graph of the automaton\n\
+  -x, --xml[=FILE]              also output an XML report of the automaton\n\
+  -M, --file-prefix-map=OLD=NEW replace prefix OLD with NEW when writing file 
paths\n\
+                                in output files\n\
 "), stdout);
       putc ('\n', stdout);
 
@@ -547,6 +549,7 @@ static char const short_options[] =
   "h"
   "k"
   "l"
+  "M:"
   "o:"
   "p:"
   "r:"
@@ -598,14 +601,15 @@ static struct option const long_options[] =
   { "yacc",           no_argument,         0, 'y' },
 
   /* Output Files. */
-  { "defines",     optional_argument,   0,   'd' },
-  { "report",      required_argument,   0,   'r' },
-  { "report-file", required_argument,   0,   REPORT_FILE_OPTION },
-  { "verbose",     no_argument,         0,   'v' },
-  { "file-prefix", required_argument,   0,   'b' },
-  { "output",      required_argument,   0,   'o' },
-  { "graph",       optional_argument,   0,   'g' },
-  { "xml",         optional_argument,   0,   'x' },
+  { "defines",         optional_argument,   0,   'd' },
+  { "report",          required_argument,   0,   'r' },
+  { "report-file",     required_argument,   0,   REPORT_FILE_OPTION },
+  { "verbose",         no_argument,         0,   'v' },
+  { "file-prefix",     required_argument,   0,   'b' },
+  { "output",          required_argument,   0,   'o' },
+  { "graph",           optional_argument,   0,   'g' },
+  { "xml",             optional_argument,   0,   'x' },
+  { "file-prefix-map", required_argument,   0,   'M' },
 
   /* Hidden. */
   { "fixed-output-files", no_argument,       0,  FIXED_OUTPUT_FILES_OPTION },
@@ -765,6 +769,18 @@ getargs (int argc, char *argv[])
         no_lines_flag = true;
         break;
 
+      case 'M': // -MOLDPREFIX=NEWPREFIX
+        {
+          if (optarg) {
+            char *newprefix = strchr (optarg, '=');
+            if (newprefix) {
+              *newprefix = 0;
+              add_prefix_map(optarg, newprefix + 1);
+            }
+          }
+        }
+        break;
+
       case 'o':
         spec_outfile = optarg;
         break;
diff --git a/src/output.c b/src/output.c
index 1871fd75..f4548468 100644
--- a/src/output.c
+++ b/src/output.c
@@ -800,8 +800,10 @@ prepare (void)
 
 #define DEFINE(Name) MUSCLE_INSERT_STRING (#Name, Name ? Name : "")
   DEFINE (dir_prefix);
+  DEFINE (mapped_dir_prefix);
   DEFINE (parser_file_name);
   DEFINE (spec_header_file);
+  DEFINE (spec_mapped_header_file);
   DEFINE (spec_file_prefix);
   DEFINE (spec_graph_file);
   DEFINE (spec_name_prefix);
diff --git a/tests/c++.at b/tests/c++.at
index 490c6c25..cdc2a0d4 100644
--- a/tests/c++.at
+++ b/tests/c++.at
@@ -1489,7 +1489,100 @@ AT_PARSER_CHECK([parser], [0])
 
 AT_CLEANUP
 
+## --------------------------- ##
+## Header Guard Prefix Mapping ##
+## --------------------------- ##
+
+AT_SETUP([Header Guard Prefix Mapping])
+
+# AT_TEST([PREFIX], [DIRECTIVES])
+# -------------------------------
+# Generate and compile to *.o.  Make sure there is no (allowed) YY*
+# nor yy* identifiers in the header after applying api.prefix.  Check
+# that headers can be compiled by a C++ compiler.
+m4_pushdef([AT_TEST],
+[AT_BISON_OPTION_PUSHDEFS([%skeleton "lalr1.cc" %define api.namespace {$1} $2])
+AT_LOC_PUSHDEF([begin.line], [begin.column], [end.line], [end.column])
+AT_DATA_GRAMMAR([$1.yy],
+[[%skeleton "lalr1.cc"
+%define api.namespace {$1}
+$2
+%code {
+  ]AT_YYERROR_DECLARE[
+  ]AT_YYLEX_DECLARE[
+}
+%%
+exp: '0';
+%%
+]AT_YYERROR_DEFINE[
+]AT_YYLEX_DEFINE(["0"])[
+]])
+
+AT_BISON_CHECK([-fcaret -o out/$1.cc -M out/=bar/ $1.yy])
+AT_LANG_COMPILE([out/$1.o], [], [-Iout/include])
+
+AT_LOC_POPDEF
+AT_BISON_OPTION_POPDEFS
+])
+
+mkdir -p out/include/ast
+
+AT_TEST([x1],
+        [%defines
+         %locations
+         %define api.location.file "include/ast/loc.hh"
+         ])
 
+# Check the CPP guard and Doxyen comments.
+AT_CHECK([sed -ne '/INCLUDED/p;/\\file/{p;n;p;}' out/include/ast/loc.hh], [],
+[[ ** \file bar/include/ast/loc.hh
+ ** Define the x1::location class.
+#ifndef YY_YY_BAR_INCLUDE_AST_LOC_HH_INCLUDED
+# define YY_YY_BAR_INCLUDE_AST_LOC_HH_INCLUDED
+#endif // !YY_YY_BAR_INCLUDE_AST_LOC_HH_INCLUDED
+]])
+
+AT_CHECK([sed -ne '/INCLUDED/p;/\\file/{p;n;p;}' out/x1.hh], [],
+[[ ** \file bar/x1.hh
+ ** Define the x1::parser class.
+#ifndef YY_YY_BAR_X1_HH_INCLUDED
+# define YY_YY_BAR_X1_HH_INCLUDED
+#endif // !YY_YY_BAR_X1_HH_INCLUDED
+]])
+
+AT_TEST([x2],
+        [%defines
+         %locations
+         %code requires {#include "include/ast/loc.hh"}
+         %define api.location.type {x1::location}])
+
+m4_popdef([AT_TEST])
+
+AT_DATA([main.cc],
+[AT_DATA_SOURCE_PROLOGUE
+[#include "x1.hh"
+#include "x2.hh"
+
+#define RUN(S)                                  \
+  do {                                          \
+    S::parser parser;                           \
+    int res = parser.parse();                   \
+    if (res)                                    \
+      std::cerr << #S": " << res << '\n';       \
+  } while (false)
+
+int
+main (void)
+{
+  RUN(x1);
+  RUN(x2);
+}
+]])# main.cc
+
+AT_COMPILE_CXX([parser], [[out/x[12].o main.cc]], [-Iout/])
+AT_PARSER_CHECK([parser], [0])
+
+AT_CLEANUP
 
 ## ---------------- ##
 ## Default action.  ##
-- 
2.17.1




reply via email to

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